• 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    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 = static_cast<uint16_t>(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 = static_cast<UINT>(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 = static_cast<uint32_t>(incoming_res_desc.Width);
651    res->base.b.height0 = static_cast<uint16_t>(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 = static_cast<uint16_t>(footprint->Depth);
675       break;
676    default:
677       unreachable("Invalid dimension");
678       break;
679    }
680    res->base.b.nr_samples = static_cast<uint8_t>(incoming_res_desc.SampleDesc.Count);
681    res->base.b.last_level = static_cast<uint8_t>(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 = static_cast<uint32_t>(input_desc.Width);
864     templ.height0 = static_cast<uint16_t>(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 = static_cast<int32_t>(width_multiplier * original_box->width);
908    ptrans->box.height = static_cast<int32_t>(height_multiplier * original_box->height);
909    ptrans->box.x = static_cast<int32_t>(width_multiplier * original_box->x);
910    ptrans->box.y = static_cast<int32_t>(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] = static_cast<unsigned>(align(static_cast<uint32_t>(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 
1086    if (offset > UINT32_MAX) {
1087       debug_printf("d3d12: Offset too large for resource \n");
1088       return NULL;
1089    }
1090 
1091    whandle.offset = static_cast<unsigned int>(offset);
1092    whandle.format = templ->format;
1093    whandle.modifier = memobj->res ? 0 : 1;
1094 
1095    // WINSYS_HANDLE_TYPE_D3D12_RES implies taking ownership of the reference
1096    ((IUnknown *)whandle.com_obj)->AddRef();
1097    return d3d12_resource_from_handle(pscreen, templ, &whandle, 0);
1098 }
1099 
1100 void
d3d12_screen_resource_init(struct pipe_screen * pscreen)1101 d3d12_screen_resource_init(struct pipe_screen *pscreen)
1102 {
1103    pscreen->resource_create = d3d12_resource_create;
1104    pscreen->resource_from_handle = d3d12_resource_from_handle;
1105    pscreen->resource_get_handle = d3d12_resource_get_handle;
1106    pscreen->resource_destroy = d3d12_resource_destroy;
1107    pscreen->resource_get_info = d3d12_resource_get_info;
1108 
1109    pscreen->memobj_create_from_handle = d3d12_memobj_create_from_handle;
1110    pscreen->memobj_destroy = d3d12_memobj_destroy;
1111    pscreen->resource_from_memobj = d3d12_resource_from_memobj;
1112 }
1113 
1114 unsigned int
get_subresource_id(struct d3d12_resource * res,unsigned resid,unsigned z,unsigned base_level)1115 get_subresource_id(struct d3d12_resource *res, unsigned resid,
1116                    unsigned z, unsigned base_level)
1117 {
1118    unsigned resource_stride = (res->base.b.last_level + 1) * res->base.b.array_size;
1119    unsigned layer_stride = res->base.b.last_level + 1;
1120 
1121    return resid * resource_stride + z * layer_stride +
1122          base_level + res->plane_slice * resource_stride;
1123 }
1124 
1125 static D3D12_TEXTURE_COPY_LOCATION
fill_texture_location(struct d3d12_resource * res,struct d3d12_transfer * trans,unsigned resid,unsigned z)1126 fill_texture_location(struct d3d12_resource *res,
1127                       struct d3d12_transfer *trans, unsigned resid, unsigned z)
1128 {
1129    D3D12_TEXTURE_COPY_LOCATION tex_loc = {0};
1130    int subres = get_subresource_id(res, resid, z, trans->base.b.level);
1131 
1132    tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
1133    tex_loc.SubresourceIndex = subres;
1134    tex_loc.pResource = d3d12_resource_resource(res);
1135    return tex_loc;
1136 }
1137 
1138 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)1139 fill_buffer_location(struct d3d12_context *ctx,
1140                      struct d3d12_resource *res,
1141                      struct d3d12_resource *staging_res,
1142                      struct d3d12_transfer *trans,
1143                      unsigned depth,
1144                      unsigned resid, unsigned z)
1145 {
1146    D3D12_TEXTURE_COPY_LOCATION buf_loc = {0};
1147    D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
1148    uint64_t offset = 0;
1149    auto descr = GetDesc(d3d12_resource_underlying(res, &offset));
1150    descr.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
1151    struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
1152    ID3D12Device* dev = screen->dev;
1153 
1154    unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.b.level);
1155    dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr);
1156 
1157    buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
1158    buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);
1159    buf_loc.PlacedFootprint = footprint;
1160    buf_loc.PlacedFootprint.Offset = offset;
1161    buf_loc.PlacedFootprint.Offset += trans->base.b.offset;
1162 
1163    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1164        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1165       buf_loc.PlacedFootprint.Footprint.Width = res->base.b.width0;
1166       buf_loc.PlacedFootprint.Footprint.Height = res->base.b.height0;
1167       buf_loc.PlacedFootprint.Footprint.Depth = res->base.b.depth0;
1168    } else {
1169       buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.b.box.width,
1170                                                       util_format_get_blockwidth(res->base.b.format));
1171       buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.b.box.height,
1172                                                        util_format_get_blockheight(res->base.b.format));
1173       buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth,
1174                                                       util_format_get_blockdepth(res->base.b.format));
1175    }
1176 
1177    buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.b.stride;
1178 
1179    return buf_loc;
1180 }
1181 
1182 struct copy_info {
1183    struct d3d12_resource *dst;
1184    D3D12_TEXTURE_COPY_LOCATION dst_loc;
1185    UINT dst_x, dst_y, dst_z;
1186    struct d3d12_resource *src;
1187    D3D12_TEXTURE_COPY_LOCATION src_loc;
1188    D3D12_BOX *src_box;
1189 };
1190 
1191 
1192 static void
copy_texture_region(struct d3d12_context * ctx,struct copy_info & info)1193 copy_texture_region(struct d3d12_context *ctx,
1194                     struct copy_info& info)
1195 {
1196    auto batch = d3d12_current_batch(ctx);
1197 
1198    d3d12_batch_reference_resource(batch, info.src, false);
1199    d3d12_batch_reference_resource(batch, info.dst, true);
1200    d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1201    d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1202    d3d12_apply_resource_states(ctx, false);
1203    ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z,
1204                                    &info.src_loc, info.src_box);
1205 }
1206 
1207 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)1208 transfer_buf_to_image_part(struct d3d12_context *ctx,
1209                            struct d3d12_resource *res,
1210                            struct d3d12_resource *staging_res,
1211                            struct d3d12_transfer *trans,
1212                            int z, int depth, int start_z, int dest_z,
1213                            int resid)
1214 {
1215    if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
1216       debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n",
1217                    trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
1218                    trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
1219                    util_format_name(staging_res->base.b.format),
1220                    util_format_name(res->base.b.format));
1221    }
1222 
1223    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1224    struct copy_info copy_info;
1225    copy_info.src = staging_res;
1226    copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z);
1227    copy_info.src_loc.PlacedFootprint.Offset += (z  - start_z) * trans->base.b.layer_stride;
1228    copy_info.src_box = nullptr;
1229    copy_info.dst = res;
1230    copy_info.dst_loc = fill_texture_location(res, trans, resid, z);
1231    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1232        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1233       copy_info.dst_x = 0;
1234       copy_info.dst_y = 0;
1235    } else {
1236       copy_info.dst_x = trans->base.b.box.x;
1237       copy_info.dst_y = trans->base.b.box.y;
1238    }
1239    copy_info.dst_z = res->base.b.target == PIPE_TEXTURE_CUBE ? 0 : dest_z;
1240    copy_info.src_box = nullptr;
1241 
1242    copy_texture_region(ctx, copy_info);
1243 }
1244 
1245 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)1246 transfer_buf_to_image(struct d3d12_context *ctx,
1247                       struct d3d12_resource *res,
1248                       struct d3d12_resource *staging_res,
1249                       struct d3d12_transfer *trans, int resid)
1250 {
1251    if (res->base.b.target == PIPE_TEXTURE_3D) {
1252       assert(resid == 0);
1253       transfer_buf_to_image_part(ctx, res, staging_res, trans,
1254                                  0, trans->base.b.box.depth, 0,
1255                                  trans->base.b.box.z, 0);
1256    } else {
1257       int num_layers = trans->base.b.box.depth;
1258       int start_z = trans->base.b.box.z;
1259 
1260       for (int z = start_z; z < start_z + num_layers; ++z) {
1261          transfer_buf_to_image_part(ctx, res, staging_res, trans,
1262                                            z, 1, start_z, 0, resid);
1263       }
1264    }
1265    return true;
1266 }
1267 
1268 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)1269 transfer_image_part_to_buf(struct d3d12_context *ctx,
1270                            struct d3d12_resource *res,
1271                            struct d3d12_resource *staging_res,
1272                            struct d3d12_transfer *trans,
1273                            unsigned resid, int z, int start_layer,
1274                            int start_box_z, int depth)
1275 {
1276    struct pipe_box *box = &trans->base.b.box;
1277    D3D12_BOX src_box = {};
1278 
1279    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1280    struct copy_info copy_info;
1281    copy_info.src_box = nullptr;
1282    copy_info.src = res;
1283    copy_info.src_loc = fill_texture_location(res, trans, resid, z);
1284    copy_info.dst = staging_res;
1285    copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans,
1286                                             depth, resid, z);
1287    copy_info.dst_loc.PlacedFootprint.Offset += (z  - start_layer) * trans->base.b.layer_stride;
1288    copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0;
1289 
1290    bool whole_resource = util_texrange_covers_whole_level(&res->base.b, trans->base.b.level,
1291                                                           box->x, box->y, start_box_z,
1292                                                           box->width, box->height, depth);
1293    if (util_format_has_depth(util_format_description(res->base.b.format)) &&
1294        screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)
1295       whole_resource = true;
1296    if (!whole_resource) {
1297       src_box.left = box->x;
1298       src_box.right = box->x + box->width;
1299       src_box.top = box->y;
1300       src_box.bottom = box->y + box->height;
1301       src_box.front = start_box_z;
1302       src_box.back = start_box_z + depth;
1303       copy_info.src_box = &src_box;
1304    }
1305 
1306    copy_texture_region(ctx, copy_info);
1307 }
1308 
1309 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)1310 transfer_image_to_buf(struct d3d12_context *ctx,
1311                             struct d3d12_resource *res,
1312                             struct d3d12_resource *staging_res,
1313                             struct d3d12_transfer *trans,
1314                             unsigned resid)
1315 {
1316 
1317    /* We only suppport loading from either an texture array
1318     * or a ZS texture, so either resid is zero, or num_layers == 1)
1319     */
1320    assert(resid == 0 || trans->base.b.box.depth == 1);
1321 
1322    if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
1323       debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n",
1324                    trans->base.b.box.x, trans->base.b.box.y, trans->base.b.box.z,
1325                    trans->base.b.box.width, trans->base.b.box.height, trans->base.b.box.depth,
1326                    util_format_name(res->base.b.format), resid,
1327                    util_format_name(staging_res->base.b.format));
1328    }
1329 
1330    struct pipe_resource *resolved_resource = nullptr;
1331 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1332    if (res->base.b.nr_samples > 1) {
1333       struct pipe_resource tmpl = res->base.b;
1334       tmpl.nr_samples = 0;
1335       resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl);
1336       struct pipe_blit_info resolve_info = {};
1337       struct pipe_box box;
1338       u_box_3d(0,0,0, (int)res->base.b.width0, (int16_t)res->base.b.height0, (int16_t)res->base.b.depth0, &box);
1339       resolve_info.dst.resource = resolved_resource;
1340       resolve_info.dst.box = box;
1341       resolve_info.dst.format = res->base.b.format;
1342       resolve_info.src.resource = &res->base.b;
1343       resolve_info.src.box = box;
1344       resolve_info.src.format = res->base.b.format;
1345       resolve_info.filter = PIPE_TEX_FILTER_NEAREST;
1346       resolve_info.mask = util_format_get_mask(tmpl.format);
1347 
1348 
1349 
1350       d3d12_blit(&ctx->base, &resolve_info);
1351       res = (struct d3d12_resource *)resolved_resource;
1352    }
1353 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1354 
1355    if (res->base.b.target == PIPE_TEXTURE_3D) {
1356       transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
1357                                  0, 0, trans->base.b.box.z, trans->base.b.box.depth);
1358    } else {
1359       int start_layer = trans->base.b.box.z;
1360       for (int z = start_layer; z < start_layer + trans->base.b.box.depth; ++z) {
1361          transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
1362                                     z, start_layer, 0, 1);
1363       }
1364    }
1365 
1366    pipe_resource_reference(&resolved_resource, NULL);
1367 
1368    return true;
1369 }
1370 
1371 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)1372 transfer_buf_to_buf(struct d3d12_context *ctx,
1373                     struct d3d12_resource *src,
1374                     struct d3d12_resource *dst,
1375                     uint64_t src_offset,
1376                     uint64_t dst_offset,
1377                     uint64_t width)
1378 {
1379    auto batch = d3d12_current_batch(ctx);
1380 
1381    d3d12_batch_reference_resource(batch, src, false);
1382    d3d12_batch_reference_resource(batch, dst, true);
1383 
1384    uint64_t src_offset_suballoc = 0;
1385    uint64_t dst_offset_suballoc = 0;
1386    auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc);
1387    auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc);
1388    src_offset += src_offset_suballoc;
1389    dst_offset += dst_offset_suballoc;
1390 
1391    // Same-resource copies not supported, since the resource would need to be in both states
1392    assert(src_d3d12 != dst_d3d12);
1393    d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1394    d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1395    d3d12_apply_resource_states(ctx, false);
1396    ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,
1397                                   src_d3d12, src_offset,
1398                                   width);
1399 }
1400 
1401 static size_t
linear_offset(int x,int y,int z,unsigned stride,size_t layer_stride)1402 linear_offset(int x, int y, int z, unsigned stride, size_t layer_stride)
1403 {
1404    return x +
1405           y * stride +
1406           z * layer_stride;
1407 }
1408 
1409 static D3D12_RANGE
linear_range(const struct pipe_box * box,unsigned stride,size_t layer_stride)1410 linear_range(const struct pipe_box *box, unsigned stride, size_t layer_stride)
1411 {
1412    D3D12_RANGE range;
1413 
1414    range.Begin = linear_offset(box->x, box->y, box->z,
1415                                stride, layer_stride);
1416    range.End = linear_offset(box->x + box->width,
1417                              box->y + box->height - 1,
1418                              box->z + box->depth - 1,
1419                              stride, layer_stride);
1420 
1421    return range;
1422 }
1423 
1424 static bool
synchronize(struct d3d12_context * ctx,struct d3d12_resource * res,unsigned usage,D3D12_RANGE * range)1425 synchronize(struct d3d12_context *ctx,
1426             struct d3d12_resource *res,
1427             unsigned usage,
1428             D3D12_RANGE *range)
1429 {
1430    assert(can_map_directly(&res->base.b));
1431 
1432    /* Check whether that range contains valid data; if not, we might not need to sync */
1433    if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
1434        usage & PIPE_MAP_WRITE &&
1435        !util_ranges_intersect(&res->valid_buffer_range, static_cast<unsigned int>(range->Begin), static_cast<unsigned int>(range->End))) {
1436       usage |= PIPE_MAP_UNSYNCHRONIZED;
1437    }
1438 
1439    if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res, usage & PIPE_MAP_WRITE)) {
1440       if (usage & PIPE_MAP_DONTBLOCK) {
1441          if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo, usage & PIPE_MAP_WRITE))
1442             d3d12_flush_cmdlist(ctx);
1443          return false;
1444       }
1445 
1446       d3d12_resource_wait_idle(ctx, res, usage & PIPE_MAP_WRITE);
1447    }
1448 
1449    if (usage & PIPE_MAP_WRITE)
1450       util_range_add(&res->base.b, &res->valid_buffer_range,
1451                      static_cast<unsigned int>(range->Begin), static_cast<unsigned int>(range->End));
1452 
1453    return true;
1454 }
1455 
1456 /* A wrapper to make sure local resources are freed and unmapped with
1457  * any exit path */
1458 struct local_resource {
local_resourcelocal_resource1459    local_resource(pipe_screen *s, struct pipe_resource *tmpl) :
1460       mapped(false)
1461    {
1462       res = d3d12_resource(d3d12_resource_create(s, tmpl));
1463    }
1464 
~local_resourcelocal_resource1465    ~local_resource() {
1466       if (res) {
1467          if (mapped)
1468             d3d12_bo_unmap(res->bo, nullptr);
1469          pipe_resource_reference((struct pipe_resource **)&res, NULL);
1470       }
1471    }
1472 
1473    void *
maplocal_resource1474    map() {
1475       void *ptr;
1476       ptr = d3d12_bo_map(res->bo, nullptr);
1477       if (ptr)
1478          mapped = true;
1479       return ptr;
1480    }
1481 
unmaplocal_resource1482    void unmap()
1483    {
1484       if (mapped)
1485          d3d12_bo_unmap(res->bo, nullptr);
1486       mapped = false;
1487    }
1488 
operator struct d3d12_resource*local_resource1489    operator struct d3d12_resource *() {
1490       return res;
1491    }
1492 
operator !local_resource1493    bool operator !() {
1494       return !res;
1495    }
1496 private:
1497    struct d3d12_resource *res;
1498    bool mapped;
1499 };
1500 
1501 /* Combined depth-stencil needs a special handling for reading back: DX handled
1502  * depth and stencil parts as separate resources and handles copying them only
1503  * by using seperate texture copy calls with different formats. So create two
1504  * buffers, read back both resources and interleave the data.
1505  */
1506 static void
prepare_zs_layer_strides(struct d3d12_screen * screen,struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1507 prepare_zs_layer_strides(struct d3d12_screen *screen,
1508                          struct d3d12_resource *res,
1509                          const struct pipe_box *box,
1510                          struct d3d12_transfer *trans)
1511 {
1512    bool copy_whole_resource = screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED;
1513    int width = copy_whole_resource ? res->base.b.width0 : box->width;
1514    int height = copy_whole_resource ? res->base.b.height0 : box->height;
1515 
1516    trans->base.b.stride = align(util_format_get_stride(res->base.b.format, width),
1517                                 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1518    trans->base.b.layer_stride = static_cast<uintptr_t>(util_format_get_2d_size(res->base.b.format,
1519                                                                                trans->base.b.stride,
1520                                                                                height));
1521 
1522    if (copy_whole_resource) {
1523       trans->zs_cpu_copy_stride = align(util_format_get_stride(res->base.b.format, box->width),
1524                                         D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1525       trans->zs_cpu_copy_layer_stride = static_cast<unsigned int>(util_format_get_2d_size(res->base.b.format,
1526                                                                                           trans->base.b.stride,
1527                                                                                           box->height));
1528    } else {
1529       trans->zs_cpu_copy_stride = trans->base.b.stride;
1530       trans->zs_cpu_copy_layer_stride = static_cast<unsigned int>(trans->base.b.layer_stride);
1531    }
1532 }
1533 
1534 static void *
read_zs_surface(struct d3d12_context * ctx,struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1535 read_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res,
1536                 const struct pipe_box *box,
1537                 struct d3d12_transfer *trans)
1538 {
1539    pipe_screen *pscreen = ctx->base.screen;
1540    struct d3d12_screen *screen = d3d12_screen(pscreen);
1541 
1542    prepare_zs_layer_strides(screen, res, box, trans);
1543 
1544    struct pipe_resource tmpl;
1545    memset(&tmpl, 0, sizeof tmpl);
1546    tmpl.target = PIPE_BUFFER;
1547    tmpl.format = PIPE_FORMAT_R32_UNORM;
1548    tmpl.bind = 0;
1549    tmpl.usage = PIPE_USAGE_STAGING;
1550    tmpl.flags = 0;
1551    tmpl.width0 = static_cast<uint32_t>(trans->base.b.layer_stride);
1552    tmpl.height0 = 1;
1553    tmpl.depth0 = 1;
1554    tmpl.array_size = 1;
1555 
1556    local_resource depth_buffer(pscreen, &tmpl);
1557    if (!depth_buffer) {
1558       debug_printf("Allocating staging buffer for depth failed\n");
1559       return NULL;
1560    }
1561 
1562    if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0))
1563       return NULL;
1564 
1565    tmpl.format = PIPE_FORMAT_R8_UINT;
1566 
1567    local_resource stencil_buffer(pscreen, &tmpl);
1568    if (!stencil_buffer) {
1569       debug_printf("Allocating staging buffer for stencilfailed\n");
1570       return NULL;
1571    }
1572 
1573    if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1))
1574       return NULL;
1575 
1576    d3d12_flush_cmdlist_and_wait(ctx);
1577 
1578    uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
1579    if (!depth_ptr) {
1580       debug_printf("Mapping staging depth buffer failed\n");
1581       return NULL;
1582    }
1583 
1584    uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
1585    if (!stencil_ptr) {
1586       debug_printf("Mapping staging stencil buffer failed\n");
1587       return NULL;
1588    }
1589 
1590    uint8_t *buf = (uint8_t *)malloc(trans->zs_cpu_copy_layer_stride);
1591    if (!buf)
1592       return NULL;
1593 
1594    trans->data = buf;
1595 
1596    switch (res->base.b.format) {
1597    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1598       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1599          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1600          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1601       }
1602       util_format_z24_unorm_s8_uint_pack_separate(buf, trans->zs_cpu_copy_stride,
1603                                                   (uint32_t *)depth_ptr, trans->base.b.stride,
1604                                                   stencil_ptr, trans->base.b.stride,
1605                                                   trans->base.b.box.width, trans->base.b.box.height);
1606       break;
1607    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1608       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1609          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1610          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
1611       }
1612       util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->zs_cpu_copy_stride,
1613                                                     (float *)depth_ptr, trans->base.b.stride,
1614                                                     trans->base.b.box.width, trans->base.b.box.height);
1615       util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->zs_cpu_copy_stride,
1616                                                     stencil_ptr, trans->base.b.stride,
1617                                                     trans->base.b.box.width, trans->base.b.box.height);
1618       break;
1619    default:
1620       unreachable("Unsupported depth steancil format");
1621    };
1622 
1623    return trans->data;
1624 }
1625 
1626 static void *
prepare_write_zs_surface(struct d3d12_resource * res,const struct pipe_box * box,struct d3d12_transfer * trans)1627 prepare_write_zs_surface(struct d3d12_resource *res,
1628                          const struct pipe_box *box,
1629                          struct d3d12_transfer *trans)
1630 {
1631    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1632    prepare_zs_layer_strides(screen, res, box, trans);
1633    uint32_t *buf = (uint32_t *)malloc(trans->base.b.layer_stride);
1634    if (!buf)
1635       return NULL;
1636 
1637    trans->data = buf;
1638    return trans->data;
1639 }
1640 
1641 static void
write_zs_surface(struct pipe_context * pctx,struct d3d12_resource * res,struct d3d12_transfer * trans)1642 write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,
1643                  struct d3d12_transfer *trans)
1644 {
1645    struct d3d12_screen *screen = d3d12_screen(res->base.b.screen);
1646    struct pipe_resource tmpl;
1647    memset(&tmpl, 0, sizeof tmpl);
1648    tmpl.target = PIPE_BUFFER;
1649    tmpl.format = PIPE_FORMAT_R32_UNORM;
1650    tmpl.bind = 0;
1651    tmpl.usage = PIPE_USAGE_STAGING;
1652    tmpl.flags = 0;
1653    tmpl.width0 = static_cast<uint32_t>(trans->base.b.layer_stride);
1654    tmpl.height0 = 1;
1655    tmpl.depth0 = 1;
1656    tmpl.array_size = 1;
1657 
1658    local_resource depth_buffer(pctx->screen, &tmpl);
1659    if (!depth_buffer) {
1660       debug_printf("Allocating staging buffer for depth failed\n");
1661       return;
1662    }
1663 
1664    local_resource stencil_buffer(pctx->screen, &tmpl);
1665    if (!stencil_buffer) {
1666       debug_printf("Allocating staging buffer for depth failed\n");
1667       return;
1668    }
1669 
1670    uint8_t *depth_ptr = (uint8_t *)depth_buffer.map();
1671    if (!depth_ptr) {
1672       debug_printf("Mapping staging depth buffer failed\n");
1673       return;
1674    }
1675 
1676    uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
1677    if (!stencil_ptr) {
1678       debug_printf("Mapping staging stencil buffer failed\n");
1679       return;
1680    }
1681 
1682    switch (res->base.b.format) {
1683    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1684       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1685          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1686          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1687       }
1688       util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1689                                              trans->zs_cpu_copy_stride, trans->base.b.box.width,
1690                                              trans->base.b.box.height);
1691       util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1692                                                    trans->zs_cpu_copy_stride, trans->base.b.box.width,
1693                                                    trans->base.b.box.height);
1694       break;
1695    case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1696       if (screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1697          depth_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x * 4;
1698          stencil_ptr += trans->base.b.box.y * trans->base.b.stride + trans->base.b.box.x;
1699       }
1700       util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1701                                                       trans->zs_cpu_copy_stride, trans->base.b.box.width,
1702                                                       trans->base.b.box.height);
1703       util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.b.stride, (uint8_t*)trans->data,
1704                                                       trans->zs_cpu_copy_stride, trans->base.b.box.width,
1705                                                       trans->base.b.box.height);
1706       break;
1707    default:
1708       unreachable("Unsupported depth steancil format");
1709    };
1710 
1711    stencil_buffer.unmap();
1712    depth_buffer.unmap();
1713 
1714    transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0);
1715    transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);
1716 }
1717 
1718 #define BUFFER_MAP_ALIGNMENT 64
1719 
1720 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)1721 d3d12_transfer_map(struct pipe_context *pctx,
1722                    struct pipe_resource *pres,
1723                    unsigned level,
1724                    unsigned usage,
1725                    const struct pipe_box *box,
1726                    struct pipe_transfer **transfer)
1727 {
1728    struct d3d12_context *ctx = d3d12_context(pctx);
1729    struct d3d12_resource *res = d3d12_resource(pres);
1730    struct d3d12_screen *screen = d3d12_screen(pres->screen);
1731 
1732    if (usage & PIPE_MAP_DIRECTLY || !res->bo)
1733       return NULL;
1734 
1735    slab_child_pool* transfer_pool = (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) ?
1736       &ctx->transfer_pool_unsync : &ctx->transfer_pool;
1737    struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_zalloc(transfer_pool);
1738    struct pipe_transfer *ptrans = &trans->base.b;
1739    if (!trans)
1740       return NULL;
1741 
1742    ptrans->level = level;
1743    ptrans->usage = (enum pipe_map_flags)usage;
1744    ptrans->box = *box;
1745 
1746    D3D12_RANGE range;
1747    range.Begin = 0;
1748 
1749    void *ptr;
1750    if (can_map_directly(&res->base.b)) {
1751       if (pres->target == PIPE_BUFFER) {
1752          ptrans->stride = 0;
1753          ptrans->layer_stride = 0;
1754       } else {
1755          ptrans->stride = util_format_get_stride(pres->format, box->width);
1756          ptrans->layer_stride = static_cast<uintptr_t>(util_format_get_2d_size(pres->format,
1757                                                                                ptrans->stride,
1758                                                                                box->height));
1759       }
1760 
1761       range = linear_range(box, ptrans->stride, ptrans->layer_stride);
1762       if (!synchronize(ctx, res, usage, &range)) {
1763          slab_free(transfer_pool, trans);
1764          return NULL;
1765       }
1766       ptr = d3d12_bo_map(res->bo, &range);
1767    } else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
1768                        pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) {
1769       if (usage & PIPE_MAP_READ) {
1770          ptr = read_zs_surface(ctx, res, box, trans);
1771       } else if (usage & PIPE_MAP_WRITE){
1772          ptr = prepare_write_zs_surface(res, box, trans);
1773       } else {
1774          ptr = nullptr;
1775       }
1776    } else if(util_format_is_yuv(res->overall_format)) {
1777 
1778       /* Get planes information*/
1779 
1780       unsigned num_planes = util_format_get_num_planes(res->overall_format);
1781       pipe_resource *planes[d3d12_max_planes];
1782       unsigned int strides[d3d12_max_planes];
1783       unsigned int layer_strides[d3d12_max_planes];
1784       unsigned int offsets[d3d12_max_planes];
1785       unsigned staging_res_size = 0;
1786 
1787       d3d12_resource_get_planes_info(
1788          pres,
1789          num_planes,
1790          planes,
1791          strides,
1792          layer_strides,
1793          offsets,
1794          &staging_res_size
1795       );
1796 
1797       /* Allocate a buffer for all the planes to fit in adjacent memory*/
1798 
1799       pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?
1800          PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
1801       trans->staging_res = pipe_buffer_create(pctx->screen, 0,
1802                                               staging_usage,
1803                                               staging_res_size);
1804       if (!trans->staging_res)
1805          return NULL;
1806 
1807       struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1808 
1809       /* Readback contents into the buffer allocation now if map was intended for read*/
1810 
1811       /* Read all planes if readback needed*/
1812       if (usage & PIPE_MAP_READ) {
1813          pipe_box original_box = ptrans->box;
1814          for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
1815             /* Adjust strides, offsets, box to the corresponding plane for the copytexture operation*/
1816             d3d12_adjust_transfer_dimensions_for_plane(res,
1817                                                        plane_slice,
1818                                                        strides[plane_slice],
1819                                                        layer_strides[plane_slice],
1820                                                        offsets[plane_slice],
1821                                                        &original_box,
1822                                                        ptrans/*inout*/);
1823             /* Perform the readback*/
1824             if(!transfer_image_to_buf(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0)){
1825                return NULL;
1826             }
1827          }
1828          ptrans->box = original_box;
1829          d3d12_flush_cmdlist_and_wait(ctx);
1830       }
1831 
1832       /* Map the whole staging buffer containing all the planes contiguously*/
1833       /* Just offset the resulting ptr to the according plane offset*/
1834 
1835       range.End = staging_res_size - range.Begin;
1836       uint8_t* all_planes_map = (uint8_t*) d3d12_bo_map(staging_res->bo, &range);
1837 
1838       ptrans->stride = strides[res->plane_slice];
1839       ptrans->layer_stride = layer_strides[res->plane_slice];
1840       ptr = all_planes_map + offsets[res->plane_slice];
1841 
1842    } else {
1843       ptrans->stride = align(util_format_get_stride(pres->format, box->width),
1844                               D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1845       ptrans->layer_stride = static_cast<uintptr_t>(util_format_get_2d_size(pres->format,
1846                                                                             ptrans->stride,
1847                                                                             box->height));
1848 
1849       if (res->base.b.target != PIPE_TEXTURE_3D)
1850          ptrans->layer_stride = static_cast<uintptr_t>(align(static_cast<uint32_t>(ptrans->layer_stride),
1851                                                              D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT));
1852 
1853       if (util_format_has_depth(util_format_description(pres->format)) &&
1854           screen->opts2.ProgrammableSamplePositionsTier == D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED) {
1855          trans->zs_cpu_copy_stride = ptrans->stride;
1856          trans->zs_cpu_copy_layer_stride = static_cast<unsigned int>(ptrans->layer_stride);
1857 
1858          ptrans->stride = align(util_format_get_stride(pres->format, pres->width0),
1859                                 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1860          ptrans->layer_stride = static_cast<uintptr_t>(util_format_get_2d_size(pres->format,
1861                                                                                ptrans->stride,
1862                                                                                pres->height0));
1863 
1864          range.Begin = box->y * ptrans->stride +
1865             box->x * util_format_get_blocksize(pres->format);
1866       }
1867 
1868       unsigned staging_res_size = static_cast<unsigned>(ptrans->layer_stride * box->depth);
1869       if (res->base.b.target == PIPE_BUFFER) {
1870          /* To properly support ARB_map_buffer_alignment, we need to return a pointer
1871           * that's appropriately offset from a 64-byte-aligned base address.
1872           */
1873          assert(box->x >= 0);
1874          unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT;
1875          staging_res_size = align(box->width + aligned_x,
1876                                   D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
1877          range.Begin = aligned_x;
1878       }
1879 
1880       pipe_resource_usage staging_usage = (usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE)) ?
1881          PIPE_USAGE_STREAM : PIPE_USAGE_STAGING;
1882 
1883       trans->staging_res = pipe_buffer_create(pctx->screen, 0,
1884                                               staging_usage,
1885                                               staging_res_size);
1886       if (!trans->staging_res) {
1887          slab_free(transfer_pool, trans);
1888          return NULL;
1889       }
1890 
1891       struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1892 
1893       if ((usage & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE | TC_TRANSFER_MAP_THREADED_UNSYNC)) == 0) {
1894          bool ret = true;
1895          if (pres->target == PIPE_BUFFER) {
1896             uint64_t src_offset = box->x;
1897             uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT;
1898             transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width);
1899          } else
1900             ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);
1901          if (!ret)
1902             return NULL;
1903          d3d12_flush_cmdlist_and_wait(ctx);
1904       }
1905 
1906       range.End = staging_res_size - range.Begin;
1907 
1908       ptr = d3d12_bo_map(staging_res->bo, &range);
1909    }
1910 
1911    pipe_resource_reference(&ptrans->resource, pres);
1912    *transfer = ptrans;
1913    return ptr;
1914 }
1915 
1916 static void
d3d12_transfer_unmap(struct pipe_context * pctx,struct pipe_transfer * ptrans)1917 d3d12_transfer_unmap(struct pipe_context *pctx,
1918                      struct pipe_transfer *ptrans)
1919 {
1920    struct d3d12_context *ctx = d3d12_context(pctx);
1921    struct d3d12_resource *res = d3d12_resource(ptrans->resource);
1922    struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;
1923    D3D12_RANGE range = { 0, 0 };
1924 
1925    if (trans->data != nullptr) {
1926       if (trans->base.b.usage & PIPE_MAP_WRITE)
1927          write_zs_surface(pctx, res, trans);
1928       free(trans->data);
1929    } else if (trans->staging_res) {
1930       if(util_format_is_yuv(res->overall_format)) {
1931 
1932          /* Get planes information*/
1933          unsigned num_planes = util_format_get_num_planes(res->overall_format);
1934          pipe_resource *planes[d3d12_max_planes];
1935          unsigned int strides[d3d12_max_planes];
1936          unsigned int layer_strides[d3d12_max_planes];
1937          unsigned int offsets[d3d12_max_planes];
1938          unsigned staging_res_size = 0;
1939 
1940          d3d12_resource_get_planes_info(
1941             ptrans->resource,
1942             num_planes,
1943             planes,
1944             strides,
1945             layer_strides,
1946             offsets,
1947             &staging_res_size
1948          );
1949 
1950          /* Flush the changed contents into the GPU texture*/
1951 
1952          /* In theory we should just flush only the contents for the plane*/
1953          /* requested in res->plane_slice, but the VAAPI frontend has this*/
1954          /* behaviour in which they assume that mapping the first plane of*/
1955          /* NV12, P010, etc resources will will give them a buffer containing*/
1956          /* both Y and UV planes contigously in vaDeriveImage and then vaMapBuffer*/
1957          /* so, flush them all*/
1958 
1959          struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1960          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1961             assert(ptrans->box.x >= 0);
1962             range.Begin = res->base.b.target == PIPE_BUFFER ?
1963                (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
1964             range.End = staging_res->base.b.width0 - range.Begin;
1965 
1966             d3d12_bo_unmap(staging_res->bo, &range);
1967             pipe_box original_box = ptrans->box;
1968             for (uint plane_slice = 0; plane_slice < num_planes; ++plane_slice) {
1969                /* Adjust strides, offsets to the corresponding plane for the copytexture operation*/
1970                d3d12_adjust_transfer_dimensions_for_plane(res,
1971                                                           plane_slice,
1972                                                           strides[plane_slice],
1973                                                           layer_strides[plane_slice],
1974                                                           offsets[plane_slice],
1975                                                           &original_box,
1976                                                           ptrans/*inout*/);
1977 
1978                transfer_buf_to_image(ctx, d3d12_resource(planes[plane_slice]), staging_res, trans, 0);
1979             }
1980             ptrans->box = original_box;
1981          }
1982 
1983          pipe_resource_reference(&trans->staging_res, NULL);
1984       } else {
1985          struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
1986          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1987             assert(ptrans->box.x >= 0);
1988             range.Begin = res->base.b.target == PIPE_BUFFER ?
1989                (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
1990             range.End = staging_res->base.b.width0 - range.Begin;
1991          }
1992          d3d12_bo_unmap(staging_res->bo, &range);
1993 
1994          if (trans->base.b.usage & PIPE_MAP_WRITE) {
1995             struct d3d12_context *ctx = d3d12_context(pctx);
1996             if (res->base.b.target == PIPE_BUFFER) {
1997                uint64_t dst_offset = trans->base.b.box.x;
1998                uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
1999                transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
2000             } else
2001                transfer_buf_to_image(ctx, res, staging_res, trans, 0);
2002          }
2003 
2004          pipe_resource_reference(&trans->staging_res, NULL);
2005       }
2006    } else {
2007       if (trans->base.b.usage & PIPE_MAP_WRITE) {
2008          range.Begin = ptrans->box.x;
2009          range.End = ptrans->box.x + ptrans->box.width;
2010       }
2011       d3d12_bo_unmap(res->bo, &range);
2012    }
2013 
2014    pipe_resource_reference(&ptrans->resource, NULL);
2015    slab_free(&d3d12_context(pctx)->transfer_pool, ptrans);
2016 }
2017 
2018 void
d3d12_context_resource_init(struct pipe_context * pctx)2019 d3d12_context_resource_init(struct pipe_context *pctx)
2020 {
2021    pctx->buffer_map = d3d12_transfer_map;
2022    pctx->buffer_unmap = d3d12_transfer_unmap;
2023    pctx->texture_map = d3d12_transfer_map;
2024    pctx->texture_unmap = d3d12_transfer_unmap;
2025 
2026    pctx->transfer_flush_region = u_default_transfer_flush_region;
2027    pctx->buffer_subdata = u_default_buffer_subdata;
2028    pctx->texture_subdata = u_default_texture_subdata;
2029 }
2030