Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_blit.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_context.h"24#include "d3d12_compiler.h"25#include "d3d12_debug.h"26#include "d3d12_format.h"27#include "d3d12_resource.h"28#include "d3d12_screen.h"2930#include "util/u_blitter.h"31#include "util/format/u_format.h"3233#include "nir_to_dxil.h"34#include "nir_builder.h"3536static void37copy_buffer_region_no_barriers(struct d3d12_context *ctx,38struct d3d12_resource *dst,39uint64_t dst_offset,40struct d3d12_resource *src,41uint64_t src_offset,42uint64_t size)43{44uint64_t dst_off, src_off;45ID3D12Resource *dst_buf = d3d12_resource_underlying(dst, &dst_off);46ID3D12Resource *src_buf = d3d12_resource_underlying(src, &src_off);4748ctx->cmdlist->CopyBufferRegion(dst_buf, dst_offset + dst_off,49src_buf, src_offset + src_off,50size);51}5253static bool54is_resolve(const struct pipe_blit_info *info)55{56return info->src.resource->nr_samples > 1 &&57info->dst.resource->nr_samples <= 1;58}5960static bool61resolve_supported(const struct pipe_blit_info *info)62{63assert(is_resolve(info));6465// check for unsupported operations66if (util_format_is_depth_or_stencil(info->src.format) &&67info->mask != PIPE_MASK_Z) {68return false;69} else {70if (util_format_get_mask(info->dst.format) != info->mask ||71util_format_get_mask(info->src.format) != info->mask)72return false;73}7475if (info->filter != PIPE_TEX_FILTER_NEAREST ||76info->scissor_enable ||77info->num_window_rectangles > 0 ||78info->alpha_blend)79return false;8081// formats need to match82struct d3d12_resource *src = d3d12_resource(info->src.resource);83struct d3d12_resource *dst = d3d12_resource(info->dst.resource);84if (src->dxgi_format != dst->dxgi_format)85return false;8687if (util_format_is_pure_integer(src->base.format))88return false;8990// sizes needs to match91if (info->src.box.width != info->dst.box.width ||92info->src.box.height != info->dst.box.height)93return false;9495// can only resolve full subresource96if (info->src.box.width != (int)u_minify(info->src.resource->width0,97info->src.level) ||98info->src.box.height != (int)u_minify(info->src.resource->height0,99info->src.level) ||100info->dst.box.width != (int)u_minify(info->dst.resource->width0,101info->dst.level) ||102info->dst.box.height != (int)u_minify(info->dst.resource->height0,103info->dst.level))104return false;105106return true;107}108109static void110blit_resolve(struct d3d12_context *ctx, const struct pipe_blit_info *info)111{112struct d3d12_batch *batch = d3d12_current_batch(ctx);113struct d3d12_resource *src = d3d12_resource(info->src.resource);114struct d3d12_resource *dst = d3d12_resource(info->dst.resource);115116d3d12_transition_resource_state(ctx, src,117D3D12_RESOURCE_STATE_RESOLVE_SOURCE,118D3D12_BIND_INVALIDATE_FULL);119d3d12_transition_resource_state(ctx, dst,120D3D12_RESOURCE_STATE_RESOLVE_DEST,121D3D12_BIND_INVALIDATE_FULL);122123d3d12_apply_resource_states(ctx);124125d3d12_batch_reference_resource(batch, src);126d3d12_batch_reference_resource(batch, dst);127128DXGI_FORMAT dxgi_format = d3d12_get_resource_srv_format(src->base.format, src->base.target);129130assert(src->dxgi_format == dst->dxgi_format);131ctx->cmdlist->ResolveSubresource(132d3d12_resource_resource(dst), info->dst.level,133d3d12_resource_resource(src), info->src.level,134dxgi_format);135}136137static bool138formats_are_copy_compatible(enum pipe_format src, enum pipe_format dst)139{140if (src == dst)141return true;142143/* We can skip the stencil copy */144if (util_format_get_depth_only(src) == dst ||145util_format_get_depth_only(dst) == src)146return true;147148return false;149}150151static bool152box_fits(const struct pipe_box *box, const struct pipe_resource *res, int level)153{154unsigned lwidth = u_minify(res->width0, level);155unsigned lheight= u_minify(res->height0, level);156unsigned ldepth = res->target == PIPE_TEXTURE_3D ? u_minify(res->depth0, level) :157res->array_size;158159unsigned wb = box->x;160unsigned we = box->x + box->width;161162unsigned hb = box->y;163unsigned he = box->y + box->height;164165unsigned db = box->z;166unsigned de = box->z + box->depth;167168return (wb <= lwidth && we <= lwidth &&169hb <= lheight && he <= lheight &&170db <= ldepth && de <= ldepth);171}172173static bool174direct_copy_supported(struct d3d12_screen *screen,175const struct pipe_blit_info *info,176bool have_predication)177{178if (info->scissor_enable || info->alpha_blend ||179(have_predication && info->render_condition_enable) ||180MAX2(info->src.resource->nr_samples, 1) != MAX2(info->dst.resource->nr_samples, 1)) {181return false;182}183184if (!formats_are_copy_compatible(info->src.format, info->dst.format))185return false;186187if (util_format_is_depth_or_stencil(info->src.format) && !(info->mask & PIPE_MASK_ZS)) {188return false;189}190191if (!util_format_is_depth_or_stencil(info->src.format)) {192if (util_format_get_mask(info->dst.format) != info->mask ||193util_format_get_mask(info->src.format) != info->mask)194return false;195}196197if (abs(info->src.box.height) != info->dst.box.height) {198return false;199}200201if (info->src.box.height != info->dst.box.height &&202(!util_format_is_depth_or_stencil(info->src.format) ||203screen->opts2.ProgrammableSamplePositionsTier ==204D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)) {205return false;206}207208if (!box_fits(&info->dst.box, info->dst.resource, info->dst.level)) {209return false;210}211if (!box_fits(&info->src.box, info->src.resource, info->src.level)) {212return false;213}214215if (info->src.box.width != info->dst.box.width) {216return false;217}218219if (info->src.box.depth != info->dst.box.depth) {220return false;221}222223if ((screen->opts2.ProgrammableSamplePositionsTier ==224D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED &&225(info->src.resource->bind & PIPE_BIND_DEPTH_STENCIL ||226info->dst.resource->bind & PIPE_BIND_DEPTH_STENCIL)) ||227info->src.resource->nr_samples > 1) {228229if (info->dst.box.x != 0 ||230info->dst.box.y != 0 ||231info->dst.box.z != 0)232return false;233234if (info->src.box.x != 0 ||235info->src.box.y != 0 ||236info->src.box.z != 0 ||237info->src.box.width != (int)u_minify(info->src.resource->width0,238info->src.level) ||239info->src.box.height != (int)u_minify(info->src.resource->height0,240info->src.level) ||241info->src.box.depth != (int)u_minify(info->src.resource->depth0,242info->src.level))243return false;244}245246return true;247}248249inline static unsigned250get_subresource_id(enum pipe_texture_target target, unsigned subres, unsigned stride,251unsigned z, unsigned *updated_z)252{253if (d3d12_subresource_id_uses_layer(target)) {254subres += stride * z;255if (updated_z)256*updated_z = 0;257}258return subres;259}260261static void262copy_subregion_no_barriers(struct d3d12_context *ctx,263struct d3d12_resource *dst,264unsigned dst_level,265unsigned dstx, unsigned dsty, unsigned dstz,266struct d3d12_resource *src,267unsigned src_level,268const struct pipe_box *psrc_box,269unsigned mask)270{271UNUSED struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);272D3D12_TEXTURE_COPY_LOCATION src_loc, dst_loc;273unsigned src_z = psrc_box->z;274275int src_subres_stride = src->base.last_level + 1;276int dst_subres_stride = dst->base.last_level + 1;277278int src_array_size = src->base.array_size;279int dst_array_size = dst->base.array_size;280281if (dst->base.target == PIPE_TEXTURE_CUBE)282dst_array_size *= 6;283284if (src->base.target == PIPE_TEXTURE_CUBE)285src_array_size *= 6;286287int stencil_src_res_offset = 1;288int stencil_dst_res_offset = 1;289290int src_nres = 1;291int dst_nres = 1;292293if (dst->base.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||294dst->base.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||295dst->base.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {296stencil_dst_res_offset = dst_subres_stride * dst_array_size;297src_nres = 2;298}299300if (src->base.format == PIPE_FORMAT_Z24_UNORM_S8_UINT ||301src->base.format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||302dst->base.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {303stencil_src_res_offset = src_subres_stride * src_array_size;304dst_nres = 2;305}306307static_assert(PIPE_MASK_S == 0x20 && PIPE_MASK_Z == 0x10, "unexpected ZS format mask");308int nsubres = MIN2(src_nres, dst_nres);309unsigned subresource_copy_mask = nsubres > 1 ? mask >> 4 : 1;310311for (int subres = 0; subres < nsubres; ++subres) {312313if (!(subresource_copy_mask & (1 << subres)))314continue;315316src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;317src_loc.SubresourceIndex = get_subresource_id(src->base.target, src_level, src_subres_stride, src_z, &src_z) +318subres * stencil_src_res_offset;319src_loc.pResource = d3d12_resource_resource(src);320321dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;322dst_loc.SubresourceIndex = get_subresource_id(dst->base.target, dst_level, dst_subres_stride, dstz, &dstz) +323subres * stencil_dst_res_offset;324dst_loc.pResource = d3d12_resource_resource(dst);325326if (psrc_box->x == 0 && psrc_box->y == 0 && psrc_box->z == 0 &&327psrc_box->width == (int)u_minify(src->base.width0, src_level) &&328psrc_box->height == (int)u_minify(src->base.height0, src_level) &&329psrc_box->depth == (int)u_minify(src->base.depth0, src_level)) {330331assert((dstx == 0 && dsty == 0 && dstz == 0) ||332screen->opts2.ProgrammableSamplePositionsTier !=333D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||334(!util_format_is_depth_or_stencil(dst->base.format) &&335!util_format_is_depth_or_stencil(src->base.format) &&336dst->base.nr_samples <= 1 &&337src->base.nr_samples <= 1));338339ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,340&src_loc, NULL);341342} else {343D3D12_BOX src_box;344src_box.left = psrc_box->x;345src_box.right = MIN2(psrc_box->x + psrc_box->width, (int)u_minify(src->base.width0, src_level));346src_box.top = psrc_box->y;347src_box.bottom = MIN2(psrc_box->y + psrc_box->height, (int)u_minify(src->base.height0, src_level));348src_box.front = src_z;349src_box.back = src_z + psrc_box->depth;350351assert((screen->opts2.ProgrammableSamplePositionsTier !=352D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED ||353(!util_format_is_depth_or_stencil(dst->base.format) &&354!util_format_is_depth_or_stencil(src->base.format))) &&355dst->base.nr_samples <= 1 &&356src->base.nr_samples <= 1);357358ctx->cmdlist->CopyTextureRegion(&dst_loc, dstx, dsty, dstz,359&src_loc, &src_box);360}361}362}363364static void365copy_resource_y_flipped_no_barriers(struct d3d12_context *ctx,366struct d3d12_resource *dst,367unsigned dst_level,368const struct pipe_box *pdst_box,369struct d3d12_resource *src,370unsigned src_level,371const struct pipe_box *psrc_box,372unsigned mask)373{374if (D3D12_DEBUG_BLIT & d3d12_debug) {375debug_printf("D3D12 BLIT as COPY: from %s@%d %dx%dx%d + %dx%dx%d\n",376util_format_name(src->base.format), src_level,377psrc_box->x, psrc_box->y, psrc_box->z,378psrc_box->width, psrc_box->height, psrc_box->depth);379debug_printf(" to %s@%d %dx%dx%d\n",380util_format_name(dst->base.format), dst_level,381pdst_box->x, pdst_box->y, pdst_box->z);382}383384struct pipe_box src_box = *psrc_box;385int src_inc = psrc_box->height > 0 ? 1 : -1;386int dst_inc = pdst_box->height > 0 ? 1 : -1;387src_box.height = 1;388int rows_to_copy = abs(psrc_box->height);389390if (psrc_box->height < 0)391--src_box.y;392393for (int y = 0, dest_y = pdst_box->y; y < rows_to_copy;394++y, src_box.y += src_inc, dest_y += dst_inc) {395copy_subregion_no_barriers(ctx, dst, dst_level,396pdst_box->x, dest_y, pdst_box->z,397src, src_level, &src_box, mask);398}399}400401void402d3d12_direct_copy(struct d3d12_context *ctx,403struct d3d12_resource *dst,404unsigned dst_level,405const struct pipe_box *pdst_box,406struct d3d12_resource *src,407unsigned src_level,408const struct pipe_box *psrc_box,409unsigned mask)410{411struct d3d12_batch *batch = d3d12_current_batch(ctx);412413unsigned src_subres = get_subresource_id(src->base.target, src_level, src->base.last_level + 1,414psrc_box->z, nullptr);415unsigned dst_subres = get_subresource_id(dst->base.target, dst_level, dst->base.last_level + 1,416pdst_box->z, nullptr);417418if (D3D12_DEBUG_BLIT & d3d12_debug)419debug_printf("BLIT: Direct copy from subres %d to subres %d\n",420src_subres, dst_subres);421422d3d12_transition_subresources_state(ctx, src, src_subres, 1, 0, 1,423d3d12_get_format_start_plane(src->base.format),424d3d12_get_format_num_planes(src->base.format),425D3D12_RESOURCE_STATE_COPY_SOURCE,426D3D12_BIND_INVALIDATE_FULL);427428d3d12_transition_subresources_state(ctx, dst, dst_subres, 1, 0, 1,429d3d12_get_format_start_plane(dst->base.format),430d3d12_get_format_num_planes(dst->base.format),431D3D12_RESOURCE_STATE_COPY_DEST,432D3D12_BIND_INVALIDATE_FULL);433434d3d12_apply_resource_states(ctx);435436d3d12_batch_reference_resource(batch, src);437d3d12_batch_reference_resource(batch, dst);438439if (src->base.target == PIPE_BUFFER) {440copy_buffer_region_no_barriers(ctx, dst, pdst_box->x,441src, psrc_box->x, psrc_box->width);442} else if (psrc_box->height == pdst_box->height) {443/* No flipping, we can forward this directly to resource_copy_region */444copy_subregion_no_barriers(ctx, dst, dst_level,445pdst_box->x, pdst_box->y, pdst_box->z,446src, src_level, psrc_box, mask);447} else {448assert(psrc_box->height == -pdst_box->height);449copy_resource_y_flipped_no_barriers(ctx, dst, dst_level, pdst_box,450src, src_level, psrc_box, mask);451}452}453454static bool455is_same_resource(const struct pipe_blit_info *info)456{457return d3d12_resource_resource(d3d12_resource(info->src.resource)) ==458d3d12_resource_resource(d3d12_resource(info->dst.resource)) &&459info->src.level == info->dst.level;460}461462static struct pipe_resource *463create_staging_resource(struct d3d12_context *ctx,464struct d3d12_resource *src,465unsigned src_level,466const struct pipe_box *src_box,467struct pipe_box *dst_box,468unsigned mask)469470{471struct pipe_resource templ = {{0}};472struct pipe_resource *staging_res;473struct pipe_box copy_src;474475u_box_3d(MIN2(src_box->x, src_box->x + src_box->width),476MIN2(src_box->y, src_box->y + src_box->height),477MIN2(src_box->z, src_box->z + src_box->depth),478abs(src_box->width), abs(src_box->height), abs(src_box->depth),479©_src);480481templ.format = src->base.format;482templ.width0 = copy_src.width;483templ.height0 = copy_src.height;484templ.depth0 = copy_src.depth;485templ.array_size = 1;486templ.nr_samples = 1;487templ.nr_storage_samples = 1;488templ.usage = PIPE_USAGE_STAGING;489templ.bind = util_format_is_depth_or_stencil(templ.format) ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET;490templ.target = src->base.target;491492staging_res = ctx->base.screen->resource_create(ctx->base.screen, &templ);493494dst_box->x = 0;495dst_box->y = 0;496dst_box->z = 0;497dst_box->width = copy_src.width;498dst_box->height = copy_src.height;499dst_box->depth = copy_src.depth;500501d3d12_direct_copy(ctx, d3d12_resource(staging_res), 0, dst_box,502src, src_level, ©_src, mask);503504if (src_box->width < 0) {505dst_box->x = dst_box->width;506dst_box->width = src_box->width;507}508509if (src_box->height < 0) {510dst_box->y = dst_box->height;511dst_box->height = src_box->height;512}513514if (src_box->depth < 0) {515dst_box->z = dst_box->depth;516dst_box->depth = src_box->depth;517}518return staging_res;519}520521static void522blit_same_resource(struct d3d12_context *ctx,523const struct pipe_blit_info *info)524{525struct pipe_blit_info dst_info = *info;526527dst_info.src.level = 0;528dst_info.src.resource = create_staging_resource(ctx, d3d12_resource(info->src.resource),529info->src.level,530&info->src.box,531&dst_info.src.box, PIPE_MASK_RGBAZS);532ctx->base.blit(&ctx->base, &dst_info);533pipe_resource_reference(&dst_info.src.resource, NULL);534}535536static void537util_blit_save_state(struct d3d12_context *ctx)538{539util_blitter_save_blend(ctx->blitter, ctx->gfx_pipeline_state.blend);540util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->gfx_pipeline_state.zsa);541util_blitter_save_vertex_elements(ctx->blitter, ctx->gfx_pipeline_state.ves);542util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);543util_blitter_save_rasterizer(ctx->blitter, ctx->gfx_pipeline_state.rast);544util_blitter_save_fragment_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_FRAGMENT]);545util_blitter_save_vertex_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_VERTEX]);546util_blitter_save_geometry_shader(ctx->blitter, ctx->gfx_stages[PIPE_SHADER_GEOMETRY]);547548util_blitter_save_framebuffer(ctx->blitter, &ctx->fb);549util_blitter_save_viewport(ctx->blitter, ctx->viewport_states);550util_blitter_save_scissor(ctx->blitter, ctx->scissor_states);551util_blitter_save_fragment_sampler_states(ctx->blitter,552ctx->num_samplers[PIPE_SHADER_FRAGMENT],553(void **)ctx->samplers[PIPE_SHADER_FRAGMENT]);554util_blitter_save_fragment_sampler_views(ctx->blitter,555ctx->num_sampler_views[PIPE_SHADER_FRAGMENT],556ctx->sampler_views[PIPE_SHADER_FRAGMENT]);557util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->cbufs[PIPE_SHADER_FRAGMENT]);558util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vbs);559util_blitter_save_sample_mask(ctx->blitter, ctx->gfx_pipeline_state.sample_mask);560util_blitter_save_so_targets(ctx->blitter, ctx->gfx_pipeline_state.num_so_targets, ctx->so_targets);561}562563static void564util_blit(struct d3d12_context *ctx,565const struct pipe_blit_info *info)566{567util_blit_save_state(ctx);568569util_blitter_blit(ctx->blitter, info);570}571572static bool573resolve_stencil_supported(struct d3d12_context *ctx,574const struct pipe_blit_info *info)575{576assert(is_resolve(info));577578if (!util_format_is_depth_or_stencil(info->src.format) ||579!(info->mask & PIPE_MASK_S))580return false;581582if (info->mask & PIPE_MASK_Z) {583struct pipe_blit_info new_info = *info;584new_info.mask = PIPE_MASK_Z;585if (!resolve_supported(&new_info) &&586!util_blitter_is_blit_supported(ctx->blitter, &new_info))587return false;588}589590struct pipe_blit_info new_info = *info;591new_info.dst.format = PIPE_FORMAT_R8_UINT;592return util_blitter_is_blit_supported(ctx->blitter, &new_info);593}594595static struct pipe_resource *596create_tmp_resource(struct pipe_screen *screen,597const struct pipe_blit_info *info)598{599struct pipe_resource tpl = {};600tpl.width0 = info->dst.box.width;601tpl.height0 = info->dst.box.height;602tpl.depth0 = info->dst.box.depth;603tpl.array_size = 1;604tpl.format = PIPE_FORMAT_R8_UINT;605tpl.target = info->dst.resource->target;606tpl.nr_samples = info->dst.resource->nr_samples;607tpl.nr_storage_samples = info->dst.resource->nr_storage_samples;608tpl.usage = PIPE_USAGE_STREAM;609tpl.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;610return screen->resource_create(screen, &tpl);611}612613static void *614get_stencil_resolve_vs(struct d3d12_context *ctx)615{616if (ctx->stencil_resolve_vs)617return ctx->stencil_resolve_vs;618619nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,620dxil_get_nir_compiler_options(),621"linear_blit_vs");622623const struct glsl_type *vec4 = glsl_vec4_type();624nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,625vec4, "pos");626627nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,628vec4, "gl_Position");629pos_out->data.location = VARYING_SLOT_POS;630631nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);632633struct pipe_shader_state state = {};634state.type = PIPE_SHADER_IR_NIR;635state.ir.nir = b.shader;636ctx->stencil_resolve_vs = ctx->base.create_vs_state(&ctx->base, &state);637638return ctx->stencil_resolve_vs;639}640641static void *642get_stencil_resolve_fs(struct d3d12_context *ctx, bool no_flip)643{644if (!no_flip && ctx->stencil_resolve_fs)645return ctx->stencil_resolve_fs;646647if (no_flip && ctx->stencil_resolve_fs_no_flip)648return ctx->stencil_resolve_fs_no_flip;649650nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,651dxil_get_nir_compiler_options(),652no_flip ? "stencil_resolve_fs_no_flip" : "stencil_resolve_fs");653654nir_variable *stencil_out = nir_variable_create(b.shader,655nir_var_shader_out,656glsl_uint_type(),657"stencil_out");658stencil_out->data.location = FRAG_RESULT_COLOR;659660const struct glsl_type *sampler_type =661glsl_sampler_type(GLSL_SAMPLER_DIM_MS, false, false, GLSL_TYPE_UINT);662nir_variable *sampler = nir_variable_create(b.shader, nir_var_uniform,663sampler_type, "stencil_tex");664sampler->data.binding = 0;665sampler->data.explicit_binding = true;666667nir_ssa_def *tex_deref = &nir_build_deref_var(&b, sampler)->dest.ssa;668669nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,670glsl_vec4_type(), "pos");671pos_in->data.location = VARYING_SLOT_POS; // VARYING_SLOT_VAR0?672nir_ssa_def *pos = nir_load_var(&b, pos_in);673674nir_ssa_def *pos_src;675676if (no_flip)677pos_src = pos;678else {679nir_tex_instr *txs = nir_tex_instr_create(b.shader, 1);680txs->op = nir_texop_txs;681txs->sampler_dim = GLSL_SAMPLER_DIM_MS;682txs->src[0].src_type = nir_tex_src_texture_deref;683txs->src[0].src = nir_src_for_ssa(tex_deref);684txs->is_array = false;685txs->dest_type = nir_type_int;686687nir_ssa_dest_init(&txs->instr, &txs->dest, 2, 32, "tex");688nir_builder_instr_insert(&b, &txs->instr);689690pos_src = nir_vec4(&b,691nir_channel(&b, pos, 0),692/*Height - pos_dest.y - 1*/693nir_fsub(&b,694nir_fsub(&b,695nir_channel(&b, nir_i2f32(&b, &txs->dest.ssa), 1),696nir_channel(&b, pos, 1)),697nir_imm_float(&b, 1.0)),698nir_channel(&b, pos, 2),699nir_channel(&b, pos, 3));700}701702nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);703tex->sampler_dim = GLSL_SAMPLER_DIM_MS;704tex->op = nir_texop_txf_ms;705tex->src[0].src_type = nir_tex_src_coord;706tex->src[0].src = nir_src_for_ssa(nir_channels(&b, nir_f2i32(&b, pos_src), 0x3));707tex->src[1].src_type = nir_tex_src_ms_index;708tex->src[1].src = nir_src_for_ssa(nir_imm_int(&b, 0)); /* just use first sample */709tex->src[2].src_type = nir_tex_src_texture_deref;710tex->src[2].src = nir_src_for_ssa(tex_deref);711tex->dest_type = nir_type_uint32;712tex->is_array = false;713tex->coord_components = 2;714715nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");716nir_builder_instr_insert(&b, &tex->instr);717718nir_store_var(&b, stencil_out, nir_channel(&b, &tex->dest.ssa, 1), 0x1);719720struct pipe_shader_state state = {};721state.type = PIPE_SHADER_IR_NIR;722state.ir.nir = b.shader;723void *result;724if (no_flip) {725result = ctx->base.create_fs_state(&ctx->base, &state);726ctx->stencil_resolve_fs_no_flip = result;727} else {728result = ctx->base.create_fs_state(&ctx->base, &state);729ctx->stencil_resolve_fs = result;730}731732return result;733}734735static void *736get_sampler_state(struct d3d12_context *ctx)737{738if (ctx->sampler_state)739return ctx->sampler_state;740741struct pipe_sampler_state state;742memset(&state, 0, sizeof(state));743state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;744state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;745state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;746state.normalized_coords = 1;747748return ctx->sampler_state = ctx->base.create_sampler_state(&ctx->base, &state);749}750751static struct pipe_resource *752resolve_stencil_to_temp(struct d3d12_context *ctx,753const struct pipe_blit_info *info)754{755struct pipe_context *pctx = &ctx->base;756struct pipe_resource *tmp = create_tmp_resource(pctx->screen, info);757if (!tmp) {758debug_printf("D3D12: failed to create stencil-resolve temp-resource\n");759return NULL;760}761assert(tmp->nr_samples < 2);762763/* resolve stencil into tmp */764struct pipe_surface dst_tmpl;765util_blitter_default_dst_texture(&dst_tmpl, tmp, 0, 0);766dst_tmpl.format = tmp->format;767struct pipe_surface *dst_surf = pctx->create_surface(pctx, tmp, &dst_tmpl);768if (!dst_surf) {769debug_printf("D3D12: failed to create stencil-resolve dst-surface\n");770return NULL;771}772773struct pipe_sampler_view src_templ, *src_view;774util_blitter_default_src_texture(ctx->blitter, &src_templ,775info->src.resource, info->src.level);776src_templ.format = util_format_stencil_only(info->src.format);777src_view = pctx->create_sampler_view(pctx, info->src.resource, &src_templ);778779void *sampler_state = get_sampler_state(ctx);780781util_blit_save_state(ctx);782pctx->set_sampler_views(pctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, &src_view);783pctx->bind_sampler_states(pctx, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);784util_blitter_custom_shader(ctx->blitter, dst_surf,785get_stencil_resolve_vs(ctx),786get_stencil_resolve_fs(ctx, info->src.box.height == info->dst.box.height));787util_blitter_restore_textures(ctx->blitter);788pipe_surface_reference(&dst_surf, NULL);789pipe_sampler_view_reference(&src_view, NULL);790return tmp;791}792793static void794blit_resolve_stencil(struct d3d12_context *ctx,795const struct pipe_blit_info *info)796{797assert(info->mask & PIPE_MASK_S);798799if (D3D12_DEBUG_BLIT & d3d12_debug)800debug_printf("D3D12 BLIT: blit_resolve_stencil\n");801802if (info->mask & PIPE_MASK_Z) {803/* resolve depth into dst */804struct pipe_blit_info new_info = *info;805new_info.mask = PIPE_MASK_Z;806807if (resolve_supported(&new_info))808blit_resolve(ctx, &new_info);809else810util_blit(ctx, &new_info);811}812813struct pipe_resource *tmp = resolve_stencil_to_temp(ctx, info);814815816/* copy resolved stencil into dst */817struct d3d12_resource *dst = d3d12_resource(info->dst.resource);818d3d12_transition_subresources_state(ctx, d3d12_resource(tmp),8190, 1, 0, 1, 0, 1,820D3D12_RESOURCE_STATE_COPY_SOURCE,821D3D12_BIND_INVALIDATE_NONE);822d3d12_transition_subresources_state(ctx, dst,8230, 1, 0, 1, 1, 1,824D3D12_RESOURCE_STATE_COPY_DEST,825D3D12_BIND_INVALIDATE_FULL);826d3d12_apply_resource_states(ctx);827828struct d3d12_batch *batch = d3d12_current_batch(ctx);829d3d12_batch_reference_resource(batch, d3d12_resource(tmp));830d3d12_batch_reference_resource(batch, dst);831832D3D12_BOX src_box;833src_box.left = src_box.top = src_box.front = 0;834src_box.right = tmp->width0;835src_box.bottom = tmp->height0;836src_box.back = tmp->depth0;837838D3D12_TEXTURE_COPY_LOCATION src_loc;839src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;840src_loc.SubresourceIndex = 0;841src_loc.pResource = d3d12_resource_resource(d3d12_resource(tmp));842843D3D12_TEXTURE_COPY_LOCATION dst_loc;844dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;845dst_loc.SubresourceIndex = 1;846dst_loc.pResource = d3d12_resource_resource(dst);847848ctx->cmdlist->CopyTextureRegion(&dst_loc, info->dst.box.x,849info->dst.box.y, info->dst.box.z,850&src_loc, &src_box);851852pipe_resource_reference(&tmp, NULL);853}854855static bool856replicate_stencil_supported(struct d3d12_context *ctx,857const struct pipe_blit_info *info)858{859if (!util_format_is_depth_or_stencil(info->src.format) ||860!(info->mask & PIPE_MASK_S))861return false;862863if (info->mask & PIPE_MASK_Z) {864struct pipe_blit_info new_info = *info;865new_info.mask = PIPE_MASK_Z;866if (!util_blitter_is_blit_supported(ctx->blitter, &new_info))867return false;868}869870return true;871}872873static void874blit_replicate_stencil(struct d3d12_context *ctx,875const struct pipe_blit_info *info)876{877assert(info->mask & PIPE_MASK_S);878879if (D3D12_DEBUG_BLIT & d3d12_debug)880debug_printf("D3D12 BLIT: blit_replicate_stencil\n");881882if (info->mask & PIPE_MASK_Z) {883/* resolve depth into dst */884struct pipe_blit_info new_info = *info;885new_info.mask = PIPE_MASK_Z;886util_blit(ctx, &new_info);887}888889util_blit_save_state(ctx);890util_blitter_stencil_fallback(ctx->blitter, info->dst.resource,891info->dst.level,892&info->dst.box,893info->src.resource,894info->src.level,895&info->src.box,896info->scissor_enable ? &info->scissor : NULL);897}898899void900d3d12_blit(struct pipe_context *pctx,901const struct pipe_blit_info *info)902{903struct d3d12_context *ctx = d3d12_context(pctx);904905if (!info->render_condition_enable && ctx->current_predication) {906if (D3D12_DEBUG_BLIT & d3d12_debug)907debug_printf("D3D12 BLIT: Disable predication\n");908ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);909}910911if (D3D12_DEBUG_BLIT & d3d12_debug) {912debug_printf("D3D12 BLIT: from %s@%d msaa:%d %dx%dx%d + %dx%dx%d\n",913util_format_name(info->src.format), info->src.level,914info->src.resource->nr_samples,915info->src.box.x, info->src.box.y, info->src.box.z,916info->src.box.width, info->src.box.height, info->src.box.depth);917debug_printf(" to %s@%d msaa:%d %dx%dx%d + %dx%dx%d ",918util_format_name(info->dst.format), info->dst.level,919info->dst.resource->nr_samples,920info->dst.box.x, info->dst.box.y, info->dst.box.z,921info->dst.box.width, info->dst.box.height, info->dst.box.depth);922debug_printf("| flags %s%s%s\n",923info->render_condition_enable ? "cond " : "",924info->scissor_enable ? "scissor " : "",925info->alpha_blend ? "blend" : "");926}927928if (is_same_resource(info))929blit_same_resource(ctx, info);930else if (is_resolve(info)) {931if (resolve_supported(info))932blit_resolve(ctx, info);933else if (util_blitter_is_blit_supported(ctx->blitter, info))934util_blit(ctx, info);935else if (resolve_stencil_supported(ctx, info))936blit_resolve_stencil(ctx, info);937else938debug_printf("D3D12: resolve unsupported %s -> %s\n",939util_format_short_name(info->src.resource->format),940util_format_short_name(info->dst.resource->format));941} else if (direct_copy_supported(d3d12_screen(pctx->screen), info,942ctx->current_predication != nullptr))943d3d12_direct_copy(ctx, d3d12_resource(info->dst.resource),944info->dst.level, &info->dst.box,945d3d12_resource(info->src.resource),946info->src.level, &info->src.box, info->mask);947else if (util_blitter_is_blit_supported(ctx->blitter, info))948util_blit(ctx, info);949else if (replicate_stencil_supported(ctx, info))950blit_replicate_stencil(ctx, info);951else952debug_printf("D3D12: blit unsupported %s -> %s\n",953util_format_short_name(info->src.resource->format),954util_format_short_name(info->dst.resource->format));955956if (!info->render_condition_enable && ctx->current_predication) {957ctx->cmdlist->SetPredication(958d3d12_resource_resource(ctx->current_predication), 0, D3D12_PREDICATION_OP_EQUAL_ZERO);959if (D3D12_DEBUG_BLIT & d3d12_debug)960debug_printf("D3D12 BLIT: Re-enable predication\n");961}962963}964965static void966d3d12_resource_copy_region(struct pipe_context *pctx,967struct pipe_resource *pdst,968unsigned dst_level,969unsigned dstx, unsigned dsty, unsigned dstz,970struct pipe_resource *psrc,971unsigned src_level,972const struct pipe_box *psrc_box)973{974struct d3d12_context *ctx = d3d12_context(pctx);975struct d3d12_resource *dst = d3d12_resource(pdst);976struct d3d12_resource *src = d3d12_resource(psrc);977struct pipe_resource *staging_res = NULL;978const struct pipe_box *src_box = psrc_box;979struct pipe_box staging_box, dst_box;980981if (D3D12_DEBUG_BLIT & d3d12_debug) {982debug_printf("D3D12 COPY: from %s@%d msaa:%d mips:%d %dx%dx%d + %dx%dx%d\n",983util_format_name(psrc->format), src_level, psrc->nr_samples,984psrc->last_level,985psrc_box->x, psrc_box->y, psrc_box->z,986psrc_box->width, psrc_box->height, psrc_box->depth);987debug_printf(" to %s@%d msaa:%d mips:%d %dx%dx%d\n",988util_format_name(pdst->format), dst_level, psrc->nr_samples,989psrc->last_level, dstx, dsty, dstz);990}991992/* Use an intermediate resource if copying from/to the same subresource */993if (d3d12_resource_resource(dst) == d3d12_resource_resource(src) && dst_level == src_level) {994staging_res = create_staging_resource(ctx, src, src_level, psrc_box, &staging_box, PIPE_MASK_RGBAZS);995src = d3d12_resource(staging_res);996src_level = 0;997src_box = &staging_box;998}9991000dst_box.x = dstx;1001dst_box.y = dsty;1002dst_box.z = dstz;1003dst_box.width = psrc_box->width;1004dst_box.height = psrc_box->height;10051006d3d12_direct_copy(ctx, dst, dst_level, &dst_box,1007src, src_level, src_box, PIPE_MASK_RGBAZS);10081009if (staging_res)1010pipe_resource_reference(&staging_res, NULL);1011}10121013void1014d3d12_context_blit_init(struct pipe_context *ctx)1015{1016ctx->resource_copy_region = d3d12_resource_copy_region;1017ctx->blit = d3d12_blit;1018}101910201021