mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
refactor(shader): emit SPIR-V declarations on demand
This commit is contained in:
1 parent
e1bcc298a0
commit
d34e30d892
20 files changed
+1629
-1495
No files matched your search
@@ -25,7 +25,8 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabili
|
||||
vk::ShaderStageFlagBits stage,
|
||||
const ShaderRecompiler::IR::Program& program) {
|
||||
const auto guest_wave_size = program.wave_size;
|
||||
if (guest_wave_size != 32u && guest_wave_size != 64u) {
|
||||
if ((guest_wave_size != 32u && guest_wave_size != 64u) ||
|
||||
!program.spirv_requirements.has_value()) {
|
||||
return {};
|
||||
}
|
||||
if (stage != vk::ShaderStageFlagBits::eCompute) {
|
||||
@@ -51,7 +52,7 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabili
|
||||
guest_wave_size <= capabilities.max_subgroup_size) {
|
||||
return {ShaderSubgroupMode::Controlled, guest_wave_size};
|
||||
}
|
||||
if (!ShaderRecompiler::Spirv::GetProgramRequirements(program).requires_exact_subgroup) {
|
||||
if (!program.spirv_requirements->requires_exact_subgroup) {
|
||||
return {ShaderSubgroupMode::FlattenedMasks, 0};
|
||||
}
|
||||
return {};
|
||||
|
||||
@@ -942,7 +942,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
|
||||
if (!IR::AllocateBindings(ir, layout_options, error)) {
|
||||
return false;
|
||||
}
|
||||
ir.spirv_requirements = Spirv::GetProgramRequirements(ir);
|
||||
Spirv::AnalyzeProgramRequirements(ir);
|
||||
std::string ir_dump;
|
||||
if (options.dump_ir) {
|
||||
ir_dump = MakeIrDump(cfg, ir);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include "graphics/shader/recompiler/backend/spirv/SpirvBuilder.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
|
||||
static constexpr size_t InitialSpirvSectionReserve = 4096;
|
||||
static constexpr size_t InitialSpirvFunctionSectionReserve = 450000;
|
||||
static constexpr size_t InitialSpirvFunctionSectionReserve = 32768;
|
||||
|
||||
static void AppendInstructionWords(std::vector<uint32_t>& section, const uint32_t* words,
|
||||
size_t words_num) {
|
||||
@@ -22,7 +21,7 @@ static void AppendInstructionWords(std::vector<uint32_t>& section, const uint32_
|
||||
Builder::Builder(uint32_t version): m_version(version) {
|
||||
m_debug.reserve(InitialSpirvSectionReserve);
|
||||
m_annotations.reserve(InitialSpirvSectionReserve);
|
||||
m_types.reserve(InitialSpirvSectionReserve);
|
||||
m_declarations.reserve(InitialSpirvSectionReserve);
|
||||
m_functions.reserve(InitialSpirvFunctionSectionReserve);
|
||||
}
|
||||
|
||||
@@ -30,6 +29,110 @@ uint32_t Builder::AllocateId() {
|
||||
return m_next_id++;
|
||||
}
|
||||
|
||||
void Builder::RequireCapability(uint32_t capability) {
|
||||
if (m_required_capabilities.insert(capability).second) {
|
||||
AddCapability({capability});
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::RequireExtension(const char* name) {
|
||||
if (m_required_extensions.emplace(name).second) {
|
||||
AddExtension(name);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Builder::Import(const char* name) {
|
||||
if (const auto it = m_import_ids.find(name); it != m_import_ids.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto id = AllocateId();
|
||||
m_import_ids.emplace(name, id);
|
||||
AddExtInstImport(id, name);
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::Type(uint32_t opcode, std::initializer_list<uint32_t> operands) {
|
||||
return Type(opcode, std::vector<uint32_t>(operands));
|
||||
}
|
||||
|
||||
uint32_t Builder::Type(uint32_t opcode, const std::vector<uint32_t>& operands) {
|
||||
std::vector<uint32_t> key;
|
||||
key.reserve(operands.size() + 2u);
|
||||
key.push_back(opcode);
|
||||
key.push_back(static_cast<uint32_t>(operands.size()));
|
||||
key.insert(key.end(), operands.begin(), operands.end());
|
||||
if (const auto it = m_declaration_ids.find(key); it != m_declaration_ids.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto id = AllocateId();
|
||||
m_declaration_ids.emplace(std::move(key), id);
|
||||
std::vector<uint32_t> words {opcode, id};
|
||||
words.insert(words.end(), operands.begin(), operands.end());
|
||||
AppendInstructionWords(m_declarations, words.data(), words.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::DecoratedType(uint32_t opcode, std::initializer_list<uint32_t> operands,
|
||||
std::initializer_list<TypeAnnotation> annotations) {
|
||||
if (annotations.size() == 0) {
|
||||
return Type(opcode, operands);
|
||||
}
|
||||
std::vector<uint32_t> key {opcode, static_cast<uint32_t>(operands.size())};
|
||||
key.insert(key.end(), operands.begin(), operands.end());
|
||||
key.push_back(static_cast<uint32_t>(annotations.size()));
|
||||
for (const auto& annotation: annotations) {
|
||||
key.push_back(annotation.opcode);
|
||||
key.push_back(static_cast<uint32_t>(annotation.operands.size()));
|
||||
key.insert(key.end(), annotation.operands.begin(), annotation.operands.end());
|
||||
}
|
||||
if (const auto it = m_declaration_ids.find(key); it != m_declaration_ids.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto id = AllocateId();
|
||||
m_declaration_ids.emplace(std::move(key), id);
|
||||
std::vector<uint32_t> words {opcode, id};
|
||||
words.insert(words.end(), operands.begin(), operands.end());
|
||||
AppendInstructionWords(m_declarations, words.data(), words.size());
|
||||
for (const auto& annotation: annotations) {
|
||||
words = {annotation.opcode, id};
|
||||
words.insert(words.end(), annotation.operands.begin(), annotation.operands.end());
|
||||
AppendInstructionWords(m_annotations, words.data(), words.size());
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::Constant(uint32_t opcode, uint32_t type,
|
||||
std::initializer_list<uint32_t> operands) {
|
||||
return Constant(opcode, type, std::vector<uint32_t>(operands));
|
||||
}
|
||||
|
||||
uint32_t Builder::Constant(uint32_t opcode, uint32_t type, const std::vector<uint32_t>& operands) {
|
||||
std::vector<uint32_t> key;
|
||||
key.reserve(operands.size() + 2u);
|
||||
key.push_back(opcode);
|
||||
key.push_back(type);
|
||||
key.insert(key.end(), operands.begin(), operands.end());
|
||||
if (const auto it = m_declaration_ids.find(key); it != m_declaration_ids.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto id = AllocateId();
|
||||
m_declaration_ids.emplace(std::move(key), id);
|
||||
std::vector<uint32_t> words {opcode, type, id};
|
||||
words.insert(words.end(), operands.begin(), operands.end());
|
||||
AppendInstructionWords(m_declarations, words.data(), words.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::DefineGlobalVariable(uint32_t pointer_type, uint32_t storage_class) {
|
||||
const auto id = AllocateId();
|
||||
DefineGlobalVariable(id, pointer_type, storage_class);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Builder::DefineGlobalVariable(uint32_t id, uint32_t pointer_type, uint32_t storage_class) {
|
||||
AddType({59u, pointer_type, id, storage_class});
|
||||
}
|
||||
|
||||
void Builder::AppendString(std::vector<uint32_t>& words, const char* text) {
|
||||
const auto len = text != nullptr ? std::strlen(text) : 0;
|
||||
const auto word_count = (len + 1u + 3u) / 4u;
|
||||
@@ -103,7 +206,7 @@ void Builder::AddAnnotation(std::initializer_list<uint32_t> words) {
|
||||
}
|
||||
|
||||
void Builder::AddType(std::initializer_list<uint32_t> words) {
|
||||
AppendInstructionWords(m_types, words.begin(), words.size());
|
||||
AppendInstructionWords(m_declarations, words.begin(), words.size());
|
||||
}
|
||||
|
||||
void Builder::AddFunction(std::initializer_list<uint32_t> words) {
|
||||
@@ -115,27 +218,12 @@ void Builder::AddFunction(const std::vector<uint32_t>& words) {
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Builder::Build() const {
|
||||
if (m_debug.size() > InitialSpirvSectionReserve) {
|
||||
std::printf("SPIR-V builder reserve exceeded: section=debug size=%zu reserve=%zu\n",
|
||||
m_debug.size(), InitialSpirvSectionReserve);
|
||||
}
|
||||
if (m_annotations.size() > InitialSpirvSectionReserve) {
|
||||
std::printf("SPIR-V builder reserve exceeded: section=annotations size=%zu reserve=%zu\n",
|
||||
m_annotations.size(), InitialSpirvSectionReserve);
|
||||
}
|
||||
if (m_types.size() > InitialSpirvSectionReserve) {
|
||||
std::printf("SPIR-V builder reserve exceeded: section=types size=%zu reserve=%zu\n",
|
||||
m_types.size(), InitialSpirvSectionReserve);
|
||||
}
|
||||
if (m_functions.size() > InitialSpirvFunctionSectionReserve) {
|
||||
std::printf("SPIR-V builder reserve exceeded: section=functions size=%zu reserve=%zu\n",
|
||||
m_functions.size(), InitialSpirvFunctionSectionReserve);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> module;
|
||||
module.reserve(5u + m_capabilities.size() + m_extensions.size() + m_ext_inst_imports.size() +
|
||||
m_memory_model.size() + m_entry_points.size() + m_execution_modes.size() +
|
||||
m_debug.size() + m_annotations.size() + m_types.size() + m_functions.size());
|
||||
m_debug.size() + m_annotations.size() + m_declarations.size() +
|
||||
m_functions.size());
|
||||
|
||||
module.push_back(0x07230203u);
|
||||
module.push_back(m_version);
|
||||
@@ -151,7 +239,7 @@ std::vector<uint32_t> Builder::Build() const {
|
||||
module.insert(module.end(), m_execution_modes.begin(), m_execution_modes.end());
|
||||
module.insert(module.end(), m_debug.begin(), m_debug.end());
|
||||
module.insert(module.end(), m_annotations.begin(), m_annotations.end());
|
||||
module.insert(module.end(), m_types.begin(), m_types.end());
|
||||
module.insert(module.end(), m_declarations.begin(), m_declarations.end());
|
||||
module.insert(module.end(), m_functions.begin(), m_functions.end());
|
||||
|
||||
return module;
|
||||
|
||||
@@ -4,10 +4,18 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
|
||||
struct TypeAnnotation {
|
||||
uint32_t opcode = 0;
|
||||
std::vector<uint32_t> operands;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
explicit Builder(uint32_t version = 0x00010300u);
|
||||
@@ -15,17 +23,25 @@ public:
|
||||
KYTY_CLASS_DEFAULT_COPY(Builder);
|
||||
|
||||
uint32_t AllocateId();
|
||||
void RequireCapability(uint32_t capability);
|
||||
void RequireExtension(const char* name);
|
||||
uint32_t Import(const char* name);
|
||||
uint32_t Type(uint32_t opcode, std::initializer_list<uint32_t> operands = {});
|
||||
uint32_t Type(uint32_t opcode, const std::vector<uint32_t>& operands);
|
||||
uint32_t DecoratedType(uint32_t opcode, std::initializer_list<uint32_t> operands,
|
||||
std::initializer_list<TypeAnnotation> annotations);
|
||||
uint32_t Constant(uint32_t opcode, uint32_t type,
|
||||
std::initializer_list<uint32_t> operands = {});
|
||||
uint32_t Constant(uint32_t opcode, uint32_t type, const std::vector<uint32_t>& operands);
|
||||
uint32_t DefineGlobalVariable(uint32_t pointer_type, uint32_t storage_class);
|
||||
void DefineGlobalVariable(uint32_t id, uint32_t pointer_type, uint32_t storage_class);
|
||||
|
||||
void AddCapability(std::initializer_list<uint32_t> operands);
|
||||
void AddExtension(const char* name);
|
||||
void AddExtInstImport(uint32_t id, const char* name);
|
||||
void AddMemoryModel(std::initializer_list<uint32_t> operands);
|
||||
void AddEntryPoint(uint32_t execution_model, uint32_t entry_point, const char* name,
|
||||
const std::vector<uint32_t>& interfaces);
|
||||
void AddExecutionMode(std::initializer_list<uint32_t> operands);
|
||||
void AddName(uint32_t target, const char* name);
|
||||
void AddAnnotation(std::initializer_list<uint32_t> words);
|
||||
void AddType(std::initializer_list<uint32_t> words);
|
||||
void AddFunction(std::initializer_list<uint32_t> words);
|
||||
void AddFunction(const std::vector<uint32_t>& words);
|
||||
|
||||
@@ -37,19 +53,27 @@ private:
|
||||
static void AppendInstruction(std::vector<uint32_t>& section, uint32_t opcode,
|
||||
std::initializer_list<uint32_t> operands);
|
||||
static void AppendString(std::vector<uint32_t>& words, const char* text);
|
||||
void AddCapability(std::initializer_list<uint32_t> operands);
|
||||
void AddExtension(const char* name);
|
||||
void AddExtInstImport(uint32_t id, const char* name);
|
||||
void AddType(std::initializer_list<uint32_t> words);
|
||||
|
||||
uint32_t m_next_id = 1;
|
||||
uint32_t m_version = 0;
|
||||
std::vector<uint32_t> m_capabilities;
|
||||
std::vector<uint32_t> m_extensions;
|
||||
std::vector<uint32_t> m_ext_inst_imports;
|
||||
std::vector<uint32_t> m_memory_model;
|
||||
std::vector<uint32_t> m_entry_points;
|
||||
std::vector<uint32_t> m_execution_modes;
|
||||
std::vector<uint32_t> m_debug;
|
||||
std::vector<uint32_t> m_annotations;
|
||||
std::vector<uint32_t> m_types;
|
||||
std::vector<uint32_t> m_functions;
|
||||
uint32_t m_next_id = 1;
|
||||
uint32_t m_version = 0;
|
||||
std::vector<uint32_t> m_capabilities;
|
||||
std::vector<uint32_t> m_extensions;
|
||||
std::vector<uint32_t> m_ext_inst_imports;
|
||||
std::vector<uint32_t> m_memory_model;
|
||||
std::vector<uint32_t> m_entry_points;
|
||||
std::vector<uint32_t> m_execution_modes;
|
||||
std::vector<uint32_t> m_debug;
|
||||
std::vector<uint32_t> m_annotations;
|
||||
std::vector<uint32_t> m_declarations;
|
||||
std::vector<uint32_t> m_functions;
|
||||
std::set<uint32_t> m_required_capabilities;
|
||||
std::set<std::string> m_required_extensions;
|
||||
std::map<std::string, uint32_t> m_import_ids;
|
||||
std::map<std::vector<uint32_t>, uint32_t> m_declaration_ids;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv
|
||||
|
||||
@@ -232,13 +232,10 @@ static void ReportReserveExceeded(const IR::Program& program, const char* vector
|
||||
InitialEmitterVectorReserve);
|
||||
}
|
||||
|
||||
IR::SpirvRequirements GetProgramRequirements(const IR::Program& program) {
|
||||
if (program.spirv_requirements.has_value()) {
|
||||
return *program.spirv_requirements;
|
||||
}
|
||||
IR::SpirvRequirements requirements;
|
||||
void AnalyzeProgramRequirements(IR::Program& program) {
|
||||
auto& requirements = program.spirv_requirements.emplace();
|
||||
if (program.values == nullptr) {
|
||||
return requirements;
|
||||
return;
|
||||
}
|
||||
const auto MarkExactSubgroup = [&] {
|
||||
requirements.requires_exact_subgroup = true;
|
||||
@@ -277,7 +274,6 @@ IR::SpirvRequirements GetProgramRequirements(const IR::Program& program) {
|
||||
MarkExactSubgroup();
|
||||
requirements.subgroup_shuffle = true;
|
||||
requirements.subgroup_local_invocation_id = true;
|
||||
requirements.function_lds = program.stage != ShaderType::Compute;
|
||||
break;
|
||||
}
|
||||
case IR::ValueOpcode::DataAppend:
|
||||
@@ -333,7 +329,6 @@ IR::SpirvRequirements GetProgramRequirements(const IR::Program& program) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return requirements;
|
||||
}
|
||||
|
||||
bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources,
|
||||
@@ -347,7 +342,8 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc
|
||||
return false;
|
||||
}
|
||||
if (!program.srt_plan_complete || !program.resource_tracking_complete ||
|
||||
!program.shader_info_complete || !program.binding_layout_complete) {
|
||||
!program.shader_info_complete || !program.binding_layout_complete ||
|
||||
!program.spirv_requirements.has_value()) {
|
||||
SetError(error, "SPIR-V emitter requires a fully planned native shader program");
|
||||
return false;
|
||||
}
|
||||
@@ -369,7 +365,6 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc
|
||||
return false;
|
||||
}
|
||||
EmitterState state(program, resources, input_info);
|
||||
const auto requirements = GetProgramRequirements(program);
|
||||
state.stage = program.stage;
|
||||
state.wave_size = program.wave_size;
|
||||
state.per_invocation_masks = program.lane_mask_mode == ShaderLaneMaskMode::PerInvocation;
|
||||
@@ -377,17 +372,9 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc
|
||||
state.outputs.reserve(InitialEmitterVectorReserve);
|
||||
state.interface_variables.reserve(InitialEmitterVectorReserve);
|
||||
CopyProgramInputsAndOutputs(state, program);
|
||||
state.needs_subgroup_ballot = requirements.subgroup_ballot;
|
||||
state.needs_subgroup_shuffle = requirements.subgroup_shuffle;
|
||||
state.needs_subgroup_local_invocation_id = requirements.subgroup_local_invocation_id;
|
||||
state.needs_compute_derivatives = requirements.compute_derivatives;
|
||||
state.needs_image_gather_extended = requirements.image_gather_extended;
|
||||
state.needs_function_lds = requirements.function_lds;
|
||||
state.needs_pixel_valid_mask = requirements.pixel_valid_mask;
|
||||
AllocateInputVariables(state);
|
||||
AllocateOutputVariables(state);
|
||||
AllocateDescriptorVariables(state);
|
||||
EmitHeaderAndTypes(state);
|
||||
DefineModule(state);
|
||||
if (!EmitValueProgram(state, value_program, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
|
||||
IR::SpirvRequirements GetProgramRequirements(const IR::Program& program);
|
||||
void AnalyzeProgramRequirements(IR::Program& program);
|
||||
|
||||
bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources,
|
||||
ShaderStageInputInfo input_info, std::vector<uint32_t>& spirv, std::string* error);
|
||||
|
||||
@@ -32,14 +32,14 @@ uint32_t NewSelect(EmitterState& state, uint32_t type, uint32_t condition, uint3
|
||||
|
||||
Pair ExtractPair(EmitterState& state, uint32_t value) {
|
||||
Pair result {state.builder.AllocateId(), state.builder.AllocateId()};
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, result.low, value, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, result.high, value, 1});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), result.low, value, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), result.high, value, 1});
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t MakePair(EmitterState& state, uint32_t low, uint32_t high) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeConstruct, state.uint_pair_type, result, low, high});
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeU32Pair(state), result, low, high});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -48,76 +48,76 @@ uint32_t Compare64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value,
|
||||
bool not_equal = false) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
const auto high_equal = NewBinary(state, OpIEqual, state.bool_type, lhs.high, rhs.high);
|
||||
const auto low_equal = NewBinary(state, OpIEqual, state.bool_type, lhs.low, rhs.low);
|
||||
const auto high_equal = NewBinary(state, OpIEqual, TypeBool(state), lhs.high, rhs.high);
|
||||
const auto low_equal = NewBinary(state, OpIEqual, TypeBool(state), lhs.low, rhs.low);
|
||||
if (equal_compare) {
|
||||
return NewBinary(
|
||||
state, not_equal ? OpLogicalOr : OpLogicalAnd, state.bool_type,
|
||||
not_equal ? NewUnary(state, OpLogicalNot, state.bool_type, high_equal) : high_equal,
|
||||
not_equal ? NewUnary(state, OpLogicalNot, state.bool_type, low_equal) : low_equal);
|
||||
state, not_equal ? OpLogicalOr : OpLogicalAnd, TypeBool(state),
|
||||
not_equal ? NewUnary(state, OpLogicalNot, TypeBool(state), high_equal) : high_equal,
|
||||
not_equal ? NewUnary(state, OpLogicalNot, TypeBool(state), low_equal) : low_equal);
|
||||
}
|
||||
const auto high_result = NewBinary(state, high_compare, state.bool_type, lhs.high, rhs.high);
|
||||
const auto low_result = NewBinary(state, low_compare, state.bool_type, lhs.low, rhs.low);
|
||||
const auto low_path = NewBinary(state, OpLogicalAnd, state.bool_type, high_equal, low_result);
|
||||
return NewBinary(state, OpLogicalOr, state.bool_type, high_result, low_path);
|
||||
const auto high_result = NewBinary(state, high_compare, TypeBool(state), lhs.high, rhs.high);
|
||||
const auto low_result = NewBinary(state, low_compare, TypeBool(state), lhs.low, rhs.low);
|
||||
const auto low_path = NewBinary(state, OpLogicalAnd, TypeBool(state), high_equal, low_result);
|
||||
return NewBinary(state, OpLogicalOr, TypeBool(state), high_result, low_path);
|
||||
}
|
||||
|
||||
uint32_t EmitAdd64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
const auto carry = EmitAddCarryValues(state, lhs.low, rhs.low, ConstantU32(state, 0));
|
||||
const auto high0 = NewBinary(state, OpIAdd, state.uint_type, lhs.high, rhs.high);
|
||||
const auto high = NewBinary(state, OpIAdd, state.uint_type, high0, carry.carry);
|
||||
const auto high0 = NewBinary(state, OpIAdd, TypeU32(state), lhs.high, rhs.high);
|
||||
const auto high = NewBinary(state, OpIAdd, TypeU32(state), high0, carry.carry);
|
||||
return MakePair(state, carry.sum, high);
|
||||
}
|
||||
|
||||
uint32_t EmitSub64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
const auto low = NewBinary(state, OpISub, state.uint_type, lhs.low, rhs.low);
|
||||
const auto borrow = NewBinary(state, OpULessThan, state.bool_type, lhs.low, rhs.low);
|
||||
const auto low = NewBinary(state, OpISub, TypeU32(state), lhs.low, rhs.low);
|
||||
const auto borrow = NewBinary(state, OpULessThan, TypeBool(state), lhs.low, rhs.low);
|
||||
const auto borrow_u32 =
|
||||
NewSelect(state, state.uint_type, borrow, ConstantU32(state, 1), ConstantU32(state, 0));
|
||||
const auto high0 = NewBinary(state, OpISub, state.uint_type, lhs.high, rhs.high);
|
||||
const auto high = NewBinary(state, OpISub, state.uint_type, high0, borrow_u32);
|
||||
NewSelect(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0));
|
||||
const auto high0 = NewBinary(state, OpISub, TypeU32(state), lhs.high, rhs.high);
|
||||
const auto high = NewBinary(state, OpISub, TypeU32(state), high0, borrow_u32);
|
||||
return MakePair(state, low, high);
|
||||
}
|
||||
|
||||
uint32_t EmitMulHigh(EmitterState& state, uint32_t lhs, uint32_t rhs, bool signed_value) {
|
||||
const auto operand_type = signed_value ? state.int_type : state.uint_type;
|
||||
const auto pair_type = signed_value ? state.int_pair_type : state.uint_pair_type;
|
||||
const auto operand_type = signed_value ? TypeI32(state) : TypeU32(state);
|
||||
const auto pair_type = signed_value ? TypeI32Pair(state) : TypeU32Pair(state);
|
||||
uint32_t lhs_operand = lhs;
|
||||
uint32_t rhs_operand = rhs;
|
||||
if (signed_value) {
|
||||
lhs_operand = NewUnary(state, OpBitcast, state.int_type, lhs);
|
||||
rhs_operand = NewUnary(state, OpBitcast, state.int_type, rhs);
|
||||
lhs_operand = NewUnary(state, OpBitcast, TypeI32(state), lhs);
|
||||
rhs_operand = NewUnary(state, OpBitcast, TypeI32(state), rhs);
|
||||
}
|
||||
const auto extended = state.builder.AllocateId();
|
||||
state.builder.AddFunction({signed_value ? OpSMulExtended : OpUMulExtended, pair_type, extended,
|
||||
lhs_operand, rhs_operand});
|
||||
const auto high = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, operand_type, high, extended, 1});
|
||||
return signed_value ? NewUnary(state, OpBitcast, state.uint_type, high) : high;
|
||||
return signed_value ? NewUnary(state, OpBitcast, TypeU32(state), high) : high;
|
||||
}
|
||||
|
||||
uint32_t EmitMul64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
const auto low = NewBinary(state, OpIMul, state.uint_type, lhs.low, rhs.low);
|
||||
const auto low = NewBinary(state, OpIMul, TypeU32(state), lhs.low, rhs.low);
|
||||
const auto high0 = EmitMulHigh(state, lhs.low, rhs.low, false);
|
||||
const auto high1 = NewBinary(state, OpIMul, state.uint_type, lhs.low, rhs.high);
|
||||
const auto high2 = NewBinary(state, OpIMul, state.uint_type, lhs.high, rhs.low);
|
||||
const auto high1 = NewBinary(state, OpIMul, TypeU32(state), lhs.low, rhs.high);
|
||||
const auto high2 = NewBinary(state, OpIMul, TypeU32(state), lhs.high, rhs.low);
|
||||
return MakePair(state, low,
|
||||
NewBinary(state, OpIAdd, state.uint_type,
|
||||
NewBinary(state, OpIAdd, state.uint_type, high0, high1), high2));
|
||||
NewBinary(state, OpIAdd, TypeU32(state),
|
||||
NewBinary(state, OpIAdd, TypeU32(state), high0, high1), high2));
|
||||
}
|
||||
|
||||
uint32_t EmitBitwise64(EmitterState& state, uint32_t opcode, uint32_t lhs_value,
|
||||
uint32_t rhs_value) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
return MakePair(state, NewBinary(state, opcode, state.uint_type, lhs.low, rhs.low),
|
||||
NewBinary(state, opcode, state.uint_type, lhs.high, rhs.high));
|
||||
return MakePair(state, NewBinary(state, opcode, TypeU32(state), lhs.low, rhs.low),
|
||||
NewBinary(state, opcode, TypeU32(state), lhs.high, rhs.high));
|
||||
}
|
||||
|
||||
uint32_t EmitShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t shift) {
|
||||
@@ -132,31 +132,31 @@ uint32_t EmitShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint3
|
||||
const auto logical = EmitShift64(state, OpShiftRightLogical, value, shift);
|
||||
const auto logical_pair = ExtractPair(state, logical);
|
||||
const auto sign =
|
||||
NewBinary(state, OpSLessThan, state.bool_type, pair.high, ConstantU32(state, 0));
|
||||
NewBinary(state, OpSLessThan, TypeBool(state), pair.high, ConstantU32(state, 0));
|
||||
const auto inverse =
|
||||
NewBinary(state, OpISub, state.uint_type, ConstantU32(state, 64), shift);
|
||||
const auto fill = NewBinary(state, OpShiftLeftLogical, state.uint_type,
|
||||
NewBinary(state, OpISub, TypeU32(state), ConstantU32(state, 64), shift);
|
||||
const auto fill = NewBinary(state, OpShiftLeftLogical, TypeU32(state),
|
||||
ConstantU32(state, 0xffffffffu), inverse);
|
||||
const auto high_shift =
|
||||
NewBinary(state, OpISub, state.uint_type, shift, ConstantU32(state, 32));
|
||||
NewBinary(state, OpISub, TypeU32(state), shift, ConstantU32(state, 32));
|
||||
const auto high_fill = NewSelect(
|
||||
state, state.uint_type,
|
||||
NewBinary(state, OpUGreaterThanEqual, state.bool_type, shift, ConstantU32(state, 32)),
|
||||
state, TypeU32(state),
|
||||
NewBinary(state, OpUGreaterThanEqual, TypeBool(state), shift, ConstantU32(state, 32)),
|
||||
ConstantU32(state, 0xffffffffu), fill);
|
||||
const auto fill_low =
|
||||
NewSelect(state, state.uint_type, sign,
|
||||
NewSelect(state, state.uint_type,
|
||||
NewBinary(state, OpUGreaterThanEqual, state.bool_type, shift,
|
||||
NewSelect(state, TypeU32(state), sign,
|
||||
NewSelect(state, TypeU32(state),
|
||||
NewBinary(state, OpUGreaterThanEqual, TypeBool(state), shift,
|
||||
ConstantU32(state, 32)),
|
||||
NewBinary(state, OpShiftLeftLogical, state.uint_type,
|
||||
NewBinary(state, OpShiftLeftLogical, TypeU32(state),
|
||||
ConstantU32(state, 0xffffffffu), high_shift),
|
||||
ConstantU32(state, 0)),
|
||||
ConstantU32(state, 0));
|
||||
const auto fill_high =
|
||||
NewSelect(state, state.uint_type, sign, high_fill, ConstantU32(state, 0));
|
||||
NewSelect(state, TypeU32(state), sign, high_fill, ConstantU32(state, 0));
|
||||
return MakePair(
|
||||
state, NewBinary(state, OpBitwiseOr, state.uint_type, logical_pair.low, fill_low),
|
||||
NewBinary(state, OpBitwiseOr, state.uint_type, logical_pair.high, fill_high));
|
||||
state, NewBinary(state, OpBitwiseOr, TypeU32(state), logical_pair.low, fill_low),
|
||||
NewBinary(state, OpBitwiseOr, TypeU32(state), logical_pair.high, fill_high));
|
||||
}
|
||||
return MakePair(state, low, high);
|
||||
}
|
||||
@@ -166,15 +166,15 @@ uint32_t EmitFindMsb64(EmitterState& state, uint32_t value) {
|
||||
const auto high_i = state.builder.AllocateId();
|
||||
const auto low_i = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.int_type, high_i, state.glsl_std450, GlslFindUMsb, pair.high});
|
||||
{OpExtInst, TypeI32(state), high_i, GlslStd450(state), GlslFindUMsb, pair.high});
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.int_type, low_i, state.glsl_std450, GlslFindUMsb, pair.low});
|
||||
const auto high = NewUnary(state, OpBitcast, state.uint_type, high_i);
|
||||
const auto low = NewUnary(state, OpBitcast, state.uint_type, low_i);
|
||||
{OpExtInst, TypeI32(state), low_i, GlslStd450(state), GlslFindUMsb, pair.low});
|
||||
const auto high = NewUnary(state, OpBitcast, TypeU32(state), high_i);
|
||||
const auto low = NewUnary(state, OpBitcast, TypeU32(state), low_i);
|
||||
const auto high_nonzero =
|
||||
NewBinary(state, OpINotEqual, state.bool_type, pair.high, ConstantU32(state, 0));
|
||||
return NewSelect(state, state.uint_type, high_nonzero,
|
||||
NewBinary(state, OpIAdd, state.uint_type, high, ConstantU32(state, 32)), low);
|
||||
NewBinary(state, OpINotEqual, TypeBool(state), pair.high, ConstantU32(state, 0));
|
||||
return NewSelect(state, TypeU32(state), high_nonzero,
|
||||
NewBinary(state, OpIAdd, TypeU32(state), high, ConstantU32(state, 32)), low);
|
||||
}
|
||||
|
||||
uint32_t EmitMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool signed_value,
|
||||
@@ -188,10 +188,10 @@ uint32_t EmitMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bo
|
||||
uint32_t EmitMed3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool signed_value) {
|
||||
const auto minimum = EmitMinMax3(state, a, b, c, signed_value, false);
|
||||
const auto maximum = EmitMinMax3(state, a, b, c, signed_value, true);
|
||||
const auto ab = NewBinary(state, OpIAdd, state.uint_type, a, b);
|
||||
const auto abc = NewBinary(state, OpIAdd, state.uint_type, ab, c);
|
||||
return NewBinary(state, OpISub, state.uint_type,
|
||||
NewBinary(state, OpISub, state.uint_type, abc, minimum), maximum);
|
||||
const auto ab = NewBinary(state, OpIAdd, TypeU32(state), a, b);
|
||||
const auto abc = NewBinary(state, OpIAdd, TypeU32(state), ab, c);
|
||||
return NewBinary(state, OpISub, TypeU32(state),
|
||||
NewBinary(state, OpISub, TypeU32(state), abc, minimum), maximum);
|
||||
}
|
||||
|
||||
uint32_t EmitFMinMax3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c, bool max_value) {
|
||||
@@ -204,17 +204,17 @@ uint32_t EmitFMed3(EmitterState& state, uint32_t a, uint32_t b, uint32_t c) {
|
||||
const auto max_ab = EmitMinMaxF32Value(state, a, b, true);
|
||||
const auto high_min = EmitMinMaxF32Value(state, max_ab, c, false);
|
||||
const auto median = EmitMinMaxF32Value(state, min_ab, high_min, true);
|
||||
const auto nan_ab = NewBinary(state, OpLogicalOr, state.bool_type,
|
||||
const auto nan_ab = NewBinary(state, OpLogicalOr, TypeBool(state),
|
||||
EmitClassifyF32(state, a).nan, EmitClassifyF32(state, b).nan);
|
||||
const auto any_nan =
|
||||
NewBinary(state, OpLogicalOr, state.bool_type, nan_ab, EmitClassifyF32(state, c).nan);
|
||||
return NewSelect(state, state.float_type, any_nan, min3, median);
|
||||
NewBinary(state, OpLogicalOr, TypeBool(state), nan_ab, EmitClassifyF32(state, c).nan);
|
||||
return NewSelect(state, TypeF32(state), any_nan, min3, median);
|
||||
}
|
||||
|
||||
uint32_t EmitExt(EmitterState& state, uint32_t type, uint32_t opcode,
|
||||
std::initializer_list<uint32_t> args) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
std::vector<uint32_t> words {OpExtInst, type, result, state.glsl_std450, opcode};
|
||||
std::vector<uint32_t> words {OpExtInst, type, result, GlslStd450(state), opcode};
|
||||
words.insert(words.end(), args.begin(), args.end());
|
||||
state.builder.AddFunction(words);
|
||||
return result;
|
||||
@@ -225,41 +225,41 @@ uint32_t EmitF32ToU32(EmitterState& state, uint32_t src, bool signed_value) {
|
||||
const auto converted_raw = state.builder.AllocateId();
|
||||
if (signed_value) {
|
||||
const auto converted_i = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertFToS, state.int_type, converted_i, trunc});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, converted_raw, converted_i});
|
||||
state.builder.AddFunction({OpConvertFToS, TypeI32(state), converted_i, trunc});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), converted_raw, converted_i});
|
||||
} else {
|
||||
state.builder.AddFunction({OpConvertFToU, state.uint_type, converted_raw, trunc});
|
||||
state.builder.AddFunction({OpConvertFToU, TypeU32(state), converted_raw, trunc});
|
||||
}
|
||||
const auto nan = EmitClassifyF32(state, src).nan;
|
||||
if (signed_value) {
|
||||
const auto below = NewBinary(state, OpFOrdLessThanEqual, state.bool_type, src,
|
||||
const auto below = NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src,
|
||||
ConstantF32(state, 0xcf000000u));
|
||||
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, state.bool_type, src,
|
||||
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src,
|
||||
ConstantF32(state, 0x4f000000u));
|
||||
const auto high = NewSelect(state, state.uint_type, above, ConstantU32(state, 0x7fffffffu),
|
||||
converted_raw);
|
||||
const auto high =
|
||||
NewSelect(state, TypeU32(state), above, ConstantU32(state, 0x7fffffffu), converted_raw);
|
||||
const auto low =
|
||||
NewSelect(state, state.uint_type, below, ConstantU32(state, 0x80000000u), high);
|
||||
return NewSelect(state, state.uint_type, nan, ConstantU32(state, 0), low);
|
||||
NewSelect(state, TypeU32(state), below, ConstantU32(state, 0x80000000u), high);
|
||||
return NewSelect(state, TypeU32(state), nan, ConstantU32(state, 0), low);
|
||||
}
|
||||
const auto below =
|
||||
NewBinary(state, OpFOrdLessThanEqual, state.bool_type, src, ConstantF32(state, 0));
|
||||
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, state.bool_type, src,
|
||||
NewBinary(state, OpFOrdLessThanEqual, TypeBool(state), src, ConstantF32(state, 0));
|
||||
const auto above = NewBinary(state, OpFOrdGreaterThanEqual, TypeBool(state), src,
|
||||
ConstantF32(state, 0x4f800000u));
|
||||
const auto zero = NewBinary(state, OpLogicalOr, state.bool_type, nan, below);
|
||||
const auto zero = NewBinary(state, OpLogicalOr, TypeBool(state), nan, below);
|
||||
const auto high =
|
||||
NewSelect(state, state.uint_type, above, ConstantU32(state, 0xffffffffu), converted_raw);
|
||||
return NewSelect(state, state.uint_type, zero, ConstantU32(state, 0), high);
|
||||
NewSelect(state, TypeU32(state), above, ConstantU32(state, 0xffffffffu), converted_raw);
|
||||
return NewSelect(state, TypeU32(state), zero, ConstantU32(state, 0), high);
|
||||
}
|
||||
|
||||
uint32_t EmitPackHalf(EmitterState& state, uint32_t src) {
|
||||
return EmitExt(state, state.uint_type, GlslPackHalf2x16, {src});
|
||||
return EmitExt(state, TypeU32(state), GlslPackHalf2x16, {src});
|
||||
}
|
||||
|
||||
uint32_t EmitUnpackHalf(EmitterState& state, uint32_t bits) {
|
||||
const auto pair = EmitExt(state, state.vec2_float_type, GlslUnpackHalf2x16, {bits});
|
||||
const auto pair = EmitExt(state, TypeF32Vector(state, 2), GlslUnpackHalf2x16, {bits});
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.float_type, result, pair, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeF32(state), result, pair, 0});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
};
|
||||
const auto ext_unary = [&](uint32_t ext) {
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, ext, {ctx.Arg(inst, 0)}));
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), ext, {ctx.Arg(inst, 0)}));
|
||||
return true;
|
||||
};
|
||||
switch (op) {
|
||||
@@ -299,7 +299,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
case IR::ValueOpcode::ConvertF16F32: {
|
||||
const auto pair = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, pair,
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeF32Vector(state, 2), pair,
|
||||
ctx.Arg(inst, 0), ConstantF32(state, 0)});
|
||||
ctx.Define(inst, EmitPackHalf(state, pair));
|
||||
return true;
|
||||
@@ -314,7 +314,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Define(inst, EmitF32ToU32(state, ctx.Arg(inst, 0), false));
|
||||
return true;
|
||||
case IR::ValueOpcode::ConvertF32S32: {
|
||||
const auto signed_value = NewUnary(state, OpBitcast, state.int_type, ctx.Arg(inst, 0));
|
||||
const auto signed_value = NewUnary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 0));
|
||||
ctx.Emit(inst, OpConvertSToF, IR::Type::F32, {signed_value});
|
||||
return true;
|
||||
}
|
||||
@@ -337,22 +337,20 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
{ctx.Arg(inst, 0), inst.Arg(1).U32()});
|
||||
return true;
|
||||
case IR::ValueOpcode::PackHalf2x16:
|
||||
ctx.Define(inst, EmitExt(state, state.uint_type, GlslPackHalf2x16, {ctx.Arg(inst, 0)}));
|
||||
ctx.Define(inst, EmitExt(state, TypeU32(state), GlslPackHalf2x16, {ctx.Arg(inst, 0)}));
|
||||
return true;
|
||||
case IR::ValueOpcode::PackSnorm2x16:
|
||||
ctx.Define(inst,
|
||||
EmitExt(state, state.uint_type, GlslPackSnorm2x16, {ctx.Arg(inst, 0)}));
|
||||
ctx.Define(inst, EmitExt(state, TypeU32(state), GlslPackSnorm2x16, {ctx.Arg(inst, 0)}));
|
||||
return true;
|
||||
case IR::ValueOpcode::PackUnorm2x16:
|
||||
ctx.Define(inst,
|
||||
EmitExt(state, state.uint_type, GlslPackUnorm2x16, {ctx.Arg(inst, 0)}));
|
||||
ctx.Define(inst, EmitExt(state, TypeU32(state), GlslPackUnorm2x16, {ctx.Arg(inst, 0)}));
|
||||
return true;
|
||||
case IR::ValueOpcode::PackFloat2x16Rtz: {
|
||||
const auto low = EmitF32ToF16RtzBits(state, ctx.Arg(inst, 0));
|
||||
const auto high =
|
||||
NewBinary(state, OpShiftLeftLogical, state.uint_type,
|
||||
NewBinary(state, OpShiftLeftLogical, TypeU32(state),
|
||||
EmitF32ToF16RtzBits(state, ctx.Arg(inst, 1)), ConstantU32(state, 16));
|
||||
ctx.Define(inst, NewBinary(state, OpBitwiseOr, state.uint_type, low, high));
|
||||
ctx.Define(inst, NewBinary(state, OpBitwiseOr, TypeU32(state), low, high));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FPAbs32:
|
||||
@@ -362,7 +360,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Define(inst, EmitFNegateValue(state, ctx.Arg(inst, 0)));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPSaturate32:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslFClamp,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslFClamp,
|
||||
{ctx.Arg(inst, 0), ConstantF32(state, 0),
|
||||
ConstantF32(state, 0x3f800000u)}));
|
||||
return true;
|
||||
@@ -414,10 +412,10 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
case IR::ValueOpcode::IAbs32: {
|
||||
const auto value = ctx.Arg(inst, 0);
|
||||
const auto neg = NewUnary(state, OpSNegate, state.uint_type, value);
|
||||
const auto neg = NewUnary(state, OpSNegate, TypeU32(state), value);
|
||||
const auto negative =
|
||||
NewBinary(state, OpSLessThan, state.bool_type, value, ConstantU32(state, 0));
|
||||
ctx.Define(inst, NewSelect(state, state.uint_type, negative, neg, value));
|
||||
NewBinary(state, OpSLessThan, TypeBool(state), value, ConstantU32(state, 0));
|
||||
ctx.Define(inst, NewSelect(state, TypeU32(state), negative, neg, value));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::ShiftLeftLogical32: return binary(OpShiftLeftLogical, IR::Type::U32);
|
||||
@@ -452,19 +450,19 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
case IR::ValueOpcode::BitCount32: return unary(OpBitCount, IR::Type::U32);
|
||||
case IR::ValueOpcode::BitCount64: {
|
||||
const auto pair = ExtractPair(state, ctx.Arg(inst, 0));
|
||||
ctx.Define(inst, NewBinary(state, OpIAdd, state.uint_type,
|
||||
NewUnary(state, OpBitCount, state.uint_type, pair.low),
|
||||
NewUnary(state, OpBitCount, state.uint_type, pair.high)));
|
||||
ctx.Define(inst, NewBinary(state, OpIAdd, TypeU32(state),
|
||||
NewUnary(state, OpBitCount, TypeU32(state), pair.low),
|
||||
NewUnary(state, OpBitCount, TypeU32(state), pair.high)));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FindILsb32: {
|
||||
const auto value = EmitExt(state, state.int_type, GlslFindILsb, {ctx.Arg(inst, 0)});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, state.uint_type, value));
|
||||
const auto value = EmitExt(state, TypeI32(state), GlslFindILsb, {ctx.Arg(inst, 0)});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, TypeU32(state), value));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FindUMsb32: {
|
||||
const auto value = EmitExt(state, state.int_type, GlslFindUMsb, {ctx.Arg(inst, 0)});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, state.uint_type, value));
|
||||
const auto value = EmitExt(state, TypeI32(state), GlslFindUMsb, {ctx.Arg(inst, 0)});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, TypeU32(state), value));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FindUMsb64:
|
||||
@@ -472,9 +470,9 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
case IR::ValueOpcode::FindSMsb32: {
|
||||
const auto value =
|
||||
EmitExt(state, state.int_type, 74u,
|
||||
{NewUnary(state, OpBitcast, state.int_type, ctx.Arg(inst, 0))});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, state.uint_type, value));
|
||||
EmitExt(state, TypeI32(state), 74u,
|
||||
{NewUnary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 0))});
|
||||
ctx.Define(inst, NewUnary(state, OpBitcast, TypeU32(state), value));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::SMin32:
|
||||
@@ -550,25 +548,25 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
case IR::ValueOpcode::ULessThanEqual64: {
|
||||
const auto greater = Compare64(state, ctx.Arg(inst, 0), ctx.Arg(inst, 1),
|
||||
OpUGreaterThan, OpUGreaterThan);
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, state.bool_type, greater));
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, TypeBool(state), greater));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::SLessThanEqual64: {
|
||||
const auto greater = Compare64(state, ctx.Arg(inst, 0), ctx.Arg(inst, 1),
|
||||
OpSGreaterThan, OpUGreaterThan);
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, state.bool_type, greater));
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, TypeBool(state), greater));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::UGreaterThanEqual64: {
|
||||
const auto less =
|
||||
Compare64(state, ctx.Arg(inst, 0), ctx.Arg(inst, 1), OpULessThan, OpULessThan);
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, state.bool_type, less));
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, TypeBool(state), less));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::SGreaterThanEqual64: {
|
||||
const auto less =
|
||||
Compare64(state, ctx.Arg(inst, 0), ctx.Arg(inst, 1), OpSLessThan, OpULessThan);
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, state.bool_type, less));
|
||||
ctx.Define(inst, NewUnary(state, OpLogicalNot, TypeBool(state), less));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::LogicalOr: return binary(OpLogicalOr, IR::Type::U1);
|
||||
@@ -602,7 +600,7 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
case IR::ValueOpcode::FPSub32: return binary(OpFSub, IR::Type::F32);
|
||||
case IR::ValueOpcode::FPMul32: return binary(OpFMul, IR::Type::F32);
|
||||
case IR::ValueOpcode::FPFma32:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslFma,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslFma,
|
||||
{ctx.Arg(inst, 0), ctx.Arg(inst, 1), ctx.Arg(inst, 2)}));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPMin32:
|
||||
@@ -625,44 +623,44 @@ bool EmitValueAlu(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
case IR::ValueOpcode::FPRecip32: {
|
||||
const auto source = EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0));
|
||||
ctx.Define(inst, NewBinary(state, OpFDiv, state.float_type,
|
||||
ctx.Define(inst, NewBinary(state, OpFDiv, TypeF32(state),
|
||||
ConstantF32(state, 0x3f800000u), source));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FPRecipIFlag32:
|
||||
// Integer-to-float inputs used by IFLAG cannot be denormal.
|
||||
ctx.Define(inst, NewBinary(state, OpFDiv, state.float_type,
|
||||
ctx.Define(inst, NewBinary(state, OpFDiv, TypeF32(state),
|
||||
ConstantF32(state, 0x3f800000u), ctx.Arg(inst, 0)));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPRecipSqrt32:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslInverseSqrt,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslInverseSqrt,
|
||||
{EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))}));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPSqrt:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslSqrt,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslSqrt,
|
||||
{EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))}));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPSin:
|
||||
case IR::ValueOpcode::FPCos: {
|
||||
auto source = EmitTrigCycleF32(state, ctx.Arg(inst, 0), op == IR::ValueOpcode::FPSin);
|
||||
source =
|
||||
NewBinary(state, OpFMul, state.float_type, source, ConstantF32(state, 0x40c90fdbu));
|
||||
ctx.Define(inst, EmitExt(state, state.float_type,
|
||||
NewBinary(state, OpFMul, TypeF32(state), source, ConstantF32(state, 0x40c90fdbu));
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state),
|
||||
op == IR::ValueOpcode::FPSin ? GlslSin : GlslCos, {source}));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FPExp2:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslExp2,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslExp2,
|
||||
{EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))}));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPLog2:
|
||||
ctx.Define(inst, EmitExt(state, state.float_type, GlslLog2,
|
||||
ctx.Define(inst, EmitExt(state, TypeF32(state), GlslLog2,
|
||||
{EmitFlushF32DenormToSignedZero(state, ctx.Arg(inst, 0))}));
|
||||
return true;
|
||||
case IR::ValueOpcode::FPLdexp: {
|
||||
const auto exponent = NewUnary(state, OpBitcast, state.int_type, ctx.Arg(inst, 1));
|
||||
const auto exponent = NewUnary(state, OpBitcast, TypeI32(state), ctx.Arg(inst, 1));
|
||||
ctx.Define(inst,
|
||||
EmitExt(state, state.float_type, GlslLdexp, {ctx.Arg(inst, 0), exponent}));
|
||||
EmitExt(state, TypeF32(state), GlslLdexp, {ctx.Arg(inst, 0), exponent}));
|
||||
return true;
|
||||
}
|
||||
case IR::ValueOpcode::FPRoundEven32: return ext_unary(GlslRoundEven);
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
uint32_t EmitSelectValueU32(EmitterState& state, uint32_t cond, uint32_t true_value,
|
||||
uint32_t false_value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, true_value, false_value});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), ret, cond, true_value, false_value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -26,20 +26,20 @@ void EmitShiftLeftLogicalU64Values(EmitterState& state, uint32_t low, uint32_t h
|
||||
const auto high_less = state.builder.AllocateId();
|
||||
const auto high_ge = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, less32, amount, ConstantU32(state, 32)});
|
||||
{OpULessThan, TypeBool(state), less32, amount, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, non_zero, amount, ConstantU32(state, 0)});
|
||||
{OpINotEqual, TypeBool(state), non_zero, amount, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpISub, state.uint_type, carry_count_base, ConstantU32(state, 32), dword_shift});
|
||||
{OpISub, TypeU32(state), carry_count_base, ConstantU32(state, 32), dword_shift});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, carry_count, carry_count_base, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, low_part, low, dword_shift});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, high_part, high, dword_shift});
|
||||
state.builder.AddFunction({OpShiftRightLogical, state.uint_type, carry_part, low, carry_count});
|
||||
{OpBitwiseAnd, TypeU32(state), carry_count, carry_count_base, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, TypeU32(state), low_part, low, dword_shift});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, TypeU32(state), high_part, high, dword_shift});
|
||||
state.builder.AddFunction({OpShiftRightLogical, TypeU32(state), carry_part, low, carry_count});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, high_less, high_part, carry});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, high_ge, low, dword_shift});
|
||||
{OpSelect, TypeU32(state), carry, non_zero, carry_part, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), high_less, high_part, carry});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, TypeU32(state), high_ge, low, dword_shift});
|
||||
out_low = EmitSelectValueU32(state, less32, low_part, ConstantU32(state, 0));
|
||||
out_high = EmitSelectValueU32(state, less32, high_less, high_ge);
|
||||
}
|
||||
@@ -59,28 +59,27 @@ void EmitShiftRightLogicalU64Values(EmitterState& state, uint32_t low, uint32_t
|
||||
const auto low_less = state.builder.AllocateId();
|
||||
const auto low_ge = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, less32, amount, ConstantU32(state, 32)});
|
||||
{OpULessThan, TypeBool(state), less32, amount, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, non_zero, amount, ConstantU32(state, 0)});
|
||||
{OpINotEqual, TypeBool(state), non_zero, amount, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpISub, state.uint_type, carry_count_base, ConstantU32(state, 32), dword_shift});
|
||||
{OpISub, TypeU32(state), carry_count_base, ConstantU32(state, 32), dword_shift});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, carry_count, carry_count_base, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpShiftRightLogical, state.uint_type, low_part, low, dword_shift});
|
||||
state.builder.AddFunction({OpShiftRightLogical, state.uint_type, high_part, high, dword_shift});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, carry_part, high, carry_count});
|
||||
{OpBitwiseAnd, TypeU32(state), carry_count, carry_count_base, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpShiftRightLogical, TypeU32(state), low_part, low, dword_shift});
|
||||
state.builder.AddFunction({OpShiftRightLogical, TypeU32(state), high_part, high, dword_shift});
|
||||
state.builder.AddFunction({OpShiftLeftLogical, TypeU32(state), carry_part, high, carry_count});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, low_less, low_part, carry});
|
||||
state.builder.AddFunction({OpShiftRightLogical, state.uint_type, low_ge, high, dword_shift});
|
||||
{OpSelect, TypeU32(state), carry, non_zero, carry_part, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), low_less, low_part, carry});
|
||||
state.builder.AddFunction({OpShiftRightLogical, TypeU32(state), low_ge, high, dword_shift});
|
||||
out_low = EmitSelectValueU32(state, less32, low_less, low_ge);
|
||||
out_high = EmitSelectValueU32(state, less32, high_part, ConstantU32(state, 0));
|
||||
}
|
||||
|
||||
uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, ret, value, ConstantU32(state, mask)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), ret, value, ConstantU32(state, mask)});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -93,45 +92,45 @@ AddCarryResult EmitAddCarryValues(EmitterState& state, uint32_t lhs, uint32_t rh
|
||||
const auto sum1 = state.builder.AllocateId();
|
||||
const auto carry1 = state.builder.AllocateId();
|
||||
const auto carry = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, pair0, lhs, rhs});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, sum0, pair0, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry0, pair0, 1});
|
||||
state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, pair1, sum0, carry_in});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, sum1, pair1, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry1, pair1, 1});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, carry, carry0, carry1});
|
||||
state.builder.AddFunction({OpIAddCarry, TypeU32Pair(state), pair0, lhs, rhs});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), sum0, pair0, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), carry0, pair0, 1});
|
||||
state.builder.AddFunction({OpIAddCarry, TypeU32Pair(state), pair1, sum0, carry_in});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), sum1, pair1, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), carry1, pair1, 1});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), carry, carry0, carry1});
|
||||
return {sum1, carry};
|
||||
}
|
||||
|
||||
uint32_t EmitShiftRightConstant(EmitterState& state, uint32_t value, uint32_t shift) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, ret, value, ConstantU32(state, shift)});
|
||||
{OpShiftRightLogical, TypeU32(state), ret, value, ConstantU32(state, shift)});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitOrU32(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value,
|
||||
uint32_t constant) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, state.bool_type, ret, value, ConstantU32(state, constant)});
|
||||
state.builder.AddFunction({opcode, TypeBool(state), ret, value, ConstantU32(state, constant)});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitSubConstantMinusU32(EmitterState& state, uint32_t constant, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpISub, state.uint_type, ret, ConstantU32(state, constant), value});
|
||||
state.builder.AddFunction({OpISub, TypeU32(state), ret, ConstantU32(state, constant), value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, f32});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, f32});
|
||||
|
||||
const auto sign = EmitAndConstant(state, EmitShiftRightConstant(state, bits, 16), 0x8000u);
|
||||
const auto exp = EmitAndConstant(state, EmitShiftRightConstant(state, bits, 23), 0xffu);
|
||||
@@ -142,12 +141,12 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
const auto normal_mant = EmitShiftRightConstant(state, mant, 13);
|
||||
const auto normal_payload = state.builder.AllocateId();
|
||||
const auto normal = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpISub, state.uint_type, half_exp, exp, ConstantU32(state, 112)});
|
||||
state.builder.AddFunction({OpISub, TypeU32(state), half_exp, exp, ConstantU32(state, 112)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, normal_exp, half_exp, ConstantU32(state, 10)});
|
||||
{OpShiftLeftLogical, TypeU32(state), normal_exp, half_exp, ConstantU32(state, 10)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseOr, state.uint_type, normal_payload, normal_exp, normal_mant});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, normal, sign, normal_payload});
|
||||
{OpBitwiseOr, TypeU32(state), normal_payload, normal_exp, normal_mant});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), normal, sign, normal_payload});
|
||||
|
||||
const auto mant_with_hidden = EmitOrU32(state, mant, ConstantU32(state, 0x00800000u));
|
||||
const auto raw_sub_shift = EmitSubConstantMinusU32(state, 126, exp);
|
||||
@@ -160,8 +159,8 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
const auto sub_mant = state.builder.AllocateId();
|
||||
const auto subnormal = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, sub_mant, mant_with_hidden, sub_shift});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, subnormal, sign, sub_mant});
|
||||
{OpShiftRightLogical, TypeU32(state), sub_mant, mant_with_hidden, sub_shift});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), subnormal, sign, sub_mant});
|
||||
|
||||
const auto nan_payload =
|
||||
EmitOrU32(state, EmitShiftRightConstant(state, mant, 13), ConstantU32(state, 0x0200u));
|
||||
@@ -185,8 +184,8 @@ uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, boo
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{max_value ? OpUGreaterThan : OpULessThan, state.bool_type, cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs});
|
||||
{max_value ? OpUGreaterThan : OpULessThan, TypeBool(state), cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), ret, cond, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -194,44 +193,44 @@ uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, boo
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{max_value ? OpSGreaterThan : OpSLessThan, state.bool_type, cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs});
|
||||
{max_value ? OpSGreaterThan : OpSLessThan, TypeBool(state), cond, lhs, rhs});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), ret, cond, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitBitcastF32ToU32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, ret, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitBitcastU32ToF32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.float_type, ret, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeF32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitAndU32(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitLogicalOrBool(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalOr, state.bool_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({OpLogicalOr, TypeBool(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalNot, state.bool_type, ret, value});
|
||||
state.builder.AddFunction({OpLogicalNot, TypeBool(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -316,7 +315,7 @@ uint32_t EmitMinMaxF32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, boo
|
||||
const auto rhs_class = EmitClassifyF32(state, rhs);
|
||||
|
||||
const auto numeric_cond = state.builder.AllocateId();
|
||||
state.builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, state.bool_type,
|
||||
state.builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, TypeBool(state),
|
||||
numeric_cond, lhs, rhs});
|
||||
const auto ordered_bits =
|
||||
EmitSelectValueU32(state, numeric_cond, lhs_class.bits, rhs_class.bits);
|
||||
@@ -340,7 +339,7 @@ uint32_t EmitMinMaxF32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, boo
|
||||
uint32_t EmitTruncF32Value(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.float_type, ret, state.glsl_std450, GlslTrunc, value});
|
||||
{OpExtInst, TypeF32(state), ret, GlslStd450(state), GlslTrunc, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -353,18 +352,18 @@ uint32_t EmitFlushF32DenormToSignedZero(EmitterState& state, uint32_t value) {
|
||||
const auto flush = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
{OpBitwiseAnd, TypeU32(state), abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, sign_bits, bits, ConstantU32(state, 0x80000000u)});
|
||||
{OpBitwiseAnd, TypeU32(state), sign_bits, bits, ConstantU32(state, 0x80000000u)});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, non_zero, abs_bits, ConstantU32(state, 0)});
|
||||
{OpINotEqual, TypeBool(state), non_zero, abs_bits, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, subnormal, abs_bits, ConstantU32(state, 0x00800000u)});
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, flush, non_zero, subnormal});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, selected, flush, sign_bits, bits});
|
||||
state.builder.AddFunction({OpBitcast, state.float_type, ret, selected});
|
||||
{OpULessThan, TypeBool(state), subnormal, abs_bits, ConstantU32(state, 0x00800000u)});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), flush, non_zero, subnormal});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), selected, flush, sign_bits, bits});
|
||||
state.builder.AddFunction({OpBitcast, TypeF32(state), ret, selected});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -377,46 +376,45 @@ uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signe
|
||||
const auto large_finite = state.builder.AllocateId();
|
||||
const auto reduced = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.float_type, fract, state.glsl_std450, GlslFract, src});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, src});
|
||||
{OpExtInst, TypeF32(state), fract, GlslStd450(state), GlslFract, src});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, src});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
{OpBitwiseAnd, TypeU32(state), abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, large, abs_bits, ConstantU32(state, 0x4b000000u)});
|
||||
{OpUGreaterThanEqual, TypeBool(state), large, abs_bits, ConstantU32(state, 0x4b000000u)});
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, finite, abs_bits, ConstantU32(state, 0x7f800000u)});
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, large_finite, large, finite});
|
||||
{OpULessThan, TypeBool(state), finite, abs_bits, ConstantU32(state, 0x7f800000u)});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), large_finite, large, finite});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.float_type, reduced, large_finite, ConstantF32(state, 0), fract});
|
||||
{OpSelect, TypeF32(state), reduced, large_finite, ConstantF32(state, 0), fract});
|
||||
if (!preserve_signed_zero) {
|
||||
return reduced;
|
||||
}
|
||||
const auto zero = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIEqual, state.bool_type, zero, abs_bits, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpSelect, state.float_type, ret, zero, src, reduced});
|
||||
state.builder.AddFunction({OpIEqual, TypeBool(state), zero, abs_bits, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpSelect, TypeF32(state), ret, zero, src, reduced});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitFNegateValue(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpFNegate, state.float_type, ret, value});
|
||||
state.builder.AddFunction({OpFNegate, TypeF32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitFAbsValue(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.float_type, ret, state.glsl_std450, GlslFAbs, value});
|
||||
state.builder.AddFunction({OpExtInst, TypeF32(state), ret, GlslStd450(state), GlslFAbs, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitF16BitsToF32(EmitterState& state, uint32_t bits) {
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, bits});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.float_type, ret, unpacked, 0});
|
||||
state.builder.AddFunction({OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state),
|
||||
GlslUnpackHalf2x16, bits});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeF32(state), ret, unpacked, 0});
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -168,45 +168,54 @@ uint32_t ImageViewSpatialComponents(ImageViewKind view) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ImageViewImageType(const EmitterState& state, ImageViewKind view, bool integer) {
|
||||
return state.sampled_images[SampledImageIndex(integer, view)].image_type;
|
||||
uint32_t ImageViewImageType(EmitterState& state, ImageViewKind view, bool integer) {
|
||||
const auto component = integer ? TypeU32(state) : TypeF32(state);
|
||||
return state.builder.Type(OpTypeImage,
|
||||
{component, ImageSpirvDimension(view), 0, ImageSpirvArrayed(view),
|
||||
ImageSpirvMultisampled(view), 1, ImageFormatUnknown});
|
||||
}
|
||||
|
||||
uint32_t ImageViewSampledImageType(const EmitterState& state, ImageViewKind view, bool integer) {
|
||||
return state.sampled_images[SampledImageIndex(integer, view)].sampled_image_type;
|
||||
uint32_t ImageViewSampledImageType(EmitterState& state, ImageViewKind view, bool integer) {
|
||||
return state.builder.Type(OpTypeSampledImage, {ImageViewImageType(state, view, integer)});
|
||||
}
|
||||
|
||||
uint32_t ImageViewSizeType(const EmitterState& state, ImageViewKind view) {
|
||||
uint32_t ImageViewSizeType(EmitterState& state, ImageViewKind view) {
|
||||
switch (ImageViewCoordinateComponents(view)) {
|
||||
case 1u: return state.uint_type;
|
||||
case 2u: return state.vec2_uint_type;
|
||||
case 3u: return state.vec3_uint_type;
|
||||
case 1u: return TypeU32(state);
|
||||
case 2u: return TypeU32Vector(state, 2);
|
||||
case 3u: return TypeU32Vector(state, 3);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t StorageImageType(const EmitterState& state, bool uint_image, ImageViewKind view) {
|
||||
return state.storage_images[StorageImageIndex(uint_image, view)].image_type;
|
||||
uint32_t StorageImageType(EmitterState& state, bool uint_image, ImageViewKind view) {
|
||||
const auto component = uint_image ? TypeU32(state) : TypeF32(state);
|
||||
const auto format = uint_image ? ImageFormatR32ui : ImageFormatUnknown;
|
||||
return state.builder.Type(OpTypeImage, {component, ImageSpirvDimension(view), 0,
|
||||
ImageSpirvArrayed(view), 0, 2, format});
|
||||
}
|
||||
|
||||
uint32_t StorageImagePointerType(const EmitterState& state, bool uint_image, ImageViewKind view) {
|
||||
return state.storage_images[StorageImageIndex(uint_image, view)].pointer_type;
|
||||
uint32_t StorageImagePointerType(EmitterState& state, bool uint_image, ImageViewKind view) {
|
||||
return state.builder.Type(
|
||||
OpTypePointer, {StorageClassUniformConstant, StorageImageType(state, uint_image, view)});
|
||||
}
|
||||
|
||||
uint32_t StorageImageVariable(const EmitterState& state, bool uint_image, ImageViewKind view) {
|
||||
return state.storage_images[StorageImageIndex(uint_image, view)].variable;
|
||||
return state.storage_image_variables[StorageImageIndex(uint_image, view)];
|
||||
}
|
||||
|
||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc,
|
||||
ImageViewKind view) {
|
||||
(void)use_pc;
|
||||
const bool integer = mem.kind == IR::ResourceKind::ImageUint;
|
||||
const auto kind = SampledBindingKind(integer, view);
|
||||
const auto binding = ResourceForDescriptor(state, kind, mem.resource);
|
||||
const auto& descriptors = state.sampled_images[SampledImageIndex(integer, view)];
|
||||
const auto pointer = DescriptorElementPointer(
|
||||
state, descriptors.pointer_type, descriptors.variable, binding.array_index, kind,
|
||||
mem.resource, "sampled image descriptor array was not emitted");
|
||||
const bool integer = mem.kind == IR::ResourceKind::ImageUint;
|
||||
const auto kind = SampledBindingKind(integer, view);
|
||||
const auto binding = ResourceForDescriptor(state, kind, mem.resource);
|
||||
const auto variable = state.sampled_image_variables[SampledImageIndex(integer, view)];
|
||||
const auto pointer_type = state.builder.Type(
|
||||
OpTypePointer, {StorageClassUniformConstant, ImageViewImageType(state, view, integer)});
|
||||
const auto pointer =
|
||||
DescriptorElementPointer(state, pointer_type, variable, binding.array_index, kind,
|
||||
mem.resource, "sampled image descriptor array was not emitted");
|
||||
const auto image = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, ImageViewImageType(state, view, integer), image, pointer});
|
||||
return image;
|
||||
@@ -215,11 +224,14 @@ uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& m
|
||||
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler, uint32_t use_pc) {
|
||||
(void)use_pc;
|
||||
const auto binding = ResourceForDescriptor(state, IR::DescriptorBindingKind::Samplers, sampler);
|
||||
const auto sampler_type = state.builder.Type(OpTypeSampler);
|
||||
const auto pointer_type =
|
||||
state.builder.Type(OpTypePointer, {StorageClassUniformConstant, sampler_type});
|
||||
const auto pointer = DescriptorElementPointer(
|
||||
state, state.ptr_uniform_sampler, state.sampler_variable, binding.array_index,
|
||||
state, pointer_type, state.sampler_variable, binding.array_index,
|
||||
IR::DescriptorBindingKind::Samplers, sampler, "sampler descriptor array was not emitted");
|
||||
const auto sampler_id = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.sampler_type, sampler_id, pointer});
|
||||
state.builder.AddFunction({OpLoad, sampler_type, sampler_id, pointer});
|
||||
return sampler_id;
|
||||
}
|
||||
|
||||
@@ -273,6 +285,9 @@ uint32_t LoadStorageImageDescriptor(EmitterState& state, uint32_t resource, bool
|
||||
|
||||
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, bool uint_image,
|
||||
ImageViewKind view, uint32_t mip_lod, uint32_t coord, uint32_t texel) {
|
||||
if (!uint_image) {
|
||||
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
||||
}
|
||||
const auto kind = StorageBindingKind(uint_image, view);
|
||||
const auto binding = ResourceForDescriptor(state, kind, resource);
|
||||
const auto& image = state.program.info.images.at(resource);
|
||||
|
||||
@@ -27,12 +27,12 @@ uint32_t EmitWqmLaneU32(EmitterState& state, uint32_t src) {
|
||||
const auto expanded = state.builder.AllocateId();
|
||||
const auto combined = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, masked, src, ConstantU32(state, mask)});
|
||||
{OpBitwiseAnd, TypeU32(state), masked, src, ConstantU32(state, mask)});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, non_zero, masked, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, expanded, non_zero,
|
||||
{OpINotEqual, TypeBool(state), non_zero, masked, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), expanded, non_zero,
|
||||
ConstantU32(state, mask), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, combined, ret, expanded});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), combined, ret, expanded});
|
||||
ret = combined;
|
||||
}
|
||||
return ret;
|
||||
@@ -40,7 +40,7 @@ uint32_t EmitWqmLaneU32(EmitterState& state, uint32_t src) {
|
||||
|
||||
uint32_t BoolAsU32(ValueEmitContext& ctx, uint32_t value) {
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpSelect, ctx.state.uint_type, result, value,
|
||||
ctx.state.builder.AddFunction({OpSelect, TypeU32(ctx.state), result, value,
|
||||
ConstantU32(ctx.state, 1), ConstantU32(ctx.state, 0)});
|
||||
return result;
|
||||
}
|
||||
@@ -57,26 +57,27 @@ uint32_t EmitBuiltinU32(ValueEmitContext& ctx, IR::StageInputKind kind, uint32_t
|
||||
if (kind == IR::StageInputKind::FrontFacing) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.bool_type, value, variable});
|
||||
state.builder.AddFunction({OpLoad, TypeBool(state), value, variable});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, bits, value, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
{OpSelect, TypeU32(state), bits, value, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
return bits;
|
||||
}
|
||||
if (kind == IR::StageInputKind::VertexIndex || kind == IR::StageInputKind::InstanceIndex) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.int_type, value, variable});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, value});
|
||||
state.builder.AddFunction({OpLoad, TypeI32(state), value, variable});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, value});
|
||||
return bits;
|
||||
}
|
||||
if (kind == IR::StageInputKind::FragCoord) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_input_float, pointer, variable,
|
||||
ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, state.float_type, value, pointer});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, value});
|
||||
state.builder.AddFunction({OpAccessChain,
|
||||
TypePointer(state, StorageClassInput, TypeF32(state)), pointer,
|
||||
variable, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, TypeF32(state), value, pointer});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, value});
|
||||
return bits;
|
||||
}
|
||||
return EmitInputComponentU32(state, kind, component);
|
||||
@@ -85,12 +86,12 @@ uint32_t EmitBuiltinU32(ValueEmitContext& ctx, IR::StageInputKind kind, uint32_t
|
||||
uint32_t EmitWqm(ValueEmitContext& ctx, uint32_t active) {
|
||||
auto& state = ctx.state;
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, TypeU32Vector(state, 4), ballot,
|
||||
ConstantU32(state, ScopeSubgroup), active});
|
||||
const auto low = state.builder.AllocateId();
|
||||
const auto high = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, low, ballot, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, ballot, 1});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), low, ballot, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), high, ballot, 1});
|
||||
const auto wqm_low = EmitWqmLaneU32(state, low);
|
||||
const auto wqm_high = EmitWqmLaneU32(state, high);
|
||||
const auto lane = EmitSubgroupLocalInvocationId(state);
|
||||
@@ -101,14 +102,14 @@ uint32_t EmitWqm(ValueEmitContext& ctx, uint32_t active) {
|
||||
const auto hit = state.builder.AllocateId();
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, upper, lane, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, mask, upper, wqm_high, wqm_low});
|
||||
{OpUGreaterThanEqual, TypeBool(state), upper, lane, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), mask, upper, wqm_high, wqm_low});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, bit_lane, lane, ConstantU32(state, 31)});
|
||||
{OpBitwiseAnd, TypeU32(state), bit_lane, lane, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), bit_lane});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, hit, mask, bit});
|
||||
state.builder.AddFunction({OpINotEqual, state.bool_type, result, hit, ConstantU32(state, 0)});
|
||||
{OpShiftLeftLogical, TypeU32(state), bit, ConstantU32(state, 1), bit_lane});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), hit, mask, bit});
|
||||
state.builder.AddFunction({OpINotEqual, TypeBool(state), result, hit, ConstantU32(state, 0)});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -128,35 +129,35 @@ uint32_t EmitDppWriteCondition(ValueEmitContext& ctx, const IR::DppMoveFlags& fl
|
||||
const auto row_ok = state.builder.AllocateId();
|
||||
const auto masks_ok = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, bank_shift, lane, ConstantU32(state, 2)});
|
||||
{OpShiftRightLogical, TypeU32(state), bank_shift, lane, ConstantU32(state, 2)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, row_shift, lane, ConstantU32(state, 4)});
|
||||
{OpShiftRightLogical, TypeU32(state), row_shift, lane, ConstantU32(state, 4)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, bank, bank_shift, ConstantU32(state, 3)});
|
||||
{OpBitwiseAnd, TypeU32(state), bank, bank_shift, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, row_shift, ConstantU32(state, 3)});
|
||||
{OpBitwiseAnd, TypeU32(state), row, row_shift, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, bank_bit, ConstantU32(state, 1), bank});
|
||||
{OpShiftLeftLogical, TypeU32(state), bank_bit, ConstantU32(state, 1), bank});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, row_bit, ConstantU32(state, 1), row});
|
||||
{OpShiftLeftLogical, TypeU32(state), row_bit, ConstantU32(state, 1), row});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, bank_hit, ConstantU32(state, flags.bank_mask), bank_bit});
|
||||
{OpBitwiseAnd, TypeU32(state), bank_hit, ConstantU32(state, flags.bank_mask), bank_bit});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row_hit, ConstantU32(state, flags.row_mask), row_bit});
|
||||
{OpBitwiseAnd, TypeU32(state), row_hit, ConstantU32(state, flags.row_mask), row_bit});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, bank_ok, bank_hit, ConstantU32(state, 0)});
|
||||
{OpINotEqual, TypeBool(state), bank_ok, bank_hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, row_ok, row_hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, masks_ok, bank_ok, row_ok});
|
||||
{OpINotEqual, TypeBool(state), row_ok, row_hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), masks_ok, bank_ok, row_ok});
|
||||
uint32_t writable = masks_ok;
|
||||
if (!flags.bound_control) {
|
||||
const auto target = EmitDppTargetLane(state, flags.control);
|
||||
const auto bounded = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, bounded, writable, target.valid});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), bounded, writable, target.valid});
|
||||
writable = bounded;
|
||||
}
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, result, exec, writable});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), result, exec, writable});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -172,9 +173,9 @@ uint32_t EmitAttribute(ValueEmitContext& ctx, uint32_t attr, uint32_t chan) {
|
||||
const auto vector = state.builder.AllocateId();
|
||||
const auto component = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.vec4_float_type, vector, input->variable_id});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.float_type, component, vector, chan & 3u});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, component});
|
||||
state.builder.AddFunction({OpLoad, TypeF32Vector(state, 4), vector, input->variable_id});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeF32(state), component, vector, chan & 3u});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, component});
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -187,7 +188,7 @@ bool MrtUsesUint(const EmitterState& state, const IR::ExportInfo& exp) {
|
||||
uint32_t ExportRawComponent(ValueEmitContext& ctx, uint32_t vector, uint32_t component) {
|
||||
const auto value = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeExtract, ctx.state.uint_type, value, vector, component});
|
||||
{OpCompositeExtract, TypeU32(ctx.state), value, vector, component});
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -203,21 +204,21 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
||||
}
|
||||
const auto packed = state.builder.AllocateId();
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, packed, data, pair});
|
||||
state.builder.AddFunction({OpExtInst, state.vec2_float_type, unpacked,
|
||||
state.glsl_std450, GlslUnpackHalf2x16, packed});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), packed, data, pair});
|
||||
state.builder.AddFunction({OpExtInst, TypeF32Vector(state, 2), unpacked,
|
||||
GlslStd450(state), GlslUnpackHalf2x16, packed});
|
||||
for (uint32_t lane = 0; lane < 2u; lane++) {
|
||||
const auto component = pair * 2u + lane;
|
||||
if (((exp.en >> component) & 1u) != 0u) {
|
||||
f32[component] = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeExtract, state.float_type, f32[component], unpacked, lane});
|
||||
{OpCompositeExtract, TypeF32(state), f32[component], unpacked, lane});
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeConstruct, state.vec4_float_type, vector, f32[0], f32[1], f32[2], f32[3]});
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeF32Vector(state, 4), vector, f32[0],
|
||||
f32[1], f32[2], f32[3]});
|
||||
return vector;
|
||||
}
|
||||
uint32_t raw[4] = {
|
||||
@@ -238,7 +239,7 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
||||
continue;
|
||||
}
|
||||
raw[component] = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, raw[component],
|
||||
state.builder.AddFunction({OpBitFieldUExtract, TypeU32(state), raw[component],
|
||||
packed, ConstantU32(state, lane * 16u),
|
||||
ConstantU32(state, 16)});
|
||||
}
|
||||
@@ -252,18 +253,18 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
||||
}
|
||||
if (uint_output) {
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeConstruct, state.vec4_uint_type, vector, raw[0], raw[1], raw[2], raw[3]});
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeU32Vector(state, 4), vector, raw[0],
|
||||
raw[1], raw[2], raw[3]});
|
||||
return vector;
|
||||
}
|
||||
uint32_t f32[4] {};
|
||||
for (uint32_t component = 0; component < 4u; component++) {
|
||||
f32[component] = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.float_type, f32[component], raw[component]});
|
||||
state.builder.AddFunction({OpBitcast, TypeF32(state), f32[component], raw[component]});
|
||||
}
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeConstruct, state.vec4_float_type, vector, f32[0], f32[1], f32[2], f32[3]});
|
||||
{OpCompositeConstruct, TypeF32Vector(state, 4), vector, f32[0], f32[1], f32[2], f32[3]});
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -271,11 +272,11 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
const auto& exp = ctx.Export(inst);
|
||||
const auto exec = ctx.Arg(inst, 1);
|
||||
if (state.stage == ShaderType::Pixel && exp.vm && state.needs_pixel_valid_mask &&
|
||||
if (state.stage == ShaderType::Pixel && exp.vm && state.requirements.pixel_valid_mask &&
|
||||
state.pixel_valid_mask_variable != 0) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, value, exec, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
{OpSelect, TypeU32(state), value, exec, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpStore, state.pixel_valid_mask_variable, value});
|
||||
}
|
||||
if (exp.kind == IR::ExportTargetKind::Null || exp.kind == IR::ExportTargetKind::Primitive ||
|
||||
@@ -288,16 +289,17 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
if ((exp.en & 1u) != 0u && state.depth_variable != 0) {
|
||||
const auto raw = ExportRawComponent(ctx, data, 0);
|
||||
const auto f32 = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.float_type, f32, raw});
|
||||
state.builder.AddFunction({OpBitcast, TypeF32(state), f32, raw});
|
||||
state.builder.AddFunction({OpStore, state.depth_variable, f32});
|
||||
}
|
||||
if ((exp.en & 4u) != 0u && state.sample_mask_variable != 0) {
|
||||
const auto raw = ExportRawComponent(ctx, data, 2);
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.int_type, value, raw});
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_output_int, pointer,
|
||||
state.sample_mask_variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitcast, TypeI32(state), value, raw});
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeI32(state)), pointer,
|
||||
state.sample_mask_variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpStore, pointer, value});
|
||||
}
|
||||
return;
|
||||
@@ -307,7 +309,7 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return;
|
||||
}
|
||||
const bool uint_output = MrtUsesUint(state, exp);
|
||||
const auto vector_type = uint_output ? state.vec4_uint_type : state.vec4_float_type;
|
||||
const auto vector_type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
|
||||
auto value = ExportVector(ctx, data, exp, uint_output);
|
||||
if (state.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt &&
|
||||
exp.index < state.input_info.pixel->target_export_mapping.size()) {
|
||||
@@ -322,8 +324,9 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
if (exp.kind == IR::ExportTargetKind::Position) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_output_vec4_float, pointer,
|
||||
variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeF32Vector(state, 4)),
|
||||
pointer, variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpStore, pointer, value});
|
||||
} else {
|
||||
state.builder.AddFunction({OpStore, variable, value});
|
||||
@@ -378,7 +381,7 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto flags = inst.Flags<IR::DppMoveFlags>();
|
||||
const auto target = EmitDppTargetLane(state, flags.control);
|
||||
const auto shuffled = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeU32(state), shuffled,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 0),
|
||||
target.lane});
|
||||
if (flags.fetch_inactive) {
|
||||
@@ -386,12 +389,12 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
}
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, TypeU32Vector(state, 4), ballot,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 1)});
|
||||
const auto source_active = EmitBallotLaneActiveBool(state, ballot, target.lane);
|
||||
const auto can_fetch = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLogicalAnd, state.bool_type, can_fetch, target.valid, source_active});
|
||||
{OpLogicalAnd, TypeBool(state), can_fetch, target.valid, source_active});
|
||||
ctx.Emit(inst, OpSelect, IR::Type::U32, {can_fetch, shuffled, ConstantU32(state, 0)});
|
||||
return true;
|
||||
}
|
||||
@@ -410,7 +413,7 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
case IR::ValueOpcode::Ballot:
|
||||
if (state.per_invocation_masks) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeConstruct, state.vec4_uint_type, result,
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeU32Vector(state, 4), result,
|
||||
BoolAsU32(ctx, ctx.Arg(inst, 0)), ConstantU32(state, 0),
|
||||
ConstantU32(state, 0), ConstantU32(state, 0)});
|
||||
ctx.Define(inst, result);
|
||||
@@ -422,9 +425,9 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
case IR::ValueOpcode::ReadFirstLane: {
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
const auto lane = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, TypeU32Vector(state, 4), ballot,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 1)});
|
||||
state.builder.AddFunction({OpGroupNonUniformBallotFindLSB, state.uint_type, lane,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallotFindLSB, TypeU32(state), lane,
|
||||
ConstantU32(state, ScopeSubgroup), ballot});
|
||||
ctx.Emit(inst, OpGroupNonUniformShuffle, IR::Type::U32,
|
||||
{ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 0), lane});
|
||||
@@ -436,7 +439,7 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
case IR::ValueOpcode::WriteLane: {
|
||||
const auto hit = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIEqual, state.bool_type, hit,
|
||||
state.builder.AddFunction({OpIEqual, TypeBool(state), hit,
|
||||
EmitSubgroupLocalInvocationId(state), ctx.Arg(inst, 2)});
|
||||
ctx.Emit(inst, OpSelect, IR::Type::U32, {hit, ctx.Arg(inst, 1), ctx.Arg(inst, 0)});
|
||||
return true;
|
||||
@@ -455,40 +458,40 @@ bool EmitValueFlow(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto index = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
{OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
if (flags.x16) {
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseXor, state.uint_type, row_value, row, ConstantU32(state, 16)});
|
||||
{OpBitwiseXor, TypeU32(state), row_value, row, ConstantU32(state, 16)});
|
||||
} else {
|
||||
state.builder.AddFunction({OpCopyObject, state.uint_type, row_value, row});
|
||||
state.builder.AddFunction({OpCopyObject, TypeU32(state), row_value, row});
|
||||
}
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
{OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane8, lane, ConstantU32(state, 7)});
|
||||
{OpBitwiseAnd, TypeU32(state), lane8, lane, ConstantU32(state, 7)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, shift, lane8, ConstantU32(state, 2)});
|
||||
{OpShiftLeftLogical, TypeU32(state), shift, lane8, ConstantU32(state, 2)});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, upper, lane, ConstantU32(state, 8)});
|
||||
{OpUGreaterThanEqual, TypeBool(state), upper, lane, ConstantU32(state, 8)});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, selected, upper, ctx.Arg(inst, 2), ctx.Arg(inst, 1)});
|
||||
{OpSelect, TypeU32(state), selected, upper, ctx.Arg(inst, 2), ctx.Arg(inst, 1)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, shifted, selected, shift});
|
||||
{OpShiftRightLogical, TypeU32(state), shifted, selected, shift});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, index, shifted, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row_value, index});
|
||||
{OpBitwiseAnd, TypeU32(state), index, shifted, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, row_value, index});
|
||||
const auto shuffled = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeU32(state), shuffled,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 0),
|
||||
target});
|
||||
uint32_t result = shuffled;
|
||||
if (!flags.fetch_inactive) {
|
||||
const auto source_exec = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.bool_type, source_exec,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeBool(state), source_exec,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 3),
|
||||
target});
|
||||
result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, result, source_exec, shuffled,
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), result, source_exec, shuffled,
|
||||
ConstantU32(state, 0)});
|
||||
}
|
||||
ctx.Define(inst, result);
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
uint32_t EmitTrueBool(EmitterState& state) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, ret, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
return ret;
|
||||
return ConstantBool(state, true);
|
||||
}
|
||||
|
||||
DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control) {
|
||||
@@ -17,15 +14,15 @@ DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, quad_base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 3)});
|
||||
{OpBitwiseAnd, TypeU32(state), quad_base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, shift, lane, ConstantU32(state, 1)});
|
||||
{OpShiftLeftLogical, TypeU32(state), shift, lane, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, selected0, ConstantU32(state, control), shift});
|
||||
{OpShiftRightLogical, TypeU32(state), selected0, ConstantU32(state, control), shift});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, selected, selected0, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, quad_base, selected});
|
||||
{OpBitwiseAnd, TypeU32(state), selected, selected0, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, quad_base, selected});
|
||||
return {target, EmitTrueBool(state)};
|
||||
}
|
||||
|
||||
@@ -37,20 +34,20 @@ DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto target = state.builder.AllocateId();
|
||||
const auto valid = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
{OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
if (left) {
|
||||
state.builder.AddFunction(
|
||||
{OpIAdd, state.uint_type, lane_shifted, lane, ConstantU32(state, amount)});
|
||||
{OpIAdd, TypeU32(state), lane_shifted, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, valid, lane, ConstantU32(state, 16u - amount)});
|
||||
{OpULessThan, TypeBool(state), valid, lane, ConstantU32(state, 16u - amount)});
|
||||
} else {
|
||||
state.builder.AddFunction(
|
||||
{OpISub, state.uint_type, lane_shifted, lane, ConstantU32(state, amount)});
|
||||
{OpISub, TypeU32(state), lane_shifted, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, valid, lane, ConstantU32(state, amount)});
|
||||
{OpUGreaterThanEqual, TypeBool(state), valid, lane, ConstantU32(state, amount)});
|
||||
}
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row, lane_shifted});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, row, lane_shifted});
|
||||
return {target, valid};
|
||||
}
|
||||
|
||||
@@ -64,15 +61,15 @@ DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subi
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)});
|
||||
{OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction({OpISub, state.uint_type, minus, lane, ConstantU32(state, amount)});
|
||||
{OpUGreaterThanEqual, TypeBool(state), in_high, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction({OpISub, TypeU32(state), minus, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{OpIAdd, state.uint_type, plus, lane, ConstantU32(state, 16u - amount)});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, selected, in_high, minus, plus});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row, selected});
|
||||
{OpIAdd, TypeU32(state), plus, lane, ConstantU32(state, 16u - amount)});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), selected, in_high, minus, plus});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, row, selected});
|
||||
return {target, EmitTrueBool(state)};
|
||||
}
|
||||
|
||||
@@ -84,12 +81,12 @@ DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool
|
||||
const auto mirrored = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, base_mask)});
|
||||
{OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, base_mask)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, lane_mask)});
|
||||
{OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, lane_mask)});
|
||||
state.builder.AddFunction(
|
||||
{OpISub, state.uint_type, mirrored, ConstantU32(state, lane_mask), lane});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, mirrored});
|
||||
{OpISub, TypeU32(state), mirrored, ConstantU32(state, lane_mask), lane});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, base, mirrored});
|
||||
return {target, EmitTrueBool(state)};
|
||||
}
|
||||
|
||||
@@ -122,7 +119,7 @@ uint32_t EmitSubgroupLocalInvocationId(EmitterState& state) {
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLoad, state.uint_type, value, state.subgroup_local_invocation_id_variable});
|
||||
{OpLoad, TypeU32(state), value, state.subgroup_local_invocation_id_variable});
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -151,9 +148,9 @@ uint32_t EmitInputComponentU32(EmitterState& state, IR::StageInputKind kind, uin
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, state.ptr_input_uint, pointer, variable, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpAccessChain, TypePointer(state, StorageClassInput, TypeU32(state)),
|
||||
pointer, variable, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), value, pointer});
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -163,7 +160,7 @@ uint32_t EmitLocalInvocationIndex(EmitterState& state) {
|
||||
return ConstantU32(state, 0);
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, variable});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), value, variable});
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -200,47 +197,47 @@ uint32_t EmitVertexParameterComponentU32(EmitterState& state, const InputBinding
|
||||
}
|
||||
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, raw});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), bits, raw});
|
||||
return bits;
|
||||
}
|
||||
|
||||
uint32_t EmitSubgroupLaneActiveBool(EmitterState& state, uint32_t lane) {
|
||||
const auto active_ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, active_ballot,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, TypeU32Vector(state, 4), active_ballot,
|
||||
ConstantU32(state, ScopeSubgroup), EmitTrueBool(state)});
|
||||
return EmitBallotLaneActiveBool(state, active_ballot, lane);
|
||||
}
|
||||
uint32_t EmitBallotLaneActiveBool(EmitterState& state, uint32_t active_ballot, uint32_t lane) {
|
||||
const auto low = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, low, active_ballot, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), low, active_ballot, 0});
|
||||
uint32_t mask = low;
|
||||
if (state.wave_size == 64u) {
|
||||
const auto high = state.builder.AllocateId();
|
||||
const auto in_high = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, active_ballot, 1});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), high, active_ballot, 1});
|
||||
state.builder.AddFunction(
|
||||
{OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, selected, in_high, high, low});
|
||||
{OpUGreaterThanEqual, TypeBool(state), in_high, lane, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), selected, in_high, high, low});
|
||||
mask = selected;
|
||||
}
|
||||
|
||||
const auto lane_low = state.builder.AllocateId();
|
||||
const auto bit = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane_low, lane, ConstantU32(state, 31)});
|
||||
{OpBitwiseAnd, TypeU32(state), lane_low, lane, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane_low});
|
||||
{OpShiftLeftLogical, TypeU32(state), bit, ConstantU32(state, 1), lane_low});
|
||||
|
||||
const auto hit = state.builder.AllocateId();
|
||||
const auto active = state.builder.AllocateId();
|
||||
const auto in_range = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, hit, mask, bit});
|
||||
state.builder.AddFunction({OpINotEqual, state.bool_type, active, hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), hit, mask, bit});
|
||||
state.builder.AddFunction({OpINotEqual, TypeBool(state), active, hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, in_range, lane, ConstantU32(state, state.wave_size)});
|
||||
state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, active, in_range});
|
||||
{OpULessThan, TypeBool(state), in_range, lane, ConstantU32(state, state.wave_size)});
|
||||
state.builder.AddFunction({OpLogicalAnd, TypeBool(state), ret, active, in_range});
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,10 +78,10 @@ uint32_t AddressU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::
|
||||
auto value = ctx.Def(address.Arg(packed));
|
||||
if (ComponentUsesA16(mem, component)) {
|
||||
if ((half & 1u) != 0u) {
|
||||
value = Binary(ctx.state, OpShiftRightLogical, ctx.state.uint_type, value,
|
||||
value = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), value,
|
||||
ConstantU32(ctx.state, 16));
|
||||
}
|
||||
value = Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type, value,
|
||||
value = Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state), value,
|
||||
ConstantU32(ctx.state, 0xffffu));
|
||||
}
|
||||
return value;
|
||||
@@ -92,7 +92,7 @@ uint32_t AddressF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::
|
||||
const auto value = AddressU32(ctx, mem, address, component);
|
||||
return ComponentUsesA16(mem, component)
|
||||
? EmitF16BitsToF32(ctx.state, value)
|
||||
: Unary(ctx.state, OpBitcast, ctx.state.float_type, value);
|
||||
: Unary(ctx.state, OpBitcast, TypeF32(ctx.state), value);
|
||||
}
|
||||
|
||||
ImageSampleLayout Layout(const IR::MemoryInfo& mem, ImageViewKind view) {
|
||||
@@ -117,28 +117,20 @@ uint32_t ZeroF32(EmitterState& state) {
|
||||
return ConstantF32(state, 0);
|
||||
}
|
||||
|
||||
uint32_t ZeroU32x4(EmitterState& state) {
|
||||
const auto zero = ConstantU32(state, 0);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddType(
|
||||
{OpConstantComposite, state.vec4_uint_type, value, zero, zero, zero, zero});
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t CubeAxis(EmitterState& state, uint32_t value) {
|
||||
return Binary(state, OpFSub, state.float_type, value, ConstantF32(state, 0x3f800000u));
|
||||
return Binary(state, OpFSub, TypeF32(state), value, ConstantF32(state, 0x3f800000u));
|
||||
}
|
||||
|
||||
uint32_t CubeLayer(EmitterState& state, uint32_t value) {
|
||||
const auto guest = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertFToU, state.uint_type, guest, value});
|
||||
state.builder.AddFunction({OpConvertFToU, TypeU32(state), guest, value});
|
||||
const auto padding =
|
||||
Binary(state, OpShiftLeftLogical, state.uint_type,
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, guest, ConstantU32(state, 3)),
|
||||
Binary(state, OpShiftLeftLogical, TypeU32(state),
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), guest, ConstantU32(state, 3)),
|
||||
ConstantU32(state, 1));
|
||||
const auto host = Binary(state, OpISub, state.uint_type, guest, padding);
|
||||
const auto host = Binary(state, OpISub, TypeU32(state), guest, padding);
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertUToF, state.float_type, result, host});
|
||||
state.builder.AddFunction({OpConvertUToF, TypeF32(state), result, host});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -159,10 +151,10 @@ uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In
|
||||
: ZeroF32(ctx.state);
|
||||
if (mem.image_cube) z = CubeLayer(ctx.state, z);
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec3_float_type, result, x, y, z});
|
||||
{OpCompositeConstruct, TypeF32Vector(ctx.state, 3), result, x, y, z});
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec2_float_type, result, x, y});
|
||||
{OpCompositeConstruct, TypeF32Vector(ctx.state, 2), result, x, y});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -179,10 +171,10 @@ uint32_t CoordU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In
|
||||
const auto z = mem.image_address_components > 2u ? AddressU32(ctx, mem, address, 2)
|
||||
: ConstantU32(ctx.state, 0);
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec3_uint_type, result, x, y, z});
|
||||
{OpCompositeConstruct, TypeU32Vector(ctx.state, 3), result, x, y, z});
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec2_uint_type, result, x, y});
|
||||
{OpCompositeConstruct, TypeU32Vector(ctx.state, 2), result, x, y});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -196,7 +188,7 @@ uint32_t LodU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst
|
||||
}
|
||||
|
||||
uint32_t FloatBits(ValueEmitContext& ctx, uint32_t value) {
|
||||
return Unary(ctx.state, OpBitcast, ctx.state.uint_type, value);
|
||||
return Unary(ctx.state, OpBitcast, TypeU32(ctx.state), value);
|
||||
}
|
||||
|
||||
uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, bool integer, bool dref) {
|
||||
@@ -208,12 +200,12 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, bool integer, bool
|
||||
}
|
||||
const auto scalar = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeExtract,
|
||||
integer ? ctx.state.uint_type : ctx.state.float_type, scalar,
|
||||
integer ? TypeU32(ctx.state) : TypeF32(ctx.state), scalar,
|
||||
value, index});
|
||||
component[index] = integer ? scalar : FloatBits(ctx, scalar);
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, ctx.state.vec4_uint_type, result,
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
component[0], component[1], component[2], component[3]});
|
||||
return result;
|
||||
}
|
||||
@@ -240,15 +232,15 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::Inst& inst, const IR::
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
result[index] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeExtract, ctx.state.uint_type, result[index], size, index});
|
||||
{OpCompositeExtract, TypeU32(ctx.state), result[index], size, index});
|
||||
}
|
||||
}
|
||||
if (ImageSpirvMultisampled(view) == 0u) {
|
||||
result[3] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpImageQueryLevels, ctx.state.uint_type, result[3], image});
|
||||
ctx.state.builder.AddFunction({OpImageQueryLevels, TypeU32(ctx.state), result[3], image});
|
||||
}
|
||||
const auto vector = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, ctx.state.vec4_uint_type, vector,
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, TypeU32Vector(ctx.state, 4), vector,
|
||||
result[0], result[1], result[2], result[3]});
|
||||
return vector;
|
||||
}
|
||||
@@ -262,55 +254,51 @@ uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
if (components == 3u) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec3_int_type, result, zero, zero, zero});
|
||||
{OpCompositeConstruct, TypeI32Vector(ctx.state, 3), result, zero, zero, zero});
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec2_int_type, result, zero, zero});
|
||||
{OpCompositeConstruct, TypeI32Vector(ctx.state, 2), result, zero, zero});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const auto packed = Unary(ctx.state, OpBitcast, ctx.state.int_type,
|
||||
const auto packed = Unary(ctx.state, OpBitcast, TypeI32(ctx.state),
|
||||
AddressU32(ctx, mem, address, layout.offset));
|
||||
uint32_t values[3] = {zero, zero, zero};
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
values[index] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpBitFieldSExtract, ctx.state.int_type, values[index],
|
||||
ctx.state.builder.AddFunction({OpBitFieldSExtract, TypeI32(ctx.state), values[index],
|
||||
packed, ConstantU32(ctx.state, index * 8u),
|
||||
ConstantU32(ctx.state, 6)});
|
||||
}
|
||||
if (components == 1u) return values[0];
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
if (components == 3u) {
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, ctx.state.vec3_int_type, result,
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct, TypeI32Vector(ctx.state, 3), result,
|
||||
values[0], values[1], values[2]});
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, ctx.state.vec2_int_type, result, values[0], values[1]});
|
||||
{OpCompositeConstruct, TypeI32Vector(ctx.state, 2), result, values[0], values[1]});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t HorizontalOffsets(EmitterState& state, ImageViewKind view) {
|
||||
const auto components = ImageViewSpatialComponents(view);
|
||||
const auto array_type = state.builder.AllocateId();
|
||||
const auto count = ConstantU32(state, 4);
|
||||
const auto element_type = components == 1u ? state.int_type : state.vec2_int_type;
|
||||
state.builder.AddType({OpTypeArray, array_type, element_type, count});
|
||||
uint32_t offsets[4] {};
|
||||
const auto element_type = components == 1u ? TypeI32(state) : TypeI32Vector(state, 2);
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {element_type, count});
|
||||
uint32_t offsets[4] {};
|
||||
for (uint32_t index = 0; index < 4u; index++) {
|
||||
const auto x = ConstantI32(state, static_cast<int32_t>(index) - 1);
|
||||
if (components == 1u) {
|
||||
offsets[index] = x;
|
||||
} else {
|
||||
offsets[index] = state.builder.AllocateId();
|
||||
state.builder.AddType({OpConstantComposite, state.vec2_int_type, offsets[index], x,
|
||||
ConstantI32(state, 0)});
|
||||
offsets[index] = state.builder.Constant(OpConstantComposite, TypeI32Vector(state, 2),
|
||||
{x, ConstantI32(state, 0)});
|
||||
}
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddType(
|
||||
{OpConstantComposite, array_type, value, offsets[0], offsets[1], offsets[2], offsets[3]});
|
||||
return value;
|
||||
return state.builder.Constant(OpConstantComposite, array_type,
|
||||
{offsets[0], offsets[1], offsets[2], offsets[3]});
|
||||
}
|
||||
|
||||
uint32_t InverseSwizzle(uint32_t swizzle, uint32_t component) {
|
||||
@@ -331,14 +319,14 @@ uint32_t StoreTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t d
|
||||
const auto packed_index = DmaskComponentIndex(dmask, source);
|
||||
raw = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeExtract, ctx.state.uint_type, raw, data, packed_index});
|
||||
{OpCompositeExtract, TypeU32(ctx.state), raw, data, packed_index});
|
||||
}
|
||||
values[component] = integer ? raw : Unary(ctx.state, OpBitcast, ctx.state.float_type, raw);
|
||||
values[component] = integer ? raw : Unary(ctx.state, OpBitcast, TypeF32(ctx.state), raw);
|
||||
}
|
||||
const auto texel = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeConstruct,
|
||||
integer ? ctx.state.vec4_uint_type : ctx.state.vec4_float_type,
|
||||
texel, values[0], values[1], values[2], values[3]});
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeConstruct, integer ? TypeU32Vector(ctx.state, 4) : TypeF32Vector(ctx.state, 4),
|
||||
texel, values[0], values[1], values[2], values[3]});
|
||||
return texel;
|
||||
}
|
||||
|
||||
@@ -372,26 +360,27 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto* address = ctx.ImageAddress(inst.Arg(sampled ? 2 : 1));
|
||||
if (address == nullptr) return true;
|
||||
if (op == IR::ValueOpcode::ImageQueryDimensions) {
|
||||
state.builder.RequireCapability(CapabilityImageQuery);
|
||||
ctx.Define(inst, QueryDimensions(ctx, inst, mem, *address));
|
||||
return true;
|
||||
}
|
||||
if (op == IR::ValueOpcode::ImageQueryLod) {
|
||||
state.builder.RequireCapability(CapabilityImageQuery);
|
||||
const auto view = SampledImageViewKind(state, mem, pc);
|
||||
const auto sampled = MakeSampledImage(state, mem, pc, view);
|
||||
const auto lod = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpImageQueryLod, state.vec2_float_type, lod, sampled,
|
||||
{OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled,
|
||||
CoordF32(ctx, mem, *address, 0, ImageViewSpatialComponents(view))});
|
||||
uint32_t values[4] = {ConstantU32(state, 0), ConstantU32(state, 0), ConstantU32(state, 0),
|
||||
ConstantU32(state, 0)};
|
||||
for (uint32_t index = 0; index < 2u; index++) {
|
||||
const auto component = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpCompositeExtract, state.float_type, component, lod, index});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeF32(state), component, lod, index});
|
||||
values[index] = FloatBits(ctx, component);
|
||||
}
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeConstruct, state.vec4_uint_type, result, values[0],
|
||||
state.builder.AddFunction({OpCompositeConstruct, TypeU32Vector(state, 4), result, values[0],
|
||||
values[1], values[2], values[3]});
|
||||
ctx.Define(inst, result);
|
||||
return true;
|
||||
@@ -403,20 +392,21 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Define(
|
||||
inst,
|
||||
EmitValueOrDefaultIfCondition(
|
||||
state, condition, state.vec4_uint_type, ZeroU32x4(state), [&]() {
|
||||
state, condition, TypeU32Vector(state, 4), ConstantU32x4Zero(state), [&]() {
|
||||
const auto image = LoadSampledImageDescriptor(state, mem, pc, view);
|
||||
const auto color = state.builder.AllocateId();
|
||||
const auto coord = CoordU32(ctx, mem, *address, view);
|
||||
if (ImageSpirvMultisampled(view) != 0u) {
|
||||
state.builder.AddFunction(
|
||||
{OpImageFetch, integer ? state.vec4_uint_type : state.vec4_float_type,
|
||||
color, image, coord, ImageOperandsSampleMask,
|
||||
{OpImageFetch,
|
||||
integer ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4), color,
|
||||
image, coord, ImageOperandsSampleMask,
|
||||
AddressU32(ctx, mem, *address, ImageViewCoordinateComponents(view))});
|
||||
} else {
|
||||
state.builder.AddFunction(
|
||||
{OpImageFetch, integer ? state.vec4_uint_type : state.vec4_float_type,
|
||||
color, image, coord, ImageOperandsLodMask,
|
||||
LodU32(ctx, mem, *address, view)});
|
||||
{OpImageFetch,
|
||||
integer ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4), color,
|
||||
image, coord, ImageOperandsLodMask, LodU32(ctx, mem, *address, view)});
|
||||
}
|
||||
return ResultVector(ctx, color, integer, false);
|
||||
}));
|
||||
@@ -448,7 +438,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto sample = state.builder.AllocateId();
|
||||
std::vector<uint32_t> words =
|
||||
dref ? std::vector<uint32_t> {OpImageDrefGather,
|
||||
state.vec4_float_type,
|
||||
TypeF32Vector(state, 4),
|
||||
sample,
|
||||
sampled,
|
||||
coord,
|
||||
@@ -456,9 +446,12 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
? AddressF32(ctx, mem, *address, layout.dref)
|
||||
: ZeroF32(state)}
|
||||
: std::vector<uint32_t> {
|
||||
OpImageGather, integer ? state.vec4_uint_type : state.vec4_float_type,
|
||||
sample, sampled,
|
||||
coord, ConstantU32(state, ImageGatherComponent(mem.dmask))};
|
||||
OpImageGather,
|
||||
integer ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4),
|
||||
sample,
|
||||
sampled,
|
||||
coord,
|
||||
ConstantU32(state, ImageGatherComponent(mem.dmask))};
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) {
|
||||
words.push_back(ImageOperandsConstOffsetsMask);
|
||||
words.push_back(HorizontalOffsets(state, view));
|
||||
@@ -478,7 +471,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
? (dref ? OpImageSampleDrefExplicitLod : OpImageSampleExplicitLod)
|
||||
: (dref ? OpImageSampleDrefImplicitLod : OpImageSampleImplicitLod);
|
||||
const auto result_type =
|
||||
dref ? state.float_type : (integer ? state.vec4_uint_type : state.vec4_float_type);
|
||||
dref ? TypeF32(state) : (integer ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4));
|
||||
const auto dref_value =
|
||||
dref ? (layout.dref != NoImageComponent ? AddressF32(ctx, mem, *address, layout.dref)
|
||||
: ZeroF32(state))
|
||||
@@ -537,10 +530,11 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
const auto LoadMapping = [&](uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer,
|
||||
state.flattened_srt_variable, ConstantU32(state, 0), index});
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state),
|
||||
pointer, state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
index});
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), value, pointer});
|
||||
return value;
|
||||
};
|
||||
const auto mapping = ConstantU32(state, image.indirect_mapping_offset);
|
||||
@@ -549,39 +543,38 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto selected = ConstantU32(state, 0u);
|
||||
for (uint32_t iteration = 0; iteration < std::bit_width(image.indirect_mapping_capacity);
|
||||
iteration++) {
|
||||
const auto active = Binary(state, OpULessThan, state.bool_type, low, high);
|
||||
const auto active = Binary(state, OpULessThan, TypeBool(state), low, high);
|
||||
const auto mid =
|
||||
Binary(state, OpShiftRightLogical, state.uint_type,
|
||||
Binary(state, OpIAdd, state.uint_type, low, high), ConstantU32(state, 1u));
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state),
|
||||
Binary(state, OpIAdd, TypeU32(state), low, high), ConstantU32(state, 1u));
|
||||
const auto probe = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, probe, active, mid, ConstantU32(state, 0u)});
|
||||
const auto entry = Binary(state, OpIAdd, state.uint_type, mapping,
|
||||
Binary(state, OpIAdd, state.uint_type,
|
||||
Binary(state, OpShiftLeftLogical, state.uint_type,
|
||||
{OpSelect, TypeU32(state), probe, active, mid, ConstantU32(state, 0u)});
|
||||
const auto entry = Binary(state, OpIAdd, TypeU32(state), mapping,
|
||||
Binary(state, OpIAdd, TypeU32(state),
|
||||
Binary(state, OpShiftLeftLogical, TypeU32(state),
|
||||
probe, ConstantU32(state, 1u)),
|
||||
ConstantU32(state, 1u)));
|
||||
const auto mapped_key = LoadMapping(entry);
|
||||
const auto candidate =
|
||||
LoadMapping(Binary(state, OpIAdd, state.uint_type, entry, ConstantU32(state, 1u)));
|
||||
const auto equal = Binary(state, OpIEqual, state.bool_type, mapped_key, key);
|
||||
const auto match = Binary(state, OpLogicalAnd, state.bool_type, active, equal);
|
||||
LoadMapping(Binary(state, OpIAdd, TypeU32(state), entry, ConstantU32(state, 1u)));
|
||||
const auto equal = Binary(state, OpIEqual, TypeBool(state), mapped_key, key);
|
||||
const auto match = Binary(state, OpLogicalAnd, TypeBool(state), active, equal);
|
||||
const auto next_selected = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, next_selected, match, candidate, selected});
|
||||
{OpSelect, TypeU32(state), next_selected, match, candidate, selected});
|
||||
selected = next_selected;
|
||||
const auto less = Binary(state, OpULessThan, state.bool_type, mapped_key, key);
|
||||
const auto take_upper = Binary(state, OpLogicalAnd, state.bool_type, active, less);
|
||||
const auto take_lower = Binary(state, OpLogicalAnd, state.bool_type, active,
|
||||
Unary(state, OpLogicalNot, state.bool_type, less));
|
||||
const auto less = Binary(state, OpULessThan, TypeBool(state), mapped_key, key);
|
||||
const auto take_upper = Binary(state, OpLogicalAnd, TypeBool(state), active, less);
|
||||
const auto take_lower = Binary(state, OpLogicalAnd, TypeBool(state), active,
|
||||
Unary(state, OpLogicalNot, TypeBool(state), less));
|
||||
const auto next_low = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, next_low, take_upper,
|
||||
Binary(state, OpIAdd, state.uint_type, mid, ConstantU32(state, 1u)), low});
|
||||
{OpSelect, TypeU32(state), next_low, take_upper,
|
||||
Binary(state, OpIAdd, TypeU32(state), mid, ConstantU32(state, 1u)), low});
|
||||
low = next_low;
|
||||
const auto next_high = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, next_high, take_lower, mid, high});
|
||||
state.builder.AddFunction({OpSelect, TypeU32(state), next_high, take_lower, mid, high});
|
||||
high = next_high;
|
||||
}
|
||||
const auto default_label = state.builder.AllocateId();
|
||||
@@ -616,12 +609,14 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto view = StorageImageViewKind(state, mem, true, pc);
|
||||
ctx.Define(inst, EmitValueOrZeroIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto pointer_type =
|
||||
state.builder.Type(OpTypePointer, {StorageClassImage, TypeU32(state)});
|
||||
state.builder.AddFunction(
|
||||
{OpImageTexelPointer, state.ptr_image_uint, pointer,
|
||||
{OpImageTexelPointer, pointer_type, pointer,
|
||||
StorageImageDescriptorPointer(state, mem.resource, true, pc, view),
|
||||
CoordU32(ctx, mem, *address, view), ConstantU32(state, 0)});
|
||||
const auto old = state.builder.AllocateId();
|
||||
state.builder.AddFunction({atomic_opcode, state.uint_type, old, pointer,
|
||||
state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer,
|
||||
ConstantU32(state, ScopeDevice),
|
||||
ConstantU32(state, MemorySemanticsNone),
|
||||
ctx.Arg(inst, 2)});
|
||||
|
||||
@@ -132,6 +132,8 @@ enum : uint32_t {
|
||||
OpTypeStruct = 30,
|
||||
OpTypePointer = 32,
|
||||
OpTypeFunction = 33,
|
||||
OpConstantTrue = 41,
|
||||
OpConstantFalse = 42,
|
||||
OpConstant = 43,
|
||||
OpConstantComposite = 44,
|
||||
OpUndef = 1,
|
||||
@@ -294,109 +296,31 @@ struct DescriptorResourceBinding {
|
||||
uint32_t array_index = 0;
|
||||
};
|
||||
|
||||
struct SampledImageDescriptors {
|
||||
uint32_t image_type = 0;
|
||||
uint32_t sampled_image_type = 0;
|
||||
uint32_t pointer_type = 0;
|
||||
uint32_t array_type = 0;
|
||||
uint32_t array_pointer_type = 0;
|
||||
uint32_t variable = 0;
|
||||
};
|
||||
|
||||
struct StorageImageDescriptors {
|
||||
uint32_t image_type = 0;
|
||||
uint32_t pointer_type = 0;
|
||||
uint32_t array_type = 0;
|
||||
uint32_t array_pointer_type = 0;
|
||||
uint32_t variable = 0;
|
||||
};
|
||||
|
||||
struct EmitterState {
|
||||
EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_,
|
||||
ShaderStageInputInfo input_info_)
|
||||
: program(program_), resources(resources_), input_info(input_info_) {}
|
||||
: program(program_), resources(resources_), input_info(input_info_),
|
||||
requirements(*program_.spirv_requirements) {}
|
||||
|
||||
Builder builder;
|
||||
const IR::Program& program;
|
||||
const IR::ResourceSnapshot& resources;
|
||||
ShaderStageInputInfo input_info;
|
||||
ShaderType stage = ShaderType::Unknown;
|
||||
uint32_t wave_size = 64;
|
||||
bool per_invocation_masks = false;
|
||||
uint32_t void_type = 0;
|
||||
uint32_t bool_type = 0;
|
||||
uint32_t uint_type = 0;
|
||||
uint32_t uint_pair_type = 0;
|
||||
uint32_t int_pair_type = 0;
|
||||
uint32_t int_type = 0;
|
||||
uint32_t float_type = 0;
|
||||
uint32_t vec2_uint_type = 0;
|
||||
uint32_t vec3_uint_type = 0;
|
||||
uint32_t vec4_uint_type = 0;
|
||||
uint32_t vec2_int_type = 0;
|
||||
uint32_t vec3_int_type = 0;
|
||||
uint32_t vec4_int_type = 0;
|
||||
uint32_t vec2_float_type = 0;
|
||||
uint32_t vec3_float_type = 0;
|
||||
uint32_t vec4_float_type = 0;
|
||||
uint32_t ptr_func_uint = 0;
|
||||
uint32_t ptr_func_bool = 0;
|
||||
uint32_t ptr_func_float = 0;
|
||||
uint32_t ptr_func_uint_pair = 0;
|
||||
uint32_t ptr_func_vec4_uint = 0;
|
||||
uint32_t ptr_func_vec2_float = 0;
|
||||
uint32_t ptr_input_float = 0;
|
||||
uint32_t ptr_input_bool = 0;
|
||||
uint32_t ptr_input_int = 0;
|
||||
uint32_t ptr_input_uint = 0;
|
||||
uint32_t ptr_input_vec2_float = 0;
|
||||
uint32_t ptr_input_vec3_float = 0;
|
||||
uint32_t ptr_input_vec2_int = 0;
|
||||
uint32_t ptr_input_vec3_int = 0;
|
||||
uint32_t ptr_input_vec4_int = 0;
|
||||
uint32_t ptr_input_vec2_uint = 0;
|
||||
uint32_t ptr_input_vec3_uint = 0;
|
||||
uint32_t ptr_input_vec4_uint = 0;
|
||||
uint32_t ptr_input_vec4_float = 0;
|
||||
uint32_t sample_mask_array_type = 0;
|
||||
uint32_t ptr_output_int = 0;
|
||||
uint32_t ptr_output_sample_mask_array = 0;
|
||||
uint32_t ptr_output_float = 0;
|
||||
uint32_t ptr_output_vec4_float = 0;
|
||||
uint32_t per_vertex_type = 0;
|
||||
uint32_t ptr_output_per_vertex = 0;
|
||||
uint32_t storage_runtime_array_type = 0;
|
||||
uint32_t storage_buffer_type = 0;
|
||||
uint32_t ptr_storage_buffer = 0;
|
||||
uint32_t ptr_storage_buffer_uint = 0;
|
||||
uint32_t storage_buffer_array_type = 0;
|
||||
uint32_t ptr_storage_buffer_array = 0;
|
||||
uint32_t storage_buffer_variable = 0;
|
||||
const IR::SpirvRequirements& requirements;
|
||||
ShaderType stage = ShaderType::Unknown;
|
||||
uint32_t wave_size = 64;
|
||||
bool per_invocation_masks = false;
|
||||
uint32_t storage_buffer_variable = 0;
|
||||
std::array<uint32_t, IR::ShaderInfo::MaxBuffers> storage_buffer_offsets {};
|
||||
uint32_t address_memory_array_type = 0;
|
||||
uint32_t ptr_address_memory_array = 0;
|
||||
uint32_t address_memory_variable = 0;
|
||||
uint32_t gds_variable = 0;
|
||||
uint32_t push_constant_array_type = 0;
|
||||
uint32_t push_constant_block_type = 0;
|
||||
uint32_t ptr_push_constant_block = 0;
|
||||
uint32_t ptr_push_constant_uint = 0;
|
||||
uint32_t push_constant_variable = 0;
|
||||
uint32_t vsharp_storage_variable = 0;
|
||||
uint32_t flattened_srt_variable = 0;
|
||||
uint32_t lds_array_type = 0;
|
||||
uint32_t ptr_workgroup_array = 0;
|
||||
uint32_t ptr_workgroup_uint = 0;
|
||||
uint32_t lds_variable = 0;
|
||||
std::array<SampledImageDescriptors, 14> sampled_images;
|
||||
std::array<StorageImageDescriptors, 10> storage_images;
|
||||
uint32_t sampler_type = 0;
|
||||
uint32_t sampler_array_type = 0;
|
||||
uint32_t ptr_uniform_sampler = 0;
|
||||
uint32_t ptr_uniform_sampler_array = 0;
|
||||
uint32_t address_memory_variable = 0;
|
||||
uint32_t gds_variable = 0;
|
||||
uint32_t push_constant_variable = 0;
|
||||
uint32_t vsharp_storage_variable = 0;
|
||||
uint32_t flattened_srt_variable = 0;
|
||||
uint32_t lds_variable = 0;
|
||||
std::array<uint32_t, 14> sampled_image_variables {};
|
||||
std::array<uint32_t, 10> storage_image_variables {};
|
||||
uint32_t sampler_variable = 0;
|
||||
uint32_t ptr_image_uint = 0;
|
||||
uint32_t func_type = 0;
|
||||
uint32_t main_func = 0;
|
||||
uint32_t entry_label = 0;
|
||||
uint32_t pixel_valid_mask_variable = 0;
|
||||
@@ -408,26 +332,33 @@ struct EmitterState {
|
||||
uint32_t dispatch_after_switch_label = 0;
|
||||
uint32_t dispatch_continue_label = 0;
|
||||
uint32_t dispatch_merge_label = 0;
|
||||
uint32_t glsl_std450 = 0;
|
||||
uint32_t subgroup_local_invocation_id_variable = 0;
|
||||
uint32_t per_vertex_variable = 0;
|
||||
uint32_t depth_variable = 0;
|
||||
uint32_t sample_mask_variable = 0;
|
||||
bool needs_subgroup_ballot = false;
|
||||
bool needs_subgroup_shuffle = false;
|
||||
bool needs_subgroup_local_invocation_id = false;
|
||||
bool needs_compute_derivatives = false;
|
||||
bool needs_image_gather_extended = false;
|
||||
bool needs_function_lds = false;
|
||||
bool needs_pixel_valid_mask = false;
|
||||
std::vector<InputBinding> inputs;
|
||||
std::vector<OutputBinding> outputs;
|
||||
std::vector<uint32_t> interface_variables;
|
||||
std::map<uint32_t, uint32_t> constants;
|
||||
std::map<uint32_t, uint32_t> signed_constants;
|
||||
std::map<uint32_t, uint32_t> float_constants;
|
||||
};
|
||||
|
||||
uint32_t TypeVoid(EmitterState& state);
|
||||
uint32_t TypeBool(EmitterState& state);
|
||||
uint32_t TypeU32(EmitterState& state);
|
||||
uint32_t TypeU32Pair(EmitterState& state);
|
||||
uint32_t TypeI32(EmitterState& state);
|
||||
uint32_t TypeI32Pair(EmitterState& state);
|
||||
uint32_t TypeF32(EmitterState& state);
|
||||
uint32_t TypeU32Vector(EmitterState& state, uint32_t components);
|
||||
uint32_t TypeI32Vector(EmitterState& state, uint32_t components);
|
||||
uint32_t TypeF32Vector(EmitterState& state, uint32_t components);
|
||||
uint32_t TypePointer(EmitterState& state, uint32_t storage_class, uint32_t pointee);
|
||||
uint32_t TypeFunction(EmitterState& state);
|
||||
uint32_t TypeStorageBufferPointer(EmitterState& state);
|
||||
uint32_t TypeStorageBufferElementPointer(EmitterState& state);
|
||||
uint32_t TypePushConstantElementPointer(EmitterState& state);
|
||||
uint32_t TypeLdsArrayPointer(EmitterState& state, uint32_t storage_class);
|
||||
uint32_t TypeLdsElementPointer(EmitterState& state, uint32_t storage_class);
|
||||
|
||||
struct ValueEmitContext {
|
||||
ValueEmitContext(EmitterState& state_, const IR::ValueProgram& program_)
|
||||
: state(state_), program(program_) {}
|
||||
@@ -597,14 +528,14 @@ VertexInputScalarKind VertexParameterScalarKind(const EmitterState& state, uint3
|
||||
|
||||
uint32_t VertexParameterComponentCount(const EmitterState& state, const InputBinding& input);
|
||||
|
||||
uint32_t VertexParameterScalarType(const EmitterState& state, VertexInputScalarKind kind);
|
||||
uint32_t VertexParameterScalarType(EmitterState& state, VertexInputScalarKind kind);
|
||||
|
||||
uint32_t VertexParameterScalarPointerType(const EmitterState& state, VertexInputScalarKind kind);
|
||||
uint32_t VertexParameterScalarPointerType(EmitterState& state, VertexInputScalarKind kind);
|
||||
|
||||
uint32_t VertexParameterVectorOrScalarType(const EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t VertexParameterVectorOrScalarType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components);
|
||||
|
||||
uint32_t VertexParameterInputPointerType(const EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t VertexParameterInputPointerType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components);
|
||||
|
||||
void SetError(std::string* error, const char* message);
|
||||
@@ -638,11 +569,15 @@ uint32_t ImageViewCoordinateComponents(ImageViewKind view);
|
||||
|
||||
uint32_t ImageViewSpatialComponents(ImageViewKind view);
|
||||
|
||||
uint32_t ImageViewImageType(const EmitterState& state, ImageViewKind view, bool integer);
|
||||
uint32_t ImageViewImageType(EmitterState& state, ImageViewKind view, bool integer);
|
||||
|
||||
uint32_t ImageViewSampledImageType(const EmitterState& state, ImageViewKind view, bool integer);
|
||||
uint32_t ImageViewSampledImageType(EmitterState& state, ImageViewKind view, bool integer);
|
||||
|
||||
uint32_t ImageViewSizeType(const EmitterState& state, ImageViewKind view);
|
||||
uint32_t ImageViewSizeType(EmitterState& state, ImageViewKind view);
|
||||
|
||||
uint32_t StorageImageType(EmitterState& state, bool uint_image, ImageViewKind view);
|
||||
|
||||
uint32_t StorageImagePointerType(EmitterState& state, bool uint_image, ImageViewKind view);
|
||||
|
||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc,
|
||||
ImageViewKind view);
|
||||
@@ -679,6 +614,14 @@ uint32_t FloatBits(float value);
|
||||
|
||||
uint32_t ConstantF32Value(EmitterState& state, float value);
|
||||
|
||||
uint32_t ConstantBool(EmitterState& state, bool value);
|
||||
|
||||
uint32_t ConstantU64(EmitterState& state, uint64_t value);
|
||||
|
||||
uint32_t ConstantU32x4Zero(EmitterState& state);
|
||||
|
||||
uint32_t GlslStd450(EmitterState& state);
|
||||
|
||||
void AllocateInputVariables(EmitterState& state);
|
||||
|
||||
void AllocateOutputVariables(EmitterState& state);
|
||||
@@ -694,9 +637,7 @@ void DecorateDescriptor(EmitterState& state, uint32_t variable, const char* name
|
||||
|
||||
void AddDescriptorAnnotationsAndNames(EmitterState& state);
|
||||
|
||||
void EmitHeaderAndTypes(EmitterState& state);
|
||||
|
||||
void AllocateDescriptorVariables(EmitterState& state);
|
||||
void DefineModule(EmitterState& state);
|
||||
|
||||
uint32_t EmitTrueBool(EmitterState& state);
|
||||
|
||||
@@ -913,7 +854,7 @@ uint32_t EmitValueOrDefaultIfCondition(EmitterState& state, uint32_t condition,
|
||||
|
||||
template <typename Fn>
|
||||
uint32_t EmitValueOrZeroIfCondition(EmitterState& state, uint32_t condition, Fn&& fn) {
|
||||
return EmitValueOrDefaultIfCondition(state, condition, state.uint_type, ConstantU32(state, 0),
|
||||
return EmitValueOrDefaultIfCondition(state, condition, TypeU32(state), ConstantU32(state, 0),
|
||||
std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ uint32_t Select(EmitterState& state, uint32_t type, uint32_t condition, uint32_t
|
||||
uint32_t AndCondition(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
if (lhs == 0) return rhs;
|
||||
if (rhs == 0) return lhs;
|
||||
return Binary(state, OpLogicalAnd, state.bool_type, lhs, rhs);
|
||||
return Binary(state, OpLogicalAnd, TypeBool(state), lhs, rhs);
|
||||
}
|
||||
|
||||
uint32_t BufferByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
|
||||
@@ -37,66 +37,66 @@ uint32_t BufferByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR
|
||||
ConstantU32(state, StorageBufferPackedStride(state, mem, inst.Flags<IR::MemoryFlags>().pc));
|
||||
if (mem.formatted && !mem.typed && inst.GetOpcode() == IR::ValueOpcode::StoreBufferU32) {
|
||||
const auto add_tid_bit = Binary(
|
||||
state, OpBitwiseAnd, state.uint_type,
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, packed, ConstantU32(state, 20)),
|
||||
state, OpBitwiseAnd, TypeU32(state),
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), packed, ConstantU32(state, 20)),
|
||||
ConstantU32(state, 1));
|
||||
const auto add_tid =
|
||||
Binary(state, OpINotEqual, state.bool_type, add_tid_bit, ConstantU32(state, 0));
|
||||
const auto lane = Binary(state, OpBitwiseAnd, state.uint_type,
|
||||
Binary(state, OpINotEqual, TypeBool(state), add_tid_bit, ConstantU32(state, 0));
|
||||
const auto lane = Binary(state, OpBitwiseAnd, TypeU32(state),
|
||||
EmitLocalInvocationIndex(state), ConstantU32(state, 63));
|
||||
index = Select(state, state.uint_type, add_tid,
|
||||
Binary(state, OpIAdd, state.uint_type, index, lane), index);
|
||||
index = Select(state, TypeU32(state), add_tid,
|
||||
Binary(state, OpIAdd, TypeU32(state), index, lane), index);
|
||||
}
|
||||
const auto stride =
|
||||
Binary(state, OpBitwiseAnd, state.uint_type, packed, ConstantU32(state, 0x3fffu));
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state), packed, ConstantU32(state, 0x3fffu));
|
||||
const auto swizzle =
|
||||
Binary(state, OpBitwiseAnd, state.uint_type,
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, packed, ConstantU32(state, 14)),
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state),
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), packed, ConstantU32(state, 14)),
|
||||
ConstantU32(state, 1));
|
||||
const auto use_swizzle =
|
||||
Binary(state, OpLogicalAnd, state.bool_type,
|
||||
Binary(state, OpINotEqual, state.bool_type, stride, ConstantU32(state, 0)),
|
||||
Binary(state, OpINotEqual, state.bool_type, swizzle, ConstantU32(state, 0)));
|
||||
Binary(state, OpLogicalAnd, TypeBool(state),
|
||||
Binary(state, OpINotEqual, TypeBool(state), stride, ConstantU32(state, 0)),
|
||||
Binary(state, OpINotEqual, TypeBool(state), swizzle, ConstantU32(state, 0)));
|
||||
const auto stride_enum =
|
||||
Binary(state, OpBitwiseAnd, state.uint_type,
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, packed, ConstantU32(state, 16)),
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state),
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), packed, ConstantU32(state, 16)),
|
||||
ConstantU32(state, 3));
|
||||
const auto index_shift =
|
||||
Binary(state, OpIAdd, state.uint_type, stride_enum, ConstantU32(state, 3));
|
||||
Binary(state, OpIAdd, TypeU32(state), stride_enum, ConstantU32(state, 3));
|
||||
const auto index_stride =
|
||||
Binary(state, OpShiftLeftLogical, state.uint_type, ConstantU32(state, 8), stride_enum);
|
||||
Binary(state, OpShiftLeftLogical, TypeU32(state), ConstantU32(state, 8), stride_enum);
|
||||
const auto index_mask =
|
||||
Binary(state, OpISub, state.uint_type, index_stride, ConstantU32(state, 1));
|
||||
offset = Binary(state, OpIAdd, state.uint_type, offset, ConstantU32(state, mem.offset));
|
||||
const auto linear = Binary(state, OpIAdd, state.uint_type,
|
||||
Binary(state, OpIMul, state.uint_type, index, stride), offset);
|
||||
const auto index_msb = Binary(state, OpShiftRightLogical, state.uint_type, index, index_shift);
|
||||
const auto index_lsb = Binary(state, OpBitwiseAnd, state.uint_type, index, index_mask);
|
||||
Binary(state, OpISub, TypeU32(state), index_stride, ConstantU32(state, 1));
|
||||
offset = Binary(state, OpIAdd, TypeU32(state), offset, ConstantU32(state, mem.offset));
|
||||
const auto linear = Binary(state, OpIAdd, TypeU32(state),
|
||||
Binary(state, OpIMul, TypeU32(state), index, stride), offset);
|
||||
const auto index_msb = Binary(state, OpShiftRightLogical, TypeU32(state), index, index_shift);
|
||||
const auto index_lsb = Binary(state, OpBitwiseAnd, TypeU32(state), index, index_mask);
|
||||
const auto offset_msb =
|
||||
Binary(state, OpBitwiseAnd, state.uint_type, offset, ConstantU32(state, ~3u));
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state), offset, ConstantU32(state, ~3u));
|
||||
const auto offset_lsb =
|
||||
Binary(state, OpBitwiseAnd, state.uint_type, offset, ConstantU32(state, 3));
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state), offset, ConstantU32(state, 3));
|
||||
const auto msb =
|
||||
Binary(state, OpIMul, state.uint_type,
|
||||
Binary(state, OpIAdd, state.uint_type,
|
||||
Binary(state, OpIMul, state.uint_type, index_msb, stride), offset_msb),
|
||||
Binary(state, OpIMul, TypeU32(state),
|
||||
Binary(state, OpIAdd, TypeU32(state),
|
||||
Binary(state, OpIMul, TypeU32(state), index_msb, stride), offset_msb),
|
||||
index_stride);
|
||||
const auto lsb =
|
||||
Binary(state, OpIAdd, state.uint_type,
|
||||
Binary(state, OpShiftLeftLogical, state.uint_type, index_lsb, ConstantU32(state, 2)),
|
||||
Binary(state, OpIAdd, TypeU32(state),
|
||||
Binary(state, OpShiftLeftLogical, TypeU32(state), index_lsb, ConstantU32(state, 2)),
|
||||
offset_lsb);
|
||||
const auto address = Select(state, state.uint_type, use_swizzle,
|
||||
Binary(state, OpIAdd, state.uint_type, msb, lsb), linear);
|
||||
return Binary(state, OpIAdd, state.uint_type, address, soffset);
|
||||
const auto address = Select(state, TypeU32(state), use_swizzle,
|
||||
Binary(state, OpIAdd, TypeU32(state), msb, lsb), linear);
|
||||
return Binary(state, OpIAdd, TypeU32(state), address, soffset);
|
||||
}
|
||||
|
||||
uint32_t AddU64Low(EmitterState& state, uint32_t low, uint32_t high, uint32_t add_low,
|
||||
uint32_t add_high, uint32_t& out_high) {
|
||||
const auto result = Binary(state, OpIAdd, state.uint_type, low, add_low);
|
||||
const auto carry = Binary(state, OpULessThan, state.bool_type, result, low);
|
||||
out_high = Binary(
|
||||
state, OpIAdd, state.uint_type, Binary(state, OpIAdd, state.uint_type, high, add_high),
|
||||
Select(state, state.uint_type, carry, ConstantU32(state, 1), ConstantU32(state, 0)));
|
||||
const auto result = Binary(state, OpIAdd, TypeU32(state), low, add_low);
|
||||
const auto carry = Binary(state, OpULessThan, TypeBool(state), result, low);
|
||||
out_high =
|
||||
Binary(state, OpIAdd, TypeU32(state), Binary(state, OpIAdd, TypeU32(state), high, add_high),
|
||||
Select(state, TypeU32(state), carry, ConstantU32(state, 1), ConstantU32(state, 0)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -106,15 +106,15 @@ uint32_t AddressByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const I
|
||||
auto immediate = static_cast<int32_t>(mem.offset);
|
||||
if (mem.kind == IR::ResourceKind::ScalarAddress) {
|
||||
immediate = static_cast<int32_t>(static_cast<uint32_t>(immediate) & ~3u);
|
||||
low = Binary(state, OpBitwiseAnd, state.uint_type, low, ConstantU32(state, ~3u));
|
||||
low = Binary(state, OpBitwiseAnd, TypeU32(state), low, ConstantU32(state, ~3u));
|
||||
}
|
||||
const auto immediate_low = ConstantU32(state, static_cast<uint32_t>(immediate));
|
||||
const auto immediate_high = ConstantU32(state, immediate < 0 ? UINT32_MAX : 0u);
|
||||
const auto base = state.program.info.addresses[mem.resource].specialized_base;
|
||||
if (mem.kind == IR::ResourceKind::Scratch) {
|
||||
low = AddU64Low(state, low, high, immediate_low, immediate_high, high);
|
||||
const auto valid = Binary(state, OpIEqual, state.bool_type, high, ConstantU32(state, 0));
|
||||
return Select(state, state.uint_type, valid, low, ConstantU32(state, UINT32_MAX));
|
||||
const auto valid = Binary(state, OpIEqual, TypeBool(state), high, ConstantU32(state, 0));
|
||||
return Select(state, TypeU32(state), valid, low, ConstantU32(state, UINT32_MAX));
|
||||
}
|
||||
if (mem.kind == IR::ResourceKind::Flat ||
|
||||
(mem.kind == IR::ResourceKind::Global &&
|
||||
@@ -122,22 +122,22 @@ uint32_t AddressByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const I
|
||||
low = AddU64Low(state, low, high, immediate_low, immediate_high, high);
|
||||
const auto base_low = ConstantU32(state, static_cast<uint32_t>(base));
|
||||
const auto base_high = ConstantU32(state, static_cast<uint32_t>(base >> 32u));
|
||||
const auto relative = Binary(state, OpISub, state.uint_type, low, base_low);
|
||||
const auto borrow = Binary(state, OpULessThan, state.bool_type, low, base_low);
|
||||
const auto relative = Binary(state, OpISub, TypeU32(state), low, base_low);
|
||||
const auto borrow = Binary(state, OpULessThan, TypeBool(state), low, base_low);
|
||||
const auto relative_high = Binary(
|
||||
state, OpISub, state.uint_type, Binary(state, OpISub, state.uint_type, high, base_high),
|
||||
Select(state, state.uint_type, borrow, ConstantU32(state, 1), ConstantU32(state, 0)));
|
||||
state, OpISub, TypeU32(state), Binary(state, OpISub, TypeU32(state), high, base_high),
|
||||
Select(state, TypeU32(state), borrow, ConstantU32(state, 1), ConstantU32(state, 0)));
|
||||
const auto valid =
|
||||
Binary(state, OpIEqual, state.bool_type, relative_high, ConstantU32(state, 0));
|
||||
return Select(state, state.uint_type, valid, relative, ConstantU32(state, UINT32_MAX));
|
||||
Binary(state, OpIEqual, TypeBool(state), relative_high, ConstantU32(state, 0));
|
||||
return Select(state, TypeU32(state), valid, relative, ConstantU32(state, UINT32_MAX));
|
||||
}
|
||||
const auto initial = base + static_cast<uint64_t>(static_cast<int64_t>(immediate));
|
||||
auto relative_high = ConstantU32(state, static_cast<uint32_t>(initial >> 32u));
|
||||
const auto relative = AddU64Low(state, ConstantU32(state, static_cast<uint32_t>(initial)),
|
||||
relative_high, low, ConstantU32(state, 0), relative_high);
|
||||
const auto valid =
|
||||
Binary(state, OpIEqual, state.bool_type, relative_high, ConstantU32(state, 0));
|
||||
return Select(state, state.uint_type, valid, relative, ConstantU32(state, UINT32_MAX));
|
||||
Binary(state, OpIEqual, TypeBool(state), relative_high, ConstantU32(state, 0));
|
||||
return Select(state, TypeU32(state), valid, relative, ConstantU32(state, UINT32_MAX));
|
||||
}
|
||||
|
||||
uint32_t ByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
|
||||
@@ -152,7 +152,7 @@ uint32_t ByteAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memo
|
||||
}
|
||||
|
||||
uint32_t DwordIndex(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
|
||||
return Binary(ctx.state, OpShiftRightLogical, ctx.state.uint_type, ByteAddress(ctx, inst, mem),
|
||||
return Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), ByteAddress(ctx, inst, mem),
|
||||
ConstantU32(ctx.state, 2));
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ uint32_t LoadWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo me
|
||||
return EmitValueOrZeroIfCondition(ctx.state, InBounds(ctx, mem, index, pc), [&]() {
|
||||
const auto value = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpLoad, ctx.state.uint_type, value, Pointer(ctx, mem, index, pc)});
|
||||
{OpLoad, TypeU32(ctx.state), value, Pointer(ctx, mem, index, pc)});
|
||||
return value;
|
||||
});
|
||||
});
|
||||
@@ -191,24 +191,24 @@ uint32_t LoadSubword(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo
|
||||
const auto pc = inst.Flags<IR::MemoryFlags>().pc;
|
||||
return EmitValueOrZeroIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
|
||||
const auto address = ByteAddress(ctx, inst, mem);
|
||||
const auto index = Binary(ctx.state, OpShiftRightLogical, ctx.state.uint_type, address,
|
||||
const auto index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, 2));
|
||||
return EmitValueOrZeroIfCondition(ctx.state, InBounds(ctx, mem, index, pc), [&]() {
|
||||
const auto word = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpLoad, ctx.state.uint_type, word, Pointer(ctx, mem, index, pc)});
|
||||
const auto byte = Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type, address,
|
||||
{OpLoad, TypeU32(ctx.state), word, Pointer(ctx, mem, index, pc)});
|
||||
const auto byte = Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, 3));
|
||||
const auto shift = Binary(ctx.state, OpShiftLeftLogical, ctx.state.uint_type, byte,
|
||||
const auto shift = Binary(ctx.state, OpShiftLeftLogical, TypeU32(ctx.state), byte,
|
||||
ConstantU32(ctx.state, 3));
|
||||
const auto value =
|
||||
Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type,
|
||||
Binary(ctx.state, OpShiftRightLogical, ctx.state.uint_type, word, shift),
|
||||
Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state),
|
||||
Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), word, shift),
|
||||
ConstantU32(ctx.state, bits == 8u ? 0xffu : 0xffffu));
|
||||
if (!sign_extend) return value;
|
||||
const auto left = Binary(ctx.state, OpShiftLeftLogical, ctx.state.uint_type, value,
|
||||
const auto left = Binary(ctx.state, OpShiftLeftLogical, TypeU32(ctx.state), value,
|
||||
ConstantU32(ctx.state, 32u - bits));
|
||||
return Binary(ctx.state, OpShiftRightArithmetic, ctx.state.uint_type, left,
|
||||
return Binary(ctx.state, OpShiftRightArithmetic, TypeU32(ctx.state), left,
|
||||
ConstantU32(ctx.state, 32u - bits));
|
||||
});
|
||||
});
|
||||
@@ -256,16 +256,16 @@ uint32_t FormattedLoad(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Me
|
||||
if (info.packed_bitfield) {
|
||||
raw = LoadWord(ctx, inst, RebaseFormattedComponent(mem, format, component));
|
||||
const auto type =
|
||||
IsSignedFormatComponent(info.type) ? ctx.state.int_type : ctx.state.uint_type;
|
||||
IsSignedFormatComponent(info.type) ? TypeI32(ctx.state) : TypeU32(ctx.state);
|
||||
const auto source =
|
||||
type == ctx.state.int_type ? Unary(ctx.state, OpBitcast, type, raw) : raw;
|
||||
type == TypeI32(ctx.state) ? Unary(ctx.state, OpBitcast, type, raw) : raw;
|
||||
const auto extracted = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{IsSignedFormatComponent(info.type) ? OpBitFieldSExtract : OpBitFieldUExtract, type,
|
||||
extracted, source, ConstantU32(ctx.state, info.component_bit_offset[component]),
|
||||
ConstantU32(ctx.state, bits)});
|
||||
raw = type == ctx.state.int_type
|
||||
? Unary(ctx.state, OpBitcast, ctx.state.uint_type, extracted)
|
||||
raw = type == TypeI32(ctx.state)
|
||||
? Unary(ctx.state, OpBitcast, TypeU32(ctx.state), extracted)
|
||||
: extracted;
|
||||
} else if (bits == 32u) {
|
||||
raw = LoadWord(ctx, inst, RebaseFormattedComponent(mem, format, component));
|
||||
@@ -290,17 +290,17 @@ uint32_t AtomicUpdate(EmitterState& state, uint32_t pointer, IR::ResourceKind ki
|
||||
const auto exchanged = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBranch, preheader});
|
||||
state.builder.AddFunction({OpLabel, preheader});
|
||||
state.builder.AddFunction({OpAtomicLoad, state.uint_type, initial, pointer,
|
||||
state.builder.AddFunction({OpAtomicLoad, TypeU32(state), initial, pointer,
|
||||
ConstantU32(state, scope), ConstantU32(state, MemorySemanticsNone)});
|
||||
state.builder.AddFunction({OpBranch, header});
|
||||
state.builder.AddFunction({OpLabel, header});
|
||||
state.builder.AddFunction(
|
||||
{OpPhi, state.uint_type, observed, initial, preheader, exchanged, cont});
|
||||
{OpPhi, TypeU32(state), observed, initial, preheader, exchanged, cont});
|
||||
const auto next = desired(observed);
|
||||
state.builder.AddFunction({OpAtomicCompareExchange, state.uint_type, exchanged, pointer,
|
||||
state.builder.AddFunction({OpAtomicCompareExchange, TypeU32(state), exchanged, pointer,
|
||||
ConstantU32(state, scope), ConstantU32(state, MemorySemanticsNone),
|
||||
ConstantU32(state, MemorySemanticsNone), next, observed});
|
||||
const auto success = Binary(state, OpIEqual, state.bool_type, exchanged, observed);
|
||||
const auto success = Binary(state, OpIEqual, TypeBool(state), exchanged, observed);
|
||||
state.builder.AddFunction({OpLoopMerge, merge, cont, LoopControlNone});
|
||||
state.builder.AddFunction({OpBranchConditional, success, merge, cont});
|
||||
state.builder.AddFunction({OpLabel, cont});
|
||||
@@ -317,32 +317,32 @@ void StoreSubword(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo me
|
||||
const auto pc = inst.Flags<IR::MemoryFlags>().pc;
|
||||
EmitIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
|
||||
const auto address = ByteAddress(ctx, inst, mem);
|
||||
const auto index = Binary(ctx.state, OpShiftRightLogical, ctx.state.uint_type, address,
|
||||
const auto index = Binary(ctx.state, OpShiftRightLogical, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, 2));
|
||||
EmitIfCondition(ctx.state, InBounds(ctx, mem, index, pc), [&]() {
|
||||
const auto pointer = Pointer(ctx, mem, index, pc);
|
||||
const auto shift = Binary(ctx.state, OpShiftLeftLogical, ctx.state.uint_type,
|
||||
Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type, address,
|
||||
ConstantU32(ctx.state, 3)),
|
||||
ConstantU32(ctx.state, 3));
|
||||
const auto mask = Binary(ctx.state, OpShiftLeftLogical, ctx.state.uint_type,
|
||||
const auto shift = Binary(ctx.state, OpShiftLeftLogical, TypeU32(ctx.state),
|
||||
Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, 3)),
|
||||
ConstantU32(ctx.state, 3));
|
||||
const auto mask = Binary(ctx.state, OpShiftLeftLogical, TypeU32(ctx.state),
|
||||
ConstantU32(ctx.state, bits == 8u ? 0xffu : 0xffffu), shift);
|
||||
const auto value = Binary(ctx.state, OpShiftLeftLogical, ctx.state.uint_type,
|
||||
Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type,
|
||||
const auto value = Binary(ctx.state, OpShiftLeftLogical, TypeU32(ctx.state),
|
||||
Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state),
|
||||
ctx.Arg(inst, inst.NumArgs() - 2),
|
||||
ConstantU32(ctx.state, bits == 8u ? 0xffu : 0xffffu)),
|
||||
shift);
|
||||
const auto merge = [&](uint32_t old) {
|
||||
return Binary(ctx.state, OpBitwiseOr, ctx.state.uint_type,
|
||||
Binary(ctx.state, OpBitwiseAnd, ctx.state.uint_type, old,
|
||||
Unary(ctx.state, OpNot, ctx.state.uint_type, mask)),
|
||||
return Binary(ctx.state, OpBitwiseOr, TypeU32(ctx.state),
|
||||
Binary(ctx.state, OpBitwiseAnd, TypeU32(ctx.state), old,
|
||||
Unary(ctx.state, OpNot, TypeU32(ctx.state), mask)),
|
||||
value);
|
||||
};
|
||||
if (mem.kind == IR::ResourceKind::Lds || mem.kind == IR::ResourceKind::Gds) {
|
||||
AtomicUpdate(ctx.state, pointer, mem.kind, merge);
|
||||
} else {
|
||||
const auto old = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpLoad, ctx.state.uint_type, old, pointer});
|
||||
ctx.state.builder.AddFunction({OpLoad, TypeU32(ctx.state), old, pointer});
|
||||
ctx.state.builder.AddFunction({OpStore, pointer, merge(old)});
|
||||
}
|
||||
});
|
||||
@@ -425,7 +425,7 @@ uint32_t EmitAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memor
|
||||
const auto value = ctx.Arg(inst, inst.NumArgs() - 2);
|
||||
const auto old = ctx.state.builder.AllocateId();
|
||||
const auto scope = mem.kind == IR::ResourceKind::Lds ? ScopeWorkgroup : ScopeDevice;
|
||||
ctx.state.builder.AddFunction({AtomicOpcode(inst.GetOpcode()), ctx.state.uint_type,
|
||||
ctx.state.builder.AddFunction({AtomicOpcode(inst.GetOpcode()), TypeU32(ctx.state),
|
||||
old, Pointer(ctx, mem, index, pc),
|
||||
ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, MemorySemanticsNone), value});
|
||||
@@ -452,29 +452,29 @@ uint32_t FloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t sour
|
||||
uint32_t key;
|
||||
};
|
||||
const auto classify = [&](uint32_t bits) {
|
||||
const auto value = Unary(state, OpBitcast, state.float_type, bits);
|
||||
const auto value = Unary(state, OpBitcast, TypeF32(state), bits);
|
||||
const auto cls = EmitClassifyF32(state, value);
|
||||
const auto negative = Binary(
|
||||
state, OpINotEqual, state.bool_type,
|
||||
Binary(state, OpBitwiseAnd, state.uint_type, bits, ConstantU32(state, 0x80000000u)),
|
||||
state, OpINotEqual, TypeBool(state),
|
||||
Binary(state, OpBitwiseAnd, TypeU32(state), bits, ConstantU32(state, 0x80000000u)),
|
||||
ConstantU32(state, 0));
|
||||
const auto negative_key = Unary(state, OpNot, state.uint_type, bits);
|
||||
const auto negative_key = Unary(state, OpNot, TypeU32(state), bits);
|
||||
const auto positive_key =
|
||||
Binary(state, OpBitwiseXor, state.uint_type, bits, ConstantU32(state, 0x80000000u));
|
||||
Binary(state, OpBitwiseXor, TypeU32(state), bits, ConstantU32(state, 0x80000000u));
|
||||
return OrderedBits {cls.nan, cls.zero,
|
||||
Select(state, state.uint_type, negative, negative_key, positive_key)};
|
||||
Select(state, TypeU32(state), negative, negative_key, positive_key)};
|
||||
};
|
||||
const auto source_class = classify(source);
|
||||
const auto old_class = classify(old);
|
||||
const auto unordered =
|
||||
Binary(state, OpLogicalOr, state.bool_type,
|
||||
Binary(state, OpLogicalOr, state.bool_type, source_class.nan, old_class.nan),
|
||||
Binary(state, OpLogicalAnd, state.bool_type, source_class.zero, old_class.zero));
|
||||
const auto ordered = Unary(state, OpLogicalNot, state.bool_type, unordered);
|
||||
const auto compare = Binary(state, max_value ? OpUGreaterThan : OpULessThan, state.bool_type,
|
||||
Binary(state, OpLogicalOr, TypeBool(state),
|
||||
Binary(state, OpLogicalOr, TypeBool(state), source_class.nan, old_class.nan),
|
||||
Binary(state, OpLogicalAnd, TypeBool(state), source_class.zero, old_class.zero));
|
||||
const auto ordered = Unary(state, OpLogicalNot, TypeBool(state), unordered);
|
||||
const auto compare = Binary(state, max_value ? OpUGreaterThan : OpULessThan, TypeBool(state),
|
||||
source_class.key, old_class.key);
|
||||
return Select(state, state.uint_type,
|
||||
Binary(state, OpLogicalAnd, state.bool_type, ordered, compare), source, old);
|
||||
return Select(state, TypeU32(state),
|
||||
Binary(state, OpLogicalAnd, TypeBool(state), ordered, compare), source, old);
|
||||
}
|
||||
|
||||
uint32_t FloatAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
|
||||
@@ -501,17 +501,17 @@ uint32_t SharedFloatAtomic(ValueEmitContext& ctx, const IR::Inst& inst, const IR
|
||||
ctx.state.builder.AddFunction({OpStore, ctx.scratch_u32_variable, ctx.Arg(inst, 2)});
|
||||
const auto data = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpLoad, ctx.state.uint_type, data, ctx.scratch_u32_variable});
|
||||
{OpLoad, TypeU32(ctx.state), data, ctx.scratch_u32_variable});
|
||||
AtomicUpdate(ctx.state, Pointer(ctx, mem, index, pc), mem.kind, [&](uint32_t old) {
|
||||
const auto old_f = Unary(ctx.state, OpBitcast, ctx.state.float_type, old);
|
||||
const auto old_f = Unary(ctx.state, OpBitcast, TypeF32(ctx.state), old);
|
||||
const auto compare_f =
|
||||
Unary(ctx.state, OpBitcast, ctx.state.float_type, ctx.Arg(inst, 3));
|
||||
const auto data_f = Unary(ctx.state, OpBitcast, ctx.state.float_type, data);
|
||||
Unary(ctx.state, OpBitcast, TypeF32(ctx.state), ctx.Arg(inst, 3));
|
||||
const auto data_f = Unary(ctx.state, OpBitcast, TypeF32(ctx.state), data);
|
||||
const auto compare = Binary(
|
||||
ctx.state, max_value ? OpFOrdGreaterThan : OpFOrdLessThan, ctx.state.bool_type,
|
||||
ctx.state, max_value ? OpFOrdGreaterThan : OpFOrdLessThan, TypeBool(ctx.state),
|
||||
max_value ? old_f : compare_f, max_value ? compare_f : old_f);
|
||||
return Unary(ctx.state, OpBitcast, ctx.state.uint_type,
|
||||
Select(ctx.state, ctx.state.float_type, compare, data_f, old_f));
|
||||
return Unary(ctx.state, OpBitcast, TypeU32(ctx.state),
|
||||
Select(ctx.state, TypeF32(ctx.state), compare, data_f, old_f));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -522,49 +522,49 @@ uint32_t AppendConsume(ValueEmitContext& ctx, const IR::Inst& inst, bool gds, bo
|
||||
auto& state = ctx.state;
|
||||
const auto m0 = ctx.Arg(inst, 1);
|
||||
const auto base =
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, m0, ConstantU32(state, 16));
|
||||
const auto size = Binary(state, OpBitwiseAnd, state.uint_type, m0, ConstantU32(state, 0xffffu));
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), m0, ConstantU32(state, 16));
|
||||
const auto size = Binary(state, OpBitwiseAnd, TypeU32(state), m0, ConstantU32(state, 0xffffu));
|
||||
const auto address =
|
||||
Binary(state, OpIAdd, state.uint_type, base, ConstantU32(state, ctx.Memory(inst).offset));
|
||||
Binary(state, OpIAdd, TypeU32(state), base, ConstantU32(state, ctx.Memory(inst).offset));
|
||||
const auto index =
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, address, ConstantU32(state, 2));
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), address, ConstantU32(state, 2));
|
||||
const auto exec = ctx.Arg(inst, 2);
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallot, TypeU32Vector(state, 4), ballot,
|
||||
ConstantU32(state, ScopeSubgroup), exec});
|
||||
const auto low = state.builder.AllocateId();
|
||||
const auto high = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, low, ballot, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, ballot, 1});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), low, ballot, 0});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), high, ballot, 1});
|
||||
const auto count_low = state.per_invocation_masks ? low : ctx.Arg(inst, 3);
|
||||
const auto count_high = state.per_invocation_masks ? high : ctx.Arg(inst, 4);
|
||||
const auto count =
|
||||
Binary(state, OpIAdd, state.uint_type, Unary(state, OpBitCount, state.uint_type, count_low),
|
||||
Unary(state, OpBitCount, state.uint_type, count_high));
|
||||
Binary(state, OpIAdd, TypeU32(state), Unary(state, OpBitCount, TypeU32(state), count_low),
|
||||
Unary(state, OpBitCount, TypeU32(state), count_high));
|
||||
const auto first = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformBallotFindLSB, state.uint_type, first,
|
||||
state.builder.AddFunction({OpGroupNonUniformBallotFindLSB, TypeU32(state), first,
|
||||
ConstantU32(state, ScopeSubgroup), ballot});
|
||||
const auto is_first =
|
||||
Binary(state, OpIEqual, state.bool_type, EmitSubgroupLocalInvocationId(state), first);
|
||||
Binary(state, OpIEqual, TypeBool(state), EmitSubgroupLocalInvocationId(state), first);
|
||||
const auto storage_bounds =
|
||||
gds ? EmitGdsElementInBounds(state, index) : EmitLdsElementInBounds(state, index);
|
||||
const auto m0_bounds =
|
||||
gds ? Binary(state, OpINotEqual, state.bool_type, size, ConstantU32(state, 0))
|
||||
: Binary(state, OpULessThan, state.bool_type,
|
||||
gds ? Binary(state, OpINotEqual, TypeBool(state), size, ConstantU32(state, 0))
|
||||
: Binary(state, OpULessThan, TypeBool(state),
|
||||
ConstantU32(state, ctx.Memory(inst).offset + 3u), size);
|
||||
const auto condition = AndCondition(
|
||||
state, is_first, AndCondition(state, exec, AndCondition(state, storage_bounds, m0_bounds)));
|
||||
const auto atomic = EmitValueOrZeroIfCondition(state, condition, [&]() {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{append ? OpAtomicIAdd : OpAtomicISub, state.uint_type, value,
|
||||
{append ? OpAtomicIAdd : OpAtomicISub, TypeU32(state), value,
|
||||
gds ? EmitGdsElementPointer(state, index) : EmitLdsElementPointer(state, index),
|
||||
ConstantU32(state, gds ? ScopeDevice : ScopeWorkgroup),
|
||||
ConstantU32(state, MemorySemanticsNone), count});
|
||||
return value;
|
||||
});
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, result,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeU32(state), result,
|
||||
ConstantU32(state, ScopeSubgroup), atomic, first});
|
||||
return result;
|
||||
}
|
||||
@@ -584,25 +584,25 @@ bool EmitValueMemory(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return true;
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
ctx.Arg(inst, 1)});
|
||||
ctx.Emit(inst, OpLoad, IR::Type::U32, {pointer});
|
||||
return true;
|
||||
}
|
||||
if (op == IR::ValueOpcode::ReadConstBuffer) {
|
||||
auto mem = ctx.Memory(inst);
|
||||
mem.kind = IR::ResourceKind::ScalarBuffer;
|
||||
const auto address = Binary(state, OpIAdd, state.uint_type, ctx.Arg(inst, 1),
|
||||
ConstantU32(state, mem.offset));
|
||||
auto mem = ctx.Memory(inst);
|
||||
mem.kind = IR::ResourceKind::ScalarBuffer;
|
||||
const auto address =
|
||||
Binary(state, OpIAdd, TypeU32(state), ctx.Arg(inst, 1), ConstantU32(state, mem.offset));
|
||||
const auto index =
|
||||
Binary(state, OpShiftRightLogical, state.uint_type, address, ConstantU32(state, 2));
|
||||
Binary(state, OpShiftRightLogical, TypeU32(state), address, ConstantU32(state, 2));
|
||||
const auto pc = inst.Flags<IR::MemoryFlags>().pc;
|
||||
const auto condition = EmitStorageBufferElementInBounds(state, mem, index, pc);
|
||||
ctx.Define(inst, EmitValueOrZeroIfCondition(state, condition, [&]() {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLoad, state.uint_type, value,
|
||||
{OpLoad, TypeU32(state), value,
|
||||
EmitStorageBufferElementPointer(state, mem, index, pc)});
|
||||
return value;
|
||||
}));
|
||||
@@ -707,20 +707,20 @@ bool EmitValueMemory(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.state.builder.AddFunction({OpStore, ctx.scratch_u32_variable, ctx.Arg(inst, 0)});
|
||||
const auto source = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpLoad, ctx.state.uint_type, source, ctx.scratch_u32_variable});
|
||||
{OpLoad, TypeU32(ctx.state), source, ctx.scratch_u32_variable});
|
||||
const auto target =
|
||||
EmitDsSwizzleTargetLane(state, EmitSubgroupLocalInvocationId(state),
|
||||
inst.Arg(1).IsImmediate() ? inst.Arg(1).U32() : 0);
|
||||
const auto shuffled = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeU32(state), shuffled,
|
||||
ConstantU32(state, ScopeSubgroup), source, target});
|
||||
const auto source_exec = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, state.bool_type, source_exec,
|
||||
state.builder.AddFunction({OpGroupNonUniformShuffle, TypeBool(state), source_exec,
|
||||
ConstantU32(state, ScopeSubgroup), ctx.Arg(inst, 2), target});
|
||||
const auto source_active =
|
||||
AndCondition(state, source_exec, EmitSubgroupLaneActiveBool(state, target));
|
||||
ctx.Define(inst,
|
||||
Select(state, state.uint_type, source_active, shuffled, ConstantU32(state, 0)));
|
||||
Select(state, TypeU32(state), source_active, shuffled, ConstantU32(state, 0)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -6,19 +6,19 @@ uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index) {
|
||||
if (state.push_constant_variable != 0) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_push_constant_uint, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypePushConstantElementPointer(state), pointer,
|
||||
state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index)});
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), value, pointer});
|
||||
return value;
|
||||
}
|
||||
if (state.vsharp_storage_variable != 0) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.vsharp_storage_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index)});
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), value, pointer});
|
||||
return value;
|
||||
}
|
||||
return ConstantU32(state, 0);
|
||||
@@ -26,13 +26,13 @@ uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index) {
|
||||
|
||||
uint32_t EmitAddU32(EmitterState& state, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIAdd, state.uint_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({OpIAdd, TypeU32(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitBinaryU32(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs});
|
||||
state.builder.AddFunction({opcode, TypeU32(state), ret, lhs, rhs});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInf
|
||||
const auto binding =
|
||||
ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, mem.resource);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferPointer(state), pointer,
|
||||
state.address_memory_variable,
|
||||
ConstantU32(state, binding.array_index)});
|
||||
return pointer;
|
||||
}
|
||||
const auto binding = StorageBufferBindingForMemory(state, mem, use_pc);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferPointer(state), pointer,
|
||||
state.storage_buffer_variable,
|
||||
ConstantU32(state, binding.array_index)});
|
||||
return pointer;
|
||||
@@ -122,8 +122,8 @@ uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryI
|
||||
const auto object = EmitStorageBufferObjectPointer(state, mem, use_pc);
|
||||
const auto length = state.builder.AllocateId();
|
||||
const auto in_bounds = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpArrayLength, state.uint_type, length, object, 0});
|
||||
state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, index, length});
|
||||
state.builder.AddFunction({OpArrayLength, TypeU32(state), length, object, 0});
|
||||
state.builder.AddFunction({OpULessThan, TypeBool(state), in_bounds, index, length});
|
||||
return in_bounds;
|
||||
}
|
||||
|
||||
@@ -138,23 +138,18 @@ uint32_t EmitStorageBufferElementPointer(EmitterState& state, const IR::MemoryIn
|
||||
const auto binding =
|
||||
ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, mem.resource);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, state.ptr_storage_buffer_uint, pointer, state.address_memory_variable,
|
||||
ConstantU32(state, binding.array_index), ConstantU32(state, 0), index});
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.address_memory_variable,
|
||||
ConstantU32(state, binding.array_index), ConstantU32(state, 0),
|
||||
index});
|
||||
return pointer;
|
||||
}
|
||||
const auto binding = StorageBufferBindingForMemory(state, mem, use_pc);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, state.ptr_storage_buffer_uint, pointer, state.storage_buffer_variable,
|
||||
ConstantU32(state, binding.array_index), ConstantU32(state, 0), index});
|
||||
return pointer;
|
||||
}
|
||||
|
||||
uint32_t EmitLdsElementPointer(EmitterState& state, uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, state.ptr_workgroup_uint, pointer, state.lds_variable, index});
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.storage_buffer_variable,
|
||||
ConstantU32(state, binding.array_index), ConstantU32(state, 0),
|
||||
index});
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@@ -162,10 +157,34 @@ uint32_t LdsDwordCount(const EmitterState& state) {
|
||||
return state.stage == ShaderType::Compute ? state.input_info.compute->lds_size_dwords : 8192u;
|
||||
}
|
||||
|
||||
static void EnsureLdsStorage(EmitterState& state) {
|
||||
if (state.lds_variable != 0) {
|
||||
return;
|
||||
}
|
||||
if (state.stage != ShaderType::Compute) {
|
||||
EXIT("function LDS was not prepared before SPIR-V function emission\n");
|
||||
}
|
||||
state.lds_variable = state.builder.DefineGlobalVariable(
|
||||
TypeLdsArrayPointer(state, StorageClassWorkgroup), StorageClassWorkgroup);
|
||||
state.builder.AddName(state.lds_variable, "lds_dwords");
|
||||
}
|
||||
|
||||
uint32_t EmitLdsElementPointer(EmitterState& state, uint32_t index) {
|
||||
EnsureLdsStorage(state);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain,
|
||||
TypeLdsElementPointer(state, state.stage == ShaderType::Compute ? StorageClassWorkgroup
|
||||
: StorageClassFunction),
|
||||
pointer, state.lds_variable, index});
|
||||
return pointer;
|
||||
}
|
||||
|
||||
uint32_t EmitLdsElementInBounds(EmitterState& state, uint32_t index) {
|
||||
EnsureLdsStorage(state);
|
||||
const auto in_bounds = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpULessThan, state.bool_type, in_bounds, index, ConstantU32(state, LdsDwordCount(state))});
|
||||
{OpULessThan, TypeBool(state), in_bounds, index, ConstantU32(state, LdsDwordCount(state))});
|
||||
return in_bounds;
|
||||
}
|
||||
|
||||
@@ -182,34 +201,33 @@ uint32_t EmitMemoryElementPointer(EmitterState& state, const IR::MemoryInfo& mem
|
||||
|
||||
uint32_t EmitTBufferBitcastF32ToU32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, ret, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeU32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitTBufferBitcastU32ToF32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.float_type, ret, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeF32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitTBufferBitcastU32ToI32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitcast, state.int_type, ret, value});
|
||||
state.builder.AddFunction({OpBitcast, TypeI32(state), ret, value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitTBufferCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value,
|
||||
uint32_t constant) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, state.bool_type, ret, value, ConstantU32(state, constant)});
|
||||
state.builder.AddFunction({opcode, TypeBool(state), ret, value, ConstantU32(state, constant)});
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitTBufferSelectF32(EmitterState& state, uint32_t condition, uint32_t true_value,
|
||||
uint32_t false_value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.float_type, ret, condition, true_value, false_value});
|
||||
state.builder.AddFunction({OpSelect, TypeF32(state), ret, condition, true_value, false_value});
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -222,8 +240,8 @@ uint32_t EmitHalfToF32Bits(EmitterState& state, uint32_t raw) {
|
||||
const auto unpacked = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, raw});
|
||||
state.builder.AddFunction({OpCompositeExtract, state.float_type, value, unpacked, 0});
|
||||
{OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state), GlslUnpackHalf2x16, raw});
|
||||
state.builder.AddFunction({OpCompositeExtract, TypeF32(state), value, unpacked, 0});
|
||||
return EmitTBufferBitcastF32ToU32(state, value);
|
||||
}
|
||||
|
||||
@@ -251,9 +269,9 @@ uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits) {
|
||||
|
||||
const auto mantissa_f32 = state.builder.AllocateId();
|
||||
const auto subnormal = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertUToF, state.float_type, mantissa_f32, mantissa});
|
||||
state.builder.AddFunction({OpConvertUToF, TypeF32(state), mantissa_f32, mantissa});
|
||||
state.builder.AddFunction(
|
||||
{OpFMul, state.float_type, subnormal, mantissa_f32,
|
||||
{OpFMul, TypeF32(state), subnormal, mantissa_f32,
|
||||
ConstantF32Value(state, std::ldexp(1.0f, 1 - 15 - static_cast<int>(mantissa_bits)))});
|
||||
|
||||
const auto zero_exp = EmitTBufferCompareU32Constant(state, OpIEqual, exponent, 0);
|
||||
@@ -271,22 +289,22 @@ uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferForma
|
||||
case Format::ComponentType::Sint: return raw;
|
||||
case Format::ComponentType::Uscaled: {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertUToF, state.float_type, value, raw});
|
||||
state.builder.AddFunction({OpConvertUToF, TypeF32(state), value, raw});
|
||||
return EmitTBufferBitcastF32ToU32(state, value);
|
||||
}
|
||||
case Format::ComponentType::Sscaled: {
|
||||
const auto signed_raw = EmitTBufferBitcastU32ToI32(state, raw);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpConvertSToF, state.float_type, value, signed_raw});
|
||||
state.builder.AddFunction({OpConvertSToF, TypeF32(state), value, signed_raw});
|
||||
return EmitTBufferBitcastF32ToU32(state, value);
|
||||
}
|
||||
case Format::ComponentType::Unorm: {
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto normalized = state.builder.AllocateId();
|
||||
const auto max_value = static_cast<float>((1u << bits) - 1u);
|
||||
state.builder.AddFunction({OpConvertUToF, state.float_type, value, raw});
|
||||
state.builder.AddFunction({OpConvertUToF, TypeF32(state), value, raw});
|
||||
state.builder.AddFunction(
|
||||
{OpFDiv, state.float_type, normalized, value, ConstantF32Value(state, max_value)});
|
||||
{OpFDiv, TypeF32(state), normalized, value, ConstantF32Value(state, max_value)});
|
||||
return EmitTBufferBitcastF32ToU32(state, normalized);
|
||||
}
|
||||
case Format::ComponentType::Snorm: {
|
||||
@@ -295,10 +313,10 @@ uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferForma
|
||||
const auto normalized = state.builder.AllocateId();
|
||||
const auto clamped = state.builder.AllocateId();
|
||||
const auto max_value = static_cast<float>((1u << (bits - 1u)) - 1u);
|
||||
state.builder.AddFunction({OpConvertSToF, state.float_type, value, signed_raw});
|
||||
state.builder.AddFunction({OpConvertSToF, TypeF32(state), value, signed_raw});
|
||||
state.builder.AddFunction(
|
||||
{OpFDiv, state.float_type, normalized, value, ConstantF32Value(state, max_value)});
|
||||
state.builder.AddFunction({OpExtInst, state.float_type, clamped, state.glsl_std450,
|
||||
{OpFDiv, TypeF32(state), normalized, value, ConstantF32Value(state, max_value)});
|
||||
state.builder.AddFunction({OpExtInst, TypeF32(state), clamped, GlslStd450(state),
|
||||
GlslFMax, normalized, ConstantF32Value(state, -1.0f)});
|
||||
return EmitTBufferBitcastF32ToU32(state, clamped);
|
||||
}
|
||||
@@ -323,14 +341,14 @@ void EmitDeviceAtomicMemoryBarrier(EmitterState& state) {
|
||||
uint32_t EmitGdsElementInBounds(EmitterState& state, uint32_t index) {
|
||||
const auto length = state.builder.AllocateId();
|
||||
const auto in_bounds = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpArrayLength, state.uint_type, length, state.gds_variable, 0});
|
||||
state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, index, length});
|
||||
state.builder.AddFunction({OpArrayLength, TypeU32(state), length, state.gds_variable, 0});
|
||||
state.builder.AddFunction({OpULessThan, TypeBool(state), in_bounds, index, length});
|
||||
return in_bounds;
|
||||
}
|
||||
|
||||
uint32_t EmitGdsElementPointer(EmitterState& state, uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer,
|
||||
state.builder.AddFunction({OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.gds_variable, ConstantU32(state, 0), index});
|
||||
return pointer;
|
||||
}
|
||||
@@ -358,16 +376,16 @@ uint32_t EmitDsSwizzleTargetLane(EmitterState& state, uint32_t subid, uint32_t c
|
||||
const auto base = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, lane2, subid, ConstantU32(state, 3)});
|
||||
{OpBitwiseAnd, TypeU32(state), lane2, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, shift, lane2, ConstantU32(state, 1)});
|
||||
{OpShiftLeftLogical, TypeU32(state), shift, lane2, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftRightLogical, state.uint_type, perm0, ConstantU32(state, control), shift});
|
||||
{OpShiftRightLogical, TypeU32(state), perm0, ConstantU32(state, control), shift});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, perm, perm0, ConstantU32(state, 3)});
|
||||
{OpBitwiseAnd, TypeU32(state), perm, perm0, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, perm});
|
||||
{OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, base, perm});
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -377,16 +395,16 @@ uint32_t EmitDsSwizzleTargetLane(EmitterState& state, uint32_t subid, uint32_t c
|
||||
const auto xored = state.builder.AllocateId();
|
||||
const auto base = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, masked, lane, ConstantU32(state, control & 0x1fu)});
|
||||
{OpBitwiseAnd, TypeU32(state), masked, lane, ConstantU32(state, control & 0x1fu)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseOr, state.uint_type, ored, masked, ConstantU32(state, (control >> 5u) & 0x1fu)});
|
||||
{OpBitwiseOr, TypeU32(state), ored, masked, ConstantU32(state, (control >> 5u) & 0x1fu)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseXor, state.uint_type, xored, ored, ConstantU32(state, (control >> 10u) & 0x1fu)});
|
||||
{OpBitwiseXor, TypeU32(state), xored, ored, ConstantU32(state, (control >> 10u) & 0x1fu)});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, 0xffffffe0u)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, xored});
|
||||
{OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, 0xffffffe0u)});
|
||||
state.builder.AddFunction({OpBitwiseOr, TypeU32(state), target, base, xored});
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,201 @@
|
||||
|
||||
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(OpTypeVoid);
|
||||
}
|
||||
|
||||
uint32_t TypeBool(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeBool);
|
||||
}
|
||||
|
||||
uint32_t TypeU32(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeInt, {32, 0});
|
||||
}
|
||||
|
||||
uint32_t TypeU32Pair(EmitterState& state) {
|
||||
const auto element = TypeU32(state);
|
||||
return state.builder.Type(OpTypeStruct, {element, element});
|
||||
}
|
||||
|
||||
uint32_t TypeI32(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeInt, {32, 1});
|
||||
}
|
||||
|
||||
uint32_t TypeI32Pair(EmitterState& state) {
|
||||
const auto element = TypeI32(state);
|
||||
return state.builder.Type(OpTypeStruct, {element, element});
|
||||
}
|
||||
|
||||
uint32_t TypeF32(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeFloat, {32});
|
||||
}
|
||||
|
||||
uint32_t TypeU32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(OpTypeVector, {TypeU32(state), components});
|
||||
}
|
||||
|
||||
uint32_t TypeI32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(OpTypeVector, {TypeI32(state), components});
|
||||
}
|
||||
|
||||
uint32_t TypeF32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(OpTypeVector, {TypeF32(state), components});
|
||||
}
|
||||
|
||||
uint32_t TypePointer(EmitterState& state, uint32_t storage_class, uint32_t pointee) {
|
||||
return state.builder.Type(OpTypePointer, {storage_class, pointee});
|
||||
}
|
||||
|
||||
uint32_t TypeFunction(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeFunction, {TypeVoid(state)});
|
||||
}
|
||||
|
||||
uint32_t StorageRuntimeArrayType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(OpTypeRuntimeArray, {TypeU32(state)},
|
||||
{{OpDecorate, {DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
}
|
||||
|
||||
uint32_t StorageBufferType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(
|
||||
OpTypeStruct, {StorageRuntimeArrayType(state)},
|
||||
{{OpMemberDecorate, {0, DecorationOffset, 0}}, {OpDecorate, {DecorationBlock}}});
|
||||
}
|
||||
|
||||
uint32_t TypeStorageBufferPointer(EmitterState& state) {
|
||||
return TypePointer(state, StorageClassStorageBuffer, StorageBufferType(state));
|
||||
}
|
||||
|
||||
uint32_t TypeStorageBufferElementPointer(EmitterState& state) {
|
||||
return TypePointer(state, StorageClassStorageBuffer, TypeU32(state));
|
||||
}
|
||||
|
||||
uint32_t TypePushConstantElementPointer(EmitterState& state) {
|
||||
return TypePointer(state, StorageClassPushConstant, TypeU32(state));
|
||||
}
|
||||
|
||||
uint32_t TypeLdsArrayPointer(EmitterState& state, uint32_t storage_class) {
|
||||
const auto count = ConstantU32(state, std::max(LdsDwordCount(state), 1u));
|
||||
const auto array = state.builder.Type(OpTypeArray, {TypeU32(state), count});
|
||||
return TypePointer(state, storage_class, array);
|
||||
}
|
||||
|
||||
uint32_t TypeLdsElementPointer(EmitterState& state, uint32_t storage_class) {
|
||||
return TypePointer(state, storage_class, TypeU32(state));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t PushConstantArrayType(EmitterState& state) {
|
||||
const auto count =
|
||||
ConstantU32(state, state.program.bindings.push_constant_size / sizeof(uint32_t));
|
||||
return state.builder.DecoratedType(OpTypeArray, {TypeU32(state), count},
|
||||
{{OpDecorate, {DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
}
|
||||
|
||||
uint32_t PushConstantBlockType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(
|
||||
OpTypeStruct, {PushConstantArrayType(state)},
|
||||
{{OpMemberDecorate, {0, DecorationOffset, state.program.bindings.push_constant_offset}},
|
||||
{OpDecorate, {DecorationBlock}}});
|
||||
}
|
||||
|
||||
uint32_t PerVertexType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(OpTypeStruct, {TypeF32Vector(state, 4)},
|
||||
{{OpMemberDecorate, {0, DecorationBuiltIn, BuiltInPosition}},
|
||||
{OpDecorate, {DecorationBlock}}});
|
||||
}
|
||||
|
||||
uint32_t SampleMaskArrayType(EmitterState& state) {
|
||||
return state.builder.Type(OpTypeArray, {TypeI32(state), ConstantU32(state, 1)});
|
||||
}
|
||||
|
||||
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(OpTypeArray, {StorageBufferType(state), count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassStorageBuffer, array_type);
|
||||
state.storage_buffer_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassStorageBuffer);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::AddressMemory) != nullptr) {
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::AddressMemory));
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {StorageBufferType(state), count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassStorageBuffer, array_type);
|
||||
state.address_memory_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassStorageBuffer);
|
||||
}
|
||||
if (state.program.bindings.push_constant_size != 0) {
|
||||
const auto pointer_type =
|
||||
TypePointer(state, StorageClassPushConstant, PushConstantBlockType(state));
|
||||
state.push_constant_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassPushConstant);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::UserData) != nullptr) {
|
||||
state.vsharp_storage_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), StorageClassStorageBuffer);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::FlattenedSrt) != nullptr) {
|
||||
state.flattened_srt_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), StorageClassStorageBuffer);
|
||||
}
|
||||
for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % SampledImageViewKindCount);
|
||||
const bool integer = i >= SampledImageViewKindCount;
|
||||
const auto kind = SampledBindingKind(integer, view);
|
||||
if (DescriptorBinding(state, kind) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
||||
const auto image_type = ImageViewImageType(state, view, integer);
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {image_type, count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
||||
state.sampled_image_variables[i] =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
||||
if (view == ImageViewKind::Dim1D || view == ImageViewKind::Dim1DArray) {
|
||||
state.builder.RequireCapability(CapabilitySampled1D);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % StorageImageViewKindCount);
|
||||
const bool integer = i >= StorageImageViewKindCount;
|
||||
const auto kind = StorageBindingKind(integer, view);
|
||||
if (DescriptorBinding(state, kind) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
||||
const auto image_type = StorageImageType(state, integer, view);
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {image_type, count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
||||
state.storage_image_variables[i] =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
||||
if (view == ImageViewKind::Dim1D || view == ImageViewKind::Dim1DArray) {
|
||||
state.builder.RequireCapability(CapabilityImage1D);
|
||||
}
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
||||
const auto sampler_type = state.builder.Type(OpTypeSampler);
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Samplers));
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {sampler_type, count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
||||
state.sampler_variable =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Gds) != nullptr) {
|
||||
state.gds_variable = state.builder.DefineGlobalVariable(TypeStorageBufferPointer(state),
|
||||
StorageClassStorageBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const IR::DescriptorBinding* DescriptorBinding(const EmitterState& state,
|
||||
IR::DescriptorBindingKind kind) {
|
||||
return IR::FindBinding(state.program.bindings, kind);
|
||||
@@ -15,37 +210,15 @@ uint32_t DescriptorCount(const EmitterState& state, IR::DescriptorBindingKind ki
|
||||
}
|
||||
|
||||
uint32_t ConstantU32(EmitterState& state, uint32_t value) {
|
||||
if (auto it = state.constants.find(value); it != state.constants.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.constants.emplace(value, id);
|
||||
state.builder.AddType({OpConstant, state.uint_type, id, value});
|
||||
return id;
|
||||
return state.builder.Constant(OpConstant, TypeU32(state), {value});
|
||||
}
|
||||
|
||||
uint32_t ConstantI32(EmitterState& state, int32_t value) {
|
||||
const auto bits = static_cast<uint32_t>(value);
|
||||
if (auto it = state.signed_constants.find(bits); it != state.signed_constants.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.signed_constants.emplace(bits, id);
|
||||
state.builder.AddType({OpConstant, state.int_type, id, bits});
|
||||
return id;
|
||||
return state.builder.Constant(OpConstant, TypeI32(state), {static_cast<uint32_t>(value)});
|
||||
}
|
||||
|
||||
uint32_t ConstantF32(EmitterState& state, uint32_t bits) {
|
||||
if (auto it = state.float_constants.find(bits); it != state.float_constants.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.float_constants.emplace(bits, id);
|
||||
state.builder.AddType({OpConstant, state.float_type, id, bits});
|
||||
return id;
|
||||
return state.builder.Constant(OpConstant, TypeF32(state), {bits});
|
||||
}
|
||||
|
||||
uint32_t FloatBits(float value) {
|
||||
@@ -58,6 +231,26 @@ uint32_t ConstantF32Value(EmitterState& state, float value) {
|
||||
return ConstantF32(state, FloatBits(value));
|
||||
}
|
||||
|
||||
uint32_t ConstantBool(EmitterState& state, bool value) {
|
||||
return state.builder.Constant(value ? OpConstantTrue : OpConstantFalse, TypeBool(state));
|
||||
}
|
||||
|
||||
uint32_t ConstantU64(EmitterState& state, uint64_t value) {
|
||||
return state.builder.Constant(OpConstantComposite, TypeU32Pair(state),
|
||||
{ConstantU32(state, static_cast<uint32_t>(value)),
|
||||
ConstantU32(state, static_cast<uint32_t>(value >> 32u))});
|
||||
}
|
||||
|
||||
uint32_t ConstantU32x4Zero(EmitterState& state) {
|
||||
const auto zero = ConstantU32(state, 0);
|
||||
return state.builder.Constant(OpConstantComposite, TypeU32Vector(state, 4),
|
||||
{zero, zero, zero, zero});
|
||||
}
|
||||
|
||||
uint32_t GlslStd450(EmitterState& state) {
|
||||
return state.builder.Import("GLSL.std.450");
|
||||
}
|
||||
|
||||
VertexInputScalarKind VertexParameterScalarKind(const EmitterState& state, uint32_t location) {
|
||||
if (state.stage != ShaderType::Vertex || location >= ShaderVertexInputInfo::RES_MAX ||
|
||||
location >= static_cast<uint32_t>(state.input_info.vertex->resources_num)) {
|
||||
@@ -100,76 +293,78 @@ uint32_t VertexParameterComponentCount(const EmitterState& state, const InputBin
|
||||
return std::clamp(count, 1u, 4u);
|
||||
}
|
||||
|
||||
uint32_t VertexParameterScalarType(const EmitterState& state, VertexInputScalarKind kind) {
|
||||
uint32_t VertexParameterScalarType(EmitterState& state, VertexInputScalarKind kind) {
|
||||
switch (kind) {
|
||||
case VertexInputScalarKind::Sint: return state.int_type;
|
||||
case VertexInputScalarKind::Uint: return state.uint_type;
|
||||
case VertexInputScalarKind::Sint: return TypeI32(state);
|
||||
case VertexInputScalarKind::Uint: return TypeU32(state);
|
||||
case VertexInputScalarKind::Float:
|
||||
default: return state.float_type;
|
||||
default: return TypeF32(state);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VertexParameterScalarPointerType(const EmitterState& state, VertexInputScalarKind kind) {
|
||||
uint32_t VertexParameterScalarPointerType(EmitterState& state, VertexInputScalarKind kind) {
|
||||
switch (kind) {
|
||||
case VertexInputScalarKind::Sint: return state.ptr_input_int;
|
||||
case VertexInputScalarKind::Uint: return state.ptr_input_uint;
|
||||
case VertexInputScalarKind::Sint:
|
||||
return TypePointer(state, StorageClassInput, TypeI32(state));
|
||||
case VertexInputScalarKind::Uint:
|
||||
return TypePointer(state, StorageClassInput, TypeU32(state));
|
||||
case VertexInputScalarKind::Float:
|
||||
default: return state.ptr_input_float;
|
||||
default: return TypePointer(state, StorageClassInput, TypeF32(state));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VertexParameterVectorOrScalarType(const EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t VertexParameterVectorOrScalarType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components) {
|
||||
switch (kind) {
|
||||
case VertexInputScalarKind::Sint:
|
||||
switch (components) {
|
||||
case 1: return state.int_type;
|
||||
case 2: return state.vec2_int_type;
|
||||
case 3: return state.vec3_int_type;
|
||||
default: return state.vec4_int_type;
|
||||
case 1: return TypeI32(state);
|
||||
case 2: return TypeI32Vector(state, 2);
|
||||
case 3: return TypeI32Vector(state, 3);
|
||||
default: return TypeI32Vector(state, 4);
|
||||
}
|
||||
case VertexInputScalarKind::Uint:
|
||||
switch (components) {
|
||||
case 1: return state.uint_type;
|
||||
case 2: return state.vec2_uint_type;
|
||||
case 3: return state.vec3_uint_type;
|
||||
default: return state.vec4_uint_type;
|
||||
case 1: return TypeU32(state);
|
||||
case 2: return TypeU32Vector(state, 2);
|
||||
case 3: return TypeU32Vector(state, 3);
|
||||
default: return TypeU32Vector(state, 4);
|
||||
}
|
||||
case VertexInputScalarKind::Float:
|
||||
default:
|
||||
switch (components) {
|
||||
case 1: return state.float_type;
|
||||
case 2: return state.vec2_float_type;
|
||||
case 3: return state.vec3_float_type;
|
||||
default: return state.vec4_float_type;
|
||||
case 1: return TypeF32(state);
|
||||
case 2: return TypeF32Vector(state, 2);
|
||||
case 3: return TypeF32Vector(state, 3);
|
||||
default: return TypeF32Vector(state, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VertexParameterInputPointerType(const EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t VertexParameterInputPointerType(EmitterState& state, VertexInputScalarKind kind,
|
||||
uint32_t components) {
|
||||
switch (kind) {
|
||||
case VertexInputScalarKind::Sint:
|
||||
switch (components) {
|
||||
case 1: return state.ptr_input_int;
|
||||
case 2: return state.ptr_input_vec2_int;
|
||||
case 3: return state.ptr_input_vec3_int;
|
||||
default: return state.ptr_input_vec4_int;
|
||||
case 1: return TypePointer(state, StorageClassInput, TypeI32(state));
|
||||
case 2: return TypePointer(state, StorageClassInput, TypeI32Vector(state, 2));
|
||||
case 3: return TypePointer(state, StorageClassInput, TypeI32Vector(state, 3));
|
||||
default: return TypePointer(state, StorageClassInput, TypeI32Vector(state, 4));
|
||||
}
|
||||
case VertexInputScalarKind::Uint:
|
||||
switch (components) {
|
||||
case 1: return state.ptr_input_uint;
|
||||
case 2: return state.ptr_input_vec2_uint;
|
||||
case 3: return state.ptr_input_vec3_uint;
|
||||
default: return state.ptr_input_vec4_uint;
|
||||
case 1: return TypePointer(state, StorageClassInput, TypeU32(state));
|
||||
case 2: return TypePointer(state, StorageClassInput, TypeU32Vector(state, 2));
|
||||
case 3: return TypePointer(state, StorageClassInput, TypeU32Vector(state, 3));
|
||||
default: return TypePointer(state, StorageClassInput, TypeU32Vector(state, 4));
|
||||
}
|
||||
case VertexInputScalarKind::Float:
|
||||
default:
|
||||
switch (components) {
|
||||
case 1: return state.ptr_input_float;
|
||||
case 2: return state.ptr_input_vec2_float;
|
||||
case 3: return state.ptr_input_vec3_float;
|
||||
default: return state.ptr_input_vec4_float;
|
||||
case 1: return TypePointer(state, StorageClassInput, TypeF32(state));
|
||||
case 2: return TypePointer(state, StorageClassInput, TypeF32Vector(state, 2));
|
||||
case 3: return TypePointer(state, StorageClassInput, TypeF32Vector(state, 3));
|
||||
default: return TypePointer(state, StorageClassInput, TypeF32Vector(state, 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +380,7 @@ void AllocateInputVariables(EmitterState& state) {
|
||||
binding.variable_id = state.builder.AllocateId();
|
||||
state.interface_variables.push_back(binding.variable_id);
|
||||
}
|
||||
if (state.needs_subgroup_local_invocation_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);
|
||||
}
|
||||
@@ -278,11 +473,8 @@ void AddInputAnnotationsAndNames(EmitterState& state) {
|
||||
|
||||
void AddOutputAnnotationsAndNames(EmitterState& state) {
|
||||
if (state.per_vertex_variable != 0) {
|
||||
state.builder.AddName(state.per_vertex_type, "gl_PerVertex");
|
||||
state.builder.AddName(PerVertexType(state), "gl_PerVertex");
|
||||
state.builder.AddName(state.per_vertex_variable, "outPerVertex");
|
||||
state.builder.AddAnnotation(
|
||||
{OpMemberDecorate, state.per_vertex_type, 0, DecorationBuiltIn, BuiltInPosition});
|
||||
state.builder.AddAnnotation({OpDecorate, state.per_vertex_type, DecorationBlock});
|
||||
}
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.AddName(state.depth_variable, "gl_FragDepth");
|
||||
@@ -343,9 +535,9 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
||||
"sampled_uint_3d",
|
||||
"sampled_uint_2d_msaa",
|
||||
"sampled_uint_2d_msaa_array"};
|
||||
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
|
||||
for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % SampledImageViewKindCount);
|
||||
Decorate(state.sampled_images[i].variable, SampledNames[i],
|
||||
Decorate(state.sampled_image_variables[i], SampledNames[i],
|
||||
SampledBindingKind(i >= SampledImageViewKindCount, view));
|
||||
}
|
||||
constexpr const char* StorageNames[] = {"storage_1d",
|
||||
@@ -358,9 +550,9 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
||||
"storage_uint_2d",
|
||||
"storage_uint_2d_array",
|
||||
"storage_uint_3d"};
|
||||
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
|
||||
for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % StorageImageViewKindCount);
|
||||
Decorate(state.storage_images[i].variable, StorageNames[i],
|
||||
Decorate(state.storage_image_variables[i], StorageNames[i],
|
||||
StorageBindingKind(i >= StorageImageViewKindCount, view));
|
||||
}
|
||||
if (state.sampler_variable != 0) {
|
||||
@@ -378,13 +570,8 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
||||
void AddVsharpAnnotationsAndNames(EmitterState& state) {
|
||||
const auto& bind = state.program.bindings;
|
||||
if (state.push_constant_variable != 0) {
|
||||
state.builder.AddName(state.push_constant_block_type, "BufferResource");
|
||||
state.builder.AddName(PushConstantBlockType(state), "BufferResource");
|
||||
state.builder.AddName(state.push_constant_variable, "vsharp");
|
||||
state.builder.AddAnnotation(
|
||||
{OpDecorate, state.push_constant_array_type, DecorationArrayStride, 4});
|
||||
state.builder.AddAnnotation({OpMemberDecorate, state.push_constant_block_type, 0,
|
||||
DecorationOffset, bind.push_constant_offset});
|
||||
state.builder.AddAnnotation({OpDecorate, state.push_constant_block_type, DecorationBlock});
|
||||
}
|
||||
if (state.vsharp_storage_variable != 0) {
|
||||
const auto* storage = DescriptorBinding(state, IR::DescriptorBindingKind::UserData);
|
||||
@@ -395,123 +582,34 @@ void AddVsharpAnnotationsAndNames(EmitterState& state) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitHeaderAndTypes(EmitterState& state) {
|
||||
state.void_type = state.builder.AllocateId();
|
||||
state.bool_type = state.builder.AllocateId();
|
||||
state.uint_type = state.builder.AllocateId();
|
||||
state.uint_pair_type = state.builder.AllocateId();
|
||||
state.int_type = state.builder.AllocateId();
|
||||
state.int_pair_type = state.builder.AllocateId();
|
||||
state.float_type = state.builder.AllocateId();
|
||||
state.vec2_uint_type = state.builder.AllocateId();
|
||||
state.vec3_uint_type = state.builder.AllocateId();
|
||||
state.vec4_uint_type = state.builder.AllocateId();
|
||||
state.vec2_int_type = state.builder.AllocateId();
|
||||
state.vec3_int_type = state.builder.AllocateId();
|
||||
state.vec4_int_type = state.builder.AllocateId();
|
||||
state.vec2_float_type = state.builder.AllocateId();
|
||||
state.vec3_float_type = state.builder.AllocateId();
|
||||
state.vec4_float_type = state.builder.AllocateId();
|
||||
state.ptr_func_uint = state.builder.AllocateId();
|
||||
state.ptr_func_bool = state.builder.AllocateId();
|
||||
state.ptr_func_float = state.builder.AllocateId();
|
||||
state.ptr_func_uint_pair = state.builder.AllocateId();
|
||||
state.ptr_func_vec4_uint = state.builder.AllocateId();
|
||||
state.ptr_func_vec2_float = state.builder.AllocateId();
|
||||
state.ptr_input_float = state.builder.AllocateId();
|
||||
state.ptr_input_bool = state.builder.AllocateId();
|
||||
state.ptr_input_int = state.builder.AllocateId();
|
||||
state.ptr_input_uint = state.builder.AllocateId();
|
||||
state.ptr_input_vec2_float = state.builder.AllocateId();
|
||||
state.ptr_input_vec3_float = state.builder.AllocateId();
|
||||
state.ptr_input_vec2_int = state.builder.AllocateId();
|
||||
state.ptr_input_vec3_int = state.builder.AllocateId();
|
||||
state.ptr_input_vec4_int = state.builder.AllocateId();
|
||||
state.ptr_input_vec2_uint = state.builder.AllocateId();
|
||||
state.ptr_input_vec3_uint = state.builder.AllocateId();
|
||||
state.ptr_input_vec4_uint = state.builder.AllocateId();
|
||||
state.ptr_input_vec4_float = state.builder.AllocateId();
|
||||
state.sample_mask_array_type = state.builder.AllocateId();
|
||||
state.ptr_output_int = state.builder.AllocateId();
|
||||
state.ptr_output_sample_mask_array = state.builder.AllocateId();
|
||||
state.ptr_output_float = state.builder.AllocateId();
|
||||
state.ptr_output_vec4_float = state.builder.AllocateId();
|
||||
const auto ptr_output_vec4_uint = state.builder.AllocateId();
|
||||
state.per_vertex_type = state.builder.AllocateId();
|
||||
state.ptr_output_per_vertex = state.builder.AllocateId();
|
||||
state.storage_runtime_array_type = state.builder.AllocateId();
|
||||
state.storage_buffer_type = state.builder.AllocateId();
|
||||
state.ptr_storage_buffer = state.builder.AllocateId();
|
||||
state.ptr_storage_buffer_uint = state.builder.AllocateId();
|
||||
state.storage_buffer_array_type = state.builder.AllocateId();
|
||||
state.ptr_storage_buffer_array = state.builder.AllocateId();
|
||||
if (state.address_memory_variable != 0) {
|
||||
state.address_memory_array_type = state.builder.AllocateId();
|
||||
state.ptr_address_memory_array = state.builder.AllocateId();
|
||||
void DefineModule(EmitterState& state) {
|
||||
DefineDescriptorVariables(state);
|
||||
if (state.requirements.function_lds) {
|
||||
state.lds_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (state.push_constant_variable != 0) {
|
||||
state.push_constant_array_type = state.builder.AllocateId();
|
||||
state.push_constant_block_type = state.builder.AllocateId();
|
||||
state.ptr_push_constant_block = state.builder.AllocateId();
|
||||
state.ptr_push_constant_uint = state.builder.AllocateId();
|
||||
}
|
||||
state.lds_array_type = state.builder.AllocateId();
|
||||
state.ptr_workgroup_array = state.builder.AllocateId();
|
||||
state.ptr_workgroup_uint = state.builder.AllocateId();
|
||||
state.lds_variable = state.builder.AllocateId();
|
||||
for (auto& image: state.sampled_images) {
|
||||
image.image_type = state.builder.AllocateId();
|
||||
image.sampled_image_type = state.builder.AllocateId();
|
||||
image.pointer_type = state.builder.AllocateId();
|
||||
image.array_type = state.builder.AllocateId();
|
||||
image.array_pointer_type = state.builder.AllocateId();
|
||||
}
|
||||
for (auto& image: state.storage_images) {
|
||||
image.image_type = state.builder.AllocateId();
|
||||
image.pointer_type = state.builder.AllocateId();
|
||||
image.array_type = state.builder.AllocateId();
|
||||
image.array_pointer_type = state.builder.AllocateId();
|
||||
}
|
||||
state.sampler_type = state.builder.AllocateId();
|
||||
state.sampler_array_type = state.builder.AllocateId();
|
||||
state.ptr_uniform_sampler = state.builder.AllocateId();
|
||||
state.ptr_uniform_sampler_array = state.builder.AllocateId();
|
||||
state.ptr_image_uint = state.builder.AllocateId();
|
||||
state.func_type = state.builder.AllocateId();
|
||||
state.main_func = state.builder.AllocateId();
|
||||
state.entry_label = state.builder.AllocateId();
|
||||
state.glsl_std450 = state.builder.AllocateId();
|
||||
state.main_func = state.builder.AllocateId();
|
||||
state.entry_label = state.builder.AllocateId();
|
||||
|
||||
state.builder.AddCapability({CapabilityShader});
|
||||
state.builder.AddCapability({CapabilitySampled1D});
|
||||
state.builder.AddCapability({CapabilityImage1D});
|
||||
state.builder.AddCapability({CapabilityImageQuery});
|
||||
state.builder.AddCapability({CapabilitySignedZeroInfNanPreserve});
|
||||
if (state.needs_image_gather_extended) {
|
||||
state.builder.AddCapability({CapabilityImageGatherExtended});
|
||||
state.builder.RequireCapability(CapabilityShader);
|
||||
state.builder.RequireCapability(CapabilitySignedZeroInfNanPreserve);
|
||||
if (state.requirements.image_gather_extended) {
|
||||
state.builder.RequireCapability(CapabilityImageGatherExtended);
|
||||
}
|
||||
if (std::any_of(state.storage_images.begin(),
|
||||
state.storage_images.begin() + StorageImageViewKindCount,
|
||||
[](const auto& image) { return image.variable != 0; })) {
|
||||
state.builder.AddCapability({CapabilityStorageImageReadWithoutFormat});
|
||||
state.builder.AddCapability({CapabilityStorageImageWriteWithoutFormat});
|
||||
if (state.requirements.subgroup_ballot || state.requirements.subgroup_shuffle ||
|
||||
state.requirements.subgroup_local_invocation_id) {
|
||||
state.builder.RequireCapability(CapabilityGroupNonUniform);
|
||||
}
|
||||
if (state.needs_subgroup_ballot || state.needs_subgroup_shuffle ||
|
||||
state.needs_subgroup_local_invocation_id) {
|
||||
state.builder.AddCapability({CapabilityGroupNonUniform});
|
||||
if (state.requirements.subgroup_ballot) {
|
||||
state.builder.RequireCapability(CapabilityGroupNonUniformBallot);
|
||||
}
|
||||
if (state.needs_subgroup_ballot) {
|
||||
state.builder.AddCapability({CapabilityGroupNonUniformBallot});
|
||||
if (state.requirements.subgroup_shuffle) {
|
||||
state.builder.RequireCapability(CapabilityGroupNonUniformShuffle);
|
||||
}
|
||||
if (state.needs_subgroup_shuffle) {
|
||||
state.builder.AddCapability({CapabilityGroupNonUniformShuffle});
|
||||
if (state.requirements.compute_derivatives && state.stage == ShaderType::Compute) {
|
||||
state.builder.RequireCapability(CapabilityComputeDerivativeGroupQuadsKHR);
|
||||
state.builder.RequireExtension("SPV_KHR_compute_shader_derivatives");
|
||||
}
|
||||
if (state.needs_compute_derivatives && state.stage == ShaderType::Compute) {
|
||||
state.builder.AddCapability({CapabilityComputeDerivativeGroupQuadsKHR});
|
||||
state.builder.AddExtension("SPV_KHR_compute_shader_derivatives");
|
||||
}
|
||||
state.builder.AddExtension("SPV_KHR_float_controls");
|
||||
state.builder.AddExtInstImport(state.glsl_std450, "GLSL.std.450");
|
||||
state.builder.RequireExtension("SPV_KHR_float_controls");
|
||||
state.builder.AddMemoryModel({AddressingModelLogical, MemoryModelGLSL450});
|
||||
state.builder.AddEntryPoint(ExecutionModelForStage(state.stage), state.main_func, "main",
|
||||
state.interface_variables);
|
||||
@@ -519,8 +617,8 @@ void EmitHeaderAndTypes(EmitterState& state) {
|
||||
// contract prevents host compilers from treating synthesized IEEE values as finite.
|
||||
state.builder.AddExecutionMode({state.main_func, ExecutionModeSignedZeroInfNanPreserve, 32u});
|
||||
if (state.stage == ShaderType::Compute) {
|
||||
uint32_t local_x = state.needs_compute_derivatives ? 2u : 1u;
|
||||
uint32_t local_y = state.needs_compute_derivatives ? 2u : 1u;
|
||||
uint32_t local_x = state.requirements.compute_derivatives ? 2u : 1u;
|
||||
uint32_t local_y = state.requirements.compute_derivatives ? 2u : 1u;
|
||||
uint32_t local_z = 1u;
|
||||
const auto* cs = state.input_info.compute;
|
||||
local_x = cs->threads_num[0] != 0u ? cs->threads_num[0] : local_x;
|
||||
@@ -540,304 +638,79 @@ void EmitHeaderAndTypes(EmitterState& state) {
|
||||
state.builder.AddExecutionMode({state.main_func, ExecutionModeEarlyFragmentTests});
|
||||
}
|
||||
}
|
||||
if (state.needs_compute_derivatives && state.stage == ShaderType::Compute) {
|
||||
if (state.requirements.compute_derivatives && state.stage == ShaderType::Compute) {
|
||||
state.builder.AddExecutionMode({state.main_func, ExecutionModeDerivativeGroupQuadsKHR});
|
||||
}
|
||||
state.builder.AddName(state.main_func, "main");
|
||||
if (state.stage == ShaderType::Compute || state.needs_function_lds) {
|
||||
if (state.requirements.function_lds) {
|
||||
state.builder.AddName(state.lds_variable, "lds_dwords");
|
||||
}
|
||||
AddInputAnnotationsAndNames(state);
|
||||
AddOutputAnnotationsAndNames(state);
|
||||
AddDescriptorAnnotationsAndNames(state);
|
||||
AddVsharpAnnotationsAndNames(state);
|
||||
state.builder.AddAnnotation(
|
||||
{OpDecorate, state.storage_runtime_array_type, DecorationArrayStride, 4});
|
||||
state.builder.AddAnnotation(
|
||||
{OpMemberDecorate, state.storage_buffer_type, 0, DecorationOffset, 0});
|
||||
state.builder.AddAnnotation({OpDecorate, state.storage_buffer_type, DecorationBlock});
|
||||
|
||||
state.builder.AddType({OpTypeVoid, state.void_type});
|
||||
state.builder.AddType({OpTypeBool, state.bool_type});
|
||||
state.builder.AddType({OpTypeInt, state.uint_type, 32, 0});
|
||||
state.builder.AddType({OpTypeStruct, state.uint_pair_type, state.uint_type, state.uint_type});
|
||||
state.builder.AddType({OpTypeInt, state.int_type, 32, 1});
|
||||
state.builder.AddType({OpTypeStruct, state.int_pair_type, state.int_type, state.int_type});
|
||||
state.builder.AddType({OpTypeFloat, state.float_type, 32});
|
||||
state.builder.AddType({OpTypeVector, state.vec2_uint_type, state.uint_type, 2});
|
||||
state.builder.AddType({OpTypeVector, state.vec3_uint_type, state.uint_type, 3});
|
||||
state.builder.AddType({OpTypeVector, state.vec4_uint_type, state.uint_type, 4});
|
||||
state.builder.AddType({OpTypeVector, state.vec2_int_type, state.int_type, 2});
|
||||
state.builder.AddType({OpTypeVector, state.vec3_int_type, state.int_type, 3});
|
||||
state.builder.AddType({OpTypeVector, state.vec4_int_type, state.int_type, 4});
|
||||
state.builder.AddType({OpTypeVector, state.vec2_float_type, state.float_type, 2});
|
||||
state.builder.AddType({OpTypeVector, state.vec3_float_type, state.float_type, 3});
|
||||
state.builder.AddType({OpTypeVector, state.vec4_float_type, state.float_type, 4});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_uint, StorageClassFunction, state.uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_bool, StorageClassFunction, state.bool_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_float, StorageClassFunction, state.float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_uint_pair, StorageClassFunction, state.uint_pair_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_vec4_uint, StorageClassFunction, state.vec4_uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_func_vec2_float, StorageClassFunction, state.vec2_float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_float, StorageClassInput, state.float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_bool, StorageClassInput, state.bool_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_input_int, StorageClassInput, state.int_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_uint, StorageClassInput, state.uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec2_float, StorageClassInput, state.vec2_float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec3_float, StorageClassInput, state.vec3_float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec2_int, StorageClassInput, state.vec2_int_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec3_int, StorageClassInput, state.vec3_int_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec4_int, StorageClassInput, state.vec4_int_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec2_uint, StorageClassInput, state.vec2_uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec3_uint, StorageClassInput, state.vec3_uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec4_uint, StorageClassInput, state.vec4_uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_input_vec4_float, StorageClassInput, state.vec4_float_type});
|
||||
if (state.subgroup_local_invocation_id_variable != 0) {
|
||||
state.builder.AddType({OpVariable, state.ptr_input_uint,
|
||||
state.subgroup_local_invocation_id_variable, StorageClassInput});
|
||||
state.builder.DefineGlobalVariable(state.subgroup_local_invocation_id_variable,
|
||||
TypePointer(state, StorageClassInput, TypeU32(state)),
|
||||
StorageClassInput);
|
||||
}
|
||||
for (const auto& input: state.inputs) {
|
||||
uint32_t ptr_type = state.ptr_input_uint;
|
||||
uint32_t ptr_type = TypePointer(state, StorageClassInput, TypeU32(state));
|
||||
switch (input.kind) {
|
||||
case IR::StageInputKind::VertexIndex:
|
||||
case IR::StageInputKind::InstanceIndex: ptr_type = state.ptr_input_int; break;
|
||||
case IR::StageInputKind::InstanceIndex:
|
||||
ptr_type = TypePointer(state, StorageClassInput, TypeI32(state));
|
||||
break;
|
||||
case IR::StageInputKind::WorkgroupId:
|
||||
case IR::StageInputKind::LocalInvocationId:
|
||||
case IR::StageInputKind::GlobalInvocationId:
|
||||
ptr_type = state.ptr_input_vec3_uint;
|
||||
ptr_type = TypePointer(state, StorageClassInput, TypeU32Vector(state, 3));
|
||||
break;
|
||||
case IR::StageInputKind::FragCoord:
|
||||
ptr_type = TypePointer(state, StorageClassInput, TypeF32Vector(state, 4));
|
||||
break;
|
||||
case IR::StageInputKind::FrontFacing:
|
||||
ptr_type = TypePointer(state, StorageClassInput, TypeBool(state));
|
||||
break;
|
||||
case IR::StageInputKind::FragCoord: ptr_type = state.ptr_input_vec4_float; break;
|
||||
case IR::StageInputKind::FrontFacing: ptr_type = state.ptr_input_bool; break;
|
||||
case IR::StageInputKind::Parameter:
|
||||
if (state.stage == ShaderType::Vertex) {
|
||||
const auto kind = VertexParameterScalarKind(state, input.location);
|
||||
const auto components = VertexParameterComponentCount(state, input);
|
||||
ptr_type = VertexParameterInputPointerType(state, kind, components);
|
||||
} else {
|
||||
ptr_type = state.ptr_input_vec4_float;
|
||||
ptr_type = TypePointer(state, StorageClassInput, TypeF32Vector(state, 4));
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
state.builder.AddType({OpVariable, ptr_type, input.variable_id, StorageClassInput});
|
||||
state.builder.DefineGlobalVariable(input.variable_id, ptr_type, StorageClassInput);
|
||||
}
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_output_float, StorageClassOutput, state.float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_output_int, StorageClassOutput, state.int_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_output_vec4_float, StorageClassOutput, state.vec4_float_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, ptr_output_vec4_uint, StorageClassOutput, state.vec4_uint_type});
|
||||
if (state.per_vertex_variable != 0) {
|
||||
state.builder.AddType({OpTypeStruct, state.per_vertex_type, state.vec4_float_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_output_per_vertex, StorageClassOutput,
|
||||
state.per_vertex_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_output_per_vertex, state.per_vertex_variable,
|
||||
StorageClassOutput});
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.per_vertex_variable, TypePointer(state, StorageClassOutput, PerVertexType(state)),
|
||||
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)
|
||||
? ptr_output_vec4_uint
|
||||
: state.ptr_output_vec4_float;
|
||||
state.builder.AddType(
|
||||
{OpVariable, pointer_type, binding.variable_id, StorageClassOutput});
|
||||
? TypePointer(state, StorageClassOutput, TypeU32Vector(state, 4))
|
||||
: TypePointer(state, StorageClassOutput, TypeF32Vector(state, 4));
|
||||
state.builder.DefineGlobalVariable(binding.variable_id, pointer_type,
|
||||
StorageClassOutput);
|
||||
}
|
||||
}
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.AddType(
|
||||
{OpVariable, state.ptr_output_float, state.depth_variable, StorageClassOutput});
|
||||
state.builder.DefineGlobalVariable(state.depth_variable,
|
||||
TypePointer(state, StorageClassOutput, TypeF32(state)),
|
||||
StorageClassOutput);
|
||||
}
|
||||
if (state.sample_mask_variable != 0) {
|
||||
state.builder.AddType(
|
||||
{OpTypeArray, state.sample_mask_array_type, state.int_type, ConstantU32(state, 1)});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_output_sample_mask_array,
|
||||
StorageClassOutput, state.sample_mask_array_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_output_sample_mask_array,
|
||||
state.sample_mask_variable, StorageClassOutput});
|
||||
}
|
||||
state.builder.AddType({OpTypeRuntimeArray, state.storage_runtime_array_type, state.uint_type});
|
||||
state.builder.AddType(
|
||||
{OpTypeStruct, state.storage_buffer_type, state.storage_runtime_array_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_storage_buffer, StorageClassStorageBuffer,
|
||||
state.storage_buffer_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_storage_buffer_uint, StorageClassStorageBuffer, state.uint_type});
|
||||
if (state.storage_buffer_variable != 0) {
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Buffers));
|
||||
state.builder.AddType(
|
||||
{OpTypeArray, state.storage_buffer_array_type, state.storage_buffer_type, count});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_storage_buffer_array,
|
||||
StorageClassStorageBuffer, state.storage_buffer_array_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_storage_buffer_array,
|
||||
state.storage_buffer_variable, StorageClassStorageBuffer});
|
||||
}
|
||||
if (state.gds_variable != 0) {
|
||||
state.builder.AddType(
|
||||
{OpVariable, state.ptr_storage_buffer, state.gds_variable, StorageClassStorageBuffer});
|
||||
}
|
||||
if (state.push_constant_variable != 0) {
|
||||
const auto dword_count =
|
||||
ConstantU32(state, state.program.bindings.push_constant_size / sizeof(uint32_t));
|
||||
state.builder.AddType(
|
||||
{OpTypeArray, state.push_constant_array_type, state.uint_type, dword_count});
|
||||
state.builder.AddType(
|
||||
{OpTypeStruct, state.push_constant_block_type, state.push_constant_array_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_push_constant_block,
|
||||
StorageClassPushConstant, state.push_constant_block_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_push_constant_uint,
|
||||
StorageClassPushConstant, state.uint_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_push_constant_block,
|
||||
state.push_constant_variable, StorageClassPushConstant});
|
||||
}
|
||||
if (state.vsharp_storage_variable != 0) {
|
||||
state.builder.AddType({OpVariable, state.ptr_storage_buffer, state.vsharp_storage_variable,
|
||||
StorageClassStorageBuffer});
|
||||
}
|
||||
if (state.address_memory_variable != 0) {
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::AddressMemory));
|
||||
state.builder.AddType(
|
||||
{OpTypeArray, state.address_memory_array_type, state.storage_buffer_type, count});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_address_memory_array,
|
||||
StorageClassStorageBuffer, state.address_memory_array_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_address_memory_array,
|
||||
state.address_memory_variable, StorageClassStorageBuffer});
|
||||
}
|
||||
if (state.flattened_srt_variable != 0) {
|
||||
state.builder.AddType({OpVariable, state.ptr_storage_buffer, state.flattened_srt_variable,
|
||||
StorageClassStorageBuffer});
|
||||
}
|
||||
if (state.stage == ShaderType::Compute || state.needs_function_lds) {
|
||||
const auto storage_class =
|
||||
state.needs_function_lds ? StorageClassFunction : StorageClassWorkgroup;
|
||||
const auto lds_dwords = std::max(LdsDwordCount(state), 1u);
|
||||
const auto lds_size = ConstantU32(state, lds_dwords);
|
||||
state.builder.AddType({OpTypeArray, state.lds_array_type, state.uint_type, lds_size});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_workgroup_array, storage_class, state.lds_array_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_workgroup_uint, storage_class, state.uint_type});
|
||||
if (state.stage == ShaderType::Compute) {
|
||||
state.builder.AddType(
|
||||
{OpVariable, state.ptr_workgroup_array, state.lds_variable, StorageClassWorkgroup});
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
|
||||
auto& image = state.sampled_images[i];
|
||||
const auto view = static_cast<ImageViewKind>(i % SampledImageViewKindCount);
|
||||
const bool integer = i >= SampledImageViewKindCount;
|
||||
const auto component = integer ? state.uint_type : state.float_type;
|
||||
state.builder.AddType({OpTypeImage, image.image_type, component, ImageSpirvDimension(view),
|
||||
0, ImageSpirvArrayed(view), ImageSpirvMultisampled(view), 1,
|
||||
ImageFormatUnknown});
|
||||
state.builder.AddType({OpTypeSampledImage, image.sampled_image_type, image.image_type});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, image.pointer_type, StorageClassUniformConstant, image.image_type});
|
||||
if (image.variable != 0) {
|
||||
const auto kind = SampledBindingKind(integer, view);
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
||||
state.builder.AddType({OpTypeArray, image.array_type, image.image_type, count});
|
||||
state.builder.AddType({OpTypePointer, image.array_pointer_type,
|
||||
StorageClassUniformConstant, image.array_type});
|
||||
state.builder.AddType({OpVariable, image.array_pointer_type, image.variable,
|
||||
StorageClassUniformConstant});
|
||||
}
|
||||
}
|
||||
state.builder.AddType({OpTypeSampler, state.sampler_type});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_uniform_sampler, StorageClassUniformConstant,
|
||||
state.sampler_type});
|
||||
if (state.sampler_variable != 0) {
|
||||
const auto count =
|
||||
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Samplers));
|
||||
state.builder.AddType({OpTypeArray, state.sampler_array_type, state.sampler_type, count});
|
||||
state.builder.AddType({OpTypePointer, state.ptr_uniform_sampler_array,
|
||||
StorageClassUniformConstant, state.sampler_array_type});
|
||||
state.builder.AddType({OpVariable, state.ptr_uniform_sampler_array, state.sampler_variable,
|
||||
StorageClassUniformConstant});
|
||||
}
|
||||
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
|
||||
auto& image = state.storage_images[i];
|
||||
const auto view = static_cast<ImageViewKind>(i % StorageImageViewKindCount);
|
||||
const bool integer = i >= StorageImageViewKindCount;
|
||||
const auto component = integer ? state.uint_type : state.float_type;
|
||||
const auto format = integer ? ImageFormatR32ui : ImageFormatUnknown;
|
||||
state.builder.AddType({OpTypeImage, image.image_type, component, ImageSpirvDimension(view),
|
||||
0, ImageSpirvArrayed(view), 0, 2, format});
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, image.pointer_type, StorageClassUniformConstant, image.image_type});
|
||||
if (image.variable != 0) {
|
||||
const auto kind = StorageBindingKind(integer, view);
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
||||
state.builder.AddType({OpTypeArray, image.array_type, image.image_type, count});
|
||||
state.builder.AddType({OpTypePointer, image.array_pointer_type,
|
||||
StorageClassUniformConstant, image.array_type});
|
||||
state.builder.AddType({OpVariable, image.array_pointer_type, image.variable,
|
||||
StorageClassUniformConstant});
|
||||
}
|
||||
}
|
||||
state.builder.AddType(
|
||||
{OpTypePointer, state.ptr_image_uint, StorageClassImage, state.uint_type});
|
||||
state.builder.AddType({OpTypeFunction, state.func_type, state.void_type});
|
||||
}
|
||||
|
||||
void AllocateDescriptorVariables(EmitterState& state) {
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Buffers) != nullptr) {
|
||||
state.storage_buffer_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::AddressMemory) != nullptr) {
|
||||
state.address_memory_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (state.program.bindings.push_constant_size != 0) {
|
||||
state.push_constant_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::UserData) != nullptr) {
|
||||
state.vsharp_storage_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::FlattenedSrt) != nullptr) {
|
||||
state.flattened_srt_variable = state.builder.AllocateId();
|
||||
}
|
||||
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % SampledImageViewKindCount);
|
||||
if (DescriptorBinding(state, SampledBindingKind(i >= SampledImageViewKindCount, view)) !=
|
||||
nullptr) {
|
||||
state.sampled_images[i].variable = state.builder.AllocateId();
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
|
||||
const auto view = static_cast<ImageViewKind>(i % StorageImageViewKindCount);
|
||||
if (DescriptorBinding(state, StorageBindingKind(i >= StorageImageViewKindCount, view)) !=
|
||||
nullptr) {
|
||||
state.storage_images[i].variable = state.builder.AllocateId();
|
||||
}
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
||||
state.sampler_variable = state.builder.AllocateId();
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Gds) != nullptr) {
|
||||
state.gds_variable = state.builder.AllocateId();
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.sample_mask_variable,
|
||||
TypePointer(state, StorageClassOutput, SampleMaskArrayType(state)), StorageClassOutput);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ void EmitKillIfBoolFalse(EmitterState& state, uint32_t active) {
|
||||
const auto kill_label = state.builder.AllocateId();
|
||||
const auto merge_label = state.builder.AllocateId();
|
||||
const auto inactive = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLogicalNot, state.bool_type, inactive, active});
|
||||
state.builder.AddFunction({OpLogicalNot, TypeBool(state), inactive, active});
|
||||
state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone});
|
||||
state.builder.AddFunction({OpBranchConditional, inactive, kill_label, merge_label});
|
||||
state.builder.AddFunction({OpLabel, kill_label});
|
||||
@@ -29,38 +29,26 @@ void EmitKillIfPixelValidMaskInactive(EmitterState& state) {
|
||||
const auto mask_value = state.builder.AllocateId();
|
||||
const auto active = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLoad, state.uint_type, mask_value, state.pixel_valid_mask_variable});
|
||||
{OpLoad, TypeU32(state), mask_value, state.pixel_valid_mask_variable});
|
||||
state.builder.AddFunction(
|
||||
{OpINotEqual, state.bool_type, active, mask_value, ConstantU32(state, 0)});
|
||||
{OpINotEqual, TypeBool(state), active, mask_value, ConstantU32(state, 0)});
|
||||
EmitKillIfBoolFalse(state, active);
|
||||
}
|
||||
|
||||
uint32_t BoolConstant(EmitterState& state, bool value) {
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.builder.AddType({value ? 41u : 42u, state.bool_type, id});
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t ConstantPair(EmitterState& state, uint64_t value) {
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.builder.AddType({OpConstantComposite, state.uint_pair_type, id,
|
||||
ConstantU32(state, static_cast<uint32_t>(value)),
|
||||
ConstantU32(state, static_cast<uint32_t>(value >> 32u))});
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t PhiPointerType(const EmitterState& state, IR::Type type) {
|
||||
uint32_t PhiPointerType(EmitterState& state, IR::Type type) {
|
||||
switch (type) {
|
||||
case IR::Type::U1: return state.ptr_func_bool;
|
||||
case IR::Type::U1: return TypePointer(state, StorageClassFunction, TypeBool(state));
|
||||
case IR::Type::U8:
|
||||
case IR::Type::U16:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F16: return state.ptr_func_uint;
|
||||
case IR::Type::F32: return state.ptr_func_float;
|
||||
case IR::Type::F16: return TypePointer(state, StorageClassFunction, TypeU32(state));
|
||||
case IR::Type::F32: return TypePointer(state, StorageClassFunction, TypeF32(state));
|
||||
case IR::Type::U64:
|
||||
case IR::Type::U32x2: return state.ptr_func_uint_pair;
|
||||
case IR::Type::U32x4: return state.ptr_func_vec4_uint;
|
||||
case IR::Type::F32x2: return state.ptr_func_vec2_float;
|
||||
case IR::Type::U32x2: return TypePointer(state, StorageClassFunction, TypeU32Pair(state));
|
||||
case IR::Type::U32x4:
|
||||
return TypePointer(state, StorageClassFunction, TypeU32Vector(state, 4));
|
||||
case IR::Type::F32x2:
|
||||
return TypePointer(state, StorageClassFunction, TypeF32Vector(state, 2));
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -168,7 +156,7 @@ void EmitDispatcherTerminator(ValueEmitContext& ctx, const IR::Block* block,
|
||||
EmitDispatcherTarget(ctx, block, term.true_block);
|
||||
EmitDispatcherTarget(ctx, block, term.false_block);
|
||||
const auto selected = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpSelect, ctx.state.uint_type, selected,
|
||||
ctx.state.builder.AddFunction({OpSelect, TypeU32(ctx.state), selected,
|
||||
ctx.Def(info.condition),
|
||||
ConstantU32(ctx.state, term.true_block),
|
||||
ConstantU32(ctx.state, term.false_block)});
|
||||
@@ -194,9 +182,9 @@ void EmitDispatcherTerminator(ValueEmitContext& ctx, const IR::Block* block,
|
||||
for (size_t index = 0; index < std::min(values.size(), targets.size()); index++) {
|
||||
const auto match = ctx.state.builder.AllocateId();
|
||||
const auto next = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpIEqual, ctx.state.bool_type, match, selector,
|
||||
ctx.state.builder.AddFunction({OpIEqual, TypeBool(ctx.state), match, selector,
|
||||
ConstantU32(ctx.state, values[index])});
|
||||
ctx.state.builder.AddFunction({OpSelect, ctx.state.uint_type, next, match,
|
||||
ctx.state.builder.AddFunction({OpSelect, TypeU32(ctx.state), next, match,
|
||||
ConstantU32(ctx.state, targets[index]),
|
||||
selected});
|
||||
selected = next;
|
||||
@@ -263,10 +251,10 @@ void EmitDispatcherFunction(ValueEmitContext& ctx) {
|
||||
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_header_label});
|
||||
const auto pc = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, pc, state.dispatch_pc_variable});
|
||||
state.builder.AddFunction({OpLoad, TypeU32(state), pc, state.dispatch_pc_variable});
|
||||
const auto done = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpIEqual, state.bool_type, done, pc, ConstantU32(ctx.state, UINT32_MAX)});
|
||||
{OpIEqual, TypeBool(state), done, pc, ConstantU32(ctx.state, UINT32_MAX)});
|
||||
state.builder.AddFunction(
|
||||
{OpLoopMerge, state.dispatch_merge_label, state.dispatch_continue_label, LoopControlNone});
|
||||
state.builder.AddFunction(
|
||||
@@ -303,16 +291,16 @@ void EmitDispatcherFunction(ValueEmitContext& ctx) {
|
||||
|
||||
uint32_t ValueEmitContext::TypeId(IR::Type type) const {
|
||||
switch (type) {
|
||||
case IR::Type::U1: return state.bool_type;
|
||||
case IR::Type::U1: return TypeBool(state);
|
||||
case IR::Type::U8:
|
||||
case IR::Type::U16:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F16: return state.uint_type;
|
||||
case IR::Type::F16: return TypeU32(state);
|
||||
case IR::Type::U64:
|
||||
case IR::Type::U32x2: return state.uint_pair_type;
|
||||
case IR::Type::F32: return state.float_type;
|
||||
case IR::Type::U32x4: return state.vec4_uint_type;
|
||||
case IR::Type::F32x2: return state.vec2_float_type;
|
||||
case IR::Type::U32x2: return TypeU32Pair(state);
|
||||
case IR::Type::F32: return TypeF32(state);
|
||||
case IR::Type::U32x4: return TypeU32Vector(state, 4);
|
||||
case IR::Type::F32x2: return TypeF32Vector(state, 2);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -321,11 +309,11 @@ uint32_t ValueEmitContext::Def(IR::Value value) {
|
||||
value = value.Resolve();
|
||||
if (value.IsImmediate()) {
|
||||
switch (value.GetType()) {
|
||||
case IR::Type::U1: return BoolConstant(state, value.U1());
|
||||
case IR::Type::U1: return ConstantBool(state, value.U1());
|
||||
case IR::Type::U8: return ConstantU32(state, value.U8());
|
||||
case IR::Type::U16: return ConstantU32(state, value.U16());
|
||||
case IR::Type::U32: return ConstantU32(state, value.U32());
|
||||
case IR::Type::U64: return ConstantPair(state, value.U64());
|
||||
case IR::Type::U64: return ConstantU64(state, value.U64());
|
||||
case IR::Type::F16: return ConstantU32(state, value.F16Bits());
|
||||
case IR::Type::F32:
|
||||
return ConstantF32(state, std::bit_cast<uint32_t>(value.F32Value()));
|
||||
@@ -430,7 +418,7 @@ void ValueEmitContext::Fail(const IR::Inst& inst, const char* reason) {
|
||||
|
||||
bool EmitValueProgram(EmitterState& state, const IR::ValueProgram& program, std::string* error) {
|
||||
ValueEmitContext ctx(state, program);
|
||||
if (state.stage == ShaderType::Pixel && state.needs_pixel_valid_mask) {
|
||||
if (state.stage == ShaderType::Pixel && state.requirements.pixel_valid_mask) {
|
||||
state.pixel_valid_mask_variable = state.builder.AllocateId();
|
||||
state.builder.AddName(state.pixel_valid_mask_variable, "pixel_valid_mask_active");
|
||||
}
|
||||
@@ -502,19 +490,21 @@ bool EmitValueProgram(EmitterState& state, const IR::ValueProgram& program, std:
|
||||
}
|
||||
}
|
||||
state.builder.AddFunction(
|
||||
{OpFunction, state.void_type, state.main_func, FunctionControlNone, state.func_type});
|
||||
{OpFunction, TypeVoid(state), state.main_func, FunctionControlNone, TypeFunction(state)});
|
||||
state.builder.AddFunction({OpLabel, state.entry_label});
|
||||
if (state.needs_function_lds) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_workgroup_array, state.lds_variable, StorageClassFunction});
|
||||
if (state.requirements.function_lds) {
|
||||
state.builder.AddFunction({OpVariable, TypeLdsArrayPointer(state, StorageClassFunction),
|
||||
state.lds_variable, StorageClassFunction});
|
||||
}
|
||||
if (state.pixel_valid_mask_variable != 0) {
|
||||
state.builder.AddFunction({OpVariable, state.ptr_func_uint, state.pixel_valid_mask_variable,
|
||||
StorageClassFunction});
|
||||
state.builder.AddFunction({OpVariable,
|
||||
TypePointer(state, StorageClassFunction, TypeU32(state)),
|
||||
state.pixel_valid_mask_variable, StorageClassFunction});
|
||||
}
|
||||
if (program.dispatcher_fallback) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_func_uint, state.dispatch_pc_variable, StorageClassFunction});
|
||||
state.builder.AddFunction({OpVariable,
|
||||
TypePointer(state, StorageClassFunction, TypeU32(state)),
|
||||
state.dispatch_pc_variable, StorageClassFunction});
|
||||
}
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
@@ -537,8 +527,9 @@ bool EmitValueProgram(EmitterState& state, const IR::ValueProgram& program, std:
|
||||
}
|
||||
}
|
||||
if (ctx.scratch_u32_variable != 0) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_func_uint, ctx.scratch_u32_variable, StorageClassFunction});
|
||||
state.builder.AddFunction({OpVariable,
|
||||
TypePointer(state, StorageClassFunction, TypeU32(state)),
|
||||
ctx.scratch_u32_variable, StorageClassFunction});
|
||||
}
|
||||
if (state.pixel_valid_mask_variable != 0) {
|
||||
state.builder.AddFunction(
|
||||
|
||||
@@ -71,11 +71,11 @@ public:
|
||||
vec4_float_type = Type(spv::Op::OpTypeVector, float_type, 4u);
|
||||
function_type = Type(spv::Op::OpTypeFunction, void_type);
|
||||
|
||||
per_vertex_type = Type(spv::Op::OpTypeStruct, vec4_float_type);
|
||||
builder.AddAnnotation({Word(spv::Op::OpMemberDecorate), per_vertex_type, 0u,
|
||||
Word(spv::Decoration::BuiltIn), Word(spv::BuiltIn::Position)});
|
||||
builder.AddAnnotation(
|
||||
{Word(spv::Op::OpDecorate), per_vertex_type, Word(spv::Decoration::Block)});
|
||||
per_vertex_type = builder.DecoratedType(
|
||||
Word(spv::Op::OpTypeStruct), {vec4_float_type},
|
||||
{{Word(spv::Op::OpMemberDecorate),
|
||||
{0u, Word(spv::Decoration::BuiltIn), Word(spv::BuiltIn::Position)}},
|
||||
{Word(spv::Op::OpDecorate), {Word(spv::Decoration::Block)}}});
|
||||
|
||||
ptr_input_vec4_float = Pointer(spv::StorageClass::Input, vec4_float_type);
|
||||
ptr_output_vec4_float = Pointer(spv::StorageClass::Output, vec4_float_type);
|
||||
@@ -197,15 +197,11 @@ public:
|
||||
private:
|
||||
template <typename... Args>
|
||||
uint32_t Type(spv::Op opcode, Args... operands) {
|
||||
const auto id = builder.AllocateId();
|
||||
builder.AddType({Word(opcode), id, Word(operands)...});
|
||||
return id;
|
||||
return builder.Type(Word(opcode), {Word(operands)...});
|
||||
}
|
||||
|
||||
uint32_t Constant(uint32_t type, uint32_t value) {
|
||||
const auto id = builder.AllocateId();
|
||||
builder.AddType({Word(spv::Op::OpConstant), type, id, value});
|
||||
return id;
|
||||
return builder.Constant(Word(spv::Op::OpConstant), type, {value});
|
||||
}
|
||||
|
||||
uint32_t Pointer(spv::StorageClass storage, uint32_t type) {
|
||||
@@ -246,26 +242,12 @@ private:
|
||||
|
||||
void Store(uint32_t pointer, uint32_t value) { Emit(spv::Op::OpStore, pointer, value); }
|
||||
|
||||
uint32_t Int(uint32_t value) {
|
||||
auto& id = int_constants[value];
|
||||
if (id == 0) {
|
||||
id = Constant(int_type, value);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
uint32_t Int(uint32_t value) { return Constant(int_type, value); }
|
||||
|
||||
uint32_t Uint(uint32_t value) {
|
||||
auto& id = uint_constants[value];
|
||||
if (id == 0) {
|
||||
id = Constant(uint_type, value);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
uint32_t Uint(uint32_t value) { return Constant(uint_type, value); }
|
||||
|
||||
uint32_t AddInterface(spv::StorageClass storage, uint32_t type) {
|
||||
const auto variable = builder.AllocateId();
|
||||
builder.AddType(
|
||||
{Word(spv::Op::OpVariable), Pointer(storage, type), variable, Word(storage)});
|
||||
const auto variable = builder.DefineGlobalVariable(Pointer(storage, type), Word(storage));
|
||||
interfaces.push_back(variable);
|
||||
return variable;
|
||||
}
|
||||
@@ -275,8 +257,8 @@ private:
|
||||
}
|
||||
|
||||
void DefineEntry(spv::ExecutionModel model) {
|
||||
builder.AddCapability({Word(spv::Capability::Shader)});
|
||||
builder.AddCapability({Word(spv::Capability::Tessellation)});
|
||||
builder.RequireCapability(Word(spv::Capability::Shader));
|
||||
builder.RequireCapability(Word(spv::Capability::Tessellation));
|
||||
main = Result(spv::Op::OpFunction, void_type, spv::FunctionControlMask::MaskNone,
|
||||
function_type);
|
||||
if (model == spv::ExecutionModel::TessellationControl) {
|
||||
@@ -358,8 +340,6 @@ private:
|
||||
std::vector<uint32_t> interfaces;
|
||||
std::vector<uint32_t> inputs;
|
||||
std::vector<uint32_t> outputs;
|
||||
std::array<uint32_t, 5> int_constants {};
|
||||
std::array<uint32_t, 5> uint_constants {};
|
||||
uint32_t main = 0;
|
||||
uint32_t void_type = 0;
|
||||
uint32_t bool_type = 0;
|
||||
|
||||
@@ -1297,24 +1297,34 @@ std::vector<u32> MakePassthroughVertexSpirv() {
|
||||
using ShaderRecompiler::Spirv::Builder;
|
||||
|
||||
Builder b;
|
||||
const auto void_type = b.AllocateId();
|
||||
const auto uint_type = b.AllocateId();
|
||||
const auto float_type = b.AllocateId();
|
||||
const auto vec2_type = b.AllocateId();
|
||||
const auto vec4_type = b.AllocateId();
|
||||
const auto per_vertex_type = b.AllocateId();
|
||||
const auto ptr_input_vec2 = b.AllocateId();
|
||||
const auto ptr_input_vec4 = b.AllocateId();
|
||||
const auto ptr_output_vec4 = b.AllocateId();
|
||||
const auto ptr_output_per_vertex = b.AllocateId();
|
||||
const auto func_type = b.AllocateId();
|
||||
const auto const_u32_0 = b.AllocateId();
|
||||
const auto const_f32_0 = b.AllocateId();
|
||||
const auto const_f32_1 = b.AllocateId();
|
||||
const auto in_pos = b.AllocateId();
|
||||
const auto in_color = b.AllocateId();
|
||||
const auto out_color = b.AllocateId();
|
||||
const auto per_vertex = b.AllocateId();
|
||||
const auto void_type = b.Type(OpTypeVoid);
|
||||
const auto uint_type = b.Type(OpTypeInt, {32, 0});
|
||||
const auto float_type = b.Type(OpTypeFloat, {32});
|
||||
const auto vec2_type = b.Type(OpTypeVector, {float_type, 2});
|
||||
const auto vec4_type = b.Type(OpTypeVector, {float_type, 4});
|
||||
const auto per_vertex_type = b.DecoratedType(
|
||||
OpTypeStruct, {vec4_type},
|
||||
{{OpDecorate, {DecorationBlock}},
|
||||
{OpMemberDecorate, {0, DecorationBuiltIn, BuiltInPosition}}});
|
||||
const auto ptr_input_vec2 =
|
||||
b.Type(OpTypePointer, {StorageClassInput, vec2_type});
|
||||
const auto ptr_input_vec4 =
|
||||
b.Type(OpTypePointer, {StorageClassInput, vec4_type});
|
||||
const auto ptr_output_vec4 =
|
||||
b.Type(OpTypePointer, {StorageClassOutput, vec4_type});
|
||||
const auto ptr_output_per_vertex =
|
||||
b.Type(OpTypePointer, {StorageClassOutput, per_vertex_type});
|
||||
const auto func_type = b.Type(OpTypeFunction, {void_type});
|
||||
const auto const_u32_0 = b.Constant(OpConstant, uint_type, {0});
|
||||
const auto const_f32_0 = b.Constant(OpConstant, float_type, {0x00000000u});
|
||||
const auto const_f32_1 = b.Constant(OpConstant, float_type, {0x3f800000u});
|
||||
const auto in_pos = b.DefineGlobalVariable(ptr_input_vec2, StorageClassInput);
|
||||
const auto in_color =
|
||||
b.DefineGlobalVariable(ptr_input_vec4, StorageClassInput);
|
||||
const auto out_color =
|
||||
b.DefineGlobalVariable(ptr_output_vec4, StorageClassOutput);
|
||||
const auto per_vertex =
|
||||
b.DefineGlobalVariable(ptr_output_per_vertex, StorageClassOutput);
|
||||
const auto main = b.AllocateId();
|
||||
const auto label = b.AllocateId();
|
||||
const auto pos2 = b.AllocateId();
|
||||
@@ -1324,37 +1334,13 @@ std::vector<u32> MakePassthroughVertexSpirv() {
|
||||
const auto position = b.AllocateId();
|
||||
const auto position_ptr = b.AllocateId();
|
||||
|
||||
b.AddCapability({CapabilityShader});
|
||||
b.RequireCapability(CapabilityShader);
|
||||
b.AddMemoryModel({AddressingModelLogical, MemoryModelGLSL450});
|
||||
b.AddEntryPoint(ExecutionModelVertex, main, "main",
|
||||
{in_pos, in_color, per_vertex, out_color});
|
||||
b.AddAnnotation({OpDecorate, in_pos, DecorationLocation, 0});
|
||||
b.AddAnnotation({OpDecorate, in_color, DecorationLocation, 1});
|
||||
b.AddAnnotation({OpDecorate, out_color, DecorationLocation, 0});
|
||||
b.AddAnnotation({OpDecorate, per_vertex_type, DecorationBlock});
|
||||
b.AddAnnotation({OpMemberDecorate, per_vertex_type, 0, DecorationBuiltIn,
|
||||
BuiltInPosition});
|
||||
|
||||
b.AddType({OpTypeVoid, void_type});
|
||||
b.AddType({OpTypeInt, uint_type, 32, 0});
|
||||
b.AddType({OpTypeFloat, float_type, 32});
|
||||
b.AddType({OpTypeVector, vec2_type, float_type, 2});
|
||||
b.AddType({OpTypeVector, vec4_type, float_type, 4});
|
||||
b.AddType({OpTypeStruct, per_vertex_type, vec4_type});
|
||||
b.AddType({OpTypePointer, ptr_input_vec2, StorageClassInput, vec2_type});
|
||||
b.AddType({OpTypePointer, ptr_input_vec4, StorageClassInput, vec4_type});
|
||||
b.AddType({OpTypePointer, ptr_output_vec4, StorageClassOutput, vec4_type});
|
||||
b.AddType({OpTypePointer, ptr_output_per_vertex, StorageClassOutput,
|
||||
per_vertex_type});
|
||||
b.AddType({OpTypeFunction, func_type, void_type});
|
||||
b.AddType({OpConstant, uint_type, const_u32_0, 0});
|
||||
b.AddType({OpConstant, float_type, const_f32_0, 0x00000000u});
|
||||
b.AddType({OpConstant, float_type, const_f32_1, 0x3f800000u});
|
||||
b.AddType({OpVariable, ptr_input_vec2, in_pos, StorageClassInput});
|
||||
b.AddType({OpVariable, ptr_input_vec4, in_color, StorageClassInput});
|
||||
b.AddType({OpVariable, ptr_output_vec4, out_color, StorageClassOutput});
|
||||
b.AddType(
|
||||
{OpVariable, ptr_output_per_vertex, per_vertex, StorageClassOutput});
|
||||
|
||||
b.AddFunction({OpFunction, void_type, main, FunctionControlNone, func_type});
|
||||
b.AddFunction({OpLabel, label});
|
||||
@@ -17471,6 +17457,7 @@ void CheckIndirectImageKeySwitch() {
|
||||
|
||||
ShaderComputeInputInfo compute{};
|
||||
std::vector<u32> spirv;
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(program);
|
||||
Require(name, "SPIR-V emit",
|
||||
ShaderRecompiler::Spirv::EmitProgram(
|
||||
program, snapshot, {.compute = &compute}, spirv, &error),
|
||||
@@ -17644,9 +17631,9 @@ TestCase ImageStoreR32FloatUsesFormatlessStorageImage() {
|
||||
test.storage_image_dwords_per_pixel = 1;
|
||||
test.storage_image_rgba = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_rgba = expected_image;
|
||||
test.required_spirv = {"OpCapability StorageImageReadWithoutFormat",
|
||||
"OpCapability StorageImageWriteWithoutFormat"};
|
||||
test.forbidden_spirv = {"Rgba32f"};
|
||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat"};
|
||||
test.forbidden_spirv = {"OpCapability StorageImageReadWithoutFormat",
|
||||
"Rgba32f", "OpTypeSampler", "OpTypeSampledImage"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -17757,6 +17744,10 @@ TestCase ImageAtomicVariants() {
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_ATOMIC_ADD, O::IMAGE_ATOMIC_UMIN,
|
||||
O::IMAGE_ATOMIC_AND, O::IMAGE_ATOMIC_OR, O::IMAGE_ATOMIC_XOR,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpImageTexelPointer", "R32ui"};
|
||||
test.forbidden_spirv = {"OpTypeSampler", "OpTypeSampledImage",
|
||||
"StorageImageReadWithoutFormat",
|
||||
"StorageImageWriteWithoutFormat"};
|
||||
test.storage_image_rgba = MakeRgbaImage(4, 4);
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
for (u32 i = 0; i < static_cast<u32>(std::size(initial)); i++) {
|
||||
|
||||
+377
-143
@@ -159,10 +159,16 @@ bool SpirvSourceHasInstructionUsing(const std::string &source,
|
||||
}
|
||||
|
||||
bool SpirvContainsOpcode(const std::vector<uint32_t> &binary, uint32_t opcode) {
|
||||
for (uint32_t word : binary) {
|
||||
for (size_t i = 5; i < binary.size();) {
|
||||
const uint32_t word = binary[i];
|
||||
const uint32_t word_count = word >> 16u;
|
||||
if (word_count == 0 || i + word_count > binary.size()) {
|
||||
return false;
|
||||
}
|
||||
if ((word & 0xffffu) == opcode) {
|
||||
return true;
|
||||
}
|
||||
i += word_count;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -188,8 +194,22 @@ uint32_t SpirvInstructionOpcodeCount(const std::vector<uint32_t> &binary,
|
||||
struct SpirvMetrics {
|
||||
size_t words = 0;
|
||||
uint32_t instructions = 0;
|
||||
uint32_t ext_inst_imports = 0;
|
||||
uint32_t type_voids = 0;
|
||||
uint32_t type_bools = 0;
|
||||
uint32_t type_ints = 0;
|
||||
uint32_t type_floats = 0;
|
||||
uint32_t type_vectors = 0;
|
||||
uint32_t type_images = 0;
|
||||
uint32_t type_samplers = 0;
|
||||
uint32_t type_sampled_images = 0;
|
||||
uint32_t runtime_arrays = 0;
|
||||
uint32_t type_pointers = 0;
|
||||
uint32_t type_functions = 0;
|
||||
uint32_t image_pointers = 0;
|
||||
uint32_t variables = 0;
|
||||
uint32_t function_variables = 0;
|
||||
uint32_t workgroup_variables = 0;
|
||||
uint32_t loads = 0;
|
||||
uint32_t stores = 0;
|
||||
uint32_t array_lengths = 0;
|
||||
@@ -202,6 +222,12 @@ struct SpirvMetrics {
|
||||
uint32_t switches = 0;
|
||||
uint32_t ballots = 0;
|
||||
uint32_t quad_broadcasts = 0;
|
||||
uint32_t sampled_1d_capabilities = 0;
|
||||
uint32_t image_1d_capabilities = 0;
|
||||
uint32_t image_query_capabilities = 0;
|
||||
uint32_t storage_read_without_format_capabilities = 0;
|
||||
uint32_t storage_write_without_format_capabilities = 0;
|
||||
uint32_t image_texel_pointers = 0;
|
||||
};
|
||||
|
||||
SpirvMetrics MeasureSpirv(const std::vector<uint32_t> &binary) {
|
||||
@@ -216,11 +242,78 @@ SpirvMetrics MeasureSpirv(const std::vector<uint32_t> &binary) {
|
||||
}
|
||||
metrics.instructions++;
|
||||
switch (opcode) {
|
||||
case 11u: // OpExtInstImport
|
||||
metrics.ext_inst_imports++;
|
||||
break;
|
||||
case 17u: // OpCapability
|
||||
if (word_count >= 2u) {
|
||||
switch (binary[i + 1u]) {
|
||||
case 43u:
|
||||
metrics.sampled_1d_capabilities++;
|
||||
break;
|
||||
case 44u:
|
||||
metrics.image_1d_capabilities++;
|
||||
break;
|
||||
case 50u:
|
||||
metrics.image_query_capabilities++;
|
||||
break;
|
||||
case 55u:
|
||||
metrics.storage_read_without_format_capabilities++;
|
||||
break;
|
||||
case 56u:
|
||||
metrics.storage_write_without_format_capabilities++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 19u: // OpTypeVoid
|
||||
metrics.type_voids++;
|
||||
break;
|
||||
case 20u: // OpTypeBool
|
||||
metrics.type_bools++;
|
||||
break;
|
||||
case 21u: // OpTypeInt
|
||||
metrics.type_ints++;
|
||||
break;
|
||||
case 22u: // OpTypeFloat
|
||||
metrics.type_floats++;
|
||||
break;
|
||||
case 23u: // OpTypeVector
|
||||
metrics.type_vectors++;
|
||||
break;
|
||||
case 25u: // OpTypeImage
|
||||
metrics.type_images++;
|
||||
break;
|
||||
case 26u: // OpTypeSampler
|
||||
metrics.type_samplers++;
|
||||
break;
|
||||
case 27u: // OpTypeSampledImage
|
||||
metrics.type_sampled_images++;
|
||||
break;
|
||||
case 29u: // OpTypeRuntimeArray
|
||||
metrics.runtime_arrays++;
|
||||
break;
|
||||
case 32u: // OpTypePointer
|
||||
metrics.type_pointers++;
|
||||
if (word_count >= 4u && binary[i + 2u] == 11u) {
|
||||
metrics.image_pointers++;
|
||||
}
|
||||
break;
|
||||
case 33u: // OpTypeFunction
|
||||
metrics.type_functions++;
|
||||
break;
|
||||
case 59u: // OpVariable
|
||||
metrics.variables++;
|
||||
if (word_count >= 4u && binary[i + 3u] == 7u) {
|
||||
metrics.function_variables++;
|
||||
} else if (word_count >= 4u && binary[i + 3u] == 4u) {
|
||||
metrics.workgroup_variables++;
|
||||
}
|
||||
break;
|
||||
case 60u: // OpImageTexelPointer
|
||||
metrics.image_texel_pointers++;
|
||||
break;
|
||||
case 61u: // OpLoad
|
||||
metrics.loads++;
|
||||
@@ -272,8 +365,15 @@ void CheckSpirvBudget(const char *name, const std::vector<uint32_t> &binary,
|
||||
const bool within =
|
||||
actual.words <= budget.words &&
|
||||
actual.instructions <= budget.instructions &&
|
||||
actual.ext_inst_imports <= budget.ext_inst_imports &&
|
||||
actual.type_images <= budget.type_images &&
|
||||
actual.type_samplers <= budget.type_samplers &&
|
||||
actual.type_sampled_images <= budget.type_sampled_images &&
|
||||
actual.runtime_arrays <= budget.runtime_arrays &&
|
||||
actual.image_pointers <= budget.image_pointers &&
|
||||
actual.variables <= budget.variables && actual.loads <= budget.loads &&
|
||||
actual.function_variables <= budget.function_variables &&
|
||||
actual.workgroup_variables <= budget.workgroup_variables &&
|
||||
actual.stores <= budget.stores &&
|
||||
actual.array_lengths <= budget.array_lengths &&
|
||||
actual.phis <= budget.phis && actual.labels <= budget.labels &&
|
||||
@@ -282,7 +382,15 @@ void CheckSpirvBudget(const char *name, const std::vector<uint32_t> &binary,
|
||||
actual.branches <= budget.branches &&
|
||||
actual.conditional_branches <= budget.conditional_branches &&
|
||||
actual.switches <= budget.switches && actual.ballots <= budget.ballots &&
|
||||
actual.quad_broadcasts <= budget.quad_broadcasts;
|
||||
actual.quad_broadcasts <= budget.quad_broadcasts &&
|
||||
actual.sampled_1d_capabilities <= budget.sampled_1d_capabilities &&
|
||||
actual.image_1d_capabilities <= budget.image_1d_capabilities &&
|
||||
actual.image_query_capabilities <= budget.image_query_capabilities &&
|
||||
actual.storage_read_without_format_capabilities <=
|
||||
budget.storage_read_without_format_capabilities &&
|
||||
actual.storage_write_without_format_capabilities <=
|
||||
budget.storage_write_without_format_capabilities &&
|
||||
actual.image_texel_pointers <= budget.image_texel_pointers;
|
||||
if (!within) {
|
||||
std::fprintf(
|
||||
stderr,
|
||||
@@ -295,9 +403,9 @@ void CheckSpirvBudget(const char *name, const std::vector<uint32_t> &binary,
|
||||
"cond=%u switches=%u ballots=%u quad=%u\n",
|
||||
name, actual.words, actual.instructions, actual.type_images,
|
||||
actual.variables, actual.loads, actual.stores, actual.array_lengths,
|
||||
actual.phis, actual.labels, actual.loop_merges,
|
||||
actual.selection_merges, actual.branches, actual.conditional_branches,
|
||||
actual.switches, actual.ballots, actual.quad_broadcasts, budget.words,
|
||||
actual.phis, actual.labels, actual.loop_merges, actual.selection_merges,
|
||||
actual.branches, actual.conditional_branches, actual.switches,
|
||||
actual.ballots, actual.quad_broadcasts, budget.words,
|
||||
budget.instructions, budget.type_images, budget.variables, budget.loads,
|
||||
budget.stores, budget.array_lengths, budget.phis, budget.labels,
|
||||
budget.loop_merges, budget.selection_merges, budget.branches,
|
||||
@@ -815,8 +923,8 @@ void TestSpirvRequirementsAnalysis() {
|
||||
block->AppendNewInst(ValueOpcode::SetAttribute, {Value(0u), Value(true)});
|
||||
export_value.SetFlags(ExportFlags{.index = 0});
|
||||
|
||||
const auto requirements =
|
||||
ShaderRecompiler::Spirv::GetProgramRequirements(program);
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(program);
|
||||
const auto requirements = *program.spirv_requirements;
|
||||
Check(requirements.requires_exact_subgroup && requirements.subgroup_ballot &&
|
||||
requirements.subgroup_shuffle &&
|
||||
requirements.subgroup_local_invocation_id &&
|
||||
@@ -826,8 +934,8 @@ void TestSpirvRequirementsAnalysis() {
|
||||
"consolidated SPIR-V requirements missed an IR dependency");
|
||||
|
||||
program.stage = ShaderType::Compute;
|
||||
const auto compute_requirements =
|
||||
ShaderRecompiler::Spirv::GetProgramRequirements(program);
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(program);
|
||||
const auto compute_requirements = *program.spirv_requirements;
|
||||
Check(!compute_requirements.function_lds &&
|
||||
!compute_requirements.pixel_valid_mask,
|
||||
"stage-specific SPIR-V requirements leaked into compute");
|
||||
@@ -835,14 +943,14 @@ void TestSpirvRequirementsAnalysis() {
|
||||
program.stage = ShaderType::Pixel;
|
||||
shared.SetFlags(MemoryFlags{.index = 1});
|
||||
export_value.SetFlags(ExportFlags{.index = 1});
|
||||
const auto invalid_metadata =
|
||||
ShaderRecompiler::Spirv::GetProgramRequirements(program);
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(program);
|
||||
const auto invalid_metadata = *program.spirv_requirements;
|
||||
Check(!invalid_metadata.function_lds && !invalid_metadata.pixel_valid_mask,
|
||||
"invalid SPIR-V requirement metadata was accepted");
|
||||
|
||||
Program empty;
|
||||
const auto empty_requirements =
|
||||
ShaderRecompiler::Spirv::GetProgramRequirements(empty);
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(empty);
|
||||
const auto empty_requirements = *empty.spirv_requirements;
|
||||
Check(!empty_requirements.requires_exact_subgroup &&
|
||||
!empty_requirements.subgroup_ballot &&
|
||||
!empty_requirements.subgroup_shuffle &&
|
||||
@@ -872,9 +980,7 @@ void TestNativeSubgroupPolicy() {
|
||||
block->AppendNewInst(opcode, {Value(&resource), Value(0u), Value(true),
|
||||
Value(1u), Value(0u)});
|
||||
}
|
||||
program.spirv_requirements.reset();
|
||||
program.spirv_requirements =
|
||||
ShaderRecompiler::Spirv::GetProgramRequirements(program);
|
||||
ShaderRecompiler::Spirv::AnalyzeProgramRequirements(program);
|
||||
};
|
||||
|
||||
GraphicContext context;
|
||||
@@ -906,8 +1012,7 @@ void TestNativeSubgroupPolicy() {
|
||||
|
||||
ShaderRecompiler::IR::Program cross_lane = safe;
|
||||
SetTypedValues(cross_lane, ShaderRecompiler::IR::ValueOpcode::ReadLane);
|
||||
Check(ShaderRecompiler::Spirv::GetProgramRequirements(cross_lane)
|
||||
.requires_exact_subgroup &&
|
||||
Check(cross_lane.spirv_requirements->requires_exact_subgroup &&
|
||||
ConfigureShaderSubgroup(ShaderSubgroupCapabilities{context},
|
||||
vk::ShaderStageFlagBits::eVertex,
|
||||
cross_lane)
|
||||
@@ -924,8 +1029,7 @@ void TestNativeSubgroupPolicy() {
|
||||
ShaderRecompiler::IR::Program zero_exec = safe;
|
||||
zero_exec.lane_mask_mode = ShaderLaneMaskMode::NativeWave;
|
||||
SetTypedValues(zero_exec);
|
||||
Check(!ShaderRecompiler::Spirv::GetProgramRequirements(zero_exec)
|
||||
.requires_exact_subgroup &&
|
||||
Check(!zero_exec.spirv_requirements->requires_exact_subgroup &&
|
||||
ConfigureShaderSubgroup(ShaderSubgroupCapabilities{context},
|
||||
vk::ShaderStageFlagBits::eCompute,
|
||||
zero_exec)
|
||||
@@ -935,20 +1039,17 @@ void TestNativeSubgroupPolicy() {
|
||||
|
||||
ShaderRecompiler::IR::Program selective_exec = safe;
|
||||
SetTypedValues(selective_exec, ShaderRecompiler::IR::ValueOpcode::Ballot);
|
||||
Check(ShaderRecompiler::Spirv::GetProgramRequirements(selective_exec)
|
||||
.requires_exact_subgroup,
|
||||
Check(selective_exec.spirv_requirements->requires_exact_subgroup,
|
||||
"selective EXEC write was classified mask-free");
|
||||
|
||||
ShaderRecompiler::IR::Program carry = safe;
|
||||
SetTypedValues(carry, ShaderRecompiler::IR::ValueOpcode::Ballot);
|
||||
Check(ShaderRecompiler::Spirv::GetProgramRequirements(carry)
|
||||
.requires_exact_subgroup,
|
||||
Check(carry.spirv_requirements->requires_exact_subgroup,
|
||||
"lane-varying VCC carry producer was classified mask-free");
|
||||
|
||||
ShaderRecompiler::IR::Program vcc_branch = safe;
|
||||
SetTypedValues(vcc_branch, ShaderRecompiler::IR::ValueOpcode::Ballot);
|
||||
Check(ShaderRecompiler::Spirv::GetProgramRequirements(vcc_branch)
|
||||
.requires_exact_subgroup,
|
||||
Check(vcc_branch.spirv_requirements->requires_exact_subgroup,
|
||||
"whole-wave VCC branch was classified mask-free");
|
||||
|
||||
ShaderRecompiler::IR::Program ds_partial = safe;
|
||||
@@ -3020,9 +3121,7 @@ void TestNewShaderRecompilerCapturedVop1SdwaByteConvert() {
|
||||
const uint32_t shader[] = {
|
||||
0x7e0822f9u,
|
||||
0x00040609u, // v_cvt_f32_ubyte0 v4, v9.word0 (PS 9ebba6b9)
|
||||
EncodeExp0(0x00, 0x1),
|
||||
EncodeExp1(4, 0, 0, 0),
|
||||
EncodeSopp(0x01),
|
||||
EncodeExp0(0x00, 0x1), EncodeExp1(4, 0, 0, 0), EncodeSopp(0x01),
|
||||
};
|
||||
|
||||
ShaderPixelInputInfo ps_info{};
|
||||
@@ -3047,8 +3146,8 @@ void TestNewShaderRecompilerCapturedVop1SdwaByteConvert() {
|
||||
for (const auto &inst : *block) {
|
||||
extracts += inst.GetOpcode() ==
|
||||
ShaderRecompiler::IR::ValueOpcode::BitFieldUExtract;
|
||||
converts += inst.GetOpcode() ==
|
||||
ShaderRecompiler::IR::ValueOpcode::ConvertF32U32;
|
||||
converts +=
|
||||
inst.GetOpcode() == ShaderRecompiler::IR::ValueOpcode::ConvertF32U32;
|
||||
}
|
||||
}
|
||||
Check(extracts != 0u && converts != 0u,
|
||||
@@ -3096,7 +3195,8 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() {
|
||||
0x4a0c0cf9u,
|
||||
0x0d860688u, // v_add_nc_u32 v6, 8, sign-extended v6.hi
|
||||
0x4a08c2f9u,
|
||||
0x0686156au, // captured v_add_nc_u32 v4.word1, vcc_lo, v97; preserve word0
|
||||
0x0686156au, // captured v_add_nc_u32 v4.word1, vcc_lo, v97; preserve
|
||||
// word0
|
||||
0x4c1616f9u,
|
||||
0x0686128du, // v_sub_nc_u32 v11.byte2, 13, v11; preserve other
|
||||
// destination bytes
|
||||
@@ -3152,9 +3252,10 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() {
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_add_nc_u32 v6") &&
|
||||
Common::ContainsStr(result.decoded_dump, "v6.sdwa(sel=5,sext=1"),
|
||||
"new decoder did not decode V_ADD_NC_U32 SDWA sign-extended high word");
|
||||
Check(Common::ContainsStr(result.decoded_dump,
|
||||
"v_add_nc_u32 v4.sdwa(sel=5,sext=0), vcc_lo, v97"),
|
||||
"new decoder did not decode captured V_ADD_NC_U32 high-word destination");
|
||||
Check(
|
||||
Common::ContainsStr(result.decoded_dump,
|
||||
"v_add_nc_u32 v4.sdwa(sel=5,sext=0), vcc_lo, v97"),
|
||||
"new decoder did not decode captured V_ADD_NC_U32 high-word destination");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_sub_nc_u32 v11.sdwa(sel=2"),
|
||||
"new decoder did not decode V_SUB_NC_U32 SDWA byte-2 destination");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_min_u32 v10.sdwa(sel=4"),
|
||||
@@ -3695,9 +3796,9 @@ void TestNewShaderDecoderArchitecture() {
|
||||
Check(DecodeInstruction(vop2_sdwa_partial_dst, 0u, sdwa_add, &error),
|
||||
error.c_str());
|
||||
Check(sdwa_add.family == Family::VOP2 &&
|
||||
sdwa_add.opcode == Opcode::V_ADD_NC_U32 && sdwa_add.word_count == 2u &&
|
||||
sdwa_add.dst.reg == 4u && sdwa_add.dst.sdwa_sel == 5u &&
|
||||
sdwa_add.dst.sdwa_dst_unused == 2u &&
|
||||
sdwa_add.opcode == Opcode::V_ADD_NC_U32 &&
|
||||
sdwa_add.word_count == 2u && sdwa_add.dst.reg == 4u &&
|
||||
sdwa_add.dst.sdwa_sel == 5u && sdwa_add.dst.sdwa_dst_unused == 2u &&
|
||||
sdwa_add.src0.kind == OperandKind::VccLo &&
|
||||
sdwa_add.src1.kind == OperandKind::Vgpr && sdwa_add.src1.reg == 97u,
|
||||
"decoder rejected or misdecoded captured partial-destination "
|
||||
@@ -3842,8 +3943,8 @@ void TestNewShaderRecompilerMemoryFamilyLowering() {
|
||||
"new decoder did not decode SMEM scalar-buffer dword load");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "s_buffer_load_dword s1, s8"),
|
||||
"SMEM scalar-buffer SBASE was not decoded as an SGPR-pair index");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "buffer_load_dword"),
|
||||
"new decoder did not decode MUBUF dword load");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "buffer_load_dword"),
|
||||
"new decoder did not decode MUBUF dword load");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "buffer_store_dword"),
|
||||
"new decoder did not decode MUBUF dword store");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "ds_read_b32"),
|
||||
@@ -3947,7 +4048,8 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
address_binding->resources == std::vector<uint32_t>{0u} &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Buffers) == nullptr &&
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Buffers) ==
|
||||
nullptr &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
raw.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) ==
|
||||
@@ -3994,7 +4096,8 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Buffers);
|
||||
Check(buffer.program.info.buffers.size() == 1u &&
|
||||
buffer.program.info.buffers[0].scalar &&
|
||||
buffer.program.info.addresses.empty() && buffer_binding != nullptr &&
|
||||
buffer.program.info.addresses.empty() &&
|
||||
buffer_binding != nullptr &&
|
||||
buffer_binding->resources == std::vector<uint32_t>{0u} &&
|
||||
ShaderRecompiler::IR::FindBinding(
|
||||
buffer.program.bindings,
|
||||
@@ -4007,8 +4110,7 @@ void TestNewShaderRecompilerScalarMemoryBindingDomains() {
|
||||
buffer.program.bindings.buffer_offset_count == 1u,
|
||||
"descriptor scalar load did not use only the buffer domain");
|
||||
Check(count_live_memory_ops(
|
||||
buffer.program,
|
||||
ShaderRecompiler::IR::ValueOpcode::ReadConstBuffer,
|
||||
buffer.program, ShaderRecompiler::IR::ValueOpcode::ReadConstBuffer,
|
||||
ShaderRecompiler::IR::ResourceKind::ScalarBuffer) == 1u,
|
||||
"descriptor scalar load did not remain a live typed buffer operation");
|
||||
CheckSpirvBinaryValidates(buffer.spirv);
|
||||
@@ -4402,6 +4504,13 @@ void TestNewShaderRecompilerPixelImageSampleLodSelection() {
|
||||
|
||||
{
|
||||
const auto result = compile(0x20, 0xf); // image_sample
|
||||
const auto metrics = MeasureSpirv(result.spirv);
|
||||
Check(metrics.type_images == 1u && metrics.type_samplers == 1u &&
|
||||
metrics.type_sampled_images == 1u &&
|
||||
metrics.sampled_1d_capabilities == 0u &&
|
||||
metrics.image_1d_capabilities == 0u &&
|
||||
metrics.image_query_capabilities == 0u,
|
||||
"plain 2D sample emitted unrelated image declarations");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "image_sample"),
|
||||
"plain pixel IMAGE_SAMPLE did not decode");
|
||||
Check(SpirvInstructionOpcodeCount(result.spirv, OpImageSampleImplicitLod) ==
|
||||
@@ -7346,13 +7455,15 @@ void TestNewShaderRecompilerCfgOverlappingEarlyExitLadder() {
|
||||
"early-exit ladder routing changed semantic instruction coverage");
|
||||
Check(graph.blocks.size() > original_block_count,
|
||||
"early-exit ladder routing did not add forwarding blocks");
|
||||
const auto route_selects = std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.condition ==
|
||||
ShaderRecompiler::CFG::BranchCondition::GotoVariable;
|
||||
});
|
||||
const auto route_sets = std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.goto_value >= 0;
|
||||
});
|
||||
const auto route_selects =
|
||||
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.condition ==
|
||||
ShaderRecompiler::CFG::BranchCondition::GotoVariable;
|
||||
});
|
||||
const auto route_sets =
|
||||
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.goto_value >= 0;
|
||||
});
|
||||
Check(route_selects != 0u && route_sets >= 3u,
|
||||
"early-exit ladder lacks explicit typed route state");
|
||||
|
||||
@@ -7398,13 +7509,15 @@ void TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal() {
|
||||
Check(CfgInstructionCoverage(graph, decoded.instructions.size()) ==
|
||||
original_coverage,
|
||||
"nested early-exit structurization changed semantic coverage");
|
||||
const auto route_selects = std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.condition ==
|
||||
ShaderRecompiler::CFG::BranchCondition::GotoVariable;
|
||||
});
|
||||
const auto route_sets = std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.goto_value >= 0;
|
||||
});
|
||||
const auto route_selects =
|
||||
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.condition ==
|
||||
ShaderRecompiler::CFG::BranchCondition::GotoVariable;
|
||||
});
|
||||
const auto route_sets =
|
||||
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||
return block.terminator.goto_value >= 0;
|
||||
});
|
||||
Check(route_selects == 1u && route_sets == 3u,
|
||||
"nested early exit lacks complete typed route state");
|
||||
|
||||
@@ -7799,6 +7912,126 @@ void TestNewShaderRecompilerExpVertexOutputs() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
}
|
||||
|
||||
void TestDemandDrivenSpirvDeclarations() {
|
||||
using ShaderRecompiler::Spirv::Builder;
|
||||
|
||||
Builder declarations;
|
||||
const auto uint_type = declarations.Type(21u, {32u, 0u});
|
||||
Check(uint_type == declarations.Type(21u, {32u, 0u}),
|
||||
"structural type interning returned different IDs");
|
||||
const auto zero = declarations.Constant(43u, uint_type, {0u});
|
||||
Check(zero == declarations.Constant(43u, uint_type, {0u}),
|
||||
"constant interning returned different IDs");
|
||||
Check(declarations.Import("GLSL.std.450") ==
|
||||
declarations.Import("GLSL.std.450"),
|
||||
"extended-instruction import was duplicated");
|
||||
declarations.RequireCapability(1u);
|
||||
declarations.RequireCapability(1u);
|
||||
const auto plain_array = declarations.Type(28u, {uint_type, zero});
|
||||
const auto decorated_array = declarations.DecoratedType(
|
||||
28u, {uint_type, zero}, {{71u, {6u, sizeof(uint32_t)}}});
|
||||
Check(decorated_array ==
|
||||
declarations.DecoratedType(28u, {uint_type, zero},
|
||||
{{71u, {6u, sizeof(uint32_t)}}}),
|
||||
"decorated type interning returned different IDs");
|
||||
Check(plain_array != decorated_array,
|
||||
"decorated and undecorated aggregate types were aliased");
|
||||
Check(declarations.DecoratedType(28u, {uint_type, zero}, {}) == plain_array,
|
||||
"empty decorated type request bypassed structural interning");
|
||||
const auto ptr = declarations.Type(32u, {7u, uint_type});
|
||||
Check(declarations.DefineGlobalVariable(ptr, 7u) !=
|
||||
declarations.DefineGlobalVariable(ptr, 7u),
|
||||
"distinct variables were structurally interned");
|
||||
const auto declaration_binary = declarations.Build();
|
||||
Check(SpirvInstructionOpcodeCount(declaration_binary, 17u) == 1u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 11u) == 1u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 21u) == 1u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 28u) == 2u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 43u) == 1u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 71u) == 1u &&
|
||||
SpirvInstructionOpcodeCount(declaration_binary, 59u) == 2u,
|
||||
"canonical builder emitted duplicate declarations");
|
||||
|
||||
const auto compile = [](std::span<const uint32_t> shader) {
|
||||
auto user_data = ImageTestUserData();
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.user_data = user_data.data();
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||
error.c_str());
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
return result.spirv;
|
||||
};
|
||||
|
||||
const uint32_t query[] = {EncodeMimg0(0x60, 0x3), EncodeMimg1(6, 0, 0, 1),
|
||||
EncodeExp0(0x00, 0x3), EncodeExp1(6, 7, 0, 0),
|
||||
EncodeSopp(0x01)};
|
||||
auto query_user_data = ImageTestUserData();
|
||||
auto query_pixel_info = RegressionPixelInputInfo();
|
||||
auto query_options = MakeCompileOptions(ShaderType::Pixel);
|
||||
query_options.input_info.pixel = &query_pixel_info;
|
||||
query_options.user_data = query_user_data.data();
|
||||
ShaderRecompiler::CompileResult query_result;
|
||||
std::string query_error;
|
||||
Check(ShaderRecompiler::TryRecompile(query, query_options, query_result,
|
||||
&query_error),
|
||||
query_error.c_str());
|
||||
CheckSpirvBinaryValidates(query_result.spirv);
|
||||
const auto &query_spirv = query_result.spirv;
|
||||
Check(SpirvInstructionOpcodeCount(query_spirv, 105u) == 1u,
|
||||
"image query fixture did not reach OpImageQueryLod");
|
||||
const auto query_metrics = MeasureSpirv(query_spirv);
|
||||
Check(query_metrics.type_images == 1u && query_metrics.type_samplers == 1u &&
|
||||
query_metrics.type_sampled_images == 1u &&
|
||||
query_metrics.image_query_capabilities == 1u &&
|
||||
query_metrics.sampled_1d_capabilities == 0u &&
|
||||
query_metrics.image_1d_capabilities == 0u,
|
||||
"image query emitted unrelated or duplicate declarations");
|
||||
|
||||
const uint32_t store[] = {EncodeMimg0(0x08, 0xf), EncodeMimg1(0, 0, 0, 20),
|
||||
EncodeSopp(0x01)};
|
||||
const auto store_spirv = compile(store);
|
||||
Check(SpirvInstructionOpcodeCount(store_spirv, 99u) == 1u,
|
||||
"storage image fixture did not reach OpImageWrite");
|
||||
const auto store_metrics = MeasureSpirv(store_spirv);
|
||||
Check(store_metrics.type_images == 1u && store_metrics.type_samplers == 0u &&
|
||||
store_metrics.type_sampled_images == 0u &&
|
||||
store_metrics.storage_read_without_format_capabilities == 0u &&
|
||||
store_metrics.storage_write_without_format_capabilities == 1u,
|
||||
"storage write emitted unrelated or duplicate declarations");
|
||||
|
||||
const uint32_t atomic[] = {EncodeMimg0(0x11, 0x1, true),
|
||||
EncodeMimg1(0, 0, 0, 20), EncodeSopp(0x01)};
|
||||
const auto atomic_spirv = compile(atomic);
|
||||
Check(SpirvInstructionOpcodeCount(atomic_spirv, 60u) == 1u,
|
||||
"image atomic fixture did not reach OpImageTexelPointer");
|
||||
const auto atomic_metrics = MeasureSpirv(atomic_spirv);
|
||||
Check(atomic_metrics.type_images == 1u &&
|
||||
atomic_metrics.type_samplers == 0u &&
|
||||
atomic_metrics.type_sampled_images == 0u &&
|
||||
atomic_metrics.image_pointers == 1u &&
|
||||
atomic_metrics.image_texel_pointers == 1u &&
|
||||
atomic_metrics.storage_read_without_format_capabilities == 0u &&
|
||||
atomic_metrics.storage_write_without_format_capabilities == 0u,
|
||||
"image atomic emitted unrelated or duplicate declarations");
|
||||
|
||||
const uint32_t glsl[] = {EncodeVop1(0x24, 0, 1), EncodeVop1(0x24, 2, 3),
|
||||
EncodeExp0(0x00, 0x3), EncodeExp1(0, 2, 0, 0),
|
||||
EncodeSopp(0x01)};
|
||||
auto glsl_pixel_info = RegressionPixelInputInfo();
|
||||
auto glsl_options = MakeCompileOptions(ShaderType::Pixel);
|
||||
glsl_options.input_info.pixel = &glsl_pixel_info;
|
||||
ShaderRecompiler::CompileResult glsl_result;
|
||||
std::string glsl_error;
|
||||
Check(ShaderRecompiler::TryRecompile(glsl, glsl_options, glsl_result,
|
||||
&glsl_error),
|
||||
glsl_error.c_str());
|
||||
CheckSpirvBinaryValidates(glsl_result.spirv);
|
||||
Check(MeasureSpirv(glsl_result.spirv).ext_inst_imports == 1u,
|
||||
"multiple GLSL operations emitted duplicate imports");
|
||||
}
|
||||
|
||||
void TestTypedEntryStateIsMinimal() {
|
||||
using namespace ShaderRecompiler;
|
||||
|
||||
@@ -7935,10 +8168,9 @@ void TestNewShaderRecompilerZeroInitialRegisterState() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const uint32_t explicit_zero_shader[] = {
|
||||
EncodeSMovB32(100, 128), // s_mov_b32 s100, 0
|
||||
EncodeVop1(0x01, 0, 100), // v_mov_b32 v0, s100
|
||||
EncodeExp0(0x0c, 0xf),
|
||||
EncodeExp1(0, 1, 2, 3), // POS0
|
||||
EncodeSMovB32(100, 128), // s_mov_b32 s100, 0
|
||||
EncodeVop1(0x01, 0, 100), // v_mov_b32 v0, s100
|
||||
EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 2, 3), // POS0
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
ShaderRecompiler::CompileResult explicit_zero;
|
||||
@@ -8059,8 +8291,7 @@ void TestNewShaderRecompilerPerInvocationMasksWithoutMirrors() {
|
||||
const uint32_t wqm_shader[] = {
|
||||
EncodeSop1(0x0a, 2, 126), // s_wqm_b64 s[2:3], exec
|
||||
EncodeVop1(0x01, 0, 2), // v_mov_b32 v0, s2
|
||||
EncodeExp0(0x0c, 0xf),
|
||||
EncodeExp1(0, 1, 2, 3), // POS0
|
||||
EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 2, 3), // POS0
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
Check(ShaderRecompiler::TryRecompile(wqm_shader, options, result, &error),
|
||||
@@ -8538,8 +8769,8 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
const auto rejected_before = rejected_spirv;
|
||||
std::string rejected_error;
|
||||
Check(!ShaderRecompiler::Spirv::EmitProgram(
|
||||
malformed, result.resources, options.input_info,
|
||||
rejected_spirv, &rejected_error) &&
|
||||
malformed, result.resources, options.input_info, rejected_spirv,
|
||||
&rejected_error) &&
|
||||
rejected_spirv == rejected_before &&
|
||||
rejected_error.find("topology") != std::string::npos,
|
||||
"malformed native binding plan was not rejected transactionally");
|
||||
@@ -8559,8 +8790,8 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
rejected_spirv = rejected_before;
|
||||
rejected_error.clear();
|
||||
Check(!ShaderRecompiler::Spirv::EmitProgram(
|
||||
result.program, stale_resources, options.input_info,
|
||||
rejected_spirv, &rejected_error) &&
|
||||
result.program, stale_resources, options.input_info, rejected_spirv,
|
||||
&rejected_error) &&
|
||||
rejected_spirv == rejected_before &&
|
||||
rejected_error.find("specialized format") != std::string::npos,
|
||||
"stale runtime image format re-selected an absent descriptor group");
|
||||
@@ -8570,8 +8801,8 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
rejected_spirv = rejected_before;
|
||||
rejected_error.clear();
|
||||
Check(!ShaderRecompiler::Spirv::EmitProgram(
|
||||
result.program, stale_dimension, options.input_info,
|
||||
rejected_spirv, &rejected_error) &&
|
||||
result.program, stale_dimension, options.input_info, rejected_spirv,
|
||||
&rejected_error) &&
|
||||
rejected_spirv == rejected_before &&
|
||||
rejected_error.find("specialized dimension") != std::string::npos,
|
||||
"unsupported runtime image type bypassed specialization validation");
|
||||
@@ -8594,8 +8825,8 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
rejected_spirv = rejected_before;
|
||||
rejected_error.clear();
|
||||
const bool rejected = !ShaderRecompiler::Spirv::EmitProgram(
|
||||
result.program, result.resources, options.input_info,
|
||||
rejected_spirv, &rejected_error);
|
||||
result.program, result.resources, options.input_info, rejected_spirv,
|
||||
&rejected_error);
|
||||
buffer_handle->SetFlags(dense);
|
||||
Check(rejected && rejected_spirv == rejected_before &&
|
||||
rejected_error.find("invalid dense resource") != std::string::npos,
|
||||
@@ -9387,7 +9618,8 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
|
||||
void TestComputeLdsAllocationIdentity() {
|
||||
const uint32_t shader[] = {
|
||||
EncodeDs0(0x0d, 4288u), // ds_write_b32 v0, v1 offset:4288
|
||||
EncodeDs1(0, 1, 0), EncodeSopp(0x01),
|
||||
EncodeDs1(0, 1, 0),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
HW::ComputeShaderInfo regs{};
|
||||
regs.cs_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||
@@ -9409,6 +9641,8 @@ void TestComputeLdsAllocationIdentity() {
|
||||
Check(input_info.lds_size_dwords == expected_dwords,
|
||||
"COMPUTE_PGM_RSRC2 LDS allocation units were not decoded");
|
||||
const std::vector<uint32_t> binary(spirv.begin(), spirv.end());
|
||||
Check(MeasureSpirv(binary).workgroup_variables == 1u,
|
||||
"LDS shader did not declare exactly one Workgroup variable");
|
||||
Check(SpirvArrayLengthCount(binary, expected_dwords) == 1u,
|
||||
"SPIR-V workgroup array did not use the declared LDS allocation");
|
||||
Check(SpirvUnsignedLessThanBoundCount(binary, expected_dwords) == 1u,
|
||||
@@ -9432,7 +9666,8 @@ void TestComputeLdsAllocationIdentity() {
|
||||
|
||||
const uint32_t append_shader[] = {
|
||||
EncodeSMovB32(124, 132), // m0 = 4 bytes
|
||||
EncodeDs0(0x3e), EncodeDs1(1, 0, 0), // ds_append v1
|
||||
EncodeDs0(0x3e),
|
||||
EncodeDs1(1, 0, 0), // ds_append v1
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
ShaderComputeInputInfo append_info = RegressionComputeInputInfo();
|
||||
@@ -9602,28 +9837,34 @@ void TestNewShaderRecompilerFlatAddressProvenanceBoundaries() {
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
const auto compile = [](const char *name, std::span<const uint32_t> shader,
|
||||
const SpirvMetrics &budget,
|
||||
ShaderType stage = ShaderType::Compute,
|
||||
ShaderLaneMaskMode lane_mask_mode =
|
||||
ShaderLaneMaskMode::NativeWave) {
|
||||
auto options = MakeCompileOptions(stage);
|
||||
options.dump_ir = true;
|
||||
options.lane_mask_mode = lane_mask_mode;
|
||||
const auto compile =
|
||||
[](const char *name, std::span<const uint32_t> shader,
|
||||
const SpirvMetrics &budget, ShaderType stage = ShaderType::Compute,
|
||||
ShaderLaneMaskMode lane_mask_mode = ShaderLaneMaskMode::NativeWave) {
|
||||
auto options = MakeCompileOptions(stage);
|
||||
options.dump_ir = true;
|
||||
options.lane_mask_mode = lane_mask_mode;
|
||||
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||
error.c_str());
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
CheckSpirvBudget(name, result.spirv, budget);
|
||||
return result;
|
||||
};
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||
error.c_str());
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
CheckSpirvBudget(name, result.spirv, budget);
|
||||
return result;
|
||||
};
|
||||
|
||||
const uint32_t empty[] = {EncodeSopp(0x01)};
|
||||
compile("empty", empty,
|
||||
{.words = 640, .instructions = 140, .type_images = 24,
|
||||
.variables = 1, .labels = 4, .branches = 3});
|
||||
const auto empty_result =
|
||||
compile("empty", empty,
|
||||
{.words = 64, .instructions = 20, .labels = 4, .branches = 3});
|
||||
const auto empty_metrics = MeasureSpirv(empty_result.spirv);
|
||||
Check(empty_metrics.type_voids == 1u && empty_metrics.type_functions == 1u &&
|
||||
empty_metrics.type_bools == 0u && empty_metrics.type_ints == 0u &&
|
||||
empty_metrics.type_floats == 0u &&
|
||||
empty_metrics.type_vectors == 0u &&
|
||||
empty_metrics.type_pointers == 0u,
|
||||
"empty shader emitted unused core types or pointers");
|
||||
|
||||
const uint32_t structured_phi[] = {
|
||||
EncodeSMovB32(0, 128), // s0 = 0
|
||||
@@ -9633,19 +9874,17 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
EncodeSopp(0x02, 0xfffcu), // continue/backedge
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const auto structured_result =
|
||||
compile("structured-phi", structured_phi,
|
||||
{.words = 705,
|
||||
.instructions = 158,
|
||||
.type_images = 24,
|
||||
.variables = 2,
|
||||
.loads = 1,
|
||||
.stores = 2,
|
||||
.phis = 1,
|
||||
.labels = 7,
|
||||
.loop_merges = 1,
|
||||
.branches = 5,
|
||||
.conditional_branches = 1});
|
||||
const auto structured_result = compile("structured-phi", structured_phi,
|
||||
{.words = 147,
|
||||
.instructions = 43,
|
||||
.variables = 1,
|
||||
.function_variables = 1,
|
||||
.loads = 1,
|
||||
.stores = 2,
|
||||
.labels = 7,
|
||||
.loop_merges = 1,
|
||||
.branches = 5,
|
||||
.conditional_branches = 1});
|
||||
Check(Common::ContainsStr(structured_result.ir_dump, "Phi"),
|
||||
"structured Phi size fixture no longer contains an IR Phi");
|
||||
|
||||
@@ -9656,25 +9895,22 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
EncodeMubuf1(0, 0, 1), // buffer_store_dwordx4 v[0:3]
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const auto wide_result =
|
||||
compile("wide-buffer", wide_buffer,
|
||||
{.words = 2549,
|
||||
.instructions = 583,
|
||||
.type_images = 24,
|
||||
.variables = 3,
|
||||
.loads = 9,
|
||||
.stores = 4,
|
||||
.array_lengths = 8,
|
||||
.phis = 8,
|
||||
.labels = 52,
|
||||
.selection_merges = 16,
|
||||
.branches = 35,
|
||||
.conditional_branches = 16});
|
||||
Check(Common::ContainsStr(wide_result.decoded_dump,
|
||||
"BUFFER_LOAD_DWORDX4"),
|
||||
const auto wide_result = compile("wide-buffer", wide_buffer,
|
||||
{.words = 1988,
|
||||
.instructions = 466,
|
||||
.runtime_arrays = 1,
|
||||
.variables = 2,
|
||||
.loads = 9,
|
||||
.stores = 4,
|
||||
.array_lengths = 8,
|
||||
.phis = 8,
|
||||
.labels = 52,
|
||||
.selection_merges = 16,
|
||||
.branches = 35,
|
||||
.conditional_branches = 16});
|
||||
Check(Common::ContainsStr(wide_result.decoded_dump, "BUFFER_LOAD_DWORDX4"),
|
||||
"wide buffer size fixture no longer decodes its x4 load");
|
||||
Check(Common::ContainsStr(wide_result.decoded_dump,
|
||||
"BUFFER_STORE_DWORDX4"),
|
||||
Check(Common::ContainsStr(wide_result.decoded_dump, "BUFFER_STORE_DWORDX4"),
|
||||
"wide buffer size fixture no longer decodes its x4 store");
|
||||
|
||||
const uint32_t wqm[] = {
|
||||
@@ -9687,9 +9923,8 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
};
|
||||
const auto wqm_result =
|
||||
compile("wqm", wqm,
|
||||
{.words = 1221,
|
||||
.instructions = 260,
|
||||
.type_images = 24,
|
||||
{.words = 703,
|
||||
.instructions = 155,
|
||||
.variables = 4,
|
||||
.loads = 3,
|
||||
.stores = 1,
|
||||
@@ -9697,8 +9932,7 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
.selection_merges = 1,
|
||||
.branches = 4,
|
||||
.conditional_branches = 1,
|
||||
.ballots = 1,
|
||||
.quad_broadcasts = 4},
|
||||
.ballots = 1},
|
||||
ShaderType::Vertex, ShaderLaneMaskMode::PerInvocation);
|
||||
Check(Common::ContainsStr(wqm_result.ir_dump, "WqmMask"),
|
||||
"WQM size fixture no longer reaches per-invocation WqmMask IR");
|
||||
@@ -9710,20 +9944,19 @@ void TestNewShaderRecompilerSpirvSizeBaselines() {
|
||||
EncodeSopp(0x02, 0xfffeu), // B -> C
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
const auto dispatcher_result =
|
||||
compile("dispatcher", dispatcher,
|
||||
{.words = 822,
|
||||
.instructions = 195,
|
||||
.type_images = 24,
|
||||
.variables = 5,
|
||||
.loads = 4,
|
||||
.stores = 14,
|
||||
.labels = 14,
|
||||
.loop_merges = 1,
|
||||
.selection_merges = 1,
|
||||
.branches = 11,
|
||||
.conditional_branches = 1,
|
||||
.switches = 1});
|
||||
const auto dispatcher_result = compile("dispatcher", dispatcher,
|
||||
{.words = 258,
|
||||
.instructions = 78,
|
||||
.variables = 4,
|
||||
.function_variables = 4,
|
||||
.loads = 4,
|
||||
.stores = 14,
|
||||
.labels = 14,
|
||||
.loop_merges = 1,
|
||||
.selection_merges = 1,
|
||||
.branches = 11,
|
||||
.conditional_branches = 1,
|
||||
.switches = 1});
|
||||
Check(dispatcher_result.program.dispatcher_fallback &&
|
||||
SpirvInstructionOpcodeCount(dispatcher_result.spirv, 251u) == 1u,
|
||||
"dispatcher size fixture no longer exercises whole-function dispatch");
|
||||
@@ -9741,6 +9974,7 @@ int main() {
|
||||
TestNormalizedImageContracts();
|
||||
TestSpirvRequirementsAnalysis();
|
||||
TestNewShaderRecompilerSpirvSizeBaselines();
|
||||
TestDemandDrivenSpirvDeclarations();
|
||||
TestNativeSubgroupPolicy();
|
||||
TestNewShaderRecompilerSMovB32();
|
||||
TestNewShaderRecompilerCapturedVop1SdwaByteConvert();
|
||||
|
||||
Reference in new issue
Block a user