17ec681f3Smrg/*
27ec681f3Smrg * Copyright © Microsoft Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include "d3d12_resource.h"
257ec681f3Smrg
267ec681f3Smrg#include "d3d12_blit.h"
277ec681f3Smrg#include "d3d12_context.h"
287ec681f3Smrg#include "d3d12_format.h"
297ec681f3Smrg#include "d3d12_screen.h"
307ec681f3Smrg#include "d3d12_debug.h"
317ec681f3Smrg
327ec681f3Smrg#include "pipebuffer/pb_bufmgr.h"
337ec681f3Smrg#include "util/slab.h"
347ec681f3Smrg#include "util/format/u_format.h"
357ec681f3Smrg#include "util/u_inlines.h"
367ec681f3Smrg#include "util/u_memory.h"
377ec681f3Smrg#include "util/format/u_format_zs.h"
387ec681f3Smrg
397ec681f3Smrg#include "frontend/sw_winsys.h"
407ec681f3Smrg
417ec681f3Smrg#include <directx/d3d12.h>
427ec681f3Smrg#include <dxguids/dxguids.h>
437ec681f3Smrg#include <memory>
447ec681f3Smrg
457ec681f3Smrgstatic bool
467ec681f3Smrgcan_map_directly(struct pipe_resource *pres)
477ec681f3Smrg{
487ec681f3Smrg   return pres->target == PIPE_BUFFER &&
497ec681f3Smrg          pres->usage != PIPE_USAGE_DEFAULT &&
507ec681f3Smrg          pres->usage != PIPE_USAGE_IMMUTABLE;
517ec681f3Smrg}
527ec681f3Smrg
537ec681f3Smrgstatic void
547ec681f3Smrginit_valid_range(struct d3d12_resource *res)
557ec681f3Smrg{
567ec681f3Smrg   if (can_map_directly(&res->base))
577ec681f3Smrg      util_range_init(&res->valid_buffer_range);
587ec681f3Smrg}
597ec681f3Smrg
607ec681f3Smrgstatic void
617ec681f3Smrgd3d12_resource_destroy(struct pipe_screen *pscreen,
627ec681f3Smrg                       struct pipe_resource *presource)
637ec681f3Smrg{
647ec681f3Smrg   struct d3d12_resource *resource = d3d12_resource(presource);
657ec681f3Smrg   if (can_map_directly(presource))
667ec681f3Smrg      util_range_destroy(&resource->valid_buffer_range);
677ec681f3Smrg   if (resource->bo)
687ec681f3Smrg      d3d12_bo_unreference(resource->bo);
697ec681f3Smrg   FREE(resource);
707ec681f3Smrg}
717ec681f3Smrg
727ec681f3Smrgstatic bool
737ec681f3Smrgresource_is_busy(struct d3d12_context *ctx,
747ec681f3Smrg                 struct d3d12_resource *res)
757ec681f3Smrg{
767ec681f3Smrg   bool busy = false;
777ec681f3Smrg
787ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); i++)
797ec681f3Smrg      busy |= d3d12_batch_has_references(&ctx->batches[i], res->bo);
807ec681f3Smrg
817ec681f3Smrg   return busy;
827ec681f3Smrg}
837ec681f3Smrg
847ec681f3Smrgvoid
857ec681f3Smrgd3d12_resource_wait_idle(struct d3d12_context *ctx,
867ec681f3Smrg                         struct d3d12_resource *res)
877ec681f3Smrg{
887ec681f3Smrg   if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo)) {
897ec681f3Smrg      d3d12_flush_cmdlist_and_wait(ctx);
907ec681f3Smrg   } else {
917ec681f3Smrg      d3d12_foreach_submitted_batch(ctx, batch) {
927ec681f3Smrg         d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);
937ec681f3Smrg         if (!resource_is_busy(ctx, res))
947ec681f3Smrg            break;
957ec681f3Smrg      }
967ec681f3Smrg   }
977ec681f3Smrg}
987ec681f3Smrg
997ec681f3Smrgvoid
1007ec681f3Smrgd3d12_resource_release(struct d3d12_resource *resource)
1017ec681f3Smrg{
1027ec681f3Smrg   if (!resource->bo)
1037ec681f3Smrg      return;
1047ec681f3Smrg   d3d12_bo_unreference(resource->bo);
1057ec681f3Smrg   resource->bo = NULL;
1067ec681f3Smrg}
1077ec681f3Smrg
1087ec681f3Smrgstatic bool
1097ec681f3Smrginit_buffer(struct d3d12_screen *screen,
1107ec681f3Smrg            struct d3d12_resource *res,
1117ec681f3Smrg            const struct pipe_resource *templ)
1127ec681f3Smrg{
1137ec681f3Smrg   struct pb_desc buf_desc;
1147ec681f3Smrg   struct pb_manager *bufmgr;
1157ec681f3Smrg   struct pb_buffer *buf;
1167ec681f3Smrg
1177ec681f3Smrg   /* Assert that we don't want to create a buffer with one of the emulated
1187ec681f3Smrg    * formats, these are (currently) only supported when passing the vertex
1197ec681f3Smrg    * element state */
1207ec681f3Smrg   assert(templ->format == d3d12_emulated_vtx_format(templ->format));
1217ec681f3Smrg
1227ec681f3Smrg   switch (templ->usage) {
1237ec681f3Smrg   case PIPE_USAGE_DEFAULT:
1247ec681f3Smrg   case PIPE_USAGE_IMMUTABLE:
1257ec681f3Smrg      bufmgr = screen->cache_bufmgr;
1267ec681f3Smrg      buf_desc.usage = (pb_usage_flags)PB_USAGE_GPU_READ_WRITE;
1277ec681f3Smrg      break;
1287ec681f3Smrg   case PIPE_USAGE_DYNAMIC:
1297ec681f3Smrg   case PIPE_USAGE_STREAM:
1307ec681f3Smrg      bufmgr = screen->slab_bufmgr;
1317ec681f3Smrg      buf_desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ);
1327ec681f3Smrg      break;
1337ec681f3Smrg   case PIPE_USAGE_STAGING:
1347ec681f3Smrg      bufmgr = screen->readback_slab_bufmgr;
1357ec681f3Smrg      buf_desc.usage = (pb_usage_flags)(PB_USAGE_GPU_WRITE | PB_USAGE_CPU_READ_WRITE);
1367ec681f3Smrg      break;
1377ec681f3Smrg   default:
1387ec681f3Smrg      unreachable("Invalid pipe usage");
1397ec681f3Smrg   }
1407ec681f3Smrg   buf_desc.alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
1417ec681f3Smrg   res->dxgi_format = DXGI_FORMAT_UNKNOWN;
1427ec681f3Smrg   buf = bufmgr->create_buffer(bufmgr, templ->width0, &buf_desc);
1437ec681f3Smrg   if (!buf)
1447ec681f3Smrg      return false;
1457ec681f3Smrg   res->bo = d3d12_bo_wrap_buffer(buf);
1467ec681f3Smrg
1477ec681f3Smrg   return true;
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3Smrgstatic bool
1517ec681f3Smrginit_texture(struct d3d12_screen *screen,
1527ec681f3Smrg             struct d3d12_resource *res,
1537ec681f3Smrg             const struct pipe_resource *templ)
1547ec681f3Smrg{
1557ec681f3Smrg   ID3D12Resource *d3d12_res;
1567ec681f3Smrg
1577ec681f3Smrg   res->mip_levels = templ->last_level + 1;
1587ec681f3Smrg   res->dxgi_format = d3d12_get_format(templ->format);
1597ec681f3Smrg
1607ec681f3Smrg   D3D12_RESOURCE_DESC desc;
1617ec681f3Smrg   desc.Format = res->dxgi_format;
1627ec681f3Smrg   desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
1637ec681f3Smrg   desc.Width = templ->width0;
1647ec681f3Smrg   desc.Height = templ->height0;
1657ec681f3Smrg   desc.DepthOrArraySize = templ->array_size;
1667ec681f3Smrg   desc.MipLevels = templ->last_level + 1;
1677ec681f3Smrg
1687ec681f3Smrg   desc.SampleDesc.Count = MAX2(templ->nr_samples, 1);
1697ec681f3Smrg   desc.SampleDesc.Quality = 0; /* TODO: figure this one out */
1707ec681f3Smrg
1717ec681f3Smrg   switch (templ->target) {
1727ec681f3Smrg   case PIPE_TEXTURE_1D:
1737ec681f3Smrg   case PIPE_TEXTURE_1D_ARRAY:
1747ec681f3Smrg      desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
1757ec681f3Smrg      break;
1767ec681f3Smrg
1777ec681f3Smrg   case PIPE_TEXTURE_CUBE:
1787ec681f3Smrg   case PIPE_TEXTURE_CUBE_ARRAY:
1797ec681f3Smrg      desc.DepthOrArraySize *= 6;
1807ec681f3Smrg      FALLTHROUGH;
1817ec681f3Smrg   case PIPE_TEXTURE_2D:
1827ec681f3Smrg   case PIPE_TEXTURE_2D_ARRAY:
1837ec681f3Smrg   case PIPE_TEXTURE_RECT:
1847ec681f3Smrg      desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1857ec681f3Smrg      break;
1867ec681f3Smrg
1877ec681f3Smrg   case PIPE_TEXTURE_3D:
1887ec681f3Smrg      desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
1897ec681f3Smrg      desc.DepthOrArraySize = templ->depth0;
1907ec681f3Smrg      break;
1917ec681f3Smrg
1927ec681f3Smrg   default:
1937ec681f3Smrg      unreachable("Invalid texture type");
1947ec681f3Smrg   }
1957ec681f3Smrg
1967ec681f3Smrg   desc.Flags = D3D12_RESOURCE_FLAG_NONE;
1977ec681f3Smrg
1987ec681f3Smrg   if (templ->bind & PIPE_BIND_SHADER_BUFFER)
1997ec681f3Smrg      desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
2007ec681f3Smrg
2017ec681f3Smrg   if (templ->bind & PIPE_BIND_RENDER_TARGET)
2027ec681f3Smrg      desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
2037ec681f3Smrg
2047ec681f3Smrg   if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {
2057ec681f3Smrg      desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
2067ec681f3Smrg
2077ec681f3Smrg      /* Sadly, we can't set D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE in the
2087ec681f3Smrg       * case where PIPE_BIND_SAMPLER_VIEW isn't set, because that would
2097ec681f3Smrg       * prevent us from using the resource with u_blitter, which requires
2107ec681f3Smrg       * sneaking in sampler-usage throught the back-door.
2117ec681f3Smrg       */
2127ec681f3Smrg   }
2137ec681f3Smrg
2147ec681f3Smrg   desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
2157ec681f3Smrg   if (templ->bind & (PIPE_BIND_SCANOUT |
2167ec681f3Smrg                      PIPE_BIND_SHARED | PIPE_BIND_LINEAR))
2177ec681f3Smrg      desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2187ec681f3Smrg
2197ec681f3Smrg   D3D12_HEAP_PROPERTIES heap_pris = screen->dev->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_DEFAULT);
2207ec681f3Smrg
2217ec681f3Smrg   HRESULT hres = screen->dev->CreateCommittedResource(&heap_pris,
2227ec681f3Smrg                                                   D3D12_HEAP_FLAG_NONE,
2237ec681f3Smrg                                                   &desc,
2247ec681f3Smrg                                                   D3D12_RESOURCE_STATE_COMMON,
2257ec681f3Smrg                                                   NULL,
2267ec681f3Smrg                                                   IID_PPV_ARGS(&d3d12_res));
2277ec681f3Smrg   if (FAILED(hres))
2287ec681f3Smrg      return false;
2297ec681f3Smrg
2307ec681f3Smrg   if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) {
2317ec681f3Smrg      struct sw_winsys *winsys = screen->winsys;
2327ec681f3Smrg      res->dt = winsys->displaytarget_create(screen->winsys,
2337ec681f3Smrg                                             res->base.bind,
2347ec681f3Smrg                                             res->base.format,
2357ec681f3Smrg                                             templ->width0,
2367ec681f3Smrg                                             templ->height0,
2377ec681f3Smrg                                             64, NULL,
2387ec681f3Smrg                                             &res->dt_stride);
2397ec681f3Smrg   }
2407ec681f3Smrg
2417ec681f3Smrg   res->bo = d3d12_bo_wrap_res(d3d12_res, templ->format);
2427ec681f3Smrg
2437ec681f3Smrg   return true;
2447ec681f3Smrg}
2457ec681f3Smrg
2467ec681f3Smrgstatic struct pipe_resource *
2477ec681f3Smrgd3d12_resource_create(struct pipe_screen *pscreen,
2487ec681f3Smrg                      const struct pipe_resource *templ)
2497ec681f3Smrg{
2507ec681f3Smrg   struct d3d12_screen *screen = d3d12_screen(pscreen);
2517ec681f3Smrg   struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
2527ec681f3Smrg   bool ret;
2537ec681f3Smrg
2547ec681f3Smrg   res->base = *templ;
2557ec681f3Smrg
2567ec681f3Smrg   if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
2577ec681f3Smrg      debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n",
2587ec681f3Smrg                   templ->usage == PIPE_USAGE_STAGING ? "STAGING " :"",
2597ec681f3Smrg                   util_format_name(templ->format), templ->nr_samples,
2607ec681f3Smrg                   templ->width0, templ->height0, templ->depth0,
2617ec681f3Smrg                   templ->array_size, templ->last_level);
2627ec681f3Smrg   }
2637ec681f3Smrg
2647ec681f3Smrg   pipe_reference_init(&res->base.reference, 1);
2657ec681f3Smrg   res->base.screen = pscreen;
2667ec681f3Smrg
2677ec681f3Smrg   if (templ->target == PIPE_BUFFER) {
2687ec681f3Smrg      ret = init_buffer(screen, res, templ);
2697ec681f3Smrg   } else {
2707ec681f3Smrg      ret = init_texture(screen, res, templ);
2717ec681f3Smrg   }
2727ec681f3Smrg
2737ec681f3Smrg   if (!ret) {
2747ec681f3Smrg      FREE(res);
2757ec681f3Smrg      return NULL;
2767ec681f3Smrg   }
2777ec681f3Smrg
2787ec681f3Smrg   init_valid_range(res);
2797ec681f3Smrg
2807ec681f3Smrg   memset(&res->bind_counts, 0, sizeof(d3d12_resource::bind_counts));
2817ec681f3Smrg
2827ec681f3Smrg   return &res->base;
2837ec681f3Smrg}
2847ec681f3Smrg
2857ec681f3Smrgstatic struct pipe_resource *
2867ec681f3Smrgd3d12_resource_from_handle(struct pipe_screen *pscreen,
2877ec681f3Smrg                          const struct pipe_resource *templ,
2887ec681f3Smrg                          struct winsys_handle *handle, unsigned usage)
2897ec681f3Smrg{
2907ec681f3Smrg   if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES)
2917ec681f3Smrg      return NULL;
2927ec681f3Smrg
2937ec681f3Smrg   struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);
2947ec681f3Smrg   if (!res)
2957ec681f3Smrg      return NULL;
2967ec681f3Smrg
2977ec681f3Smrg   res->base = *templ;
2987ec681f3Smrg   pipe_reference_init(&res->base.reference, 1);
2997ec681f3Smrg   res->base.screen = pscreen;
3007ec681f3Smrg   res->dxgi_format = templ->target == PIPE_BUFFER ? DXGI_FORMAT_UNKNOWN :
3017ec681f3Smrg                 d3d12_get_format(templ->format);
3027ec681f3Smrg   res->bo = d3d12_bo_wrap_res((ID3D12Resource *)handle->com_obj, templ->format);
3037ec681f3Smrg   init_valid_range(res);
3047ec681f3Smrg   return &res->base;
3057ec681f3Smrg}
3067ec681f3Smrg
3077ec681f3Smrgstatic bool
3087ec681f3Smrgd3d12_resource_get_handle(struct pipe_screen *pscreen,
3097ec681f3Smrg                          struct pipe_context *pcontext,
3107ec681f3Smrg                          struct pipe_resource *pres,
3117ec681f3Smrg                          struct winsys_handle *handle,
3127ec681f3Smrg                          unsigned usage)
3137ec681f3Smrg{
3147ec681f3Smrg   struct d3d12_resource *res = d3d12_resource(pres);
3157ec681f3Smrg
3167ec681f3Smrg   if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES)
3177ec681f3Smrg      return false;
3187ec681f3Smrg
3197ec681f3Smrg   handle->com_obj = d3d12_resource_resource(res);
3207ec681f3Smrg   return true;
3217ec681f3Smrg}
3227ec681f3Smrg
3237ec681f3Smrgvoid
3247ec681f3Smrgd3d12_screen_resource_init(struct pipe_screen *pscreen)
3257ec681f3Smrg{
3267ec681f3Smrg   pscreen->resource_create = d3d12_resource_create;
3277ec681f3Smrg   pscreen->resource_from_handle = d3d12_resource_from_handle;
3287ec681f3Smrg   pscreen->resource_get_handle = d3d12_resource_get_handle;
3297ec681f3Smrg   pscreen->resource_destroy = d3d12_resource_destroy;
3307ec681f3Smrg}
3317ec681f3Smrg
3327ec681f3Smrgunsigned int
3337ec681f3Smrgget_subresource_id(struct d3d12_resource *res, unsigned resid,
3347ec681f3Smrg                   unsigned z, unsigned base_level)
3357ec681f3Smrg{
3367ec681f3Smrg   unsigned resource_stride = res->base.last_level + 1;
3377ec681f3Smrg   if (res->base.target == PIPE_TEXTURE_1D_ARRAY ||
3387ec681f3Smrg       res->base.target == PIPE_TEXTURE_2D_ARRAY)
3397ec681f3Smrg      resource_stride *= res->base.array_size;
3407ec681f3Smrg
3417ec681f3Smrg   if (res->base.target == PIPE_TEXTURE_CUBE)
3427ec681f3Smrg      resource_stride *= 6;
3437ec681f3Smrg
3447ec681f3Smrg   if (res->base.target == PIPE_TEXTURE_CUBE_ARRAY)
3457ec681f3Smrg      resource_stride *= 6 * res->base.array_size;
3467ec681f3Smrg
3477ec681f3Smrg   unsigned layer_stride = res->base.last_level + 1;
3487ec681f3Smrg
3497ec681f3Smrg   return resid * resource_stride + z * layer_stride +
3507ec681f3Smrg         base_level;
3517ec681f3Smrg}
3527ec681f3Smrg
3537ec681f3Smrgstatic D3D12_TEXTURE_COPY_LOCATION
3547ec681f3Smrgfill_texture_location(struct d3d12_resource *res,
3557ec681f3Smrg                      struct d3d12_transfer *trans, unsigned resid, unsigned z)
3567ec681f3Smrg{
3577ec681f3Smrg   D3D12_TEXTURE_COPY_LOCATION tex_loc = {0};
3587ec681f3Smrg   int subres = get_subresource_id(res, resid, z, trans->base.level);
3597ec681f3Smrg
3607ec681f3Smrg   tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3617ec681f3Smrg   tex_loc.SubresourceIndex = subres;
3627ec681f3Smrg   tex_loc.pResource = d3d12_resource_resource(res);
3637ec681f3Smrg   return tex_loc;
3647ec681f3Smrg}
3657ec681f3Smrg
3667ec681f3Smrgstatic D3D12_TEXTURE_COPY_LOCATION
3677ec681f3Smrgfill_buffer_location(struct d3d12_context *ctx,
3687ec681f3Smrg                     struct d3d12_resource *res,
3697ec681f3Smrg                     struct d3d12_resource *staging_res,
3707ec681f3Smrg                     struct d3d12_transfer *trans,
3717ec681f3Smrg                     unsigned depth,
3727ec681f3Smrg                     unsigned resid, unsigned z)
3737ec681f3Smrg{
3747ec681f3Smrg   D3D12_TEXTURE_COPY_LOCATION buf_loc = {0};
3757ec681f3Smrg   D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
3767ec681f3Smrg   uint64_t offset = 0;
3777ec681f3Smrg   auto descr = d3d12_resource_underlying(res, &offset)->GetDesc();
3787ec681f3Smrg   ID3D12Device* dev = d3d12_screen(ctx->base.screen)->dev;
3797ec681f3Smrg
3807ec681f3Smrg   unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.level);
3817ec681f3Smrg   dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr);
3827ec681f3Smrg
3837ec681f3Smrg   buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3847ec681f3Smrg   buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);
3857ec681f3Smrg   buf_loc.PlacedFootprint = footprint;
3867ec681f3Smrg   buf_loc.PlacedFootprint.Offset += offset;
3877ec681f3Smrg
3887ec681f3Smrg   buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.box.width,
3897ec681f3Smrg                                                   util_format_get_blockwidth(res->base.format));
3907ec681f3Smrg   buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.box.height,
3917ec681f3Smrg                                                    util_format_get_blockheight(res->base.format));
3927ec681f3Smrg   buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth,
3937ec681f3Smrg                                                   util_format_get_blockdepth(res->base.format));
3947ec681f3Smrg
3957ec681f3Smrg   buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.stride;
3967ec681f3Smrg
3977ec681f3Smrg   return buf_loc;
3987ec681f3Smrg}
3997ec681f3Smrg
4007ec681f3Smrgstruct copy_info {
4017ec681f3Smrg   struct d3d12_resource *dst;
4027ec681f3Smrg   D3D12_TEXTURE_COPY_LOCATION dst_loc;
4037ec681f3Smrg   UINT dst_x, dst_y, dst_z;
4047ec681f3Smrg   struct d3d12_resource *src;
4057ec681f3Smrg   D3D12_TEXTURE_COPY_LOCATION src_loc;
4067ec681f3Smrg   D3D12_BOX *src_box;
4077ec681f3Smrg};
4087ec681f3Smrg
4097ec681f3Smrg
4107ec681f3Smrgstatic void
4117ec681f3Smrgcopy_texture_region(struct d3d12_context *ctx,
4127ec681f3Smrg                    struct copy_info& info)
4137ec681f3Smrg{
4147ec681f3Smrg   auto batch = d3d12_current_batch(ctx);
4157ec681f3Smrg
4167ec681f3Smrg   d3d12_batch_reference_resource(batch, info.src);
4177ec681f3Smrg   d3d12_batch_reference_resource(batch, info.dst);
4187ec681f3Smrg   d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_BIND_INVALIDATE_FULL);
4197ec681f3Smrg   d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_FULL);
4207ec681f3Smrg   d3d12_apply_resource_states(ctx);
4217ec681f3Smrg   ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z,
4227ec681f3Smrg                                   &info.src_loc, info.src_box);
4237ec681f3Smrg}
4247ec681f3Smrg
4257ec681f3Smrgstatic void
4267ec681f3Smrgtransfer_buf_to_image_part(struct d3d12_context *ctx,
4277ec681f3Smrg                           struct d3d12_resource *res,
4287ec681f3Smrg                           struct d3d12_resource *staging_res,
4297ec681f3Smrg                           struct d3d12_transfer *trans,
4307ec681f3Smrg                           int z, int depth, int start_z, int dest_z,
4317ec681f3Smrg                           int resid)
4327ec681f3Smrg{
4337ec681f3Smrg   if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
4347ec681f3Smrg      debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n",
4357ec681f3Smrg                   trans->base.box.x, trans->base.box.y, trans->base.box.z,
4367ec681f3Smrg                   trans->base.box.width, trans->base.box.height, trans->base.box.depth,
4377ec681f3Smrg                   util_format_name(staging_res->base.format),
4387ec681f3Smrg                   util_format_name(res->base.format));
4397ec681f3Smrg   }
4407ec681f3Smrg
4417ec681f3Smrg   struct copy_info copy_info;
4427ec681f3Smrg   copy_info.src = staging_res;
4437ec681f3Smrg   copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z);
4447ec681f3Smrg   copy_info.src_loc.PlacedFootprint.Offset = (z  - start_z) * trans->base.layer_stride;
4457ec681f3Smrg   copy_info.src_box = nullptr;
4467ec681f3Smrg   copy_info.dst = res;
4477ec681f3Smrg   copy_info.dst_loc = fill_texture_location(res, trans, resid, z);
4487ec681f3Smrg   copy_info.dst_x = trans->base.box.x;
4497ec681f3Smrg   copy_info.dst_y = trans->base.box.y;
4507ec681f3Smrg   copy_info.dst_z = res->base.target == PIPE_TEXTURE_CUBE ? 0 : dest_z;
4517ec681f3Smrg   copy_info.src_box = nullptr;
4527ec681f3Smrg
4537ec681f3Smrg   copy_texture_region(ctx, copy_info);
4547ec681f3Smrg}
4557ec681f3Smrg
4567ec681f3Smrgstatic bool
4577ec681f3Smrgtransfer_buf_to_image(struct d3d12_context *ctx,
4587ec681f3Smrg                      struct d3d12_resource *res,
4597ec681f3Smrg                      struct d3d12_resource *staging_res,
4607ec681f3Smrg                      struct d3d12_transfer *trans, int resid)
4617ec681f3Smrg{
4627ec681f3Smrg   if (res->base.target == PIPE_TEXTURE_3D) {
4637ec681f3Smrg      assert(resid == 0);
4647ec681f3Smrg      transfer_buf_to_image_part(ctx, res, staging_res, trans,
4657ec681f3Smrg                                 0, trans->base.box.depth, 0,
4667ec681f3Smrg                                 trans->base.box.z, 0);
4677ec681f3Smrg   } else {
4687ec681f3Smrg      int num_layers = trans->base.box.depth;
4697ec681f3Smrg      int start_z = trans->base.box.z;
4707ec681f3Smrg
4717ec681f3Smrg      for (int z = start_z; z < start_z + num_layers; ++z) {
4727ec681f3Smrg         transfer_buf_to_image_part(ctx, res, staging_res, trans,
4737ec681f3Smrg                                           z, 1, start_z, 0, resid);
4747ec681f3Smrg      }
4757ec681f3Smrg   }
4767ec681f3Smrg   return true;
4777ec681f3Smrg}
4787ec681f3Smrg
4797ec681f3Smrgstatic void
4807ec681f3Smrgtransfer_image_part_to_buf(struct d3d12_context *ctx,
4817ec681f3Smrg                           struct d3d12_resource *res,
4827ec681f3Smrg                           struct d3d12_resource *staging_res,
4837ec681f3Smrg                           struct d3d12_transfer *trans,
4847ec681f3Smrg                           unsigned resid, int z, int start_layer,
4857ec681f3Smrg                           int start_box_z, int depth)
4867ec681f3Smrg{
4877ec681f3Smrg   struct pipe_box *box = &trans->base.box;
4887ec681f3Smrg   D3D12_BOX src_box = {};
4897ec681f3Smrg
4907ec681f3Smrg   struct copy_info copy_info;
4917ec681f3Smrg   copy_info.src_box = nullptr;
4927ec681f3Smrg   copy_info.src = res;
4937ec681f3Smrg   copy_info.src_loc = fill_texture_location(res, trans, resid, z);
4947ec681f3Smrg   copy_info.dst = staging_res;
4957ec681f3Smrg   copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans,
4967ec681f3Smrg                                            depth, resid, z);
4977ec681f3Smrg   copy_info.dst_loc.PlacedFootprint.Offset = (z  - start_layer) * trans->base.layer_stride;
4987ec681f3Smrg   copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0;
4997ec681f3Smrg
5007ec681f3Smrg   if (!util_texrange_covers_whole_level(&res->base, trans->base.level,
5017ec681f3Smrg                                         box->x, box->y, start_box_z,
5027ec681f3Smrg                                         box->width, box->height, depth)) {
5037ec681f3Smrg      src_box.left = box->x;
5047ec681f3Smrg      src_box.right = box->x + box->width;
5057ec681f3Smrg      src_box.top = box->y;
5067ec681f3Smrg      src_box.bottom = box->y + box->height;
5077ec681f3Smrg      src_box.front = start_box_z;
5087ec681f3Smrg      src_box.back = start_box_z + depth;
5097ec681f3Smrg      copy_info.src_box = &src_box;
5107ec681f3Smrg   }
5117ec681f3Smrg
5127ec681f3Smrg   copy_texture_region(ctx, copy_info);
5137ec681f3Smrg}
5147ec681f3Smrg
5157ec681f3Smrgstatic bool
5167ec681f3Smrgtransfer_image_to_buf(struct d3d12_context *ctx,
5177ec681f3Smrg                            struct d3d12_resource *res,
5187ec681f3Smrg                            struct d3d12_resource *staging_res,
5197ec681f3Smrg                            struct d3d12_transfer *trans,
5207ec681f3Smrg                            unsigned resid)
5217ec681f3Smrg{
5227ec681f3Smrg
5237ec681f3Smrg   /* We only suppport loading from either an texture array
5247ec681f3Smrg    * or a ZS texture, so either resid is zero, or num_layers == 1)
5257ec681f3Smrg    */
5267ec681f3Smrg   assert(resid == 0 || trans->base.box.depth == 1);
5277ec681f3Smrg
5287ec681f3Smrg   if (D3D12_DEBUG_RESOURCE & d3d12_debug) {
5297ec681f3Smrg      debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n",
5307ec681f3Smrg                   trans->base.box.x, trans->base.box.y, trans->base.box.z,
5317ec681f3Smrg                   trans->base.box.width, trans->base.box.height, trans->base.box.depth,
5327ec681f3Smrg                   util_format_name(res->base.format), resid,
5337ec681f3Smrg                   util_format_name(staging_res->base.format));
5347ec681f3Smrg   }
5357ec681f3Smrg
5367ec681f3Smrg   struct pipe_resource *resolved_resource = nullptr;
5377ec681f3Smrg   if (res->base.nr_samples > 1) {
5387ec681f3Smrg      struct pipe_resource tmpl = res->base;
5397ec681f3Smrg      tmpl.nr_samples = 0;
5407ec681f3Smrg      resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl);
5417ec681f3Smrg      struct pipe_blit_info resolve_info = {};
5427ec681f3Smrg      struct pipe_box box = {0,0,0, (int)res->base.width0, (int16_t)res->base.height0, (int16_t)res->base.depth0};
5437ec681f3Smrg      resolve_info.dst.resource = resolved_resource;
5447ec681f3Smrg      resolve_info.dst.box = box;
5457ec681f3Smrg      resolve_info.dst.format = res->base.format;
5467ec681f3Smrg      resolve_info.src.resource = &res->base;
5477ec681f3Smrg      resolve_info.src.box = box;
5487ec681f3Smrg      resolve_info.src.format = res->base.format;
5497ec681f3Smrg      resolve_info.filter = PIPE_TEX_FILTER_NEAREST;
5507ec681f3Smrg      resolve_info.mask = util_format_get_mask(tmpl.format);
5517ec681f3Smrg
5527ec681f3Smrg
5537ec681f3Smrg
5547ec681f3Smrg      d3d12_blit(&ctx->base, &resolve_info);
5557ec681f3Smrg      res = (struct d3d12_resource *)resolved_resource;
5567ec681f3Smrg   }
5577ec681f3Smrg
5587ec681f3Smrg
5597ec681f3Smrg   if (res->base.target == PIPE_TEXTURE_3D) {
5607ec681f3Smrg      transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
5617ec681f3Smrg                                 0, 0, trans->base.box.z, trans->base.box.depth);
5627ec681f3Smrg   } else {
5637ec681f3Smrg      int start_layer = trans->base.box.z;
5647ec681f3Smrg      for (int z = start_layer; z < start_layer + trans->base.box.depth; ++z) {
5657ec681f3Smrg         transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,
5667ec681f3Smrg                                    z, start_layer, 0, 1);
5677ec681f3Smrg      }
5687ec681f3Smrg   }
5697ec681f3Smrg
5707ec681f3Smrg   pipe_resource_reference(&resolved_resource, NULL);
5717ec681f3Smrg
5727ec681f3Smrg   return true;
5737ec681f3Smrg}
5747ec681f3Smrg
5757ec681f3Smrgstatic void
5767ec681f3Smrgtransfer_buf_to_buf(struct d3d12_context *ctx,
5777ec681f3Smrg                    struct d3d12_resource *src,
5787ec681f3Smrg                    struct d3d12_resource *dst,
5797ec681f3Smrg                    uint64_t src_offset,
5807ec681f3Smrg                    uint64_t dst_offset,
5817ec681f3Smrg                    uint64_t width)
5827ec681f3Smrg{
5837ec681f3Smrg   auto batch = d3d12_current_batch(ctx);
5847ec681f3Smrg
5857ec681f3Smrg   d3d12_batch_reference_resource(batch, src);
5867ec681f3Smrg   d3d12_batch_reference_resource(batch, dst);
5877ec681f3Smrg
5887ec681f3Smrg   uint64_t src_offset_suballoc = 0;
5897ec681f3Smrg   uint64_t dst_offset_suballoc = 0;
5907ec681f3Smrg   auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc);
5917ec681f3Smrg   auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc);
5927ec681f3Smrg   src_offset += src_offset_suballoc;
5937ec681f3Smrg   dst_offset += dst_offset_suballoc;
5947ec681f3Smrg
5957ec681f3Smrg   // Same-resource copies not supported, since the resource would need to be in both states
5967ec681f3Smrg   assert(src_d3d12 != dst_d3d12);
5977ec681f3Smrg   d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_BIND_INVALIDATE_FULL);
5987ec681f3Smrg   d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_FULL);
5997ec681f3Smrg   d3d12_apply_resource_states(ctx);
6007ec681f3Smrg   ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,
6017ec681f3Smrg                                  src_d3d12, src_offset,
6027ec681f3Smrg                                  width);
6037ec681f3Smrg}
6047ec681f3Smrg
6057ec681f3Smrgstatic unsigned
6067ec681f3Smrglinear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride)
6077ec681f3Smrg{
6087ec681f3Smrg   return x +
6097ec681f3Smrg          y * stride +
6107ec681f3Smrg          z * layer_stride;
6117ec681f3Smrg}
6127ec681f3Smrg
6137ec681f3Smrgstatic D3D12_RANGE
6147ec681f3Smrglinear_range(const struct pipe_box *box, unsigned stride, unsigned layer_stride)
6157ec681f3Smrg{
6167ec681f3Smrg   D3D12_RANGE range;
6177ec681f3Smrg
6187ec681f3Smrg   range.Begin = linear_offset(box->x, box->y, box->z,
6197ec681f3Smrg                               stride, layer_stride);
6207ec681f3Smrg   range.End = linear_offset(box->x + box->width,
6217ec681f3Smrg                             box->y + box->height - 1,
6227ec681f3Smrg                             box->z + box->depth - 1,
6237ec681f3Smrg                             stride, layer_stride);
6247ec681f3Smrg
6257ec681f3Smrg   return range;
6267ec681f3Smrg}
6277ec681f3Smrg
6287ec681f3Smrgstatic bool
6297ec681f3Smrgsynchronize(struct d3d12_context *ctx,
6307ec681f3Smrg            struct d3d12_resource *res,
6317ec681f3Smrg            unsigned usage,
6327ec681f3Smrg            D3D12_RANGE *range)
6337ec681f3Smrg{
6347ec681f3Smrg   assert(can_map_directly(&res->base));
6357ec681f3Smrg
6367ec681f3Smrg   /* Check whether that range contains valid data; if not, we might not need to sync */
6377ec681f3Smrg   if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
6387ec681f3Smrg       usage & PIPE_MAP_WRITE &&
6397ec681f3Smrg       !util_ranges_intersect(&res->valid_buffer_range, range->Begin, range->End)) {
6407ec681f3Smrg      usage |= PIPE_MAP_UNSYNCHRONIZED;
6417ec681f3Smrg   }
6427ec681f3Smrg
6437ec681f3Smrg   if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res)) {
6447ec681f3Smrg      if (usage & PIPE_MAP_DONTBLOCK)
6457ec681f3Smrg         return false;
6467ec681f3Smrg
6477ec681f3Smrg      d3d12_resource_wait_idle(ctx, res);
6487ec681f3Smrg   }
6497ec681f3Smrg
6507ec681f3Smrg   if (usage & PIPE_MAP_WRITE)
6517ec681f3Smrg      util_range_add(&res->base, &res->valid_buffer_range,
6527ec681f3Smrg                     range->Begin, range->End);
6537ec681f3Smrg
6547ec681f3Smrg   return true;
6557ec681f3Smrg}
6567ec681f3Smrg
6577ec681f3Smrg/* A wrapper to make sure local resources are freed and unmapped with
6587ec681f3Smrg * any exit path */
6597ec681f3Smrgstruct local_resource {
6607ec681f3Smrg   local_resource(pipe_screen *s, struct pipe_resource *tmpl) :
6617ec681f3Smrg      mapped(false)
6627ec681f3Smrg   {
6637ec681f3Smrg      res = d3d12_resource(d3d12_resource_create(s, tmpl));
6647ec681f3Smrg   }
6657ec681f3Smrg
6667ec681f3Smrg   ~local_resource() {
6677ec681f3Smrg      if (res) {
6687ec681f3Smrg         if (mapped)
6697ec681f3Smrg            d3d12_bo_unmap(res->bo, nullptr);
6707ec681f3Smrg         pipe_resource_reference((struct pipe_resource **)&res, NULL);
6717ec681f3Smrg      }
6727ec681f3Smrg   }
6737ec681f3Smrg
6747ec681f3Smrg   void *
6757ec681f3Smrg   map() {
6767ec681f3Smrg      void *ptr;
6777ec681f3Smrg      ptr = d3d12_bo_map(res->bo, nullptr);
6787ec681f3Smrg      if (ptr)
6797ec681f3Smrg         mapped = true;
6807ec681f3Smrg      return ptr;
6817ec681f3Smrg   }
6827ec681f3Smrg
6837ec681f3Smrg   void unmap()
6847ec681f3Smrg   {
6857ec681f3Smrg      if (mapped)
6867ec681f3Smrg         d3d12_bo_unmap(res->bo, nullptr);
6877ec681f3Smrg      mapped = false;
6887ec681f3Smrg   }
6897ec681f3Smrg
6907ec681f3Smrg   operator struct d3d12_resource *() {
6917ec681f3Smrg      return res;
6927ec681f3Smrg   }
6937ec681f3Smrg
6947ec681f3Smrg   bool operator !() {
6957ec681f3Smrg      return !res;
6967ec681f3Smrg   }
6977ec681f3Smrgprivate:
6987ec681f3Smrg   struct d3d12_resource *res;
6997ec681f3Smrg   bool mapped;
7007ec681f3Smrg};
7017ec681f3Smrg
7027ec681f3Smrg/* Combined depth-stencil needs a special handling for reading back: DX handled
7037ec681f3Smrg * depth and stencil parts as separate resources and handles copying them only
7047ec681f3Smrg * by using seperate texture copy calls with different formats. So create two
7057ec681f3Smrg * buffers, read back both resources and interleave the data.
7067ec681f3Smrg */
7077ec681f3Smrgstatic void
7087ec681f3Smrgprepare_zs_layer_strides(struct d3d12_resource *res,
7097ec681f3Smrg                         const struct pipe_box *box,
7107ec681f3Smrg                         struct d3d12_transfer *trans)
7117ec681f3Smrg{
7127ec681f3Smrg   trans->base.stride = align(util_format_get_stride(res->base.format, box->width),
7137ec681f3Smrg                              D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
7147ec681f3Smrg   trans->base.layer_stride = util_format_get_2d_size(res->base.format,
7157ec681f3Smrg                                                      trans->base.stride,
7167ec681f3Smrg                                                      box->height);
7177ec681f3Smrg}
7187ec681f3Smrg
7197ec681f3Smrgstatic void *
7207ec681f3Smrgread_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res,
7217ec681f3Smrg                const struct pipe_box *box,
7227ec681f3Smrg                struct d3d12_transfer *trans)
7237ec681f3Smrg{
7247ec681f3Smrg   pipe_screen *pscreen = ctx->base.screen;
7257ec681f3Smrg
7267ec681f3Smrg   prepare_zs_layer_strides(res, box, trans);
7277ec681f3Smrg
7287ec681f3Smrg   struct pipe_resource tmpl;
7297ec681f3Smrg   memset(&tmpl, 0, sizeof tmpl);
7307ec681f3Smrg   tmpl.target = PIPE_BUFFER;
7317ec681f3Smrg   tmpl.format = PIPE_FORMAT_R32_UNORM;
7327ec681f3Smrg   tmpl.bind = 0;
7337ec681f3Smrg   tmpl.usage = PIPE_USAGE_STAGING;
7347ec681f3Smrg   tmpl.flags = 0;
7357ec681f3Smrg   tmpl.width0 = trans->base.layer_stride;
7367ec681f3Smrg   tmpl.height0 = 1;
7377ec681f3Smrg   tmpl.depth0 = 1;
7387ec681f3Smrg   tmpl.array_size = 1;
7397ec681f3Smrg
7407ec681f3Smrg   local_resource depth_buffer(pscreen, &tmpl);
7417ec681f3Smrg   if (!depth_buffer) {
7427ec681f3Smrg      debug_printf("Allocating staging buffer for depth failed\n");
7437ec681f3Smrg      return NULL;
7447ec681f3Smrg   }
7457ec681f3Smrg
7467ec681f3Smrg   if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0))
7477ec681f3Smrg      return NULL;
7487ec681f3Smrg
7497ec681f3Smrg   tmpl.format = PIPE_FORMAT_R8_UINT;
7507ec681f3Smrg
7517ec681f3Smrg   local_resource stencil_buffer(pscreen, &tmpl);
7527ec681f3Smrg   if (!stencil_buffer) {
7537ec681f3Smrg      debug_printf("Allocating staging buffer for stencilfailed\n");
7547ec681f3Smrg      return NULL;
7557ec681f3Smrg   }
7567ec681f3Smrg
7577ec681f3Smrg   if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1))
7587ec681f3Smrg      return NULL;
7597ec681f3Smrg
7607ec681f3Smrg   d3d12_flush_cmdlist_and_wait(ctx);
7617ec681f3Smrg
7627ec681f3Smrg   void *depth_ptr = depth_buffer.map();
7637ec681f3Smrg   if (!depth_ptr) {
7647ec681f3Smrg      debug_printf("Mapping staging depth buffer failed\n");
7657ec681f3Smrg      return NULL;
7667ec681f3Smrg   }
7677ec681f3Smrg
7687ec681f3Smrg   uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
7697ec681f3Smrg   if (!stencil_ptr) {
7707ec681f3Smrg      debug_printf("Mapping staging stencil buffer failed\n");
7717ec681f3Smrg      return NULL;
7727ec681f3Smrg   }
7737ec681f3Smrg
7747ec681f3Smrg   uint8_t *buf = (uint8_t *)malloc(trans->base.layer_stride);
7757ec681f3Smrg   if (!buf)
7767ec681f3Smrg      return NULL;
7777ec681f3Smrg
7787ec681f3Smrg   trans->data = buf;
7797ec681f3Smrg
7807ec681f3Smrg   switch (res->base.format) {
7817ec681f3Smrg   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
7827ec681f3Smrg      util_format_z24_unorm_s8_uint_pack_separate(buf, trans->base.stride,
7837ec681f3Smrg                                                  (uint32_t *)depth_ptr, trans->base.stride,
7847ec681f3Smrg                                                  stencil_ptr, trans->base.stride,
7857ec681f3Smrg                                                  trans->base.box.width, trans->base.box.height);
7867ec681f3Smrg      break;
7877ec681f3Smrg   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
7887ec681f3Smrg      util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->base.stride,
7897ec681f3Smrg                                                    (float *)depth_ptr, trans->base.stride,
7907ec681f3Smrg                                                    trans->base.box.width, trans->base.box.height);
7917ec681f3Smrg      util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->base.stride,
7927ec681f3Smrg                                                    stencil_ptr, trans->base.stride,
7937ec681f3Smrg                                                    trans->base.box.width, trans->base.box.height);
7947ec681f3Smrg      break;
7957ec681f3Smrg   default:
7967ec681f3Smrg      unreachable("Unsupported depth steancil format");
7977ec681f3Smrg   };
7987ec681f3Smrg
7997ec681f3Smrg   return trans->data;
8007ec681f3Smrg}
8017ec681f3Smrg
8027ec681f3Smrgstatic void *
8037ec681f3Smrgprepare_write_zs_surface(struct d3d12_resource *res,
8047ec681f3Smrg                         const struct pipe_box *box,
8057ec681f3Smrg                         struct d3d12_transfer *trans)
8067ec681f3Smrg{
8077ec681f3Smrg   prepare_zs_layer_strides(res, box, trans);
8087ec681f3Smrg   uint32_t *buf = (uint32_t *)malloc(trans->base.layer_stride);
8097ec681f3Smrg   if (!buf)
8107ec681f3Smrg      return NULL;
8117ec681f3Smrg
8127ec681f3Smrg   trans->data = buf;
8137ec681f3Smrg   return trans->data;
8147ec681f3Smrg}
8157ec681f3Smrg
8167ec681f3Smrgstatic void
8177ec681f3Smrgwrite_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,
8187ec681f3Smrg                 struct d3d12_transfer *trans)
8197ec681f3Smrg{
8207ec681f3Smrg   struct pipe_resource tmpl;
8217ec681f3Smrg   memset(&tmpl, 0, sizeof tmpl);
8227ec681f3Smrg   tmpl.target = PIPE_BUFFER;
8237ec681f3Smrg   tmpl.format = PIPE_FORMAT_R32_UNORM;
8247ec681f3Smrg   tmpl.bind = 0;
8257ec681f3Smrg   tmpl.usage = PIPE_USAGE_STAGING;
8267ec681f3Smrg   tmpl.flags = 0;
8277ec681f3Smrg   tmpl.width0 = trans->base.layer_stride;
8287ec681f3Smrg   tmpl.height0 = 1;
8297ec681f3Smrg   tmpl.depth0 = 1;
8307ec681f3Smrg   tmpl.array_size = 1;
8317ec681f3Smrg
8327ec681f3Smrg   local_resource depth_buffer(pctx->screen, &tmpl);
8337ec681f3Smrg   if (!depth_buffer) {
8347ec681f3Smrg      debug_printf("Allocating staging buffer for depth failed\n");
8357ec681f3Smrg      return;
8367ec681f3Smrg   }
8377ec681f3Smrg
8387ec681f3Smrg   local_resource stencil_buffer(pctx->screen, &tmpl);
8397ec681f3Smrg   if (!stencil_buffer) {
8407ec681f3Smrg      debug_printf("Allocating staging buffer for depth failed\n");
8417ec681f3Smrg      return;
8427ec681f3Smrg   }
8437ec681f3Smrg
8447ec681f3Smrg   void *depth_ptr = depth_buffer.map();
8457ec681f3Smrg   if (!depth_ptr) {
8467ec681f3Smrg      debug_printf("Mapping staging depth buffer failed\n");
8477ec681f3Smrg      return;
8487ec681f3Smrg   }
8497ec681f3Smrg
8507ec681f3Smrg   uint8_t *stencil_ptr =  (uint8_t *)stencil_buffer.map();
8517ec681f3Smrg   if (!stencil_ptr) {
8527ec681f3Smrg      debug_printf("Mapping staging stencil buffer failed\n");
8537ec681f3Smrg      return;
8547ec681f3Smrg   }
8557ec681f3Smrg
8567ec681f3Smrg   switch (res->base.format) {
8577ec681f3Smrg   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
8587ec681f3Smrg      util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.stride, (uint8_t*)trans->data,
8597ec681f3Smrg                                             trans->base.stride, trans->base.box.width,
8607ec681f3Smrg                                             trans->base.box.height);
8617ec681f3Smrg      util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.stride, (uint8_t*)trans->data,
8627ec681f3Smrg                                                   trans->base.stride, trans->base.box.width,
8637ec681f3Smrg                                                   trans->base.box.height);
8647ec681f3Smrg      break;
8657ec681f3Smrg   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
8667ec681f3Smrg      util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.stride, (uint8_t*)trans->data,
8677ec681f3Smrg                                                      trans->base.stride, trans->base.box.width,
8687ec681f3Smrg                                                      trans->base.box.height);
8697ec681f3Smrg      util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.stride, (uint8_t*)trans->data,
8707ec681f3Smrg                                                      trans->base.stride, trans->base.box.width,
8717ec681f3Smrg                                                      trans->base.box.height);
8727ec681f3Smrg      break;
8737ec681f3Smrg   default:
8747ec681f3Smrg      unreachable("Unsupported depth steancil format");
8757ec681f3Smrg   };
8767ec681f3Smrg
8777ec681f3Smrg   stencil_buffer.unmap();
8787ec681f3Smrg   depth_buffer.unmap();
8797ec681f3Smrg
8807ec681f3Smrg   transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0);
8817ec681f3Smrg   transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);
8827ec681f3Smrg}
8837ec681f3Smrg
8847ec681f3Smrg#define BUFFER_MAP_ALIGNMENT 64
8857ec681f3Smrg
8867ec681f3Smrgstatic void *
8877ec681f3Smrgd3d12_transfer_map(struct pipe_context *pctx,
8887ec681f3Smrg                   struct pipe_resource *pres,
8897ec681f3Smrg                   unsigned level,
8907ec681f3Smrg                   unsigned usage,
8917ec681f3Smrg                   const struct pipe_box *box,
8927ec681f3Smrg                   struct pipe_transfer **transfer)
8937ec681f3Smrg{
8947ec681f3Smrg   struct d3d12_context *ctx = d3d12_context(pctx);
8957ec681f3Smrg   struct d3d12_resource *res = d3d12_resource(pres);
8967ec681f3Smrg
8977ec681f3Smrg   if (usage & PIPE_MAP_DIRECTLY || !res->bo)
8987ec681f3Smrg      return NULL;
8997ec681f3Smrg
9007ec681f3Smrg   struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_alloc(&ctx->transfer_pool);
9017ec681f3Smrg   struct pipe_transfer *ptrans = &trans->base;
9027ec681f3Smrg   if (!trans)
9037ec681f3Smrg      return NULL;
9047ec681f3Smrg
9057ec681f3Smrg   memset(trans, 0, sizeof(*trans));
9067ec681f3Smrg   pipe_resource_reference(&ptrans->resource, pres);
9077ec681f3Smrg
9087ec681f3Smrg   ptrans->resource = pres;
9097ec681f3Smrg   ptrans->level = level;
9107ec681f3Smrg   ptrans->usage = (enum pipe_map_flags)usage;
9117ec681f3Smrg   ptrans->box = *box;
9127ec681f3Smrg
9137ec681f3Smrg   D3D12_RANGE range;
9147ec681f3Smrg   range.Begin = 0;
9157ec681f3Smrg
9167ec681f3Smrg   void *ptr;
9177ec681f3Smrg   if (can_map_directly(&res->base)) {
9187ec681f3Smrg      if (pres->target == PIPE_BUFFER) {
9197ec681f3Smrg         ptrans->stride = 0;
9207ec681f3Smrg         ptrans->layer_stride = 0;
9217ec681f3Smrg      } else {
9227ec681f3Smrg         ptrans->stride = util_format_get_stride(pres->format, box->width);
9237ec681f3Smrg         ptrans->layer_stride = util_format_get_2d_size(pres->format,
9247ec681f3Smrg                                                        ptrans->stride,
9257ec681f3Smrg                                                        box->height);
9267ec681f3Smrg      }
9277ec681f3Smrg
9287ec681f3Smrg      range = linear_range(box, ptrans->stride, ptrans->layer_stride);
9297ec681f3Smrg      if (!synchronize(ctx, res, usage, &range))
9307ec681f3Smrg         return NULL;
9317ec681f3Smrg      ptr = d3d12_bo_map(res->bo, &range);
9327ec681f3Smrg   } else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||
9337ec681f3Smrg                       pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) {
9347ec681f3Smrg      if (usage & PIPE_MAP_READ) {
9357ec681f3Smrg         ptr = read_zs_surface(ctx, res, box, trans);
9367ec681f3Smrg      } else if (usage & PIPE_MAP_WRITE){
9377ec681f3Smrg         ptr = prepare_write_zs_surface(res, box, trans);
9387ec681f3Smrg      } else {
9397ec681f3Smrg         ptr = nullptr;
9407ec681f3Smrg      }
9417ec681f3Smrg   } else {
9427ec681f3Smrg      ptrans->stride = align(util_format_get_stride(pres->format, box->width),
9437ec681f3Smrg                              D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
9447ec681f3Smrg      ptrans->layer_stride = util_format_get_2d_size(pres->format,
9457ec681f3Smrg                                                     ptrans->stride,
9467ec681f3Smrg                                                     box->height);
9477ec681f3Smrg
9487ec681f3Smrg      if (res->base.target != PIPE_TEXTURE_3D)
9497ec681f3Smrg         ptrans->layer_stride = align(ptrans->layer_stride,
9507ec681f3Smrg                                      D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
9517ec681f3Smrg
9527ec681f3Smrg      unsigned staging_res_size = ptrans->layer_stride * box->depth;
9537ec681f3Smrg      if (res->base.target == PIPE_BUFFER) {
9547ec681f3Smrg         /* To properly support ARB_map_buffer_alignment, we need to return a pointer
9557ec681f3Smrg          * that's appropriately offset from a 64-byte-aligned base address.
9567ec681f3Smrg          */
9577ec681f3Smrg         assert(box->x >= 0);
9587ec681f3Smrg         unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT;
9597ec681f3Smrg         staging_res_size = align(box->width + aligned_x,
9607ec681f3Smrg                                  D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
9617ec681f3Smrg         range.Begin = aligned_x;
9627ec681f3Smrg      }
9637ec681f3Smrg
9647ec681f3Smrg      pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?
9657ec681f3Smrg         PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
9667ec681f3Smrg
9677ec681f3Smrg      trans->staging_res = pipe_buffer_create(pctx->screen, 0,
9687ec681f3Smrg                                              staging_usage,
9697ec681f3Smrg                                              staging_res_size);
9707ec681f3Smrg      if (!trans->staging_res)
9717ec681f3Smrg         return NULL;
9727ec681f3Smrg
9737ec681f3Smrg      struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
9747ec681f3Smrg
9757ec681f3Smrg      if (usage & PIPE_MAP_READ) {
9767ec681f3Smrg         bool ret = true;
9777ec681f3Smrg         if (pres->target == PIPE_BUFFER) {
9787ec681f3Smrg            uint64_t src_offset = box->x;
9797ec681f3Smrg            uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT;
9807ec681f3Smrg            transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width);
9817ec681f3Smrg         } else
9827ec681f3Smrg            ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);
9837ec681f3Smrg         if (!ret)
9847ec681f3Smrg            return NULL;
9857ec681f3Smrg         d3d12_flush_cmdlist_and_wait(ctx);
9867ec681f3Smrg      }
9877ec681f3Smrg
9887ec681f3Smrg      range.End = staging_res_size - range.Begin;
9897ec681f3Smrg
9907ec681f3Smrg      ptr = d3d12_bo_map(staging_res->bo, &range);
9917ec681f3Smrg   }
9927ec681f3Smrg
9937ec681f3Smrg   *transfer = ptrans;
9947ec681f3Smrg   return ptr;
9957ec681f3Smrg}
9967ec681f3Smrg
9977ec681f3Smrgstatic void
9987ec681f3Smrgd3d12_transfer_unmap(struct pipe_context *pctx,
9997ec681f3Smrg                     struct pipe_transfer *ptrans)
10007ec681f3Smrg{
10017ec681f3Smrg   struct d3d12_resource *res = d3d12_resource(ptrans->resource);
10027ec681f3Smrg   struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;
10037ec681f3Smrg   D3D12_RANGE range = { 0, 0 };
10047ec681f3Smrg
10057ec681f3Smrg   if (trans->data != nullptr) {
10067ec681f3Smrg      if (trans->base.usage & PIPE_MAP_WRITE)
10077ec681f3Smrg         write_zs_surface(pctx, res, trans);
10087ec681f3Smrg      free(trans->data);
10097ec681f3Smrg   } else if (trans->staging_res) {
10107ec681f3Smrg      struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);
10117ec681f3Smrg
10127ec681f3Smrg      if (trans->base.usage & PIPE_MAP_WRITE) {
10137ec681f3Smrg         assert(ptrans->box.x >= 0);
10147ec681f3Smrg         range.Begin = res->base.target == PIPE_BUFFER ?
10157ec681f3Smrg            (unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;
10167ec681f3Smrg         range.End = staging_res->base.width0 - range.Begin;
10177ec681f3Smrg      }
10187ec681f3Smrg      d3d12_bo_unmap(staging_res->bo, &range);
10197ec681f3Smrg
10207ec681f3Smrg      if (trans->base.usage & PIPE_MAP_WRITE) {
10217ec681f3Smrg         struct d3d12_context *ctx = d3d12_context(pctx);
10227ec681f3Smrg         if (res->base.target == PIPE_BUFFER) {
10237ec681f3Smrg            uint64_t dst_offset = trans->base.box.x;
10247ec681f3Smrg            uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;
10257ec681f3Smrg            transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);
10267ec681f3Smrg         } else
10277ec681f3Smrg            transfer_buf_to_image(ctx, res, staging_res, trans, 0);
10287ec681f3Smrg      }
10297ec681f3Smrg
10307ec681f3Smrg      pipe_resource_reference(&trans->staging_res, NULL);
10317ec681f3Smrg   } else {
10327ec681f3Smrg      if (trans->base.usage & PIPE_MAP_WRITE) {
10337ec681f3Smrg         range.Begin = ptrans->box.x;
10347ec681f3Smrg         range.End = ptrans->box.x + ptrans->box.width;
10357ec681f3Smrg      }
10367ec681f3Smrg      d3d12_bo_unmap(res->bo, &range);
10377ec681f3Smrg   }
10387ec681f3Smrg
10397ec681f3Smrg   pipe_resource_reference(&ptrans->resource, NULL);
10407ec681f3Smrg   slab_free(&d3d12_context(pctx)->transfer_pool, ptrans);
10417ec681f3Smrg}
10427ec681f3Smrg
10437ec681f3Smrgvoid
10447ec681f3Smrgd3d12_resource_make_writeable(struct pipe_context *pctx,
10457ec681f3Smrg                              struct pipe_resource *pres)
10467ec681f3Smrg{
10477ec681f3Smrg   struct d3d12_context *ctx = d3d12_context(pctx);
10487ec681f3Smrg   struct d3d12_resource *res = d3d12_resource(pres);
10497ec681f3Smrg   struct d3d12_resource *dup_res;
10507ec681f3Smrg
10517ec681f3Smrg   if (!res->bo || !d3d12_bo_is_suballocated(res->bo))
10527ec681f3Smrg      return;
10537ec681f3Smrg
10547ec681f3Smrg   dup_res = d3d12_resource(pipe_buffer_create(pres->screen,
10557ec681f3Smrg                                               pres->bind & PIPE_BIND_STREAM_OUTPUT,
10567ec681f3Smrg                                               (pipe_resource_usage) pres->usage,
10577ec681f3Smrg                                               pres->width0));
10587ec681f3Smrg
10597ec681f3Smrg   if (res->valid_buffer_range.end > res->valid_buffer_range.start) {
10607ec681f3Smrg      struct pipe_box box;
10617ec681f3Smrg
10627ec681f3Smrg      box.x = res->valid_buffer_range.start;
10637ec681f3Smrg      box.y = 0;
10647ec681f3Smrg      box.z = 0;
10657ec681f3Smrg      box.width = res->valid_buffer_range.end - res->valid_buffer_range.start;
10667ec681f3Smrg      box.height = 1;
10677ec681f3Smrg      box.depth = 1;
10687ec681f3Smrg
10697ec681f3Smrg      d3d12_direct_copy(ctx, dup_res, 0, &box, res, 0, &box, PIPE_MASK_RGBAZS);
10707ec681f3Smrg   }
10717ec681f3Smrg
10727ec681f3Smrg   /* Move new BO to old resource */
10737ec681f3Smrg   d3d12_bo_unreference(res->bo);
10747ec681f3Smrg   res->bo = dup_res->bo;
10757ec681f3Smrg   d3d12_bo_reference(res->bo);
10767ec681f3Smrg
10777ec681f3Smrg   d3d12_resource_destroy(dup_res->base.screen, &dup_res->base);
10787ec681f3Smrg}
10797ec681f3Smrg
10807ec681f3Smrgvoid
10817ec681f3Smrgd3d12_context_resource_init(struct pipe_context *pctx)
10827ec681f3Smrg{
10837ec681f3Smrg   pctx->buffer_map = d3d12_transfer_map;
10847ec681f3Smrg   pctx->buffer_unmap = d3d12_transfer_unmap;
10857ec681f3Smrg   pctx->texture_map = d3d12_transfer_map;
10867ec681f3Smrg   pctx->texture_unmap = d3d12_transfer_unmap;
10877ec681f3Smrg
10887ec681f3Smrg   pctx->transfer_flush_region = u_default_transfer_flush_region;
10897ec681f3Smrg   pctx->buffer_subdata = u_default_buffer_subdata;
10907ec681f3Smrg   pctx->texture_subdata = u_default_texture_subdata;
10917ec681f3Smrg}
1092