1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "d3d12_context.h"
25 #include "d3d12_format.h"
26 #include "d3d12_resource.h"
27 #include "d3d12_screen.h"
28 #include "d3d12_surface.h"
29
30 #include "util/format/u_format.h"
31 #include "util/u_inlines.h"
32 #include "util/u_memory.h"
33
34 static D3D12_DSV_DIMENSION
view_dsv_dimension(enum pipe_texture_target target,unsigned samples)35 view_dsv_dimension(enum pipe_texture_target target, unsigned samples)
36 {
37 switch (target) {
38 case PIPE_TEXTURE_1D: return D3D12_DSV_DIMENSION_TEXTURE1D;
39 case PIPE_TEXTURE_1D_ARRAY: return D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
40
41 case PIPE_TEXTURE_2D:
42 case PIPE_TEXTURE_RECT:
43 return samples > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS :
44 D3D12_DSV_DIMENSION_TEXTURE2D;
45
46 case PIPE_TEXTURE_2D_ARRAY:
47 case PIPE_TEXTURE_CUBE:
48 return samples > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY :
49 D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
50
51 default:
52 unreachable("unexpected target");
53 }
54 }
55
56 static D3D12_RTV_DIMENSION
view_rtv_dimension(enum pipe_texture_target target,unsigned samples)57 view_rtv_dimension(enum pipe_texture_target target, unsigned samples)
58 {
59 switch (target) {
60 case PIPE_BUFFER: return D3D12_RTV_DIMENSION_BUFFER;
61 case PIPE_TEXTURE_1D: return D3D12_RTV_DIMENSION_TEXTURE1D;
62 case PIPE_TEXTURE_1D_ARRAY: return D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
63
64 case PIPE_TEXTURE_2D:
65 case PIPE_TEXTURE_RECT:
66 return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS :
67 D3D12_RTV_DIMENSION_TEXTURE2D;
68
69 case PIPE_TEXTURE_2D_ARRAY:
70 case PIPE_TEXTURE_CUBE:
71 return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY :
72 D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
73
74 case PIPE_TEXTURE_3D: return D3D12_RTV_DIMENSION_TEXTURE3D;
75
76 default:
77 unreachable("unexpected target");
78 }
79 }
80
81 static void
initialize_dsv(struct pipe_context * pctx,struct pipe_resource * pres,const struct pipe_surface * tpl,struct d3d12_descriptor_handle * handle,DXGI_FORMAT dxgi_format)82 initialize_dsv(struct pipe_context *pctx,
83 struct pipe_resource *pres,
84 const struct pipe_surface *tpl,
85 struct d3d12_descriptor_handle *handle,
86 DXGI_FORMAT dxgi_format)
87 {
88 struct d3d12_resource *res = d3d12_resource(pres);
89 struct d3d12_screen *screen = d3d12_screen(pctx->screen);
90
91 D3D12_DEPTH_STENCIL_VIEW_DESC desc;
92 desc.Format = dxgi_format;
93 desc.Flags = D3D12_DSV_FLAG_NONE;
94
95 desc.ViewDimension = view_dsv_dimension(pres->target, pres->nr_samples);
96 switch (desc.ViewDimension) {
97 case D3D12_DSV_DIMENSION_TEXTURE1D:
98 if (tpl->u.tex.first_layer > 0)
99 debug_printf("D3D12: can't create 1D DSV from layer %d\n",
100 tpl->u.tex.first_layer);
101
102 desc.Texture1D.MipSlice = tpl->u.tex.level;
103 break;
104
105 case D3D12_DSV_DIMENSION_TEXTURE1DARRAY:
106 desc.Texture1DArray.MipSlice = tpl->u.tex.level;
107 desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer;
108 desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
109 break;
110
111 case D3D12_DSV_DIMENSION_TEXTURE2DMS:
112 if (tpl->u.tex.first_layer > 0)
113 debug_printf("D3D12: can't create 2DMS DSV from layer %d\n",
114 tpl->u.tex.first_layer);
115
116 break;
117
118 case D3D12_DSV_DIMENSION_TEXTURE2D:
119 if (tpl->u.tex.first_layer > 0)
120 debug_printf("D3D12: can't create 2D DSV from layer %d\n",
121 tpl->u.tex.first_layer);
122
123 desc.Texture2D.MipSlice = tpl->u.tex.level;
124 break;
125
126 case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY:
127 desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer;
128 desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
129 break;
130
131 case D3D12_DSV_DIMENSION_TEXTURE2DARRAY:
132 desc.Texture2DArray.MipSlice = tpl->u.tex.level;
133 desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer;
134 desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
135 break;
136
137 default:
138 unreachable("Unhandled DSV dimension");
139 }
140
141 mtx_lock(&screen->descriptor_pool_mutex);
142 d3d12_descriptor_pool_alloc_handle(screen->dsv_pool, handle);
143 mtx_unlock(&screen->descriptor_pool_mutex);
144
145 screen->dev->CreateDepthStencilView(d3d12_resource_resource(res), &desc,
146 handle->cpu_handle);
147 }
148
149 static void
initialize_rtv(struct pipe_context * pctx,struct pipe_resource * pres,const struct pipe_surface * tpl,struct d3d12_descriptor_handle * handle,DXGI_FORMAT dxgi_format)150 initialize_rtv(struct pipe_context *pctx,
151 struct pipe_resource *pres,
152 const struct pipe_surface *tpl,
153 struct d3d12_descriptor_handle *handle,
154 DXGI_FORMAT dxgi_format)
155 {
156 struct d3d12_resource *res = d3d12_resource(pres);
157 struct d3d12_screen *screen = d3d12_screen(pctx->screen);
158
159 D3D12_RENDER_TARGET_VIEW_DESC desc;
160 desc.Format = dxgi_format;
161
162 desc.ViewDimension = view_rtv_dimension(pres->target, pres->nr_samples);
163 switch (desc.ViewDimension) {
164 case D3D12_RTV_DIMENSION_BUFFER:
165 desc.Buffer.FirstElement = 0;
166 desc.Buffer.NumElements = pres->width0 / util_format_get_blocksize(tpl->format);
167 break;
168
169 case D3D12_RTV_DIMENSION_TEXTURE1D:
170 if (tpl->u.tex.first_layer > 0)
171 debug_printf("D3D12: can't create 1D RTV from layer %d\n",
172 tpl->u.tex.first_layer);
173
174 desc.Texture1D.MipSlice = tpl->u.tex.level;
175 break;
176
177 case D3D12_RTV_DIMENSION_TEXTURE1DARRAY:
178 desc.Texture1DArray.MipSlice = tpl->u.tex.level;
179 desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer;
180 desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
181 break;
182
183 case D3D12_RTV_DIMENSION_TEXTURE2DMS:
184 if (tpl->u.tex.first_layer > 0)
185 debug_printf("D3D12: can't create 2DMS RTV from layer %d\n",
186 tpl->u.tex.first_layer);
187 break;
188
189 case D3D12_RTV_DIMENSION_TEXTURE2D:
190 if (tpl->u.tex.first_layer > 0)
191 debug_printf("D3D12: can't create 2D RTV from layer %d\n",
192 tpl->u.tex.first_layer);
193
194 desc.Texture2D.MipSlice = tpl->u.tex.level;
195 desc.Texture2D.PlaneSlice = 0;
196 break;
197
198 case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY:
199 desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer;
200 desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
201 break;
202
203 case D3D12_RTV_DIMENSION_TEXTURE2DARRAY:
204 desc.Texture2DArray.MipSlice = tpl->u.tex.level;
205 desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer;
206 desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
207 desc.Texture2DArray.PlaneSlice = 0;
208 break;
209
210 case D3D12_RTV_DIMENSION_TEXTURE3D:
211 desc.Texture3D.MipSlice = tpl->u.tex.level;
212 desc.Texture3D.FirstWSlice = tpl->u.tex.first_layer;
213 desc.Texture3D.WSize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
214 break;
215
216 default:
217 unreachable("Unhandled RTV dimension");
218 }
219
220 mtx_lock(&screen->descriptor_pool_mutex);
221 d3d12_descriptor_pool_alloc_handle(screen->rtv_pool, handle);
222 mtx_unlock(&screen->descriptor_pool_mutex);
223
224 screen->dev->CreateRenderTargetView(d3d12_resource_resource(res), &desc,
225 handle->cpu_handle);
226 }
227
228 static struct pipe_surface *
d3d12_create_surface(struct pipe_context * pctx,struct pipe_resource * pres,const struct pipe_surface * tpl)229 d3d12_create_surface(struct pipe_context *pctx,
230 struct pipe_resource *pres,
231 const struct pipe_surface *tpl)
232 {
233 bool is_depth_or_stencil = util_format_is_depth_or_stencil(tpl->format);
234 unsigned bind = is_depth_or_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET;
235
236 /* Don't bother if we don't support the requested format as RT or DS */
237 if (!pctx->screen->is_format_supported(pctx->screen, tpl->format, PIPE_TEXTURE_2D,
238 tpl->nr_samples, tpl->nr_samples,bind))
239 return NULL;
240
241 struct d3d12_surface *surface = CALLOC_STRUCT(d3d12_surface);
242 if (!surface)
243 return NULL;
244
245 pipe_resource_reference(&surface->base.texture, pres);
246 pipe_reference_init(&surface->base.reference, 1);
247 surface->base.context = pctx;
248 surface->base.format = tpl->format;
249 surface->base.width = u_minify(pres->width0, tpl->u.tex.level);
250 surface->base.height = u_minify(pres->height0, tpl->u.tex.level);
251 surface->base.u.tex.level = tpl->u.tex.level;
252 surface->base.u.tex.first_layer = tpl->u.tex.first_layer;
253 surface->base.u.tex.last_layer = tpl->u.tex.last_layer;
254
255 DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(tpl->format);
256 if (is_depth_or_stencil)
257 initialize_dsv(pctx, pres, tpl, &surface->desc_handle, dxgi_format);
258 else
259 initialize_rtv(pctx, pres, tpl, &surface->desc_handle, dxgi_format);
260
261 return &surface->base;
262 }
263
264 static void
d3d12_surface_destroy(struct pipe_context * pctx,struct pipe_surface * psurf)265 d3d12_surface_destroy(struct pipe_context *pctx,
266 struct pipe_surface *psurf)
267 {
268 struct d3d12_surface *surface = (struct d3d12_surface*) psurf;
269 struct d3d12_screen *screen = d3d12_screen(pctx->screen);
270
271 mtx_lock(&screen->descriptor_pool_mutex);
272 d3d12_descriptor_handle_free(&surface->desc_handle);
273 if (d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle))
274 d3d12_descriptor_handle_free(&surface->uint_rtv_handle);
275 mtx_unlock(&screen->descriptor_pool_mutex);
276
277 pipe_resource_reference(&psurf->texture, NULL);
278 pipe_resource_reference(&surface->rgba_texture, NULL);
279 FREE(surface);
280 }
281
282 static void
blit_surface(struct d3d12_surface * surface,bool pre)283 blit_surface(struct d3d12_surface *surface, bool pre)
284 {
285 struct pipe_blit_info info = {};
286
287 info.src.resource = pre ? surface->base.texture : surface->rgba_texture;
288 info.dst.resource = pre ? surface->rgba_texture : surface->base.texture;
289 info.src.format = pre ? surface->base.texture->format : PIPE_FORMAT_R8G8B8A8_UNORM;
290 info.dst.format = pre ? PIPE_FORMAT_R8G8B8A8_UNORM : surface->base.texture->format;
291 info.src.level = info.dst.level = 0;
292 info.src.box.x = info.dst.box.x = 0;
293 info.src.box.y = info.dst.box.y = 0;
294 info.src.box.z = info.dst.box.z = 0;
295 info.src.box.width = info.dst.box.width = surface->base.width;
296 info.src.box.height = info.dst.box.height = surface->base.height;
297 info.src.box.depth = info.dst.box.depth = 0;
298 info.mask = PIPE_MASK_RGBA;
299
300 d3d12_blit(surface->base.context, &info);
301 }
302
303 enum d3d12_surface_conversion_mode
d3d12_surface_update_pre_draw(struct d3d12_surface * surface,DXGI_FORMAT format)304 d3d12_surface_update_pre_draw(struct d3d12_surface *surface,
305 DXGI_FORMAT format)
306 {
307 struct d3d12_screen *screen = d3d12_screen(surface->base.context->screen);
308 struct d3d12_resource *res = d3d12_resource(surface->base.texture);
309 DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(surface->base.format);
310 enum d3d12_surface_conversion_mode mode;
311
312 if (dxgi_format == format)
313 return D3D12_SURFACE_CONVERSION_NONE;
314
315 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
316 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
317 mode = D3D12_SURFACE_CONVERSION_BGRA_UINT;
318 else
319 mode = D3D12_SURFACE_CONVERSION_RGBA_UINT;
320
321 if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT) {
322 if (!surface->rgba_texture) {
323 struct pipe_resource templ = {};
324 struct pipe_resource *src = surface->base.texture;
325
326 templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
327 templ.width0 = src->width0;
328 templ.height0 = src->height0;
329 templ.depth0 = src->depth0;
330 templ.array_size = src->array_size;
331 templ.nr_samples = src->nr_samples;
332 templ.nr_storage_samples = src->nr_storage_samples;
333 templ.usage = PIPE_USAGE_DEFAULT | PIPE_USAGE_STAGING;
334 templ.bind = src->bind;
335 templ.target = src->target;
336
337 surface->rgba_texture = screen->base.resource_create(&screen->base, &templ);
338 }
339
340 blit_surface(surface, true);
341 res = d3d12_resource(surface->rgba_texture);
342 }
343
344 if (!d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle)) {
345 initialize_rtv(surface->base.context, &res->base, &surface->base,
346 &surface->uint_rtv_handle, DXGI_FORMAT_R8G8B8A8_UINT);
347 }
348
349 return mode;
350 }
351
352 void
d3d12_surface_update_post_draw(struct d3d12_surface * surface,enum d3d12_surface_conversion_mode mode)353 d3d12_surface_update_post_draw(struct d3d12_surface *surface,
354 enum d3d12_surface_conversion_mode mode)
355 {
356 if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT)
357 blit_surface(surface, false);
358 }
359
360 D3D12_CPU_DESCRIPTOR_HANDLE
d3d12_surface_get_handle(struct d3d12_surface * surface,enum d3d12_surface_conversion_mode mode)361 d3d12_surface_get_handle(struct d3d12_surface *surface,
362 enum d3d12_surface_conversion_mode mode)
363 {
364 if (mode != D3D12_SURFACE_CONVERSION_NONE)
365 return surface->uint_rtv_handle.cpu_handle;
366 return surface->desc_handle.cpu_handle;
367 }
368
369 void
d3d12_context_surface_init(struct pipe_context * context)370 d3d12_context_surface_init(struct pipe_context *context)
371 {
372 context->create_surface = d3d12_create_surface;
373 context->surface_destroy = d3d12_surface_destroy;
374 }
375