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