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
49static bool
50can_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
57static void
58init_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
64static void
65d3d12_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
77static bool
78resource_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
93void
94d3d12_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
108void
109d3d12_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
117static bool
118init_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
167static bool
168init_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
301static void
302convert_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
345static struct pipe_resource *
346d3d12_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
394static struct pipe_resource *
395d3d12_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
405static struct pipe_resource *
406d3d12_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
633invalid:
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
642static bool
643d3d12_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
681struct pipe_resource *
682d3d12_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 */
725static 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
757static
758void 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
788static 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 */
794void
795d3d12_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
828static struct pipe_memory_object *
829d3d12_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
891static void
892d3d12_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
902static pipe_resource *
903d3d12_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
921void
922d3d12_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
935unsigned int
936get_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
956static D3D12_TEXTURE_COPY_LOCATION
957fill_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
969static D3D12_TEXTURE_COPY_LOCATION
970fill_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
1012struct 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
1022static void
1023copy_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
1037static void
1038transfer_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
1075static bool
1076transfer_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
1098static void
1099transfer_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
1139static bool
1140transfer_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
1199static void
1200transfer_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
1229static unsigned
1230linear_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
1237static D3D12_RANGE
1238linear_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
1252static bool
1253synchronize(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 */
1286struct local_resource {
1287   local_resource(pipe_screen *s, struct pipe_resource *tmpl) :
1288      mapped(false)
1289   {
1290      res = d3d12_resource(d3d12_resource_create(s, tmpl));
1291   }
1292
1293   ~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 *
1302   map() {
1303      void *ptr;
1304      ptr = d3d12_bo_map(res->bo, nullptr);
1305      if (ptr)
1306         mapped = true;
1307      return ptr;
1308   }
1309
1310   void unmap()
1311   {
1312      if (mapped)
1313         d3d12_bo_unmap(res->bo, nullptr);
1314      mapped = false;
1315   }
1316
1317   operator struct d3d12_resource *() {
1318      return res;
1319   }
1320
1321   bool operator !() {
1322      return !res;
1323   }
1324private:
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 */
1334static void
1335prepare_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
1362static void *
1363read_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
1454static void *
1455prepare_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
1469static void
1470write_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
1548static void *
1549d3d12_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
1744static void
1745d3d12_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
1845void
1846d3d12_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