Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_pipeline_state.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_pipeline_state.h"24#include "d3d12_compiler.h"25#include "d3d12_context.h"26#include "d3d12_screen.h"2728#include "util/hash_table.h"29#include "util/set.h"30#include "util/u_memory.h"31#include "util/u_prim.h"3233#include <dxguids/dxguids.h>3435struct d3d12_pso_entry {36struct d3d12_gfx_pipeline_state key;37ID3D12PipelineState *pso;38};3940static const char *41get_semantic_name(int slot, unsigned *index)42{43*index = 0; /* Default index */4445switch (slot) {4647case VARYING_SLOT_POS:48return "SV_Position";4950case VARYING_SLOT_FACE:51return "SV_IsFrontFace";5253case VARYING_SLOT_CLIP_DIST1:54*index = 1;55FALLTHROUGH;56case VARYING_SLOT_CLIP_DIST0:57return "SV_ClipDistance";5859case VARYING_SLOT_PRIMITIVE_ID:60return "SV_PrimitiveID";6162default: {63*index = slot - VARYING_SLOT_POS;64return "TEXCOORD";65}66}67}6869static void70fill_so_declaration(const struct pipe_stream_output_info *info,71D3D12_SO_DECLARATION_ENTRY *entries, UINT *num_entries,72UINT *strides, UINT *num_strides)73{74int next_offset[MAX_VERTEX_STREAMS] = { 0 };7576*num_entries = 0;7778for (unsigned i = 0; i < info->num_outputs; i++) {79const struct pipe_stream_output *output = &info->output[i];80const int buffer = output->output_buffer;81unsigned index;8283/* Mesa doesn't store entries for gl_SkipComponents in the Outputs[]84* array. Instead, it simply increments DstOffset for the following85* input by the number of components that should be skipped.86*87* DirectX12 requires that we create gap entries.88*/89int skip_components = output->dst_offset - next_offset[buffer];9091if (skip_components > 0) {92entries[*num_entries].Stream = output->stream;93entries[*num_entries].SemanticName = NULL;94entries[*num_entries].ComponentCount = skip_components;95entries[*num_entries].OutputSlot = buffer;96(*num_entries)++;97}9899next_offset[buffer] = output->dst_offset + output->num_components;100101entries[*num_entries].Stream = output->stream;102entries[*num_entries].SemanticName = get_semantic_name(output->register_index, &index);103entries[*num_entries].SemanticIndex = index;104entries[*num_entries].StartComponent = output->start_component;105entries[*num_entries].ComponentCount = output->num_components;106entries[*num_entries].OutputSlot = buffer;107(*num_entries)++;108}109110for (unsigned i = 0; i < MAX_VERTEX_STREAMS; i++)111strides[i] = info->stride[i] * 4;112*num_strides = MAX_VERTEX_STREAMS;113}114115static bool116depth_bias(struct d3d12_rasterizer_state *state, enum pipe_prim_type reduced_prim)117{118/* glPolygonOffset is supposed to be only enabled when rendering polygons.119* In d3d12 case, all polygons (and quads) are lowered to triangles */120if (reduced_prim != PIPE_PRIM_TRIANGLES)121return false;122123unsigned fill_mode = state->base.cull_face == PIPE_FACE_FRONT ? state->base.fill_back124: state->base.fill_front;125126switch (fill_mode) {127case PIPE_POLYGON_MODE_FILL:128return state->base.offset_tri;129130case PIPE_POLYGON_MODE_LINE:131return state->base.offset_line;132133case PIPE_POLYGON_MODE_POINT:134return state->base.offset_point;135136default:137unreachable("unexpected fill mode");138}139}140141static D3D12_PRIMITIVE_TOPOLOGY_TYPE142topology_type(enum pipe_prim_type reduced_prim)143{144switch (reduced_prim) {145case PIPE_PRIM_POINTS:146return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;147148case PIPE_PRIM_LINES:149return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;150151case PIPE_PRIM_TRIANGLES:152return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;153154case PIPE_PRIM_PATCHES:155return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;156157default:158debug_printf("pipe_prim_type: %s\n", u_prim_name(reduced_prim));159unreachable("unexpected enum pipe_prim_type");160}161}162163DXGI_FORMAT164d3d12_rtv_format(struct d3d12_context *ctx, unsigned index)165{166DXGI_FORMAT fmt = ctx->gfx_pipeline_state.rtv_formats[index];167168if (ctx->gfx_pipeline_state.blend->desc.RenderTarget[0].LogicOpEnable &&169!ctx->gfx_pipeline_state.has_float_rtv) {170switch (fmt) {171case DXGI_FORMAT_R8G8B8A8_SNORM:172case DXGI_FORMAT_R8G8B8A8_UNORM:173case DXGI_FORMAT_B8G8R8A8_UNORM:174case DXGI_FORMAT_B8G8R8X8_UNORM:175return DXGI_FORMAT_R8G8B8A8_UINT;176default:177unreachable("unsupported logic-op format");178}179}180181return fmt;182}183184static ID3D12PipelineState *185create_gfx_pipeline_state(struct d3d12_context *ctx)186{187struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);188struct d3d12_gfx_pipeline_state *state = &ctx->gfx_pipeline_state;189enum pipe_prim_type reduced_prim = u_reduced_prim(state->prim_type);190D3D12_SO_DECLARATION_ENTRY entries[PIPE_MAX_SO_OUTPUTS] = {};191UINT strides[PIPE_MAX_SO_OUTPUTS] = { 0 };192UINT num_entries = 0, num_strides = 0;193194D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { 0 };195pso_desc.pRootSignature = state->root_signature;196197bool last_vertex_stage_writes_pos = false;198199if (state->stages[PIPE_SHADER_VERTEX]) {200auto shader = state->stages[PIPE_SHADER_VERTEX];201pso_desc.VS.BytecodeLength = shader->bytecode_length;202pso_desc.VS.pShaderBytecode = shader->bytecode;203last_vertex_stage_writes_pos = (shader->nir->info.outputs_written & VARYING_BIT_POS) != 0;204}205206if (state->stages[PIPE_SHADER_GEOMETRY]) {207auto shader = state->stages[PIPE_SHADER_GEOMETRY];208pso_desc.GS.BytecodeLength = shader->bytecode_length;209pso_desc.GS.pShaderBytecode = shader->bytecode;210last_vertex_stage_writes_pos = (shader->nir->info.outputs_written & VARYING_BIT_POS) != 0;211}212213if (last_vertex_stage_writes_pos && state->stages[PIPE_SHADER_FRAGMENT] &&214!state->rast->base.rasterizer_discard) {215auto shader = state->stages[PIPE_SHADER_FRAGMENT];216pso_desc.PS.BytecodeLength = shader->bytecode_length;217pso_desc.PS.pShaderBytecode = shader->bytecode;218}219220if (state->num_so_targets)221fill_so_declaration(&state->so_info, entries, &num_entries,222strides, &num_strides);223pso_desc.StreamOutput.NumEntries = num_entries;224pso_desc.StreamOutput.pSODeclaration = entries;225pso_desc.StreamOutput.RasterizedStream = state->rast->base.rasterizer_discard ? D3D12_SO_NO_RASTERIZED_STREAM : 0;226pso_desc.StreamOutput.NumStrides = num_strides;227pso_desc.StreamOutput.pBufferStrides = strides;228229pso_desc.BlendState = state->blend->desc;230if (state->has_float_rtv)231pso_desc.BlendState.RenderTarget[0].LogicOpEnable = FALSE;232233pso_desc.DepthStencilState = state->zsa->desc;234pso_desc.SampleMask = state->sample_mask;235pso_desc.RasterizerState = state->rast->desc;236237if (reduced_prim != PIPE_PRIM_TRIANGLES)238pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;239240if (depth_bias(state->rast, reduced_prim)) {241pso_desc.RasterizerState.DepthBias = state->rast->base.offset_units * 2;242pso_desc.RasterizerState.DepthBiasClamp = state->rast->base.offset_clamp;243pso_desc.RasterizerState.SlopeScaledDepthBias = state->rast->base.offset_scale;244}245246pso_desc.InputLayout.pInputElementDescs = state->ves->elements;247pso_desc.InputLayout.NumElements = state->ves->num_elements;248249pso_desc.IBStripCutValue = state->ib_strip_cut_value;250251pso_desc.PrimitiveTopologyType = topology_type(reduced_prim);252253pso_desc.NumRenderTargets = state->num_cbufs;254for (unsigned i = 0; i < state->num_cbufs; ++i)255pso_desc.RTVFormats[i] = d3d12_rtv_format(ctx, i);256pso_desc.DSVFormat = state->dsv_format;257258pso_desc.SampleDesc.Count = state->samples;259pso_desc.SampleDesc.Quality = 0;260261pso_desc.NodeMask = 0;262263pso_desc.CachedPSO.pCachedBlob = NULL;264pso_desc.CachedPSO.CachedBlobSizeInBytes = 0;265266pso_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;267268ID3D12PipelineState *ret;269if (FAILED(screen->dev->CreateGraphicsPipelineState(&pso_desc,270IID_PPV_ARGS(&ret)))) {271debug_printf("D3D12: CreateGraphicsPipelineState failed!\n");272return NULL;273}274275return ret;276}277278static uint32_t279hash_gfx_pipeline_state(const void *key)280{281return _mesa_hash_data(key, sizeof(struct d3d12_gfx_pipeline_state));282}283284static bool285equals_gfx_pipeline_state(const void *a, const void *b)286{287return memcmp(a, b, sizeof(struct d3d12_gfx_pipeline_state)) == 0;288}289290ID3D12PipelineState *291d3d12_get_gfx_pipeline_state(struct d3d12_context *ctx)292{293uint32_t hash = hash_gfx_pipeline_state(&ctx->gfx_pipeline_state);294struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->pso_cache, hash,295&ctx->gfx_pipeline_state);296if (!entry) {297struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)MALLOC(sizeof(struct d3d12_pso_entry));298if (!data)299return NULL;300301data->key = ctx->gfx_pipeline_state;302data->pso = create_gfx_pipeline_state(ctx);303if (!data->pso) {304FREE(data);305return NULL;306}307308entry = _mesa_hash_table_insert_pre_hashed(ctx->pso_cache, hash, &data->key, data);309assert(entry);310}311312return ((struct d3d12_pso_entry *)(entry->data))->pso;313}314315void316d3d12_gfx_pipeline_state_cache_init(struct d3d12_context *ctx)317{318ctx->pso_cache = _mesa_hash_table_create(NULL, NULL, equals_gfx_pipeline_state);319}320321static void322delete_entry(struct hash_entry *entry)323{324struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)entry->data;325data->pso->Release();326FREE(data);327}328329static void330remove_entry(struct d3d12_context *ctx, struct hash_entry *entry)331{332struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)entry->data;333334if (ctx->current_pso == data->pso)335ctx->current_pso = NULL;336_mesa_hash_table_remove(ctx->pso_cache, entry);337delete_entry(entry);338}339340void341d3d12_gfx_pipeline_state_cache_destroy(struct d3d12_context *ctx)342{343_mesa_hash_table_destroy(ctx->pso_cache, delete_entry);344}345346void347d3d12_gfx_pipeline_state_cache_invalidate(struct d3d12_context *ctx, const void *state)348{349hash_table_foreach(ctx->pso_cache, entry) {350const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;351if (key->blend == state || key->zsa == state || key->rast == state)352remove_entry(ctx, entry);353}354}355356void357d3d12_gfx_pipeline_state_cache_invalidate_shader(struct d3d12_context *ctx,358enum pipe_shader_type stage,359struct d3d12_shader_selector *selector)360{361struct d3d12_shader *shader = selector->first;362363while (shader) {364hash_table_foreach(ctx->pso_cache, entry) {365const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;366if (key->stages[stage] == shader)367remove_entry(ctx, entry);368}369shader = shader->next_variant;370}371}372373374