• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    case PIPE_TEXTURE_CUBE_ARRAY:
49       return samples > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY :
50                            D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
51 
52    default:
53       unreachable("unexpected target");
54    }
55 }
56 
57 static D3D12_RTV_DIMENSION
view_rtv_dimension(enum pipe_texture_target target,unsigned samples)58 view_rtv_dimension(enum pipe_texture_target target, unsigned samples)
59 {
60    switch (target) {
61    case PIPE_BUFFER: return D3D12_RTV_DIMENSION_BUFFER;
62    case PIPE_TEXTURE_1D: return D3D12_RTV_DIMENSION_TEXTURE1D;
63    case PIPE_TEXTURE_1D_ARRAY: return D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
64 
65    case PIPE_TEXTURE_2D:
66    case PIPE_TEXTURE_RECT:
67       return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS :
68                            D3D12_RTV_DIMENSION_TEXTURE2D;
69 
70    case PIPE_TEXTURE_2D_ARRAY:
71    case PIPE_TEXTURE_CUBE:
72    case PIPE_TEXTURE_CUBE_ARRAY:
73       return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY :
74                            D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
75 
76    case PIPE_TEXTURE_3D: return D3D12_RTV_DIMENSION_TEXTURE3D;
77 
78    default:
79       unreachable("unexpected target");
80    }
81 }
82 
83 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)84 initialize_dsv(struct pipe_context *pctx,
85                struct pipe_resource *pres,
86                const struct pipe_surface *tpl,
87                struct d3d12_descriptor_handle *handle,
88                DXGI_FORMAT dxgi_format)
89 {
90    struct d3d12_resource *res = d3d12_resource(pres);
91    struct d3d12_screen *screen = d3d12_screen(pctx->screen);
92 
93    D3D12_DEPTH_STENCIL_VIEW_DESC desc;
94    desc.Format = dxgi_format;
95    desc.Flags = D3D12_DSV_FLAG_NONE;
96 
97    desc.ViewDimension = view_dsv_dimension(pres->target, pres->nr_samples);
98    switch (desc.ViewDimension) {
99    case D3D12_DSV_DIMENSION_TEXTURE1D:
100       if (tpl->u.tex.first_layer > 0)
101          debug_printf("D3D12: can't create 1D DSV from layer %d\n",
102                       tpl->u.tex.first_layer);
103 
104       desc.Texture1D.MipSlice = tpl->u.tex.level;
105       break;
106 
107    case D3D12_DSV_DIMENSION_TEXTURE1DARRAY:
108       desc.Texture1DArray.MipSlice = tpl->u.tex.level;
109       desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer;
110       desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
111       break;
112 
113    case D3D12_DSV_DIMENSION_TEXTURE2DMS:
114       if (tpl->u.tex.first_layer > 0)
115          debug_printf("D3D12: can't create 2DMS DSV from layer %d\n",
116                       tpl->u.tex.first_layer);
117 
118       break;
119 
120    case D3D12_DSV_DIMENSION_TEXTURE2D:
121       if (tpl->u.tex.first_layer > 0)
122          debug_printf("D3D12: can't create 2D DSV from layer %d\n",
123                       tpl->u.tex.first_layer);
124 
125       desc.Texture2D.MipSlice = tpl->u.tex.level;
126       break;
127 
128    case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY:
129       desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer;
130       desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
131       break;
132 
133    case D3D12_DSV_DIMENSION_TEXTURE2DARRAY:
134       desc.Texture2DArray.MipSlice = tpl->u.tex.level;
135       desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer;
136       desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
137       break;
138 
139    default:
140       unreachable("Unhandled DSV dimension");
141    }
142 
143    mtx_lock(&screen->descriptor_pool_mutex);
144    d3d12_descriptor_pool_alloc_handle(screen->dsv_pool, handle);
145    mtx_unlock(&screen->descriptor_pool_mutex);
146 
147    screen->dev->CreateDepthStencilView(d3d12_resource_resource(res), &desc,
148                                        handle->cpu_handle);
149 }
150 
151 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)152 initialize_rtv(struct pipe_context *pctx,
153                struct pipe_resource *pres,
154                const struct pipe_surface *tpl,
155                struct d3d12_descriptor_handle *handle,
156                DXGI_FORMAT dxgi_format)
157 {
158    struct d3d12_resource *res = d3d12_resource(pres);
159    struct d3d12_screen *screen = d3d12_screen(pctx->screen);
160 
161    D3D12_RENDER_TARGET_VIEW_DESC desc;
162    desc.Format = dxgi_format;
163 
164    desc.ViewDimension = view_rtv_dimension(pres->target, pres->nr_samples);
165    switch (desc.ViewDimension) {
166    case D3D12_RTV_DIMENSION_BUFFER:
167       desc.Buffer.FirstElement = 0;
168       desc.Buffer.NumElements = pres->width0 / util_format_get_blocksize(tpl->format);
169       break;
170 
171    case D3D12_RTV_DIMENSION_TEXTURE1D:
172       if (tpl->u.tex.first_layer > 0)
173          debug_printf("D3D12: can't create 1D RTV from layer %d\n",
174                       tpl->u.tex.first_layer);
175 
176       desc.Texture1D.MipSlice = tpl->u.tex.level;
177       break;
178 
179    case D3D12_RTV_DIMENSION_TEXTURE1DARRAY:
180       desc.Texture1DArray.MipSlice = tpl->u.tex.level;
181       desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer;
182       desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
183       break;
184 
185    case D3D12_RTV_DIMENSION_TEXTURE2DMS:
186       if (tpl->u.tex.first_layer > 0)
187          debug_printf("D3D12: can't create 2DMS RTV from layer %d\n",
188                       tpl->u.tex.first_layer);
189       break;
190 
191    case D3D12_RTV_DIMENSION_TEXTURE2D:
192       if (tpl->u.tex.first_layer > 0)
193          debug_printf("D3D12: can't create 2D RTV from layer %d\n",
194                       tpl->u.tex.first_layer);
195 
196       desc.Texture2D.MipSlice = tpl->u.tex.level;
197       desc.Texture2D.PlaneSlice = res->plane_slice;
198       break;
199 
200    case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY:
201       desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer;
202       desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
203       break;
204 
205    case D3D12_RTV_DIMENSION_TEXTURE2DARRAY:
206       desc.Texture2DArray.MipSlice = tpl->u.tex.level;
207       desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer;
208       desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
209       desc.Texture2DArray.PlaneSlice = 0;
210       break;
211 
212    case D3D12_RTV_DIMENSION_TEXTURE3D:
213       desc.Texture3D.MipSlice = tpl->u.tex.level;
214       desc.Texture3D.FirstWSlice = tpl->u.tex.first_layer;
215       desc.Texture3D.WSize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1;
216       break;
217 
218    default:
219       unreachable("Unhandled RTV dimension");
220    }
221 
222    mtx_lock(&screen->descriptor_pool_mutex);
223    d3d12_descriptor_pool_alloc_handle(screen->rtv_pool, handle);
224    mtx_unlock(&screen->descriptor_pool_mutex);
225 
226    screen->dev->CreateRenderTargetView(d3d12_resource_resource(res), &desc,
227                                        handle->cpu_handle);
228 }
229 
230 static struct pipe_surface *
d3d12_create_surface(struct pipe_context * pctx,struct pipe_resource * pres,const struct pipe_surface * tpl)231 d3d12_create_surface(struct pipe_context *pctx,
232                      struct pipe_resource *pres,
233                      const struct pipe_surface *tpl)
234 {
235    bool is_depth_or_stencil = util_format_is_depth_or_stencil(tpl->format);
236    unsigned bind = is_depth_or_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET;
237 
238    /* Don't bother if we don't support the requested format as RT or DS */
239    if (!pctx->screen->is_format_supported(pctx->screen, tpl->format, PIPE_TEXTURE_2D,
240                                           tpl->nr_samples, tpl->nr_samples,bind))
241       return NULL;
242 
243    struct d3d12_surface *surface = CALLOC_STRUCT(d3d12_surface);
244    if (!surface)
245       return NULL;
246 
247    pipe_resource_reference(&surface->base.texture, pres);
248    pipe_reference_init(&surface->base.reference, 1);
249    surface->base.context = pctx;
250    surface->base.format = tpl->format;
251    surface->base.width = u_minify(pres->width0, tpl->u.tex.level);
252    surface->base.height = u_minify(pres->height0, tpl->u.tex.level);
253    surface->base.u.tex.level = tpl->u.tex.level;
254    surface->base.u.tex.first_layer = tpl->u.tex.first_layer;
255    surface->base.u.tex.last_layer = tpl->u.tex.last_layer;
256 
257    DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(tpl->format);
258    if (is_depth_or_stencil)
259       initialize_dsv(pctx, pres, tpl, &surface->desc_handle, dxgi_format);
260    else
261       initialize_rtv(pctx, pres, tpl, &surface->desc_handle, dxgi_format);
262 
263    return &surface->base;
264 }
265 
266 static void
d3d12_surface_destroy(struct pipe_context * pctx,struct pipe_surface * psurf)267 d3d12_surface_destroy(struct pipe_context *pctx,
268                       struct pipe_surface *psurf)
269 {
270    struct d3d12_surface *surface = (struct d3d12_surface*) psurf;
271    struct d3d12_screen *screen = d3d12_screen(pctx->screen);
272 
273    mtx_lock(&screen->descriptor_pool_mutex);
274    d3d12_descriptor_handle_free(&surface->desc_handle);
275    if (d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle))
276       d3d12_descriptor_handle_free(&surface->uint_rtv_handle);
277    mtx_unlock(&screen->descriptor_pool_mutex);
278 
279    pipe_resource_reference(&psurf->texture, NULL);
280    pipe_resource_reference(&surface->rgba_texture, NULL);
281    FREE(surface);
282 }
283 
284 static void
blit_surface(struct pipe_context * pctx,struct d3d12_surface * surface,bool pre)285 blit_surface(struct pipe_context *pctx, struct d3d12_surface *surface, bool pre)
286 {
287    struct pipe_blit_info info = {};
288 
289    info.src.resource = pre ? surface->base.texture : surface->rgba_texture;
290    info.dst.resource = pre ? surface->rgba_texture : surface->base.texture;
291    info.src.format = pre ? surface->base.texture->format : PIPE_FORMAT_R8G8B8A8_UNORM;
292    info.dst.format = pre ? PIPE_FORMAT_R8G8B8A8_UNORM : surface->base.texture->format;
293    info.src.level = info.dst.level = 0;
294    info.src.box.x = info.dst.box.x = 0;
295    info.src.box.y = info.dst.box.y = 0;
296    info.src.box.z = info.dst.box.z = 0;
297    info.src.box.width = info.dst.box.width = surface->base.width;
298    info.src.box.height = info.dst.box.height = surface->base.height;
299    info.src.box.depth = info.dst.box.depth = 0;
300    info.mask = PIPE_MASK_RGBA;
301 
302    d3d12_blit(pctx, &info);
303 }
304 
305 enum d3d12_surface_conversion_mode
d3d12_surface_update_pre_draw(struct pipe_context * pctx,struct d3d12_surface * surface,DXGI_FORMAT format)306 d3d12_surface_update_pre_draw(struct pipe_context *pctx,
307                               struct d3d12_surface *surface,
308                               DXGI_FORMAT format)
309 {
310    struct d3d12_screen *screen = d3d12_screen(surface->base.context->screen);
311    struct d3d12_resource *res = d3d12_resource(surface->base.texture);
312    DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(surface->base.format);
313    enum d3d12_surface_conversion_mode mode;
314 
315    if (dxgi_format == format)
316       return D3D12_SURFACE_CONVERSION_NONE;
317 
318    if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
319        dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
320       mode = D3D12_SURFACE_CONVERSION_BGRA_UINT;
321    else
322       mode = D3D12_SURFACE_CONVERSION_RGBA_UINT;
323 
324    if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT) {
325       if (!surface->rgba_texture) {
326          struct pipe_resource templ = {};
327          struct pipe_resource *src = surface->base.texture;
328 
329          templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
330          templ.width0 = src->width0;
331          templ.height0 = src->height0;
332          templ.depth0 = src->depth0;
333          templ.array_size = src->array_size;
334          templ.nr_samples = src->nr_samples;
335          templ.nr_storage_samples = src->nr_storage_samples;
336          templ.usage = PIPE_USAGE_DEFAULT | PIPE_USAGE_STAGING;
337          templ.bind = src->bind;
338          templ.target = src->target;
339 
340          surface->rgba_texture = screen->base.resource_create(&screen->base, &templ);
341       }
342 
343       blit_surface(pctx, surface, true);
344       res = d3d12_resource(surface->rgba_texture);
345    }
346 
347    if (!d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle)) {
348       initialize_rtv(surface->base.context, &res->base.b, &surface->base,
349                      &surface->uint_rtv_handle, DXGI_FORMAT_R8G8B8A8_UINT);
350    }
351 
352    return mode;
353 }
354 
355 void
d3d12_surface_update_post_draw(struct pipe_context * pctx,struct d3d12_surface * surface,enum d3d12_surface_conversion_mode mode)356 d3d12_surface_update_post_draw(struct pipe_context *pctx,
357                                struct d3d12_surface *surface,
358                                enum d3d12_surface_conversion_mode mode)
359 {
360    if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT)
361       blit_surface(pctx, surface, false);
362 }
363 
364 D3D12_CPU_DESCRIPTOR_HANDLE
d3d12_surface_get_handle(struct d3d12_surface * surface,enum d3d12_surface_conversion_mode mode)365 d3d12_surface_get_handle(struct d3d12_surface *surface,
366                          enum d3d12_surface_conversion_mode mode)
367 {
368    if (mode != D3D12_SURFACE_CONVERSION_NONE)
369       return surface->uint_rtv_handle.cpu_handle;
370    return surface->desc_handle.cpu_handle;
371 }
372 
373 void
d3d12_context_surface_init(struct pipe_context * context)374 d3d12_context_surface_init(struct pipe_context *context)
375 {
376    context->create_surface = d3d12_create_surface;
377    context->surface_destroy = d3d12_surface_destroy;
378 }
379