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