diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 6682ec22e..07465c71d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -89,8 +89,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, DescriptorSetProvider{instance, pool, TEXTURE_BINDINGS}, DescriptorSetProvider{instance, pool, SHADOW_BINDINGS}}, trivial_vertex_shader{ - instance, vk::ShaderStageFlagBits::eVertex, - GLSL::GenerateTrivialVertexShader(instance.IsShaderClipDistanceSupported(), true)} { + instance, SPIRV::GenerateTrivialVertexShader(instance.IsShaderClipDistanceSupported())} { profile = Pica::Shader::Profile{ .has_separable_shaders = true, .has_clip_planes = instance.IsShaderClipDistanceSupported(), diff --git a/src/video_core/shader/generator/spv_shader_gen.cpp b/src/video_core/shader/generator/spv_shader_gen.cpp index c3479f903..edf518e7a 100644 --- a/src/video_core/shader/generator/spv_shader_gen.cpp +++ b/src/video_core/shader/generator/spv_shader_gen.cpp @@ -13,8 +13,7 @@ namespace Pica::Shader::Generator::SPIRV { constexpr u32 SPIRV_VERSION_1_3 = 0x00010300; -VertexModule::VertexModule(const PicaVSConfig& config_, const Profile& profile_) - : Sirit::Module{SPIRV_VERSION_1_3}, config{config_}, profile{profile_} { +VertexModule::VertexModule() : Sirit::Module{SPIRV_VERSION_1_3} { DefineArithmeticTypes(); DefineInterface(); DefineEntryPoint(); @@ -22,25 +21,19 @@ VertexModule::VertexModule(const PicaVSConfig& config_, const Profile& profile_) VertexModule::~VertexModule() = default; -void VertexModule::Generate() { - AddLabel(OpLabel()); - OpReturn(); - OpFunctionEnd(); -} - void VertexModule::DefineArithmeticTypes() { - void_id = Name(TypeVoid(), "void_id"); - bool_id = Name(TypeBool(), "bool_id"); - f32_id = Name(TypeFloat(32), "f32_id"); - i32_id = Name(TypeSInt(32), "i32_id"); - u32_id = Name(TypeUInt(32), "u32_id"); + ids.void_id = Name(TypeVoid(), "void_id"); + ids.bool_id = Name(TypeBool(), "bool_id"); + ids.f32_id = Name(TypeFloat(32), "f32_id"); + ids.i32_id = Name(TypeSInt(32), "i32_id"); + ids.u32_id = Name(TypeUInt(32), "u32_id"); for (u32 size = 2; size <= 4; size++) { const u32 i = size - 2; - vec_ids.ids[i] = Name(TypeVector(f32_id, size), fmt::format("vec{}_id", size)); - ivec_ids.ids[i] = Name(TypeVector(i32_id, size), fmt::format("ivec{}_id", size)); - uvec_ids.ids[i] = Name(TypeVector(u32_id, size), fmt::format("uvec{}_id", size)); - bvec_ids.ids[i] = Name(TypeVector(bool_id, size), fmt::format("bvec{}_id", size)); + ids.bvec_ids.ids[i] = Name(TypeVector(ids.bool_id, size), fmt::format("bvec{}_id", size)); + ids.vec_ids.ids[i] = Name(TypeVector(ids.f32_id, size), fmt::format("vec{}_id", size)); + ids.ivec_ids.ids[i] = Name(TypeVector(ids.i32_id, size), fmt::format("ivec{}_id", size)); + ids.uvec_ids.ids[i] = Name(TypeVector(ids.u32_id, size), fmt::format("uvec{}_id", size)); } } @@ -51,17 +44,104 @@ void VertexModule::DefineEntryPoint() { const Id main_type{TypeFunction(TypeVoid())}; const Id main_func{OpFunction(TypeVoid(), spv::FunctionControlMask::MaskNone, main_type)}; - AddEntryPoint(spv::ExecutionModel::Vertex, main_func, "main"); + const Id interface_ids[] = { + ids.vert_in_position_id, ids.vert_in_color_id, ids.vert_in_texcoord0_id, + ids.vert_in_texcoord1_id, ids.vert_in_texcoord2_id, ids.vert_in_texcoord0_w_id, + ids.vert_in_normquat_id, ids.vert_in_view_id, ids.gl_position, + ids.vert_out_color_id, ids.vert_out_texcoord0_id, ids.vert_out_texcoord1_id, + ids.vert_out_texcoord2_id, ids.vert_out_texcoord0_w_id, ids.vert_out_normquat_id, + ids.vert_out_view_id, + }; + + AddEntryPoint(spv::ExecutionModel::Vertex, main_func, "main", interface_ids); } void VertexModule::DefineInterface() { // Define interface block + + // Inputs + ids.vert_in_position_id = + Name(DefineInput(ids.vec_ids.Get(4), ATTRIBUTE_POSITION), "vert_in_position_id"); + ids.vert_in_color_id = + Name(DefineInput(ids.vec_ids.Get(4), ATTRIBUTE_COLOR), "vert_in_color_id"); + ids.vert_in_texcoord0_id = + Name(DefineInput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD0), "vert_in_texcoord0_id"); + ids.vert_in_texcoord1_id = + Name(DefineInput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD1), "vert_in_texcoord1_id"); + ids.vert_in_texcoord2_id = + Name(DefineInput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD2), "vert_in_texcoord2_id"); + ids.vert_in_texcoord0_w_id = + Name(DefineInput(ids.f32_id, ATTRIBUTE_TEXCOORD0_W), "vert_in_texcoord0_w_id"); + ids.vert_in_normquat_id = + Name(DefineInput(ids.vec_ids.Get(4), ATTRIBUTE_NORMQUAT), "vert_in_normquat_id"); + ids.vert_in_view_id = Name(DefineInput(ids.vec_ids.Get(3), ATTRIBUTE_VIEW), "vert_in_view_id"); + + // Outputs + ids.vert_out_color_id = + Name(DefineOutput(ids.vec_ids.Get(4), ATTRIBUTE_COLOR), "vert_out_color_id"); + ids.vert_out_texcoord0_id = + Name(DefineOutput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD0), "vert_out_texcoord0_id"); + ids.vert_out_texcoord1_id = + Name(DefineOutput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD1), "vert_out_texcoord1_id"); + ids.vert_out_texcoord2_id = + Name(DefineOutput(ids.vec_ids.Get(2), ATTRIBUTE_TEXCOORD2), "vert_out_texcoord2_id"); + ids.vert_out_texcoord0_w_id = + Name(DefineOutput(ids.f32_id, ATTRIBUTE_TEXCOORD0_W), "vert_out_texcoord0_w_id"); + ids.vert_out_normquat_id = + Name(DefineOutput(ids.vec_ids.Get(4), ATTRIBUTE_NORMQUAT), "vert_out_normquat_id"); + ids.vert_out_view_id = + Name(DefineOutput(ids.vec_ids.Get(3), ATTRIBUTE_VIEW), "vert_out_view_id"); + + // Built-ins + ids.gl_position = DefineVar(ids.vec_ids.Get(4), spv::StorageClass::Output); + Decorate(ids.gl_position, spv::Decoration::BuiltIn, spv::BuiltIn::Position); +} + +void VertexModule::Generate(Common::UniqueFunction proc) { + AddLabel(OpLabel()); + proc(*this, ids); + OpReturn(); + OpFunctionEnd(); +} + +void VertexModule::Generate(const PicaVSConfig& config, const Profile& profile) { + AddLabel(OpLabel()); + OpReturn(); + OpFunctionEnd(); +} + +std::vector GenerateTrivialVertexShader(bool use_clip_planes) { + VertexModule module; + module.Generate([](Sirit::Module& code, const VertexModule::EmitterIDs& ids) -> void { + code.OpStore(ids.gl_position, code.OpLoad(ids.vec_ids.Get(4), ids.vert_in_position_id)); + + // Negate Z + const Id pos_z = code.OpAccessChain(code.TypePointer(spv::StorageClass::Output, ids.f32_id), + ids.gl_position, code.Constant(ids.u32_id, 2)); + + code.OpStore(pos_z, code.OpFNegate(ids.f32_id, code.OpLoad(ids.f32_id, pos_z))); + + // Pass-through + code.OpStore(ids.vert_out_color_id, code.OpLoad(ids.vec_ids.Get(4), ids.vert_in_color_id)); + code.OpStore(ids.vert_out_texcoord0_id, + code.OpLoad(ids.vec_ids.Get(2), ids.vert_in_texcoord0_id)); + code.OpStore(ids.vert_out_texcoord1_id, + code.OpLoad(ids.vec_ids.Get(2), ids.vert_in_texcoord1_id)); + code.OpStore(ids.vert_out_texcoord2_id, + code.OpLoad(ids.vec_ids.Get(2), ids.vert_in_texcoord2_id)); + code.OpStore(ids.vert_out_texcoord0_w_id, + code.OpLoad(ids.f32_id, ids.vert_in_texcoord0_w_id)); + code.OpStore(ids.vert_out_normquat_id, + code.OpLoad(ids.vec_ids.Get(4), ids.vert_in_normquat_id)); + code.OpStore(ids.vert_out_view_id, code.OpLoad(ids.vec_ids.Get(3), ids.vert_in_view_id)); + }); + return module.Assemble(); } std::vector GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& config, const Profile& profile) { - VertexModule module(config, profile); - module.Generate(); + VertexModule module; + module.Generate(config, profile); return module.Assemble(); } diff --git a/src/video_core/shader/generator/spv_shader_gen.h b/src/video_core/shader/generator/spv_shader_gen.h index 1f8fda8e0..419051283 100644 --- a/src/video_core/shader/generator/spv_shader_gen.h +++ b/src/video_core/shader/generator/spv_shader_gen.h @@ -6,6 +6,8 @@ #include +#include "common/unique_function.h" + namespace Pica { struct ShaderSetup; } @@ -35,39 +37,90 @@ struct VectorIds { class VertexModule : public Sirit::Module { public: - explicit VertexModule(const PicaVSConfig& config, const Profile& profile); + explicit VertexModule(); ~VertexModule(); - /// Emits SPIR-V bytecode corresponding to the provided pica vertex configuration - void Generate(); - private: + template + [[nodiscard]] Id DefineVar(Id type, spv::StorageClass storage_class) { + const Id pointer_type_id{TypePointer(storage_class, type)}; + return global ? AddGlobalVariable(pointer_type_id, storage_class) + : AddLocalVariable(pointer_type_id, storage_class); + } + + /// Defines an input variable + [[nodiscard]] Id DefineInput(Id type, u32 location) { + const Id input_id{DefineVar(type, spv::StorageClass::Input)}; + Decorate(input_id, spv::Decoration::Location, location); + return input_id; + } + + /// Defines an output variable + [[nodiscard]] Id DefineOutput(Id type, u32 location) { + const Id output_id{DefineVar(type, spv::StorageClass::Output)}; + Decorate(output_id, spv::Decoration::Location, location); + return output_id; + } + void DefineArithmeticTypes(); void DefineEntryPoint(); void DefineInterface(); -private: - const PicaVSConfig& config; - const Profile& profile; +public: + struct EmitterIDs { + Id void_id{}; + Id bool_id{}; + Id f32_id{}; + Id i32_id{}; + Id u32_id{}; - Id void_id{}; - Id bool_id{}; - Id f32_id{}; - Id i32_id{}; - Id u32_id{}; + VectorIds vec_ids{}; + VectorIds ivec_ids{}; + VectorIds uvec_ids{}; + VectorIds bvec_ids{}; - VectorIds vec_ids{}; - VectorIds ivec_ids{}; - VectorIds uvec_ids{}; - VectorIds bvec_ids{}; + // Input vertex attributes + Id vert_in_position_id{}; + Id vert_in_color_id{}; + Id vert_in_texcoord0_id{}; + Id vert_in_texcoord1_id{}; + Id vert_in_texcoord2_id{}; + Id vert_in_texcoord0_w_id{}; + Id vert_in_normquat_id{}; + Id vert_in_view_id{}; + + // Output vertex attributes + Id vert_out_color_id{}; + Id vert_out_texcoord0_id{}; + Id vert_out_texcoord1_id{}; + Id vert_out_texcoord2_id{}; + Id vert_out_texcoord0_w_id{}; + Id vert_out_normquat_id{}; + Id vert_out_view_id{}; + + // Built-ins + Id gl_position; + } ids; + + /// Generate code using the provided SPIRV emitter context + void Generate(Common::UniqueFunction proc); + + /// Emits SPIR-V bytecode corresponding to the provided pica vertex configuration + void Generate(const PicaVSConfig& config, const Profile& profile); }; +/** + * Generates the SPIRV vertex shader program source code that accepts vertices from software shader + * and directly passes them to the fragment shader. + * @returns SPIRV shader assembly; empty on failure + */ +std::vector GenerateTrivialVertexShader(bool use_clip_planes); + /** * Generates the SPIRV vertex shader program source code for the given VS program * @param config ShaderCacheKey object generated for the current Pica state, used for the shader * configuration (NOTE: Use state in this struct only, not the Pica registers!) - * @param separable_shader generates shader that can be used for separate shader object - * @returns String of the shader source code; empty on failure + * @returns SPIRV shader assembly; empty on failure */ std::vector GenerateVertexShader(const Pica::ShaderSetup& setup, const PicaVSConfig& config, const Profile& profile);