1 /*
2  * This file is part of libplacebo.
3  *
4  * libplacebo is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * libplacebo is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #pragma once
19 
20 #include <stdalign.h>
21 #include <d3d11_4.h>
22 #include <dxgi1_6.h>
23 #include <d3dcompiler.h>
24 #include <spirv_cross_c.h>
25 
26 #include "../gpu.h"
27 
28 #include "common.h"
29 #include "utils.h"
30 
31 pl_gpu pl_gpu_create_d3d11(struct d3d11_ctx *ctx);
32 
33 // --- pl_gpu internal structs and helpers
34 
35 // Size of one constant in a constant buffer
36 #define CBUF_ELEM (sizeof(float[4]))
37 
38 struct d3d_stream_buf {
39     UINT bind_flags;
40     ID3D11Buffer *buf;
41     size_t size;
42     size_t used;
43     unsigned int align;
44 };
45 
46 struct pl_gpu_d3d11 {
47     struct pl_gpu_fns impl;
48     struct d3d11_ctx *ctx;
49     ID3D11Device *dev;
50     ID3D11Device1 *dev1;
51     ID3D11Device5 *dev5;
52     ID3D11DeviceContext *imm;
53     ID3D11DeviceContext1 *imm1;
54     ID3D11DeviceContext4 *imm4;
55 
56     struct spirv_compiler *spirv;
57 
58     pD3DCompile D3DCompile;
59     struct dll_version d3d_compiler_ver;
60 
61     // Device capabilities
62     D3D_FEATURE_LEVEL fl;
63     bool has_timestamp_queries;
64     bool has_monitored_fences;
65 
66     int max_srvs;
67     int max_uavs;
68 
69     // This is a pl_dispatch used on ourselves for the purposes of dispatching
70     // shaders for performing various emulation tasks (e.g. blits).
71     // Warning: As in pl_vk, care must be taken to avoid recursive calls.
72     struct pl_dispatch *dp;
73 
74     // Streaming vertex and index buffers
75     struct d3d_stream_buf vbuf;
76     struct d3d_stream_buf ibuf;
77 
78     // Shared rasterizer state
79     ID3D11RasterizerState *rstate;
80 
81     // Shared depth-stencil state
82     ID3D11DepthStencilState *dsstate;
83 
84     // Array of ID3D11SamplerStates for every combination of sample/address modes
85     ID3D11SamplerState *samplers[PL_TEX_SAMPLE_MODE_COUNT][PL_TEX_ADDRESS_MODE_COUNT];
86 
87     // Resources for finish()
88     ID3D11Fence *finish_fence;
89     uint64_t finish_value;
90     HANDLE finish_event;
91     ID3D11Query *finish_query;
92     pl_buf finish_buf_src;
93     pl_buf finish_buf_dst;
94 };
95 
96 void pl_d3d11_setup_formats(struct pl_gpu *gpu);
97 
98 void pl_d3d11_timer_start(pl_gpu gpu, pl_timer timer);
99 void pl_d3d11_timer_end(pl_gpu gpu, pl_timer timer);
100 
101 struct pl_buf_d3d11 {
102     ID3D11Buffer *buf;
103     ID3D11Buffer *staging;
104     ID3D11ShaderResourceView *raw_srv;
105     ID3D11UnorderedAccessView *raw_uav;
106     ID3D11ShaderResourceView *texel_srv;
107     ID3D11UnorderedAccessView *texel_uav;
108 
109     char *data;
110     bool dirty;
111 };
112 
113 void pl_d3d11_buf_destroy(pl_gpu gpu, pl_buf buf);
114 pl_buf pl_d3d11_buf_create(pl_gpu gpu, const struct pl_buf_params *params);
115 void pl_d3d11_buf_write(pl_gpu gpu, pl_buf buf, size_t offset, const void *data,
116                         size_t size);
117 bool pl_d3d11_buf_read(pl_gpu gpu, pl_buf buf, size_t offset, void *dest,
118                        size_t size);
119 void pl_d3d11_buf_copy(pl_gpu gpu, pl_buf dst, size_t dst_offset, pl_buf src,
120                        size_t src_offset, size_t size);
121 
122 // Ensure a buffer is up-to-date with its system memory mirror before it is used
123 void pl_d3d11_buf_resolve(pl_gpu gpu, pl_buf buf);
124 
125 struct pl_tex_d3d11 {
126     // res mirrors one of tex1d, tex2d or tex3d for convenience. It does not
127     // hold an additional reference to the texture object.
128     ID3D11Resource *res;
129 
130     ID3D11Texture1D *tex1d;
131     ID3D11Texture2D *tex2d;
132     ID3D11Texture3D *tex3d;
133     int array_slice;
134 
135     // Mirrors one of staging1d, staging2d, or staging3d, and doesn't hold a ref
136     ID3D11Resource *staging;
137 
138     // Staging textures for pl_tex_download
139     ID3D11Texture1D *staging1d;
140     ID3D11Texture2D *staging2d;
141     ID3D11Texture3D *staging3d;
142 
143     ID3D11ShaderResourceView *srv;
144     ID3D11RenderTargetView *rtv;
145     ID3D11UnorderedAccessView *uav;
146 };
147 
148 void pl_d3d11_tex_destroy(pl_gpu gpu, pl_tex tex);
149 pl_tex pl_d3d11_tex_create(pl_gpu gpu, const struct pl_tex_params *params);
150 void pl_d3d11_tex_invalidate(pl_gpu gpu, pl_tex tex);
151 void pl_d3d11_tex_clear_ex(pl_gpu gpu, pl_tex tex,
152                            const union pl_clear_color color);
153 void pl_d3d11_tex_blit(pl_gpu gpu, const struct pl_tex_blit_params *params);
154 bool pl_d3d11_tex_upload(pl_gpu gpu, const struct pl_tex_transfer_params *params);
155 bool pl_d3d11_tex_download(pl_gpu gpu, const struct pl_tex_transfer_params *params);
156 
157 // Constant buffer layout used for gl_NumWorkGroups emulation
158 struct d3d_num_workgroups_buf {
159     alignas(CBUF_ELEM) uint32_t num_wgs[3];
160 };
161 
162 // Represents a descriptor binding to a specific shader stage (VS, PS, CS)
163 struct d3d_desc_stage {
164     // The HLSL register number used for this resource
165     int cbv_slot;     // register(bN)
166     int srv_slot;     // register(tN)
167     int sampler_slot; // register(sN)
168     int uav_slot;     // register(uN)
169 
170     // Is the resource used in this shader pass? Used to optimize pipeline
171     // binding for resources that are used in the vertex shader but not the
172     // fragment shader or vice versa.
173     bool used;
174 };
175 
176 struct pl_desc_d3d11 {
177     struct d3d_desc_stage main; // PS and CS
178     struct d3d_desc_stage vertex;
179 };
180 
181 enum {
182     HLSL_BINDING_NOT_USED = -1, // Slot should always be bound as NULL
183     HLSL_BINDING_NUM_WORKGROUPS = -2, // Slot used for gl_NumWorkGroups emulation
184 };
185 
186 // Represents a specific shader stage in a pl_pass (VS, PS, CS)
187 struct d3d_pass_stage {
188     // GLSL->HLSL translator state
189     spvc_context sc;
190     spvc_compiler sc_comp;
191 
192     // Lists for each resource type, to simplify binding in pl_pass_run. Indexes
193     // match the index of the arrays passed to the ID3D11DeviceContext methods.
194     // Entries are the index of pass->params.descriptors which should be bound
195     // in that position, or a HLSL_BINDING_* special value.
196     PL_ARRAY(int) cbvs;
197     PL_ARRAY(int) srvs;
198     PL_ARRAY(int) samplers;
199 };
200 
201 struct pl_pass_d3d11 {
202     ID3D11PixelShader *ps;
203     ID3D11VertexShader *vs;
204     ID3D11ComputeShader *cs;
205     ID3D11InputLayout *layout;
206     ID3D11BlendState *bstate;
207 
208     // gl_NumWorkGroups emulation
209     struct d3d_num_workgroups_buf last_num_wgs;
210     ID3D11Buffer *num_workgroups_buf;
211     bool num_workgroups_used;
212 
213     struct pl_desc_d3d11 *descriptors;
214 
215     struct d3d_pass_stage main; // PS and CS
216     struct d3d_pass_stage vertex;
217 
218     // List of resources, as in `struct pass_stage`, except UAVs are shared
219     // between all shader stages
220     PL_ARRAY(int) uavs;
221 
222     // Pre-allocated resource arrays to use in pl_pass_run
223     ID3D11Buffer **cbv_arr;
224     ID3D11ShaderResourceView **srv_arr;
225     ID3D11SamplerState **sampler_arr;
226     ID3D11UnorderedAccessView **uav_arr;
227 };
228 
229 void pl_d3d11_pass_destroy(pl_gpu gpu, pl_pass pass);
230 const struct pl_pass *pl_d3d11_pass_create(pl_gpu gpu,
231                                            const struct pl_pass_params *params);
232 void pl_d3d11_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params);
233