diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index 229951c8e..e065970c7 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -9,12 +9,16 @@ #include "xenia/gpu/spirv_shader_translator.h" +#include + #include #include "xenia/base/logging.h" #include "xenia/gpu/spirv/passes/control_flow_analysis_pass.h" #include "xenia/gpu/spirv/passes/control_flow_simplification_pass.h" +DEFINE_bool(spv_validate, false, "Validate SPIR-V shaders after generation"); + namespace xe { namespace gpu { using namespace ucode; @@ -56,11 +60,6 @@ void SpirvShaderTranslator::StartTranslation() { b.addCapability(spv::Capability::CapabilityDerivativeControl); } - spv::Block* function_block = nullptr; - translated_main_ = - b.makeFunctionEntry(spv::NoPrecision, b.makeVoidType(), "translated_main", - {}, {}, &function_block); - bool_type_ = b.makeBoolType(); float_type_ = b.makeFloatType(32); int_type_ = b.makeIntType(32); @@ -80,6 +79,11 @@ void SpirvShaderTranslator::StartTranslation() { std::vector({b.makeFloatConstant(0.f), b.makeFloatConstant(0.f), b.makeFloatConstant(0.f), b.makeFloatConstant(0.f)})); + spv::Block* function_block = nullptr; + translated_main_ = + b.makeFunctionEntry(spv::NoPrecision, b.makeVoidType(), "translated_main", + {}, {}, &function_block); + registers_type_ = b.makeArrayType(vec4_float_type_, b.makeUintConstant(register_count()), 0); registers_ptr_ = b.createVariable(spv::StorageClass::StorageClassFunction, @@ -241,6 +245,7 @@ void SpirvShaderTranslator::StartTranslation() { b.addDecoration(attrib_var, spv::Decoration::DecorationLocation, attrib.attrib_index); + interface_ids_.push_back(attrib_var); vertex_binding_map_[binding.fetch_constant] [attrib.fetch_instr.attributes.offset] = attrib_var; } @@ -268,6 +273,10 @@ void SpirvShaderTranslator::StartTranslation() { b.addDecoration(vertex_id_, spv::Decoration::DecorationBuiltIn, spv::BuiltIn::BuiltInVertexId); + interface_ids_.push_back(interpolators_); + interface_ids_.push_back(pos_); + interface_ids_.push_back(vertex_id_); + auto vertex_id = b.createLoad(vertex_id_); vertex_id = b.createUnaryOp(spv::Op::OpConvertSToF, float_type_, vertex_id); auto r0_ptr = b.createAccessChain(spv::StorageClass::StorageClassFunction, @@ -295,6 +304,9 @@ void SpirvShaderTranslator::StartTranslation() { b.addDecoration(frag_depth_, spv::Decoration::DecorationBuiltIn, spv::BuiltIn::BuiltInFragDepth); + interface_ids_.push_back(interpolators_); + interface_ids_.push_back(frag_outputs_); + interface_ids_.push_back(frag_depth_); // TODO(benvanik): frag depth, etc. // Copy interpolators to r[0..16]. @@ -328,6 +340,9 @@ void SpirvShaderTranslator::StartTranslation() { vec2_float_type_, "gl_PointCoord"); b.addDecoration(point_coord, spv::Decoration::DecorationBuiltIn, spv::BuiltIn::BuiltInPointCoord); + interface_ids_.push_back(frag_coord); + interface_ids_.push_back(point_coord); + auto param = b.createOp(spv::Op::OpVectorShuffle, vec4_float_type_, {frag_coord, point_coord, 0, 1, 4, 5}); /* @@ -372,11 +387,20 @@ std::vector SpirvShaderTranslator::CompleteTranslation() { // main() entry point. auto mainFn = b.makeMain(); if (is_vertex_shader()) { - b.addEntryPoint(spv::ExecutionModel::ExecutionModelVertex, mainFn, "main"); + auto entry = b.addEntryPoint(spv::ExecutionModel::ExecutionModelVertex, + mainFn, "main"); + + for (auto id : interface_ids_) { + entry->addIdOperand(id); + } } else { - b.addEntryPoint(spv::ExecutionModel::ExecutionModelFragment, mainFn, - "main"); + auto entry = b.addEntryPoint(spv::ExecutionModel::ExecutionModelFragment, + mainFn, "main"); b.addExecutionMode(mainFn, spv::ExecutionModeOriginUpperLeft); + + for (auto id : interface_ids_) { + entry->addIdOperand(id); + } } // TODO(benvanik): transform feedback. @@ -500,13 +524,14 @@ std::vector SpirvShaderTranslator::CompleteTranslation() { void SpirvShaderTranslator::PostTranslation(Shader* shader) { // Validation. - // TODO(DrChat): Only do this if a flag is set (this is pretty slow). - auto validation = validator_.Validate( - reinterpret_cast(shader->translated_binary().data()), - shader->translated_binary().size() / 4); - if (validation->has_error()) { - XELOGE("SPIR-V Shader Validation failed! Error: %s", - validation->error_string()); + if (FLAGS_spv_validate) { + auto validation = validator_.Validate( + reinterpret_cast(shader->translated_binary().data()), + shader->translated_binary().size() / 4); + if (validation->has_error()) { + XELOGE("SPIR-V Shader Validation failed! Error: %s", + validation->error_string()); + } } // TODO(benvanik): only if needed? could be slowish. diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index b6a761a24..d452b42a1 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -134,6 +134,9 @@ class SpirvShaderTranslator : public ShaderTranslator { spv::Id samplers_ = 0; spv::Id tex_[4] = {0}; // Images {1D, 2D, 3D, Cube} + // SPIR-V IDs that are part of the in/out interface. + std::vector interface_ids_; + // Map of {binding -> {offset -> spv input}} std::map> vertex_binding_map_;