mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
shader: construct SPIR-V module variables in one place
This commit is contained in:
@@ -321,12 +321,6 @@ std::vector<uint32_t> EmitProgram(const IR::Program& program,
|
||||
workgroup != nullptr && program.wave_size == 64u && workgroup->host_subgroup_size == 32u
|
||||
? 2u
|
||||
: 1u;
|
||||
state.inputs.reserve(program.info.inputs.size());
|
||||
state.outputs.reserve(program.info.outputs.size());
|
||||
state.interface_variables.reserve(program.info.inputs.size() + program.info.outputs.size());
|
||||
CopyProgramInputsAndOutputs(state, program);
|
||||
AllocateInputVariables(state);
|
||||
AllocateOutputVariables(state);
|
||||
DefineModule(state);
|
||||
EmitProgram(state);
|
||||
state.builder.AddEntryPoint(ExecutionModelForStage(state.program.stage), state.main_func,
|
||||
|
||||
@@ -30,16 +30,6 @@ bool PixelParameterIsCustom(const EmitterState& state, uint32_t attr) {
|
||||
ShaderPixelParameterIsCustom(*state.input_info.pixel, attr);
|
||||
}
|
||||
|
||||
void CopyProgramInputsAndOutputs(EmitterState& state, const IR::Program& program) {
|
||||
for (const auto& input: program.info.inputs) {
|
||||
state.inputs.push_back({input.kind, input.location, input.component_count, 0,
|
||||
input.debug_name, input.per_vertex});
|
||||
}
|
||||
for (const auto& output: program.info.outputs) {
|
||||
state.outputs.push_back({output.kind, output.index, output.location, 0, output.debug_name});
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t OutputVariableForExport(const EmitterState& state, const IR::ExportInfo& exp) {
|
||||
if (exp.kind == IR::ExportTargetKind::Position && exp.index == 0) {
|
||||
return state.per_vertex_variable;
|
||||
|
||||
@@ -25,22 +25,13 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
struct InputBinding {
|
||||
IR::StageInputKind kind = IR::StageInputKind::VertexIndex;
|
||||
uint32_t location = 0;
|
||||
uint32_t component_count = 1;
|
||||
uint32_t variable_id = 0;
|
||||
std::string debug_name;
|
||||
bool per_vertex = false;
|
||||
struct InputBinding : IR::StageInput {
|
||||
uint32_t variable_id = 0;
|
||||
};
|
||||
|
||||
struct OutputBinding {
|
||||
IR::StageOutputKind kind = IR::StageOutputKind::Parameter;
|
||||
uint32_t index = 0;
|
||||
uint32_t location = 0;
|
||||
uint32_t variable_id = 0;
|
||||
std::string debug_name;
|
||||
uint32_t mesh_data_variable = 0;
|
||||
struct OutputBinding : IR::StageOutput {
|
||||
uint32_t variable_id = 0;
|
||||
uint32_t mesh_data_variable = 0;
|
||||
};
|
||||
|
||||
using ImageDimension = Decoder::ImageDimension;
|
||||
@@ -124,8 +115,6 @@ struct EmitterState {
|
||||
uint32_t cull_distance_variable = 0;
|
||||
uint32_t layer_variable = 0;
|
||||
uint32_t viewport_index_variable = 0;
|
||||
uint32_t clip_distance_count = 0;
|
||||
uint32_t cull_distance_count = 0;
|
||||
uint32_t depth_variable = 0;
|
||||
uint32_t sample_mask_variable = 0;
|
||||
std::vector<InputBinding> inputs;
|
||||
@@ -267,11 +256,6 @@ uint32_t VertexParameterComponentCount(const InputBinding& input);
|
||||
|
||||
uint32_t VertexParameterScalarType(EmitterState& state, VertexInputScalarKind kind);
|
||||
|
||||
uint32_t VertexParameterInputPointerType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components);
|
||||
|
||||
|
||||
void CopyProgramInputsAndOutputs(EmitterState& state, const IR::Program& program);
|
||||
|
||||
uint32_t OutputVariableForExport(const EmitterState& state, const IR::ExportInfo& exp);
|
||||
|
||||
@@ -329,21 +313,6 @@ uint32_t ConstantU64(EmitterState& state, uint64_t value);
|
||||
|
||||
uint32_t ConstantU32CompositeZero(EmitterState& state, uint32_t components);
|
||||
|
||||
void AllocateInputVariables(EmitterState& state);
|
||||
|
||||
void AllocateOutputVariables(EmitterState& state);
|
||||
|
||||
uint32_t BuiltInForInput(IR::StageInputKind kind);
|
||||
|
||||
void AddInputAnnotationsAndNames(EmitterState& state);
|
||||
|
||||
void AddOutputAnnotationsAndNames(EmitterState& state);
|
||||
|
||||
void DecorateDescriptor(EmitterState& state, uint32_t variable, const char* name,
|
||||
IR::DescriptorBindingKind kind);
|
||||
|
||||
void AddDescriptorAnnotationsAndNames(EmitterState& state);
|
||||
|
||||
void DefineModule(EmitterState& state);
|
||||
void DefineMeshOutputs(EmitterState& state);
|
||||
void EmitMeshEntryPoint(EmitterState& state);
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
const IR::DescriptorBinding* DescriptorBinding(const EmitterState& state,
|
||||
IR::DescriptorBindingKind kind);
|
||||
uint32_t DescriptorCount(const EmitterState& state, IR::DescriptorBindingKind kind);
|
||||
|
||||
uint32_t TypeVoid(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeVoid);
|
||||
}
|
||||
@@ -160,105 +156,91 @@ uint32_t SampleMaskArrayType(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeArray, {TypeI32(state), ConstantU32(state, 1)});
|
||||
}
|
||||
|
||||
uint32_t BdaPagetableType(EmitterState& state) {
|
||||
const auto array = state.builder.DecoratedType(
|
||||
spv::OpTypeRuntimeArray, {TypeScalarU64(state)},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint64_t)}}});
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct, {array},
|
||||
{{spv::OpMemberDecorate, {0, spv::DecorationOffset, 0}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
}
|
||||
|
||||
uint32_t F32ArrayType(EmitterState& state, uint32_t count) {
|
||||
return state.builder.Type(spv::OpTypeArray, {TypeF32(state), ConstantU32(state, count)});
|
||||
}
|
||||
|
||||
void DefineDescriptorVariables(EmitterState& state) {
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Buffers) != nullptr) {
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Buffers));
|
||||
const auto array_type =
|
||||
state.builder.Type(spv::OpTypeArray, {StorageBufferType(state), count});
|
||||
const auto pointer_type = TypePointer(state, spv::StorageClassStorageBuffer, array_type);
|
||||
state.storage_buffer_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, spv::StorageClassStorageBuffer);
|
||||
if (state.requirements.buffer_int64_atomics) {
|
||||
const auto u64_array_type =
|
||||
state.builder.Type(spv::OpTypeArray, {StorageBufferU64Type(state), count});
|
||||
state.storage_buffer_u64_variable = state.builder.DefineGlobalVariable(
|
||||
TypePointer(state, spv::StorageClassStorageBuffer, u64_array_type),
|
||||
spv::StorageClassStorageBuffer);
|
||||
}
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::BdaPagetable) != nullptr) {
|
||||
state.bda_pagetable_variable = state.builder.DefineGlobalVariable(
|
||||
TypePointer(state, spv::StorageClassStorageBuffer, BdaPagetableType(state)),
|
||||
spv::StorageClassStorageBuffer);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::FaultBuffer) != nullptr) {
|
||||
state.fault_buffer_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), spv::StorageClassStorageBuffer);
|
||||
}
|
||||
void DefineDescriptors(EmitterState& state) {
|
||||
if (state.program.bindings.UsesPushData() || state.program.stage == ShaderType::Mesh) {
|
||||
const auto pointer_type =
|
||||
TypePointer(state, spv::StorageClassPushConstant, PushConstantBlockType(state));
|
||||
state.push_constant_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, spv::StorageClassPushConstant);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::ShaderData) != nullptr) {
|
||||
state.shader_data_storage_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), spv::StorageClassStorageBuffer);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::FlattenedSrt) != nullptr) {
|
||||
state.flattened_srt_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), spv::StorageClassStorageBuffer);
|
||||
const auto type = PushConstantBlockType(state);
|
||||
state.push_constant_variable = state.builder.DefineGlobalVariable(
|
||||
TypePointer(state, spv::StorageClassPushConstant, type), spv::StorageClassPushConstant);
|
||||
state.builder.AddName(type, "BufferResource");
|
||||
state.builder.AddName(state.push_constant_variable, "vsharp");
|
||||
}
|
||||
for (const auto& binding: state.program.bindings.descriptors) {
|
||||
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
const auto Define = [&](uint32_t type, const char* name,
|
||||
spv::StorageClass storage = spv::StorageClassStorageBuffer) {
|
||||
const auto variable =
|
||||
state.builder.DefineGlobalVariable(TypePointer(state, storage, type), storage);
|
||||
state.builder.AddName(variable, name);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, variable, spv::DecorationDescriptorSet, 0});
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationBinding,
|
||||
IR::NativeBinding(state.program.stage, binding.kind)});
|
||||
return variable;
|
||||
};
|
||||
const auto ArrayType = [&](uint32_t type) {
|
||||
return state.builder.Type(
|
||||
spv::OpTypeArray,
|
||||
{type, ConstantU32(state, static_cast<uint32_t>(binding.resources.size()))});
|
||||
};
|
||||
switch (binding.kind) {
|
||||
case IR::DescriptorBindingKind::Buffers:
|
||||
state.storage_buffer_variable =
|
||||
Define(ArrayType(StorageBufferType(state)), "buffers");
|
||||
if (state.requirements.buffer_int64_atomics) {
|
||||
state.storage_buffer_u64_variable =
|
||||
Define(ArrayType(StorageBufferU64Type(state)), "buffers_u64");
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.storage_buffer_variable, spv::DecorationAliased});
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.storage_buffer_u64_variable,
|
||||
spv::DecorationAliased});
|
||||
}
|
||||
break;
|
||||
case IR::DescriptorBindingKind::BdaPagetable:
|
||||
state.bda_pagetable_variable = Define(StorageBufferU64Type(state), "bda_pagetable");
|
||||
break;
|
||||
case IR::DescriptorBindingKind::FaultBuffer:
|
||||
state.fault_buffer_variable = Define(StorageBufferType(state), "fault_buffer");
|
||||
break;
|
||||
case IR::DescriptorBindingKind::ShaderData:
|
||||
state.shader_data_storage_variable =
|
||||
Define(StorageBufferType(state), "shader_data");
|
||||
break;
|
||||
case IR::DescriptorBindingKind::FlattenedSrt:
|
||||
state.flattened_srt_variable = Define(StorageBufferType(state), "flattened_srt");
|
||||
break;
|
||||
case IR::DescriptorBindingKind::Samplers:
|
||||
state.sampler_variable = Define(ArrayType(state.builder.Type(spv::OpTypeSampler)),
|
||||
"samplers", spv::StorageClassUniformConstant);
|
||||
break;
|
||||
case IR::DescriptorBindingKind::Gds:
|
||||
state.gds_variable = Define(StorageBufferType(state), "gds");
|
||||
break;
|
||||
default: {
|
||||
EXIT_IF(IR::ImageBindingResourceClass(binding.kind) ==
|
||||
IR::ImageResourceClass::None);
|
||||
const auto& image = state.program.info.images.at(binding.resources.front());
|
||||
const auto name = "image_" + std::to_string(static_cast<uint32_t>(binding.kind));
|
||||
state.image_variables[IR::ImageBindingIndex(binding.kind)] =
|
||||
Define(ArrayType(ImageType(state, image)), name.c_str(),
|
||||
spv::StorageClassUniformConstant);
|
||||
if (image.dimension == ImageDimension::Dim1D ||
|
||||
image.dimension == ImageDimension::Dim1DArray) {
|
||||
state.builder.RequireCapability(image.resource_class ==
|
||||
IR::ImageResourceClass::Sampled
|
||||
? spv::CapabilitySampled1D
|
||||
: spv::CapabilityImage1D);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto& image = state.program.info.images.at(binding.resources.front());
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, binding.kind));
|
||||
const auto image_type = ImageType(state, image);
|
||||
const auto array_type = state.builder.Type(spv::OpTypeArray, {image_type, count});
|
||||
const auto pointer_type = TypePointer(state, spv::StorageClassUniformConstant, array_type);
|
||||
state.image_variables[IR::ImageBindingIndex(binding.kind)] =
|
||||
state.builder.DefineGlobalVariable(pointer_type, spv::StorageClassUniformConstant);
|
||||
if (image.dimension == ImageDimension::Dim1D ||
|
||||
image.dimension == ImageDimension::Dim1DArray) {
|
||||
const auto capability = image.resource_class == IR::ImageResourceClass::Sampled
|
||||
? spv::CapabilitySampled1D
|
||||
: spv::CapabilityImage1D;
|
||||
state.builder.RequireCapability(capability);
|
||||
}
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
||||
const auto sampler_type = state.builder.Type(spv::OpTypeSampler);
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Samplers));
|
||||
const auto array_type = state.builder.Type(spv::OpTypeArray, {sampler_type, count});
|
||||
const auto pointer_type = TypePointer(state, spv::StorageClassUniformConstant, array_type);
|
||||
state.sampler_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, spv::StorageClassUniformConstant);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Gds) != nullptr) {
|
||||
state.gds_variable = state.builder.DefineGlobalVariable(TypeStorageBufferPointer(state),
|
||||
spv::StorageClassStorageBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const IR::DescriptorBinding* DescriptorBinding(const EmitterState& state,
|
||||
IR::DescriptorBindingKind kind) {
|
||||
return IR::FindBinding(state.program.bindings, kind);
|
||||
}
|
||||
|
||||
uint32_t DescriptorCount(const EmitterState& state, IR::DescriptorBindingKind kind) {
|
||||
const auto* binding = DescriptorBinding(state, kind);
|
||||
return binding != nullptr ? static_cast<uint32_t>(binding->resources.size()) : 0;
|
||||
}
|
||||
|
||||
uint32_t ConstantU32(EmitterState& state, uint32_t value) {
|
||||
return state.builder.Constant(spv::OpConstant, TypeU32(state), {value});
|
||||
}
|
||||
@@ -348,127 +330,17 @@ uint32_t VertexParameterScalarType(EmitterState& state, VertexInputScalarKind ki
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VertexParameterInputPointerType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components) {
|
||||
switch (kind) {
|
||||
case VertexInputScalarKind::Sint:
|
||||
switch (components) {
|
||||
case 1: return TypePointer(state, spv::StorageClassInput, TypeI32(state));
|
||||
case 2: return TypePointer(state, spv::StorageClassInput, TypeI32Vector(state, 2));
|
||||
case 3: return TypePointer(state, spv::StorageClassInput, TypeI32Vector(state, 3));
|
||||
default: return TypePointer(state, spv::StorageClassInput, TypeI32Vector(state, 4));
|
||||
}
|
||||
case VertexInputScalarKind::Uint:
|
||||
switch (components) {
|
||||
case 1: return TypePointer(state, spv::StorageClassInput, TypeU32(state));
|
||||
case 2: return TypePointer(state, spv::StorageClassInput, TypeU32Vector(state, 2));
|
||||
case 3: return TypePointer(state, spv::StorageClassInput, TypeU32Vector(state, 3));
|
||||
default: return TypePointer(state, spv::StorageClassInput, TypeU32Vector(state, 4));
|
||||
}
|
||||
case VertexInputScalarKind::Float:
|
||||
default:
|
||||
switch (components) {
|
||||
case 1: return TypePointer(state, spv::StorageClassInput, TypeF32(state));
|
||||
case 2: return TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 2));
|
||||
case 3: return TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 3));
|
||||
default: return TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace {
|
||||
|
||||
static bool MrtUsesUintOutput(const EmitterState& state, uint32_t index) {
|
||||
return state.program.stage == ShaderType::Pixel &&
|
||||
index < std::size(state.input_info.pixel->target_output_mode) &&
|
||||
state.input_info.pixel->target_output_mode[index] == 7u;
|
||||
}
|
||||
|
||||
void AllocateInputVariables(EmitterState& state) {
|
||||
if (state.lane_count == 2) {
|
||||
const auto add_builtin = [&](IR::StageInputKind kind, uint32_t components,
|
||||
const char* name) {
|
||||
if (std::ranges::none_of(state.inputs, [kind](const InputBinding& input) {
|
||||
return input.kind == kind;
|
||||
})) {
|
||||
state.inputs.push_back({kind, 0, components, 0, name});
|
||||
}
|
||||
};
|
||||
add_builtin(IR::StageInputKind::LocalInvocationIndex, 1, "gl_LocalInvocationIndex");
|
||||
if (std::ranges::any_of(state.inputs, [](const InputBinding& input) {
|
||||
return input.kind == IR::StageInputKind::GlobalInvocationId;
|
||||
})) {
|
||||
add_builtin(IR::StageInputKind::WorkgroupId, 3, "gl_WorkGroupID");
|
||||
}
|
||||
}
|
||||
for (auto& binding: state.inputs) {
|
||||
binding.variable_id = state.builder.AllocateId();
|
||||
state.interface_variables.push_back(binding.variable_id);
|
||||
}
|
||||
if (state.requirements.subgroup_local_invocation_id) {
|
||||
state.subgroup_local_invocation_id_variable = state.builder.AllocateId();
|
||||
state.interface_variables.push_back(state.subgroup_local_invocation_id_variable);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t AllocateInterfaceVariable(EmitterState& state) {
|
||||
const auto variable = state.builder.AllocateId();
|
||||
uint32_t DefineInterfaceVariable(EmitterState& state, uint32_t type, spv::StorageClass storage,
|
||||
const char* name) {
|
||||
const auto variable =
|
||||
state.builder.DefineGlobalVariable(TypePointer(state, storage, type), storage);
|
||||
state.interface_variables.push_back(variable);
|
||||
state.builder.AddName(variable, name);
|
||||
return variable;
|
||||
}
|
||||
|
||||
static uint32_t AllocateSharedOutputVariable(EmitterState& state, uint32_t& variable) {
|
||||
if (variable == 0) {
|
||||
variable = AllocateInterfaceVariable(state);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
void AllocateOutputVariables(EmitterState& state) {
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
DefineMeshOutputs(state);
|
||||
return;
|
||||
}
|
||||
for (auto& binding: state.outputs) {
|
||||
switch (binding.kind) {
|
||||
case IR::StageOutputKind::Position:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.per_vertex_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::PointSize:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.point_size_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::ClipDistance:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.clip_distance_variable);
|
||||
state.clip_distance_count = std::max(state.clip_distance_count, binding.index + 1);
|
||||
break;
|
||||
case IR::StageOutputKind::CullDistance:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.cull_distance_variable);
|
||||
state.cull_distance_count = std::max(state.cull_distance_count, binding.index + 1);
|
||||
break;
|
||||
case IR::StageOutputKind::Layer:
|
||||
binding.variable_id = AllocateSharedOutputVariable(state, state.layer_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::ViewportIndex:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.viewport_index_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::Depth:
|
||||
binding.variable_id = AllocateSharedOutputVariable(state, state.depth_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::SampleMask:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.sample_mask_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::Parameter:
|
||||
case IR::StageOutputKind::Mrt:
|
||||
binding.variable_id = AllocateInterfaceVariable(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BuiltInForInput(IR::StageInputKind kind) {
|
||||
switch (kind) {
|
||||
case IR::StageInputKind::VertexIndex: return spv::BuiltInVertexIndex;
|
||||
@@ -487,21 +359,60 @@ uint32_t BuiltInForInput(IR::StageInputKind kind) {
|
||||
}
|
||||
}
|
||||
|
||||
void AddInputAnnotationsAndNames(EmitterState& state) {
|
||||
if (state.subgroup_local_invocation_id_variable != 0) {
|
||||
state.builder.AddName(state.subgroup_local_invocation_id_variable,
|
||||
"gl_SubgroupInvocationID");
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.subgroup_local_invocation_id_variable,
|
||||
spv::DecorationBuiltIn,
|
||||
spv::BuiltInSubgroupLocalInvocationId});
|
||||
if (state.program.stage == ShaderType::Pixel) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate,
|
||||
state.subgroup_local_invocation_id_variable,
|
||||
spv::DecorationFlat});
|
||||
void DefineInputs(EmitterState& state) {
|
||||
state.inputs.reserve(state.program.info.inputs.size());
|
||||
for (const auto& input: state.program.info.inputs) {
|
||||
state.inputs.push_back({input});
|
||||
}
|
||||
if (state.lane_count == 2) {
|
||||
const auto add_builtin = [&](IR::StageInputKind kind, uint32_t components,
|
||||
const char* name) {
|
||||
if (std::ranges::none_of(state.inputs, [kind](const InputBinding& input) {
|
||||
return input.kind == kind;
|
||||
})) {
|
||||
state.inputs.push_back({{kind, 0, components, name}});
|
||||
}
|
||||
};
|
||||
add_builtin(IR::StageInputKind::LocalInvocationIndex, 1, "gl_LocalInvocationIndex");
|
||||
if (std::ranges::any_of(state.inputs, [](const InputBinding& input) {
|
||||
return input.kind == IR::StageInputKind::GlobalInvocationId;
|
||||
})) {
|
||||
add_builtin(IR::StageInputKind::WorkgroupId, 3, "gl_WorkGroupID");
|
||||
}
|
||||
}
|
||||
for (const auto& input: state.inputs) {
|
||||
state.builder.AddName(input.variable_id, input.debug_name.c_str());
|
||||
for (auto& input: state.inputs) {
|
||||
uint32_t type = TypeU32(state);
|
||||
switch (input.kind) {
|
||||
case IR::StageInputKind::VertexIndex:
|
||||
case IR::StageInputKind::InstanceIndex:
|
||||
case IR::StageInputKind::Layer:
|
||||
case IR::StageInputKind::SampleId: type = TypeI32(state); break;
|
||||
case IR::StageInputKind::WorkgroupId:
|
||||
case IR::StageInputKind::LocalInvocationId:
|
||||
case IR::StageInputKind::GlobalInvocationId: type = TypeU32Vector(state, 3); break;
|
||||
case IR::StageInputKind::FragCoord: type = TypeF32Vector(state, 4); break;
|
||||
case IR::StageInputKind::BaryCoordSmooth:
|
||||
case IR::StageInputKind::BaryCoordNoPerspective: type = TypeF32Vector(state, 3); break;
|
||||
case IR::StageInputKind::FrontFacing: type = TypeBool(state); break;
|
||||
case IR::StageInputKind::Parameter:
|
||||
if (state.program.stage == ShaderType::Vertex) {
|
||||
type = VertexParameterScalarType(
|
||||
state, VertexParameterScalarKind(state, input.location));
|
||||
const auto components = VertexParameterComponentCount(input);
|
||||
if (components > 1u) {
|
||||
type = state.builder.Type(spv::OpTypeVector, {type, components});
|
||||
}
|
||||
} else if (input.per_vertex) {
|
||||
type = state.builder.Type(spv::OpTypeArray,
|
||||
{TypeF32Vector(state, 4), ConstantU32(state, 3)});
|
||||
} else {
|
||||
type = TypeF32Vector(state, 4);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
input.variable_id =
|
||||
DefineInterfaceVariable(state, type, spv::StorageClassInput, input.debug_name.c_str());
|
||||
if (input.kind == IR::StageInputKind::Layer || input.kind == IR::StageInputKind::SampleId) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, input.variable_id, spv::DecorationFlat});
|
||||
}
|
||||
@@ -519,126 +430,119 @@ void AddInputAnnotationsAndNames(EmitterState& state) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationNoPerspective});
|
||||
}
|
||||
const auto location = PixelParameterLocation(state, input.location);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationLocation, location});
|
||||
continue;
|
||||
}
|
||||
const auto builtin = BuiltInForInput(input.kind);
|
||||
if (builtin != UINT32_MAX) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, input.variable_id,
|
||||
spv::DecorationLocation,
|
||||
PixelParameterLocation(state, input.location)});
|
||||
} else if (const auto builtin = BuiltInForInput(input.kind); builtin != UINT32_MAX) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationBuiltIn, builtin});
|
||||
}
|
||||
}
|
||||
if (state.requirements.subgroup_local_invocation_id) {
|
||||
const auto variable = DefineInterfaceVariable(state, TypeU32(state), spv::StorageClassInput,
|
||||
"gl_SubgroupInvocationID");
|
||||
state.subgroup_local_invocation_id_variable = variable;
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationBuiltIn,
|
||||
spv::BuiltInSubgroupLocalInvocationId});
|
||||
if (state.program.stage == ShaderType::Pixel) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationFlat});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddOutputAnnotationsAndNames(EmitterState& state) {
|
||||
void DefineOutputs(EmitterState& state) {
|
||||
state.outputs.reserve(state.program.info.outputs.size());
|
||||
uint32_t clip_distance_count = 0;
|
||||
uint32_t cull_distance_count = 0;
|
||||
for (const auto& output: state.program.info.outputs) {
|
||||
state.outputs.push_back({output});
|
||||
if (output.kind == IR::StageOutputKind::ClipDistance) {
|
||||
clip_distance_count = std::max(clip_distance_count, output.index + 1);
|
||||
} else if (output.kind == IR::StageOutputKind::CullDistance) {
|
||||
cull_distance_count = std::max(cull_distance_count, output.index + 1);
|
||||
}
|
||||
}
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
DefineMeshOutputs(state);
|
||||
return;
|
||||
}
|
||||
if (state.per_vertex_variable != 0) {
|
||||
state.builder.AddName(PerVertexType(state), "gl_PerVertex");
|
||||
state.builder.AddName(state.per_vertex_variable, "outPerVertex");
|
||||
}
|
||||
auto AddBuiltIn = [&](uint32_t variable, const char* name, uint32_t builtin) {
|
||||
if (variable != 0) {
|
||||
state.builder.AddName(variable, name);
|
||||
const auto BuiltIn = [&](uint32_t& variable, uint32_t type, const char* name,
|
||||
spv::BuiltIn builtin) {
|
||||
if (variable == 0) {
|
||||
variable = DefineInterfaceVariable(state, type, spv::StorageClassOutput, name);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, variable, spv::DecorationBuiltIn, builtin});
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
AddBuiltIn(state.point_size_variable, "gl_PointSize", spv::BuiltInPointSize);
|
||||
AddBuiltIn(state.clip_distance_variable, "gl_ClipDistance", spv::BuiltInClipDistance);
|
||||
AddBuiltIn(state.cull_distance_variable, "gl_CullDistance", spv::BuiltInCullDistance);
|
||||
AddBuiltIn(state.layer_variable, "gl_Layer", spv::BuiltInLayer);
|
||||
AddBuiltIn(state.viewport_index_variable, "gl_ViewportIndex", spv::BuiltInViewportIndex);
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.AddName(state.depth_variable, "gl_FragDepth");
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.depth_variable, spv::DecorationBuiltIn, spv::BuiltInFragDepth});
|
||||
}
|
||||
if (state.sample_mask_variable != 0) {
|
||||
state.builder.AddName(state.sample_mask_variable, "gl_SampleMask");
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.sample_mask_variable,
|
||||
spv::DecorationBuiltIn, spv::BuiltInSampleMask});
|
||||
}
|
||||
for (const auto& binding: state.outputs) {
|
||||
if (binding.kind == IR::StageOutputKind::Parameter ||
|
||||
binding.kind == IR::StageOutputKind::Mrt) {
|
||||
state.builder.AddName(binding.variable_id, binding.debug_name.c_str());
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, binding.variable_id, spv::DecorationLocation, binding.location});
|
||||
for (auto& binding: state.outputs) {
|
||||
switch (binding.kind) {
|
||||
case IR::StageOutputKind::Position:
|
||||
if (state.per_vertex_variable == 0) {
|
||||
const auto type = PerVertexType(state);
|
||||
state.builder.AddName(type, "gl_PerVertex");
|
||||
state.per_vertex_variable = DefineInterfaceVariable(
|
||||
state, type, spv::StorageClassOutput, "outPerVertex");
|
||||
}
|
||||
binding.variable_id = state.per_vertex_variable;
|
||||
break;
|
||||
case IR::StageOutputKind::PointSize:
|
||||
binding.variable_id = BuiltIn(state.point_size_variable, TypeF32(state),
|
||||
"gl_PointSize", spv::BuiltInPointSize);
|
||||
break;
|
||||
case IR::StageOutputKind::ClipDistance:
|
||||
binding.variable_id =
|
||||
BuiltIn(state.clip_distance_variable, F32ArrayType(state, clip_distance_count),
|
||||
"gl_ClipDistance", spv::BuiltInClipDistance);
|
||||
break;
|
||||
case IR::StageOutputKind::CullDistance:
|
||||
binding.variable_id =
|
||||
BuiltIn(state.cull_distance_variable, F32ArrayType(state, cull_distance_count),
|
||||
"gl_CullDistance", spv::BuiltInCullDistance);
|
||||
break;
|
||||
case IR::StageOutputKind::Layer:
|
||||
binding.variable_id =
|
||||
BuiltIn(state.layer_variable, TypeU32(state), "gl_Layer", spv::BuiltInLayer);
|
||||
break;
|
||||
case IR::StageOutputKind::ViewportIndex:
|
||||
binding.variable_id = BuiltIn(state.viewport_index_variable, TypeU32(state),
|
||||
"gl_ViewportIndex", spv::BuiltInViewportIndex);
|
||||
break;
|
||||
case IR::StageOutputKind::Depth:
|
||||
binding.variable_id = BuiltIn(state.depth_variable, TypeF32(state), "gl_FragDepth",
|
||||
spv::BuiltInFragDepth);
|
||||
break;
|
||||
case IR::StageOutputKind::SampleMask:
|
||||
binding.variable_id =
|
||||
BuiltIn(state.sample_mask_variable, SampleMaskArrayType(state), "gl_SampleMask",
|
||||
spv::BuiltInSampleMask);
|
||||
break;
|
||||
case IR::StageOutputKind::Parameter:
|
||||
case IR::StageOutputKind::Mrt: {
|
||||
const bool uint_output =
|
||||
binding.kind == IR::StageOutputKind::Mrt &&
|
||||
state.program.stage == ShaderType::Pixel &&
|
||||
binding.index < std::size(state.input_info.pixel->target_output_mode) &&
|
||||
state.input_info.pixel->target_output_mode[binding.index] == 7u;
|
||||
const auto type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
|
||||
binding.variable_id = DefineInterfaceVariable(state, type, spv::StorageClassOutput,
|
||||
binding.debug_name.c_str());
|
||||
state.builder.AddAnnotation({spv::OpDecorate, binding.variable_id,
|
||||
spv::DecorationLocation, binding.location});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecorateDescriptor(EmitterState& state, uint32_t variable, const char* name,
|
||||
IR::DescriptorBindingKind kind) {
|
||||
if (variable == 0) {
|
||||
return;
|
||||
}
|
||||
state.builder.AddName(variable, name);
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationDescriptorSet, 0});
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationBinding,
|
||||
IR::NativeBinding(state.program.stage, kind)});
|
||||
}
|
||||
|
||||
void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
||||
auto Decorate = [&](uint32_t variable, const char* name, IR::DescriptorBindingKind kind) {
|
||||
DecorateDescriptor(state, variable, name, kind);
|
||||
};
|
||||
if (state.storage_buffer_variable != 0) {
|
||||
Decorate(state.storage_buffer_variable, "buffers", IR::DescriptorBindingKind::Buffers);
|
||||
}
|
||||
if (state.storage_buffer_u64_variable != 0) {
|
||||
Decorate(state.storage_buffer_u64_variable, "buffers_u64",
|
||||
IR::DescriptorBindingKind::Buffers);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.storage_buffer_variable, spv::DecorationAliased});
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.storage_buffer_u64_variable, spv::DecorationAliased});
|
||||
}
|
||||
if (state.bda_pagetable_variable != 0) {
|
||||
Decorate(state.bda_pagetable_variable, "bda_pagetable",
|
||||
IR::DescriptorBindingKind::BdaPagetable);
|
||||
}
|
||||
if (state.fault_buffer_variable != 0) {
|
||||
Decorate(state.fault_buffer_variable, "fault_buffer",
|
||||
IR::DescriptorBindingKind::FaultBuffer);
|
||||
}
|
||||
for (const auto& binding: state.program.bindings.descriptors) {
|
||||
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
}
|
||||
const auto name = "image_" + std::to_string(static_cast<uint32_t>(binding.kind));
|
||||
Decorate(state.image_variables[IR::ImageBindingIndex(binding.kind)], name.c_str(),
|
||||
binding.kind);
|
||||
}
|
||||
if (state.sampler_variable != 0) {
|
||||
Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);
|
||||
}
|
||||
if (state.gds_variable != 0) {
|
||||
Decorate(state.gds_variable, "gds", IR::DescriptorBindingKind::Gds);
|
||||
}
|
||||
if (state.flattened_srt_variable != 0) {
|
||||
Decorate(state.flattened_srt_variable, "flattened_srt",
|
||||
IR::DescriptorBindingKind::FlattenedSrt);
|
||||
}
|
||||
}
|
||||
|
||||
void AddVsharpAnnotationsAndNames(EmitterState& state) {
|
||||
if (state.push_constant_variable != 0) {
|
||||
state.builder.AddName(PushConstantBlockType(state), "BufferResource");
|
||||
state.builder.AddName(state.push_constant_variable, "vsharp");
|
||||
}
|
||||
if (state.shader_data_storage_variable != 0) {
|
||||
DecorateDescriptor(state, state.shader_data_storage_variable, "shader_data",
|
||||
IR::DescriptorBindingKind::ShaderData);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DefineModule(EmitterState& state) {
|
||||
DefineDescriptorVariables(state);
|
||||
state.interface_variables.reserve(state.program.info.inputs.size() +
|
||||
state.program.info.outputs.size());
|
||||
DefineInputs(state);
|
||||
DefineOutputs(state);
|
||||
DefineDescriptors(state);
|
||||
if (state.requirements.function_lds) {
|
||||
state.lds_variable = state.builder.AllocateId();
|
||||
}
|
||||
@@ -647,7 +551,7 @@ void DefineModule(EmitterState& state) {
|
||||
state.scratch_variable[half] = state.builder.AllocateId();
|
||||
}
|
||||
}
|
||||
state.main_func = state.builder.AllocateId();
|
||||
state.main_func = state.builder.AllocateId();
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
state.mesh_guest_func = state.builder.AllocateId();
|
||||
state.builder.RequireCapability(spv::CapabilityMeshShadingEXT); // MeshShadingEXT
|
||||
@@ -767,117 +671,6 @@ void DefineModule(EmitterState& state) {
|
||||
state.builder.AddName(state.scratch_variable[half], "scratch_dwords");
|
||||
}
|
||||
}
|
||||
AddInputAnnotationsAndNames(state);
|
||||
AddOutputAnnotationsAndNames(state);
|
||||
AddDescriptorAnnotationsAndNames(state);
|
||||
AddVsharpAnnotationsAndNames(state);
|
||||
|
||||
if (state.subgroup_local_invocation_id_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.subgroup_local_invocation_id_variable,
|
||||
TypePointer(state, spv::StorageClassInput, TypeU32(state)), spv::StorageClassInput);
|
||||
}
|
||||
for (const auto& input: state.inputs) {
|
||||
uint32_t ptr_type = TypePointer(state, spv::StorageClassInput, TypeU32(state));
|
||||
switch (input.kind) {
|
||||
case IR::StageInputKind::VertexIndex:
|
||||
case IR::StageInputKind::InstanceIndex:
|
||||
case IR::StageInputKind::Layer:
|
||||
case IR::StageInputKind::SampleId:
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeI32(state));
|
||||
break;
|
||||
case IR::StageInputKind::WorkgroupId:
|
||||
case IR::StageInputKind::LocalInvocationId:
|
||||
case IR::StageInputKind::GlobalInvocationId:
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeU32Vector(state, 3));
|
||||
break;
|
||||
case IR::StageInputKind::FragCoord:
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 4));
|
||||
break;
|
||||
case IR::StageInputKind::BaryCoordSmooth:
|
||||
case IR::StageInputKind::BaryCoordNoPerspective:
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 3));
|
||||
break;
|
||||
case IR::StageInputKind::FrontFacing:
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeBool(state));
|
||||
break;
|
||||
case IR::StageInputKind::Parameter:
|
||||
if (state.program.stage == ShaderType::Vertex) {
|
||||
const auto kind = VertexParameterScalarKind(state, input.location);
|
||||
const auto components = VertexParameterComponentCount(input);
|
||||
ptr_type = VertexParameterInputPointerType(state, kind, components);
|
||||
} else if (input.per_vertex) {
|
||||
const auto array_type = state.builder.Type(
|
||||
spv::OpTypeArray, {TypeF32Vector(state, 4), ConstantU32(state, 3)});
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, array_type);
|
||||
} else {
|
||||
ptr_type = TypePointer(state, spv::StorageClassInput, TypeF32Vector(state, 4));
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
state.builder.DefineGlobalVariable(input.variable_id, ptr_type, spv::StorageClassInput);
|
||||
}
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
return;
|
||||
}
|
||||
if (state.per_vertex_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.per_vertex_variable,
|
||||
TypePointer(state, spv::StorageClassOutput, PerVertexType(state)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.point_size_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.point_size_variable, TypePointer(state, spv::StorageClassOutput, TypeF32(state)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.clip_distance_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.clip_distance_variable,
|
||||
TypePointer(state, spv::StorageClassOutput,
|
||||
F32ArrayType(state, state.clip_distance_count)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.cull_distance_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.cull_distance_variable,
|
||||
TypePointer(state, spv::StorageClassOutput,
|
||||
F32ArrayType(state, state.cull_distance_count)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.layer_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.layer_variable, TypePointer(state, spv::StorageClassOutput, TypeU32(state)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.viewport_index_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.viewport_index_variable,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeU32(state)), spv::StorageClassOutput);
|
||||
}
|
||||
for (const auto& binding: state.outputs) {
|
||||
if (binding.kind == IR::StageOutputKind::Parameter ||
|
||||
binding.kind == IR::StageOutputKind::Mrt) {
|
||||
const auto pointer_type =
|
||||
binding.kind == IR::StageOutputKind::Mrt && MrtUsesUintOutput(state, binding.index)
|
||||
? TypePointer(state, spv::StorageClassOutput, TypeU32Vector(state, 4))
|
||||
: TypePointer(state, spv::StorageClassOutput, TypeF32Vector(state, 4));
|
||||
state.builder.DefineGlobalVariable(binding.variable_id, pointer_type,
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
}
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.depth_variable, TypePointer(state, spv::StorageClassOutput, TypeF32(state)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
if (state.sample_mask_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.sample_mask_variable,
|
||||
TypePointer(state, spv::StorageClassOutput, SampleMaskArrayType(state)),
|
||||
spv::StorageClassOutput);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter
|
||||
|
||||
Reference in New Issue
Block a user