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