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