xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_resource.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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_resource.h"
25 
26 #include "d3d12_blit.h"
27 #include "d3d12_context.h"
28 #include "d3d12_format.h"
29 #include "d3d12_screen.h"
30 #include "d3d12_debug.h"
31 
32 #include "pipebuffer/pb_bufmgr.h"
33 #include "util/slab.h"
34 #include "util/format/u_format.h"
35 #include "util/u_inlines.h"
36 #include "util/u_memory.h"
37 #include "util/format/u_format_zs.h"
38 
39 #include "frontend/sw_winsys.h"
40 
41 #include <dxguids/dxguids.h>
42 #include <memory>
43 
44 #ifndef _GAMING_XBOX
45 #include <wrl/client.h>
46 using Microsoft::WRL::ComPtr;
47 #endif
48 
49 #ifndef GENERIC_ALL
50  // This is only added to winadapter.h in newer DirectX-Headers
51 #define GENERIC_ALL 0x10000000L
52 #endif
53 
54 static bool
can_map_directly(struct pipe_resource * pres)55 can_map_directly(struct pipe_resource *pres)
56 {
57    return pres->target == PIPE_BUFFER &&
58           pres->usage != PIPE_USAGE_DEFAULT &&
59           pres->usage != PIPE_USAGE_IMMUTABLE;
60 }
61 
62 static void
init_valid_range(struct d3d12_resource * res)63 init_valid_range(struct d3d12_resource *res)
64 {
65    if (can_map_directly(&res->base.b))
66       util_range_init(&res->valid_buffer_range);
67 }
68 
69 static void
d3d12_resource_destroy(struct pipe_screen * pscreen,struct pipe_resource * presource)70 d3d12_resource_destroy(struct pipe_screen *pscreen,
71                        struct pipe_resource *presource)
72 {
73    struct d3d12_resource *resource = d3d12_resource(presource);
74 
75    // When instanciating a planar d3d12_resource, the same resource->dt pointer
76    // is copied to all their planes linked list resources
77    // Different instances of objects like d3d12_surface, can be pointing
78    // to different planes of the same overall (ie. NV12) planar d3d12_resource
79    // sharing the same dt, so keep a refcount when destroying them
80    // and only destroy it on the last plane being destroyed
81    if (resource->dt_refcount > 0)
82       resource->dt_refcount--;
83    if ((resource->dt_refcount == 0) && resource->dt)
84    {
85       struct d3d12_screen *screen = d3d12_screen(pscreen);
86       screen->winsys->displaytarget_destroy(screen->winsys, resource->dt);
87    }
88 
89    if (resource->dt_proxy)
90       pipe_resource_reference(&resource->dt_proxy, NULL);
91    threaded_resource_deinit(presource);
92    if (can_map_directly(presource))
93       util_range_destroy(&resource->valid_buffer_range);
94    if (resource->bo)
95       d3d12_bo_unreference(resource->bo);
96    FREE(resource);
97 }
98 
99 static bool
resource_is_busy(struct d3d12_context * ctx,struct d3d12_resource * res,bool want_to_write)100 resource_is_busy(struct d3d12_context *ctx,
101                  struct d3d12_resource *res,
102                  bool want_to_write)
103 {
104    if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write))
105       return true;
106 
107    bool busy = false;
108    d3d12_foreach_submitted_batch(ctx, batch) {
109       if (!d3d12_reset_batch(ctx, batch, 0))
110          busy |= d3d12_batch_has_references(batch, res->bo, want_to_write);
111    }
112    return busy;
113 }
114 
115 void
d3d12_resource_wait_idle(struct d3d12_context * ctx,struct d3d12_resource * res,bool want_to_write)116 d3d12_resource_wait_idle(struct d3d12_context *ctx,
117                          struct d3d12_resource *res,
118                          bool want_to_write)
119 {
120    if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, want_to_write)) {
121       d3d12_flush_cmdlist_and_wait(ctx);
122    } else {
123       d3d12_foreach_submitted_batch(ctx, batch) {
124          if (d3d12_batch_has_references(batch, res->bo, want_to_write))
125             d3d12_reset_batch(ctx, batch, OS_TIMEOUT_INFINITE);
126       }
127    }
128 }
129 
130 void
d3d12_resource_release(struct d3d12_resource * resource)131 d3d12_resource_release(struct d3d12_resource *resource)
132 {
133    if (!resource->bo)
134       return;
135    d3d12_bo_unreference(resource->bo);
136    resource->bo = NULL;
137 }
138 
139 static bool
init_buffer(struct d3d12_screen * screen,struct d3d12_resource * res,const struct pipe_resource * templ)140 init_buffer(struct d3d12_screen *screen,
141             struct d3d12_resource *res,
142             const struct pipe_resource *templ)
143 {
144    struct pb_desc buf_desc;
145    struct pb_manager *bufmgr;
146    struct pb_buffer *buf;
147 
148    /* Assert that we don't want to create a buffer with one of the emulated
149     * formats, these are (currently) only supported when passing the vertex
150     * element state */
151    assert(templ->format == d3d12_emulated_vtx_format(templ->format));
152 
153    if ((templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) &&
154        res->base.b.usage == PIPE_USAGE_DEFAULT)
155    {
156       res->base.b.usage = PIPE_USAGE_STAGING;
157    }
158    switch (res->base.b.usage) {
159    case PIPE_USAGE_DEFAULT:
160    case PIPE_USAGE_IMMUTABLE:
161       bufmgr = screen->cache_bufmgr;
162       buf_desc.usage = (pb_usage_flags)PB_USAGE_GPU_READ_WRITE;
163       break;
164    case PIPE_USAGE_DYNAMIC:
165    case PIPE_USAGE_STREAM:
166       bufmgr = screen->slab_bufmgr;
167       buf_desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ);
168       break;
169    case PIPE_USAGE_STAGING:
170       bufmgr = screen->readback_slab_bufmgr;
171       buf_desc.usage = (pb_usage_flags)(PB_USAGE_GPU_WRITE | PB_USAGE_CPU_READ_WRITE);
172       break;
173    default:
174       unreachable("Invalid pipe usage");
175    }
176 
177    /* We can't suballocate buffers that might be bound as a sampler view, *only*
178     * because in the case of R32G32B32 formats (12 bytes per pixel), it's not possible
179     * to guarantee the offset will be divisible.
180     */
181    if (templ->bind & PIPE_BIND_SAMPLER_VIEW)
182       bufmgr = screen->cache_bufmgr;
183 
184    buf_desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
185    res->dxgi_format = DXGI_FORMAT_UNKNOWN;
186    buf = bufmgr->create_buffer(bufmgr, templ->width0, &buf_desc);
187    if (!buf)
188       return false;
189    res->bo = d3d12_bo_wrap_buffer(screen, buf);
190 
191    return true;
192 }
193 
194 static bool
init_texture(struct d3d12_screen * screen,struct d3d12_resource * res,const struct pipe_resource * templ,ID3D12Heap * heap,uint64_t placed_offset)195 init_texture(struct d3d12_screen *screen,
196              struct d3d12_resource *res,
197              const struct pipe_resource *templ,
198              ID3D12Heap *heap,
199              uint64_t placed_offset)
200 {
201    ID3D12Resource *d3d12_res;
202 
203    res->mip_levels = templ->last_level + 1;
204    res->dxgi_format = d3d12_get_format(templ->format);
205 
206    D3D12_RESOURCE_DESC desc;
207    desc.Format = res->dxgi_format;
208    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
209    desc.Width = templ->width0;
210    desc.Height = templ->height0;
211    desc.DepthOrArraySize = templ->array_size;
212    desc.MipLevels = templ->last_level + 1;
213 
214    desc.SampleDesc.Count = MAX2(templ->nr_samples, 1);
215    desc.SampleDesc.Quality = 0;
216 
217    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
218    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
219 
220    switch (templ->target) {
221    case PIPE_BUFFER:
222       desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
223       desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
224       desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
225       break;
226 
227    case PIPE_TEXTURE_1D:
228    case PIPE_TEXTURE_1D_ARRAY:
229       desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
230       break;
231 
232    case PIPE_TEXTURE_CUBE:
233    case PIPE_TEXTURE_CUBE_ARRAY:
234    case PIPE_TEXTURE_2D:
235    case PIPE_TEXTURE_2D_ARRAY:
236    case PIPE_TEXTURE_RECT:
237       desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
238       break;
239 
240    case PIPE_TEXTURE_3D:
241       desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
242       desc.DepthOrArraySize = templ->depth0;
243       break;
244 
245    default:
246       unreachable("Invalid texture type");
247    }
248 
249    if (templ->bind & PIPE_BIND_SHADER_BUFFER)
250       desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
251 
252    if (templ->bind & PIPE_BIND_RENDER_TARGET)
253       desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
254 
255    if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {
256       desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
257 
258       /* Sadly, we can't set D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE in the
259        * case where PIPE_BIND_SAMPLER_VIEW isn't set, because that would
260        * prevent us from using the resource with u_blitter, which requires
261        * sneaking in sampler-usage throught the back-door.
262        */
263    }
264 
265    if (templ->bind & PIPE_BIND_VIDEO_DECODE_DPB)
266       desc.Flags |= (D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY |
267                      D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
268 
269    if (templ->bind & PIPE_BIND_VIDEO_ENCODE_DPB)
270       desc.Flags |= (D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY |
271                      D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
272 
273    const DXGI_FORMAT *format_cast_list = NULL;
274    uint32_t num_castable_formats = 0;
275 
276    if (screen->opts12.RelaxedFormatCastingSupported) {
277       /* All formats that fall into a cast set need to be castable and accessible as a shader image. */
278       format_cast_list = d3d12_get_format_cast_list(templ->format, &num_castable_formats);
279       if (format_cast_list != nullptr && !util_format_is_compressed(templ->format) &&
280           screen->support_shader_images && templ->nr_samples <= 1) {
281          desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
282       }
283    } else {
284       /* The VA frontend VaFourccToPipeFormat chooses _UNORM types for RGBx formats as typeless formats
285        * such as DXGI_R8G8B8A8_TYPELESS are not supported as Video Processor input/output as specified in:
286        * https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/hardware-support-for-direct3d-12-1-formats
287        * PIPE_BIND_CUSTOM is used by the video frontend to hint this resource will be used in video and the
288        * original format must be not converted to _TYPELESS
289       */
290       if (((templ->bind & PIPE_BIND_CUSTOM) == 0) &&
291           (screen->support_shader_images && templ->nr_samples <= 1)) {
292          /* Ideally, we'd key off of PIPE_BIND_SHADER_IMAGE for this, but it doesn't
293           * seem to be set properly. So, all UAV-capable resources need the UAV flag.
294           */
295          D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { desc.Format };
296          if (SUCCEEDED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
297              (support.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) ==
298              (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) {
299             desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
300             desc.Format = d3d12_get_typeless_format(templ->format);
301          }
302       }
303    }
304 
305    if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR))
306       desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
307 
308    HRESULT hres = E_FAIL;
309    enum d3d12_residency_status init_residency;
310 #ifndef _GAMING_XBOX
311 
312    if (heap && screen->max_feature_level == D3D_FEATURE_LEVEL_1_0_GENERIC) {
313       D3D12_FEATURE_DATA_PLACED_RESOURCE_SUPPORT_INFO capData;
314       capData.Dimension = desc.Dimension;
315       capData.Format = desc.Format;
316       capData.DestHeapProperties = GetDesc(heap).Properties;
317       capData.Supported = false;
318       if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_PLACED_RESOURCE_SUPPORT_INFO, &capData, sizeof(capData))) || !capData.Supported) {
319          debug_printf("D3D12: d3d12_resource_create_or_place cannot place a resource since D3D12_FEATURE_DATA_PLACED_RESOURCE_SUPPORT_INFO is not supported\n");
320          return false;
321       }
322    }
323 
324    if (screen->opts12.RelaxedFormatCastingSupported) {
325       D3D12_RESOURCE_DESC1 desc1 = {
326          desc.Dimension,
327          desc.Alignment,
328          desc.Width,
329          desc.Height,
330          desc.DepthOrArraySize,
331          desc.MipLevels,
332          desc.Format,
333          desc.SampleDesc,
334          desc.Layout,
335          desc.Flags,
336       };
337       if (heap) {
338          init_residency = d3d12_permanently_resident;
339          hres = screen->dev10->CreatePlacedResource2(heap,
340                                                      placed_offset,
341                                                      &desc1,
342                                                      D3D12_BARRIER_LAYOUT_COMMON,
343                                                      nullptr,
344                                                      num_castable_formats,
345                                                      format_cast_list,
346                                                      IID_PPV_ARGS(&d3d12_res));
347       }
348       else {
349          D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(screen->dev, D3D12_HEAP_TYPE_DEFAULT);
350 
351          D3D12_HEAP_FLAGS heap_flags = screen->support_create_not_resident ?
352             D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT : D3D12_HEAP_FLAG_NONE;
353          init_residency = screen->support_create_not_resident ? d3d12_evicted : d3d12_resident;
354 
355          hres = screen->dev10->CreateCommittedResource3(&heap_pris,
356                                                         heap_flags,
357                                                         &desc1,
358                                                         D3D12_BARRIER_LAYOUT_COMMON,
359                                                         nullptr,
360                                                         nullptr,
361                                                         num_castable_formats,
362                                                         format_cast_list,
363                                                         IID_PPV_ARGS(&d3d12_res));
364       }
365    } else
366 #endif
367    {
368       if (heap) {
369          init_residency = d3d12_permanently_resident;
370          hres = screen->dev->CreatePlacedResource(heap,
371                                                   placed_offset,
372                                                   &desc,
373                                                   D3D12_RESOURCE_STATE_COMMON,
374                                                   nullptr,
375                                                   IID_PPV_ARGS(&d3d12_res));
376       } else {
377          D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(screen->dev, D3D12_HEAP_TYPE_DEFAULT);
378 
379          D3D12_HEAP_FLAGS heap_flags = screen->support_create_not_resident ?
380             D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT : D3D12_HEAP_FLAG_NONE;
381          init_residency = screen->support_create_not_resident ? d3d12_evicted : d3d12_resident;
382 
383          hres = screen->dev->CreateCommittedResource(&heap_pris,
384                                                      heap_flags,
385                                                      &desc,
386                                                      D3D12_RESOURCE_STATE_COMMON,
387                                                      NULL,
388                                                      IID_PPV_ARGS(&d3d12_res));
389       }
390    }
391 
392    if (FAILED(hres))
393       return false;
394 
395    if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) {
396       struct sw_winsys *winsys = screen->winsys;
397       if (winsys->is_displaytarget_format_supported(winsys, res->base.b.bind, res->base.b.format)) {
398          res->dt = winsys->displaytarget_create(screen->winsys,
399                                                 res->base.b.bind,
400                                                 res->base.b.format,
401                                                 templ->width0,
402                                                 templ->height0,
403                                                 64, NULL,
404                                                 &res->dt_stride);
405          res->dt_refcount = 1;
406       } else {
407          assert(res->base.b.format == PIPE_FORMAT_R16G16B16A16_FLOAT); /* The only format we proxy right now */
408          struct pipe_resource proxy_templ = *templ;
409          proxy_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
410          res->dt_proxy = screen->base.resource_create(&screen->base, &proxy_templ);
411          if (!res->dt_proxy)
412             return false;
413          assert(d3d12_resource(res->dt_proxy)->dt);
414       }
415    }
416 
417    res->bo = d3d12_bo_wrap_res(screen, d3d12_res, init_residency);
418 
419    return true;
420 }
421 
422 static void
convert_planar_resource(struct d3d12_resource * res)423 convert_planar_resource(struct d3d12_resource *res)
424 {
425    unsigned num_planes = util_format_get_num_planes(res->base.b.format);
426    if (num_planes <= 1 || res->base.b.next || !res->bo)
427       return;
428 
429    struct pipe_resource *next = nullptr;
430    struct pipe_resource *planes[3] = {
431       &res->base.b, nullptr, nullptr
432    };
433    for (int plane = num_planes - 1; plane >= 0; --plane) {
434       struct d3d12_resource *plane_res = d3d12_resource(planes[plane]);
435       if (!plane_res) {
436          plane_res = CALLOC_STRUCT(d3d12_resource);
437          *plane_res = *res;
438          plane_res->dt_refcount = num_planes;
439          d3d12_bo_reference(plane_res->bo);
440          pipe_reference_init(&plane_res->base.b.reference, 1);
441          threaded_resource_init(&plane_res->base.b, false);
442       }
443 
444       plane_res->base.b.next = next;
445       next = &plane_res->base.b;
446 
447       plane_res->plane_slice = plane;
448       plane_res->base.b.format = util_format_get_plane_format(res->base.b.format, plane);
449       plane_res->base.b.width0 = util_format_get_plane_width(res->base.b.format, plane, res->base.b.width0);
450       plane_res->base.b.height0 = util_format_get_plane_height(res->base.b.format, plane, res->base.b.height0);
451 
452 #if MESA_DEBUG
453       struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
454       D3D12_RESOURCE_DESC desc = GetDesc(res->bo->res);
455       desc.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
456       D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {};
457       D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint;
458       unsigned subresource = plane * desc.MipLevels * desc.DepthOrArraySize;
459       screen->dev->GetCopyableFootprints(&desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr);
460       assert(plane_res->base.b.width0 == footprint->Width);
461       assert(plane_res->base.b.height0 == footprint->Height);
462       assert(plane_res->base.b.depth0 == footprint->Depth);
463       assert(plane_res->first_plane == &res->base.b);
464 #endif
465    }
466 }
467 
468 static struct pipe_resource *
d3d12_resource_create_or_place(struct d3d12_screen * screen,struct d3d12_resource * res,const struct pipe_resource * templ,ID3D12Heap * heap,uint64_t placed_offset)469 d3d12_resource_create_or_place(struct d3d12_screen *screen,
470                                struct d3d12_resource *res,
471                                const struct pipe_resource *templ,
472                                ID3D12Heap *heap,
473                                uint64_t placed_offset)
474 {
475    bool ret;
476 
477    res->base.b = *templ;
478 
479    res->overall_format = templ->format;
480    res->plane_slice = 0;
481    res->first_plane = &res->base.b;
482 
483    if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
484       debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n",
485                    templ->usage == PIPE_USAGE_STAGING ? "STAGING " :"",
486                    util_format_name(templ->format), templ->nr_samples,
487                    templ->width0, templ->height0, templ->depth0,
488                    templ->array_size, templ->last_level);
489    }
490 
491    pipe_reference_init(&res->base.b.reference, 1);
492    res->base.b.screen = &screen->base;
493 
494    if (templ->target == PIPE_BUFFER && !heap) {
495       ret = init_buffer(screen, res, templ);
496    } else {
497       ret = init_texture(screen, res, templ, heap, placed_offset);
498    }
499 
500    if (!ret) {
501       FREE(res);
502       return NULL;
503    }
504 
505    init_valid_range(res);
506    threaded_resource_init(&res->base.b,
507       templ->usage == PIPE_USAGE_DEFAULT &&
508       templ->target == PIPE_BUFFER);
509 
510    memset(&res->bind_counts, 0, sizeof(d3d12_resource::bind_counts));
511 
512    convert_planar_resource(res);
513 
514    return &res->base.b;
515 }
516 
517 static struct pipe_resource *
d3d12_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ)518 d3d12_resource_create(struct pipe_screen *pscreen,
519                       const struct pipe_resource *templ)
520 {
521    struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
522    if (!res)
523       return NULL;
524 
525    return d3d12_resource_create_or_place(d3d12_screen(pscreen), res, templ, nullptr, 0);
526 }
527 
528 static struct pipe_resource *
d3d12_resource_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct winsys_handle * handle,unsigned usage)529 d3d12_resource_from_handle(struct pipe_screen *pscreen,
530                           const struct pipe_resource *templ,
531                           struct winsys_handle *handle, unsigned usage)
532 {
533    struct d3d12_screen *screen = d3d12_screen(pscreen);
534    if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES &&
535        handle->type != WINSYS_HANDLE_TYPE_FD &&
536        handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME)
537       return NULL;
538 
539    struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
540    if (!res)
541       return NULL;
542 
543    if (templ && templ->next) {
544       struct d3d12_resource* next = d3d12_resource(templ->next);
545       if (next->bo) {
546          res->base.b = *templ;
547          res->bo = next->bo;
548          d3d12_bo_reference(res->bo);
549       }
550    }
551 
552 #ifdef _WIN32
553    HANDLE d3d_handle = handle->handle;
554 #else
555    HANDLE d3d_handle = (HANDLE) (intptr_t) handle->handle;
556 #endif
557 
558 #ifndef _GAMING_XBOX
559    if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
560       ComPtr<IUnknown> screen_device;
561       ComPtr<IUnknown> res_device;
562       screen->dev->QueryInterface(screen_device.GetAddressOf());
563       ((ID3D12DeviceChild *)handle->com_obj)->GetDevice(IID_PPV_ARGS(res_device.GetAddressOf()));
564 
565       if (screen_device.Get() != res_device.Get()) {
566          debug_printf("d3d12: Importing resource - Resource's parent device (%p) does not"
567                       " match d3d12 device (%p) instance from this pipe_screen."
568                       " Attempting to re-import via NT Handle...\n", screen_device.Get(), res_device.Get());
569 
570          handle->type = WINSYS_HANDLE_TYPE_FD;
571          HRESULT hr = screen->dev->CreateSharedHandle(((ID3D12DeviceChild *)handle->com_obj),
572                nullptr,
573                GENERIC_ALL,
574                nullptr,
575                &d3d_handle);
576 
577          if (FAILED(hr)) {
578             debug_printf("d3d12: Error %x - Couldn't export incoming resource com_obj "
579                          "(%p) via shared NT handle.\n", hr, handle->com_obj);
580             return NULL;
581          }
582       }
583    }
584 #endif
585 
586 #ifdef _WIN32
587    HANDLE d3d_handle_to_close = nullptr;
588    if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) {
589       screen->dev->OpenSharedHandleByName((LPCWSTR)handle->name, GENERIC_ALL, &d3d_handle_to_close);
590       d3d_handle = d3d_handle_to_close;
591    }
592 #endif
593 
594    ID3D12Resource *d3d12_res = nullptr;
595    ID3D12Heap *d3d12_heap = nullptr;
596    if (res->bo) {
597       d3d12_res = res->bo->res;
598    } else if (handle->type == WINSYS_HANDLE_TYPE_D3D12_RES) {
599       if (handle->modifier == 1) {
600          d3d12_heap = (ID3D12Heap *) handle->com_obj;
601       } else {
602          d3d12_res = (ID3D12Resource *) handle->com_obj;
603       }
604    } else {
605       screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&d3d12_res));
606    }
607 
608 #ifdef _WIN32
609    if (d3d_handle_to_close) {
610       CloseHandle(d3d_handle_to_close);
611    }
612 #endif
613 
614    D3D12_PLACED_SUBRESOURCE_FOOTPRINT placed_footprint = {};
615    D3D12_SUBRESOURCE_FOOTPRINT *footprint = &placed_footprint.Footprint;
616    D3D12_RESOURCE_DESC incoming_res_desc;
617 
618    if (!d3d12_res && !d3d12_heap)
619       goto invalid;
620 
621    if (d3d12_heap) {
622       assert(templ);
623       assert(!res->bo);
624       assert(!d3d12_res);
625       return d3d12_resource_create_or_place(screen, res, templ, d3d12_heap, handle->offset);
626    }
627 
628    pipe_reference_init(&res->base.b.reference, 1);
629    res->base.b.screen = pscreen;
630    incoming_res_desc = GetDesc(d3d12_res);
631 
632    /* Get a description for this plane */
633    if (templ && handle->format != templ->format) {
634       unsigned subresource = handle->plane * incoming_res_desc.MipLevels * incoming_res_desc.DepthOrArraySize;
635       auto temp_desc = incoming_res_desc;
636       temp_desc.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
637       screen->dev->GetCopyableFootprints(&temp_desc, subresource, 1, 0, &placed_footprint, nullptr, nullptr, nullptr);
638    } else {
639       footprint->Format = incoming_res_desc.Format;
640       footprint->Width = incoming_res_desc.Width;
641       footprint->Height = incoming_res_desc.Height;
642       footprint->Depth = incoming_res_desc.DepthOrArraySize;
643    }
644 
645    if (footprint->Width > UINT32_MAX ||
646        footprint->Height > UINT16_MAX) {
647       debug_printf("d3d12: Importing resource too large\n");
648       goto invalid;
649    }
650    res->base.b.width0 = incoming_res_desc.Width;
651    res->base.b.height0 = incoming_res_desc.Height;
652    res->base.b.depth0 = 1;
653    res->base.b.array_size = 1;
654 
655    switch (incoming_res_desc.Dimension) {
656    case D3D12_RESOURCE_DIMENSION_BUFFER:
657       res->base.b.target = PIPE_BUFFER;
658       res->base.b.bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_CONSTANT_BUFFER |
659          PIPE_BIND_INDEX_BUFFER | PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_SHADER_BUFFER |
660          PIPE_BIND_COMMAND_ARGS_BUFFER | PIPE_BIND_QUERY_BUFFER;
661       break;
662    case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
663       res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
664          PIPE_TEXTURE_1D_ARRAY : PIPE_TEXTURE_1D;
665       res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
666       break;
667    case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
668       res->base.b.target = incoming_res_desc.DepthOrArraySize > 1 ?
669          PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
670       res->base.b.array_size = incoming_res_desc.DepthOrArraySize;
671       break;
672    case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
673       res->base.b.target = PIPE_TEXTURE_3D;
674       res->base.b.depth0 = footprint->Depth;
675       break;
676    default:
677       unreachable("Invalid dimension");
678       break;
679    }
680    res->base.b.nr_samples = incoming_res_desc.SampleDesc.Count;
681    res->base.b.last_level = incoming_res_desc.MipLevels - 1;
682    res->base.b.usage = PIPE_USAGE_DEFAULT;
683    res->base.b.bind |= PIPE_BIND_SHARED;
684    if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
685       res->base.b.bind |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE | PIPE_BIND_DISPLAY_TARGET;
686    if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
687       res->base.b.bind |= PIPE_BIND_DEPTH_STENCIL;
688    if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
689       res->base.b.bind |= PIPE_BIND_SHADER_IMAGE;
690    if ((incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == D3D12_RESOURCE_FLAG_NONE)
691       res->base.b.bind |= PIPE_BIND_SAMPLER_VIEW;
692    if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_VIDEO_DECODE_REFERENCE_ONLY)
693       res->base.b.bind |= PIPE_BIND_VIDEO_DECODE_DPB;
694    if (incoming_res_desc.Flags & D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY)
695       res->base.b.bind |= PIPE_BIND_VIDEO_ENCODE_DPB;
696 
697    if (templ) {
698       if (res->base.b.target == PIPE_TEXTURE_2D_ARRAY &&
699             (templ->target == PIPE_TEXTURE_CUBE ||
700              templ->target == PIPE_TEXTURE_CUBE_ARRAY)) {
701          if (res->base.b.array_size < 6) {
702             debug_printf("d3d12: Importing cube resource with too few array layers\n");
703             goto invalid;
704          }
705          res->base.b.target = templ->target;
706          res->base.b.array_size /= 6;
707       }
708       unsigned templ_samples = MAX2(templ->nr_samples, 1);
709       if (res->base.b.target != templ->target ||
710           footprint->Width != templ->width0 ||
711           footprint->Height != templ->height0 ||
712           footprint->Depth != templ->depth0 ||
713           res->base.b.array_size != templ->array_size ||
714           incoming_res_desc.SampleDesc.Count != templ_samples ||
715           res->base.b.last_level != templ->last_level) {
716          debug_printf("d3d12: Importing resource with mismatched dimensions: "
717             "plane: %d, target: %d vs %d, width: %d vs %d, height: %d vs %d, "
718             "depth: %d vs %d, array_size: %d vs %d, samples: %d vs %d, mips: %d vs %d\n",
719             handle->plane,
720             res->base.b.target, templ->target,
721             footprint->Width, templ->width0,
722             footprint->Height, templ->height0,
723             footprint->Depth, templ->depth0,
724             res->base.b.array_size, templ->array_size,
725             incoming_res_desc.SampleDesc.Count, templ_samples,
726             res->base.b.last_level + 1, templ->last_level + 1);
727          goto invalid;
728       }
729       if (templ->target != PIPE_BUFFER) {
730          if ((footprint->Format != d3d12_get_format(templ->format) &&
731               footprint->Format != d3d12_get_typeless_format(templ->format)) ||
732              (incoming_res_desc.Format != d3d12_get_format((enum pipe_format)handle->format) &&
733               incoming_res_desc.Format != d3d12_get_typeless_format((enum pipe_format)handle->format))) {
734             debug_printf("d3d12: Importing resource with mismatched format: "
735                "plane could be DXGI format %d or %d, but is %d, "
736                "overall could be DXGI format %d or %d, but is %d\n",
737                d3d12_get_format(templ->format),
738                d3d12_get_typeless_format(templ->format),
739                footprint->Format,
740                d3d12_get_format((enum pipe_format)handle->format),
741                d3d12_get_typeless_format((enum pipe_format)handle->format),
742                incoming_res_desc.Format);
743             goto invalid;
744          }
745       }
746       /* In an ideal world we'd be able to validate this, but gallium's use of bind
747        * flags during resource creation is pretty bad: some bind flags are always set
748        * (like PIPE_BIND_RENDER_TARGET) while others are never set (PIPE_BIND_SHADER_BUFFER)
749        *
750       if (templ->bind & ~res->base.b.bind) {
751          debug_printf("d3d12: Imported resource doesn't have necessary bind flags\n");
752          goto invalid;
753       } */
754 
755       res->base.b.format = templ->format;
756       res->overall_format = (enum pipe_format)handle->format;
757    } else {
758       /* Search the pipe format lookup table for an entry */
759       res->base.b.format = d3d12_get_pipe_format(incoming_res_desc.Format);
760 
761       if (res->base.b.format == PIPE_FORMAT_NONE) {
762          /* Convert from typeless to a reasonable default */
763          if (incoming_res_desc.Format == DXGI_FORMAT_UNKNOWN)
764             res->base.b.format = PIPE_FORMAT_R8_UNORM;
765          else
766             res->base.b.format = d3d12_get_default_pipe_format(incoming_res_desc.Format);
767 
768          if (res->base.b.format == PIPE_FORMAT_NONE) {
769             debug_printf("d3d12: Unable to deduce non-typeless resource format %d\n", incoming_res_desc.Format);
770             goto invalid;
771          }
772       }
773 
774       res->overall_format = res->base.b.format;
775    }
776 
777    if (!templ)
778       handle->format = res->overall_format;
779 
780    res->dxgi_format = d3d12_get_format(res->overall_format);
781    res->plane_slice = handle->plane;
782    res->first_plane = &res->base.b;
783 
784    if (!res->bo) {
785       res->bo = d3d12_bo_wrap_res(screen, d3d12_res, d3d12_permanently_resident);
786    }
787    init_valid_range(res);
788 
789    threaded_resource_init(&res->base.b, false);
790    convert_planar_resource(res);
791 
792    return &res->base.b;
793 
794 invalid:
795    if (res->bo)
796       d3d12_bo_unreference(res->bo);
797    else if (d3d12_res)
798       d3d12_res->Release();
799    FREE(res);
800    return NULL;
801 }
802 
803 static bool
d3d12_resource_get_handle(struct pipe_screen * pscreen,struct pipe_context * pcontext,struct pipe_resource * pres,struct winsys_handle * handle,unsigned usage)804 d3d12_resource_get_handle(struct pipe_screen *pscreen,
805                           struct pipe_context *pcontext,
806                           struct pipe_resource *pres,
807                           struct winsys_handle *handle,
808                           unsigned usage)
809 {
810    struct d3d12_resource *res = d3d12_resource(pres);
811    struct d3d12_screen *screen = d3d12_screen(pscreen);
812 
813    switch (handle->type) {
814    case WINSYS_HANDLE_TYPE_D3D12_RES:
815       handle->com_obj = d3d12_resource_resource(res);
816       return true;
817    case WINSYS_HANDLE_TYPE_FD: {
818       HANDLE d3d_handle = nullptr;
819 
820       screen->dev->CreateSharedHandle(d3d12_resource_resource(res),
821                                       nullptr,
822                                       GENERIC_ALL,
823                                       nullptr,
824                                       &d3d_handle);
825       if (!d3d_handle)
826          return false;
827 
828 #ifdef _WIN32
829       handle->handle = d3d_handle;
830 #else
831       handle->handle = (int)(intptr_t)d3d_handle;
832 #endif
833       handle->format = pres->format;
834       handle->modifier = ~0ull;
835       return true;
836    }
837    default:
838       return false;
839    }
840 }
841 
842 struct pipe_resource *
d3d12_resource_from_resource(struct pipe_screen * pscreen,ID3D12Resource * input_res)843 d3d12_resource_from_resource(struct pipe_screen *pscreen,
844                               ID3D12Resource* input_res)
845 {
846     D3D12_RESOURCE_DESC input_desc = GetDesc(input_res);
847     struct winsys_handle handle;
848     memset(&handle, 0, sizeof(handle));
849     handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
850     handle.format = d3d12_get_pipe_format(input_desc.Format);
851     handle.com_obj = input_res;
852     input_res->AddRef();
853 
854     struct pipe_resource templ;
855     memset(&templ, 0, sizeof(templ));
856     if(input_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
857        templ.target = PIPE_BUFFER;
858     } else {
859       templ.target = (input_desc.DepthOrArraySize > 1) ? PIPE_TEXTURE_2D_ARRAY : PIPE_TEXTURE_2D;
860     }
861 
862     templ.format = d3d12_get_pipe_format(input_desc.Format);
863     templ.width0 = input_desc.Width;
864     templ.height0 = input_desc.Height;
865     templ.depth0 = input_desc.DepthOrArraySize;
866     templ.array_size = input_desc.DepthOrArraySize;
867     templ.flags = 0;
868 
869     return d3d12_resource_from_handle(
870         pscreen,
871         &templ,
872         &handle,
873         PIPE_USAGE_DEFAULT
874     );
875 }
876 
877 /**
878  * On Map/Unmap operations, we readback or flush all the underlying planes
879  * of planar resources. The map/unmap operation from the caller is
880  * expected to be done for res->plane_slice plane only, but some
881  * callers expect adjacent allocations for next contiguous plane access
882  *
883  * In this function, we take the res and box the caller passed, and the plane_* properties
884  * that are currently being readback/flushed, and adjust the d3d12_transfer ptrans
885  * accordingly for the GPU copy operation between planes.
886  */
d3d12_adjust_transfer_dimensions_for_plane(const struct d3d12_resource * res,unsigned plane_slice,unsigned plane_stride,unsigned plane_layer_stride,unsigned plane_offset,const struct pipe_box * original_box,struct pipe_transfer * ptrans)887 static void d3d12_adjust_transfer_dimensions_for_plane(const struct d3d12_resource *res,
888                                                        unsigned plane_slice,
889                                                        unsigned plane_stride,
890                                                        unsigned plane_layer_stride,
891                                                        unsigned plane_offset,
892                                                        const struct pipe_box* original_box,
893                                                        struct pipe_transfer *ptrans/*inout*/)
894 {
895    /* Adjust strides, offsets to the corresponding plane*/
896    ptrans->stride = plane_stride;
897    ptrans->layer_stride = plane_layer_stride;
898    ptrans->offset = plane_offset;
899 
900    /* Find multipliers such that:*/
901    /* first_plane.width = width_multiplier * planes[res->plane_slice].width*/
902    /* first_plane.height = height_multiplier * planes[res->plane_slice].height*/
903    float width_multiplier = res->first_plane->width0 / (float) util_format_get_plane_width(res->overall_format, res->plane_slice, res->first_plane->width0);
904    float height_multiplier = res->first_plane->height0 / (float) util_format_get_plane_height(res->overall_format, res->plane_slice, res->first_plane->height0);
905 
906    /* Normalize box back to overall dimensions (first plane)*/
907    ptrans->box.width = width_multiplier * original_box->width;
908    ptrans->box.height = height_multiplier * original_box->height;
909    ptrans->box.x = width_multiplier * original_box->x;
910    ptrans->box.y = height_multiplier * original_box->y;
911 
912    /* Now adjust dimensions to plane_slice*/
913    ptrans->box.width = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.width);
914    ptrans->box.height = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.height);
915    ptrans->box.x = util_format_get_plane_width(res->overall_format, plane_slice, ptrans->box.x);
916    ptrans->box.y = util_format_get_plane_height(res->overall_format, plane_slice, ptrans->box.y);
917 }
918 
919 static
d3d12_resource_get_planes_info(pipe_resource * pres,unsigned num_planes,pipe_resource ** planes,unsigned * strides,unsigned * layer_strides,unsigned * offsets,unsigned * staging_res_size)920 void d3d12_resource_get_planes_info(pipe_resource *pres,
921                                     unsigned num_planes,
922                                     pipe_resource **planes,
923                                     unsigned *strides,
924                                     unsigned *layer_strides,
925                                     unsigned *offsets,
926                                     unsigned *staging_res_size)
927 {
928    struct d3d12_resource* res = d3d12_resource(pres);
929    *staging_res_size = 0;
930    struct pipe_resource *cur_plane_resource = res->first_plane;
931    for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
932       planes[plane_slice] = cur_plane_resource;
933       int width = util_format_get_plane_width(res->base.b.format, plane_slice, res->first_plane->width0);
934       int height = util_format_get_plane_height(res->base.b.format, plane_slice, res->first_plane->height0);
935 
936       strides[plane_slice] = align(util_format_get_stride(cur_plane_resource->format, width),
937                            D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
938 
939       layer_strides[plane_slice] = align(util_format_get_2d_size(cur_plane_resource->format,
940                                                    strides[plane_slice],
941                                                    height),
942                                  D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
943 
944       offsets[plane_slice] = *staging_res_size;
945       *staging_res_size += layer_strides[plane_slice];
946       cur_plane_resource = cur_plane_resource->next;
947    }
948 }
949 
950 static constexpr unsigned d3d12_max_planes = 3;
951 
952 /**
953  * Get stride and offset for the given pipe resource without the need to get
954  * a winsys_handle.
955  */
956 void
d3d12_resource_get_info(struct pipe_screen * pscreen,struct pipe_resource * pres,unsigned * stride,unsigned * offset)957 d3d12_resource_get_info(struct pipe_screen *pscreen,
958                         struct pipe_resource *pres,
959                         unsigned *stride,
960                         unsigned *offset)
961 {
962 
963    struct d3d12_resource* res = d3d12_resource(pres);
964    unsigned num_planes = util_format_get_num_planes(res->overall_format);
965 
966    pipe_resource *planes[d3d12_max_planes];
967    unsigned int strides[d3d12_max_planes];
968    unsigned int layer_strides[d3d12_max_planes];
969    unsigned int offsets[d3d12_max_planes];
970    unsigned staging_res_size = 0;
971    d3d12_resource_get_planes_info(
972       pres,
973       num_planes,
974       planes,
975       strides,
976       layer_strides,
977       offsets,
978       &staging_res_size
979    );
980 
981    if(stride) {
982       *stride = strides[res->plane_slice];
983    }
984 
985    if(offset) {
986       *offset = offsets[res->plane_slice];
987    }
988 }
989 
990 static struct pipe_memory_object *
d3d12_memobj_create_from_handle(struct pipe_screen * pscreen,struct winsys_handle * handle,bool dedicated)991 d3d12_memobj_create_from_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, bool dedicated)
992 {
993    if (handle->type != WINSYS_HANDLE_TYPE_WIN32_HANDLE &&
994        handle->type != WINSYS_HANDLE_TYPE_WIN32_NAME) {
995       debug_printf("d3d12: Unsupported memobj handle type\n");
996       return NULL;
997    }
998 
999    struct d3d12_screen *screen = d3d12_screen(pscreen);
1000 #ifdef _GAMING_XBOX
1001    IGraphicsUnknown
1002 #else
1003    IUnknown
1004 #endif
1005       *obj;
1006 #ifdef _WIN32
1007       HANDLE d3d_handle = handle->handle;
1008 #else
1009       HANDLE d3d_handle = (HANDLE)(intptr_t)handle->handle;
1010 #endif
1011 
1012 #ifdef _WIN32
1013       HANDLE d3d_handle_to_close = nullptr;
1014       if (handle->type == WINSYS_HANDLE_TYPE_WIN32_NAME) {
1015          screen->dev->OpenSharedHandleByName((LPCWSTR) handle->name, GENERIC_ALL, &d3d_handle_to_close);
1016          d3d_handle = d3d_handle_to_close;
1017       }
1018 #endif
1019 
1020    screen->dev->OpenSharedHandle(d3d_handle, IID_PPV_ARGS(&obj));
1021 
1022 #ifdef _WIN32
1023    if (d3d_handle_to_close) {
1024       CloseHandle(d3d_handle_to_close);
1025    }
1026 #endif
1027 
1028    if (!obj) {
1029       debug_printf("d3d12: Failed to open memobj handle as anything\n");
1030       return NULL;
1031    }
1032 
1033    struct d3d12_memory_object *memobj = CALLOC_STRUCT(d3d12_memory_object);
1034    if (!memobj) {
1035       obj->Release();
1036       return NULL;
1037    }
1038    memobj->base.dedicated = dedicated;
1039 
1040    obj->AddRef();
1041    if (handle->modifier == 1) {
1042       memobj->heap = (ID3D12Heap *) obj;
1043    } else {
1044       memobj->res = (ID3D12Resource *) obj;
1045    }
1046 
1047    obj->Release();
1048    if (!memobj->res && !memobj->heap) {
1049       debug_printf("d3d12: Memory object isn't a resource or heap\n");
1050       free(memobj);
1051       return NULL;
1052    }
1053 
1054    bool expect_dedicated = memobj->res != nullptr;
1055    if (dedicated != expect_dedicated)
1056       debug_printf("d3d12: Expected dedicated to be %s for imported %s\n",
1057                    expect_dedicated ? "true" : "false",
1058                    expect_dedicated ? "resource" : "heap");
1059 
1060    return &memobj->base;
1061 }
1062 
1063 static void
d3d12_memobj_destroy(struct pipe_screen * pscreen,struct pipe_memory_object * pmemobj)1064 d3d12_memobj_destroy(struct pipe_screen *pscreen, struct pipe_memory_object *pmemobj)
1065 {
1066    struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj);
1067    if (memobj->res)
1068       memobj->res->Release();
1069    if (memobj->heap)
1070       memobj->heap->Release();
1071    free(memobj);
1072 }
1073 
1074 static pipe_resource *
d3d12_resource_from_memobj(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct pipe_memory_object * pmemobj,uint64_t offset)1075 d3d12_resource_from_memobj(struct pipe_screen *pscreen,
1076                            const struct pipe_resource *templ,
1077                            struct pipe_memory_object *pmemobj,
1078                            uint64_t offset)
1079 {
1080    struct d3d12_memory_object *memobj = d3d12_memory_object(pmemobj);
1081 
1082    struct winsys_handle whandle = {};
1083    whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
1084    whandle.com_obj = memobj->res ? (void *) memobj->res : (void *) memobj->heap;
1085    whandle.offset = offset;
1086    whandle.format = templ->format;
1087    whandle.modifier = memobj->res ? 0 : 1;
1088 
1089    // WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference
1090    ((IUnknown *)whandle.com_obj)->AddRef();
1091    return d3d12_resource_from_handle(pscreen, templ, &whandle, 0);
1092 }
1093 
1094 void
d3d12_screen_resource_init(struct pipe_screen * pscreen)1095 d3d12_screen_resource_init(struct pipe_screen *pscreen)
1096 {
1097    pscreen->resource_create = d3d12_resource_create;
1098    pscreen->resource_from_handle = d3d12_resource_from_handle;
1099    pscreen->resource_get_handle = d3d12_resource_get_handle;
1100    pscreen->resource_destroy = d3d12_resource_destroy;
1101    pscreen->resource_get_info = d3d12_resource_get_info;
1102 
1103    pscreen->memobj_create_from_handle = d3d12_memobj_create_from_handle;
1104    pscreen->memobj_destroy = d3d12_memobj_destroy;
1105    pscreen->resource_from_memobj = d3d12_resource_from_memobj;
1106 }
1107 
1108 unsigned int
get_subresource_id(struct d3d12_resource * res,unsigned resid,unsigned z,unsigned base_level)1109 get_subresource_id(struct d3d12_resource *res, unsigned resid,
1110                    unsigned z, unsigned base_level)
1111 {
1112    unsigned resource_stride = (res->base.b.last_level + 1) * res->base.b.array_size;
1113    unsigned layer_stride = res->base.b.last_level + 1;
1114 
1115    return resid * resource_stride + z * layer_stride +
1116          base_level + res->plane_slice * resource_stride;
1117 }
1118 
1119 static D3D12_TEXTURE_COPY_LOCATION
fill_texture_location(struct d3d12_resource * res,struct d3d12_transfer * trans,unsigned resid,unsigned z)1120 fill_texture_location(struct d3d12_resource *res,
1121                       struct d3d12_transfer *trans, unsigned resid, unsigned z)
1122 {
1123    D3D12_TEXTURE_COPY_LOCATION tex_loc = {0};
1124    int subres = get_subresource_id(res, resid, z, trans->base.b.level);
1125 
1126    tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
1127    tex_loc.SubresourceIndex = subres;
1128    tex_loc.pResource = d3d12_resource_resource(res);
1129    return tex_loc;
1130 }
1131 
1132 static D3D12_TEXTURE_COPY_LOCATION
fill_buffer_location(struct d3d12_context * ctx,struct d3d12_resource * res,struct d3d12_resource * staging_res,struct d3d12_transfer * trans,unsigned depth,unsigned resid,unsigned z)1133 fill_buffer_location(struct d3d12_context *ctx,
1134                      struct d3d12_resource *res,
1135                      struct d3d12_resource *staging_res,
1136                      struct d3d12_transfer *trans,
1137                      unsigned depth,
1138                      unsigned resid, unsigned z)
1139 {
1140    D3D12_TEXTURE_COPY_LOCATION buf_loc = {0};
1141    D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
1142    uint64_t offset = 0;
1143    auto descr = GetDesc(d3d12_resource_underlying(res, &offset));
1144    descr.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
1145    struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
1146    ID3D12Device* dev = screen->dev;
1147 
1148    unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.b.level);
1149    dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr);
1150 
1151    buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
1152    buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);
1153    buf_loc.PlacedFootprint = footprint;
1154    buf_loc.PlacedFootprint.Offset = offset;
1155    buf_loc.PlacedFootprint.Offset += trans->base.b.offset;
1156 
1157    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1158        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1159       buf_loc.PlacedFootprint.Footprint.Width = res->base.b.width0;
1160       buf_loc.PlacedFootprint.Footprint.Height = res->base.b.height0;
1161       buf_loc.PlacedFootprint.Footprint.Depth = res->base.b.depth0;
1162    } else {
1163       buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.b.box.width,
1164                                                       util_format_get_blockwidth(res->base.b.format));
1165       buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.b.box.height,
1166                                                        util_format_get_blockheight(res->base.b.format));
1167       buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth,
1168                                                       util_format_get_blockdepth(res->base.b.format));
1169    }
1170 
1171    buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.b.stride;
1172 
1173    return buf_loc;
1174 }
1175 
1176 struct copy_info {
1177    struct d3d12_resource *dst;
1178    D3D12_TEXTURE_COPY_LOCATION dst_loc;
1179    UINT dst_x, dst_y, dst_z;
1180    struct d3d12_resource *src;
1181    D3D12_TEXTURE_COPY_LOCATION src_loc;
1182    D3D12_BOX *src_box;
1183 };
1184 
1185 
1186 static void
copy_texture_region(struct d3d12_context * ctx,struct copy_info & info)1187 copy_texture_region(struct d3d12_context *ctx,
1188                     struct copy_info& info)
1189 {
1190    auto batch = d3d12_current_batch(ctx);
1191 
1192    d3d12_batch_reference_resource(batch, info.src, false);
1193    d3d12_batch_reference_resource(batch, info.dst, true);
1194    d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1195    d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1196    d3d12_apply_resource_states(ctx, false);
1197    ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z,
1198                                    &info.src_loc, info.src_box);
1199 }
1200 
1201 static void
transfer_buf_to_image_part(struct d3d12_context * ctx,struct d3d12_resource * res,struct d3d12_resource * staging_res,struct d3d12_transfer * trans,int z,int depth,int start_z,int dest_z,int resid)1202 transfer_buf_to_image_part(struct d3d12_context *ctx,
1203                            struct d3d12_resource *res,
1204                            struct d3d12_resource *staging_res,
1205                            struct d3d12_transfer *trans,
1206                            int z, int depth, int start_z, int dest_z,
1207                            int resid)
1208 {
1209    if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
1210       debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n",
1211                    trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
1212                    trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
1213                    util_format_name(staging_res->base.b.format),
1214                    util_format_name(res->base.b.format));
1215    }
1216 
1217    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1218    struct copy_info copy_info;
1219    copy_info.src = staging_res;
1220    copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z);
1221    copy_info.src_loc.PlacedFootprint.Offset += (z  - start_z) * trans->base.b.layer_stride;
1222    copy_info.src_box = nullptr;
1223    copy_info.dst = res;
1224    copy_info.dst_loc = fill_texture_location(res, trans, resid, z);
1225    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1226        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1227       copy_info.dst_x = 0;
1228       copy_info.dst_y = 0;
1229    } else {
1230       copy_info.dst_x = trans->base.b.box.x;
1231       copy_info.dst_y = trans->base.b.box.y;
1232    }
1233    copy_info.dst_z = res->base.b.target == PIPE_TEXTURE_CUBE ? 0 : dest_z;
1234    copy_info.src_box = nullptr;
1235 
1236    copy_texture_region(ctx, copy_info);
1237 }
1238 
1239 static bool
transfer_buf_to_image(struct d3d12_context * ctx,struct d3d12_resource * res,struct d3d12_resource * staging_res,struct d3d12_transfer * trans,int resid)1240 transfer_buf_to_image(struct d3d12_context *ctx,
1241                       struct d3d12_resource *res,
1242                       struct d3d12_resource *staging_res,
1243                       struct d3d12_transfer *trans, int resid)
1244 {
1245    if (res->base.b.target == PIPE_TEXTURE_3D) {
1246       assert(resid == 0);
1247       transfer_buf_to_image_part(ctx, res, staging_res, trans,
1248                                  0, trans->base.b.box.depth, 0,
1249                                  trans->base.b.box.z, 0);
1250    } else {
1251       int num_layers = trans->base.b.box.depth;
1252       int start_z = trans->base.b.box.z;
1253 
1254       for (int z = start_z; z < start_z + num_layers; ++z) {
1255          transfer_buf_to_image_part(ctx, res, staging_res, trans,
1256                                            z, 1, start_z, 0, resid);
1257       }
1258    }
1259    return true;
1260 }
1261 
1262 static void
transfer_image_part_to_buf(struct d3d12_context * ctx,struct d3d12_resource * res,struct d3d12_resource * staging_res,struct d3d12_transfer * trans,unsigned resid,int z,int start_layer,int start_box_z,int depth)1263 transfer_image_part_to_buf(struct d3d12_context *ctx,
1264                            struct d3d12_resource *res,
1265                            struct d3d12_resource *staging_res,
1266                            struct d3d12_transfer *trans,
1267                            unsigned resid, int z, int start_layer,
1268                            int start_box_z, int depth)
1269 {
1270    struct pipe_box *box = &trans->base.b.box;
1271    D3D12_BOX src_box = {};
1272 
1273    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1274    struct copy_info copy_info;
1275    copy_info.src_box = nullptr;
1276    copy_info.src = res;
1277    copy_info.src_loc = fill_texture_location(res, trans, resid, z);
1278    copy_info.dst = staging_res;
1279    copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans,
1280                                             depth, resid, z);
1281    copy_info.dst_loc.PlacedFootprint.Offset += (z  - start_layer) * trans->base.b.layer_stride;
1282    copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0;
1283 
1284    bool whole_resource = util_texrange_covers_whole_level(&res->base.b, trans->base.b.level,
1285                                                           box->x, box->y, start_box_z,
1286                                                           box->width, box->height, depth);
1287    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1288        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)
1289       whole_resource = true;
1290    if (!whole_resource) {
1291       src_box.left = box->x;
1292       src_box.right = box->x + box->width;
1293       src_box.top = box->y;
1294       src_box.bottom = box->y + box->height;
1295       src_box.front = start_box_z;
1296       src_box.back = start_box_z + depth;
1297       copy_info.src_box = &src_box;
1298    }
1299 
1300    copy_texture_region(ctx, copy_info);
1301 }
1302 
1303 static bool
transfer_image_to_buf(struct d3d12_context * ctx,struct d3d12_resource * res,struct d3d12_resource * staging_res,struct d3d12_transfer * trans,unsigned resid)1304 transfer_image_to_buf(struct d3d12_context *ctx,
1305                             struct d3d12_resource *res,
1306                             struct d3d12_resource *staging_res,
1307                             struct d3d12_transfer *trans,
1308                             unsigned resid)
1309 {
1310 
1311    /* We only suppport loading from either an texture array
1312     * or a ZS texture, so either resid is zero, or num_layers == 1)
1313     */
1314    assert(resid == 0 || trans->base.b.box.depth == 1);
1315 
1316    if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
1317       debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n",
1318                    trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
1319                    trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
1320                    util_format_name(res->base.b.format), resid,
1321                    util_format_name(staging_res->base.b.format));
1322    }
1323 
1324    struct pipe_resource *resolved_resource = nullptr;
1325 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1326    if (res->base.b.nr_samples > 1) {
1327       struct pipe_resource tmpl = res->base.b;
1328       tmpl.nr_samples = 0;
1329       resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl);
1330       struct pipe_blit_info resolve_info = {};
1331       struct pipe_box box;
1332       u_box_3d(0,0,0, (int)res->base.b.width0, (int16_t)res->base.b.height0, (int16_t)res->base.b.depth0, &box);
1333       resolve_info.dst.resource = resolved_resource;
1334       resolve_info.dst.box = box;
1335       resolve_info.dst.format = res->base.b.format;
1336       resolve_info.src.resource = &res->base.b;
1337       resolve_info.src.box = box;
1338       resolve_info.src.format = res->base.b.format;
1339       resolve_info.filter = PIPE_TEX_FILTER_NEAREST;
1340       resolve_info.mask = util_format_get_mask(tmpl.format);
1341 
1342 
1343 
1344       d3d12_blit(&ctx->base, &resolve_info);
1345       res = (struct d3d12_resource *)resolved_resource;
1346    }
1347 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1348 
1349    if (res->base.b.target == PIPE_TEXTURE_3D) {
1350       transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
1351                                  0, 0, trans->base.b.box.z, trans->base.b.box.depth);
1352    } else {
1353       int start_layer = trans->base.b.box.z;
1354       for (int z = start_layer; z < start_layer + trans->base.b.box.depth; ++z) {
1355          transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
1356                                     z, start_layer, 0, 1);
1357       }
1358    }
1359 
1360    pipe_resource_reference(&resolved_resource, NULL);
1361 
1362    return true;
1363 }
1364 
1365 static void
transfer_buf_to_buf(struct d3d12_context * ctx,struct d3d12_resource * src,struct d3d12_resource * dst,uint64_t src_offset,uint64_t dst_offset,uint64_t width)1366 transfer_buf_to_buf(struct d3d12_context *ctx,
1367                     struct d3d12_resource *src,
1368                     struct d3d12_resource *dst,
1369                     uint64_t src_offset,
1370                     uint64_t dst_offset,
1371                     uint64_t width)
1372 {
1373    auto batch = d3d12_current_batch(ctx);
1374 
1375    d3d12_batch_reference_resource(batch, src, false);
1376    d3d12_batch_reference_resource(batch, dst, true);
1377 
1378    uint64_t src_offset_suballoc = 0;
1379    uint64_t dst_offset_suballoc = 0;
1380    auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc);
1381    auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc);
1382    src_offset += src_offset_suballoc;
1383    dst_offset += dst_offset_suballoc;
1384 
1385    // Same-resource copies not supported, since the resource would need to be in both states
1386    assert(src_d3d12 != dst_d3d12);
1387    d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1388    d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1389    d3d12_apply_resource_states(ctx, false);
1390    ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,
1391                                   src_d3d12, src_offset,
1392                                   width);
1393 }
1394 
1395 static unsigned
linear_offset(int x,int y,int z,unsigned stride,unsigned layer_stride)1396 linear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride)
1397 {
1398    return x +
1399           y * stride +
1400           z * layer_stride;
1401 }
1402 
1403 static D3D12_RANGE
linear_range(const struct pipe_box * box,unsigned stride,unsigned layer_stride)1404 linear_range(const struct pipe_box *box, unsigned stride, unsigned layer_stride)
1405 {
1406    D3D12_RANGE range;
1407 
1408    range.Begin = linear_offset(box->x, box->y, box->z,
1409                                stride, layer_stride);
1410    range.End = linear_offset(box->x + box->width,
1411                              box->y + box->height - 1,
1412                              box->z + box->depth - 1,
1413                              stride, layer_stride);
1414 
1415    return range;
1416 }
1417 
1418 static bool
synchronize(struct d3d12_context * ctx,struct d3d12_resource * res,unsigned usage,D3D12_RANGE * range)1419 synchronize(struct d3d12_context *ctx,
1420             struct d3d12_resource *res,
1421             unsigned usage,
1422             D3D12_RANGE *range)
1423 {
1424    assert(can_map_directly(&res->base.b));
1425 
1426    /* Check whether that range contains valid data; if not, we might not need to sync */
1427    if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
1428        usage & PIPE_MAP_WRITE &&
1429        !util_ranges_intersect(&res->valid_buffer_range, range->Begin, range->End)) {
1430       usage |= PIPE_MAP_UNSYNCHRONIZED;
1431    }
1432 
1433    if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res, usage & PIPE_MAP_WRITE)) {
1434       if (usage & PIPE_MAP_DONTBLOCK) {
1435          if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, usage & PIPE_MAP_WRITE))
1436             d3d12_flush_cmdlist(ctx);
1437          return false;
1438       }
1439 
1440       d3d12_resource_wait_idle(ctx, res, usage & PIPE_MAP_WRITE);
1441    }
1442 
1443    if (usage & PIPE_MAP_WRITE)
1444       util_range_add(&res->base.b, &res->valid_buffer_range,
1445                      range->Begin, range->End);
1446 
1447    return true;
1448 }
1449 
1450 /* A wrapper to make sure local resources are freed and unmapped with
1451  * any exit path */
1452 struct local_resource {
local_resourcelocal_resource1453    local_resource(pipe_screen *s, struct pipe_resource *tmpl) :
1454       mapped(false)
1455    {
1456       res = d3d12_resource(d3d12_resource_create(s, tmpl));
1457    }
1458 
~local_resourcelocal_resource1459    ~local_resource() {
1460       if (res) {
1461          if (mapped)
1462             d3d12_bo_unmap(res->bo, nullptr);
1463          pipe_resource_reference((struct pipe_resource **)&res, NULL);
1464       }
1465    }
1466 
1467    void *
maplocal_resource1468    map() {
1469       void *ptr;
1470       ptr = d3d12_bo_map(res->bo, nullptr);
1471       if (ptr)
1472          mapped = true;
1473       return ptr;
1474    }
1475 
unmaplocal_resource1476    void unmap()
1477    {
1478       if (mapped)
1479          d3d12_bo_unmap(res->bo, nullptr);
1480       mapped = false;
1481    }
1482 
operator struct d3d12_resource*local_resource1483    operator struct d3d12_resource *() {
1484       return res;
1485    }
1486 
operator !local_resource1487    bool operator !() {
1488       return !res;
1489    }
1490 private:
1491    struct d3d12_resource *res;
1492    bool mapped;
1493 };
1494 
1495 /* Combined depth-stencil needs a special handling for reading back: DX handled
1496  * depth and stencil parts as separate resources and handles copying them only
1497  * by using seperate texture copy calls with different formats. So create two
1498  * buffers, read back both resources and interleave the data.
1499  */
1500 static void
prepare_zs_layer_strides(struct d3d12_screen * screen,struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1501 prepare_zs_layer_strides(struct d3d12_screen *screen,
1502                          struct d3d12_resource *res,
1503                          const struct pipe_box *box,
1504                          struct d3d12_transfer *trans)
1505 {
1506    bool copy_whole_resource = screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
1507    int width = copy_whole_resource ? res->base.b.width0 : box->width;
1508    int height = copy_whole_resource ? res->base.b.height0 : box->height;
1509 
1510    trans->base.b.stride = align(util_format_get_stride(res->base.b.format, width),
1511                                 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1512    trans->base.b.layer_stride = util_format_get_2d_size(res->base.b.format,
1513                                                         trans->base.b.stride,
1514                                                         height);
1515 
1516    if (copy_whole_resource) {
1517       trans->zs_cpu_copy_stride = align(util_format_get_stride(res->base.b.format, box->width),
1518                                         D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1519       trans->zs_cpu_copy_layer_stride = util_format_get_2d_size(res->base.b.format,
1520                                                                 trans->base.b.stride,
1521                                                                 box->height);
1522    } else {
1523       trans->zs_cpu_copy_stride = trans->base.b.stride;
1524       trans->zs_cpu_copy_layer_stride = trans->base.b.layer_stride;
1525    }
1526 }
1527 
1528 static void *
read_zs_surface(struct d3d12_context * ctx,struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1529 read_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res,
1530                 const struct pipe_box *box,
1531                 struct d3d12_transfer *trans)
1532 {
1533    pipe_screen *pscreen = ctx->base.screen;
1534    struct d3d12_screen *screen = d3d12_screen(pscreen);
1535 
1536    prepare_zs_layer_strides(screen, res, box, trans);
1537 
1538    struct pipe_resource tmpl;
1539    memset(&tmpl, 0, sizeof tmpl);
1540    tmpl.target = PIPE_BUFFER;
1541    tmpl.format = PIPE_FORMAT_R32_UNORM;
1542    tmpl.bind = 0;
1543    tmpl.usage = PIPE_USAGE_STAGING;
1544    tmpl.flags = 0;
1545    tmpl.width0 = trans->base.b.layer_stride;
1546    tmpl.height0 = 1;
1547    tmpl.depth0 = 1;
1548    tmpl.array_size = 1;
1549 
1550    local_resource depth_buffer(pscreen, &tmpl);
1551    if (!depth_buffer) {
1552       debug_printf("Allocating staging buffer for depth failed\n");
1553       return NULL;
1554    }
1555 
1556    if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0))
1557       return NULL;
1558 
1559    tmpl.format = PIPE_FORMAT_R8_UINT;
1560 
1561    local_resource stencil_buffer(pscreen, &tmpl);
1562    if (!stencil_buffer) {
1563       debug_printf("Allocating staging buffer for stencilfailed\n");
1564       return NULL;
1565    }
1566 
1567    if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1))
1568       return NULL;
1569 
1570    d3d12_flush_cmdlist_and_wait(ctx);
1571 
1572    uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
1573    if (!depth_ptr) {
1574       debug_printf("Mapping staging depth buffer failed\n");
1575       return NULL;
1576    }
1577 
1578    uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
1579    if (!stencil_ptr) {
1580       debug_printf("Mapping staging stencil buffer failed\n");
1581       return NULL;
1582    }
1583 
1584    uint8_t *buf = (uint8_t *)malloc(trans->zs_cpu_copy_layer_stride);
1585    if (!buf)
1586       return NULL;
1587 
1588    trans->data = buf;
1589 
1590    switch (res->base.b.format) {
1591    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1592       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1593          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1594          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1595       }
1596       util_format_z24_unorm_s8_uint_pack_separate(buf, trans->zs_cpu_copy_stride,
1597                                                   (uint32_t *)depth_ptr, trans->base.b.stride,
1598                                                   stencil_ptr, trans->base.b.stride,
1599                                                   trans->base.b.box.width, trans->base.b.box.height);
1600       break;
1601    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1602       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1603          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1604          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
1605       }
1606       util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->zs_cpu_copy_stride,
1607                                                     (float *)depth_ptr, trans->base.b.stride,
1608                                                     trans->base.b.box.width, trans->base.b.box.height);
1609       util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->zs_cpu_copy_stride,
1610                                                     stencil_ptr, trans->base.b.stride,
1611                                                     trans->base.b.box.width, trans->base.b.box.height);
1612       break;
1613    default:
1614       unreachable("Unsupported depth steancil format");
1615    };
1616 
1617    return trans->data;
1618 }
1619 
1620 static void *
prepare_write_zs_surface(struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1621 prepare_write_zs_surface(struct d3d12_resource *res,
1622                          const struct pipe_box *box,
1623                          struct d3d12_transfer *trans)
1624 {
1625    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1626    prepare_zs_layer_strides(screen, res, box, trans);
1627    uint32_t *buf = (uint32_t *)malloc(trans->base.b.layer_stride);
1628    if (!buf)
1629       return NULL;
1630 
1631    trans->data = buf;
1632    return trans->data;
1633 }
1634 
1635 static void
write_zs_surface(struct pipe_context * pctx,struct d3d12_resource * res,struct d3d12_transfer * trans)1636 write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,
1637                  struct d3d12_transfer *trans)
1638 {
1639    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1640    struct pipe_resource tmpl;
1641    memset(&tmpl, 0, sizeof tmpl);
1642    tmpl.target = PIPE_BUFFER;
1643    tmpl.format = PIPE_FORMAT_R32_UNORM;
1644    tmpl.bind = 0;
1645    tmpl.usage = PIPE_USAGE_STAGING;
1646    tmpl.flags = 0;
1647    tmpl.width0 = trans->base.b.layer_stride;
1648    tmpl.height0 = 1;
1649    tmpl.depth0 = 1;
1650    tmpl.array_size = 1;
1651 
1652    local_resource depth_buffer(pctx->screen, &tmpl);
1653    if (!depth_buffer) {
1654       debug_printf("Allocating staging buffer for depth failed\n");
1655       return;
1656    }
1657 
1658    local_resource stencil_buffer(pctx->screen, &tmpl);
1659    if (!stencil_buffer) {
1660       debug_printf("Allocating staging buffer for depth failed\n");
1661       return;
1662    }
1663 
1664    uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
1665    if (!depth_ptr) {
1666       debug_printf("Mapping staging depth buffer failed\n");
1667       return;
1668    }
1669 
1670    uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
1671    if (!stencil_ptr) {
1672       debug_printf("Mapping staging stencil buffer failed\n");
1673       return;
1674    }
1675 
1676    switch (res->base.b.format) {
1677    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1678       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1679          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1680          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1681       }
1682       util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1683                                              trans->zs_cpu_copy_stride, trans->base.b.box.width,
1684                                              trans->base.b.box.height);
1685       util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1686                                                    trans->zs_cpu_copy_stride, trans->base.b.box.width,
1687                                                    trans->base.b.box.height);
1688       break;
1689    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1690       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1691          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1692          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
1693       }
1694       util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1695                                                       trans->zs_cpu_copy_stride, trans->base.b.box.width,
1696                                                       trans->base.b.box.height);
1697       util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1698                                                       trans->zs_cpu_copy_stride, trans->base.b.box.width,
1699                                                       trans->base.b.box.height);
1700       break;
1701    default:
1702       unreachable("Unsupported depth steancil format");
1703    };
1704 
1705    stencil_buffer.unmap();
1706    depth_buffer.unmap();
1707 
1708    transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0);
1709    transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);
1710 }
1711 
1712 #define BUFFER_MAP_ALIGNMENT 64
1713 
1714 static void *
d3d12_transfer_map(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** transfer)1715 d3d12_transfer_map(struct pipe_context *pctx,
1716                    struct pipe_resource *pres,
1717                    unsigned level,
1718                    unsigned usage,
1719                    const struct pipe_box *box,
1720                    struct pipe_transfer **transfer)
1721 {
1722    struct d3d12_context *ctx = d3d12_context(pctx);
1723    struct d3d12_resource *res = d3d12_resource(pres);
1724    struct d3d12_screen *screen = d3d12_screen(pres->screen);
1725 
1726    if (usage & PIPE_MAP_DIRECTLY || !res->bo)
1727       return NULL;
1728 
1729    slab_child_pool* transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ?
1730       &ctx->transfer_pool_unsync : &ctx->transfer_pool;
1731    struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool);
1732    struct pipe_transfer *ptrans = &trans->base.b;
1733    if (!trans)
1734       return NULL;
1735 
1736    ptrans->level = level;
1737    ptrans->usage = (enum pipe_map_flags)usage;
1738    ptrans->box = *box;
1739 
1740    D3D12_RANGE range;
1741    range.Begin = 0;
1742 
1743    void *ptr;
1744    if (can_map_directly(&res->base.b)) {
1745       if (pres->target == PIPE_BUFFER) {
1746          ptrans->stride = 0;
1747          ptrans->layer_stride = 0;
1748       } else {
1749          ptrans->stride = util_format_get_stride(pres->format, box->width);
1750          ptrans->layer_stride = util_format_get_2d_size(pres->format,
1751                                                         ptrans->stride,
1752                                                         box->height);
1753       }
1754 
1755       range = linear_range(box, ptrans->stride, ptrans->layer_stride);
1756       if (!synchronize(ctx, res, usage, &range)) {
1757          slab_free(transfer_pool, trans);
1758          return NULL;
1759       }
1760       ptr = d3d12_bo_map(res->bo, &range);
1761    } else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
1762                        pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) {
1763       if (usage & PIPE_MAP_READ) {
1764          ptr = read_zs_surface(ctx, res, box, trans);
1765       } else if (usage & PIPE_MAP_WRITE){
1766          ptr = prepare_write_zs_surface(res, box, trans);
1767       } else {
1768          ptr = nullptr;
1769       }
1770    } else if(util_format_is_yuv(res->overall_format)) {
1771 
1772       /* Get planes information*/
1773 
1774       unsigned num_planes = util_format_get_num_planes(res->overall_format);
1775       pipe_resource *planes[d3d12_max_planes];
1776       unsigned int strides[d3d12_max_planes];
1777       unsigned int layer_strides[d3d12_max_planes];
1778       unsigned int offsets[d3d12_max_planes];
1779       unsigned staging_res_size = 0;
1780 
1781       d3d12_resource_get_planes_info(
1782          pres,
1783          num_planes,
1784          planes,
1785          strides,
1786          layer_strides,
1787          offsets,
1788          &staging_res_size
1789       );
1790 
1791       /* Allocate a buffer for all the planes to fit in adjacent memory*/
1792 
1793       pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?
1794          PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
1795       trans->staging_res = pipe_buffer_create(pctx->screen, 0,
1796                                               staging_usage,
1797                                               staging_res_size);
1798       if (!trans->staging_res)
1799          return NULL;
1800 
1801       struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1802 
1803       /* Readback contents into the buffer allocation now if map was intended for read*/
1804 
1805       /* Read all planes if readback needed*/
1806       if (usage & PIPE_MAP_READ) {
1807          pipe_box original_box = ptrans->box;
1808          for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
1809             /* Adjust strides, offsets, box to the corresponding plane for the copytexture operation*/
1810             d3d12_adjust_transfer_dimensions_for_plane(res,
1811                                                        plane_slice,
1812                                                        strides[plane_slice],
1813                                                        layer_strides[plane_slice],
1814                                                        offsets[plane_slice],
1815                                                        &original_box,
1816                                                        ptrans/*inout*/);
1817             /* Perform the readback*/
1818             if(!transfer_image_to_buf(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0)){
1819                return NULL;
1820             }
1821          }
1822          ptrans->box = original_box;
1823          d3d12_flush_cmdlist_and_wait(ctx);
1824       }
1825 
1826       /* Map the whole staging buffer containing all the planes contiguously*/
1827       /* Just offset the resulting ptr to the according plane offset*/
1828 
1829       range.End = staging_res_size - range.Begin;
1830       uint8_t* all_planes_map = (uint8_t*) d3d12_bo_map(staging_res->bo, &range);
1831 
1832       ptrans->stride = strides[res->plane_slice];
1833       ptrans->layer_stride = layer_strides[res->plane_slice];
1834       ptr = all_planes_map + offsets[res->plane_slice];
1835 
1836    } else {
1837       ptrans->stride = align(util_format_get_stride(pres->format, box->width),
1838                               D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1839       ptrans->layer_stride = util_format_get_2d_size(pres->format,
1840                                                      ptrans->stride,
1841                                                      box->height);
1842 
1843       if (res->base.b.target != PIPE_TEXTURE_3D)
1844          ptrans->layer_stride = align(ptrans->layer_stride,
1845                                       D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
1846 
1847       if (util_format_has_depth(util_format_description(pres->format)) &&
1848           screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1849          trans->zs_cpu_copy_stride = ptrans->stride;
1850          trans->zs_cpu_copy_layer_stride = ptrans->layer_stride;
1851 
1852          ptrans->stride = align(util_format_get_stride(pres->format, pres->width0),
1853                                 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1854          ptrans->layer_stride = util_format_get_2d_size(pres->format,
1855                                                         ptrans->stride,
1856                                                         pres->height0);
1857 
1858          range.Begin = box->y * ptrans->stride +
1859             box->x * util_format_get_blocksize(pres->format);
1860       }
1861 
1862       unsigned staging_res_size = ptrans->layer_stride * box->depth;
1863       if (res->base.b.target == PIPE_BUFFER) {
1864          /* To properly support ARB_map_buffer_alignment, we need to return a pointer
1865           * that's appropriately offset from a 64-byte-aligned base address.
1866           */
1867          assert(box->x >= 0);
1868          unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT;
1869          staging_res_size = align(box->width + aligned_x,
1870                                   D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1871          range.Begin = aligned_x;
1872       }
1873 
1874       pipe_resource_usage staging_usage = (usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE)) ?
1875          PIPE_USAGE_STREAM : PIPE_USAGE_STAGING;
1876 
1877       trans->staging_res = pipe_buffer_create(pctx->screen, 0,
1878                                               staging_usage,
1879                                               staging_res_size);
1880       if (!trans->staging_res) {
1881          slab_free(transfer_pool, trans);
1882          return NULL;
1883       }
1884 
1885       struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1886 
1887       if ((usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE | TC_TRANSFER_MAP_THREADED_UNSYNC)) == 0) {
1888          bool ret = true;
1889          if (pres->target == PIPE_BUFFER) {
1890             uint64_t src_offset = box->x;
1891             uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT;
1892             transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width);
1893          } else
1894             ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);
1895          if (!ret)
1896             return NULL;
1897          d3d12_flush_cmdlist_and_wait(ctx);
1898       }
1899 
1900       range.End = staging_res_size - range.Begin;
1901 
1902       ptr = d3d12_bo_map(staging_res->bo, &range);
1903    }
1904 
1905    pipe_resource_reference(&ptrans->resource, pres);
1906    *transfer = ptrans;
1907    return ptr;
1908 }
1909 
1910 static void
d3d12_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)1911 d3d12_transfer_unmap(struct pipe_context *pctx,
1912                      struct pipe_transfer *ptrans)
1913 {
1914    struct d3d12_context *ctx = d3d12_context(pctx);
1915    struct d3d12_resource *res = d3d12_resource(ptrans->resource);
1916    struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;
1917    D3D12_RANGE range = { 0, 0 };
1918 
1919    if (trans->data != nullptr) {
1920       if (trans->base.b.usage & PIPE_MAP_WRITE)
1921          write_zs_surface(pctx, res, trans);
1922       free(trans->data);
1923    } else if (trans->staging_res) {
1924       if(util_format_is_yuv(res->overall_format)) {
1925 
1926          /* Get planes information*/
1927          unsigned num_planes = util_format_get_num_planes(res->overall_format);
1928          pipe_resource *planes[d3d12_max_planes];
1929          unsigned int strides[d3d12_max_planes];
1930          unsigned int layer_strides[d3d12_max_planes];
1931          unsigned int offsets[d3d12_max_planes];
1932          unsigned staging_res_size = 0;
1933 
1934          d3d12_resource_get_planes_info(
1935             ptrans->resource,
1936             num_planes,
1937             planes,
1938             strides,
1939             layer_strides,
1940             offsets,
1941             &staging_res_size
1942          );
1943 
1944          /* Flush the changed contents into the GPU texture*/
1945 
1946          /* In theory we should just flush only the contents for the plane*/
1947          /* requested in res->plane_slice, but the VAAPI frontend has this*/
1948          /* behaviour in which they assume that mapping the first plane of*/
1949          /* NV12, P010, etc resources will will give them a buffer containing*/
1950          /* both Y and UV planes contigously in vaDeriveImage and then vaMapBuffer*/
1951          /* so, flush them all*/
1952 
1953          struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1954          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1955             assert(ptrans->box.x >= 0);
1956             range.Begin = res->base.b.target == PIPE_BUFFER ?
1957                (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
1958             range.End = staging_res->base.b.width0 - range.Begin;
1959 
1960             d3d12_bo_unmap(staging_res->bo, &range);
1961             pipe_box original_box = ptrans->box;
1962             for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
1963                /* Adjust strides, offsets to the corresponding plane for the copytexture operation*/
1964                d3d12_adjust_transfer_dimensions_for_plane(res,
1965                                                           plane_slice,
1966                                                           strides[plane_slice],
1967                                                           layer_strides[plane_slice],
1968                                                           offsets[plane_slice],
1969                                                           &original_box,
1970                                                           ptrans/*inout*/);
1971 
1972                transfer_buf_to_image(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0);
1973             }
1974             ptrans->box = original_box;
1975          }
1976 
1977          pipe_resource_reference(&trans->staging_res, NULL);
1978       } else {
1979          struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1980          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1981             assert(ptrans->box.x >= 0);
1982             range.Begin = res->base.b.target == PIPE_BUFFER ?
1983                (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
1984             range.End = staging_res->base.b.width0 - range.Begin;
1985          }
1986          d3d12_bo_unmap(staging_res->bo, &range);
1987 
1988          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1989             struct d3d12_context *ctx = d3d12_context(pctx);
1990             if (res->base.b.target == PIPE_BUFFER) {
1991                uint64_t dst_offset = trans->base.b.box.x;
1992                uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
1993                transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
1994             } else
1995                transfer_buf_to_image(ctx, res, staging_res, trans, 0);
1996          }
1997 
1998          pipe_resource_reference(&trans->staging_res, NULL);
1999       }
2000    } else {
2001       if (trans->base.b.usage & PIPE_MAP_WRITE) {
2002          range.Begin = ptrans->box.x;
2003          range.End = ptrans->box.x + ptrans->box.width;
2004       }
2005       d3d12_bo_unmap(res->bo, &range);
2006    }
2007 
2008    pipe_resource_reference(&ptrans->resource, NULL);
2009    slab_free(&d3d12_context(pctx)->transfer_pool, ptrans);
2010 }
2011 
2012 void
d3d12_context_resource_init(struct pipe_context * pctx)2013 d3d12_context_resource_init(struct pipe_context *pctx)
2014 {
2015    pctx->buffer_map = d3d12_transfer_map;
2016    pctx->buffer_unmap = d3d12_transfer_unmap;
2017    pctx->texture_map = d3d12_transfer_map;
2018    pctx->texture_unmap = d3d12_transfer_unmap;
2019 
2020    pctx->transfer_flush_region = u_default_transfer_flush_region;
2021    pctx->buffer_subdata = u_default_buffer_subdata;
2022    pctx->texture_subdata = u_default_texture_subdata;
2023 }
2024