Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_resource.cpp
4570 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "d3d12_resource.h"2425#include "d3d12_blit.h"26#include "d3d12_context.h"27#include "d3d12_format.h"28#include "d3d12_screen.h"29#include "d3d12_debug.h"3031#include "pipebuffer/pb_bufmgr.h"32#include "util/slab.h"33#include "util/format/u_format.h"34#include "util/u_inlines.h"35#include "util/u_memory.h"36#include "util/format/u_format_zs.h"3738#include "frontend/sw_winsys.h"3940#include <directx/d3d12.h>41#include <dxguids/dxguids.h>42#include <memory>4344static bool45can_map_directly(struct pipe_resource *pres)46{47return pres->target == PIPE_BUFFER &&48pres->usage != PIPE_USAGE_DEFAULT &&49pres->usage != PIPE_USAGE_IMMUTABLE;50}5152static void53init_valid_range(struct d3d12_resource *res)54{55if (can_map_directly(&res->base))56util_range_init(&res->valid_buffer_range);57}5859static void60d3d12_resource_destroy(struct pipe_screen *pscreen,61struct pipe_resource *presource)62{63struct d3d12_resource *resource = d3d12_resource(presource);64if (can_map_directly(presource))65util_range_destroy(&resource->valid_buffer_range);66if (resource->bo)67d3d12_bo_unreference(resource->bo);68FREE(resource);69}7071static bool72resource_is_busy(struct d3d12_context *ctx,73struct d3d12_resource *res)74{75bool busy = false;7677for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); i++)78busy |= d3d12_batch_has_references(&ctx->batches[i], res->bo);7980return busy;81}8283void84d3d12_resource_wait_idle(struct d3d12_context *ctx,85struct d3d12_resource *res)86{87if (d3d12_batch_has_references(d3d12_current_batch(ctx), res->bo)) {88d3d12_flush_cmdlist_and_wait(ctx);89} else {90d3d12_foreach_submitted_batch(ctx, batch) {91d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);92if (!resource_is_busy(ctx, res))93break;94}95}96}9798void99d3d12_resource_release(struct d3d12_resource *resource)100{101if (!resource->bo)102return;103d3d12_bo_unreference(resource->bo);104resource->bo = NULL;105}106107static bool108init_buffer(struct d3d12_screen *screen,109struct d3d12_resource *res,110const struct pipe_resource *templ)111{112struct pb_desc buf_desc;113struct pb_manager *bufmgr;114struct pb_buffer *buf;115116/* Assert that we don't want to create a buffer with one of the emulated117* formats, these are (currently) only supported when passing the vertex118* element state */119assert(templ->format == d3d12_emulated_vtx_format(templ->format));120121switch (templ->usage) {122case PIPE_USAGE_DEFAULT:123case PIPE_USAGE_IMMUTABLE:124bufmgr = screen->cache_bufmgr;125buf_desc.usage = (pb_usage_flags)PB_USAGE_GPU_READ_WRITE;126break;127case PIPE_USAGE_DYNAMIC:128case PIPE_USAGE_STREAM:129bufmgr = screen->slab_bufmgr;130buf_desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ);131break;132case PIPE_USAGE_STAGING:133bufmgr = screen->readback_slab_bufmgr;134buf_desc.usage = (pb_usage_flags)(PB_USAGE_GPU_WRITE | PB_USAGE_CPU_READ_WRITE);135break;136default:137unreachable("Invalid pipe usage");138}139buf_desc.alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;140res->dxgi_format = DXGI_FORMAT_UNKNOWN;141buf = bufmgr->create_buffer(bufmgr, templ->width0, &buf_desc);142if (!buf)143return false;144res->bo = d3d12_bo_wrap_buffer(buf);145146return true;147}148149static bool150init_texture(struct d3d12_screen *screen,151struct d3d12_resource *res,152const struct pipe_resource *templ)153{154ID3D12Resource *d3d12_res;155156res->mip_levels = templ->last_level + 1;157res->dxgi_format = d3d12_get_format(templ->format);158159D3D12_RESOURCE_DESC desc;160desc.Format = res->dxgi_format;161desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;162desc.Width = templ->width0;163desc.Height = templ->height0;164desc.DepthOrArraySize = templ->array_size;165desc.MipLevels = templ->last_level + 1;166167desc.SampleDesc.Count = MAX2(templ->nr_samples, 1);168desc.SampleDesc.Quality = 0; /* TODO: figure this one out */169170switch (templ->target) {171case PIPE_TEXTURE_1D:172case PIPE_TEXTURE_1D_ARRAY:173desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;174break;175176case PIPE_TEXTURE_CUBE:177case PIPE_TEXTURE_CUBE_ARRAY:178desc.DepthOrArraySize *= 6;179FALLTHROUGH;180case PIPE_TEXTURE_2D:181case PIPE_TEXTURE_2D_ARRAY:182case PIPE_TEXTURE_RECT:183desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;184break;185186case PIPE_TEXTURE_3D:187desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;188desc.DepthOrArraySize = templ->depth0;189break;190191default:192unreachable("Invalid texture type");193}194195desc.Flags = D3D12_RESOURCE_FLAG_NONE;196197if (templ->bind & PIPE_BIND_SHADER_BUFFER)198desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;199200if (templ->bind & PIPE_BIND_RENDER_TARGET)201desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;202203if (templ->bind & PIPE_BIND_DEPTH_STENCIL) {204desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;205206/* Sadly, we can't set D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE in the207* case where PIPE_BIND_SAMPLER_VIEW isn't set, because that would208* prevent us from using the resource with u_blitter, which requires209* sneaking in sampler-usage throught the back-door.210*/211}212213desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;214if (templ->bind & (PIPE_BIND_SCANOUT |215PIPE_BIND_SHARED | PIPE_BIND_LINEAR))216desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;217218D3D12_HEAP_PROPERTIES heap_pris = screen->dev->GetCustomHeapProperties(0, D3D12_HEAP_TYPE_DEFAULT);219220HRESULT hres = screen->dev->CreateCommittedResource(&heap_pris,221D3D12_HEAP_FLAG_NONE,222&desc,223D3D12_RESOURCE_STATE_COMMON,224NULL,225IID_PPV_ARGS(&d3d12_res));226if (FAILED(hres))227return false;228229if (screen->winsys && (templ->bind & PIPE_BIND_DISPLAY_TARGET)) {230struct sw_winsys *winsys = screen->winsys;231res->dt = winsys->displaytarget_create(screen->winsys,232res->base.bind,233res->base.format,234templ->width0,235templ->height0,23664, NULL,237&res->dt_stride);238}239240res->bo = d3d12_bo_wrap_res(d3d12_res, templ->format);241242return true;243}244245static struct pipe_resource *246d3d12_resource_create(struct pipe_screen *pscreen,247const struct pipe_resource *templ)248{249struct d3d12_screen *screen = d3d12_screen(pscreen);250struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);251bool ret;252253res->base = *templ;254255if (D3D12_DEBUG_RESOURCE & d3d12_debug) {256debug_printf("D3D12: Create %sresource %s@%d %dx%dx%d as:%d mip:%d\n",257templ->usage == PIPE_USAGE_STAGING ? "STAGING " :"",258util_format_name(templ->format), templ->nr_samples,259templ->width0, templ->height0, templ->depth0,260templ->array_size, templ->last_level);261}262263pipe_reference_init(&res->base.reference, 1);264res->base.screen = pscreen;265266if (templ->target == PIPE_BUFFER) {267ret = init_buffer(screen, res, templ);268} else {269ret = init_texture(screen, res, templ);270}271272if (!ret) {273FREE(res);274return NULL;275}276277init_valid_range(res);278279memset(&res->bind_counts, 0, sizeof(d3d12_resource::bind_counts));280281return &res->base;282}283284static struct pipe_resource *285d3d12_resource_from_handle(struct pipe_screen *pscreen,286const struct pipe_resource *templ,287struct winsys_handle *handle, unsigned usage)288{289if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES)290return NULL;291292struct d3d12_resource *res = CALLOC_STRUCT(d3d12_resource);293if (!res)294return NULL;295296res->base = *templ;297pipe_reference_init(&res->base.reference, 1);298res->base.screen = pscreen;299res->dxgi_format = templ->target == PIPE_BUFFER ? DXGI_FORMAT_UNKNOWN :300d3d12_get_format(templ->format);301res->bo = d3d12_bo_wrap_res((ID3D12Resource *)handle->com_obj, templ->format);302init_valid_range(res);303return &res->base;304}305306static bool307d3d12_resource_get_handle(struct pipe_screen *pscreen,308struct pipe_context *pcontext,309struct pipe_resource *pres,310struct winsys_handle *handle,311unsigned usage)312{313struct d3d12_resource *res = d3d12_resource(pres);314315if (handle->type != WINSYS_HANDLE_TYPE_D3D12_RES)316return false;317318handle->com_obj = d3d12_resource_resource(res);319return true;320}321322void323d3d12_screen_resource_init(struct pipe_screen *pscreen)324{325pscreen->resource_create = d3d12_resource_create;326pscreen->resource_from_handle = d3d12_resource_from_handle;327pscreen->resource_get_handle = d3d12_resource_get_handle;328pscreen->resource_destroy = d3d12_resource_destroy;329}330331unsigned int332get_subresource_id(struct d3d12_resource *res, unsigned resid,333unsigned z, unsigned base_level)334{335unsigned resource_stride = res->base.last_level + 1;336if (res->base.target == PIPE_TEXTURE_1D_ARRAY ||337res->base.target == PIPE_TEXTURE_2D_ARRAY)338resource_stride *= res->base.array_size;339340if (res->base.target == PIPE_TEXTURE_CUBE)341resource_stride *= 6;342343if (res->base.target == PIPE_TEXTURE_CUBE_ARRAY)344resource_stride *= 6 * res->base.array_size;345346unsigned layer_stride = res->base.last_level + 1;347348return resid * resource_stride + z * layer_stride +349base_level;350}351352static D3D12_TEXTURE_COPY_LOCATION353fill_texture_location(struct d3d12_resource *res,354struct d3d12_transfer *trans, unsigned resid, unsigned z)355{356D3D12_TEXTURE_COPY_LOCATION tex_loc = {0};357int subres = get_subresource_id(res, resid, z, trans->base.level);358359tex_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;360tex_loc.SubresourceIndex = subres;361tex_loc.pResource = d3d12_resource_resource(res);362return tex_loc;363}364365static D3D12_TEXTURE_COPY_LOCATION366fill_buffer_location(struct d3d12_context *ctx,367struct d3d12_resource *res,368struct d3d12_resource *staging_res,369struct d3d12_transfer *trans,370unsigned depth,371unsigned resid, unsigned z)372{373D3D12_TEXTURE_COPY_LOCATION buf_loc = {0};374D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;375uint64_t offset = 0;376auto descr = d3d12_resource_underlying(res, &offset)->GetDesc();377ID3D12Device* dev = d3d12_screen(ctx->base.screen)->dev;378379unsigned sub_resid = get_subresource_id(res, resid, z, trans->base.level);380dev->GetCopyableFootprints(&descr, sub_resid, 1, 0, &footprint, nullptr, nullptr, nullptr);381382buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;383buf_loc.pResource = d3d12_resource_underlying(staging_res, &offset);384buf_loc.PlacedFootprint = footprint;385buf_loc.PlacedFootprint.Offset += offset;386387buf_loc.PlacedFootprint.Footprint.Width = ALIGN(trans->base.box.width,388util_format_get_blockwidth(res->base.format));389buf_loc.PlacedFootprint.Footprint.Height = ALIGN(trans->base.box.height,390util_format_get_blockheight(res->base.format));391buf_loc.PlacedFootprint.Footprint.Depth = ALIGN(depth,392util_format_get_blockdepth(res->base.format));393394buf_loc.PlacedFootprint.Footprint.RowPitch = trans->base.stride;395396return buf_loc;397}398399struct copy_info {400struct d3d12_resource *dst;401D3D12_TEXTURE_COPY_LOCATION dst_loc;402UINT dst_x, dst_y, dst_z;403struct d3d12_resource *src;404D3D12_TEXTURE_COPY_LOCATION src_loc;405D3D12_BOX *src_box;406};407408409static void410copy_texture_region(struct d3d12_context *ctx,411struct copy_info& info)412{413auto batch = d3d12_current_batch(ctx);414415d3d12_batch_reference_resource(batch, info.src);416d3d12_batch_reference_resource(batch, info.dst);417d3d12_transition_resource_state(ctx, info.src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_BIND_INVALIDATE_FULL);418d3d12_transition_resource_state(ctx, info.dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_FULL);419d3d12_apply_resource_states(ctx);420ctx->cmdlist->CopyTextureRegion(&info.dst_loc, info.dst_x, info.dst_y, info.dst_z,421&info.src_loc, info.src_box);422}423424static void425transfer_buf_to_image_part(struct d3d12_context *ctx,426struct d3d12_resource *res,427struct d3d12_resource *staging_res,428struct d3d12_transfer *trans,429int z, int depth, int start_z, int dest_z,430int resid)431{432if (D3D12_DEBUG_RESOURCE & d3d12_debug) {433debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from buffer %s to image %s\n",434trans->base.box.x, trans->base.box.y, trans->base.box.z,435trans->base.box.width, trans->base.box.height, trans->base.box.depth,436util_format_name(staging_res->base.format),437util_format_name(res->base.format));438}439440struct copy_info copy_info;441copy_info.src = staging_res;442copy_info.src_loc = fill_buffer_location(ctx, res, staging_res, trans, depth, resid, z);443copy_info.src_loc.PlacedFootprint.Offset = (z - start_z) * trans->base.layer_stride;444copy_info.src_box = nullptr;445copy_info.dst = res;446copy_info.dst_loc = fill_texture_location(res, trans, resid, z);447copy_info.dst_x = trans->base.box.x;448copy_info.dst_y = trans->base.box.y;449copy_info.dst_z = res->base.target == PIPE_TEXTURE_CUBE ? 0 : dest_z;450copy_info.src_box = nullptr;451452copy_texture_region(ctx, copy_info);453}454455static bool456transfer_buf_to_image(struct d3d12_context *ctx,457struct d3d12_resource *res,458struct d3d12_resource *staging_res,459struct d3d12_transfer *trans, int resid)460{461if (res->base.target == PIPE_TEXTURE_3D) {462assert(resid == 0);463transfer_buf_to_image_part(ctx, res, staging_res, trans,4640, trans->base.box.depth, 0,465trans->base.box.z, 0);466} else {467int num_layers = trans->base.box.depth;468int start_z = trans->base.box.z;469470for (int z = start_z; z < start_z + num_layers; ++z) {471transfer_buf_to_image_part(ctx, res, staging_res, trans,472z, 1, start_z, 0, resid);473}474}475return true;476}477478static void479transfer_image_part_to_buf(struct d3d12_context *ctx,480struct d3d12_resource *res,481struct d3d12_resource *staging_res,482struct d3d12_transfer *trans,483unsigned resid, int z, int start_layer,484int start_box_z, int depth)485{486struct pipe_box *box = &trans->base.box;487D3D12_BOX src_box = {};488489struct copy_info copy_info;490copy_info.src_box = nullptr;491copy_info.src = res;492copy_info.src_loc = fill_texture_location(res, trans, resid, z);493copy_info.dst = staging_res;494copy_info.dst_loc = fill_buffer_location(ctx, res, staging_res, trans,495depth, resid, z);496copy_info.dst_loc.PlacedFootprint.Offset = (z - start_layer) * trans->base.layer_stride;497copy_info.dst_x = copy_info.dst_y = copy_info.dst_z = 0;498499if (!util_texrange_covers_whole_level(&res->base, trans->base.level,500box->x, box->y, start_box_z,501box->width, box->height, depth)) {502src_box.left = box->x;503src_box.right = box->x + box->width;504src_box.top = box->y;505src_box.bottom = box->y + box->height;506src_box.front = start_box_z;507src_box.back = start_box_z + depth;508copy_info.src_box = &src_box;509}510511copy_texture_region(ctx, copy_info);512}513514static bool515transfer_image_to_buf(struct d3d12_context *ctx,516struct d3d12_resource *res,517struct d3d12_resource *staging_res,518struct d3d12_transfer *trans,519unsigned resid)520{521522/* We only suppport loading from either an texture array523* or a ZS texture, so either resid is zero, or num_layers == 1)524*/525assert(resid == 0 || trans->base.box.depth == 1);526527if (D3D12_DEBUG_RESOURCE & d3d12_debug) {528debug_printf("D3D12: Copy %dx%dx%d + %dx%dx%d from %s@%d to %s\n",529trans->base.box.x, trans->base.box.y, trans->base.box.z,530trans->base.box.width, trans->base.box.height, trans->base.box.depth,531util_format_name(res->base.format), resid,532util_format_name(staging_res->base.format));533}534535struct pipe_resource *resolved_resource = nullptr;536if (res->base.nr_samples > 1) {537struct pipe_resource tmpl = res->base;538tmpl.nr_samples = 0;539resolved_resource = d3d12_resource_create(ctx->base.screen, &tmpl);540struct pipe_blit_info resolve_info = {};541struct pipe_box box = {0,0,0, (int)res->base.width0, (int16_t)res->base.height0, (int16_t)res->base.depth0};542resolve_info.dst.resource = resolved_resource;543resolve_info.dst.box = box;544resolve_info.dst.format = res->base.format;545resolve_info.src.resource = &res->base;546resolve_info.src.box = box;547resolve_info.src.format = res->base.format;548resolve_info.filter = PIPE_TEX_FILTER_NEAREST;549resolve_info.mask = util_format_get_mask(tmpl.format);550551552553d3d12_blit(&ctx->base, &resolve_info);554res = (struct d3d12_resource *)resolved_resource;555}556557558if (res->base.target == PIPE_TEXTURE_3D) {559transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,5600, 0, trans->base.box.z, trans->base.box.depth);561} else {562int start_layer = trans->base.box.z;563for (int z = start_layer; z < start_layer + trans->base.box.depth; ++z) {564transfer_image_part_to_buf(ctx, res, staging_res, trans, resid,565z, start_layer, 0, 1);566}567}568569pipe_resource_reference(&resolved_resource, NULL);570571return true;572}573574static void575transfer_buf_to_buf(struct d3d12_context *ctx,576struct d3d12_resource *src,577struct d3d12_resource *dst,578uint64_t src_offset,579uint64_t dst_offset,580uint64_t width)581{582auto batch = d3d12_current_batch(ctx);583584d3d12_batch_reference_resource(batch, src);585d3d12_batch_reference_resource(batch, dst);586587uint64_t src_offset_suballoc = 0;588uint64_t dst_offset_suballoc = 0;589auto src_d3d12 = d3d12_resource_underlying(src, &src_offset_suballoc);590auto dst_d3d12 = d3d12_resource_underlying(dst, &dst_offset_suballoc);591src_offset += src_offset_suballoc;592dst_offset += dst_offset_suballoc;593594// Same-resource copies not supported, since the resource would need to be in both states595assert(src_d3d12 != dst_d3d12);596d3d12_transition_resource_state(ctx, src, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_BIND_INVALIDATE_FULL);597d3d12_transition_resource_state(ctx, dst, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_FULL);598d3d12_apply_resource_states(ctx);599ctx->cmdlist->CopyBufferRegion(dst_d3d12, dst_offset,600src_d3d12, src_offset,601width);602}603604static unsigned605linear_offset(int x, int y, int z, unsigned stride, unsigned layer_stride)606{607return x +608y * stride +609z * layer_stride;610}611612static D3D12_RANGE613linear_range(const struct pipe_box *box, unsigned stride, unsigned layer_stride)614{615D3D12_RANGE range;616617range.Begin = linear_offset(box->x, box->y, box->z,618stride, layer_stride);619range.End = linear_offset(box->x + box->width,620box->y + box->height - 1,621box->z + box->depth - 1,622stride, layer_stride);623624return range;625}626627static bool628synchronize(struct d3d12_context *ctx,629struct d3d12_resource *res,630unsigned usage,631D3D12_RANGE *range)632{633assert(can_map_directly(&res->base));634635/* Check whether that range contains valid data; if not, we might not need to sync */636if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&637usage & PIPE_MAP_WRITE &&638!util_ranges_intersect(&res->valid_buffer_range, range->Begin, range->End)) {639usage |= PIPE_MAP_UNSYNCHRONIZED;640}641642if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && resource_is_busy(ctx, res)) {643if (usage & PIPE_MAP_DONTBLOCK)644return false;645646d3d12_resource_wait_idle(ctx, res);647}648649if (usage & PIPE_MAP_WRITE)650util_range_add(&res->base, &res->valid_buffer_range,651range->Begin, range->End);652653return true;654}655656/* A wrapper to make sure local resources are freed and unmapped with657* any exit path */658struct local_resource {659local_resource(pipe_screen *s, struct pipe_resource *tmpl) :660mapped(false)661{662res = d3d12_resource(d3d12_resource_create(s, tmpl));663}664665~local_resource() {666if (res) {667if (mapped)668d3d12_bo_unmap(res->bo, nullptr);669pipe_resource_reference((struct pipe_resource **)&res, NULL);670}671}672673void *674map() {675void *ptr;676ptr = d3d12_bo_map(res->bo, nullptr);677if (ptr)678mapped = true;679return ptr;680}681682void unmap()683{684if (mapped)685d3d12_bo_unmap(res->bo, nullptr);686mapped = false;687}688689operator struct d3d12_resource *() {690return res;691}692693bool operator !() {694return !res;695}696private:697struct d3d12_resource *res;698bool mapped;699};700701/* Combined depth-stencil needs a special handling for reading back: DX handled702* depth and stencil parts as separate resources and handles copying them only703* by using seperate texture copy calls with different formats. So create two704* buffers, read back both resources and interleave the data.705*/706static void707prepare_zs_layer_strides(struct d3d12_resource *res,708const struct pipe_box *box,709struct d3d12_transfer *trans)710{711trans->base.stride = align(util_format_get_stride(res->base.format, box->width),712D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);713trans->base.layer_stride = util_format_get_2d_size(res->base.format,714trans->base.stride,715box->height);716}717718static void *719read_zs_surface(struct d3d12_context *ctx, struct d3d12_resource *res,720const struct pipe_box *box,721struct d3d12_transfer *trans)722{723pipe_screen *pscreen = ctx->base.screen;724725prepare_zs_layer_strides(res, box, trans);726727struct pipe_resource tmpl;728memset(&tmpl, 0, sizeof tmpl);729tmpl.target = PIPE_BUFFER;730tmpl.format = PIPE_FORMAT_R32_UNORM;731tmpl.bind = 0;732tmpl.usage = PIPE_USAGE_STAGING;733tmpl.flags = 0;734tmpl.width0 = trans->base.layer_stride;735tmpl.height0 = 1;736tmpl.depth0 = 1;737tmpl.array_size = 1;738739local_resource depth_buffer(pscreen, &tmpl);740if (!depth_buffer) {741debug_printf("Allocating staging buffer for depth failed\n");742return NULL;743}744745if (!transfer_image_to_buf(ctx, res, depth_buffer, trans, 0))746return NULL;747748tmpl.format = PIPE_FORMAT_R8_UINT;749750local_resource stencil_buffer(pscreen, &tmpl);751if (!stencil_buffer) {752debug_printf("Allocating staging buffer for stencilfailed\n");753return NULL;754}755756if (!transfer_image_to_buf(ctx, res, stencil_buffer, trans, 1))757return NULL;758759d3d12_flush_cmdlist_and_wait(ctx);760761void *depth_ptr = depth_buffer.map();762if (!depth_ptr) {763debug_printf("Mapping staging depth buffer failed\n");764return NULL;765}766767uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map();768if (!stencil_ptr) {769debug_printf("Mapping staging stencil buffer failed\n");770return NULL;771}772773uint8_t *buf = (uint8_t *)malloc(trans->base.layer_stride);774if (!buf)775return NULL;776777trans->data = buf;778779switch (res->base.format) {780case PIPE_FORMAT_Z24_UNORM_S8_UINT:781util_format_z24_unorm_s8_uint_pack_separate(buf, trans->base.stride,782(uint32_t *)depth_ptr, trans->base.stride,783stencil_ptr, trans->base.stride,784trans->base.box.width, trans->base.box.height);785break;786case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:787util_format_z32_float_s8x24_uint_pack_z_float(buf, trans->base.stride,788(float *)depth_ptr, trans->base.stride,789trans->base.box.width, trans->base.box.height);790util_format_z32_float_s8x24_uint_pack_s_8uint(buf, trans->base.stride,791stencil_ptr, trans->base.stride,792trans->base.box.width, trans->base.box.height);793break;794default:795unreachable("Unsupported depth steancil format");796};797798return trans->data;799}800801static void *802prepare_write_zs_surface(struct d3d12_resource *res,803const struct pipe_box *box,804struct d3d12_transfer *trans)805{806prepare_zs_layer_strides(res, box, trans);807uint32_t *buf = (uint32_t *)malloc(trans->base.layer_stride);808if (!buf)809return NULL;810811trans->data = buf;812return trans->data;813}814815static void816write_zs_surface(struct pipe_context *pctx, struct d3d12_resource *res,817struct d3d12_transfer *trans)818{819struct pipe_resource tmpl;820memset(&tmpl, 0, sizeof tmpl);821tmpl.target = PIPE_BUFFER;822tmpl.format = PIPE_FORMAT_R32_UNORM;823tmpl.bind = 0;824tmpl.usage = PIPE_USAGE_STAGING;825tmpl.flags = 0;826tmpl.width0 = trans->base.layer_stride;827tmpl.height0 = 1;828tmpl.depth0 = 1;829tmpl.array_size = 1;830831local_resource depth_buffer(pctx->screen, &tmpl);832if (!depth_buffer) {833debug_printf("Allocating staging buffer for depth failed\n");834return;835}836837local_resource stencil_buffer(pctx->screen, &tmpl);838if (!stencil_buffer) {839debug_printf("Allocating staging buffer for depth failed\n");840return;841}842843void *depth_ptr = depth_buffer.map();844if (!depth_ptr) {845debug_printf("Mapping staging depth buffer failed\n");846return;847}848849uint8_t *stencil_ptr = (uint8_t *)stencil_buffer.map();850if (!stencil_ptr) {851debug_printf("Mapping staging stencil buffer failed\n");852return;853}854855switch (res->base.format) {856case PIPE_FORMAT_Z24_UNORM_S8_UINT:857util_format_z32_unorm_unpack_z_32unorm((uint32_t *)depth_ptr, trans->base.stride, (uint8_t*)trans->data,858trans->base.stride, trans->base.box.width,859trans->base.box.height);860util_format_z24_unorm_s8_uint_unpack_s_8uint(stencil_ptr, trans->base.stride, (uint8_t*)trans->data,861trans->base.stride, trans->base.box.width,862trans->base.box.height);863break;864case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:865util_format_z32_float_s8x24_uint_unpack_z_float((float *)depth_ptr, trans->base.stride, (uint8_t*)trans->data,866trans->base.stride, trans->base.box.width,867trans->base.box.height);868util_format_z32_float_s8x24_uint_unpack_s_8uint(stencil_ptr, trans->base.stride, (uint8_t*)trans->data,869trans->base.stride, trans->base.box.width,870trans->base.box.height);871break;872default:873unreachable("Unsupported depth steancil format");874};875876stencil_buffer.unmap();877depth_buffer.unmap();878879transfer_buf_to_image(d3d12_context(pctx), res, depth_buffer, trans, 0);880transfer_buf_to_image(d3d12_context(pctx), res, stencil_buffer, trans, 1);881}882883#define BUFFER_MAP_ALIGNMENT 64884885static void *886d3d12_transfer_map(struct pipe_context *pctx,887struct pipe_resource *pres,888unsigned level,889unsigned usage,890const struct pipe_box *box,891struct pipe_transfer **transfer)892{893struct d3d12_context *ctx = d3d12_context(pctx);894struct d3d12_resource *res = d3d12_resource(pres);895896if (usage & PIPE_MAP_DIRECTLY || !res->bo)897return NULL;898899struct d3d12_transfer *trans = (struct d3d12_transfer *)slab_alloc(&ctx->transfer_pool);900struct pipe_transfer *ptrans = &trans->base;901if (!trans)902return NULL;903904memset(trans, 0, sizeof(*trans));905pipe_resource_reference(&ptrans->resource, pres);906907ptrans->resource = pres;908ptrans->level = level;909ptrans->usage = (enum pipe_map_flags)usage;910ptrans->box = *box;911912D3D12_RANGE range;913range.Begin = 0;914915void *ptr;916if (can_map_directly(&res->base)) {917if (pres->target == PIPE_BUFFER) {918ptrans->stride = 0;919ptrans->layer_stride = 0;920} else {921ptrans->stride = util_format_get_stride(pres->format, box->width);922ptrans->layer_stride = util_format_get_2d_size(pres->format,923ptrans->stride,924box->height);925}926927range = linear_range(box, ptrans->stride, ptrans->layer_stride);928if (!synchronize(ctx, res, usage, &range))929return NULL;930ptr = d3d12_bo_map(res->bo, &range);931} else if (unlikely(pres->format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||932pres->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) {933if (usage & PIPE_MAP_READ) {934ptr = read_zs_surface(ctx, res, box, trans);935} else if (usage & PIPE_MAP_WRITE){936ptr = prepare_write_zs_surface(res, box, trans);937} else {938ptr = nullptr;939}940} else {941ptrans->stride = align(util_format_get_stride(pres->format, box->width),942D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);943ptrans->layer_stride = util_format_get_2d_size(pres->format,944ptrans->stride,945box->height);946947if (res->base.target != PIPE_TEXTURE_3D)948ptrans->layer_stride = align(ptrans->layer_stride,949D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);950951unsigned staging_res_size = ptrans->layer_stride * box->depth;952if (res->base.target == PIPE_BUFFER) {953/* To properly support ARB_map_buffer_alignment, we need to return a pointer954* that's appropriately offset from a 64-byte-aligned base address.955*/956assert(box->x >= 0);957unsigned aligned_x = (unsigned)box->x % BUFFER_MAP_ALIGNMENT;958staging_res_size = align(box->width + aligned_x,959D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);960range.Begin = aligned_x;961}962963pipe_resource_usage staging_usage = (usage & (PIPE_MAP_READ | PIPE_MAP_READ_WRITE)) ?964PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;965966trans->staging_res = pipe_buffer_create(pctx->screen, 0,967staging_usage,968staging_res_size);969if (!trans->staging_res)970return NULL;971972struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);973974if (usage & PIPE_MAP_READ) {975bool ret = true;976if (pres->target == PIPE_BUFFER) {977uint64_t src_offset = box->x;978uint64_t dst_offset = src_offset % BUFFER_MAP_ALIGNMENT;979transfer_buf_to_buf(ctx, res, staging_res, src_offset, dst_offset, box->width);980} else981ret = transfer_image_to_buf(ctx, res, staging_res, trans, 0);982if (!ret)983return NULL;984d3d12_flush_cmdlist_and_wait(ctx);985}986987range.End = staging_res_size - range.Begin;988989ptr = d3d12_bo_map(staging_res->bo, &range);990}991992*transfer = ptrans;993return ptr;994}995996static void997d3d12_transfer_unmap(struct pipe_context *pctx,998struct pipe_transfer *ptrans)999{1000struct d3d12_resource *res = d3d12_resource(ptrans->resource);1001struct d3d12_transfer *trans = (struct d3d12_transfer *)ptrans;1002D3D12_RANGE range = { 0, 0 };10031004if (trans->data != nullptr) {1005if (trans->base.usage & PIPE_MAP_WRITE)1006write_zs_surface(pctx, res, trans);1007free(trans->data);1008} else if (trans->staging_res) {1009struct d3d12_resource *staging_res = d3d12_resource(trans->staging_res);10101011if (trans->base.usage & PIPE_MAP_WRITE) {1012assert(ptrans->box.x >= 0);1013range.Begin = res->base.target == PIPE_BUFFER ?1014(unsigned)ptrans->box.x % BUFFER_MAP_ALIGNMENT : 0;1015range.End = staging_res->base.width0 - range.Begin;1016}1017d3d12_bo_unmap(staging_res->bo, &range);10181019if (trans->base.usage & PIPE_MAP_WRITE) {1020struct d3d12_context *ctx = d3d12_context(pctx);1021if (res->base.target == PIPE_BUFFER) {1022uint64_t dst_offset = trans->base.box.x;1023uint64_t src_offset = dst_offset % BUFFER_MAP_ALIGNMENT;1024transfer_buf_to_buf(ctx, staging_res, res, src_offset, dst_offset, ptrans->box.width);1025} else1026transfer_buf_to_image(ctx, res, staging_res, trans, 0);1027}10281029pipe_resource_reference(&trans->staging_res, NULL);1030} else {1031if (trans->base.usage & PIPE_MAP_WRITE) {1032range.Begin = ptrans->box.x;1033range.End = ptrans->box.x + ptrans->box.width;1034}1035d3d12_bo_unmap(res->bo, &range);1036}10371038pipe_resource_reference(&ptrans->resource, NULL);1039slab_free(&d3d12_context(pctx)->transfer_pool, ptrans);1040}10411042void1043d3d12_resource_make_writeable(struct pipe_context *pctx,1044struct pipe_resource *pres)1045{1046struct d3d12_context *ctx = d3d12_context(pctx);1047struct d3d12_resource *res = d3d12_resource(pres);1048struct d3d12_resource *dup_res;10491050if (!res->bo || !d3d12_bo_is_suballocated(res->bo))1051return;10521053dup_res = d3d12_resource(pipe_buffer_create(pres->screen,1054pres->bind & PIPE_BIND_STREAM_OUTPUT,1055(pipe_resource_usage) pres->usage,1056pres->width0));10571058if (res->valid_buffer_range.end > res->valid_buffer_range.start) {1059struct pipe_box box;10601061box.x = res->valid_buffer_range.start;1062box.y = 0;1063box.z = 0;1064box.width = res->valid_buffer_range.end - res->valid_buffer_range.start;1065box.height = 1;1066box.depth = 1;10671068d3d12_direct_copy(ctx, dup_res, 0, &box, res, 0, &box, PIPE_MASK_RGBAZS);1069}10701071/* Move new BO to old resource */1072d3d12_bo_unreference(res->bo);1073res->bo = dup_res->bo;1074d3d12_bo_reference(res->bo);10751076d3d12_resource_destroy(dup_res->base.screen, &dup_res->base);1077}10781079void1080d3d12_context_resource_init(struct pipe_context *pctx)1081{1082pctx->buffer_map = d3d12_transfer_map;1083pctx->buffer_unmap = d3d12_transfer_unmap;1084pctx->texture_map = d3d12_transfer_map;1085pctx->texture_unmap = d3d12_transfer_unmap;10861087pctx->transfer_flush_region = u_default_transfer_flush_region;1088pctx->buffer_subdata = u_default_buffer_subdata;1089pctx->texture_subdata = u_default_texture_subdata;1090}109110921093