Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_compiler.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_compiler.h"24#include "d3d12_context.h"25#include "d3d12_debug.h"26#include "d3d12_screen.h"27#include "d3d12_nir_passes.h"28#include "nir_to_dxil.h"29#include "dxil_nir.h"3031#include "pipe/p_state.h"3233#include "nir.h"34#include "nir/nir_draw_helpers.h"35#include "nir/tgsi_to_nir.h"36#include "compiler/nir/nir_builder.h"37#include "tgsi/tgsi_from_mesa.h"38#include "tgsi/tgsi_ureg.h"3940#include "util/u_memory.h"41#include "util/u_prim.h"42#include "util/u_simple_shaders.h"43#include "util/u_dl.h"4445#include <directx/d3d12.h>46#include <dxguids/dxguids.h>4748#include <dxcapi.h>49#include <wrl/client.h>5051extern "C" {52#include "tgsi/tgsi_parse.h"53#include "tgsi/tgsi_point_sprite.h"54}5556using Microsoft::WRL::ComPtr;5758struct d3d12_validation_tools59{60d3d12_validation_tools();6162bool validate_and_sign(struct blob *dxil);6364void disassemble(struct blob *dxil);6566void load_dxil_dll();6768struct HModule {69HModule();70~HModule();7172bool load(LPCSTR file_name);73operator util_dl_library *() const;74private:75util_dl_library *module;76};7778HModule dxil_module;79HModule dxc_compiler_module;80ComPtr<IDxcCompiler> compiler;81ComPtr<IDxcValidator> validator;82ComPtr<IDxcLibrary> library;83};8485struct d3d12_validation_tools *d3d12_validator_create()86{87d3d12_validation_tools *tools = new d3d12_validation_tools();88if (tools->validator)89return tools;90delete tools;91return nullptr;92}9394void d3d12_validator_destroy(struct d3d12_validation_tools *validator)95{96delete validator;97}9899100const void *101d3d12_get_compiler_options(struct pipe_screen *screen,102enum pipe_shader_ir ir,103enum pipe_shader_type shader)104{105assert(ir == PIPE_SHADER_IR_NIR);106return dxil_get_nir_compiler_options();107}108109static uint32_t110resource_dimension(enum glsl_sampler_dim dim)111{112switch (dim) {113case GLSL_SAMPLER_DIM_1D:114return RESOURCE_DIMENSION_TEXTURE1D;115case GLSL_SAMPLER_DIM_2D:116return RESOURCE_DIMENSION_TEXTURE2D;117case GLSL_SAMPLER_DIM_3D:118return RESOURCE_DIMENSION_TEXTURE3D;119case GLSL_SAMPLER_DIM_CUBE:120return RESOURCE_DIMENSION_TEXTURECUBE;121default:122return RESOURCE_DIMENSION_UNKNOWN;123}124}125126static struct d3d12_shader *127compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,128struct d3d12_shader_key *key, struct nir_shader *nir)129{130struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);131struct d3d12_shader *shader = rzalloc(sel, d3d12_shader);132shader->key = *key;133shader->nir = nir;134sel->current = shader;135136NIR_PASS_V(nir, nir_lower_samplers);137NIR_PASS_V(nir, dxil_nir_create_bare_samplers);138139if (key->samples_int_textures)140NIR_PASS_V(nir, dxil_lower_sample_to_txf_for_integer_tex,141key->tex_wrap_states, key->swizzle_state,142screen->base.get_paramf(&screen->base, PIPE_CAPF_MAX_TEXTURE_LOD_BIAS));143144if (key->vs.needs_format_emulation)145d3d12_nir_lower_vs_vertex_conversion(nir, key->vs.format_conversion);146147uint32_t num_ubos_before_lower_to_ubo = nir->info.num_ubos;148uint32_t num_uniforms_before_lower_to_ubo = nir->num_uniforms;149NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, false, false);150shader->has_default_ubo0 = num_uniforms_before_lower_to_ubo > 0 &&151nir->info.num_ubos > num_ubos_before_lower_to_ubo;152153if (key->last_vertex_processing_stage) {154if (key->invert_depth)155NIR_PASS_V(nir, d3d12_nir_invert_depth);156NIR_PASS_V(nir, nir_lower_clip_halfz);157NIR_PASS_V(nir, d3d12_lower_yflip);158}159NIR_PASS_V(nir, nir_lower_packed_ubo_loads);160NIR_PASS_V(nir, d3d12_lower_load_first_vertex);161NIR_PASS_V(nir, d3d12_lower_state_vars, shader);162NIR_PASS_V(nir, d3d12_lower_bool_input);163164struct nir_to_dxil_options opts = {};165opts.interpolate_at_vertex = screen->have_load_at_vertex;166opts.lower_int16 = !screen->opts4.Native16BitShaderOpsSupported;167opts.ubo_binding_offset = shader->has_default_ubo0 ? 0 : 1;168opts.provoking_vertex = key->fs.provoking_vertex;169170struct blob tmp;171if (!nir_to_dxil(nir, &opts, &tmp)) {172debug_printf("D3D12: nir_to_dxil failed\n");173return NULL;174}175176// Non-ubo variables177shader->begin_srv_binding = (UINT_MAX);178nir_foreach_variable_with_modes(var, nir, nir_var_uniform) {179auto type = glsl_without_array(var->type);180if (glsl_type_is_sampler(type) && glsl_get_sampler_result_type(type) != GLSL_TYPE_VOID) {181unsigned count = glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;182for (unsigned i = 0; i < count; ++i) {183shader->srv_bindings[var->data.binding + i].binding = var->data.binding;184shader->srv_bindings[var->data.binding + i].dimension = resource_dimension(glsl_get_sampler_dim(type));185}186shader->begin_srv_binding = MIN2(var->data.binding, shader->begin_srv_binding);187shader->end_srv_binding = MAX2(var->data.binding + count, shader->end_srv_binding);188}189}190191// Ubo variables192if(nir->info.num_ubos) {193// Ignore state_vars ubo as it is bound as root constants194unsigned num_ubo_bindings = nir->info.num_ubos - (shader->state_vars_used ? 1 : 0);195for(unsigned i = opts.ubo_binding_offset; i < num_ubo_bindings; ++i) {196shader->cb_bindings[shader->num_cb_bindings++].binding = i;197}198}199if (ctx->validation_tools) {200ctx->validation_tools->validate_and_sign(&tmp);201202if (d3d12_debug & D3D12_DEBUG_DISASS) {203ctx->validation_tools->disassemble(&tmp);204}205}206207blob_finish_get_buffer(&tmp, &shader->bytecode, &shader->bytecode_length);208209if (d3d12_debug & D3D12_DEBUG_DXIL) {210char buf[256];211static int i;212snprintf(buf, sizeof(buf), "dump%02d.dxil", i++);213FILE *fp = fopen(buf, "wb");214fwrite(shader->bytecode, sizeof(char), shader->bytecode_length, fp);215fclose(fp);216fprintf(stderr, "wrote '%s'...\n", buf);217}218return shader;219}220221struct d3d12_selection_context {222struct d3d12_context *ctx;223const struct pipe_draw_info *dinfo;224bool needs_point_sprite_lowering;225bool needs_vertex_reordering;226unsigned provoking_vertex;227bool alternate_tri;228unsigned fill_mode_lowered;229unsigned cull_mode_lowered;230bool manual_depth_range;231unsigned missing_dual_src_outputs;232unsigned frag_result_color_lowering;233};234235static unsigned236missing_dual_src_outputs(struct d3d12_context *ctx)237{238if (!ctx->gfx_pipeline_state.blend->is_dual_src)239return 0;240241struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];242nir_shader *s = fs->initial;243244unsigned indices_seen = 0;245nir_foreach_function(function, s) {246if (function->impl) {247nir_foreach_block(block, function->impl) {248nir_foreach_instr(instr, block) {249if (instr->type != nir_instr_type_intrinsic)250continue;251252nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);253if (intr->intrinsic != nir_intrinsic_store_deref)254continue;255256nir_variable *var = nir_intrinsic_get_var(intr, 0);257if (var->data.mode != nir_var_shader_out ||258(var->data.location != FRAG_RESULT_COLOR &&259var->data.location != FRAG_RESULT_DATA0))260continue;261262indices_seen |= 1u << var->data.index;263if ((indices_seen & 3) == 3)264return 0;265}266}267}268}269270return 3 & ~indices_seen;271}272273static unsigned274frag_result_color_lowering(struct d3d12_context *ctx)275{276struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];277assert(fs);278279if (fs->initial->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_COLOR))280return ctx->fb.nr_cbufs > 1 ? ctx->fb.nr_cbufs : 0;281282return 0;283}284285static bool286manual_depth_range(struct d3d12_context *ctx)287{288if (!d3d12_need_zero_one_depth_range(ctx))289return false;290291/**292* If we can't use the D3D12 zero-one depth-range, we might have to apply293* depth-range ourselves.294*295* Because we only need to override the depth-range to zero-one range in296* the case where we write frag-depth, we only need to apply manual297* depth-range to gl_FragCoord.z.298*299* No extra care is needed to be taken in the case where gl_FragDepth is300* written conditionally, because the GLSL 4.60 spec states:301*302* If a shader statically assigns a value to gl_FragDepth, and there303* is an execution path through the shader that does not set304* gl_FragDepth, then the value of the fragment’s depth may be305* undefined for executions of the shader that take that path. That306* is, if the set of linked fragment shaders statically contain a307* write to gl_FragDepth, then it is responsible for always writing308* it.309*/310311struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];312return fs && fs->initial->info.inputs_read & VARYING_BIT_POS;313}314315static bool316needs_edge_flag_fix(enum pipe_prim_type mode)317{318return (mode == PIPE_PRIM_QUADS ||319mode == PIPE_PRIM_QUAD_STRIP ||320mode == PIPE_PRIM_POLYGON);321}322323static unsigned324fill_mode_lowered(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)325{326struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];327328if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&329!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant) ||330ctx->gfx_pipeline_state.rast == NULL ||331(dinfo->mode != PIPE_PRIM_TRIANGLES &&332dinfo->mode != PIPE_PRIM_TRIANGLE_STRIP))333return PIPE_POLYGON_MODE_FILL;334335/* D3D12 supports line mode (wireframe) but doesn't support edge flags */336if (((ctx->gfx_pipeline_state.rast->base.fill_front == PIPE_POLYGON_MODE_LINE &&337ctx->gfx_pipeline_state.rast->base.cull_face != PIPE_FACE_FRONT) ||338(ctx->gfx_pipeline_state.rast->base.fill_back == PIPE_POLYGON_MODE_LINE &&339ctx->gfx_pipeline_state.rast->base.cull_face == PIPE_FACE_FRONT)) &&340(vs->initial->info.outputs_written & VARYING_BIT_EDGE ||341needs_edge_flag_fix(ctx->initial_api_prim)))342return PIPE_POLYGON_MODE_LINE;343344if (ctx->gfx_pipeline_state.rast->base.fill_front == PIPE_POLYGON_MODE_POINT)345return PIPE_POLYGON_MODE_POINT;346347return PIPE_POLYGON_MODE_FILL;348}349350static bool351needs_point_sprite_lowering(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)352{353struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];354struct d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];355356if (gs != NULL && !gs->is_gs_variant) {357/* There is an user GS; Check if it outputs points with PSIZE */358return (gs->initial->info.gs.output_primitive == GL_POINTS &&359gs->initial->info.outputs_written & VARYING_BIT_PSIZ);360} else {361/* No user GS; check if we are drawing wide points */362return ((dinfo->mode == PIPE_PRIM_POINTS ||363fill_mode_lowered(ctx, dinfo) == PIPE_POLYGON_MODE_POINT) &&364(ctx->gfx_pipeline_state.rast->base.point_size > 1.0 ||365ctx->gfx_pipeline_state.rast->base.offset_point ||366(ctx->gfx_pipeline_state.rast->base.point_size_per_vertex &&367vs->initial->info.outputs_written & VARYING_BIT_PSIZ)) &&368(vs->initial->info.outputs_written & VARYING_BIT_POS));369}370}371372static unsigned373cull_mode_lowered(struct d3d12_context *ctx, unsigned fill_mode)374{375if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&376!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant) ||377ctx->gfx_pipeline_state.rast == NULL ||378ctx->gfx_pipeline_state.rast->base.cull_face == PIPE_FACE_NONE)379return PIPE_FACE_NONE;380381return ctx->gfx_pipeline_state.rast->base.cull_face;382}383384static unsigned385get_provoking_vertex(struct d3d12_selection_context *sel_ctx, bool *alternate)386{387struct d3d12_shader_selector *vs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_VERTEX];388struct d3d12_shader_selector *gs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY];389struct d3d12_shader_selector *last_vertex_stage = gs && !gs->is_gs_variant ? gs : vs;390391/* Make sure GL prims match Gallium prims */392STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);393STATIC_ASSERT(GL_LINES == PIPE_PRIM_LINES);394STATIC_ASSERT(GL_LINE_STRIP == PIPE_PRIM_LINE_STRIP);395396enum pipe_prim_type mode;397switch (last_vertex_stage->stage) {398case PIPE_SHADER_GEOMETRY:399mode = (enum pipe_prim_type)last_vertex_stage->current->nir->info.gs.output_primitive;400break;401case PIPE_SHADER_VERTEX:402mode = sel_ctx->dinfo ? sel_ctx->dinfo->mode : PIPE_PRIM_TRIANGLES;403break;404default:405unreachable("Tesselation shaders are not supported");406}407408bool flatshade_first = sel_ctx->ctx->gfx_pipeline_state.rast &&409sel_ctx->ctx->gfx_pipeline_state.rast->base.flatshade_first;410*alternate = (mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_STRIP_ADJACENCY) &&411(!gs || gs->is_gs_variant ||412gs->initial->info.gs.vertices_out > u_prim_vertex_count(mode)->min);413return flatshade_first ? 0 : u_prim_vertex_count(mode)->min - 1;414}415416static bool417has_flat_varyings(struct d3d12_context *ctx)418{419struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];420421if (!fs || !fs->current)422return false;423424nir_foreach_variable_with_modes(input, fs->current->nir,425nir_var_shader_in) {426if (input->data.interpolation == INTERP_MODE_FLAT)427return true;428}429430return false;431}432433static bool434needs_vertex_reordering(struct d3d12_selection_context *sel_ctx)435{436struct d3d12_context *ctx = sel_ctx->ctx;437bool flat = has_flat_varyings(ctx);438bool xfb = ctx->gfx_pipeline_state.num_so_targets > 0;439440if (fill_mode_lowered(ctx, sel_ctx->dinfo) != PIPE_POLYGON_MODE_FILL)441return false;442443/* TODO add support for line primitives */444445/* When flat shading a triangle and provoking vertex is not the first one, we use load_at_vertex.446If not available for this adapter, or if it's a triangle strip, we need to reorder the vertices */447if (flat && sel_ctx->provoking_vertex >= 2 && (!d3d12_screen(ctx->base.screen)->have_load_at_vertex ||448sel_ctx->alternate_tri))449return true;450451/* When transform feedback is enabled and the output is alternating (triangle strip or triangle452strip with adjacency), we need to reorder vertices to get the order expected by OpenGL. This453only works when there is no flat shading involved. In that scenario, we don't care about454the provoking vertex. */455if (xfb && !flat && sel_ctx->alternate_tri) {456sel_ctx->provoking_vertex = 0;457return true;458}459460return false;461}462463static nir_variable *464create_varying_from_info(nir_shader *nir, struct d3d12_varying_info *info,465unsigned slot, nir_variable_mode mode)466{467nir_variable *var;468char tmp[100];469470snprintf(tmp, ARRAY_SIZE(tmp),471mode == nir_var_shader_in ? "in_%d" : "out_%d",472info->vars[slot].driver_location);473var = nir_variable_create(nir, mode, info->vars[slot].type, tmp);474var->data.location = slot;475var->data.driver_location = info->vars[slot].driver_location;476var->data.interpolation = info->vars[slot].interpolation;477478return var;479}480481static void482fill_varyings(struct d3d12_varying_info *info, nir_shader *s,483nir_variable_mode modes, uint64_t mask)484{485nir_foreach_variable_with_modes(var, s, modes) {486unsigned slot = var->data.location;487uint64_t slot_bit = BITFIELD64_BIT(slot);488489if (!(mask & slot_bit))490continue;491info->vars[slot].driver_location = var->data.driver_location;492info->vars[slot].type = var->type;493info->vars[slot].interpolation = var->data.interpolation;494info->mask |= slot_bit;495}496}497498static void499fill_flat_varyings(struct d3d12_gs_variant_key *key, d3d12_shader_selector *fs)500{501if (!fs || !fs->current)502return;503504nir_foreach_variable_with_modes(input, fs->current->nir,505nir_var_shader_in) {506if (input->data.interpolation == INTERP_MODE_FLAT)507key->flat_varyings |= BITFIELD64_BIT(input->data.location);508}509}510511static void512validate_geometry_shader_variant(struct d3d12_selection_context *sel_ctx)513{514struct d3d12_context *ctx = sel_ctx->ctx;515d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];516d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];517struct d3d12_gs_variant_key key = {0};518bool variant_needed = false;519520d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];521522/* Nothing to do if there is a user geometry shader bound */523if (gs != NULL && !gs->is_gs_variant)524return;525526/* Fill the geometry shader variant key */527if (sel_ctx->fill_mode_lowered != PIPE_POLYGON_MODE_FILL) {528key.fill_mode = sel_ctx->fill_mode_lowered;529key.cull_mode = sel_ctx->cull_mode_lowered;530key.has_front_face = BITSET_TEST(fs->initial->info.system_values_read, SYSTEM_VALUE_FRONT_FACE);531if (key.cull_mode != PIPE_FACE_NONE || key.has_front_face)532key.front_ccw = ctx->gfx_pipeline_state.rast->base.front_ccw ^ (ctx->flip_y < 0);533key.edge_flag_fix = needs_edge_flag_fix(ctx->initial_api_prim);534fill_flat_varyings(&key, fs);535if (key.flat_varyings != 0)536key.flatshade_first = ctx->gfx_pipeline_state.rast->base.flatshade_first;537variant_needed = true;538} else if (sel_ctx->needs_point_sprite_lowering) {539key.passthrough = true;540variant_needed = true;541} else if (sel_ctx->needs_vertex_reordering) {542/* TODO support cases where flat shading (pv != 0) and xfb are enabled */543key.provoking_vertex = sel_ctx->provoking_vertex;544key.alternate_tri = sel_ctx->alternate_tri;545variant_needed = true;546}547548if (variant_needed) {549fill_varyings(&key.varyings, vs->initial, nir_var_shader_out,550vs->initial->info.outputs_written);551}552553/* Check if the currently bound geometry shader variant is correct */554if (gs && memcmp(&gs->gs_key, &key, sizeof(key)) == 0)555return;556557/* Find/create the proper variant and bind it */558gs = variant_needed ? d3d12_get_gs_variant(ctx, &key) : NULL;559ctx->gfx_stages[PIPE_SHADER_GEOMETRY] = gs;560}561562static bool563d3d12_compare_shader_keys(const d3d12_shader_key *expect, const d3d12_shader_key *have)564{565assert(expect->stage == have->stage);566assert(expect);567assert(have);568569/* Because we only add varyings we check that a shader has at least the expected in-570* and outputs. */571if (memcmp(&expect->required_varying_inputs, &have->required_varying_inputs,572sizeof(struct d3d12_varying_info)) ||573memcmp(&expect->required_varying_outputs, &have->required_varying_outputs,574sizeof(struct d3d12_varying_info)) ||575(expect->next_varying_inputs != have->next_varying_inputs) ||576(expect->prev_varying_outputs != have->prev_varying_outputs))577return false;578579if (expect->stage == PIPE_SHADER_GEOMETRY) {580if (expect->gs.writes_psize) {581if (!have->gs.writes_psize ||582expect->gs.point_pos_stream_out != have->gs.point_pos_stream_out ||583expect->gs.sprite_coord_enable != have->gs.sprite_coord_enable ||584expect->gs.sprite_origin_upper_left != have->gs.sprite_origin_upper_left ||585expect->gs.point_size_per_vertex != have->gs.point_size_per_vertex)586return false;587} else if (have->gs.writes_psize) {588return false;589}590if (expect->gs.primitive_id != have->gs.primitive_id ||591expect->gs.triangle_strip != have->gs.triangle_strip)592return false;593} else if (expect->stage == PIPE_SHADER_FRAGMENT) {594if (expect->fs.frag_result_color_lowering != have->fs.frag_result_color_lowering ||595expect->fs.manual_depth_range != have->fs.manual_depth_range ||596expect->fs.polygon_stipple != have->fs.polygon_stipple ||597expect->fs.cast_to_uint != have->fs.cast_to_uint ||598expect->fs.cast_to_int != have->fs.cast_to_int)599return false;600}601602if (expect->tex_saturate_s != have->tex_saturate_s ||603expect->tex_saturate_r != have->tex_saturate_r ||604expect->tex_saturate_t != have->tex_saturate_t)605return false;606607if (expect->samples_int_textures != have->samples_int_textures)608return false;609610if (expect->n_texture_states != have->n_texture_states)611return false;612613if (memcmp(expect->tex_wrap_states, have->tex_wrap_states,614expect->n_texture_states * sizeof(dxil_wrap_sampler_state)))615return false;616617if (memcmp(expect->swizzle_state, have->swizzle_state,618expect->n_texture_states * sizeof(dxil_texture_swizzle_state)))619return false;620621if (memcmp(expect->sampler_compare_funcs, have->sampler_compare_funcs,622expect->n_texture_states * sizeof(enum compare_func)))623return false;624625if (expect->invert_depth != have->invert_depth)626return false;627628if (expect->stage == PIPE_SHADER_VERTEX) {629if (expect->vs.needs_format_emulation != have->vs.needs_format_emulation)630return false;631632if (expect->vs.needs_format_emulation) {633if (memcmp(expect->vs.format_conversion, have->vs.format_conversion,634PIPE_MAX_ATTRIBS * sizeof (enum pipe_format)))635return false;636}637}638639if (expect->fs.provoking_vertex != have->fs.provoking_vertex)640return false;641642return true;643}644645static void646d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,647d3d12_shader_key *key, d3d12_shader_selector *sel,648d3d12_shader_selector *prev, d3d12_shader_selector *next)649{650pipe_shader_type stage = sel->stage;651652uint64_t system_generated_in_values =653VARYING_BIT_PNTC |654VARYING_BIT_PRIMITIVE_ID;655656uint64_t system_out_values =657VARYING_BIT_CLIP_DIST0 |658VARYING_BIT_CLIP_DIST1;659660memset(key, 0, sizeof(d3d12_shader_key));661key->stage = stage;662663if (prev) {664/* We require as inputs what the previous stage has written,665* except certain system values */666if (stage == PIPE_SHADER_FRAGMENT || stage == PIPE_SHADER_GEOMETRY)667system_out_values |= VARYING_BIT_POS;668if (stage == PIPE_SHADER_FRAGMENT)669system_out_values |= VARYING_BIT_PSIZ;670uint64_t mask = prev->current->nir->info.outputs_written & ~system_out_values;671fill_varyings(&key->required_varying_inputs, prev->current->nir,672nir_var_shader_out, mask);673key->prev_varying_outputs = prev->current->nir->info.outputs_written;674675/* Set the provoking vertex based on the previous shader output. Only set the676* key value if the driver actually supports changing the provoking vertex though */677if (stage == PIPE_SHADER_FRAGMENT && sel_ctx->ctx->gfx_pipeline_state.rast &&678!sel_ctx->needs_vertex_reordering &&679d3d12_screen(sel_ctx->ctx->base.screen)->have_load_at_vertex)680key->fs.provoking_vertex = sel_ctx->provoking_vertex;681}682683/* We require as outputs what the next stage reads,684* except certain system values */685if (next) {686if (!next->is_gs_variant) {687if (stage == PIPE_SHADER_VERTEX)688system_generated_in_values |= VARYING_BIT_POS;689uint64_t mask = next->current->nir->info.inputs_read & ~system_generated_in_values;690fill_varyings(&key->required_varying_outputs, next->current->nir,691nir_var_shader_in, mask);692}693key->next_varying_inputs = next->current->nir->info.inputs_read;694}695696if (stage == PIPE_SHADER_GEOMETRY ||697(stage == PIPE_SHADER_VERTEX && (!next || next->stage != PIPE_SHADER_GEOMETRY))) {698key->last_vertex_processing_stage = 1;699key->invert_depth = sel_ctx->ctx->reverse_depth_range;700if (sel_ctx->ctx->pstipple.enabled)701key->next_varying_inputs |= VARYING_BIT_POS;702}703704if (stage == PIPE_SHADER_GEOMETRY && sel_ctx->ctx->gfx_pipeline_state.rast) {705struct pipe_rasterizer_state *rast = &sel_ctx->ctx->gfx_pipeline_state.rast->base;706if (sel_ctx->needs_point_sprite_lowering) {707key->gs.writes_psize = 1;708key->gs.point_size_per_vertex = rast->point_size_per_vertex;709key->gs.sprite_coord_enable = rast->sprite_coord_enable;710key->gs.sprite_origin_upper_left = (rast->sprite_coord_mode != PIPE_SPRITE_COORD_LOWER_LEFT);711if (sel_ctx->ctx->flip_y < 0)712key->gs.sprite_origin_upper_left = !key->gs.sprite_origin_upper_left;713key->gs.aa_point = rast->point_smooth;714key->gs.stream_output_factor = 6;715} else if (sel_ctx->fill_mode_lowered == PIPE_POLYGON_MODE_LINE) {716key->gs.stream_output_factor = 2;717} else if (sel_ctx->needs_vertex_reordering && !sel->is_gs_variant) {718key->gs.triangle_strip = 1;719}720721if (sel->is_gs_variant && next && next->initial->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)722key->gs.primitive_id = 1;723} else if (stage == PIPE_SHADER_FRAGMENT) {724key->fs.missing_dual_src_outputs = sel_ctx->missing_dual_src_outputs;725key->fs.frag_result_color_lowering = sel_ctx->frag_result_color_lowering;726key->fs.manual_depth_range = sel_ctx->manual_depth_range;727key->fs.polygon_stipple = sel_ctx->ctx->pstipple.enabled;728if (sel_ctx->ctx->gfx_pipeline_state.blend &&729sel_ctx->ctx->gfx_pipeline_state.blend->desc.RenderTarget[0].LogicOpEnable &&730!sel_ctx->ctx->gfx_pipeline_state.has_float_rtv) {731key->fs.cast_to_uint = util_format_is_unorm(sel_ctx->ctx->fb.cbufs[0]->format);732key->fs.cast_to_int = !key->fs.cast_to_uint;733}734}735736if (sel->samples_int_textures) {737key->samples_int_textures = sel->samples_int_textures;738key->n_texture_states = sel_ctx->ctx->num_sampler_views[stage];739/* Copy only states with integer textures */740for(int i = 0; i < key->n_texture_states; ++i) {741auto& wrap_state = sel_ctx->ctx->tex_wrap_states[stage][i];742if (wrap_state.is_int_sampler) {743memcpy(&key->tex_wrap_states[i], &wrap_state, sizeof(wrap_state));744key->swizzle_state[i] = sel_ctx->ctx->tex_swizzle_state[stage][i];745}746}747}748749for (unsigned i = 0; i < sel_ctx->ctx->num_samplers[stage]; ++i) {750if (!sel_ctx->ctx->samplers[stage][i] ||751sel_ctx->ctx->samplers[stage][i]->filter == PIPE_TEX_FILTER_NEAREST)752continue;753754if (sel_ctx->ctx->samplers[stage][i]->wrap_r == PIPE_TEX_WRAP_CLAMP)755key->tex_saturate_r |= 1 << i;756if (sel_ctx->ctx->samplers[stage][i]->wrap_s == PIPE_TEX_WRAP_CLAMP)757key->tex_saturate_s |= 1 << i;758if (sel_ctx->ctx->samplers[stage][i]->wrap_t == PIPE_TEX_WRAP_CLAMP)759key->tex_saturate_t |= 1 << i;760}761762if (sel->compare_with_lod_bias_grad) {763key->n_texture_states = sel_ctx->ctx->num_sampler_views[stage];764memcpy(key->sampler_compare_funcs, sel_ctx->ctx->tex_compare_func[stage],765key->n_texture_states * sizeof(enum compare_func));766memcpy(key->swizzle_state, sel_ctx->ctx->tex_swizzle_state[stage],767key->n_texture_states * sizeof(dxil_texture_swizzle_state));768}769770if (stage == PIPE_SHADER_VERTEX && sel_ctx->ctx->gfx_pipeline_state.ves) {771key->vs.needs_format_emulation = sel_ctx->ctx->gfx_pipeline_state.ves->needs_format_emulation;772if (key->vs.needs_format_emulation) {773memcpy(key->vs.format_conversion, sel_ctx->ctx->gfx_pipeline_state.ves->format_conversion,774sel_ctx->ctx->gfx_pipeline_state.ves->num_elements * sizeof(enum pipe_format));775}776}777778if (stage == PIPE_SHADER_FRAGMENT &&779sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY] &&780sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_gs_variant &&781sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->gs_key.has_front_face) {782key->fs.remap_front_facing = 1;783}784}785786static void787select_shader_variant(struct d3d12_selection_context *sel_ctx, d3d12_shader_selector *sel,788d3d12_shader_selector *prev, d3d12_shader_selector *next)789{790struct d3d12_context *ctx = sel_ctx->ctx;791d3d12_shader_key key;792nir_shader *new_nir_variant;793unsigned pstipple_binding = UINT32_MAX;794795d3d12_fill_shader_key(sel_ctx, &key, sel, prev, next);796797/* Check for an existing variant */798for (d3d12_shader *variant = sel->first; variant;799variant = variant->next_variant) {800801if (d3d12_compare_shader_keys(&key, &variant->key)) {802sel->current = variant;803return;804}805}806807/* Clone the NIR shader */808new_nir_variant = nir_shader_clone(sel, sel->initial);809810/* Apply any needed lowering passes */811if (key.gs.writes_psize) {812NIR_PASS_V(new_nir_variant, d3d12_lower_point_sprite,813!key.gs.sprite_origin_upper_left,814key.gs.point_size_per_vertex,815key.gs.sprite_coord_enable,816key.next_varying_inputs);817818nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);819nir_shader_gather_info(new_nir_variant, impl);820}821822if (key.gs.primitive_id) {823NIR_PASS_V(new_nir_variant, d3d12_lower_primitive_id);824825nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);826nir_shader_gather_info(new_nir_variant, impl);827}828829if (key.gs.triangle_strip)830NIR_PASS_V(new_nir_variant, d3d12_lower_triangle_strip);831832if (key.fs.polygon_stipple) {833NIR_PASS_V(new_nir_variant, nir_lower_pstipple_fs,834&pstipple_binding, 0, false);835836nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);837nir_shader_gather_info(new_nir_variant, impl);838}839840if (key.fs.remap_front_facing) {841d3d12_forward_front_face(new_nir_variant);842843nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);844nir_shader_gather_info(new_nir_variant, impl);845}846847if (key.fs.missing_dual_src_outputs) {848NIR_PASS_V(new_nir_variant, d3d12_add_missing_dual_src_target,849key.fs.missing_dual_src_outputs);850} else if (key.fs.frag_result_color_lowering) {851NIR_PASS_V(new_nir_variant, nir_lower_fragcolor,852key.fs.frag_result_color_lowering);853}854855if (key.fs.manual_depth_range)856NIR_PASS_V(new_nir_variant, d3d12_lower_depth_range);857858if (sel->compare_with_lod_bias_grad)859NIR_PASS_V(new_nir_variant, d3d12_lower_sample_tex_compare, key.n_texture_states,860key.sampler_compare_funcs, key.swizzle_state);861862if (key.fs.cast_to_uint)863NIR_PASS_V(new_nir_variant, d3d12_lower_uint_cast, false);864if (key.fs.cast_to_int)865NIR_PASS_V(new_nir_variant, d3d12_lower_uint_cast, true);866867{868struct nir_lower_tex_options tex_options = { };869tex_options.lower_txp = ~0u; /* No equivalent for textureProj */870tex_options.lower_rect = true;871tex_options.lower_rect_offset = true;872tex_options.saturate_s = key.tex_saturate_s;873tex_options.saturate_r = key.tex_saturate_r;874tex_options.saturate_t = key.tex_saturate_t;875876NIR_PASS_V(new_nir_variant, nir_lower_tex, &tex_options);877}878879/* Add the needed in and outputs, and re-sort */880uint64_t mask = key.required_varying_inputs.mask & ~new_nir_variant->info.inputs_read;881882if (prev) {883while (mask) {884int slot = u_bit_scan64(&mask);885create_varying_from_info(new_nir_variant, &key.required_varying_inputs, slot, nir_var_shader_in);886}887dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_in,888key.prev_varying_outputs);889}890891mask = key.required_varying_outputs.mask & ~new_nir_variant->info.outputs_written;892893if (next) {894while (mask) {895int slot = u_bit_scan64(&mask);896create_varying_from_info(new_nir_variant, &key.required_varying_outputs, slot, nir_var_shader_out);897}898dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_out,899key.next_varying_inputs);900}901902d3d12_shader *new_variant = compile_nir(ctx, sel, &key, new_nir_variant);903assert(new_variant);904905/* keep track of polygon stipple texture binding */906new_variant->pstipple_binding = pstipple_binding;907908/* prepend the new shader in the selector chain and pick it */909new_variant->next_variant = sel->first;910sel->current = sel->first = new_variant;911}912913static d3d12_shader_selector *914get_prev_shader(struct d3d12_context *ctx, pipe_shader_type current)915{916/* No TESS_CTRL or TESS_EVAL yet */917918switch (current) {919case PIPE_SHADER_VERTEX:920return NULL;921case PIPE_SHADER_FRAGMENT:922if (ctx->gfx_stages[PIPE_SHADER_GEOMETRY])923return ctx->gfx_stages[PIPE_SHADER_GEOMETRY];924FALLTHROUGH;925case PIPE_SHADER_GEOMETRY:926return ctx->gfx_stages[PIPE_SHADER_VERTEX];927default:928unreachable("shader type not supported");929}930}931932static d3d12_shader_selector *933get_next_shader(struct d3d12_context *ctx, pipe_shader_type current)934{935/* No TESS_CTRL or TESS_EVAL yet */936937switch (current) {938case PIPE_SHADER_VERTEX:939if (ctx->gfx_stages[PIPE_SHADER_GEOMETRY])940return ctx->gfx_stages[PIPE_SHADER_GEOMETRY];941FALLTHROUGH;942case PIPE_SHADER_GEOMETRY:943return ctx->gfx_stages[PIPE_SHADER_FRAGMENT];944case PIPE_SHADER_FRAGMENT:945return NULL;946default:947unreachable("shader type not supported");948}949}950951enum tex_scan_flags {952TEX_SAMPLE_INTEGER_TEXTURE = 1 << 0,953TEX_CMP_WITH_LOD_BIAS_GRAD = 1 << 1,954TEX_SCAN_ALL_FLAGS = (1 << 2) - 1955};956957static unsigned958scan_texture_use(nir_shader *nir)959{960unsigned result = 0;961nir_foreach_function(func, nir) {962nir_foreach_block(block, func->impl) {963nir_foreach_instr(instr, block) {964if (instr->type == nir_instr_type_tex) {965auto tex = nir_instr_as_tex(instr);966switch (tex->op) {967case nir_texop_txb:968case nir_texop_txl:969case nir_texop_txd:970if (tex->is_shadow)971result |= TEX_CMP_WITH_LOD_BIAS_GRAD;972FALLTHROUGH;973case nir_texop_tex:974if (tex->dest_type & (nir_type_int | nir_type_uint))975result |= TEX_SAMPLE_INTEGER_TEXTURE;976default:977;978}979}980if (TEX_SCAN_ALL_FLAGS == result)981return result;982}983}984}985return result;986}987988static uint64_t989update_so_info(struct pipe_stream_output_info *so_info,990uint64_t outputs_written)991{992uint64_t so_outputs = 0;993uint8_t reverse_map[64] = {0};994unsigned slot = 0;995996while (outputs_written)997reverse_map[slot++] = u_bit_scan64(&outputs_written);998999for (unsigned i = 0; i < so_info->num_outputs; i++) {1000struct pipe_stream_output *output = &so_info->output[i];10011002/* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */1003output->register_index = reverse_map[output->register_index];10041005so_outputs |= 1ull << output->register_index;1006}10071008return so_outputs;1009}10101011struct d3d12_shader_selector *1012d3d12_create_shader(struct d3d12_context *ctx,1013pipe_shader_type stage,1014const struct pipe_shader_state *shader)1015{1016struct d3d12_shader_selector *sel = rzalloc(nullptr, d3d12_shader_selector);1017sel->stage = stage;10181019struct nir_shader *nir = NULL;10201021if (shader->type == PIPE_SHADER_IR_NIR) {1022nir = (nir_shader *)shader->ir.nir;1023} else {1024assert(shader->type == PIPE_SHADER_IR_TGSI);1025nir = tgsi_to_nir(shader->tokens, ctx->base.screen, false);1026}10271028nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));10291030unsigned tex_scan_result = scan_texture_use(nir);1031sel->samples_int_textures = (tex_scan_result & TEX_SAMPLE_INTEGER_TEXTURE) != 0;1032sel->compare_with_lod_bias_grad = (tex_scan_result & TEX_CMP_WITH_LOD_BIAS_GRAD) != 0;10331034memcpy(&sel->so_info, &shader->stream_output, sizeof(sel->so_info));1035update_so_info(&sel->so_info, nir->info.outputs_written);10361037assert(nir != NULL);1038d3d12_shader_selector *prev = get_prev_shader(ctx, sel->stage);1039d3d12_shader_selector *next = get_next_shader(ctx, sel->stage);10401041uint64_t in_mask = nir->info.stage == MESA_SHADER_VERTEX ?10420 : VARYING_BIT_PRIMITIVE_ID;10431044uint64_t out_mask = nir->info.stage == MESA_SHADER_FRAGMENT ?1045(1ull << FRAG_RESULT_STENCIL) :1046VARYING_BIT_PRIMITIVE_ID;10471048d3d12_fix_io_uint_type(nir, in_mask, out_mask);1049NIR_PASS_V(nir, dxil_nir_split_clip_cull_distance);10501051if (nir->info.stage != MESA_SHADER_VERTEX)1052nir->info.inputs_read =1053dxil_reassign_driver_locations(nir, nir_var_shader_in,1054prev ? prev->current->nir->info.outputs_written : 0);1055else1056nir->info.inputs_read = dxil_sort_by_driver_location(nir, nir_var_shader_in);10571058if (nir->info.stage != MESA_SHADER_FRAGMENT) {1059nir->info.outputs_written =1060dxil_reassign_driver_locations(nir, nir_var_shader_out,1061next ? next->current->nir->info.inputs_read : 0);1062} else {1063NIR_PASS_V(nir, nir_lower_fragcoord_wtrans);1064dxil_sort_ps_outputs(nir);1065}10661067/* Integer cube maps are not supported in DirectX because sampling is not supported1068* on integer textures and TextureLoad is not supported for cube maps, so we have to1069* lower integer cube maps to be handled like 2D textures arrays*/1070NIR_PASS_V(nir, d3d12_lower_int_cubmap_to_array);10711072/* Keep this initial shader as the blue print for possible variants */1073sel->initial = nir;10741075/*1076* We must compile some shader here, because if the previous or a next shaders exists later1077* when the shaders are bound, then the key evaluation in the shader selector will access1078* the current variant of these prev and next shader, and we can only assign1079* a current variant when it has been successfully compiled.1080*1081* For shaders that require lowering because certain instructions are not available1082* and their emulation is state depended (like sampling an integer texture that must be1083* emulated and needs handling of boundary conditions, or shadow compare sampling with LOD),1084* we must go through the shader selector here to create a compilable variant.1085* For shaders that are not depended on the state this is just compiling the original1086* shader.1087*1088* TODO: get rid of having to compiling the shader here if it can be forseen that it will1089* be thrown away (i.e. it depends on states that are likely to change before the shader is1090* used for the first time)1091*/1092struct d3d12_selection_context sel_ctx = {0};1093sel_ctx.ctx = ctx;1094select_shader_variant(&sel_ctx, sel, prev, next);10951096if (!sel->current) {1097ralloc_free(sel);1098return NULL;1099}11001101return sel;1102}11031104void1105d3d12_select_shader_variants(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)1106{1107static unsigned order[] = {PIPE_SHADER_VERTEX, PIPE_SHADER_GEOMETRY, PIPE_SHADER_FRAGMENT};1108struct d3d12_selection_context sel_ctx;11091110sel_ctx.ctx = ctx;1111sel_ctx.dinfo = dinfo;1112sel_ctx.needs_point_sprite_lowering = needs_point_sprite_lowering(ctx, dinfo);1113sel_ctx.fill_mode_lowered = fill_mode_lowered(ctx, dinfo);1114sel_ctx.cull_mode_lowered = cull_mode_lowered(ctx, sel_ctx.fill_mode_lowered);1115sel_ctx.provoking_vertex = get_provoking_vertex(&sel_ctx, &sel_ctx.alternate_tri);1116sel_ctx.needs_vertex_reordering = needs_vertex_reordering(&sel_ctx);1117sel_ctx.missing_dual_src_outputs = missing_dual_src_outputs(ctx);1118sel_ctx.frag_result_color_lowering = frag_result_color_lowering(ctx);1119sel_ctx.manual_depth_range = manual_depth_range(ctx);11201121validate_geometry_shader_variant(&sel_ctx);11221123for (unsigned i = 0; i < ARRAY_SIZE(order); ++i) {1124auto sel = ctx->gfx_stages[order[i]];1125if (!sel)1126continue;11271128d3d12_shader_selector *prev = get_prev_shader(ctx, sel->stage);1129d3d12_shader_selector *next = get_next_shader(ctx, sel->stage);11301131select_shader_variant(&sel_ctx, sel, prev, next);1132}1133}11341135void1136d3d12_shader_free(struct d3d12_shader_selector *sel)1137{1138auto shader = sel->first;1139while (shader) {1140free(shader->bytecode);1141shader = shader->next_variant;1142}1143ralloc_free(sel->initial);1144ralloc_free(sel);1145}11461147#ifdef _WIN321148// Used to get path to self1149extern "C" extern IMAGE_DOS_HEADER __ImageBase;1150#endif11511152void d3d12_validation_tools::load_dxil_dll()1153{1154if (!dxil_module.load(UTIL_DL_PREFIX "dxil" UTIL_DL_EXT)) {1155#ifdef _WIN321156char selfPath[MAX_PATH] = "";1157uint32_t pathSize = GetModuleFileNameA((HINSTANCE)&__ImageBase, selfPath, sizeof(selfPath));1158if (pathSize == 0 || pathSize == sizeof(selfPath)) {1159debug_printf("D3D12: Unable to get path to self");1160return;1161}11621163auto lastSlash = strrchr(selfPath, '\\');1164if (!lastSlash) {1165debug_printf("D3D12: Unable to get path to self");1166return;1167}11681169*(lastSlash + 1) = '\0';1170if (strcat_s(selfPath, "dxil.dll") != 0) {1171debug_printf("D3D12: Unable to get path to dxil.dll next to self");1172return;1173}11741175dxil_module.load(selfPath);1176#endif1177}1178}11791180d3d12_validation_tools::d3d12_validation_tools()1181{1182load_dxil_dll();1183DxcCreateInstanceProc dxil_create_func = (DxcCreateInstanceProc)util_dl_get_proc_address(dxil_module, "DxcCreateInstance");11841185if (dxil_create_func) {1186HRESULT hr = dxil_create_func(CLSID_DxcValidator, IID_PPV_ARGS(&validator));1187if (FAILED(hr)) {1188debug_printf("D3D12: Unable to create validator\n");1189}1190}1191#ifdef _WIN321192else if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)) {1193debug_printf("D3D12: Unable to load DXIL.dll\n");1194}1195#endif11961197DxcCreateInstanceProc compiler_create_func = nullptr;1198if(dxc_compiler_module.load("dxcompiler.dll"))1199compiler_create_func = (DxcCreateInstanceProc)util_dl_get_proc_address(dxc_compiler_module, "DxcCreateInstance");12001201if (compiler_create_func) {1202HRESULT hr = compiler_create_func(CLSID_DxcLibrary, IID_PPV_ARGS(&library));1203if (FAILED(hr)) {1204debug_printf("D3D12: Unable to create library instance: %x\n", hr);1205}12061207if (d3d12_debug & D3D12_DEBUG_DISASS) {1208hr = compiler_create_func(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler));1209if (FAILED(hr)) {1210debug_printf("D3D12: Unable to create compiler instance\n");1211}1212}1213} else if (d3d12_debug & D3D12_DEBUG_DISASS) {1214debug_printf("D3D12: Disassembly requested but compiler couldn't be loaded\n");1215}1216}12171218d3d12_validation_tools::HModule::HModule():1219module(0)1220{1221}12221223d3d12_validation_tools::HModule::~HModule()1224{1225if (module)1226util_dl_close(module);1227}12281229inline1230d3d12_validation_tools::HModule::operator util_dl_library * () const1231{1232return module;1233}12341235bool1236d3d12_validation_tools::HModule::load(LPCSTR file_name)1237{1238module = util_dl_open(file_name);1239return module != nullptr;1240}124112421243class ShaderBlob : public IDxcBlob {1244public:1245ShaderBlob(blob* data) : m_data(data) {}12461247LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override { return m_data->data; }12481249SIZE_T STDMETHODCALLTYPE GetBufferSize() override { return m_data->size; }12501251HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) override { return E_NOINTERFACE; }12521253ULONG STDMETHODCALLTYPE AddRef() override { return 1; }12541255ULONG STDMETHODCALLTYPE Release() override { return 0; }12561257blob* m_data;1258};12591260bool d3d12_validation_tools::validate_and_sign(struct blob *dxil)1261{1262ShaderBlob source(dxil);12631264ComPtr<IDxcOperationResult> result;12651266validator->Validate(&source, DxcValidatorFlags_InPlaceEdit, &result);1267HRESULT validationStatus;1268result->GetStatus(&validationStatus);1269if (FAILED(validationStatus) && library) {1270ComPtr<IDxcBlobEncoding> printBlob, printBlobUtf8;1271result->GetErrorBuffer(&printBlob);1272library->GetBlobAsUtf8(printBlob.Get(), printBlobUtf8.GetAddressOf());12731274char *errorString;1275if (printBlobUtf8) {1276errorString = reinterpret_cast<char*>(printBlobUtf8->GetBufferPointer());12771278errorString[printBlobUtf8->GetBufferSize() - 1] = 0;1279debug_printf("== VALIDATION ERROR =============================================\n%s\n"1280"== END ==========================================================\n",1281errorString);1282}12831284return false;1285}1286return true;12871288}12891290void d3d12_validation_tools::disassemble(struct blob *dxil)1291{1292if (!compiler) {1293fprintf(stderr, "D3D12: No Disassembler\n");1294return;1295}1296ShaderBlob source(dxil);1297IDxcBlobEncoding* pDisassembly = nullptr;12981299if (FAILED(compiler->Disassemble(&source, &pDisassembly))) {1300fprintf(stderr, "D3D12: Disassembler failed\n");1301return;1302}13031304ComPtr<IDxcBlobEncoding> dissassably(pDisassembly);1305ComPtr<IDxcBlobEncoding> blobUtf8;1306library->GetBlobAsUtf8(pDisassembly, blobUtf8.GetAddressOf());1307if (!blobUtf8) {1308fprintf(stderr, "D3D12: Unable to get utf8 encoding\n");1309return;1310}13111312char *disassembly = reinterpret_cast<char*>(blobUtf8->GetBufferPointer());1313disassembly[blobUtf8->GetBufferSize() - 1] = 0;13141315fprintf(stderr, "== BEGIN SHADER ============================================\n"1316"%s\n"1317"== END SHADER ==============================================\n",1318disassembly);1319}132013211322