Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_context.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_blit.h"24#include "d3d12_context.h"25#include "d3d12_compiler.h"26#include "d3d12_debug.h"27#include "d3d12_fence.h"28#include "d3d12_format.h"29#include "d3d12_query.h"30#include "d3d12_resource.h"31#include "d3d12_root_signature.h"32#include "d3d12_screen.h"33#include "d3d12_surface.h"3435#include "util/u_blitter.h"36#include "util/u_dual_blend.h"37#include "util/u_framebuffer.h"38#include "util/u_helpers.h"39#include "util/u_inlines.h"40#include "util/u_memory.h"41#include "util/u_upload_mgr.h"42#include "util/u_pstipple.h"43#include "util/u_dl.h"44#include "nir_to_dxil.h"4546#include "D3D12ResourceState.h"4748#include <dxguids/dxguids.h>4950extern "C" {51#include "indices/u_primconvert.h"52}5354#include <string.h>5556static void57d3d12_context_destroy(struct pipe_context *pctx)58{59struct d3d12_context *ctx = d3d12_context(pctx);60if (ctx->validation_tools)61d3d12_validator_destroy(ctx->validation_tools);6263if (ctx->timestamp_query)64pctx->destroy_query(pctx, ctx->timestamp_query);6566util_blitter_destroy(ctx->blitter);67d3d12_end_batch(ctx, d3d12_current_batch(ctx));68for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i)69d3d12_destroy_batch(ctx, &ctx->batches[i]);70ctx->cmdlist->Release();71ctx->cmdqueue_fence->Release();72d3d12_descriptor_pool_free(ctx->sampler_pool);73util_primconvert_destroy(ctx->primconvert);74slab_destroy_child(&ctx->transfer_pool);75d3d12_gs_variant_cache_destroy(ctx);76d3d12_gfx_pipeline_state_cache_destroy(ctx);77d3d12_root_signature_cache_destroy(ctx);7879u_suballocator_destroy(&ctx->query_allocator);8081if (pctx->stream_uploader)82u_upload_destroy(pctx->stream_uploader);83if (pctx->const_uploader)84u_upload_destroy(pctx->const_uploader);8586delete ctx->resource_state_manager;8788FREE(ctx);89}9091static void *92d3d12_create_vertex_elements_state(struct pipe_context *pctx,93unsigned num_elements,94const struct pipe_vertex_element *elements)95{96struct d3d12_vertex_elements_state *cso = CALLOC_STRUCT(d3d12_vertex_elements_state);97if (!cso)98return NULL;99100for (unsigned i = 0; i < num_elements; ++i) {101cso->elements[i].SemanticName = "TEXCOORD";102cso->elements[i].SemanticIndex = i;103104enum pipe_format format_helper = d3d12_emulated_vtx_format(elements[i].src_format);105bool needs_emulation = format_helper != elements[i].src_format;106cso->needs_format_emulation |= needs_emulation;107cso->format_conversion[i] = needs_emulation ? elements[i].src_format : PIPE_FORMAT_NONE;108109cso->elements[i].Format = d3d12_get_format(format_helper);110assert(cso->elements[i].Format != DXGI_FORMAT_UNKNOWN);111cso->elements[i].InputSlot = elements[i].vertex_buffer_index;112cso->elements[i].AlignedByteOffset = elements[i].src_offset;113114if (elements[i].instance_divisor) {115cso->elements[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;116cso->elements[i].InstanceDataStepRate = elements[i].instance_divisor;117} else {118cso->elements[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;119cso->elements[i].InstanceDataStepRate = 0;120}121}122123cso->num_elements = num_elements;124return cso;125}126127static void128d3d12_bind_vertex_elements_state(struct pipe_context *pctx,129void *ve)130{131struct d3d12_context *ctx = d3d12_context(pctx);132ctx->gfx_pipeline_state.ves = (struct d3d12_vertex_elements_state *)ve;133ctx->state_dirty |= D3D12_DIRTY_VERTEX_ELEMENTS;134}135136static void137d3d12_delete_vertex_elements_state(struct pipe_context *pctx,138void *ve)139{140FREE(ve);141}142143static D3D12_BLEND144blend_factor_rgb(enum pipe_blendfactor factor)145{146switch (factor) {147case PIPE_BLENDFACTOR_ZERO: return D3D12_BLEND_ZERO;148case PIPE_BLENDFACTOR_ONE: return D3D12_BLEND_ONE;149case PIPE_BLENDFACTOR_SRC_COLOR: return D3D12_BLEND_SRC_COLOR;150case PIPE_BLENDFACTOR_SRC_ALPHA: return D3D12_BLEND_SRC_ALPHA;151case PIPE_BLENDFACTOR_DST_ALPHA: return D3D12_BLEND_DEST_ALPHA;152case PIPE_BLENDFACTOR_DST_COLOR: return D3D12_BLEND_DEST_COLOR;153case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return D3D12_BLEND_SRC_ALPHA_SAT;154case PIPE_BLENDFACTOR_CONST_COLOR: return D3D12_BLEND_BLEND_FACTOR;155case PIPE_BLENDFACTOR_SRC1_COLOR: return D3D12_BLEND_SRC1_COLOR;156case PIPE_BLENDFACTOR_SRC1_ALPHA: return D3D12_BLEND_SRC1_ALPHA;157case PIPE_BLENDFACTOR_INV_SRC_COLOR: return D3D12_BLEND_INV_SRC_COLOR;158case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return D3D12_BLEND_INV_SRC_ALPHA;159case PIPE_BLENDFACTOR_INV_DST_ALPHA: return D3D12_BLEND_INV_DEST_ALPHA;160case PIPE_BLENDFACTOR_INV_DST_COLOR: return D3D12_BLEND_INV_DEST_COLOR;161case PIPE_BLENDFACTOR_INV_CONST_COLOR: return D3D12_BLEND_INV_BLEND_FACTOR;162case PIPE_BLENDFACTOR_INV_SRC1_COLOR: return D3D12_BLEND_INV_SRC1_COLOR;163case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: return D3D12_BLEND_INV_SRC1_ALPHA;164case PIPE_BLENDFACTOR_CONST_ALPHA: return D3D12_BLEND_BLEND_FACTOR; /* Doesn't exist in D3D12 */165case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return D3D12_BLEND_INV_BLEND_FACTOR; /* Doesn't exist in D3D12 */166}167unreachable("unexpected blend factor");168}169170static D3D12_BLEND171blend_factor_alpha(enum pipe_blendfactor factor)172{173switch (factor) {174case PIPE_BLENDFACTOR_ZERO: return D3D12_BLEND_ZERO;175case PIPE_BLENDFACTOR_ONE: return D3D12_BLEND_ONE;176case PIPE_BLENDFACTOR_SRC_COLOR:177case PIPE_BLENDFACTOR_SRC_ALPHA: return D3D12_BLEND_SRC_ALPHA;178case PIPE_BLENDFACTOR_DST_COLOR:179case PIPE_BLENDFACTOR_DST_ALPHA: return D3D12_BLEND_DEST_ALPHA;180case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return D3D12_BLEND_SRC_ALPHA_SAT;181case PIPE_BLENDFACTOR_CONST_COLOR:182case PIPE_BLENDFACTOR_CONST_ALPHA: return D3D12_BLEND_BLEND_FACTOR;183case PIPE_BLENDFACTOR_SRC1_COLOR:184case PIPE_BLENDFACTOR_SRC1_ALPHA: return D3D12_BLEND_SRC1_ALPHA;185case PIPE_BLENDFACTOR_INV_SRC_COLOR:186case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return D3D12_BLEND_INV_SRC_ALPHA;187case PIPE_BLENDFACTOR_INV_DST_COLOR:188case PIPE_BLENDFACTOR_INV_DST_ALPHA: return D3D12_BLEND_INV_DEST_ALPHA;189case PIPE_BLENDFACTOR_INV_SRC1_COLOR:190case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: return D3D12_BLEND_INV_SRC1_ALPHA;191case PIPE_BLENDFACTOR_INV_CONST_COLOR:192case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return D3D12_BLEND_INV_BLEND_FACTOR;193}194unreachable("unexpected blend factor");195}196197static unsigned198need_blend_factor_rgb(enum pipe_blendfactor factor)199{200switch (factor) {201case PIPE_BLENDFACTOR_CONST_COLOR:202case PIPE_BLENDFACTOR_INV_CONST_COLOR:203return D3D12_BLEND_FACTOR_COLOR;204case PIPE_BLENDFACTOR_CONST_ALPHA:205case PIPE_BLENDFACTOR_INV_CONST_ALPHA:206return D3D12_BLEND_FACTOR_ALPHA;207208default:209return D3D12_BLEND_FACTOR_NONE;210}211}212213static unsigned214need_blend_factor_alpha(enum pipe_blendfactor factor)215{216switch (factor) {217case PIPE_BLENDFACTOR_CONST_COLOR:218case PIPE_BLENDFACTOR_INV_CONST_COLOR:219case PIPE_BLENDFACTOR_CONST_ALPHA:220case PIPE_BLENDFACTOR_INV_CONST_ALPHA:221return D3D12_BLEND_FACTOR_ANY;222223default:224return D3D12_BLEND_FACTOR_NONE;225}226}227228static D3D12_BLEND_OP229blend_op(enum pipe_blend_func func)230{231switch (func) {232case PIPE_BLEND_ADD: return D3D12_BLEND_OP_ADD;233case PIPE_BLEND_SUBTRACT: return D3D12_BLEND_OP_SUBTRACT;234case PIPE_BLEND_REVERSE_SUBTRACT: return D3D12_BLEND_OP_REV_SUBTRACT;235case PIPE_BLEND_MIN: return D3D12_BLEND_OP_MIN;236case PIPE_BLEND_MAX: return D3D12_BLEND_OP_MAX;237}238unreachable("unexpected blend function");239}240241static D3D12_COMPARISON_FUNC242compare_op(enum pipe_compare_func op)243{244switch (op) {245case PIPE_FUNC_NEVER: return D3D12_COMPARISON_FUNC_NEVER;246case PIPE_FUNC_LESS: return D3D12_COMPARISON_FUNC_LESS;247case PIPE_FUNC_EQUAL: return D3D12_COMPARISON_FUNC_EQUAL;248case PIPE_FUNC_LEQUAL: return D3D12_COMPARISON_FUNC_LESS_EQUAL;249case PIPE_FUNC_GREATER: return D3D12_COMPARISON_FUNC_GREATER;250case PIPE_FUNC_NOTEQUAL: return D3D12_COMPARISON_FUNC_NOT_EQUAL;251case PIPE_FUNC_GEQUAL: return D3D12_COMPARISON_FUNC_GREATER_EQUAL;252case PIPE_FUNC_ALWAYS: return D3D12_COMPARISON_FUNC_ALWAYS;253}254unreachable("unexpected compare");255}256257static D3D12_LOGIC_OP258logic_op(enum pipe_logicop func)259{260switch (func) {261case PIPE_LOGICOP_CLEAR: return D3D12_LOGIC_OP_CLEAR;262case PIPE_LOGICOP_NOR: return D3D12_LOGIC_OP_NOR;263case PIPE_LOGICOP_AND_INVERTED: return D3D12_LOGIC_OP_AND_INVERTED;264case PIPE_LOGICOP_COPY_INVERTED: return D3D12_LOGIC_OP_COPY_INVERTED;265case PIPE_LOGICOP_AND_REVERSE: return D3D12_LOGIC_OP_AND_REVERSE;266case PIPE_LOGICOP_INVERT: return D3D12_LOGIC_OP_INVERT;267case PIPE_LOGICOP_XOR: return D3D12_LOGIC_OP_XOR;268case PIPE_LOGICOP_NAND: return D3D12_LOGIC_OP_NAND;269case PIPE_LOGICOP_AND: return D3D12_LOGIC_OP_AND;270case PIPE_LOGICOP_EQUIV: return D3D12_LOGIC_OP_EQUIV;271case PIPE_LOGICOP_NOOP: return D3D12_LOGIC_OP_NOOP;272case PIPE_LOGICOP_OR_INVERTED: return D3D12_LOGIC_OP_OR_INVERTED;273case PIPE_LOGICOP_COPY: return D3D12_LOGIC_OP_COPY;274case PIPE_LOGICOP_OR_REVERSE: return D3D12_LOGIC_OP_OR_REVERSE;275case PIPE_LOGICOP_OR: return D3D12_LOGIC_OP_OR;276case PIPE_LOGICOP_SET: return D3D12_LOGIC_OP_SET;277}278unreachable("unexpected logicop function");279}280281static UINT8282color_write_mask(unsigned colormask)283{284UINT8 mask = 0;285286if (colormask & PIPE_MASK_R)287mask |= D3D12_COLOR_WRITE_ENABLE_RED;288if (colormask & PIPE_MASK_G)289mask |= D3D12_COLOR_WRITE_ENABLE_GREEN;290if (colormask & PIPE_MASK_B)291mask |= D3D12_COLOR_WRITE_ENABLE_BLUE;292if (colormask & PIPE_MASK_A)293mask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;294295return mask;296}297298static void *299d3d12_create_blend_state(struct pipe_context *pctx,300const struct pipe_blend_state *blend_state)301{302struct d3d12_blend_state *state = CALLOC_STRUCT(d3d12_blend_state);303if (!state)304return NULL;305306if (blend_state->logicop_enable) {307state->desc.RenderTarget[0].LogicOpEnable = TRUE;308state->desc.RenderTarget[0].LogicOp = logic_op((pipe_logicop) blend_state->logicop_func);309}310311/* TODO Dithering */312313state->desc.AlphaToCoverageEnable = blend_state->alpha_to_coverage;314315int num_targets = 1;316if (blend_state->independent_blend_enable) {317state->desc.IndependentBlendEnable = TRUE;318num_targets = PIPE_MAX_COLOR_BUFS;319}320321for (int i = 0; i < num_targets; ++i) {322const struct pipe_rt_blend_state *rt = blend_state->rt + i;323324if (rt->blend_enable) {325state->desc.RenderTarget[i].BlendEnable = TRUE;326state->desc.RenderTarget[i].SrcBlend = blend_factor_rgb((pipe_blendfactor) rt->rgb_src_factor);327state->desc.RenderTarget[i].DestBlend = blend_factor_rgb((pipe_blendfactor) rt->rgb_dst_factor);328state->desc.RenderTarget[i].BlendOp = blend_op((pipe_blend_func) rt->rgb_func);329state->desc.RenderTarget[i].SrcBlendAlpha = blend_factor_alpha((pipe_blendfactor) rt->alpha_src_factor);330state->desc.RenderTarget[i].DestBlendAlpha = blend_factor_alpha((pipe_blendfactor) rt->alpha_dst_factor);331state->desc.RenderTarget[i].BlendOpAlpha = blend_op((pipe_blend_func) rt->alpha_func);332333state->blend_factor_flags |= need_blend_factor_rgb((pipe_blendfactor) rt->rgb_src_factor);334state->blend_factor_flags |= need_blend_factor_rgb((pipe_blendfactor) rt->rgb_dst_factor);335state->blend_factor_flags |= need_blend_factor_alpha((pipe_blendfactor) rt->alpha_src_factor);336state->blend_factor_flags |= need_blend_factor_alpha((pipe_blendfactor) rt->alpha_dst_factor);337338if (state->blend_factor_flags == (D3D12_BLEND_FACTOR_COLOR | D3D12_BLEND_FACTOR_ALPHA) &&339(d3d12_debug & D3D12_DEBUG_VERBOSE)) {340/* We can't set a blend factor for both constant color and constant alpha */341debug_printf("D3D12: unsupported blend factors combination (const color and const alpha)\n");342}343344if (util_blend_state_is_dual(blend_state, i))345state->is_dual_src = true;346}347348state->desc.RenderTarget[i].RenderTargetWriteMask = color_write_mask(rt->colormask);349}350351return state;352}353354static void355d3d12_bind_blend_state(struct pipe_context *pctx, void *blend_state)356{357struct d3d12_context *ctx = d3d12_context(pctx);358struct d3d12_blend_state *new_state = (struct d3d12_blend_state *) blend_state;359struct d3d12_blend_state *old_state = ctx->gfx_pipeline_state.blend;360361ctx->gfx_pipeline_state.blend = new_state;362ctx->state_dirty |= D3D12_DIRTY_BLEND;363if (new_state == NULL || old_state == NULL ||364new_state->blend_factor_flags != old_state->blend_factor_flags)365ctx->state_dirty |= D3D12_DIRTY_BLEND_COLOR;366}367368static void369d3d12_delete_blend_state(struct pipe_context *pctx, void *blend_state)370{371d3d12_gfx_pipeline_state_cache_invalidate(d3d12_context(pctx), blend_state);372FREE(blend_state);373}374375static D3D12_STENCIL_OP376stencil_op(enum pipe_stencil_op op)377{378switch (op) {379case PIPE_STENCIL_OP_KEEP: return D3D12_STENCIL_OP_KEEP;380case PIPE_STENCIL_OP_ZERO: return D3D12_STENCIL_OP_ZERO;381case PIPE_STENCIL_OP_REPLACE: return D3D12_STENCIL_OP_REPLACE;382case PIPE_STENCIL_OP_INCR: return D3D12_STENCIL_OP_INCR_SAT;383case PIPE_STENCIL_OP_DECR: return D3D12_STENCIL_OP_DECR_SAT;384case PIPE_STENCIL_OP_INCR_WRAP: return D3D12_STENCIL_OP_INCR;385case PIPE_STENCIL_OP_DECR_WRAP: return D3D12_STENCIL_OP_DECR;386case PIPE_STENCIL_OP_INVERT: return D3D12_STENCIL_OP_INVERT;387}388unreachable("unexpected op");389}390391static D3D12_DEPTH_STENCILOP_DESC392stencil_op_state(const struct pipe_stencil_state *src)393{394D3D12_DEPTH_STENCILOP_DESC ret;395ret.StencilFailOp = stencil_op((pipe_stencil_op) src->fail_op);396ret.StencilPassOp = stencil_op((pipe_stencil_op) src->zpass_op);397ret.StencilDepthFailOp = stencil_op((pipe_stencil_op) src->zfail_op);398ret.StencilFunc = compare_op((pipe_compare_func) src->func);399return ret;400}401402static void *403d3d12_create_depth_stencil_alpha_state(struct pipe_context *pctx,404const struct pipe_depth_stencil_alpha_state *depth_stencil_alpha)405{406struct d3d12_depth_stencil_alpha_state *dsa = CALLOC_STRUCT(d3d12_depth_stencil_alpha_state);407if (!dsa)408return NULL;409410if (depth_stencil_alpha->depth_enabled) {411dsa->desc.DepthEnable = TRUE;412dsa->desc.DepthFunc = compare_op((pipe_compare_func) depth_stencil_alpha->depth_func);413}414415/* TODO Add support for GL_depth_bound_tests */416#if 0417if (depth_stencil_alpha->depth.bounds_test) {418dsa->desc.DepthBoundsTestEnable = TRUE;419dsa->min_depth_bounds = depth_stencil_alpha->depth.bounds_min;420dsa->max_depth_bounds = depth_stencil_alpha->depth.bounds_max;421}422#endif423424if (depth_stencil_alpha->stencil[0].enabled) {425dsa->desc.StencilEnable = TRUE;426dsa->desc.FrontFace = stencil_op_state(depth_stencil_alpha->stencil);427}428429if (depth_stencil_alpha->stencil[1].enabled)430dsa->desc.BackFace = stencil_op_state(depth_stencil_alpha->stencil + 1);431else432dsa->desc.BackFace = dsa->desc.FrontFace;433434dsa->desc.StencilReadMask = depth_stencil_alpha->stencil[0].valuemask; /* FIXME Back face mask */435dsa->desc.StencilWriteMask = depth_stencil_alpha->stencil[0].writemask; /* FIXME Back face mask */436dsa->desc.DepthWriteMask = (D3D12_DEPTH_WRITE_MASK) depth_stencil_alpha->depth_writemask;437438return dsa;439}440441static void442d3d12_bind_depth_stencil_alpha_state(struct pipe_context *pctx,443void *dsa)444{445struct d3d12_context *ctx = d3d12_context(pctx);446ctx->gfx_pipeline_state.zsa = (struct d3d12_depth_stencil_alpha_state *) dsa;447ctx->state_dirty |= D3D12_DIRTY_ZSA;448}449450static void451d3d12_delete_depth_stencil_alpha_state(struct pipe_context *pctx,452void *dsa_state)453{454d3d12_gfx_pipeline_state_cache_invalidate(d3d12_context(pctx), dsa_state);455FREE(dsa_state);456}457458static D3D12_FILL_MODE459fill_mode(unsigned mode)460{461switch (mode) {462case PIPE_POLYGON_MODE_FILL:463return D3D12_FILL_MODE_SOLID;464case PIPE_POLYGON_MODE_LINE:465return D3D12_FILL_MODE_WIREFRAME;466case PIPE_POLYGON_MODE_POINT:467return D3D12_FILL_MODE_SOLID;468469default:470unreachable("unsupported fill-mode");471}472}473474static void *475d3d12_create_rasterizer_state(struct pipe_context *pctx,476const struct pipe_rasterizer_state *rs_state)477{478struct d3d12_rasterizer_state *cso = CALLOC_STRUCT(d3d12_rasterizer_state);479if (!cso)480return NULL;481482cso->base = *rs_state;483484assert(rs_state->depth_clip_near == rs_state->depth_clip_far);485486switch (rs_state->cull_face) {487case PIPE_FACE_NONE:488if (rs_state->fill_front != rs_state->fill_back) {489cso->base.cull_face = PIPE_FACE_BACK;490cso->desc.CullMode = D3D12_CULL_MODE_BACK;491cso->desc.FillMode = fill_mode(rs_state->fill_front);492493/* create a modified CSO for the back-state, so we can draw with494* either.495*/496struct pipe_rasterizer_state templ = *rs_state;497templ.cull_face = PIPE_FACE_FRONT;498templ.fill_front = rs_state->fill_back;499cso->twoface_back = d3d12_create_rasterizer_state(pctx, &templ);500501if (!cso->twoface_back) {502FREE(cso);503return NULL;504}505} else {506cso->desc.CullMode = D3D12_CULL_MODE_NONE;507cso->desc.FillMode = fill_mode(rs_state->fill_front);508}509break;510511case PIPE_FACE_FRONT:512cso->desc.CullMode = D3D12_CULL_MODE_FRONT;513cso->desc.FillMode = fill_mode(rs_state->fill_back);514break;515516case PIPE_FACE_BACK:517cso->desc.CullMode = D3D12_CULL_MODE_BACK;518cso->desc.FillMode = fill_mode(rs_state->fill_front);519break;520521case PIPE_FACE_FRONT_AND_BACK:522/* this is wrong, and we shouldn't actually have to support this! */523cso->desc.CullMode = D3D12_CULL_MODE_NONE;524cso->desc.FillMode = D3D12_FILL_MODE_SOLID;525break;526527default:528unreachable("unsupported cull-mode");529}530531cso->desc.FrontCounterClockwise = rs_state->front_ccw;532cso->desc.DepthClipEnable = rs_state->depth_clip_near;533cso->desc.MultisampleEnable = rs_state->multisample;534cso->desc.AntialiasedLineEnable = rs_state->line_smooth;535cso->desc.ForcedSampleCount = 0; // TODO536cso->desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; /* Not Implemented */537538return cso;539}540541static void542d3d12_bind_rasterizer_state(struct pipe_context *pctx, void *rs_state)543{544struct d3d12_context *ctx = d3d12_context(pctx);545ctx->gfx_pipeline_state.rast = (struct d3d12_rasterizer_state *)rs_state;546ctx->state_dirty |= D3D12_DIRTY_RASTERIZER | D3D12_DIRTY_SCISSOR;547}548549static void550d3d12_delete_rasterizer_state(struct pipe_context *pctx, void *rs_state)551{552d3d12_gfx_pipeline_state_cache_invalidate(d3d12_context(pctx), rs_state);553FREE(rs_state);554}555556static D3D12_TEXTURE_ADDRESS_MODE557sampler_address_mode(enum pipe_tex_wrap wrap, enum pipe_tex_filter filter)558{559switch (wrap) {560case PIPE_TEX_WRAP_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_WRAP;561case PIPE_TEX_WRAP_CLAMP: return filter == PIPE_TEX_FILTER_NEAREST ?562D3D12_TEXTURE_ADDRESS_MODE_CLAMP :563D3D12_TEXTURE_ADDRESS_MODE_BORDER;564case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;565case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_BORDER;566case PIPE_TEX_WRAP_MIRROR_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;567case PIPE_TEX_WRAP_MIRROR_CLAMP: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; /* not technically correct, but kinda works */568case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;569case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; /* FIXME: Doesn't exist in D3D12 */570}571unreachable("unexpected wrap");572}573574static D3D12_FILTER575get_filter(const struct pipe_sampler_state *state)576{577static const D3D12_FILTER lut[16] = {578D3D12_FILTER_MIN_MAG_MIP_POINT,579D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,580D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,581D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR,582D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,583D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,584D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT,585D3D12_FILTER_MIN_MAG_MIP_LINEAR,586D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT,587D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR,588D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT,589D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR,590D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT,591D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR,592D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT,593D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR,594};595596static const D3D12_FILTER anisotropic_lut[2] = {597D3D12_FILTER_ANISOTROPIC,598D3D12_FILTER_COMPARISON_ANISOTROPIC,599};600601if (state->max_anisotropy > 1) {602return anisotropic_lut[state->compare_mode];603} else {604int idx = (state->mag_img_filter << 1) |605(state->min_img_filter << 2) |606(state->compare_mode << 3);607if (state->min_mip_filter != PIPE_TEX_MIPFILTER_NONE)608idx |= state->min_mip_filter;609return lut[idx];610}611}612613static void *614d3d12_create_sampler_state(struct pipe_context *pctx,615const struct pipe_sampler_state *state)616{617struct d3d12_context *ctx = d3d12_context(pctx);618struct d3d12_screen *screen = d3d12_screen(pctx->screen);619struct d3d12_sampler_state *ss;620D3D12_SAMPLER_DESC desc = {};621if (!state)622return NULL;623624ss = CALLOC_STRUCT(d3d12_sampler_state);625ss->filter = (pipe_tex_filter)state->min_img_filter;626ss->wrap_r = (pipe_tex_wrap)state->wrap_r;627ss->wrap_s = (pipe_tex_wrap)state->wrap_s;628ss->wrap_t = (pipe_tex_wrap)state->wrap_t;629ss->lod_bias = state->lod_bias;630ss->min_lod = state->min_lod;631ss->max_lod = state->max_lod;632memcpy(ss->border_color, state->border_color.f, sizeof(float) * 4);633ss->compare_func = (pipe_compare_func)state->compare_func;634635if (state->min_mip_filter < PIPE_TEX_MIPFILTER_NONE) {636desc.MinLOD = state->min_lod;637desc.MaxLOD = state->max_lod;638} else if (state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {639desc.MinLOD = 0;640desc.MaxLOD = 0;641} else {642unreachable("unexpected mip filter");643}644645if (state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {646desc.ComparisonFunc = compare_op((pipe_compare_func) state->compare_func);647desc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;648} else if (state->compare_mode == PIPE_TEX_COMPARE_NONE) {649desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;650desc.Filter = get_filter(state);651} else652unreachable("unexpected comparison mode");653654desc.MaxAnisotropy = state->max_anisotropy;655656desc.AddressU = sampler_address_mode((pipe_tex_wrap) state->wrap_s,657(pipe_tex_filter) state->min_img_filter);658desc.AddressV = sampler_address_mode((pipe_tex_wrap) state->wrap_t,659(pipe_tex_filter) state->min_img_filter);660desc.AddressW = sampler_address_mode((pipe_tex_wrap) state->wrap_r,661(pipe_tex_filter) state->min_img_filter);662desc.MipLODBias = CLAMP(state->lod_bias, -16.0f, 15.99f);663memcpy(desc.BorderColor, state->border_color.f, sizeof(float) * 4);664665// TODO Normalized Coordinates?666d3d12_descriptor_pool_alloc_handle(ctx->sampler_pool, &ss->handle);667screen->dev->CreateSampler(&desc, ss->handle.cpu_handle);668669if (state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {670desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;671struct pipe_sampler_state fake_state = *state;672fake_state.compare_mode = PIPE_TEX_COMPARE_NONE;673desc.Filter = get_filter(&fake_state);674675d3d12_descriptor_pool_alloc_handle(ctx->sampler_pool,676&ss->handle_without_shadow);677screen->dev->CreateSampler(&desc,678ss->handle_without_shadow.cpu_handle);679ss->is_shadow_sampler = true;680}681682return ss;683}684685static void686d3d12_bind_sampler_states(struct pipe_context *pctx,687enum pipe_shader_type shader,688unsigned start_slot,689unsigned num_samplers,690void **samplers)691{692struct d3d12_context *ctx = d3d12_context(pctx);693bool shader_state_dirty = false;694695#define STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(X) \696static_assert((enum compare_func)PIPE_FUNC_##X == COMPARE_FUNC_##X, #X " needs switch case");697698STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(LESS);699STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(GREATER);700STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(LEQUAL);701STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(GEQUAL);702STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(NOTEQUAL);703STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(NEVER);704STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC(ALWAYS);705706#undef STATIC_ASSERT_PIPE_EQUAL_COMP_FUNC707708for (unsigned i = 0; i < num_samplers; ++i) {709d3d12_sampler_state *sampler = (struct d3d12_sampler_state*) samplers[i];710ctx->samplers[shader][start_slot + i] = sampler;711dxil_wrap_sampler_state &wrap = ctx->tex_wrap_states[shader][start_slot + i];712if (sampler) {713shader_state_dirty |= wrap.wrap[0] != sampler->wrap_s ||714wrap.wrap[1] != sampler->wrap_t ||715wrap.wrap[2] != sampler->wrap_r;716shader_state_dirty |= !!memcmp(wrap.border_color, sampler->border_color, 4 * sizeof(float));717718wrap.wrap[0] = sampler->wrap_s;719wrap.wrap[1] = sampler->wrap_t;720wrap.wrap[2] = sampler->wrap_r;721wrap.lod_bias = sampler->lod_bias;722wrap.min_lod = sampler->min_lod;723wrap.max_lod = sampler->max_lod;724memcpy(wrap.border_color, sampler->border_color, 4 * sizeof(float));725ctx->tex_compare_func[shader][start_slot + i] = (enum compare_func)sampler->compare_func;726} else {727memset(&wrap, 0, sizeof (dxil_wrap_sampler_state));728}729}730731ctx->num_samplers[shader] = start_slot + num_samplers;732ctx->shader_dirty[shader] |= D3D12_SHADER_DIRTY_SAMPLERS;733if (shader_state_dirty)734ctx->state_dirty |= D3D12_DIRTY_SHADER;735}736737static void738d3d12_delete_sampler_state(struct pipe_context *pctx,739void *ss)740{741struct d3d12_batch *batch = d3d12_current_batch(d3d12_context(pctx));742struct d3d12_sampler_state *state = (struct d3d12_sampler_state*) ss;743util_dynarray_append(&batch->zombie_samplers, d3d12_descriptor_handle,744state->handle);745if (state->is_shadow_sampler)746util_dynarray_append(&batch->zombie_samplers, d3d12_descriptor_handle,747state->handle_without_shadow);748FREE(ss);749}750751static D3D12_SRV_DIMENSION752view_dimension(enum pipe_texture_target target, unsigned samples)753{754switch (target) {755case PIPE_BUFFER: return D3D12_SRV_DIMENSION_BUFFER;756case PIPE_TEXTURE_1D: return D3D12_SRV_DIMENSION_TEXTURE1D;757case PIPE_TEXTURE_1D_ARRAY: return D3D12_SRV_DIMENSION_TEXTURE1DARRAY;758case PIPE_TEXTURE_RECT:759case PIPE_TEXTURE_2D:760return samples > 1 ? D3D12_SRV_DIMENSION_TEXTURE2DMS :761D3D12_SRV_DIMENSION_TEXTURE2D;762case PIPE_TEXTURE_2D_ARRAY:763return samples > 1 ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY :764D3D12_SRV_DIMENSION_TEXTURE2DARRAY;765case PIPE_TEXTURE_CUBE: return D3D12_SRV_DIMENSION_TEXTURECUBE;766case PIPE_TEXTURE_CUBE_ARRAY: return D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;767case PIPE_TEXTURE_3D: return D3D12_SRV_DIMENSION_TEXTURE3D;768default:769unreachable("unexpected target");770}771}772773static D3D12_SHADER_COMPONENT_MAPPING774component_mapping(enum pipe_swizzle swizzle, D3D12_SHADER_COMPONENT_MAPPING id)775{776switch (swizzle) {777case PIPE_SWIZZLE_X: return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0;778case PIPE_SWIZZLE_Y: return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1;779case PIPE_SWIZZLE_Z: return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2;780case PIPE_SWIZZLE_W: return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3;781case PIPE_SWIZZLE_0: return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0;782case PIPE_SWIZZLE_1: return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1;783case PIPE_SWIZZLE_NONE: return id;784default:785unreachable("unexpected swizzle");786}787}788789static struct pipe_sampler_view *790d3d12_create_sampler_view(struct pipe_context *pctx,791struct pipe_resource *texture,792const struct pipe_sampler_view *state)793{794struct d3d12_screen *screen = d3d12_screen(pctx->screen);795struct d3d12_resource *res = d3d12_resource(texture);796struct d3d12_sampler_view *sampler_view = CALLOC_STRUCT(d3d12_sampler_view);797798sampler_view->base = *state;799sampler_view->base.texture = NULL;800pipe_resource_reference(&sampler_view->base.texture, texture);801sampler_view->base.reference.count = 1;802sampler_view->base.context = pctx;803sampler_view->mip_levels = state->u.tex.last_level - state->u.tex.first_level + 1;804sampler_view->array_size = texture->array_size;805806D3D12_SHADER_RESOURCE_VIEW_DESC desc = {};807struct d3d12_format_info format_info = d3d12_get_format_info(state->format, state->target);808pipe_swizzle swizzle[4] = {809format_info.swizzle[sampler_view->base.swizzle_r],810format_info.swizzle[sampler_view->base.swizzle_g],811format_info.swizzle[sampler_view->base.swizzle_b],812format_info.swizzle[sampler_view->base.swizzle_a]813};814815sampler_view->swizzle_override_r = swizzle[0];816sampler_view->swizzle_override_g = swizzle[1];817sampler_view->swizzle_override_b = swizzle[2];818sampler_view->swizzle_override_a = swizzle[3];819820desc.Format = d3d12_get_resource_srv_format(state->format, state->target);821desc.ViewDimension = view_dimension(state->target, texture->nr_samples);822823/* Integer cube textures are not really supported, because TextureLoad doesn't exist824* for cube maps, and we sampling is not supported for integer textures, so we have to825* handle this SRV as if it were a 2D texture array */826if ((desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE ||827desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) &&828util_format_is_pure_integer(state->format)) {829desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;830}831832desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(833component_mapping(swizzle[0], D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0),834component_mapping(swizzle[1], D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1),835component_mapping(swizzle[2], D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2),836component_mapping(swizzle[3], D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3)837);838839unsigned array_size = state->u.tex.last_layer - state->u.tex.first_layer + 1;840switch (desc.ViewDimension) {841case D3D12_SRV_DIMENSION_TEXTURE1D:842if (state->u.tex.first_layer > 0)843debug_printf("D3D12: can't create 1D SRV from layer %d\n",844state->u.tex.first_layer);845846desc.Texture1D.MostDetailedMip = state->u.tex.first_level;847desc.Texture1D.MipLevels = sampler_view->mip_levels;848desc.Texture1D.ResourceMinLODClamp = 0.0f;849break;850case D3D12_SRV_DIMENSION_TEXTURE1DARRAY:851desc.Texture1DArray.MostDetailedMip = state->u.tex.first_level;852desc.Texture1DArray.MipLevels = sampler_view->mip_levels;853desc.Texture1DArray.ResourceMinLODClamp = 0.0f;854desc.Texture1DArray.FirstArraySlice = state->u.tex.first_layer;855desc.Texture1DArray.ArraySize = array_size;856break;857case D3D12_SRV_DIMENSION_TEXTURE2D:858if (state->u.tex.first_layer > 0)859debug_printf("D3D12: can't create 2D SRV from layer %d\n",860state->u.tex.first_layer);861862desc.Texture2D.MostDetailedMip = state->u.tex.first_level;863desc.Texture2D.MipLevels = sampler_view->mip_levels;864desc.Texture2D.PlaneSlice = format_info.plane_slice;865desc.Texture2D.ResourceMinLODClamp = 0.0f;866break;867case D3D12_SRV_DIMENSION_TEXTURE2DMS:868if (state->u.tex.first_layer > 0)869debug_printf("D3D12: can't create 2DMS SRV from layer %d\n",870state->u.tex.first_layer);871break;872case D3D12_SRV_DIMENSION_TEXTURE2DARRAY:873desc.Texture2DArray.MostDetailedMip = state->u.tex.first_level;874desc.Texture2DArray.MipLevels = sampler_view->mip_levels;875desc.Texture2DArray.ResourceMinLODClamp = 0.0f;876desc.Texture2DArray.FirstArraySlice = state->u.tex.first_layer;877desc.Texture2DArray.PlaneSlice = format_info.plane_slice;878desc.Texture2DArray.ArraySize = array_size;879break;880case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY:881desc.Texture2DMSArray.FirstArraySlice = state->u.tex.first_layer;882desc.Texture2DMSArray.ArraySize = array_size;883break;884case D3D12_SRV_DIMENSION_TEXTURE3D:885if (state->u.tex.first_layer > 0)886debug_printf("D3D12: can't create 3D SRV from layer %d\n",887state->u.tex.first_layer);888889desc.Texture3D.MostDetailedMip = state->u.tex.first_level;890desc.Texture3D.MipLevels = sampler_view->mip_levels;891desc.Texture3D.ResourceMinLODClamp = 0.0f;892break;893case D3D12_SRV_DIMENSION_TEXTURECUBE:894if (state->u.tex.first_layer > 0)895debug_printf("D3D12: can't create CUBE SRV from layer %d\n",896state->u.tex.first_layer);897898desc.TextureCube.MostDetailedMip = state->u.tex.first_level;899desc.TextureCube.MipLevels = sampler_view->mip_levels;900desc.TextureCube.ResourceMinLODClamp = 0.0f;901break;902case D3D12_SRV_DIMENSION_BUFFER:903desc.Buffer.FirstElement = 0;904desc.Buffer.StructureByteStride = 0;905desc.Buffer.NumElements = texture->width0 / util_format_get_blocksize(state->format);906break;907default:908unreachable("Invalid SRV dimension");909}910911mtx_lock(&screen->descriptor_pool_mutex);912d3d12_descriptor_pool_alloc_handle(screen->view_pool, &sampler_view->handle);913mtx_unlock(&screen->descriptor_pool_mutex);914915screen->dev->CreateShaderResourceView(d3d12_resource_resource(res), &desc,916sampler_view->handle.cpu_handle);917918return &sampler_view->base;919}920921static void922d3d12_increment_sampler_view_bind_count(struct pipe_context *ctx,923enum pipe_shader_type shader_type,924struct pipe_sampler_view *view) {925struct d3d12_resource *res = d3d12_resource(view->texture);926if (res)927res->bind_counts[shader_type][D3D12_RESOURCE_BINDING_TYPE_SRV]++;928}929930static void931d3d12_decrement_sampler_view_bind_count(struct pipe_context *ctx,932enum pipe_shader_type shader_type,933struct pipe_sampler_view *view) {934struct d3d12_resource *res = d3d12_resource(view->texture);935if (res) {936assert(res->bind_counts[shader_type][D3D12_RESOURCE_BINDING_TYPE_SRV] > 0);937res->bind_counts[shader_type][D3D12_RESOURCE_BINDING_TYPE_SRV]--;938}939}940941static void942d3d12_set_sampler_views(struct pipe_context *pctx,943enum pipe_shader_type shader_type,944unsigned start_slot,945unsigned num_views,946unsigned unbind_num_trailing_slots,947struct pipe_sampler_view **views)948{949struct d3d12_context *ctx = d3d12_context(pctx);950unsigned shader_bit = (1 << shader_type);951ctx->has_int_samplers &= ~shader_bit;952953for (unsigned i = 0; i < num_views; ++i) {954struct pipe_sampler_view *&old_view = ctx->sampler_views[shader_type][start_slot + i];955if (old_view)956d3d12_decrement_sampler_view_bind_count(pctx, shader_type, old_view);957958struct pipe_sampler_view *new_view = views[i];959if (new_view)960d3d12_increment_sampler_view_bind_count(pctx, shader_type, new_view);961962pipe_sampler_view_reference(&old_view, views[i]);963964if (views[i]) {965dxil_wrap_sampler_state &wss = ctx->tex_wrap_states[shader_type][start_slot + i];966dxil_texture_swizzle_state &swizzle_state = ctx->tex_swizzle_state[shader_type][i];967if (util_format_is_pure_integer(views[i]->format)) {968ctx->has_int_samplers |= shader_bit;969wss.is_int_sampler = 1;970wss.last_level = views[i]->texture->last_level;971/* When we emulate a integer cube texture (array) by using a texture 2d Array972* the coordinates are evaluated to always reside withing the acceptable range973* because the 3d ray for picking the texel is always pointing at one cube face,974* hence we can skip the boundary condition handling when the texture operations are975* lowered to texel fetches later. */976wss.skip_boundary_conditions = views[i]->target == PIPE_TEXTURE_CUBE ||977views[i]->target == PIPE_TEXTURE_CUBE_ARRAY;978} else {979wss.is_int_sampler = 0;980}981/* We need the swizzle state for compare texture lowering, because it982* encode the use of the shadow texture lookup result as either luminosity,983* intensity, or alpha. and we need the swizzle state for applying the984* boundary color correctly */985struct d3d12_sampler_view *ss = d3d12_sampler_view(views[i]);986swizzle_state.swizzle_r = ss->swizzle_override_r;987swizzle_state.swizzle_g = ss->swizzle_override_g;988swizzle_state.swizzle_b = ss->swizzle_override_b;989swizzle_state.swizzle_a = ss->swizzle_override_a;990}991}992993for (unsigned i = 0; i < unbind_num_trailing_slots; i++) {994struct pipe_sampler_view *&old_view = ctx->sampler_views[shader_type][start_slot + num_views + i];995if (old_view)996d3d12_decrement_sampler_view_bind_count(pctx, shader_type, old_view);997pipe_sampler_view_reference(&old_view, NULL);998}999ctx->num_sampler_views[shader_type] = start_slot + num_views;1000ctx->shader_dirty[shader_type] |= D3D12_SHADER_DIRTY_SAMPLER_VIEWS;1001}10021003static void1004d3d12_destroy_sampler_view(struct pipe_context *pctx,1005struct pipe_sampler_view *pview)1006{1007struct d3d12_sampler_view *view = d3d12_sampler_view(pview);1008d3d12_descriptor_handle_free(&view->handle);1009pipe_resource_reference(&view->base.texture, NULL);1010FREE(view);1011}10121013static void1014delete_shader(struct d3d12_context *ctx, enum pipe_shader_type stage,1015struct d3d12_shader_selector *shader)1016{1017d3d12_gfx_pipeline_state_cache_invalidate_shader(ctx, stage, shader);10181019/* Make sure the pipeline state no longer reference the deleted shader */1020struct d3d12_shader *iter = shader->first;1021while (iter) {1022if (ctx->gfx_pipeline_state.stages[stage] == iter) {1023ctx->gfx_pipeline_state.stages[stage] = NULL;1024break;1025}1026iter = iter->next_variant;1027}10281029d3d12_shader_free(shader);1030}10311032static void1033bind_stage(struct d3d12_context *ctx, enum pipe_shader_type stage,1034struct d3d12_shader_selector *shader)1035{1036assert(stage < D3D12_GFX_SHADER_STAGES);1037ctx->gfx_stages[stage] = shader;1038}10391040static void *1041d3d12_create_vs_state(struct pipe_context *pctx,1042const struct pipe_shader_state *shader)1043{1044return d3d12_create_shader(d3d12_context(pctx), PIPE_SHADER_VERTEX, shader);1045}10461047static void1048d3d12_bind_vs_state(struct pipe_context *pctx,1049void *vss)1050{1051bind_stage(d3d12_context(pctx), PIPE_SHADER_VERTEX,1052(struct d3d12_shader_selector *) vss);1053}10541055static void1056d3d12_delete_vs_state(struct pipe_context *pctx,1057void *vs)1058{1059delete_shader(d3d12_context(pctx), PIPE_SHADER_VERTEX,1060(struct d3d12_shader_selector *) vs);1061}10621063static void *1064d3d12_create_fs_state(struct pipe_context *pctx,1065const struct pipe_shader_state *shader)1066{1067return d3d12_create_shader(d3d12_context(pctx), PIPE_SHADER_FRAGMENT, shader);1068}10691070static void1071d3d12_bind_fs_state(struct pipe_context *pctx,1072void *fss)1073{1074bind_stage(d3d12_context(pctx), PIPE_SHADER_FRAGMENT,1075(struct d3d12_shader_selector *) fss);1076}10771078static void1079d3d12_delete_fs_state(struct pipe_context *pctx,1080void *fs)1081{1082delete_shader(d3d12_context(pctx), PIPE_SHADER_FRAGMENT,1083(struct d3d12_shader_selector *) fs);1084}10851086static void *1087d3d12_create_gs_state(struct pipe_context *pctx,1088const struct pipe_shader_state *shader)1089{1090return d3d12_create_shader(d3d12_context(pctx), PIPE_SHADER_GEOMETRY, shader);1091}10921093static void1094d3d12_bind_gs_state(struct pipe_context *pctx, void *gss)1095{1096bind_stage(d3d12_context(pctx), PIPE_SHADER_GEOMETRY,1097(struct d3d12_shader_selector *) gss);1098}10991100static void1101d3d12_delete_gs_state(struct pipe_context *pctx, void *gs)1102{1103delete_shader(d3d12_context(pctx), PIPE_SHADER_GEOMETRY,1104(struct d3d12_shader_selector *) gs);1105}11061107static bool1108d3d12_init_polygon_stipple(struct pipe_context *pctx)1109{1110struct d3d12_context *ctx = d3d12_context(pctx);11111112ctx->pstipple.texture = util_pstipple_create_stipple_texture(pctx, NULL);1113if (!ctx->pstipple.texture)1114return false;11151116ctx->pstipple.sampler_view = util_pstipple_create_sampler_view(pctx, ctx->pstipple.texture);1117if (!ctx->pstipple.sampler_view)1118return false;11191120ctx->pstipple.sampler_cso = (struct d3d12_sampler_state *)util_pstipple_create_sampler(pctx);1121if (!ctx->pstipple.sampler_cso)1122return false;11231124return true;1125}11261127static void1128d3d12_set_polygon_stipple(struct pipe_context *pctx,1129const struct pipe_poly_stipple *ps)1130{1131static bool initialized = false;1132static const uint32_t zero[32] = {0};1133static uint32_t undef[32] = {0};1134struct d3d12_context *ctx = d3d12_context(pctx);11351136if (!initialized)1137memset(undef, UINT32_MAX, sizeof(undef));11381139if (!memcmp(ctx->pstipple.pattern, ps->stipple, sizeof(ps->stipple)))1140return;11411142memcpy(ctx->pstipple.pattern, ps->stipple, sizeof(ps->stipple));1143ctx->pstipple.enabled = !!memcmp(ps->stipple, undef, sizeof(ps->stipple)) &&1144!!memcmp(ps->stipple, zero, sizeof(ps->stipple));1145if (ctx->pstipple.enabled)1146util_pstipple_update_stipple_texture(pctx, ctx->pstipple.texture, ps->stipple);1147}11481149static void1150d3d12_set_vertex_buffers(struct pipe_context *pctx,1151unsigned start_slot,1152unsigned num_buffers,1153unsigned unbind_num_trailing_slots,1154bool take_ownership,1155const struct pipe_vertex_buffer *buffers)1156{1157struct d3d12_context *ctx = d3d12_context(pctx);1158util_set_vertex_buffers_count(ctx->vbs, &ctx->num_vbs,1159buffers, start_slot, num_buffers,1160unbind_num_trailing_slots,1161take_ownership);11621163for (unsigned i = 0; i < ctx->num_vbs; ++i) {1164const struct pipe_vertex_buffer* buf = ctx->vbs + i;1165if (!buf->buffer.resource)1166continue;1167struct d3d12_resource *res = d3d12_resource(buf->buffer.resource);1168ctx->vbvs[i].BufferLocation = d3d12_resource_gpu_virtual_address(res) + buf->buffer_offset;1169ctx->vbvs[i].StrideInBytes = buf->stride;1170ctx->vbvs[i].SizeInBytes = res->base.width0 - buf->buffer_offset;1171}1172ctx->state_dirty |= D3D12_DIRTY_VERTEX_BUFFERS;1173}11741175static void1176d3d12_set_viewport_states(struct pipe_context *pctx,1177unsigned start_slot,1178unsigned num_viewports,1179const struct pipe_viewport_state *state)1180{1181struct d3d12_context *ctx = d3d12_context(pctx);11821183for (unsigned i = 0; i < num_viewports; ++i) {1184if (state[i].scale[1] < 0) {1185ctx->flip_y = 1.0f;1186ctx->viewports[start_slot + i].TopLeftY = state[i].translate[1] + state[i].scale[1];1187ctx->viewports[start_slot + i].Height = -state[i].scale[1] * 2;1188} else {1189ctx->flip_y = -1.0f;1190ctx->viewports[start_slot + i].TopLeftY = state[i].translate[1] - state[i].scale[1];1191ctx->viewports[start_slot + i].Height = state[i].scale[1] * 2;1192}1193ctx->viewports[start_slot + i].TopLeftX = state[i].translate[0] - state[i].scale[0];1194ctx->viewports[start_slot + i].Width = state[i].scale[0] * 2;11951196float near_depth = state[i].translate[2] - state[i].scale[2];1197float far_depth = state[i].translate[2] + state[i].scale[2];11981199ctx->reverse_depth_range = near_depth > far_depth;1200if (ctx->reverse_depth_range) {1201float tmp = near_depth;1202near_depth = far_depth;1203far_depth = tmp;1204}1205ctx->viewports[start_slot + i].MinDepth = near_depth;1206ctx->viewports[start_slot + i].MaxDepth = far_depth;1207ctx->viewport_states[start_slot + i] = state[i];1208}1209ctx->num_viewports = start_slot + num_viewports;1210ctx->state_dirty |= D3D12_DIRTY_VIEWPORT;1211}121212131214static void1215d3d12_set_scissor_states(struct pipe_context *pctx,1216unsigned start_slot, unsigned num_scissors,1217const struct pipe_scissor_state *states)1218{1219struct d3d12_context *ctx = d3d12_context(pctx);12201221for (unsigned i = 0; i < num_scissors; i++) {1222ctx->scissors[start_slot + i].left = states[i].minx;1223ctx->scissors[start_slot + i].top = states[i].miny;1224ctx->scissors[start_slot + i].right = states[i].maxx;1225ctx->scissors[start_slot + i].bottom = states[i].maxy;1226ctx->scissor_states[start_slot + i] = states[i];1227}1228ctx->state_dirty |= D3D12_DIRTY_SCISSOR;1229}12301231static void1232d3d12_decrement_constant_buffer_bind_count(struct d3d12_context *ctx,1233enum pipe_shader_type shader,1234struct d3d12_resource *res) {1235assert(res->bind_counts[shader][D3D12_RESOURCE_BINDING_TYPE_CBV] > 0);1236res->bind_counts[shader][D3D12_RESOURCE_BINDING_TYPE_CBV]--;1237}12381239static void1240d3d12_increment_constant_buffer_bind_count(struct d3d12_context *ctx,1241enum pipe_shader_type shader,1242struct d3d12_resource *res) {1243res->bind_counts[shader][D3D12_RESOURCE_BINDING_TYPE_CBV]++;1244}12451246static void1247d3d12_set_constant_buffer(struct pipe_context *pctx,1248enum pipe_shader_type shader, uint index,1249bool take_ownership,1250const struct pipe_constant_buffer *buf)1251{1252struct d3d12_context *ctx = d3d12_context(pctx);12531254if (buf) {1255struct pipe_resource *buffer = buf->buffer;1256unsigned offset = buf->buffer_offset;1257if (buf->user_buffer) {1258u_upload_data(pctx->const_uploader, 0, buf->buffer_size,1259D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,1260buf->user_buffer, &offset, &ctx->cbufs[shader][index].buffer);12611262} else {1263if (take_ownership) {1264struct d3d12_resource *old_buf = d3d12_resource(ctx->cbufs[shader][index].buffer);1265if (old_buf)1266d3d12_decrement_constant_buffer_bind_count(ctx, shader, old_buf);1267pipe_resource_reference(&ctx->cbufs[shader][index].buffer, NULL);1268ctx->cbufs[shader][index].buffer = buffer;1269if (buffer)1270d3d12_increment_constant_buffer_bind_count(ctx, shader, d3d12_resource(buffer));1271} else {1272pipe_resource_reference(&ctx->cbufs[shader][index].buffer, buffer);1273}1274}127512761277ctx->cbufs[shader][index].buffer_offset = offset;1278ctx->cbufs[shader][index].buffer_size = buf->buffer_size;1279ctx->cbufs[shader][index].user_buffer = NULL;12801281} else {1282pipe_resource_reference(&ctx->cbufs[shader][index].buffer, NULL);1283ctx->cbufs[shader][index].buffer_offset = 0;1284ctx->cbufs[shader][index].buffer_size = 0;1285ctx->cbufs[shader][index].user_buffer = NULL;1286}1287ctx->shader_dirty[shader] |= D3D12_SHADER_DIRTY_CONSTBUF;1288}12891290static void1291d3d12_set_framebuffer_state(struct pipe_context *pctx,1292const struct pipe_framebuffer_state *state)1293{1294struct d3d12_context *ctx = d3d12_context(pctx);1295int samples = -1;12961297util_copy_framebuffer_state(&d3d12_context(pctx)->fb, state);12981299ctx->gfx_pipeline_state.num_cbufs = state->nr_cbufs;1300ctx->gfx_pipeline_state.has_float_rtv = false;1301for (int i = 0; i < state->nr_cbufs; ++i) {1302if (state->cbufs[i]) {1303if (util_format_is_float(state->cbufs[i]->format))1304ctx->gfx_pipeline_state.has_float_rtv = true;1305ctx->gfx_pipeline_state.rtv_formats[i] = d3d12_get_format(state->cbufs[i]->format);1306samples = MAX2(samples, (int)state->cbufs[i]->texture->nr_samples);1307} else {1308ctx->gfx_pipeline_state.rtv_formats[i] = DXGI_FORMAT_UNKNOWN;1309}1310}13111312if (state->zsbuf) {1313ctx->gfx_pipeline_state.dsv_format = d3d12_get_resource_rt_format(state->zsbuf->format);1314samples = MAX2(samples, (int)ctx->fb.zsbuf->texture->nr_samples);1315} else1316ctx->gfx_pipeline_state.dsv_format = DXGI_FORMAT_UNKNOWN;13171318if (samples < 0)1319samples = state->samples;13201321ctx->gfx_pipeline_state.samples = MAX2(samples, 1);13221323ctx->state_dirty |= D3D12_DIRTY_FRAMEBUFFER;1324}13251326static void1327d3d12_set_blend_color(struct pipe_context *pctx,1328const struct pipe_blend_color *color)1329{1330struct d3d12_context *ctx = d3d12_context(pctx);1331memcpy(ctx->blend_factor, color->color, sizeof(float) * 4);1332ctx->state_dirty |= D3D12_DIRTY_BLEND_COLOR;1333}13341335static void1336d3d12_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask)1337{1338struct d3d12_context *ctx = d3d12_context(pctx);1339ctx->gfx_pipeline_state.sample_mask = sample_mask;1340ctx->state_dirty |= D3D12_DIRTY_SAMPLE_MASK;1341}13421343static void1344d3d12_set_stencil_ref(struct pipe_context *pctx,1345const struct pipe_stencil_ref ref)1346{1347struct d3d12_context *ctx = d3d12_context(pctx);1348if ((ref.ref_value[0] != ref.ref_value[1]) &&1349(d3d12_debug & D3D12_DEBUG_VERBOSE))1350debug_printf("D3D12: Different values for front and back stencil reference are not supported\n");1351ctx->stencil_ref = ref;1352ctx->state_dirty |= D3D12_DIRTY_STENCIL_REF;1353}13541355static void1356d3d12_set_clip_state(struct pipe_context *pctx,1357const struct pipe_clip_state *pcs)1358{1359}13601361static struct pipe_stream_output_target *1362d3d12_create_stream_output_target(struct pipe_context *pctx,1363struct pipe_resource *pres,1364unsigned buffer_offset,1365unsigned buffer_size)1366{1367struct d3d12_resource *res = d3d12_resource(pres);1368struct d3d12_stream_output_target *cso = CALLOC_STRUCT(d3d12_stream_output_target);13691370if (!cso)1371return NULL;13721373pipe_reference_init(&cso->base.reference, 1);1374pipe_resource_reference(&cso->base.buffer, pres);1375cso->base.buffer_offset = buffer_offset;1376cso->base.buffer_size = buffer_size;1377cso->base.context = pctx;13781379if (res->bo && res->bo->buffer && d3d12_buffer(res->bo->buffer)->map)1380util_range_add(pres, &res->valid_buffer_range, buffer_offset,1381buffer_offset + buffer_size);13821383return &cso->base;1384}13851386static void1387d3d12_stream_output_target_destroy(struct pipe_context *ctx,1388struct pipe_stream_output_target *state)1389{1390pipe_resource_reference(&state->buffer, NULL);13911392FREE(state);1393}13941395static void1396fill_stream_output_buffer_view(D3D12_STREAM_OUTPUT_BUFFER_VIEW *view,1397struct d3d12_stream_output_target *target)1398{1399struct d3d12_resource *res = d3d12_resource(target->base.buffer);1400struct d3d12_resource *fill_res = d3d12_resource(target->fill_buffer);14011402view->SizeInBytes = target->base.buffer_size;1403view->BufferLocation = d3d12_resource_gpu_virtual_address(res) + target->base.buffer_offset;1404view->BufferFilledSizeLocation = d3d12_resource_gpu_virtual_address(fill_res) + target->fill_buffer_offset;1405}14061407static void1408d3d12_set_stream_output_targets(struct pipe_context *pctx,1409unsigned num_targets,1410struct pipe_stream_output_target **targets,1411const unsigned *offsets)1412{1413struct d3d12_context *ctx = d3d12_context(pctx);14141415assert(num_targets <= ARRAY_SIZE(ctx->so_targets));14161417d3d12_disable_fake_so_buffers(ctx);14181419for (unsigned i = 0; i < PIPE_MAX_SO_BUFFERS; i++) {1420struct d3d12_stream_output_target *target =1421i < num_targets ? (struct d3d12_stream_output_target *)targets[i] : NULL;14221423if (target) {1424/* Sub-allocate a new fill buffer each time to avoid GPU/CPU synchronization */1425u_suballocator_alloc(&ctx->so_allocator, sizeof(uint64_t), 4,1426&target->fill_buffer_offset, &target->fill_buffer);1427fill_stream_output_buffer_view(&ctx->so_buffer_views[i], target);1428pipe_so_target_reference(&ctx->so_targets[i], targets[i]);1429} else {1430ctx->so_buffer_views[i].SizeInBytes = 0;1431pipe_so_target_reference(&ctx->so_targets[i], NULL);1432}1433}14341435ctx->gfx_pipeline_state.num_so_targets = num_targets;1436ctx->state_dirty |= D3D12_DIRTY_STREAM_OUTPUT;1437}14381439static void1440d3d12_invalidate_context_bindings(struct d3d12_context *ctx, struct d3d12_resource *res) {1441// For each shader type, if the resource is currently bound as CBV or SRV1442// set the context shader_dirty bit.1443for (uint i = 0; i < PIPE_SHADER_TYPES; ++i) {1444if (res->bind_counts[i][D3D12_RESOURCE_BINDING_TYPE_CBV] > 0) {1445ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_CONSTBUF;1446}14471448if (res->bind_counts[i][D3D12_RESOURCE_BINDING_TYPE_SRV] > 0) {1449ctx->shader_dirty[i] |= D3D12_SHADER_DIRTY_SAMPLER_VIEWS;1450}1451}1452}14531454bool1455d3d12_enable_fake_so_buffers(struct d3d12_context *ctx, unsigned factor)1456{1457if (ctx->fake_so_buffer_factor == factor)1458return true;14591460d3d12_disable_fake_so_buffers(ctx);14611462for (unsigned i = 0; i < ctx->gfx_pipeline_state.num_so_targets; ++i) {1463struct d3d12_stream_output_target *target = (struct d3d12_stream_output_target *)ctx->so_targets[i];1464struct d3d12_stream_output_target *fake_target;14651466fake_target = CALLOC_STRUCT(d3d12_stream_output_target);1467if (!fake_target)1468return false;1469pipe_reference_init(&fake_target->base.reference, 1);1470fake_target->base.context = &ctx->base;14711472d3d12_resource_wait_idle(ctx, d3d12_resource(target->base.buffer));14731474/* Check if another target is using the same buffer */1475for (unsigned j = 0; j < i; ++j) {1476if (ctx->so_targets[j] && ctx->so_targets[j]->buffer == target->base.buffer) {1477struct d3d12_stream_output_target *prev_target =1478(struct d3d12_stream_output_target *)ctx->fake_so_targets[j];1479pipe_resource_reference(&fake_target->base.buffer, prev_target->base.buffer);1480pipe_resource_reference(&fake_target->fill_buffer, prev_target->fill_buffer);1481fake_target->fill_buffer_offset = prev_target->fill_buffer_offset;1482fake_target->cached_filled_size = prev_target->cached_filled_size;1483break;1484}1485}14861487/* Create new SO buffer 6x (2 triangles instead of 1 point) the original size if not */1488if (!fake_target->base.buffer) {1489fake_target->base.buffer = pipe_buffer_create(ctx->base.screen,1490PIPE_BIND_STREAM_OUTPUT,1491PIPE_USAGE_STAGING,1492target->base.buffer->width0 * factor);1493u_suballocator_alloc(&ctx->so_allocator, sizeof(uint64_t), 4,1494&fake_target->fill_buffer_offset, &fake_target->fill_buffer);1495pipe_buffer_read(&ctx->base, target->fill_buffer,1496target->fill_buffer_offset, sizeof(uint64_t),1497&fake_target->cached_filled_size);1498}14991500fake_target->base.buffer_offset = target->base.buffer_offset * factor;1501fake_target->base.buffer_size = (target->base.buffer_size - fake_target->cached_filled_size) * factor;1502ctx->fake_so_targets[i] = &fake_target->base;1503fill_stream_output_buffer_view(&ctx->fake_so_buffer_views[i], fake_target);1504}15051506ctx->fake_so_buffer_factor = factor;1507ctx->cmdlist_dirty |= D3D12_DIRTY_STREAM_OUTPUT;15081509return true;1510}15111512bool1513d3d12_disable_fake_so_buffers(struct d3d12_context *ctx)1514{1515if (ctx->fake_so_buffer_factor == 0)1516return true;15171518d3d12_flush_cmdlist_and_wait(ctx);15191520for (unsigned i = 0; i < ctx->gfx_pipeline_state.num_so_targets; ++i) {1521struct d3d12_stream_output_target *target = (struct d3d12_stream_output_target *)ctx->so_targets[i];1522struct d3d12_stream_output_target *fake_target = (struct d3d12_stream_output_target *)ctx->fake_so_targets[i];1523uint64_t filled_size = 0;1524struct pipe_transfer *src_transfer, *dst_transfer;1525uint8_t *src, *dst;15261527if (fake_target == NULL)1528continue;15291530pipe_buffer_read(&ctx->base, fake_target->fill_buffer,1531fake_target->fill_buffer_offset, sizeof(uint64_t),1532&filled_size);15331534src = (uint8_t *)pipe_buffer_map_range(&ctx->base, fake_target->base.buffer,1535fake_target->base.buffer_offset,1536fake_target->base.buffer_size,1537PIPE_MAP_READ, &src_transfer);1538dst = (uint8_t *)pipe_buffer_map_range(&ctx->base, target->base.buffer,1539target->base.buffer_offset,1540target->base.buffer_size,1541PIPE_MAP_READ, &dst_transfer);15421543/* Note: This will break once support for gl_SkipComponents is added */1544uint32_t stride = ctx->gfx_pipeline_state.so_info.stride[i] * 4;1545uint64_t src_offset = 0, dst_offset = fake_target->cached_filled_size;1546while (src_offset < filled_size) {1547memcpy(dst + dst_offset, src + src_offset, stride);1548src_offset += stride * ctx->fake_so_buffer_factor;1549dst_offset += stride;1550}15511552pipe_buffer_unmap(&ctx->base, src_transfer);1553pipe_buffer_unmap(&ctx->base, dst_transfer);15541555pipe_so_target_reference(&ctx->fake_so_targets[i], NULL);1556ctx->fake_so_buffer_views[i].SizeInBytes = 0;15571558/* Make sure the buffer is not copied twice */1559for (unsigned j = i + 1; j <= ctx->gfx_pipeline_state.num_so_targets; ++j) {1560if (ctx->so_targets[j] && ctx->so_targets[j]->buffer == target->base.buffer)1561pipe_so_target_reference(&ctx->fake_so_targets[j], NULL);1562}1563}15641565ctx->fake_so_buffer_factor = 0;1566ctx->cmdlist_dirty |= D3D12_DIRTY_STREAM_OUTPUT;15671568return true;1569}15701571void1572d3d12_flush_cmdlist(struct d3d12_context *ctx)1573{1574d3d12_end_batch(ctx, d3d12_current_batch(ctx));15751576ctx->current_batch_idx++;1577if (ctx->current_batch_idx == ARRAY_SIZE(ctx->batches))1578ctx->current_batch_idx = 0;15791580d3d12_start_batch(ctx, d3d12_current_batch(ctx));1581}15821583void1584d3d12_flush_cmdlist_and_wait(struct d3d12_context *ctx)1585{1586struct d3d12_batch *batch = d3d12_current_batch(ctx);15871588d3d12_foreach_submitted_batch(ctx, old_batch)1589d3d12_reset_batch(ctx, old_batch, PIPE_TIMEOUT_INFINITE);1590d3d12_flush_cmdlist(ctx);1591d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);1592}15931594void1595d3d12_transition_resource_state(struct d3d12_context *ctx,1596struct d3d12_resource *res,1597D3D12_RESOURCE_STATES state,1598d3d12_bind_invalidate_option bind_invalidate)1599{1600TransitionableResourceState *xres = d3d12_resource_state(res);16011602if (bind_invalidate == D3D12_BIND_INVALIDATE_FULL)1603d3d12_invalidate_context_bindings(ctx, res);16041605ctx->resource_state_manager->TransitionResource(xres, state);1606}16071608void1609d3d12_transition_subresources_state(struct d3d12_context *ctx,1610struct d3d12_resource *res,1611uint32_t start_level, uint32_t num_levels,1612uint32_t start_layer, uint32_t num_layers,1613uint32_t start_plane, uint32_t num_planes,1614D3D12_RESOURCE_STATES state,1615d3d12_bind_invalidate_option bind_invalidate)1616{1617TransitionableResourceState *xres = d3d12_resource_state(res);16181619if(bind_invalidate == D3D12_BIND_INVALIDATE_FULL)1620d3d12_invalidate_context_bindings(ctx, res);16211622for (uint32_t l = 0; l < num_levels; l++) {1623const uint32_t level = start_level + l;1624for (uint32_t a = 0; a < num_layers; a++) {1625const uint32_t layer = start_layer + a;1626for( uint32_t p = 0; p < num_planes; p++) {1627const uint32_t plane = start_plane + p;1628uint32_t subres_id = level + (layer * res->mip_levels) + plane * (res->mip_levels * res->base.array_size);1629assert(subres_id < xres->NumSubresources());1630ctx->resource_state_manager->TransitionSubresource(xres, subres_id, state);1631}1632}1633}1634}16351636void1637d3d12_apply_resource_states(struct d3d12_context *ctx)1638{1639ctx->resource_state_manager->ApplyAllResourceTransitions(ctx->cmdlist, ctx->fence_value);1640}16411642static void1643d3d12_clear_render_target(struct pipe_context *pctx,1644struct pipe_surface *psurf,1645const union pipe_color_union *color,1646unsigned dstx, unsigned dsty,1647unsigned width, unsigned height,1648bool render_condition_enabled)1649{1650struct d3d12_context *ctx = d3d12_context(pctx);1651struct d3d12_surface *surf = d3d12_surface(psurf);16521653if (!render_condition_enabled && ctx->current_predication)1654ctx->cmdlist->SetPredication(NULL, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);16551656struct d3d12_resource *res = d3d12_resource(psurf->texture);1657d3d12_transition_resource_state(ctx, res,1658D3D12_RESOURCE_STATE_RENDER_TARGET,1659D3D12_BIND_INVALIDATE_FULL);1660d3d12_apply_resource_states(ctx);16611662enum pipe_format format = psurf->texture->format;1663float clear_color[4];16641665if (util_format_is_pure_uint(format)) {1666for (int c = 0; c < 4; ++c)1667clear_color[c] = color->ui[c];1668} else if (util_format_is_pure_sint(format)) {1669for (int c = 0; c < 4; ++c)1670clear_color[c] = color->i[c];1671} else {1672for (int c = 0; c < 4; ++c)1673clear_color[c] = color->f[c];1674}16751676D3D12_RECT rect = { (int)dstx, (int)dsty,1677(int)dstx + (int)width,1678(int)dsty + (int)height };1679ctx->cmdlist->ClearRenderTargetView(surf->desc_handle.cpu_handle,1680clear_color, 1, &rect);16811682d3d12_batch_reference_surface_texture(d3d12_current_batch(ctx), surf);16831684if (!render_condition_enabled && ctx->current_predication) {1685ctx->cmdlist->SetPredication(1686d3d12_resource_resource(ctx->current_predication), 0,1687D3D12_PREDICATION_OP_EQUAL_ZERO);1688}1689}16901691static void1692d3d12_clear_depth_stencil(struct pipe_context *pctx,1693struct pipe_surface *psurf,1694unsigned clear_flags,1695double depth,1696unsigned stencil,1697unsigned dstx, unsigned dsty,1698unsigned width, unsigned height,1699bool render_condition_enabled)1700{1701struct d3d12_context *ctx = d3d12_context(pctx);1702struct d3d12_surface *surf = d3d12_surface(psurf);17031704if (!render_condition_enabled && ctx->current_predication)1705ctx->cmdlist->SetPredication(NULL, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);17061707D3D12_CLEAR_FLAGS flags = (D3D12_CLEAR_FLAGS)0;1708if (clear_flags & PIPE_CLEAR_DEPTH)1709flags |= D3D12_CLEAR_FLAG_DEPTH;1710if (clear_flags & PIPE_CLEAR_STENCIL)1711flags |= D3D12_CLEAR_FLAG_STENCIL;17121713struct d3d12_resource *res = d3d12_resource(ctx->fb.zsbuf->texture);1714d3d12_transition_resource_state(ctx, res,1715D3D12_RESOURCE_STATE_DEPTH_WRITE,1716D3D12_BIND_INVALIDATE_FULL);1717d3d12_apply_resource_states(ctx);17181719D3D12_RECT rect = { (int)dstx, (int)dsty,1720(int)dstx + (int)width,1721(int)dsty + (int)height };1722ctx->cmdlist->ClearDepthStencilView(surf->desc_handle.cpu_handle, flags,1723depth, stencil, 1, &rect);17241725d3d12_batch_reference_surface_texture(d3d12_current_batch(ctx), surf);17261727if (!render_condition_enabled && ctx->current_predication) {1728ctx->cmdlist->SetPredication(1729d3d12_resource_resource(ctx->current_predication), 0,1730D3D12_PREDICATION_OP_EQUAL_ZERO);1731}1732}17331734static void1735d3d12_clear(struct pipe_context *pctx,1736unsigned buffers,1737const struct pipe_scissor_state *scissor_state,1738const union pipe_color_union *color,1739double depth, unsigned stencil)1740{1741struct d3d12_context *ctx = d3d12_context(pctx);17421743if (buffers & PIPE_CLEAR_COLOR) {1744for (int i = 0; i < ctx->fb.nr_cbufs; ++i) {1745if (buffers & (PIPE_CLEAR_COLOR0 << i)) {1746struct pipe_surface *psurf = ctx->fb.cbufs[i];1747d3d12_clear_render_target(pctx, psurf, color,17480, 0, psurf->width, psurf->height,1749true);1750}1751}1752}17531754if (buffers & PIPE_CLEAR_DEPTHSTENCIL && ctx->fb.zsbuf) {1755struct pipe_surface *psurf = ctx->fb.zsbuf;1756d3d12_clear_depth_stencil(pctx, psurf,1757buffers & PIPE_CLEAR_DEPTHSTENCIL,1758depth, stencil,17590, 0, psurf->width, psurf->height,1760true);1761}1762}17631764static void1765d3d12_flush(struct pipe_context *pipe,1766struct pipe_fence_handle **fence,1767unsigned flags)1768{1769struct d3d12_context *ctx = d3d12_context(pipe);1770struct d3d12_batch *batch = d3d12_current_batch(ctx);17711772d3d12_flush_cmdlist(ctx);17731774if (fence)1775d3d12_fence_reference((struct d3d12_fence **)fence, batch->fence);1776}17771778static void1779d3d12_flush_resource(struct pipe_context *pctx,1780struct pipe_resource *pres)1781{1782struct d3d12_context *ctx = d3d12_context(pctx);1783struct d3d12_resource *res = d3d12_resource(pres);17841785d3d12_transition_resource_state(ctx, res,1786D3D12_RESOURCE_STATE_COMMON,1787D3D12_BIND_INVALIDATE_FULL);1788d3d12_apply_resource_states(ctx);1789}17901791static void1792d3d12_init_null_sampler(struct d3d12_context *ctx)1793{1794struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);17951796d3d12_descriptor_pool_alloc_handle(ctx->sampler_pool, &ctx->null_sampler);17971798D3D12_SAMPLER_DESC desc;1799desc.Filter = D3D12_FILTER_ANISOTROPIC;1800desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;1801desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;1802desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;1803desc.MipLODBias = 0.0f;1804desc.MaxAnisotropy = 0;1805desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;1806desc.MinLOD = 0.0f;1807desc.MaxLOD = 0.0f;1808memset(desc.BorderColor, 0, sizeof(desc.BorderColor));1809screen->dev->CreateSampler(&desc, ctx->null_sampler.cpu_handle);1810}18111812static uint64_t1813d3d12_get_timestamp(struct pipe_context *pctx)1814{1815struct d3d12_context *ctx = d3d12_context(pctx);18161817if (!ctx->timestamp_query)1818ctx->timestamp_query = pctx->create_query(pctx, PIPE_QUERY_TIMESTAMP, 0);18191820pipe_query_result result;1821pctx->end_query(pctx, ctx->timestamp_query);1822pctx->get_query_result(pctx, ctx->timestamp_query, true, &result);1823return result.u64;1824}18251826struct pipe_context *1827d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)1828{1829struct d3d12_screen *screen = d3d12_screen(pscreen);18301831struct d3d12_context *ctx = CALLOC_STRUCT(d3d12_context);1832if (!ctx)1833return NULL;18341835ctx->base.screen = pscreen;1836ctx->base.priv = priv;18371838ctx->base.destroy = d3d12_context_destroy;18391840ctx->base.create_vertex_elements_state = d3d12_create_vertex_elements_state;1841ctx->base.bind_vertex_elements_state = d3d12_bind_vertex_elements_state;1842ctx->base.delete_vertex_elements_state = d3d12_delete_vertex_elements_state;18431844ctx->base.create_blend_state = d3d12_create_blend_state;1845ctx->base.bind_blend_state = d3d12_bind_blend_state;1846ctx->base.delete_blend_state = d3d12_delete_blend_state;18471848ctx->base.create_depth_stencil_alpha_state = d3d12_create_depth_stencil_alpha_state;1849ctx->base.bind_depth_stencil_alpha_state = d3d12_bind_depth_stencil_alpha_state;1850ctx->base.delete_depth_stencil_alpha_state = d3d12_delete_depth_stencil_alpha_state;18511852ctx->base.create_rasterizer_state = d3d12_create_rasterizer_state;1853ctx->base.bind_rasterizer_state = d3d12_bind_rasterizer_state;1854ctx->base.delete_rasterizer_state = d3d12_delete_rasterizer_state;18551856ctx->base.create_sampler_state = d3d12_create_sampler_state;1857ctx->base.bind_sampler_states = d3d12_bind_sampler_states;1858ctx->base.delete_sampler_state = d3d12_delete_sampler_state;18591860ctx->base.create_sampler_view = d3d12_create_sampler_view;1861ctx->base.set_sampler_views = d3d12_set_sampler_views;1862ctx->base.sampler_view_destroy = d3d12_destroy_sampler_view;18631864ctx->base.create_vs_state = d3d12_create_vs_state;1865ctx->base.bind_vs_state = d3d12_bind_vs_state;1866ctx->base.delete_vs_state = d3d12_delete_vs_state;18671868ctx->base.create_fs_state = d3d12_create_fs_state;1869ctx->base.bind_fs_state = d3d12_bind_fs_state;1870ctx->base.delete_fs_state = d3d12_delete_fs_state;18711872ctx->base.create_gs_state = d3d12_create_gs_state;1873ctx->base.bind_gs_state = d3d12_bind_gs_state;1874ctx->base.delete_gs_state = d3d12_delete_gs_state;18751876ctx->base.set_polygon_stipple = d3d12_set_polygon_stipple;1877ctx->base.set_vertex_buffers = d3d12_set_vertex_buffers;1878ctx->base.set_viewport_states = d3d12_set_viewport_states;1879ctx->base.set_scissor_states = d3d12_set_scissor_states;1880ctx->base.set_constant_buffer = d3d12_set_constant_buffer;1881ctx->base.set_framebuffer_state = d3d12_set_framebuffer_state;1882ctx->base.set_clip_state = d3d12_set_clip_state;1883ctx->base.set_blend_color = d3d12_set_blend_color;1884ctx->base.set_sample_mask = d3d12_set_sample_mask;1885ctx->base.set_stencil_ref = d3d12_set_stencil_ref;18861887ctx->base.create_stream_output_target = d3d12_create_stream_output_target;1888ctx->base.stream_output_target_destroy = d3d12_stream_output_target_destroy;1889ctx->base.set_stream_output_targets = d3d12_set_stream_output_targets;18901891ctx->base.get_timestamp = d3d12_get_timestamp;18921893ctx->base.clear = d3d12_clear;1894ctx->base.clear_render_target = d3d12_clear_render_target;1895ctx->base.clear_depth_stencil = d3d12_clear_depth_stencil;1896ctx->base.draw_vbo = d3d12_draw_vbo;1897ctx->base.flush = d3d12_flush;1898ctx->base.flush_resource = d3d12_flush_resource;18991900ctx->gfx_pipeline_state.sample_mask = ~0;19011902d3d12_context_surface_init(&ctx->base);1903d3d12_context_resource_init(&ctx->base);1904d3d12_context_query_init(&ctx->base);1905d3d12_context_blit_init(&ctx->base);190619071908slab_create_child(&ctx->transfer_pool, &d3d12_screen(pscreen)->transfer_pool);19091910ctx->base.stream_uploader = u_upload_create_default(&ctx->base);1911ctx->base.const_uploader = u_upload_create_default(&ctx->base);1912u_suballocator_init(&ctx->so_allocator, &ctx->base, 4096, 0,1913PIPE_USAGE_DEFAULT,19140, true);19151916struct primconvert_config cfg;1917cfg.primtypes_mask = 1 << PIPE_PRIM_POINTS |19181 << PIPE_PRIM_LINES |19191 << PIPE_PRIM_LINE_STRIP |19201 << PIPE_PRIM_TRIANGLES |19211 << PIPE_PRIM_TRIANGLE_STRIP;1922cfg.fixed_prim_restart = true;1923ctx->primconvert = util_primconvert_create_config(&ctx->base, &cfg);1924if (!ctx->primconvert) {1925debug_printf("D3D12: failed to create primconvert\n");1926return NULL;1927}19281929d3d12_gfx_pipeline_state_cache_init(ctx);1930d3d12_root_signature_cache_init(ctx);1931d3d12_gs_variant_cache_init(ctx);19321933util_dl_library *d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);1934if (!d3d12_mod) {1935debug_printf("D3D12: failed to load D3D12.DLL\n");1936return NULL;1937}1938ctx->D3D12SerializeVersionedRootSignature =1939(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)util_dl_get_proc_address(d3d12_mod, "D3D12SerializeVersionedRootSignature");19401941if (FAILED(screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE,1942IID_PPV_ARGS(&ctx->cmdqueue_fence)))) {1943FREE(ctx);1944return NULL;1945}19461947for (unsigned i = 0; i < ARRAY_SIZE(ctx->batches); ++i) {1948if (!d3d12_init_batch(ctx, &ctx->batches[i])) {1949FREE(ctx);1950return NULL;1951}1952}1953d3d12_start_batch(ctx, &ctx->batches[0]);19541955ctx->sampler_pool = d3d12_descriptor_pool_new(screen,1956D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,195764);1958if (!ctx->sampler_pool) {1959FREE(ctx);1960return NULL;1961}1962d3d12_init_null_sampler(ctx);19631964ctx->validation_tools = d3d12_validator_create();19651966ctx->blitter = util_blitter_create(&ctx->base);1967if (!ctx->blitter)1968return NULL;19691970ctx->resource_state_manager = new ResourceStateManager();19711972if (!d3d12_init_polygon_stipple(&ctx->base)) {1973debug_printf("D3D12: failed to initialize polygon stipple resources\n");1974FREE(ctx);1975return NULL;1976}19771978return &ctx->base;1979}19801981bool1982d3d12_need_zero_one_depth_range(struct d3d12_context *ctx)1983{1984struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];19851986/**1987* OpenGL Compatibility spec, section 15.2.3 (Shader Outputs) says1988* the following:1989*1990* For fixed-point depth buffers, the final fragment depth written by1991* a fragment shader is first clamped to [0, 1] and then converted to1992* fixed-point as if it were a window z value (see section 13.8.1).1993* For floating-point depth buffers, conversion is not performed but1994* clamping is. Note that the depth range computation is not applied1995* here, only the conversion to fixed-point.1996*1997* However, the D3D11.3 Functional Spec, section 17.10 (Depth Clamp) says1998* the following:1999*2000* Depth values that reach the Output Merger, whether coming from2001* interpolation or from Pixel Shader output (replacing the2002* interpolated z), are always clamped:2003* z = min(Viewport.MaxDepth,max(Viewport.MinDepth,z))2004* following the D3D11 Floating Point Rules(3.1) for min/max.2005*2006* This means that we can't always use the fixed-function viewport-mapping2007* D3D provides.2008*2009* There's only one case where the difference matters: When the fragment2010* shader writes a non-implicit value to gl_FragDepth. In all other2011* cases, the fragment either shouldn't have been rasterized in the2012* first place, or the implicit gl_FragCoord.z-value should already have2013* been clamped to the depth-range.2014*2015* For simplicity, let's assume that an explicitly written frag-result2016* doesn't simply forward the value of gl_FragCoord.z. If it does, we'll2017* end up generating needless code, but the result will be correct.2018*/20192020return fs->initial->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH);2021}202220232024