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