renderer_vulkan: SPIRV TrivialVertexShader generation

Seems to work just fine when hardware-shaders are disabled!
This commit is contained in:
Wunkolo 2024-03-02 12:51:08 -08:00
parent 99e83a4ab8
commit 3fb681bcc6
3 changed files with 172 additions and 40 deletions

View file

@ -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(),

View file

@ -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<void, Sirit::Module&, const EmitterIDs&> proc) {
AddLabel(OpLabel());
proc(*this, ids);
OpReturn();
OpFunctionEnd();
}
void VertexModule::Generate(const PicaVSConfig& config, const Profile& profile) {
AddLabel(OpLabel());
OpReturn();
OpFunctionEnd();
}
std::vector<u32> 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<u32> 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();
}

View file

@ -6,6 +6,8 @@
#include <sirit/sirit.h>
#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 <bool global = true>
[[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<void, Sirit::Module&, const EmitterIDs&> 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<u32> 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<u32> GenerateVertexShader(const Pica::ShaderSetup& setup, const PicaVSConfig& config,
const Profile& profile);