mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
224 lines
8.2 KiB
C++
224 lines
8.2 KiB
C++
#include "graphics/shader/recompiler/backend/spirv/SpirvBuilder.h"
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
|
|
|
static constexpr size_t InitialSpirvSectionReserve = 4096;
|
|
static constexpr size_t InitialSpirvFunctionSectionReserve = 32768;
|
|
|
|
static void AppendInstructionWords(std::vector<uint32_t>& section, const uint32_t* words,
|
|
size_t words_num) {
|
|
if (words_num == 0) {
|
|
return;
|
|
}
|
|
const uint32_t opcode = words[0];
|
|
const auto word_count = static_cast<uint32_t>(words_num);
|
|
section.push_back((word_count << spv::WordCountShift) | opcode);
|
|
section.insert(section.end(), words + 1, words + words_num);
|
|
}
|
|
|
|
Builder::Builder(uint32_t version): m_version(version) {
|
|
m_debug.reserve(InitialSpirvSectionReserve);
|
|
m_annotations.reserve(InitialSpirvSectionReserve);
|
|
m_declarations.reserve(InitialSpirvSectionReserve);
|
|
m_functions.reserve(InitialSpirvFunctionSectionReserve);
|
|
}
|
|
|
|
uint32_t Builder::AllocateId() {
|
|
return m_next_id++;
|
|
}
|
|
|
|
void Builder::RequireVersion(uint32_t version) {
|
|
m_version = std::max(m_version, version);
|
|
}
|
|
|
|
void Builder::RequireCapability(spv::Capability capability) {
|
|
if (m_required_capabilities.insert(capability).second) {
|
|
AppendInstruction(m_capabilities, spv::OpCapability, capability);
|
|
}
|
|
}
|
|
|
|
void Builder::RequireExtension(const char* name) {
|
|
if (m_required_extensions.emplace(name).second) {
|
|
std::vector<uint32_t> operands;
|
|
AppendString(operands, name);
|
|
AppendInstruction(m_extensions, spv::OpExtension, operands);
|
|
}
|
|
}
|
|
|
|
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);
|
|
std::vector<uint32_t> operands = {id};
|
|
AppendString(operands, name);
|
|
AppendInstruction(m_ext_inst_imports, spv::OpExtInstImport, operands);
|
|
return id;
|
|
}
|
|
|
|
uint32_t Builder::DeclareType(spv::Op opcode, std::vector<uint32_t> key) {
|
|
if (const auto it = m_declaration_ids.find(key); it != m_declaration_ids.end()) {
|
|
return it->second;
|
|
}
|
|
const auto id = AllocateId();
|
|
AppendInstruction(m_declarations, opcode, id, std::span<const uint32_t>(key).subspan(2));
|
|
m_declaration_ids.emplace(std::move(key), id);
|
|
return id;
|
|
}
|
|
|
|
uint32_t Builder::DeclareDecoratedType(spv::Op opcode, std::vector<uint32_t> key,
|
|
std::initializer_list<TypeAnnotation> annotations) {
|
|
if (annotations.size() == 0) {
|
|
return DeclareType(opcode, std::move(key));
|
|
}
|
|
const auto operand_count = key[1];
|
|
key.push_back(static_cast<uint32_t>(annotations.size()));
|
|
for (const auto& annotation: annotations) {
|
|
AppendOperand(key, 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();
|
|
AppendInstruction(m_declarations, opcode, id,
|
|
std::span<const uint32_t>(key).subspan(2, operand_count));
|
|
m_declaration_ids.emplace(std::move(key), id);
|
|
for (const auto& annotation: annotations) {
|
|
AppendInstruction(m_annotations, annotation.opcode, id, annotation.operands);
|
|
}
|
|
return id;
|
|
}
|
|
|
|
uint32_t Builder::DeclareConstant(spv::Op opcode, std::vector<uint32_t> key) {
|
|
if (const auto it = m_declaration_ids.find(key); it != m_declaration_ids.end()) {
|
|
return it->second;
|
|
}
|
|
const auto id = AllocateId();
|
|
AppendInstruction(m_declarations, opcode, key[1], id,
|
|
std::span<const uint32_t>(key).subspan(2));
|
|
m_declaration_ids.emplace(std::move(key), id);
|
|
return id;
|
|
}
|
|
|
|
uint32_t Builder::DefineGlobalVariable(uint32_t pointer_type, spv::StorageClass storage_class) {
|
|
const auto id = AllocateId();
|
|
DefineGlobalVariable(id, pointer_type, storage_class);
|
|
return id;
|
|
}
|
|
|
|
void Builder::DefineGlobalVariable(uint32_t id, uint32_t pointer_type,
|
|
spv::StorageClass storage_class) {
|
|
AppendInstruction(m_declarations, spv::OpVariable, 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;
|
|
for (size_t i = 0; i < word_count; i++) {
|
|
uint32_t word = 0;
|
|
for (size_t byte = 0; byte < 4; byte++) {
|
|
const auto index = i * 4u + byte;
|
|
if (index < len) {
|
|
word |= static_cast<uint32_t>(static_cast<unsigned char>(text[index]))
|
|
<< (byte * 8u);
|
|
}
|
|
}
|
|
words.push_back(word);
|
|
}
|
|
}
|
|
|
|
void Builder::AddMemoryModel(spv::AddressingModel addressing_model, spv::MemoryModel memory_model) {
|
|
AppendInstruction(m_memory_model, spv::OpMemoryModel, addressing_model, memory_model);
|
|
}
|
|
|
|
void Builder::AddEntryPoint(spv::ExecutionModel execution_model, uint32_t entry_point,
|
|
const char* name, const std::vector<uint32_t>& interfaces) {
|
|
std::vector<uint32_t> operands;
|
|
AppendOperands(operands, execution_model, entry_point);
|
|
AppendString(operands, name);
|
|
operands.insert(operands.end(), interfaces.begin(), interfaces.end());
|
|
if (m_version >= 0x00010400u) {
|
|
for (size_t offset = 0; offset < m_declarations.size();) {
|
|
const auto count = m_declarations[offset] >> spv::WordCountShift;
|
|
if ((m_declarations[offset] & spv::OpCodeMask) == spv::OpVariable) {
|
|
const auto id = m_declarations[offset + 2u];
|
|
if (std::find(interfaces.begin(), interfaces.end(), id) == interfaces.end()) {
|
|
operands.push_back(id);
|
|
}
|
|
}
|
|
offset += count;
|
|
}
|
|
}
|
|
AppendInstruction(m_entry_points, spv::OpEntryPoint, operands);
|
|
}
|
|
|
|
void Builder::AddName(uint32_t target, const char* name) {
|
|
std::vector<uint32_t> operands = {target};
|
|
AppendString(operands, name);
|
|
AppendInstruction(m_debug, spv::OpName, operands);
|
|
}
|
|
|
|
void Builder::AddFunction(std::span<const uint32_t> words) {
|
|
AppendInstructionWords(m_functions, words.data(), words.size());
|
|
}
|
|
|
|
DeferredPhi Builder::AddDeferredPhi(uint32_t type, uint32_t result, size_t incoming_count) {
|
|
std::vector<uint32_t> words {spv::OpPhi, type, result};
|
|
words.resize(words.size() + incoming_count * 2u);
|
|
const DeferredPhi phi {m_functions.size()};
|
|
AddFunction(words);
|
|
m_unpatched_phi_incomings += incoming_count;
|
|
return phi;
|
|
}
|
|
|
|
void Builder::PatchDeferredPhi(DeferredPhi phi, size_t incoming, uint32_t value, uint32_t parent) {
|
|
const auto incoming_count =
|
|
((m_functions.at(phi.word_offset) >> spv::WordCountShift) - 3u) / 2u;
|
|
EXIT_IF(incoming >= incoming_count || value == 0 || parent == 0);
|
|
const auto value_word = phi.word_offset + 3u + incoming * 2u;
|
|
const auto parent_word = value_word + 1u;
|
|
EXIT_IF(m_functions.at(value_word) != 0 || m_functions.at(parent_word) != 0);
|
|
m_functions[value_word] = value;
|
|
m_functions[parent_word] = parent;
|
|
m_unpatched_phi_incomings--;
|
|
}
|
|
|
|
std::vector<uint32_t> Builder::Build() const {
|
|
EXIT_IF(m_unpatched_phi_incomings != 0);
|
|
|
|
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_declarations.size() +
|
|
m_functions.size());
|
|
|
|
module.push_back(spv::MagicNumber);
|
|
module.push_back(m_version);
|
|
module.push_back(0u);
|
|
module.push_back(m_next_id);
|
|
module.push_back(0u);
|
|
|
|
module.insert(module.end(), m_capabilities.begin(), m_capabilities.end());
|
|
module.insert(module.end(), m_extensions.begin(), m_extensions.end());
|
|
module.insert(module.end(), m_ext_inst_imports.begin(), m_ext_inst_imports.end());
|
|
module.insert(module.end(), m_memory_model.begin(), m_memory_model.end());
|
|
module.insert(module.end(), m_entry_points.begin(), m_entry_points.end());
|
|
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_declarations.begin(), m_declarations.end());
|
|
module.insert(module.end(), m_functions.begin(), m_functions.end());
|
|
|
|
return module;
|
|
}
|
|
|
|
} // namespace Libs::Graphics::ShaderRecompiler::Spirv
|