renderer_vulkan: SPIRV TrivialVertexShader generation
Seems to work just fine when hardware-shaders are disabled!
This commit is contained in:
parent
99e83a4ab8
commit
3fb681bcc6
3 changed files with 172 additions and 40 deletions
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <sirit/sirit.h>
|
||||
|
||||
#include "common/unique_function.h"
|
||||
|
||||
namespace Pica {
|
||||
struct ShaderSetup;
|
||||
}
|
||||
|
@ -35,21 +37,37 @@ 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{};
|
||||
|
@ -60,14 +78,49 @@ private:
|
|||
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);
|
||||
|
|
Loading…
Reference in a new issue