mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
069f928edc | ||
|
|
0f3674f531 | ||
|
|
a21ffde34e | ||
|
|
1208d22547 | ||
|
|
3a27f8a76a | ||
|
|
dff2b19c56 | ||
|
|
a58db4f023 | ||
|
|
7bcd43dbee | ||
|
|
7c5473400e |
No files matched your search
@@ -90,8 +90,14 @@ starting a large change.
|
||||
|
||||
Set up the clang-format hook after cloning:
|
||||
|
||||
```powershell
|
||||
python -m pip install pre-commit
|
||||
Install `pre-commit` using the method appropriate for your platform:
|
||||
|
||||
- **Arch Linux / CachyOS:** `sudo pacman -S pre-commit`
|
||||
- **Other Linux / macOS / Windows:** `python -m pip install pre-commit`
|
||||
|
||||
Then install the Git hook:
|
||||
|
||||
```bash
|
||||
python -m pre_commit install --install-hooks
|
||||
```
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ ShaderOptimizationType GetShaderOptimizationType() {
|
||||
return g_config->shader_optimization_type;
|
||||
}
|
||||
|
||||
ShaderLogDirection GetShaderLogDirection() {
|
||||
LogDirection GetShaderLogDirection() {
|
||||
return g_config->shader_log_direction;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ bool GraphicsDebugDumpEnabled() {
|
||||
return g_config->graphics_debug_dump_enabled;
|
||||
}
|
||||
|
||||
OutputDirection GetPrintfDirection() {
|
||||
LogDirection GetPrintfDirection() {
|
||||
return g_config->printf_direction;
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ std::filesystem::path GetPrintfOutputFile() {
|
||||
return g_config->printf_output_file;
|
||||
}
|
||||
|
||||
ProfilerDirection GetProfilerDirection() {
|
||||
return g_config->profiler_direction;
|
||||
bool ProfilerEnabled() {
|
||||
return g_config->profiler_enabled;
|
||||
}
|
||||
|
||||
bool SpirvDebugPrintfEnabled() {
|
||||
|
||||
@@ -21,11 +21,7 @@ struct Lifecycle {
|
||||
|
||||
enum class ShaderOptimizationType { None, Size, Performance };
|
||||
|
||||
enum class ShaderLogDirection { Silent, Console, File };
|
||||
|
||||
enum class ProfilerDirection { None, Network };
|
||||
|
||||
enum class OutputDirection { Silent, Console, File };
|
||||
enum class LogDirection { Silent, Console, File };
|
||||
|
||||
enum class PresentMode { Fifo, Mailbox, Immediate };
|
||||
|
||||
@@ -47,7 +43,7 @@ struct ConfigOptions {
|
||||
uint32_t screen_height = 720;
|
||||
std::string user_name = "Kyty";
|
||||
int32_t user_id = DEFAULT_USER_ID;
|
||||
PresentMode present_mode = PresentMode::Fifo;
|
||||
PresentMode present_mode = PresentMode::Mailbox;
|
||||
int32_t gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
uint32_t vblank_frequency = 60;
|
||||
@@ -55,14 +51,14 @@ struct ConfigOptions {
|
||||
bool vulkan_validation_enabled = false;
|
||||
bool shader_validation_enabled = false;
|
||||
ShaderOptimizationType shader_optimization_type = ShaderOptimizationType::None;
|
||||
ShaderLogDirection shader_log_direction = ShaderLogDirection::Silent;
|
||||
LogDirection shader_log_direction = LogDirection::Silent;
|
||||
std::filesystem::path shader_log_folder = "_Shaders";
|
||||
bool command_buffer_dump_enabled = false;
|
||||
std::filesystem::path command_buffer_dump_folder = "_Buffers";
|
||||
bool graphics_debug_dump_enabled = false;
|
||||
OutputDirection printf_direction = OutputDirection::Silent;
|
||||
LogDirection printf_direction = LogDirection::Silent;
|
||||
std::filesystem::path printf_output_file = "_kyty.txt";
|
||||
ProfilerDirection profiler_direction = ProfilerDirection::None;
|
||||
bool profiler_enabled = false;
|
||||
bool spirv_debug_printf_enabled = false;
|
||||
bool gpu_assisted_validation_enabled = false;
|
||||
bool renderdoc_enabled = false;
|
||||
@@ -89,7 +85,7 @@ bool VulkanValidationEnabled();
|
||||
|
||||
bool ShaderValidationEnabled();
|
||||
ShaderOptimizationType GetShaderOptimizationType();
|
||||
ShaderLogDirection GetShaderLogDirection();
|
||||
LogDirection GetShaderLogDirection();
|
||||
std::filesystem::path GetShaderLogFolder();
|
||||
|
||||
bool CommandBufferDumpEnabled();
|
||||
@@ -97,10 +93,10 @@ std::filesystem::path GetCommandBufferDumpFolder();
|
||||
|
||||
bool GraphicsDebugDumpEnabled();
|
||||
|
||||
OutputDirection GetPrintfDirection();
|
||||
LogDirection GetPrintfDirection();
|
||||
std::filesystem::path GetPrintfOutputFile();
|
||||
|
||||
ProfilerDirection GetProfilerDirection();
|
||||
bool ProfilerEnabled();
|
||||
|
||||
bool SpirvDebugPrintfEnabled();
|
||||
|
||||
|
||||
@@ -152,9 +152,9 @@ void WriteFatal(fmt::text_style style, std::string_view text) {
|
||||
void Initialize() {
|
||||
g_initialized = true;
|
||||
switch (Config::GetPrintfDirection()) {
|
||||
case Config::OutputDirection::Silent: g_direction = Direction::Silent; break;
|
||||
case Config::OutputDirection::Console: g_direction = Direction::Console; break;
|
||||
case Config::OutputDirection::File: g_direction = Direction::File; break;
|
||||
case Config::LogDirection::Silent: g_direction = Direction::Silent; break;
|
||||
case Config::LogDirection::Console: g_direction = Direction::Console; break;
|
||||
case Config::LogDirection::File: g_direction = Direction::File; break;
|
||||
}
|
||||
g_output_file =
|
||||
(g_direction == Direction::File ? Config::GetPrintfOutputFile() : std::filesystem::path {});
|
||||
|
||||
+7
-13
@@ -55,19 +55,13 @@ void SetThreadName(const char* name) {
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
switch (Config::GetProfilerDirection()) {
|
||||
case Config::ProfilerDirection::Network:
|
||||
if (!tracy::ProfilerAvailable()) {
|
||||
tracy::StartupProfiler();
|
||||
TracySetProgramName("KytyPS5");
|
||||
::printf("Tracy profiler enabled: client %d.%d.%d, protocol %u, "
|
||||
"broadcast %u, connect to 127.0.0.1:8086\n",
|
||||
tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch,
|
||||
tracy::ProtocolVersion, tracy::BroadcastVersion);
|
||||
}
|
||||
break;
|
||||
case Config::ProfilerDirection::None:
|
||||
default: break;
|
||||
if (Config::ProfilerEnabled() && !tracy::ProfilerAvailable()) {
|
||||
tracy::StartupProfiler();
|
||||
TracySetProgramName("KytyPS5");
|
||||
::printf("Tracy profiler enabled: client %d.%d.%d, protocol %u, "
|
||||
"broadcast %u, connect to 127.0.0.1:8086\n",
|
||||
tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch,
|
||||
tracy::ProtocolVersion, tracy::BroadcastVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
|
||||
static bool GraphicsRunDebugDumpEnabled() {
|
||||
return Config::GraphicsDebugDumpEnabled() &&
|
||||
Config::GetPrintfDirection() != Config::OutputDirection::Silent;
|
||||
Config::GetPrintfDirection() != Config::LogDirection::Silent;
|
||||
}
|
||||
|
||||
GuestGpu::GuestGpu(RenderContext& renderer): m_renderer(renderer) {
|
||||
|
||||
@@ -56,7 +56,7 @@ uint32_t render_target_first_bound_slot(const CommandBuffer& buffer) {
|
||||
|
||||
bool graphics_debug_dump_enabled() {
|
||||
return Config::GraphicsDebugDumpEnabled() &&
|
||||
Config::GetPrintfDirection() != Config::OutputDirection::Silent;
|
||||
Config::GetPrintfDirection() != Config::LogDirection::Silent;
|
||||
}
|
||||
|
||||
void uc_print(const char* func, const HW::UserConfig& uc) {
|
||||
|
||||
@@ -334,7 +334,7 @@ struct PipelineCache::ProgramCache {
|
||||
options.shader_hash = params.hash;
|
||||
options.user_data = params.user_data;
|
||||
options.back_code = params.back_code;
|
||||
options.dump_ir = Config::GetShaderLogDirection() != Config::ShaderLogDirection::Silent;
|
||||
options.dump_ir = Config::GetShaderLogDirection() != Config::LogDirection::Silent;
|
||||
options.early_dump = options.dump_ir;
|
||||
options.dump_label = label;
|
||||
options.input_info = stage_input;
|
||||
|
||||
@@ -1152,7 +1152,7 @@ bool FlipQueue::Flip(uint32_t micros) {
|
||||
Graphics::RenderDocOnGuestFlip(m_presenter.Renderer());
|
||||
|
||||
if (Config::GraphicsDebugDumpEnabled() &&
|
||||
Config::GetPrintfDirection() != Config::OutputDirection::Silent) {
|
||||
Config::GetPrintfDirection() != Config::LogDirection::Silent) {
|
||||
LOGF("Flip done: %d\n", r.index);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ static void AppendInstructionWords(std::vector<uint32_t>& section, const uint32_
|
||||
if (words_num == 0) {
|
||||
return;
|
||||
}
|
||||
const auto opcode = words[0];
|
||||
const auto word_count = static_cast<uint32_t>(words_num);
|
||||
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);
|
||||
}
|
||||
@@ -38,7 +38,7 @@ void Builder::RequireVersion(uint32_t version) {
|
||||
|
||||
void Builder::RequireCapability(spv::Capability capability) {
|
||||
if (m_required_capabilities.insert(capability).second) {
|
||||
AppendInstruction(m_capabilities, spv::OpCapability, {capability});
|
||||
AppendInstruction(m_capabilities, spv::OpCapability, capability);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,37 +62,25 @@ uint32_t Builder::Import(const char* name) {
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::Type(spv::Op opcode, std::initializer_list<uint32_t> operands) {
|
||||
return Type(opcode, std::vector<uint32_t>(operands));
|
||||
}
|
||||
|
||||
uint32_t Builder::Type(spv::Op 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());
|
||||
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);
|
||||
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(spv::Op opcode, std::initializer_list<uint32_t> operands,
|
||||
std::initializer_list<TypeAnnotation> annotations) {
|
||||
uint32_t Builder::DeclareDecoratedType(spv::Op opcode, std::vector<uint32_t> key,
|
||||
std::initializer_list<TypeAnnotation> annotations) {
|
||||
if (annotations.size() == 0) {
|
||||
return Type(opcode, operands);
|
||||
return DeclareType(opcode, std::move(key));
|
||||
}
|
||||
std::vector<uint32_t> key {opcode, static_cast<uint32_t>(operands.size())};
|
||||
key.insert(key.end(), operands.begin(), operands.end());
|
||||
const auto operand_count = key[1];
|
||||
key.push_back(static_cast<uint32_t>(annotations.size()));
|
||||
for (const auto& annotation: annotations) {
|
||||
key.push_back(annotation.opcode);
|
||||
AppendOperand(key, annotation.opcode);
|
||||
key.push_back(static_cast<uint32_t>(annotation.operands.size()));
|
||||
key.insert(key.end(), annotation.operands.begin(), annotation.operands.end());
|
||||
}
|
||||
@@ -100,37 +88,23 @@ uint32_t Builder::DecoratedType(spv::Op opcode, std::initializer_list<uint32_t>
|
||||
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);
|
||||
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());
|
||||
AppendInstruction(m_annotations, annotation.opcode, id, annotation.operands);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t Builder::Constant(spv::Op opcode, uint32_t type,
|
||||
std::initializer_list<uint32_t> operands) {
|
||||
return Constant(opcode, type, std::vector<uint32_t>(operands));
|
||||
}
|
||||
|
||||
uint32_t Builder::Constant(spv::Op 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());
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -142,7 +116,7 @@ uint32_t Builder::DefineGlobalVariable(uint32_t pointer_type, spv::StorageClass
|
||||
|
||||
void Builder::DefineGlobalVariable(uint32_t id, uint32_t pointer_type,
|
||||
spv::StorageClass storage_class) {
|
||||
AppendInstruction(m_declarations, spv::OpVariable, {pointer_type, id, storage_class});
|
||||
AppendInstruction(m_declarations, spv::OpVariable, pointer_type, id, storage_class);
|
||||
}
|
||||
|
||||
void Builder::AppendString(std::vector<uint32_t>& words, const char* text) {
|
||||
@@ -161,27 +135,14 @@ void Builder::AppendString(std::vector<uint32_t>& words, const char* text) {
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::AppendInstruction(std::vector<uint32_t>& section, spv::Op opcode,
|
||||
const std::vector<uint32_t>& operands) {
|
||||
const uint32_t word_count = static_cast<uint32_t>(operands.size() + 1u);
|
||||
section.push_back((word_count << spv::WordCountShift) | opcode);
|
||||
section.insert(section.end(), operands.begin(), operands.end());
|
||||
}
|
||||
|
||||
void Builder::AppendInstruction(std::vector<uint32_t>& section, spv::Op opcode,
|
||||
std::initializer_list<uint32_t> operands) {
|
||||
const uint32_t word_count = static_cast<uint32_t>(operands.size() + 1u);
|
||||
section.push_back((word_count << spv::WordCountShift) | opcode);
|
||||
section.insert(section.end(), operands.begin(), operands.end());
|
||||
}
|
||||
|
||||
void Builder::AddMemoryModel(std::initializer_list<uint32_t> operands) {
|
||||
AppendInstruction(m_memory_model, spv::OpMemoryModel, operands);
|
||||
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 = {execution_model, entry_point};
|
||||
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) {
|
||||
@@ -199,25 +160,13 @@ void Builder::AddEntryPoint(spv::ExecutionModel execution_model, uint32_t entry_
|
||||
AppendInstruction(m_entry_points, spv::OpEntryPoint, operands);
|
||||
}
|
||||
|
||||
void Builder::AddExecutionMode(std::initializer_list<uint32_t> operands) {
|
||||
AppendInstruction(m_execution_modes, spv::OpExecutionMode, 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::AddAnnotation(std::initializer_list<uint32_t> words) {
|
||||
AppendInstructionWords(m_annotations, words.begin(), words.size());
|
||||
}
|
||||
|
||||
void Builder::AddFunction(std::initializer_list<uint32_t> words) {
|
||||
AppendInstructionWords(m_functions, words.begin(), words.size());
|
||||
}
|
||||
|
||||
void Builder::AddFunction(const std::vector<uint32_t>& words) {
|
||||
void Builder::AddFunction(std::span<const uint32_t> words) {
|
||||
AppendInstructionWords(m_functions, words.data(), words.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,21 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <spirv/unified1/spirv.hpp>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
|
||||
struct TypeAnnotation {
|
||||
spv::Op opcode = spv::OpNop;
|
||||
std::vector<uint32_t> operands;
|
||||
std::vector<uint32_t> operands; // Already encoded operand words.
|
||||
};
|
||||
|
||||
struct DeferredPhi {
|
||||
@@ -32,33 +36,109 @@ public:
|
||||
void RequireCapability(spv::Capability capability);
|
||||
void RequireExtension(const char* name);
|
||||
uint32_t Import(const char* name);
|
||||
uint32_t Type(spv::Op opcode, std::initializer_list<uint32_t> operands = {});
|
||||
uint32_t Type(spv::Op opcode, const std::vector<uint32_t>& operands);
|
||||
uint32_t DecoratedType(spv::Op opcode, std::initializer_list<uint32_t> operands,
|
||||
std::initializer_list<TypeAnnotation> annotations);
|
||||
uint32_t Constant(spv::Op opcode, uint32_t type, std::initializer_list<uint32_t> operands = {});
|
||||
uint32_t Constant(spv::Op opcode, uint32_t type, const std::vector<uint32_t>& operands);
|
||||
template <typename... Args>
|
||||
uint32_t Type(spv::Op opcode, const Args&... operands) {
|
||||
return DeclareType(opcode, MakeTypeKey(opcode, operands...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
uint32_t DecoratedType(spv::Op opcode, std::initializer_list<TypeAnnotation> annotations,
|
||||
const Args&... operands) {
|
||||
return DeclareDecoratedType(opcode, MakeTypeKey(opcode, operands...), annotations);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
uint32_t Constant(spv::Op opcode, uint32_t type, const Args&... operands) {
|
||||
std::vector<uint32_t> key;
|
||||
key.reserve(2u + (0u + ... + OperandWordCount(operands)));
|
||||
AppendOperands(key, opcode, type, operands...);
|
||||
return DeclareConstant(opcode, std::move(key));
|
||||
}
|
||||
|
||||
uint32_t DefineGlobalVariable(uint32_t pointer_type, spv::StorageClass storage_class);
|
||||
void DefineGlobalVariable(uint32_t id, uint32_t pointer_type, spv::StorageClass storage_class);
|
||||
|
||||
void AddMemoryModel(std::initializer_list<uint32_t> operands);
|
||||
void AddMemoryModel(spv::AddressingModel addressing_model, spv::MemoryModel memory_model);
|
||||
void AddEntryPoint(spv::ExecutionModel 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 AddFunction(std::initializer_list<uint32_t> words);
|
||||
void AddFunction(const std::vector<uint32_t>& words);
|
||||
template <typename... Args>
|
||||
void AddExecutionMode(uint32_t entry_point, spv::ExecutionMode mode, const Args&... operands) {
|
||||
AppendInstruction(m_execution_modes, spv::OpExecutionMode, entry_point, mode, operands...);
|
||||
}
|
||||
|
||||
void AddName(uint32_t target, const char* name);
|
||||
template <typename... Args>
|
||||
void AddAnnotation(spv::Op opcode, const Args&... operands) {
|
||||
AppendInstruction(m_annotations, opcode, operands...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void AddFunction(spv::Op opcode, const Args&... operands) {
|
||||
AppendInstruction(m_functions, opcode, operands...);
|
||||
}
|
||||
|
||||
void AddFunction(std::span<const uint32_t> words);
|
||||
DeferredPhi AddDeferredPhi(uint32_t type, uint32_t result, size_t incoming_count);
|
||||
void PatchDeferredPhi(DeferredPhi phi, size_t incoming, uint32_t value, uint32_t parent);
|
||||
|
||||
[[nodiscard]] std::vector<uint32_t> Build() const;
|
||||
|
||||
private:
|
||||
static void AppendOperand(std::vector<uint32_t>& words, uint32_t value) {
|
||||
words.push_back(value);
|
||||
}
|
||||
|
||||
static void AppendOperand(std::vector<uint32_t>& words, int32_t value) {
|
||||
words.push_back(static_cast<uint32_t>(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_enum_v<T>
|
||||
static void AppendOperand(std::vector<uint32_t>& words, T value) {
|
||||
static_assert(sizeof(T) == sizeof(uint32_t));
|
||||
words.push_back(static_cast<uint32_t>(value));
|
||||
}
|
||||
|
||||
static void AppendOperand(std::vector<uint32_t>& words, std::span<const uint32_t> values) {
|
||||
words.insert(words.end(), values.begin(), values.end());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void AppendOperands(std::vector<uint32_t>& words, const Args&... operands) {
|
||||
(AppendOperand(words, operands), ...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static size_t OperandWordCount(const T& operand) {
|
||||
if constexpr (std::is_integral_v<T> || std::is_enum_v<T>) {
|
||||
return 1;
|
||||
} else {
|
||||
return std::size(operand);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static std::vector<uint32_t> MakeTypeKey(spv::Op opcode, const Args&... operands) {
|
||||
const auto operand_count = static_cast<uint32_t>((0u + ... + OperandWordCount(operands)));
|
||||
std::vector<uint32_t> key;
|
||||
key.reserve(2u + operand_count);
|
||||
AppendOperands(key, opcode, operand_count, operands...);
|
||||
return key;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void AppendInstruction(std::vector<uint32_t>& section, spv::Op opcode,
|
||||
const std::vector<uint32_t>& operands);
|
||||
static void AppendInstruction(std::vector<uint32_t>& section, spv::Op opcode,
|
||||
std::initializer_list<uint32_t> operands);
|
||||
const Args&... operands) {
|
||||
const auto offset = section.size();
|
||||
AppendOperands(section, opcode, operands...);
|
||||
const auto word_count = static_cast<uint32_t>(section.size() - offset);
|
||||
section[offset] |= word_count << spv::WordCountShift;
|
||||
}
|
||||
|
||||
uint32_t DeclareType(spv::Op opcode, std::vector<uint32_t> key);
|
||||
uint32_t DeclareDecoratedType(spv::Op opcode, std::vector<uint32_t> key,
|
||||
std::initializer_list<TypeAnnotation> annotations);
|
||||
uint32_t DeclareConstant(spv::Op opcode, std::vector<uint32_t> key);
|
||||
static void AppendString(std::vector<uint32_t>& words, const char* text);
|
||||
|
||||
uint32_t m_next_id = 1;
|
||||
|
||||
@@ -12,14 +12,14 @@ struct Pair {
|
||||
|
||||
Pair ExtractPair(EmitterState& state, uint32_t value) {
|
||||
Pair result {state.builder.AllocateId(), state.builder.AllocateId()};
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), result.low, value, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), result.high, value, 1});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), result.low, value, 0);
|
||||
state.builder.AddFunction(spv::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({spv::OpCompositeConstruct, TypeU64(state), result, low, high});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeU64(state), result, low, high);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ uint32_t CompareEqual64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_va
|
||||
}
|
||||
|
||||
uint32_t CompareOrdered64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value,
|
||||
uint32_t high_compare, uint32_t low_compare) {
|
||||
spv::Op high_compare, spv::Op low_compare) {
|
||||
const auto lhs = ExtractPair(state, lhs_value);
|
||||
const auto rhs = ExtractPair(state, rhs_value);
|
||||
const auto high_equal = Binary(state, spv::OpIEqual, TypeBool(state), lhs.high, rhs.high);
|
||||
@@ -51,10 +51,10 @@ uint32_t EmitMulHigh(EmitterState& state, uint32_t lhs, uint32_t rhs, bool signe
|
||||
rhs_operand = Unary(state, spv::OpBitcast, TypeI32(state), rhs);
|
||||
}
|
||||
const auto extended = state.builder.AllocateId();
|
||||
state.builder.AddFunction({signed_value ? spv::OpSMulExtended : spv::OpUMulExtended, pair_type,
|
||||
extended, lhs_operand, rhs_operand});
|
||||
state.builder.AddFunction(signed_value ? spv::OpSMulExtended : spv::OpUMulExtended, pair_type,
|
||||
extended, lhs_operand, rhs_operand);
|
||||
const auto high = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, operand_type, high, extended, 1});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, operand_type, high, extended, 1);
|
||||
return signed_value ? Unary(state, spv::OpBitcast, TypeU32(state), high) : high;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ uint32_t EmitShift64(EmitterState& state, spv::Op opcode, uint32_t value, uint32
|
||||
Select(state, TypeU32(state), at_least_32, fill, high));
|
||||
}
|
||||
|
||||
uint32_t EmitConstantShift64(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t shift) {
|
||||
uint32_t EmitConstantShift64(EmitterState& state, spv::Op opcode, uint32_t value, uint32_t shift) {
|
||||
shift &= 63u;
|
||||
if (shift == 0u) {
|
||||
return value;
|
||||
@@ -173,10 +173,10 @@ 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({spv::OpConvertFToS, TypeI32(state), converted_i, trunc});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), converted_raw, converted_i});
|
||||
state.builder.AddFunction(spv::OpConvertFToS, TypeI32(state), converted_i, trunc);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), converted_raw, converted_i);
|
||||
} else {
|
||||
state.builder.AddFunction({spv::OpConvertFToU, TypeU32(state), converted_raw, trunc});
|
||||
state.builder.AddFunction(spv::OpConvertFToU, TypeU32(state), converted_raw, trunc);
|
||||
}
|
||||
const auto nan = EmitClassifyF32(state, src).nan;
|
||||
if (signed_value) {
|
||||
@@ -218,10 +218,10 @@ uint32_t EmitFindUMsb64(EmitterState& state, uint32_t value) {
|
||||
const auto pair = ExtractPair(state, value);
|
||||
const auto high_i = state.builder.AllocateId();
|
||||
const auto low_i = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpExtInst, TypeI32(state), high_i, GlslStd450(state), GLSLstd450FindUMsb, pair.high});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpExtInst, TypeI32(state), low_i, GlslStd450(state), GLSLstd450FindUMsb, pair.low});
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeI32(state), high_i, GlslStd450(state),
|
||||
GLSLstd450FindUMsb, pair.high);
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeI32(state), low_i, GlslStd450(state),
|
||||
GLSLstd450FindUMsb, pair.low);
|
||||
const auto high = Unary(state, spv::OpBitcast, TypeU32(state), high_i);
|
||||
const auto low = Unary(state, spv::OpBitcast, TypeU32(state), low_i);
|
||||
const auto high_nonzero =
|
||||
@@ -260,9 +260,9 @@ uint32_t EmitIAdd64(EmitterState& state, uint32_t lhs_value, uint32_t rhs_value)
|
||||
const auto low_pair = state.builder.AllocateId();
|
||||
const auto low = state.builder.AllocateId();
|
||||
const auto carry = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpIAddCarry, TypeU32Pair(state), low_pair, lhs.low, rhs.low});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), low, low_pair, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), carry, low_pair, 1});
|
||||
state.builder.AddFunction(spv::OpIAddCarry, TypeU32Pair(state), low_pair, lhs.low, rhs.low);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), low, low_pair, 0);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), carry, low_pair, 1);
|
||||
const auto high0 = Binary(state, spv::OpIAdd, TypeU32(state), lhs.high, rhs.high);
|
||||
const auto high = Binary(state, spv::OpIAdd, TypeU32(state), high0, carry);
|
||||
return MakePair(state, low, high);
|
||||
@@ -278,8 +278,8 @@ uint32_t EmitConvertU8U32(EmitterState& state, uint32_t arg0) {
|
||||
|
||||
uint32_t EmitConvertF16F32(EmitterState& state, uint32_t arg0) {
|
||||
const auto pair = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeF32Vector(state, 2), pair, arg0, ConstantF32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 2), pair, arg0,
|
||||
ConstantF32(state, 0));
|
||||
return EmitPackHalf2x16(state, pair);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,35 +4,35 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), ret, value, ConstantU32(state, mask)});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), ret, value,
|
||||
ConstantU32(state, mask));
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitShiftRightConstant(EmitterState& state, uint32_t value, uint32_t shift) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), ret, value, ConstantU32(state, shift)});
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), ret, value,
|
||||
ConstantU32(state, shift));
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value,
|
||||
uint32_t EmitCompareU32Constant(EmitterState& state, spv::Op opcode, uint32_t value,
|
||||
uint32_t constant) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, TypeBool(state), 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(
|
||||
{spv::OpISub, TypeU32(state), ret, ConstantU32(state, constant), value});
|
||||
state.builder.AddFunction(spv::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({spv::OpBitcast, TypeU32(state), bits, f32});
|
||||
state.builder.AddFunction(spv::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);
|
||||
@@ -43,13 +43,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(
|
||||
{spv::OpISub, TypeU32(state), half_exp, exp, ConstantU32(state, 112)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), normal_exp, half_exp, ConstantU32(state, 10)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseOr, TypeU32(state), normal_payload, normal_exp, normal_mant});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), normal, sign, normal_payload});
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), half_exp, exp, ConstantU32(state, 112));
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), normal_exp, half_exp,
|
||||
ConstantU32(state, 10));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), normal_payload, normal_exp,
|
||||
normal_mant);
|
||||
state.builder.AddFunction(spv::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);
|
||||
@@ -61,9 +60,9 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
EmitSelectValueU32(state, exp_gt_112, ConstantU32(state, 14), sub_shift_low);
|
||||
const auto sub_mant = state.builder.AllocateId();
|
||||
const auto subnormal = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), sub_mant, mant_with_hidden, sub_shift});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), subnormal, sign, sub_mant});
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), sub_mant, mant_with_hidden,
|
||||
sub_shift);
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), subnormal, sign, sub_mant);
|
||||
|
||||
const auto nan_payload =
|
||||
EmitOrU32(state, EmitShiftRightConstant(state, mant, 13), ConstantU32(state, 0x0200u));
|
||||
@@ -86,18 +85,18 @@ uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) {
|
||||
uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{max_value ? spv::OpUGreaterThan : spv::OpULessThan, TypeBool(state), cond, lhs, rhs});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs});
|
||||
state.builder.AddFunction(max_value ? spv::OpUGreaterThan : spv::OpULessThan, TypeBool(state),
|
||||
cond, lhs, rhs);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) {
|
||||
const auto cond = state.builder.AllocateId();
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{max_value ? spv::OpSGreaterThan : spv::OpSLessThan, TypeBool(state), cond, lhs, rhs});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs});
|
||||
state.builder.AddFunction(max_value ? spv::OpSGreaterThan : spv::OpSLessThan, TypeBool(state),
|
||||
cond, lhs, rhs);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), ret, cond, lhs, rhs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -184,8 +183,8 @@ 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 ? spv::OpFOrdGreaterThanEqual : spv::OpFOrdLessThan,
|
||||
TypeBool(state), numeric_cond, lhs, rhs});
|
||||
state.builder.AddFunction(max_value ? spv::OpFOrdGreaterThanEqual : spv::OpFOrdLessThan,
|
||||
TypeBool(state), numeric_cond, lhs, rhs);
|
||||
const auto ordered_bits =
|
||||
EmitSelectValueU32(state, numeric_cond, lhs_class.bits, rhs_class.bits);
|
||||
|
||||
@@ -209,18 +208,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({spv::OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), sign_bits, bits, ConstantU32(state, 0x80000000u)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), non_zero, abs_bits, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpULessThan, TypeBool(state), subnormal, abs_bits, ConstantU32(state, 0x00800000u)});
|
||||
state.builder.AddFunction({spv::OpLogicalAnd, TypeBool(state), flush, non_zero, subnormal});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), selected, flush, sign_bits, bits});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeF32(state), ret, selected});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), abs_bits, bits,
|
||||
ConstantU32(state, 0x7fffffffu));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), sign_bits, bits,
|
||||
ConstantU32(state, 0x80000000u));
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), non_zero, abs_bits,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), subnormal, abs_bits,
|
||||
ConstantU32(state, 0x00800000u));
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), flush, non_zero, subnormal);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), selected, flush, sign_bits, bits);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeF32(state), ret, selected);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -232,35 +231,35 @@ uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signe
|
||||
const auto finite = state.builder.AllocateId();
|
||||
const auto large_finite = state.builder.AllocateId();
|
||||
const auto reduced = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpExtInst, TypeF32(state), fract, GlslStd450(state), GLSLstd450Fract, src});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, src});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), abs_bits, bits, ConstantU32(state, 0x7fffffffu)});
|
||||
state.builder.AddFunction({spv::OpUGreaterThanEqual, TypeBool(state), large, abs_bits,
|
||||
ConstantU32(state, 0x4b000000u)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpULessThan, TypeBool(state), finite, abs_bits, ConstantU32(state, 0x7f800000u)});
|
||||
state.builder.AddFunction({spv::OpLogicalAnd, TypeBool(state), large_finite, large, finite});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeF32(state), reduced, large_finite, ConstantF32(state, 0), fract});
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeF32(state), fract, GlslStd450(state),
|
||||
GLSLstd450Fract, src);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, src);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), abs_bits, bits,
|
||||
ConstantU32(state, 0x7fffffffu));
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), large, abs_bits,
|
||||
ConstantU32(state, 0x4b000000u));
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), finite, abs_bits,
|
||||
ConstantU32(state, 0x7f800000u));
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), large_finite, large, finite);
|
||||
state.builder.AddFunction(spv::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(
|
||||
{spv::OpIEqual, TypeBool(state), zero, abs_bits, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeF32(state), ret, zero, src, reduced});
|
||||
state.builder.AddFunction(spv::OpIEqual, TypeBool(state), zero, abs_bits,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpSelect, TypeF32(state), ret, zero, src, reduced);
|
||||
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({spv::OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state),
|
||||
GLSLstd450UnpackHalf2x16, bits});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeF32(state), ret, unpacked, 0});
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state),
|
||||
GLSLstd450UnpackHalf2x16, bits);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeF32(state), ret, unpacked, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +82,8 @@ uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type,
|
||||
ExitDescriptorBindingFailure(state, kind, resource, variable_name);
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, result_ptr_type, pointer, variable_id,
|
||||
ConstantU32(state, array_index)});
|
||||
state.builder.AddFunction(spv::OpAccessChain, result_ptr_type, pointer, variable_id,
|
||||
ConstantU32(state, array_index));
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@@ -109,8 +109,7 @@ uint32_t ImageScalarType(EmitterState& state, Prospero::TextureNumericClass nume
|
||||
|
||||
uint32_t ImageVectorType(EmitterState& state, Prospero::TextureNumericClass numeric_class,
|
||||
uint32_t components) {
|
||||
return state.builder.Type(spv::OpTypeVector,
|
||||
{ImageScalarType(state, numeric_class), components});
|
||||
return state.builder.Type(spv::OpTypeVector, ImageScalarType(state, numeric_class), components);
|
||||
}
|
||||
|
||||
uint32_t ImageType(EmitterState& state, const IR::ImageResource& image) {
|
||||
@@ -131,10 +130,9 @@ uint32_t ImageType(EmitterState& state, const IR::ImageResource& image) {
|
||||
EXIT("invalid image resource class");
|
||||
}
|
||||
const auto& info = ImageDimensionInfoFor(image.dimension);
|
||||
return state.builder.Type(spv::OpTypeImage,
|
||||
{ImageScalarType(state, image.numeric_class), info.spirv_dimension,
|
||||
image.depth_compare ? 1u : 0u, info.arrayed, info.multisampled,
|
||||
sampled, format});
|
||||
return state.builder.Type(spv::OpTypeImage, ImageScalarType(state, image.numeric_class),
|
||||
info.spirv_dimension, image.depth_compare ? 1u : 0u, info.arrayed,
|
||||
info.multisampled, sampled, format);
|
||||
}
|
||||
|
||||
uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension) {
|
||||
@@ -154,12 +152,12 @@ uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource) {
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
const auto pointer_type = state.builder.Type(
|
||||
spv::OpTypePointer, {spv::StorageClassUniformConstant, ImageType(state, image_resource)});
|
||||
spv::OpTypePointer, spv::StorageClassUniformConstant, ImageType(state, image_resource));
|
||||
const auto pointer =
|
||||
DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"sampled image descriptor array was not emitted");
|
||||
const auto image = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, ImageType(state, image_resource), image, pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, ImageType(state, image_resource), image, pointer);
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -168,12 +166,12 @@ uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler) {
|
||||
ResourceForDescriptor(state, IR::DescriptorBindingKind::Samplers, sampler);
|
||||
const auto sampler_type = state.builder.Type(spv::OpTypeSampler);
|
||||
const auto pointer_type =
|
||||
state.builder.Type(spv::OpTypePointer, {spv::StorageClassUniformConstant, sampler_type});
|
||||
state.builder.Type(spv::OpTypePointer, spv::StorageClassUniformConstant, sampler_type);
|
||||
const auto pointer = DescriptorElementPointer(
|
||||
state, pointer_type, state.sampler_variable, array_index,
|
||||
IR::DescriptorBindingKind::Samplers, sampler, "sampler descriptor array was not emitted");
|
||||
const auto sampler_id = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, sampler_type, sampler_id, pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, sampler_type, sampler_id, pointer);
|
||||
return sampler_id;
|
||||
}
|
||||
|
||||
@@ -183,9 +181,8 @@ uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampl
|
||||
const auto sampler_id = LoadSamplerDescriptor(state, sampler);
|
||||
const auto sampled_image = state.builder.AllocateId();
|
||||
const auto sampled_type =
|
||||
state.builder.Type(spv::OpTypeSampledImage, {ImageType(state, image_resource)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSampledImage, sampled_type, sampled_image, image, sampler_id});
|
||||
state.builder.Type(spv::OpTypeSampledImage, ImageType(state, image_resource));
|
||||
state.builder.AddFunction(spv::OpSampledImage, sampled_type, sampled_image, image, sampler_id);
|
||||
return sampled_image;
|
||||
}
|
||||
|
||||
@@ -194,9 +191,9 @@ uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) {
|
||||
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||
const auto kind = IR::DescriptorBindingForImage(image);
|
||||
EXIT_IF(!kind.has_value());
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto pointer_type = state.builder.Type(
|
||||
spv::OpTypePointer, {spv::StorageClassUniformConstant, ImageType(state, image)});
|
||||
spv::OpTypePointer, spv::StorageClassUniformConstant, ImageType(state, image));
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
return DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"storage image descriptor array was not emitted");
|
||||
@@ -214,18 +211,18 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto image_type = ImageType(state, image);
|
||||
const auto pointer_type =
|
||||
state.builder.Type(spv::OpTypePointer, {spv::StorageClassUniformConstant, image_type});
|
||||
state.builder.Type(spv::OpTypePointer, spv::StorageClassUniformConstant, image_type);
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
const auto LoadAt = [&](uint32_t array_index) {
|
||||
const auto pointer =
|
||||
DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"storage image descriptor array was not emitted");
|
||||
const auto descriptor = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, image_type, descriptor, pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, image_type, descriptor, pointer);
|
||||
return descriptor;
|
||||
};
|
||||
if (image.mip_mode != IR::ImageMipMode::DynamicStorage) {
|
||||
state.builder.AddFunction({spv::OpImageWrite, LoadAt(array_index), coord, texel});
|
||||
state.builder.AddFunction(spv::OpImageWrite, LoadAt(array_index), coord, texel);
|
||||
return;
|
||||
}
|
||||
if (image.mip_count == 0u) {
|
||||
@@ -241,12 +238,12 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_
|
||||
words.push_back(mip);
|
||||
words.push_back(labels[mip]);
|
||||
}
|
||||
state.builder.AddFunction({spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(words);
|
||||
for (uint32_t mip = 0; mip < image.mip_count; mip++) {
|
||||
EmitLabel(state, labels[mip]);
|
||||
state.builder.AddFunction({spv::OpImageWrite, LoadAt(array_index + mip), coord, texel});
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpImageWrite, LoadAt(array_index + mip), coord, texel);
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
}
|
||||
EmitLabel(state, merge_label);
|
||||
}
|
||||
|
||||
@@ -45,28 +45,28 @@ uint32_t EmitBuiltinU32(EmitterState& state, IR::StageInputKind kind, uint32_t c
|
||||
if (kind == IR::StageInputKind::FrontFacing) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeBool(state), value, variable});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), bits, value,
|
||||
ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeBool(state), value, variable);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), bits, value, ConstantU32(state, 1),
|
||||
ConstantU32(state, 0));
|
||||
return bits;
|
||||
}
|
||||
if (kind == IR::StageInputKind::VertexIndex || kind == IR::StageInputKind::InstanceIndex ||
|
||||
kind == IR::StageInputKind::Layer || kind == IR::StageInputKind::SampleId) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeI32(state), value, variable});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeI32(state), value, variable);
|
||||
state.builder.AddFunction(spv::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({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32(state), value, pointer});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, component));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32(state), value, pointer);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value);
|
||||
return bits;
|
||||
}
|
||||
if (kind == IR::StageInputKind::BaryCoordSmooth ||
|
||||
@@ -74,11 +74,11 @@ uint32_t EmitBuiltinU32(EmitterState& state, IR::StageInputKind kind, uint32_t c
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, component + 1u)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32(state), value, pointer});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, component + 1u));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32(state), value, pointer);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value);
|
||||
return bits;
|
||||
}
|
||||
return EmitInputComponentU32(state, kind, component);
|
||||
@@ -99,37 +99,37 @@ uint32_t EmitDppWriteCondition(ValueEmitContext& ctx, const IR::DppMoveFlags& fl
|
||||
const auto bank_ok = state.builder.AllocateId();
|
||||
const auto row_ok = state.builder.AllocateId();
|
||||
const auto masks_ok = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), bank_shift, lane, ConstantU32(state, 2)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), row_shift, lane, ConstantU32(state, 4)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), bank, bank_shift, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), row, row_shift, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), bank_bit, ConstantU32(state, 1), bank});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), row_bit, ConstantU32(state, 1), row});
|
||||
state.builder.AddFunction({spv::OpBitwiseAnd, TypeU32(state), bank_hit,
|
||||
ConstantU32(state, flags.bank_mask), bank_bit});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), row_hit, ConstantU32(state, flags.row_mask), row_bit});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), bank_ok, bank_hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), row_ok, row_hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpLogicalAnd, TypeBool(state), masks_ok, bank_ok, row_ok});
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), bank_shift, lane,
|
||||
ConstantU32(state, 2));
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), row_shift, lane,
|
||||
ConstantU32(state, 4));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), bank, bank_shift,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, row_shift,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), bank_bit,
|
||||
ConstantU32(state, 1), bank);
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), row_bit,
|
||||
ConstantU32(state, 1), row);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), bank_hit,
|
||||
ConstantU32(state, flags.bank_mask), bank_bit);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row_hit,
|
||||
ConstantU32(state, flags.row_mask), row_bit);
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), bank_ok, bank_hit,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), row_ok, row_hit,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::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(
|
||||
{spv::OpLogicalAnd, TypeBool(state), bounded, writable, target.valid});
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), bounded, writable,
|
||||
target.valid);
|
||||
writable = bounded;
|
||||
}
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLogicalAnd, TypeBool(state), result, exec, writable});
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), result, exec, writable);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -144,11 +144,10 @@ uint32_t EmitAttribute(EmitterState& state, uint32_t attr, uint32_t chan) {
|
||||
const auto load_per_vertex = [&](uint32_t vertex) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, input->variable_id, ConstantU32(state, vertex),
|
||||
ConstantU32(state, chan & 3u)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32(state), value, pointer});
|
||||
state.builder.AddFunction(
|
||||
spv::OpAccessChain, TypePointer(state, spv::StorageClassInput, TypeF32(state)), pointer,
|
||||
input->variable_id, ConstantU32(state, vertex), ConstantU32(state, chan & 3u));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32(state), value, pointer);
|
||||
return value;
|
||||
};
|
||||
if (input->per_vertex) {
|
||||
@@ -161,31 +160,31 @@ uint32_t EmitAttribute(EmitterState& state, uint32_t attr, uint32_t chan) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto weight = state.builder.AllocateId();
|
||||
const auto product = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, barycentric, ConstantU32(state, vertex)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32(state), weight, pointer});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFMul, TypeF32(state), product, load_per_vertex(vertex), weight});
|
||||
state.builder.AddFunction(spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, barycentric, ConstantU32(state, vertex));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32(state), weight, pointer);
|
||||
state.builder.AddFunction(spv::OpFMul, TypeF32(state), product, load_per_vertex(vertex),
|
||||
weight);
|
||||
if (vertex == 0u) {
|
||||
sum = product;
|
||||
} else {
|
||||
const auto next = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpFAdd, TypeF32(state), next, sum, product});
|
||||
state.builder.AddFunction(spv::OpFAdd, TypeF32(state), next, sum, product);
|
||||
sum = next;
|
||||
}
|
||||
}
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, sum});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, sum);
|
||||
return bits;
|
||||
}
|
||||
const auto vector = state.builder.AllocateId();
|
||||
const auto component = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32Vector(state, 4), vector, input->variable_id});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeF32(state), component, vector, chan & 3u});
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, component});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32Vector(state, 4), vector, input->variable_id);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeF32(state), component, vector,
|
||||
chan & 3u);
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, component);
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -199,11 +198,10 @@ uint32_t EmitInterpolationParameter(ValueEmitContext& ctx, uint32_t attr, uint32
|
||||
const auto load_vertex = [&](uint32_t vertex) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeF32(state)),
|
||||
pointer, input->variable_id, ConstantU32(state, vertex),
|
||||
ConstantU32(state, chan & 3u)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeF32(state), value, pointer});
|
||||
state.builder.AddFunction(
|
||||
spv::OpAccessChain, TypePointer(state, spv::StorageClassInput, TypeF32(state)), pointer,
|
||||
input->variable_id, ConstantU32(state, vertex), ConstantU32(state, chan & 3u));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeF32(state), value, pointer);
|
||||
return value;
|
||||
};
|
||||
|
||||
@@ -211,11 +209,11 @@ uint32_t EmitInterpolationParameter(ValueEmitContext& ctx, uint32_t attr, uint32
|
||||
uint32_t value = load_vertex(selected_vertex);
|
||||
if (!PixelParameterIsCustom(state, attr) && mode < 2u) {
|
||||
const auto delta = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpFSub, TypeF32(state), delta, value, load_vertex(0)});
|
||||
state.builder.AddFunction(spv::OpFSub, TypeF32(state), delta, value, load_vertex(0));
|
||||
value = delta;
|
||||
}
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, value});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value);
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -229,8 +227,8 @@ uint32_t MrtOutputMode(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(
|
||||
{spv::OpCompositeExtract, TypeU32(ctx.state), value, vector, component});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), value, vector,
|
||||
component);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -248,22 +246,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(
|
||||
{spv::OpCompositeExtract, TypeU32(state), packed, data, pair});
|
||||
state.builder.AddFunction({spv::OpExtInst, TypeF32Vector(state, 2), unpacked,
|
||||
GlslStd450(state), unpack, packed});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), packed, data, pair);
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeF32Vector(state, 2), unpacked,
|
||||
GlslStd450(state), unpack, 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(
|
||||
{spv::OpCompositeExtract, TypeF32(state), f32[component], unpacked, lane});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeF32(state),
|
||||
f32[component], unpacked, lane);
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeF32Vector(state, 4), vector,
|
||||
f32[0], f32[1], f32[2], f32[3]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 4), vector,
|
||||
f32[0], f32[1], f32[2], f32[3]);
|
||||
return vector;
|
||||
}
|
||||
uint32_t raw[4] = {
|
||||
@@ -284,9 +281,9 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
||||
continue;
|
||||
}
|
||||
raw[component] = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitFieldUExtract, TypeU32(state), raw[component],
|
||||
packed, ConstantU32(state, lane * 16u),
|
||||
ConstantU32(state, 16)});
|
||||
state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(state), raw[component],
|
||||
packed, ConstantU32(state, lane * 16u),
|
||||
ConstantU32(state, 16));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -298,18 +295,18 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
||||
}
|
||||
if (uint_output) {
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(state, 4), vector,
|
||||
raw[0], raw[1], raw[2], raw[3]});
|
||||
state.builder.AddFunction(spv::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({spv::OpBitcast, TypeF32(state), f32[component], raw[component]});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeF32(state), f32[component], raw[component]);
|
||||
}
|
||||
const auto vector = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeF32Vector(state, 4), vector, f32[0],
|
||||
f32[1], f32[2], f32[3]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 4), vector, f32[0],
|
||||
f32[1], f32[2], f32[3]);
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -325,19 +322,19 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
|
||||
const auto raw = ExportRawComponent(ctx, data, component);
|
||||
if (output.layer) {
|
||||
const auto layer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), layer, raw, ConstantU32(state, 0x7ffu)});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), layer, raw,
|
||||
ConstantU32(state, 0x7ffu));
|
||||
const auto pointer = state.program.stage == ShaderType::Mesh
|
||||
? MeshOutputPointer(state, IR::StageOutputKind::Layer)
|
||||
: state.layer_variable;
|
||||
state.builder.AddFunction({spv::OpStore, pointer, layer});
|
||||
state.builder.AddFunction(spv::OpStore, pointer, layer);
|
||||
}
|
||||
if (output.viewport) {
|
||||
// GFX10 MISC.z packs the viewport index in bits 16..19 alongside the layer.
|
||||
const auto viewport = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitFieldUExtract, TypeU32(state), viewport, raw,
|
||||
ConstantU32(state, 16), ConstantU32(state, 4)});
|
||||
state.builder.AddFunction({spv::OpStore, state.viewport_index_variable, viewport});
|
||||
state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(state), viewport, raw,
|
||||
ConstantU32(state, 16), ConstantU32(state, 4));
|
||||
state.builder.AddFunction(spv::OpStore, state.viewport_index_variable, viewport);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -348,9 +345,9 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
|
||||
|
||||
const auto raw = ExportRawComponent(ctx, data, component);
|
||||
const auto f32 = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeF32(state), f32, raw});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeF32(state), f32, raw);
|
||||
if (output.point_size) {
|
||||
state.builder.AddFunction({spv::OpStore, state.point_size_variable, f32});
|
||||
state.builder.AddFunction(spv::OpStore, state.point_size_variable, f32);
|
||||
continue;
|
||||
}
|
||||
auto StoreDistance = [&](uint32_t variable, uint32_t index) {
|
||||
@@ -358,10 +355,10 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
|
||||
return;
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, index)});
|
||||
state.builder.AddFunction({spv::OpStore, pointer, f32});
|
||||
state.builder.AddFunction(spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeF32(state)),
|
||||
pointer, variable, ConstantU32(state, index));
|
||||
state.builder.AddFunction(spv::OpStore, pointer, f32);
|
||||
};
|
||||
StoreDistance(state.clip_distance_variable, output.clip_distance);
|
||||
StoreDistance(state.cull_distance_variable, output.cull_distance);
|
||||
@@ -374,14 +371,14 @@ uint32_t ConvertClipCoordinate(EmitterState& state, uint32_t coordinate, float s
|
||||
const auto biased = state.builder.AllocateId();
|
||||
const auto divided = state.builder.AllocateId();
|
||||
const auto ndc = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFMul, TypeF32(state), window, coordinate, ConstantF32Value(state, scale)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFAdd, TypeF32(state), biased, window, ConstantF32Value(state, offset)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFDiv, TypeF32(state), divided, biased, ConstantF32Value(state, half_extent)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFSub, TypeF32(state), ndc, divided, ConstantF32Value(state, 1.0f)});
|
||||
state.builder.AddFunction(spv::OpFMul, TypeF32(state), window, coordinate,
|
||||
ConstantF32Value(state, scale));
|
||||
state.builder.AddFunction(spv::OpFAdd, TypeF32(state), biased, window,
|
||||
ConstantF32Value(state, offset));
|
||||
state.builder.AddFunction(spv::OpFDiv, TypeF32(state), divided, biased,
|
||||
ConstantF32Value(state, half_extent));
|
||||
state.builder.AddFunction(spv::OpFSub, TypeF32(state), ndc, divided,
|
||||
ConstantF32Value(state, 1.0f));
|
||||
return ndc;
|
||||
}
|
||||
|
||||
@@ -390,16 +387,16 @@ uint32_t ConvertPositionToClipSpace(EmitterState& state, uint32_t position) {
|
||||
uint32_t components[4] {};
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
components[i] = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeF32(state), components[i], position, i});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeF32(state), components[i], position,
|
||||
i);
|
||||
}
|
||||
components[0] = ConvertClipCoordinate(state, components[0], transform.scale[0],
|
||||
transform.offset[0], transform.half_extent[0]);
|
||||
components[1] = ConvertClipCoordinate(state, components[1], transform.scale[1],
|
||||
transform.offset[1], transform.half_extent[1]);
|
||||
const auto converted = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeF32Vector(state, 4), converted,
|
||||
components[0], components[1], components[2], components[3]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 4), converted,
|
||||
components[0], components[1], components[2], components[3]);
|
||||
return converted;
|
||||
}
|
||||
|
||||
@@ -411,17 +408,17 @@ uint32_t EmitWqmU64(EmitterState& state, uint32_t value) {
|
||||
const auto merged_two = state.builder.AllocateId();
|
||||
const auto quad_bits = state.builder.AllocateId();
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpShiftRightLogical, TypeU64(state), shifted_one, value,
|
||||
ConstantU64(state, 0x0000000100000001ull)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU64(state), merged_one, value, shifted_one});
|
||||
state.builder.AddFunction({spv::OpShiftRightLogical, TypeU64(state), shifted_two, merged_one,
|
||||
ConstantU64(state, 0x0000000200000002ull)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseOr, TypeU64(state), merged_two, merged_one, shifted_two});
|
||||
state.builder.AddFunction({spv::OpBitwiseAnd, TypeU64(state), quad_bits, merged_two,
|
||||
ConstantU64(state, 0x1111111111111111ull)});
|
||||
state.builder.AddFunction({spv::OpIMul, TypeU64(state), result, quad_bits,
|
||||
ConstantU64(state, 0x0000000f0000000full)});
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU64(state), shifted_one, value,
|
||||
ConstantU64(state, 0x0000000100000001ull));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU64(state), merged_one, value, shifted_one);
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU64(state), shifted_two, merged_one,
|
||||
ConstantU64(state, 0x0000000200000002ull));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU64(state), merged_two, merged_one,
|
||||
shifted_two);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU64(state), quad_bits, merged_two,
|
||||
ConstantU64(state, 0x1111111111111111ull));
|
||||
state.builder.AddFunction(spv::OpIMul, TypeU64(state), result, quad_bits,
|
||||
ConstantU64(state, 0x0000000f0000000full));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -432,9 +429,9 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
if (state.program.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({spv::OpSelect, TypeU32(state), value, exec,
|
||||
ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpStore, state.pixel_valid_mask_variable, value});
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), value, exec, ConstantU32(state, 1),
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpStore, state.pixel_valid_mask_variable, value);
|
||||
}
|
||||
if (exp.kind == IR::ExportTargetKind::Null || exp.en == 0u) {
|
||||
return;
|
||||
@@ -443,8 +440,8 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto data = ctx.Arg(inst, 0);
|
||||
if (exp.kind == IR::ExportTargetKind::Primitive) {
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpStore, MeshPrimitivePointer(state), ExportRawComponent(ctx, data, 0)});
|
||||
state.builder.AddFunction(spv::OpStore, MeshPrimitivePointer(state),
|
||||
ExportRawComponent(ctx, data, 0));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -456,19 +453,18 @@ void EmitSetAttribute(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({spv::OpBitcast, TypeF32(state), f32, raw});
|
||||
state.builder.AddFunction({spv::OpStore, state.depth_variable, f32});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeF32(state), f32, raw);
|
||||
state.builder.AddFunction(spv::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({spv::OpBitcast, TypeI32(state), value, raw});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeI32(state), value, raw);
|
||||
state.builder.AddFunction(
|
||||
{spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeI32(state)), pointer,
|
||||
state.sample_mask_variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpStore, pointer, value});
|
||||
spv::OpAccessChain, TypePointer(state, spv::StorageClassOutput, TypeI32(state)),
|
||||
pointer, state.sample_mask_variable, ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpStore, pointer, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -485,9 +481,9 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto mapping = state.input_info.pixel->target_export_mapping[exp.index];
|
||||
if (!mapping.IsIdentity()) {
|
||||
const auto mapped = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpVectorShuffle, vector_type, mapped, value, value,
|
||||
mapping.Map(0), mapping.Map(1), mapping.Map(2),
|
||||
mapping.Map(3)});
|
||||
state.builder.AddFunction(spv::OpVectorShuffle, vector_type, mapped, value, value,
|
||||
mapping.Map(0), mapping.Map(1), mapping.Map(2),
|
||||
mapping.Map(3));
|
||||
value = mapped;
|
||||
}
|
||||
}
|
||||
@@ -499,17 +495,17 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto kind = exp.kind == IR::ExportTargetKind::Position
|
||||
? IR::StageOutputKind::Position
|
||||
: IR::StageOutputKind::Parameter;
|
||||
state.builder.AddFunction(
|
||||
{spv::OpStore, MeshOutputPointer(state, kind, exp.index), value});
|
||||
state.builder.AddFunction(spv::OpStore, MeshOutputPointer(state, kind, exp.index),
|
||||
value);
|
||||
} else if (exp.kind == IR::ExportTargetKind::Position) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeF32Vector(state, 4)), pointer,
|
||||
variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpStore, pointer, value});
|
||||
spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassOutput, TypeF32Vector(state, 4)), pointer,
|
||||
variable, ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpStore, pointer, value);
|
||||
} else {
|
||||
state.builder.AddFunction({spv::OpStore, variable, value});
|
||||
state.builder.AddFunction(spv::OpStore, variable, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -523,9 +519,9 @@ void EmitVoid(ValueEmitContext&) {}
|
||||
void EmitBarrier(EmitterState& state) {
|
||||
const auto semantics =
|
||||
spv::MemorySemanticsAcquireReleaseMask | spv::MemorySemanticsWorkgroupMemoryMask;
|
||||
state.builder.AddFunction({spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, semantics)});
|
||||
state.builder.AddFunction(spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, semantics));
|
||||
}
|
||||
|
||||
uint32_t EmitMeshDrawParameter(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
@@ -536,10 +532,10 @@ uint32_t EmitMeshDrawParameter(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Fail(inst, "invalid mesh draw parameter");
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypePushConstantElementPointer(state), pointer,
|
||||
state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, index)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), result, pointer});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypePushConstantElementPointer(state), pointer,
|
||||
state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, index));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), result, pointer);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -559,7 +555,7 @@ uint32_t EmitGetBuiltin(ValueEmitContext& ctx, IR::Value kind, IR::Value index)
|
||||
|
||||
uint32_t EmitUndefU1(EmitterState& state, const IR::Inst& inst) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpUndef, TypeId(state, inst.GetType()), result});
|
||||
state.builder.AddFunction(spv::OpUndef, TypeId(state, inst.GetType()), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -574,8 +570,8 @@ uint32_t EmitDppMoveU32(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto ballot = ctx.Ballot(inst.Arg(1));
|
||||
const auto source_active = EmitBallotLaneActiveBool(state, ballot, target.lane);
|
||||
const auto can_fetch = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpLogicalAnd, TypeBool(state), can_fetch, target.valid, source_active});
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), can_fetch, target.valid,
|
||||
source_active);
|
||||
return EmitNative<spv::OpSelect, IR::Type::U32>(ctx.state, can_fetch, shuffled,
|
||||
ConstantU32(state, 0));
|
||||
}
|
||||
@@ -604,8 +600,8 @@ uint32_t EmitReadLane(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
uint32_t EmitWriteLane(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
const auto hit = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpIEqual, TypeBool(state), hit,
|
||||
EmitSubgroupLocalInvocationId(state), ctx.Arg(inst, 2)});
|
||||
state.builder.AddFunction(spv::OpIEqual, TypeBool(state), hit,
|
||||
EmitSubgroupLocalInvocationId(state), ctx.Arg(inst, 2));
|
||||
return EmitNative<spv::OpSelect, IR::Type::U32>(ctx.state, hit, ctx.Arg(inst, 1),
|
||||
ctx.Arg(inst, 0));
|
||||
}
|
||||
@@ -624,35 +620,35 @@ uint32_t EmitPermlane16U32(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto shifted = state.builder.AllocateId();
|
||||
const auto index = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, subid,
|
||||
ConstantU32(state, 0xfffffff0u));
|
||||
if (flags.x16) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseXor, TypeU32(state), row_value, row, ConstantU32(state, 16)});
|
||||
state.builder.AddFunction(spv::OpBitwiseXor, TypeU32(state), row_value, row,
|
||||
ConstantU32(state, 16));
|
||||
} else {
|
||||
state.builder.AddFunction({spv::OpCopyObject, TypeU32(state), row_value, row});
|
||||
state.builder.AddFunction(spv::OpCopyObject, TypeU32(state), row_value, row);
|
||||
}
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane8, lane, ConstantU32(state, 7)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), shift, lane8, ConstantU32(state, 2)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpUGreaterThanEqual, TypeBool(state), upper, lane, ConstantU32(state, 8)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), selected, upper, ctx.Arg(inst, 2), ctx.Arg(inst, 1)});
|
||||
state.builder.AddFunction({spv::OpShiftRightLogical, TypeU32(state), shifted, selected, shift});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), index, shifted, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, row_value, index});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 15));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane8, lane,
|
||||
ConstantU32(state, 7));
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), shift, lane8,
|
||||
ConstantU32(state, 2));
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), upper, lane,
|
||||
ConstantU32(state, 8));
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), selected, upper, ctx.Arg(inst, 2),
|
||||
ctx.Arg(inst, 1));
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), shifted, selected, shift);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), index, shifted,
|
||||
ConstantU32(state, 15));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, row_value, index);
|
||||
const auto shuffled = ctx.Shuffle(inst, 0, target);
|
||||
uint32_t result = shuffled;
|
||||
if (!flags.fetch_inactive) {
|
||||
const auto source_exec = ctx.Shuffle(inst, 3, target);
|
||||
result = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), result, source_exec, shuffled, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), result, source_exec, shuffled,
|
||||
ConstantU32(state, 0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -9,17 +9,17 @@ DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto selected0 = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), quad_base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), shift, lane, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), selected0, ConstantU32(state, control), shift});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), selected, selected0, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, quad_base, selected});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), quad_base, subid,
|
||||
ConstantU32(state, 0xfffffffcu));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), shift, lane,
|
||||
ConstantU32(state, 1));
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), selected0,
|
||||
ConstantU32(state, control), shift);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), selected, selected0,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, quad_base, selected);
|
||||
return {target, ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
@@ -30,22 +30,22 @@ DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
const auto lane_shifted = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
const auto valid = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, subid,
|
||||
ConstantU32(state, 0xfffffff0u));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 15));
|
||||
if (left) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpIAdd, TypeU32(state), lane_shifted, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpULessThan, TypeBool(state), valid, lane, ConstantU32(state, 16u - amount)});
|
||||
state.builder.AddFunction(spv::OpIAdd, TypeU32(state), lane_shifted, lane,
|
||||
ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), valid, lane,
|
||||
ConstantU32(state, 16u - amount));
|
||||
} else {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpISub, TypeU32(state), lane_shifted, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpUGreaterThanEqual, TypeBool(state), valid, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), lane_shifted, lane,
|
||||
ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), valid, lane,
|
||||
ConstantU32(state, amount));
|
||||
}
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, row, lane_shifted});
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, row, lane_shifted);
|
||||
return {target, valid};
|
||||
}
|
||||
|
||||
@@ -58,18 +58,17 @@ DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subi
|
||||
const auto plus = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), row, subid, ConstantU32(state, 0xfffffff0u)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 15)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpUGreaterThanEqual, TypeBool(state), in_high, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpISub, TypeU32(state), minus, lane, ConstantU32(state, amount)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpIAdd, TypeU32(state), plus, lane, ConstantU32(state, 16u - amount)});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), selected, in_high, minus, plus});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, row, selected});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, subid,
|
||||
ConstantU32(state, 0xfffffff0u));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 15));
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), in_high, lane,
|
||||
ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), minus, lane, ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpIAdd, TypeU32(state), plus, lane,
|
||||
ConstantU32(state, 16u - amount));
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), selected, in_high, minus, plus);
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, row, selected);
|
||||
return {target, ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
@@ -80,13 +79,13 @@ DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto mirrored = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, base_mask)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, lane_mask)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpISub, TypeU32(state), mirrored, ConstantU32(state, lane_mask), lane});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, base, mirrored});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), base, subid,
|
||||
ConstantU32(state, base_mask));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, lane_mask));
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), mirrored, ConstantU32(state, lane_mask),
|
||||
lane);
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, base, mirrored);
|
||||
return {target, ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
@@ -112,8 +111,8 @@ DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control) {
|
||||
}
|
||||
if (control >= 0x160u && control <= 0x16fu) {
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseXor, TypeU32(state), target, subid, ConstantU32(state, control & 0xfu)});
|
||||
state.builder.AddFunction(spv::OpBitwiseXor, TypeU32(state), target, subid,
|
||||
ConstantU32(state, control & 0xfu));
|
||||
return {target, ConstantBool(state, true)};
|
||||
}
|
||||
return {subid, ConstantBool(state, true)};
|
||||
@@ -124,8 +123,8 @@ uint32_t EmitSubgroupLocalInvocationId(EmitterState& state) {
|
||||
EXIT("SubgroupLocalInvocationId was not declared before SPIR-V function emission\n");
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpLoad, TypeU32(state), value, state.subgroup_local_invocation_id_variable});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value,
|
||||
state.subgroup_local_invocation_id_variable);
|
||||
return state.lane_half == 0 ? value : EmitAddU32(state, value, ConstantU32(state, 32));
|
||||
}
|
||||
|
||||
@@ -154,10 +153,10 @@ uint32_t EmitInputComponentU32(EmitterState& state, IR::StageInputKind kind, uin
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeU32(state)), pointer,
|
||||
variable, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer});
|
||||
state.builder.AddFunction(spv::OpAccessChain,
|
||||
TypePointer(state, spv::StorageClassInput, TypeU32(state)), pointer,
|
||||
variable, ConstantU32(state, component));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -167,7 +166,7 @@ uint32_t EmitLocalInvocationIndex(EmitterState& state) {
|
||||
return ConstantU32(state, 0);
|
||||
}
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, variable});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, variable);
|
||||
if (state.lane_count == 2) {
|
||||
const auto wave_base =
|
||||
EmitBinaryU32(state, spv::OpBitwiseAnd, value, ConstantU32(state, ~31u));
|
||||
@@ -184,13 +183,13 @@ uint32_t EmitVertexParameterComponentU32(EmitterState& state, const InputBinding
|
||||
const auto scalar_type = VertexParameterScalarType(state, kind);
|
||||
uint32_t raw = state.builder.AllocateId();
|
||||
if (count == 1u) {
|
||||
state.builder.AddFunction({spv::OpLoad, scalar_type, raw, input.variable_id});
|
||||
state.builder.AddFunction(spv::OpLoad, scalar_type, raw, input.variable_id);
|
||||
} else {
|
||||
const auto pointer_type = TypePointer(state, spv::StorageClassInput, scalar_type);
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, pointer_type, pointer, input.variable_id,
|
||||
ConstantU32(state, component)});
|
||||
state.builder.AddFunction({spv::OpLoad, scalar_type, raw, pointer});
|
||||
state.builder.AddFunction(spv::OpAccessChain, pointer_type, pointer, input.variable_id,
|
||||
ConstantU32(state, component));
|
||||
state.builder.AddFunction(spv::OpLoad, scalar_type, raw, pointer);
|
||||
}
|
||||
|
||||
if (kind == VertexInputScalarKind::Uint) {
|
||||
@@ -198,49 +197,48 @@ uint32_t EmitVertexParameterComponentU32(EmitterState& state, const InputBinding
|
||||
}
|
||||
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeU32(state), bits, raw});
|
||||
state.builder.AddFunction(spv::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({spv::OpGroupNonUniformBallot, TypeU32Vector(state, 4), active_ballot,
|
||||
ConstantU32(state, spv::ScopeSubgroup), ConstantBool(state, true)});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformBallot, TypeU32Vector(state, 4), active_ballot,
|
||||
ConstantU32(state, spv::ScopeSubgroup), ConstantBool(state, true));
|
||||
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({spv::OpCompositeExtract, TypeU32(state), low, active_ballot, 0});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), low, active_ballot, 0);
|
||||
uint32_t mask = low;
|
||||
if (state.program.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(
|
||||
{spv::OpCompositeExtract, TypeU32(state), high, active_ballot, 1});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpUGreaterThanEqual, TypeBool(state), in_high, lane, ConstantU32(state, 32)});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), selected, in_high, high, low});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), high, active_ballot, 1);
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), in_high, lane,
|
||||
ConstantU32(state, 32));
|
||||
state.builder.AddFunction(spv::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(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane_low, lane, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), bit, ConstantU32(state, 1), lane_low});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane_low, lane,
|
||||
ConstantU32(state, 31));
|
||||
state.builder.AddFunction(spv::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({spv::OpBitwiseAnd, TypeU32(state), hit, mask, bit});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), active, hit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpULessThan, TypeBool(state), in_range, lane,
|
||||
ConstantU32(state, state.program.wave_size)});
|
||||
state.builder.AddFunction({spv::OpLogicalAnd, TypeBool(state), ret, active, in_range});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), hit, mask, bit);
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), active, hit,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), in_range, lane,
|
||||
ConstantU32(state, state.program.wave_size));
|
||||
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), ret, active, in_range);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,14 +90,14 @@ uint32_t CubeAxis(EmitterState& state, uint32_t value) {
|
||||
|
||||
uint32_t CubeLayer(EmitterState& state, uint32_t value) {
|
||||
const auto guest = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpConvertFToU, TypeU32(state), guest, value});
|
||||
state.builder.AddFunction(spv::OpConvertFToU, TypeU32(state), guest, value);
|
||||
const auto padding = Binary(
|
||||
state, spv::OpShiftLeftLogical, TypeU32(state),
|
||||
Binary(state, spv::OpShiftRightLogical, TypeU32(state), guest, ConstantU32(state, 3)),
|
||||
ConstantU32(state, 1));
|
||||
const auto host = Binary(state, spv::OpISub, TypeU32(state), guest, padding);
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpConvertUToF, TypeF32(state), result, host});
|
||||
state.builder.AddFunction(spv::OpConvertUToF, TypeF32(state), result, host);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -118,11 +118,11 @@ uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In
|
||||
? AddressF32(ctx, mem, address, first + 2u)
|
||||
: ZeroF32(ctx.state);
|
||||
if (cube) z = CubeLayer(ctx.state, z);
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeF32Vector(ctx.state, 3), result, x, y, z});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(ctx.state, 3),
|
||||
result, x, y, z);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeF32Vector(ctx.state, 2), result, x, y});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(ctx.state, 2),
|
||||
result, x, y);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -138,11 +138,11 @@ uint32_t CoordU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In
|
||||
if (components == 3u) {
|
||||
const auto z = mem.image_address_components > 2u ? AddressU32(ctx, mem, address, 2)
|
||||
: ConstantU32(ctx.state, 0);
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 3), result, x, y, z});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 3),
|
||||
result, x, y, z);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 2), result, x, y});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 2),
|
||||
result, x, y);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -193,9 +193,9 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value,
|
||||
if (dref) return value;
|
||||
const auto component = gather ? index : DmaskComponent(mem.dmask, index);
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeExtract,
|
||||
ImageScalarType(ctx.state, value_class), result, value,
|
||||
component});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract,
|
||||
ImageScalarType(ctx.state, value_class), result, value,
|
||||
component);
|
||||
return result;
|
||||
};
|
||||
for (uint32_t word = 0; word < mem.data_dwords; word++) {
|
||||
@@ -218,17 +218,16 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value,
|
||||
ConstantU32(ctx.state, 16u)));
|
||||
} else {
|
||||
const auto pair = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeF32Vector(ctx.state, 2), pair, low, high});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct,
|
||||
TypeF32Vector(ctx.state, 2), pair, low, high);
|
||||
packed[word] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpExtInst, TypeU32(ctx.state), packed[word],
|
||||
GlslStd450(ctx.state), GLSLstd450PackHalf2x16,
|
||||
pair});
|
||||
ctx.state.builder.AddFunction(spv::OpExtInst, TypeU32(ctx.state), packed[word],
|
||||
GlslStd450(ctx.state), GLSLstd450PackHalf2x16, pair);
|
||||
}
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4),
|
||||
result, packed[0], packed[1], packed[2], packed[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4),
|
||||
result, packed[0], packed[1], packed[2], packed[3]);
|
||||
return result;
|
||||
}
|
||||
uint32_t component[4] {};
|
||||
@@ -238,14 +237,13 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value,
|
||||
continue;
|
||||
}
|
||||
const auto scalar = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeExtract,
|
||||
ImageScalarType(ctx.state, value_class), scalar, value,
|
||||
index});
|
||||
ctx.state.builder.AddFunction(
|
||||
spv::OpCompositeExtract, ImageScalarType(ctx.state, value_class), scalar, value, index);
|
||||
component[index] = SampledComponentBits(ctx, scalar, value_class);
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
component[0], component[1], component[2], component[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
component[0], component[1], component[2], component[3]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -256,12 +254,12 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||
const auto image = LoadSampledImageDescriptor(ctx.state, mem.resource);
|
||||
const auto size = ctx.state.builder.AllocateId();
|
||||
if (info.multisampled != 0u) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpImageQuerySize, ImageViewSizeType(ctx.state, dimension), size, image});
|
||||
ctx.state.builder.AddFunction(spv::OpImageQuerySize,
|
||||
ImageViewSizeType(ctx.state, dimension), size, image);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction({spv::OpImageQuerySizeLod,
|
||||
ImageViewSizeType(ctx.state, dimension), size, image,
|
||||
AddressU32(ctx, mem, address, 0)});
|
||||
ctx.state.builder.AddFunction(spv::OpImageQuerySizeLod,
|
||||
ImageViewSizeType(ctx.state, dimension), size, image,
|
||||
AddressU32(ctx, mem, address, 0));
|
||||
}
|
||||
const auto components = info.coordinate_components;
|
||||
uint32_t result[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0),
|
||||
@@ -271,18 +269,18 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||
} else {
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
result[index] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(ctx.state), result[index], size, index});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state),
|
||||
result[index], size, index);
|
||||
}
|
||||
}
|
||||
if (info.multisampled == 0u) {
|
||||
result[3] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpImageQueryLevels, TypeU32(ctx.state), result[3], image});
|
||||
ctx.state.builder.AddFunction(spv::OpImageQueryLevels, TypeU32(ctx.state), result[3],
|
||||
image);
|
||||
}
|
||||
const auto vector = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), vector,
|
||||
result[0], result[1], result[2], result[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), vector,
|
||||
result[0], result[1], result[2], result[3]);
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -294,11 +292,11 @@ uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR
|
||||
if (components == 1u) return zero;
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
if (components == 3u) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3), result, zero, zero, zero});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3),
|
||||
result, zero, zero, zero);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2), result, zero, zero});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2),
|
||||
result, zero, zero);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -307,18 +305,18 @@ uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR
|
||||
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({spv::OpBitFieldSExtract, TypeI32(ctx.state), values[index],
|
||||
packed, ConstantU32(ctx.state, index * 8u),
|
||||
ConstantU32(ctx.state, 6)});
|
||||
ctx.state.builder.AddFunction(spv::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({spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3),
|
||||
result, values[0], values[1], values[2]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3),
|
||||
result, values[0], values[1], values[2]);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2), result, values[0], values[1]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2),
|
||||
result, values[0], values[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -327,7 +325,7 @@ uint32_t HorizontalOffsets(EmitterState& state, ImageDimension dimension) {
|
||||
const auto components = ImageDimensionInfoFor(dimension).spatial_components;
|
||||
const auto count = ConstantU32(state, 4);
|
||||
const auto element_type = components == 1u ? TypeI32(state) : TypeI32Vector(state, 2);
|
||||
const auto array_type = state.builder.Type(spv::OpTypeArray, {element_type, count});
|
||||
const auto array_type = state.builder.Type(spv::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);
|
||||
@@ -335,11 +333,11 @@ uint32_t HorizontalOffsets(EmitterState& state, ImageDimension dimension) {
|
||||
offsets[index] = x;
|
||||
} else {
|
||||
offsets[index] = state.builder.Constant(
|
||||
spv::OpConstantComposite, TypeI32Vector(state, 2), {x, ConstantI32(state, 0)});
|
||||
spv::OpConstantComposite, TypeI32Vector(state, 2), x, ConstantI32(state, 0));
|
||||
}
|
||||
}
|
||||
return state.builder.Constant(spv::OpConstantComposite, array_type,
|
||||
{offsets[0], offsets[1], offsets[2], offsets[3]});
|
||||
return state.builder.Constant(spv::OpConstantComposite, array_type, offsets[0], offsets[1],
|
||||
offsets[2], offsets[3]);
|
||||
}
|
||||
|
||||
uint32_t InverseSwizzle(uint32_t swizzle, uint32_t component) {
|
||||
@@ -367,15 +365,15 @@ uint32_t UnpackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint
|
||||
if (info.format == Prospero::BufferFormat::kInvalid) return texel;
|
||||
|
||||
const auto packed = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(ctx.state), packed, texel, 0u});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), packed, texel, 0u);
|
||||
uint32_t components[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0),
|
||||
ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0)};
|
||||
for (uint32_t component = 0; component < info.component_count; component++) {
|
||||
components[component] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpBitFieldUExtract, TypeU32(ctx.state),
|
||||
components[component], packed,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[component]),
|
||||
ConstantU32(ctx.state, info.component_bits[component])});
|
||||
ctx.state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(ctx.state),
|
||||
components[component], packed,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[component]),
|
||||
ConstantU32(ctx.state, info.component_bits[component]));
|
||||
}
|
||||
for (uint32_t component = info.component_count; component < 4u; component++) {
|
||||
components[component] = components[component % info.component_count];
|
||||
@@ -394,8 +392,8 @@ uint32_t UnpackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint
|
||||
}
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
selected[0], selected[1], selected[2], selected[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
selected[0], selected[1], selected[2], selected[3]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -409,24 +407,24 @@ uint32_t UnpackImageGather(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uin
|
||||
if (selector < 4u) {
|
||||
const auto value = ConstantU32(ctx.state, selector == 1u ? 1u : 0u);
|
||||
return ctx.state.builder.Constant(spv::OpConstantComposite, TypeU32Vector(ctx.state, 4),
|
||||
{value, value, value, value});
|
||||
value, value, value, value);
|
||||
}
|
||||
|
||||
uint32_t values[4] {};
|
||||
for (uint32_t lane = 0; lane < 4u; lane++) {
|
||||
const auto packed = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(ctx.state), packed, gathered, lane});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), packed, gathered,
|
||||
lane);
|
||||
values[lane] = ctx.state.builder.AllocateId();
|
||||
const auto physical = (selector - 4u) % info.component_count;
|
||||
ctx.state.builder.AddFunction({spv::OpBitFieldUExtract, TypeU32(ctx.state), values[lane],
|
||||
packed,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[physical]),
|
||||
ConstantU32(ctx.state, info.component_bits[physical])});
|
||||
ctx.state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(ctx.state), values[lane],
|
||||
packed,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[physical]),
|
||||
ConstantU32(ctx.state, info.component_bits[physical]));
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
values[0], values[1], values[2], values[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
values[0], values[1], values[2], values[3]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -436,16 +434,16 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
||||
state.builder.RequireCapability(spv::CapabilityImageQuery);
|
||||
const auto image = LoadSampledImageDescriptor(state, mem.resource);
|
||||
const auto width = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpImageQuerySizeLod, TypeU32(state), width, image,
|
||||
ConstantU32(state, 0));
|
||||
const auto width_f32 = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpConvertUToF, TypeF32(state), width_f32, width});
|
||||
state.builder.AddFunction(spv::OpConvertUToF, TypeF32(state), width_f32, width);
|
||||
const auto left = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpExtInst, TypeF32(state), left, GlslStd450(state),
|
||||
GLSLstd450Floor,
|
||||
Binary(state, spv::OpFSub, TypeF32(state),
|
||||
Binary(state, spv::OpFMul, TypeF32(state), coord, width_f32),
|
||||
ConstantF32(state, 0x3f000000u))});
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeF32(state), left, GlslStd450(state),
|
||||
GLSLstd450Floor,
|
||||
Binary(state, spv::OpFSub, TypeF32(state),
|
||||
Binary(state, spv::OpFMul, TypeF32(state), coord, width_f32),
|
||||
ConstantF32(state, 0x3f000000u)));
|
||||
|
||||
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||
const auto vector_type = ImageVectorType(state, numeric_class, 4);
|
||||
@@ -462,15 +460,15 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
||||
ConstantF32(state, index == 0u ? 0x3f000000u : 0x3fc00000u)),
|
||||
width_f32);
|
||||
const auto texel = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpImageSampleExplicitLod, vector_type, texel, sampled,
|
||||
sample_coord, spv::ImageOperandsLodMask, ZeroF32(state)});
|
||||
state.builder.AddFunction(spv::OpImageSampleExplicitLod, vector_type, texel, sampled,
|
||||
sample_coord, spv::ImageOperandsLodMask, ZeroF32(state));
|
||||
values[index] = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, scalar_type, values[index], texel, component});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, scalar_type, values[index], texel,
|
||||
component);
|
||||
}
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, vector_type, result, values[0], values[1],
|
||||
values[1], values[0]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, vector_type, result, values[0], values[1],
|
||||
values[1], values[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -481,8 +479,8 @@ uint32_t PackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32
|
||||
auto packed = ConstantU32(ctx.state, 0u);
|
||||
for (uint32_t component = 0; component < info.component_count; component++) {
|
||||
const auto value = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(ctx.state), value, texel, component});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), value, texel,
|
||||
component);
|
||||
const auto maximum =
|
||||
ConstantU32(ctx.state, info.component_bits[component] == 32u
|
||||
? UINT32_MAX
|
||||
@@ -490,8 +488,8 @@ uint32_t PackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32
|
||||
const auto within =
|
||||
Binary(ctx.state, spv::OpULessThan, TypeBool(ctx.state), value, maximum);
|
||||
const auto clamped = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(ctx.state), clamped, within, value, maximum});
|
||||
ctx.state.builder.AddFunction(spv::OpSelect, TypeU32(ctx.state), clamped, within, value,
|
||||
maximum);
|
||||
const auto shifted =
|
||||
info.component_bit_offset[component] == 0u
|
||||
? clamped
|
||||
@@ -501,8 +499,8 @@ uint32_t PackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32
|
||||
}
|
||||
const auto zero = ConstantU32(ctx.state, 0u);
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result, packed, zero, zero, zero});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(ctx.state, 4), result,
|
||||
packed, zero, zero, zero);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -516,9 +514,8 @@ uint32_t StoreTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t d
|
||||
if (source < 4u && ((dmask >> source) & 1u) != 0u) {
|
||||
const auto packed_index = DmaskComponentIndex(dmask, source);
|
||||
raw = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(ctx.state), raw, data,
|
||||
mem.data_bits == 16u ? packed_index / 2u : packed_index});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), raw, data,
|
||||
mem.data_bits == 16u ? packed_index / 2u : packed_index);
|
||||
if (mem.data_bits == 16u) {
|
||||
if ((packed_index & 1u) != 0u) {
|
||||
raw = Binary(ctx.state, spv::OpShiftRightLogical, TypeU32(ctx.state), raw,
|
||||
@@ -534,14 +531,14 @@ uint32_t StoreTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t d
|
||||
: Unary(ctx.state, spv::OpBitcast, TypeF32(ctx.state), raw);
|
||||
}
|
||||
const auto texel = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpCompositeConstruct,
|
||||
integer ? TypeU32Vector(ctx.state, 4) : TypeF32Vector(ctx.state, 4), texel, values[0],
|
||||
values[1], values[2], values[3]});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct,
|
||||
integer ? TypeU32Vector(ctx.state, 4)
|
||||
: TypeF32Vector(ctx.state, 4),
|
||||
texel, values[0], values[1], values[2], values[3]);
|
||||
return PackImageTexel(ctx, mem, texel);
|
||||
}
|
||||
|
||||
uint32_t ImageAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
spv::Op ImageAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case IR::ValueOpcode::ImageAtomicSwap32: return spv::OpAtomicExchange;
|
||||
case IR::ValueOpcode::ImageAtomicIAdd32: return spv::OpAtomicIAdd;
|
||||
@@ -550,7 +547,7 @@ uint32_t ImageAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
case IR::ValueOpcode::ImageAtomicAnd32: return spv::OpAtomicAnd;
|
||||
case IR::ValueOpcode::ImageAtomicOr32: return spv::OpAtomicOr;
|
||||
case IR::ValueOpcode::ImageAtomicXor32: return spv::OpAtomicXor;
|
||||
default: return 0;
|
||||
default: return spv::OpNop;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,19 +573,19 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||
const auto lod = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled,
|
||||
CoordF32(ctx, mem, *address, 0, ImageDimensionInfoFor(dimension).spatial_components)});
|
||||
spv::OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled,
|
||||
CoordF32(ctx, mem, *address, 0, ImageDimensionInfoFor(dimension).spatial_components));
|
||||
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(
|
||||
{spv::OpCompositeExtract, TypeF32(state), component, lod, index});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeF32(state), component, lod,
|
||||
index);
|
||||
values[index] = FloatBits(ctx, component);
|
||||
}
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(state, 4), result,
|
||||
values[0], values[1], values[2], values[3]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(state, 4), result,
|
||||
values[0], values[1], values[2], values[3]);
|
||||
ctx.Define(inst, result);
|
||||
return;
|
||||
}
|
||||
@@ -607,14 +604,14 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
||||
if (dimension_info.multisampled != 0u) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpImageFetch, ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, spv::ImageOperandsSampleMask,
|
||||
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
||||
spv::OpImageFetch, ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, spv::ImageOperandsSampleMask,
|
||||
AddressU32(ctx, mem, *address, dimension_info.coordinate_components));
|
||||
} else {
|
||||
state.builder.AddFunction({spv::OpImageFetch,
|
||||
ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, spv::ImageOperandsLodMask,
|
||||
LodU32(ctx, mem, *address, dimension)});
|
||||
state.builder.AddFunction(spv::OpImageFetch,
|
||||
ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, spv::ImageOperandsLodMask,
|
||||
LodU32(ctx, mem, *address, dimension));
|
||||
}
|
||||
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), numeric_class,
|
||||
false, mem);
|
||||
@@ -711,7 +708,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
HasFlag(mem, Decoder::ImageSampleFlagLod) ||
|
||||
HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
||||
state.program.stage != ShaderType::Pixel;
|
||||
uint32_t opcode = spv::OpImageSampleImplicitLod;
|
||||
auto opcode = spv::OpImageSampleImplicitLod;
|
||||
if (explicit_lod) {
|
||||
opcode = dref ? spv::OpImageSampleDrefExplicitLod : spv::OpImageSampleExplicitLod;
|
||||
} else if (dref) {
|
||||
@@ -748,15 +745,15 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto EmitSample = [&](uint32_t resource) {
|
||||
const auto sampled = MakeSampledImage(state, resource, mem.sampler);
|
||||
const auto sample = state.builder.AllocateId();
|
||||
std::vector<uint32_t> words {opcode, result_type, sample, sampled, coord};
|
||||
std::vector<uint32_t> sample_operands {result_type, sample, sampled, coord};
|
||||
if (dref) {
|
||||
words.push_back(dref_value);
|
||||
sample_operands.push_back(dref_value);
|
||||
}
|
||||
if (operand_mask != 0u) {
|
||||
words.push_back(operand_mask);
|
||||
words.insert(words.end(), operands.begin(), operands.end());
|
||||
sample_operands.push_back(operand_mask);
|
||||
sample_operands.insert(sample_operands.end(), operands.begin(), operands.end());
|
||||
}
|
||||
state.builder.AddFunction(words);
|
||||
state.builder.AddFunction(opcode, sample_operands);
|
||||
return sample;
|
||||
};
|
||||
if (image.indirect_root != mem.resource) {
|
||||
@@ -785,11 +782,11 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
const auto LoadMapping = [&](uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeStorageBufferElementPointer(state),
|
||||
pointer, state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
index});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeStorageBufferElementPointer(state),
|
||||
pointer, state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
index);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer);
|
||||
return value;
|
||||
};
|
||||
const auto mapping = ConstantU32(state, image.indirect_mapping_offset);
|
||||
@@ -802,9 +799,9 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto mid = Binary(state, spv::OpShiftRightLogical, TypeU32(state),
|
||||
Binary(state, spv::OpIAdd, TypeU32(state), low, high),
|
||||
ConstantU32(state, 1u));
|
||||
const auto probe = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), probe, active, mid, ConstantU32(state, 0u)});
|
||||
const auto probe = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), probe, active, mid,
|
||||
ConstantU32(state, 0u));
|
||||
const auto entry = Binary(state, spv::OpIAdd, TypeU32(state), mapping,
|
||||
Binary(state, spv::OpIAdd, TypeU32(state),
|
||||
Binary(state, spv::OpShiftLeftLogical, TypeU32(state),
|
||||
@@ -816,8 +813,8 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto equal = Binary(state, spv::OpIEqual, TypeBool(state), mapped_key, key);
|
||||
const auto match = Binary(state, spv::OpLogicalAnd, TypeBool(state), active, equal);
|
||||
const auto next_selected = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), next_selected, match, candidate, selected});
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), next_selected, match,
|
||||
candidate, selected);
|
||||
selected = next_selected;
|
||||
const auto less = Binary(state, spv::OpULessThan, TypeBool(state), mapped_key, key);
|
||||
const auto take_upper = Binary(state, spv::OpLogicalAnd, TypeBool(state), active, less);
|
||||
@@ -825,12 +822,12 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
Unary(state, spv::OpLogicalNot, TypeBool(state), less));
|
||||
const auto next_low = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), next_low, take_upper,
|
||||
Binary(state, spv::OpIAdd, TypeU32(state), mid, ConstantU32(state, 1u)), low});
|
||||
spv::OpSelect, TypeU32(state), next_low, take_upper,
|
||||
Binary(state, spv::OpIAdd, TypeU32(state), mid, ConstantU32(state, 1u)), low);
|
||||
low = next_low;
|
||||
const auto next_high = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelect, TypeU32(state), next_high, take_lower, mid, high});
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), next_high, take_lower, mid,
|
||||
high);
|
||||
high = next_high;
|
||||
}
|
||||
const auto default_label = state.builder.AllocateId();
|
||||
@@ -842,19 +839,19 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
switch_words.push_back(candidate);
|
||||
switch_words.push_back(labels[candidate - 1u]);
|
||||
}
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label,
|
||||
spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(switch_words);
|
||||
std::vector<uint32_t> phi_words {spv::OpPhi, result_type, state.builder.AllocateId()};
|
||||
EmitLabel(state, default_label);
|
||||
phi_words.push_back(EmitSample(image.indirect_resources[0]));
|
||||
phi_words.push_back(default_label);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
for (uint32_t candidate = 1; candidate < image.indirect_resources.size(); candidate++) {
|
||||
EmitLabel(state, labels[candidate - 1u]);
|
||||
phi_words.push_back(EmitSample(image.indirect_resources[candidate]));
|
||||
phi_words.push_back(labels[candidate - 1u]);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
}
|
||||
EmitLabel(state, merge_label);
|
||||
state.builder.AddFunction(phi_words);
|
||||
@@ -866,21 +863,21 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
return;
|
||||
}
|
||||
const auto atomic_opcode = ImageAtomicOpcode(op);
|
||||
if (atomic_opcode != 0u) {
|
||||
if (atomic_opcode != spv::OpNop) {
|
||||
const auto dimension = image.dimension;
|
||||
ctx.Define(inst, EmitValueOrZeroIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto pointer_type = state.builder.Type(
|
||||
spv::OpTypePointer, {spv::StorageClassImage, TypeU32(state)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpImageTexelPointer, pointer_type, pointer,
|
||||
StorageImageDescriptorPointer(state, mem.resource),
|
||||
CoordU32(ctx, mem, *address, dimension), ConstantU32(state, 0)});
|
||||
spv::OpTypePointer, spv::StorageClassImage, TypeU32(state));
|
||||
state.builder.AddFunction(spv::OpImageTexelPointer, pointer_type, pointer,
|
||||
StorageImageDescriptorPointer(state, mem.resource),
|
||||
CoordU32(ctx, mem, *address, dimension),
|
||||
ConstantU32(state, 0));
|
||||
const auto old = state.builder.AllocateId();
|
||||
state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer,
|
||||
ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone),
|
||||
ctx.Arg(inst, 2)});
|
||||
state.builder.AddFunction(atomic_opcode, TypeU32(state), old, pointer,
|
||||
ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone),
|
||||
ctx.Arg(inst, 2));
|
||||
EmitDeviceAtomicMemoryBarrier(state);
|
||||
return old;
|
||||
}));
|
||||
|
||||
@@ -151,7 +151,7 @@ uint32_t TypeU32ElementPointer(EmitterState& state, spv::StorageClass storage_cl
|
||||
|
||||
inline void EmitLabel(EmitterState& state, uint32_t label) {
|
||||
state.current_label = label;
|
||||
state.builder.AddFunction({spv::OpLabel, label});
|
||||
state.builder.AddFunction(spv::OpLabel, label);
|
||||
}
|
||||
|
||||
uint32_t TypeId(EmitterState& state, IR::Type type);
|
||||
@@ -160,7 +160,7 @@ uint32_t TypeId(EmitterState& state, IR::Type type);
|
||||
template <spv::Op opcode, IR::Type type, typename... Args>
|
||||
uint32_t EmitNative(EmitterState& state, Args... args) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, TypeId(state, type), result, args...});
|
||||
state.builder.AddFunction(opcode, TypeId(state, type), result, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -171,23 +171,23 @@ uint32_t EmitGlsl(EmitterState& state, Args... args) {
|
||||
return EmitNative<spv::OpExtInst, type>(state, GlslStd450(state), opcode, args...);
|
||||
}
|
||||
|
||||
inline uint32_t Unary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t value) {
|
||||
inline uint32_t Unary(EmitterState& state, spv::Op opcode, uint32_t type, uint32_t value) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, type, result, value});
|
||||
state.builder.AddFunction(opcode, type, result, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t Binary(EmitterState& state, uint32_t opcode, uint32_t type, uint32_t lhs,
|
||||
inline uint32_t Binary(EmitterState& state, spv::Op opcode, uint32_t type, uint32_t lhs,
|
||||
uint32_t rhs) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, type, result, lhs, rhs});
|
||||
state.builder.AddFunction(opcode, type, result, lhs, rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t Select(EmitterState& state, uint32_t type, uint32_t condition, uint32_t true_value,
|
||||
uint32_t false_value) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpSelect, type, result, condition, true_value, false_value});
|
||||
state.builder.AddFunction(spv::OpSelect, type, result, condition, true_value, false_value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ uint32_t EmitSubgroupLaneActiveBool(EmitterState& state, uint32_t lane);
|
||||
|
||||
inline constexpr auto EmitAddU32 = EmitNative<spv::OpIAdd, IR::Type::U32, uint32_t, uint32_t>;
|
||||
|
||||
uint32_t EmitBinaryU32(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs);
|
||||
uint32_t EmitBinaryU32(EmitterState& state, spv::Op opcode, uint32_t lhs, uint32_t rhs);
|
||||
|
||||
uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index);
|
||||
|
||||
@@ -417,7 +417,7 @@ uint32_t EmitShiftRightConstant(EmitterState& state, uint32_t value, uint32_t sh
|
||||
|
||||
inline constexpr auto EmitOrU32 = EmitNative<spv::OpBitwiseOr, IR::Type::U32, uint32_t, uint32_t>;
|
||||
|
||||
uint32_t EmitCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value,
|
||||
uint32_t EmitCompareU32Constant(EmitterState& state, spv::Op opcode, uint32_t value,
|
||||
uint32_t constant);
|
||||
|
||||
uint32_t EmitSubConstantMinusU32(EmitterState& state, uint32_t constant, uint32_t value);
|
||||
@@ -474,11 +474,11 @@ template <typename Fn>
|
||||
void EmitIfCondition(EmitterState& state, uint32_t condition, Fn&& fn) {
|
||||
const auto then_label = state.builder.AllocateId();
|
||||
const auto merge_label = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction({spv::OpBranchConditional, condition, then_label, merge_label});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, condition, then_label, merge_label);
|
||||
EmitLabel(state, then_label);
|
||||
fn();
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
EmitLabel(state, merge_label);
|
||||
}
|
||||
|
||||
@@ -489,19 +489,19 @@ uint32_t EmitValueOrDefaultIfCondition(EmitterState& state, uint32_t condition,
|
||||
const auto then_exit = state.builder.AllocateId();
|
||||
const auto else_label = state.builder.AllocateId();
|
||||
const auto merge_label = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction({spv::OpBranchConditional, condition, then_label, else_label});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, condition, then_label, else_label);
|
||||
EmitLabel(state, then_label);
|
||||
const auto then_value = fn();
|
||||
state.builder.AddFunction({spv::OpBranch, then_exit});
|
||||
state.builder.AddFunction(spv::OpBranch, then_exit);
|
||||
EmitLabel(state, then_exit);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
EmitLabel(state, else_label);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
EmitLabel(state, merge_label);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpPhi, type, value, then_value, then_exit, default_value, else_label});
|
||||
state.builder.AddFunction(spv::OpPhi, type, value, then_value, then_exit, default_value,
|
||||
else_label);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -528,30 +528,29 @@ uint32_t AtomicUpdate(EmitterState& state, uint32_t pointer, IR::ResourceKind ki
|
||||
const auto initial = state.builder.AllocateId();
|
||||
const auto observed = state.builder.AllocateId();
|
||||
const auto exchanged = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBranch, preheader});
|
||||
state.builder.AddFunction(spv::OpBranch, preheader);
|
||||
EmitLabel(state, preheader);
|
||||
state.builder.AddFunction({spv::OpAtomicLoad, TypeU32(state), initial, pointer,
|
||||
ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone)});
|
||||
state.builder.AddFunction({spv::OpBranch, header});
|
||||
state.builder.AddFunction(spv::OpAtomicLoad, TypeU32(state), initial, pointer,
|
||||
ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone));
|
||||
state.builder.AddFunction(spv::OpBranch, header);
|
||||
EmitLabel(state, header);
|
||||
state.builder.AddFunction(
|
||||
{spv::OpPhi, TypeU32(state), observed, initial, preheader, exchanged, cont});
|
||||
state.builder.AddFunction(spv::OpPhi, TypeU32(state), observed, initial, preheader, exchanged,
|
||||
cont);
|
||||
const auto next = desired(observed);
|
||||
state.builder.AddFunction({spv::OpAtomicCompareExchange, TypeU32(state), exchanged, pointer,
|
||||
ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), next, observed});
|
||||
state.builder.AddFunction(spv::OpAtomicCompareExchange, TypeU32(state), exchanged, pointer,
|
||||
ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), next, observed);
|
||||
const auto success = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpIEqual, TypeBool(state), success, exchanged, observed});
|
||||
state.builder.AddFunction({spv::OpLoopMerge, merge, cont, spv::LoopControlMaskNone});
|
||||
state.builder.AddFunction({spv::OpBranchConditional, success, merge, cont});
|
||||
state.builder.AddFunction(spv::OpIEqual, TypeBool(state), success, exchanged, observed);
|
||||
state.builder.AddFunction(spv::OpLoopMerge, merge, cont, spv::LoopControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, success, merge, cont);
|
||||
EmitLabel(state, cont);
|
||||
state.builder.AddFunction({spv::OpBranch, header});
|
||||
state.builder.AddFunction(spv::OpBranch, header);
|
||||
EmitLabel(state, merge);
|
||||
state.builder.AddFunction(
|
||||
{spv::OpMemoryBarrier, ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask | memory)});
|
||||
state.builder.AddFunction(spv::OpMemoryBarrier, ConstantU32(state, scope),
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask | memory));
|
||||
return observed;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ uint32_t EmitDsMaskedLaneRead(EmitterState& state, uint32_t source, uint32_t tar
|
||||
target = Binary(state, spv::OpBitwiseAnd, TypeU32(state), target, ConstantU32(state, 31));
|
||||
}
|
||||
const auto shuffled = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpGroupNonUniformShuffle, TypeU32(state), shuffled,
|
||||
ConstantU32(state, spv::ScopeSubgroup), source, target});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, TypeU32(state), shuffled,
|
||||
ConstantU32(state, spv::ScopeSubgroup), source, target);
|
||||
const auto source_exec = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpGroupNonUniformShuffle, TypeBool(state), source_exec,
|
||||
ConstantU32(state, spv::ScopeSubgroup), exec, target});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, TypeBool(state), source_exec,
|
||||
ConstantU32(state, spv::ScopeSubgroup), exec, target);
|
||||
const auto source_active =
|
||||
AndCondition(state, source_exec, EmitSubgroupLaneActiveBool(state, target));
|
||||
return Select(state, TypeU32(state), source_active, shuffled, ConstantU32(state, 0));
|
||||
@@ -107,9 +107,9 @@ uint32_t ScratchByteAddress(ValueEmitContext& ctx, const IR::MemoryInfo& mem, ui
|
||||
}
|
||||
|
||||
uint32_t ConstantDeviceAddress(EmitterState& state, uint64_t value) {
|
||||
return state.builder.Constant(
|
||||
spv::OpConstant, TypeScalarU64(state),
|
||||
{static_cast<uint32_t>(value), static_cast<uint32_t>(value >> 32u)});
|
||||
return state.builder.Constant(spv::OpConstant, TypeScalarU64(state),
|
||||
static_cast<uint32_t>(value),
|
||||
static_cast<uint32_t>(value >> 32u));
|
||||
}
|
||||
|
||||
uint32_t DeviceAddressFromWords(EmitterState& state, uint32_t low, uint32_t high) {
|
||||
@@ -153,8 +153,8 @@ uint32_t GuestAddress(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Mem
|
||||
|
||||
uint32_t FaultElementPointer(EmitterState& state, uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.fault_buffer_variable, ConstantU32(state, 0), index});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.fault_buffer_variable, ConstantU32(state, 0), index);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@@ -166,16 +166,16 @@ void RecordBdaFault(EmitterState& state, uint32_t page) {
|
||||
Binary(state, spv::OpBitwiseAnd, TypeU32(state), page, ConstantU32(state, 31)));
|
||||
const auto pointer = FaultElementPointer(state, word);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpStore, pointer, Binary(state, spv::OpBitwiseOr, TypeU32(state), value, bit)});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer);
|
||||
state.builder.AddFunction(spv::OpStore, pointer,
|
||||
Binary(state, spv::OpBitwiseOr, TypeU32(state), value, bit));
|
||||
}
|
||||
|
||||
uint32_t GetBdaPointer(ValueEmitContext& ctx, uint32_t address) {
|
||||
auto& state = ctx.state;
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFunctionCall, TypeScalarU64(state), result, state.bda_pointer_function, address});
|
||||
state.builder.AddFunction(spv::OpFunctionCall, TypeScalarU64(state), result,
|
||||
state.bda_pointer_function, address);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -186,11 +186,12 @@ uint32_t LoadBdaDword(ValueEmitContext& ctx, uint32_t address) {
|
||||
Binary(state, spv::OpINotEqual, TypeBool(state), bda, ConstantDeviceAddress(state, 0));
|
||||
return EmitValueOrZeroIfCondition(state, present, [&]() {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpConvertUToPtr, TypePhysicalU32Pointer(state), pointer, bda});
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer,
|
||||
spv::MemoryAccessAlignedMask, sizeof(uint32_t)});
|
||||
state.builder.AddFunction(spv::OpConvertUToPtr, TypePhysicalU32Pointer(state), pointer,
|
||||
bda);
|
||||
const auto value = state.builder.AllocateId();
|
||||
constexpr uint32_t alignment = sizeof(uint32_t);
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer,
|
||||
spv::MemoryAccessAlignedMask, alignment);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
@@ -306,7 +307,7 @@ uint32_t LoadWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& res
|
||||
uint32_t index) {
|
||||
const auto value = ctx.state.builder.AllocateId();
|
||||
const auto pointer = EmitMemoryElementPointer(ctx.state, resource, index);
|
||||
ctx.state.builder.AddFunction({spv::OpLoad, TypeU32(ctx.state), value, pointer});
|
||||
ctx.state.builder.AddFunction(spv::OpLoad, TypeU32(ctx.state), value, pointer);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -401,11 +402,11 @@ uint32_t LoadFormattedComponent(ValueEmitContext& ctx, const IR::MemoryInfo& mem
|
||||
const auto source_value =
|
||||
type == TypeI32(ctx.state) ? Unary(ctx.state, spv::OpBitcast, type, raw) : raw;
|
||||
const auto extracted = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{IsSignedFormatComponent(info.type) ? spv::OpBitFieldSExtract : spv::OpBitFieldUExtract,
|
||||
type, extracted, source_value,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[component]),
|
||||
ConstantU32(ctx.state, bits)});
|
||||
ctx.state.builder.AddFunction(IsSignedFormatComponent(info.type) ? spv::OpBitFieldSExtract
|
||||
: spv::OpBitFieldUExtract,
|
||||
type, extracted, source_value,
|
||||
ConstantU32(ctx.state, info.component_bit_offset[component]),
|
||||
ConstantU32(ctx.state, bits));
|
||||
raw = type == TypeI32(ctx.state)
|
||||
? Unary(ctx.state, spv::OpBitcast, TypeU32(ctx.state), extracted)
|
||||
: extracted;
|
||||
@@ -465,8 +466,8 @@ void StoreSubwordInBounds(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||
};
|
||||
if (mem.kind == IR::ResourceKind::Scratch) {
|
||||
const auto old = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpLoad, TypeU32(ctx.state), old, pointer});
|
||||
ctx.state.builder.AddFunction({spv::OpStore, pointer, merge(old)});
|
||||
ctx.state.builder.AddFunction(spv::OpLoad, TypeU32(ctx.state), old, pointer);
|
||||
ctx.state.builder.AddFunction(spv::OpStore, pointer, merge(old));
|
||||
} else {
|
||||
AtomicUpdate(ctx.state, pointer, mem.kind, merge);
|
||||
}
|
||||
@@ -495,15 +496,15 @@ void StoreWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Me
|
||||
const MemoryResourceAccess& resource, uint32_t data) {
|
||||
const auto index = EmitMemoryElementIndex(ctx.state, resource, DwordIndex(ctx, inst, mem));
|
||||
EmitIfCondition(ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpStore, EmitMemoryElementPointer(ctx.state, resource, index), data});
|
||||
ctx.state.builder.AddFunction(spv::OpStore,
|
||||
EmitMemoryElementPointer(ctx.state, resource, index), data);
|
||||
});
|
||||
}
|
||||
|
||||
void StoreWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource, uint32_t index,
|
||||
uint32_t data) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpStore, EmitMemoryElementPointer(ctx.state, resource, index), data});
|
||||
ctx.state.builder.AddFunction(spv::OpStore,
|
||||
EmitMemoryElementPointer(ctx.state, resource, index), data);
|
||||
}
|
||||
|
||||
void StoreWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem) {
|
||||
@@ -538,7 +539,7 @@ void FormattedStore(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Memor
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t SpirvAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case IR::ValueOpcode::BufferAtomicCmpSwap32: return spv::OpAtomicCompareExchange;
|
||||
case IR::ValueOpcode::BufferAtomicSwap32:
|
||||
@@ -563,7 +564,7 @@ uint32_t SpirvAtomicOpcode(IR::ValueOpcode opcode) {
|
||||
case IR::ValueOpcode::SharedAtomicOr32: return spv::OpAtomicOr;
|
||||
case IR::ValueOpcode::BufferAtomicXor32:
|
||||
case IR::ValueOpcode::SharedAtomicXor32: return spv::OpAtomicXor;
|
||||
default: return 0;
|
||||
default: return spv::OpNop;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,15 +575,14 @@ uint32_t EmitAtomicOperation(ValueEmitContext& ctx, const IR::Inst& inst, uint32
|
||||
const auto desired = ctx.Arg(inst, inst.NumArgs() - 3);
|
||||
const auto comparator = ctx.Arg(inst, inst.NumArgs() - 2);
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpAtomicCompareExchange, TypeU32(ctx.state), old, pointer,
|
||||
ConstantU32(ctx.state, scope), ConstantU32(ctx.state, spv::MemorySemanticsMaskNone),
|
||||
ConstantU32(ctx.state, spv::MemorySemanticsMaskNone), desired, comparator});
|
||||
spv::OpAtomicCompareExchange, TypeU32(ctx.state), old, pointer,
|
||||
ConstantU32(ctx.state, scope), ConstantU32(ctx.state, spv::MemorySemanticsMaskNone),
|
||||
ConstantU32(ctx.state, spv::MemorySemanticsMaskNone), desired, comparator);
|
||||
} else {
|
||||
const auto value = ctx.Arg(inst, inst.NumArgs() - 2);
|
||||
ctx.state.builder.AddFunction({SpirvAtomicOpcode(inst.GetOpcode()), TypeU32(ctx.state), old,
|
||||
pointer, ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, spv::MemorySemanticsMaskNone),
|
||||
value});
|
||||
ctx.state.builder.AddFunction(SpirvAtomicOpcode(inst.GetOpcode()), TypeU32(ctx.state), old,
|
||||
pointer, ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, spv::MemorySemanticsMaskNone), value);
|
||||
}
|
||||
return old;
|
||||
}
|
||||
@@ -782,8 +782,8 @@ void StoreWideBuffer(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t compo
|
||||
EmitIfCondition(state, plan.in_bounds, [&]() {
|
||||
for (uint32_t component = 0; component < components; component++) {
|
||||
const auto data = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(state), data, composite, component});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), data,
|
||||
composite, component);
|
||||
StoreFormattedInBounds(ctx, mem, plan, component, data);
|
||||
}
|
||||
});
|
||||
@@ -791,8 +791,8 @@ void StoreWideBuffer(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t compo
|
||||
}
|
||||
for (uint32_t component = 0; component < components; component++) {
|
||||
const auto data = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCompositeExtract, TypeU32(state), data, composite, component});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), data, composite,
|
||||
component);
|
||||
StoreWordPrepared(ctx, inst, RebaseRawComponent(mem, component), resource, data);
|
||||
}
|
||||
});
|
||||
@@ -851,49 +851,49 @@ void DefineGetBdaPointer(EmitterState& state) {
|
||||
return;
|
||||
}
|
||||
const auto type = TypeScalarU64(state);
|
||||
const auto function_type = state.builder.Type(spv::OpTypeFunction, {type, type});
|
||||
const auto function_type = state.builder.Type(spv::OpTypeFunction, type, type);
|
||||
state.bda_pointer_function = state.builder.AllocateId();
|
||||
const auto address = state.builder.AllocateId();
|
||||
const auto entry_label = state.builder.AllocateId();
|
||||
state.builder.AddName(state.bda_pointer_function, "get_bda_pointer");
|
||||
state.builder.AddFunction({spv::OpFunction, type, state.bda_pointer_function,
|
||||
spv::FunctionControlMaskNone, function_type});
|
||||
state.builder.AddFunction({spv::OpFunctionParameter, type, address});
|
||||
state.builder.AddFunction(spv::OpFunction, type, state.bda_pointer_function,
|
||||
spv::FunctionControlMaskNone, function_type);
|
||||
state.builder.AddFunction(spv::OpFunctionParameter, type, address);
|
||||
EmitLabel(state, entry_label);
|
||||
|
||||
const auto page64 = Binary(state, spv::OpShiftRightLogical, type, address,
|
||||
ConstantDeviceAddress(state, BufferCache::CACHING_PAGEBITS));
|
||||
const auto page = Unary(state, spv::OpUConvert, TypeU32(state), page64);
|
||||
const auto entry_pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeStorageBufferU64ElementPointer(state),
|
||||
entry_pointer, state.bda_pagetable_variable, ConstantU32(state, 0),
|
||||
page});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeStorageBufferU64ElementPointer(state),
|
||||
entry_pointer, state.bda_pagetable_variable, ConstantU32(state, 0),
|
||||
page);
|
||||
const auto base = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, type, base, entry_pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, type, base, entry_pointer);
|
||||
const auto missing =
|
||||
Binary(state, spv::OpIEqual, TypeBool(state), base, ConstantDeviceAddress(state, 0));
|
||||
const auto fault_label = state.builder.AllocateId();
|
||||
const auto available_label = state.builder.AllocateId();
|
||||
const auto merge_label = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction({spv::OpBranchConditional, missing, fault_label, available_label});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, missing, fault_label, available_label);
|
||||
|
||||
EmitLabel(state, fault_label);
|
||||
RecordBdaFault(state, page);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
|
||||
EmitLabel(state, available_label);
|
||||
const auto offset = Binary(state, spv::OpBitwiseAnd, type, address,
|
||||
ConstantDeviceAddress(state, BufferCache::CACHING_PAGESIZE - 1));
|
||||
const auto available = Binary(state, spv::OpIAdd, type, base, offset);
|
||||
state.builder.AddFunction({spv::OpBranch, merge_label});
|
||||
state.builder.AddFunction(spv::OpBranch, merge_label);
|
||||
|
||||
EmitLabel(state, merge_label);
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpPhi, type, result, ConstantDeviceAddress(state, 0),
|
||||
fault_label, available, available_label});
|
||||
state.builder.AddFunction({spv::OpReturnValue, result});
|
||||
state.builder.AddFunction({spv::OpFunctionEnd});
|
||||
state.builder.AddFunction(spv::OpPhi, type, result, ConstantDeviceAddress(state, 0),
|
||||
fault_label, available, available_label);
|
||||
state.builder.AddFunction(spv::OpReturnValue, result);
|
||||
state.builder.AddFunction(spv::OpFunctionEnd);
|
||||
}
|
||||
|
||||
uint32_t EmitAtomic32(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
@@ -905,8 +905,8 @@ uint32_t EmitAtomic32(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
if (mem.kind == IR::ResourceKind::Lds) {
|
||||
const auto semantics =
|
||||
spv::MemorySemanticsAcquireReleaseMask | spv::MemorySemanticsWorkgroupMemoryMask;
|
||||
ctx.state.builder.AddFunction({spv::OpMemoryBarrier, ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, semantics)});
|
||||
ctx.state.builder.AddFunction(spv::OpMemoryBarrier, ConstantU32(ctx.state, scope),
|
||||
ConstantU32(ctx.state, semantics));
|
||||
} else {
|
||||
EmitDeviceAtomicMemoryBarrier(ctx.state);
|
||||
}
|
||||
@@ -932,11 +932,11 @@ uint32_t EmitBufferAtomic64(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Arg(inst, inst.NumArgs() - 2));
|
||||
const auto old = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{SpirvAtomicOpcode(inst.GetOpcode()), TypeScalarU64(state), old,
|
||||
EmitStorageBufferElementPointer(state, resource, index,
|
||||
TypeStorageBufferU64ElementPointer(state)),
|
||||
ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), value});
|
||||
SpirvAtomicOpcode(inst.GetOpcode()), TypeScalarU64(state), old,
|
||||
EmitStorageBufferElementPointer(state, resource, index,
|
||||
TypeStorageBufferU64ElementPointer(state)),
|
||||
ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), value);
|
||||
EmitDeviceAtomicMemoryBarrier(state);
|
||||
return Unary(state, spv::OpBitcast, TypeU64(state), old);
|
||||
});
|
||||
@@ -959,11 +959,11 @@ void EmitSharedFloatAtomic(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto access = PrepareMemoryElement(ctx, mem, DwordIndex(ctx, inst, mem));
|
||||
EmitIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, access.resource, access.index), [&]() {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpStore, ctx.scratch_u32_variable, ctx.Arg(inst, 1)});
|
||||
ctx.state.builder.AddFunction(spv::OpStore, ctx.scratch_u32_variable,
|
||||
ctx.Arg(inst, 1));
|
||||
const auto data = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpLoad, TypeU32(ctx.state), data, ctx.scratch_u32_variable});
|
||||
ctx.state.builder.AddFunction(spv::OpLoad, TypeU32(ctx.state), data,
|
||||
ctx.scratch_u32_variable);
|
||||
AtomicUpdate(
|
||||
ctx.state, EmitMemoryElementPointer(ctx.state, access.resource, access.index),
|
||||
mem.kind, [&](uint32_t old) {
|
||||
@@ -1006,8 +1006,8 @@ uint32_t EmitAppendConsume(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto ballot = ctx.Ballot(inst.Arg(1));
|
||||
const auto low = state.builder.AllocateId();
|
||||
const auto high = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), low, ballot, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), high, ballot, 1});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), low, ballot, 0);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), high, ballot, 1);
|
||||
const auto count = Binary(state, spv::OpIAdd, TypeU32(state),
|
||||
Unary(state, spv::OpBitCount, TypeU32(state), low),
|
||||
Unary(state, spv::OpBitCount, TypeU32(state), high));
|
||||
@@ -1033,17 +1033,17 @@ uint32_t EmitAppendConsume(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
AndCondition(state, storage_bounds, m0_bounds)));
|
||||
const auto atomic = EmitValueOrZeroIfCondition(state, condition, [&]() {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{append ? spv::OpAtomicIAdd : spv::OpAtomicISub, TypeU32(state), value,
|
||||
EmitMemoryElementPointer(state, access, index),
|
||||
ConstantU32(state, mem.kind == IR::ResourceKind::Gds ? spv::ScopeDevice
|
||||
: spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), count});
|
||||
state.builder.AddFunction(append ? spv::OpAtomicIAdd : spv::OpAtomicISub, TypeU32(state),
|
||||
value, EmitMemoryElementPointer(state, access, index),
|
||||
ConstantU32(state, mem.kind == IR::ResourceKind::Gds
|
||||
? spv::ScopeDevice
|
||||
: spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::MemorySemanticsMaskNone), count);
|
||||
return value;
|
||||
});
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpGroupNonUniformShuffle, TypeU32(state), result,
|
||||
ConstantU32(state, spv::ScopeSubgroup), atomic, source_lane});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, TypeU32(state), result,
|
||||
ConstantU32(state, spv::ScopeSubgroup), atomic, source_lane);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1053,9 +1053,9 @@ uint32_t EmitReadConst(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Fail(inst, "requires the flattened SRT descriptor");
|
||||
}
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
ctx.Arg(inst, 1)});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeStorageBufferElementPointer(state), pointer,
|
||||
state.flattened_srt_variable, ConstantU32(state, 0),
|
||||
ctx.Arg(inst, 1));
|
||||
return EmitNative<spv::OpLoad, IR::Type::U32>(state, pointer);
|
||||
}
|
||||
|
||||
@@ -1131,7 +1131,7 @@ uint32_t EmitSharedIncDec(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
|
||||
uint32_t EmitSwizzleU32(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
state.builder.AddFunction({spv::OpStore, ctx.scratch_u32_variable, ctx.Arg(inst, 0)});
|
||||
state.builder.AddFunction(spv::OpStore, ctx.scratch_u32_variable, ctx.Arg(inst, 0));
|
||||
const auto source = EmitNative<spv::OpLoad, IR::Type::U32>(state, ctx.scratch_u32_variable);
|
||||
const auto target = EmitDsSwizzleTargetLane(state, EmitSubgroupLocalInvocationId(state),
|
||||
inst.Arg(1).IsImmediate() ? inst.Arg(1).U32() : 0);
|
||||
|
||||
@@ -7,27 +7,27 @@ uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index) {
|
||||
dword_index += state.program.bindings.push_data_start_dword;
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypePushConstantElementPointer(state),
|
||||
pointer, state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypePushConstantElementPointer(state),
|
||||
pointer, state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer);
|
||||
return value;
|
||||
}
|
||||
if (state.shader_data_storage_variable != 0) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeStorageBufferElementPointer(state),
|
||||
pointer, state.shader_data_storage_variable,
|
||||
ConstantU32(state, 0), ConstantU32(state, dword_index)});
|
||||
state.builder.AddFunction({spv::OpLoad, TypeU32(state), value, pointer});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeStorageBufferElementPointer(state),
|
||||
pointer, state.shader_data_storage_variable,
|
||||
ConstantU32(state, 0), ConstantU32(state, dword_index));
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), value, pointer);
|
||||
return value;
|
||||
}
|
||||
return ConstantU32(state, 0);
|
||||
}
|
||||
|
||||
uint32_t EmitBinaryU32(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) {
|
||||
uint32_t EmitBinaryU32(EmitterState& state, spv::Op opcode, uint32_t lhs, uint32_t rhs) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({opcode, TypeU32(state), ret, lhs, rhs});
|
||||
state.builder.AddFunction(opcode, TypeU32(state), ret, lhs, rhs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -88,12 +88,12 @@ MemoryResourceAccess PrepareStorageBufferResourceAccess(EmitterState& state,
|
||||
ResourceForDescriptor(state, IR::DescriptorBindingKind::Buffers, mem.resource);
|
||||
MemoryResourceAccess access {.kind = mem.kind};
|
||||
access.object_pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, pointer_type, access.object_pointer, variable,
|
||||
ConstantU32(state, array_index)});
|
||||
state.builder.AddFunction(spv::OpAccessChain, pointer_type, access.object_pointer, variable,
|
||||
ConstantU32(state, array_index));
|
||||
access.byte_offset = state.memory_byte_offsets[array_index];
|
||||
access.length = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpArrayLength, TypeU32(state), access.length, access.object_pointer, 0});
|
||||
state.builder.AddFunction(spv::OpArrayLength, TypeU32(state), access.length,
|
||||
access.object_pointer, 0);
|
||||
return access;
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ MemoryResourceAccess PrepareMemoryResourceAccess(EmitterState& state, const IR::
|
||||
default: EXIT("unsupported memory resource kind: %u\n", static_cast<unsigned>(mem.kind));
|
||||
}
|
||||
access.length = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpArrayLength, TypeU32(state), access.length, access.object_pointer, 0});
|
||||
state.builder.AddFunction(spv::OpArrayLength, TypeU32(state), access.length,
|
||||
access.object_pointer, 0);
|
||||
return access;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ uint32_t EmitMemoryElementIndex(EmitterState& state, const MemoryResourceAccess&
|
||||
uint32_t EmitMemoryElementInBounds(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index) {
|
||||
const auto in_bounds = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpULessThan, TypeBool(state), in_bounds, index, access.length});
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), in_bounds, index, access.length);
|
||||
return in_bounds;
|
||||
}
|
||||
|
||||
@@ -165,8 +165,8 @@ uint32_t EmitMemoryElementPointer(EmitterState& state, const MemoryResourceAcces
|
||||
: ShaderWorkgroupInput(state.program.stage, state.input_info) != nullptr
|
||||
? spv::StorageClassWorkgroup
|
||||
: spv::StorageClassFunction;
|
||||
state.builder.AddFunction({spv::OpAccessChain, TypeU32ElementPointer(state, storage_class),
|
||||
pointer, access.object_pointer, index});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypeU32ElementPointer(state, storage_class),
|
||||
pointer, access.object_pointer, index);
|
||||
return pointer;
|
||||
}
|
||||
return EmitStorageBufferElementPointer(state, access, index,
|
||||
@@ -177,14 +177,14 @@ uint32_t EmitStorageBufferElementPointer(EmitterState& state,
|
||||
const MemoryResourceAccess& access, uint32_t index,
|
||||
uint32_t pointer_type) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpAccessChain, pointer_type, pointer, access.object_pointer,
|
||||
ConstantU32(state, 0), index});
|
||||
state.builder.AddFunction(spv::OpAccessChain, pointer_type, pointer, access.object_pointer,
|
||||
ConstantU32(state, 0), index);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
uint32_t EmitTBufferBitcastU32ToI32(EmitterState& state, uint32_t value) {
|
||||
const auto ret = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitcast, TypeI32(state), ret, value});
|
||||
state.builder.AddFunction(spv::OpBitcast, TypeI32(state), ret, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -218,10 +218,10 @@ 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({spv::OpConvertUToF, TypeF32(state), mantissa_f32, mantissa});
|
||||
state.builder.AddFunction(spv::OpConvertUToF, TypeF32(state), mantissa_f32, mantissa);
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFMul, TypeF32(state), subnormal, mantissa_f32,
|
||||
ConstantF32Value(state, std::ldexp(1.0f, 1 - 15 - static_cast<int>(mantissa_bits)))});
|
||||
spv::OpFMul, TypeF32(state), subnormal, mantissa_f32,
|
||||
ConstantF32Value(state, std::ldexp(1.0f, 1 - 15 - static_cast<int>(mantissa_bits))));
|
||||
|
||||
const auto zero_exp = EmitCompareU32Constant(state, spv::OpIEqual, exponent, 0);
|
||||
const auto special_exp = EmitCompareU32Constant(state, spv::OpIEqual, exponent, 31);
|
||||
@@ -238,22 +238,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({spv::OpConvertUToF, TypeF32(state), value, raw});
|
||||
state.builder.AddFunction(spv::OpConvertUToF, TypeF32(state), value, raw);
|
||||
return EmitBitcastF32ToU32(state, value);
|
||||
}
|
||||
case Format::ComponentType::Sscaled: {
|
||||
const auto signed_raw = EmitTBufferBitcastU32ToI32(state, raw);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpConvertSToF, TypeF32(state), value, signed_raw});
|
||||
state.builder.AddFunction(spv::OpConvertSToF, TypeF32(state), value, signed_raw);
|
||||
return EmitBitcastF32ToU32(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({spv::OpConvertUToF, TypeF32(state), value, raw});
|
||||
state.builder.AddFunction({spv::OpFDiv, TypeF32(state), normalized, value,
|
||||
ConstantF32Value(state, max_value)});
|
||||
state.builder.AddFunction(spv::OpConvertUToF, TypeF32(state), value, raw);
|
||||
state.builder.AddFunction(spv::OpFDiv, TypeF32(state), normalized, value,
|
||||
ConstantF32Value(state, max_value));
|
||||
return EmitBitcastF32ToU32(state, normalized);
|
||||
}
|
||||
case Format::ComponentType::Snorm: {
|
||||
@@ -262,11 +262,11 @@ 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({spv::OpConvertSToF, TypeF32(state), value, signed_raw});
|
||||
state.builder.AddFunction({spv::OpFDiv, TypeF32(state), normalized, value,
|
||||
ConstantF32Value(state, max_value)});
|
||||
state.builder.AddFunction({spv::OpExtInst, TypeF32(state), clamped, GlslStd450(state),
|
||||
GLSLstd450FMax, normalized, ConstantF32Value(state, -1.0f)});
|
||||
state.builder.AddFunction(spv::OpConvertSToF, TypeF32(state), value, signed_raw);
|
||||
state.builder.AddFunction(spv::OpFDiv, TypeF32(state), normalized, value,
|
||||
ConstantF32Value(state, max_value));
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeF32(state), clamped, GlslStd450(state),
|
||||
GLSLstd450FMax, normalized, ConstantF32Value(state, -1.0f));
|
||||
return EmitBitcastF32ToU32(state, clamped);
|
||||
}
|
||||
case Format::ComponentType::Float:
|
||||
@@ -284,8 +284,8 @@ uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferForma
|
||||
void EmitDeviceAtomicMemoryBarrier(EmitterState& state) {
|
||||
const auto semantics =
|
||||
spv::MemorySemanticsAcquireReleaseMask | spv::MemorySemanticsUniformMemoryMask;
|
||||
state.builder.AddFunction({spv::OpMemoryBarrier, ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, semantics)});
|
||||
state.builder.AddFunction(spv::OpMemoryBarrier, ConstantU32(state, spv::ScopeDevice),
|
||||
ConstantU32(state, semantics));
|
||||
}
|
||||
|
||||
uint32_t EmitFloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t source,
|
||||
@@ -300,7 +300,7 @@ uint32_t EmitFloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t
|
||||
const auto negative = EmitCompareU32Constant(state, spv::OpINotEqual,
|
||||
EmitAndConstant(state, bits, 0x80000000u), 0u);
|
||||
const auto negative_key = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpNot, TypeU32(state), negative_key, bits});
|
||||
state.builder.AddFunction(spv::OpNot, TypeU32(state), negative_key, bits);
|
||||
const auto positive_key =
|
||||
EmitBinaryU32(state, spv::OpBitwiseXor, bits, ConstantU32(state, 0x80000000u));
|
||||
return OrderedBits {
|
||||
@@ -313,8 +313,8 @@ uint32_t EmitFloatAtomicReplacement(EmitterState& state, uint32_t old, uint32_t
|
||||
state, EmitLogicalOrBool(state, source_class.nan, old_class.nan),
|
||||
EmitLogicalAndBool(state, source_class.zero, old_class.zero));
|
||||
const auto compare = state.builder.AllocateId();
|
||||
state.builder.AddFunction({max_value ? spv::OpUGreaterThan : spv::OpULessThan, TypeBool(state),
|
||||
compare, source_class.key, old_class.key});
|
||||
state.builder.AddFunction(max_value ? spv::OpUGreaterThan : spv::OpULessThan, TypeBool(state),
|
||||
compare, source_class.key, old_class.key);
|
||||
return EmitSelectValueU32(
|
||||
state, EmitLogicalAndBool(state, EmitLogicalNotBool(state, unordered), compare), source,
|
||||
old);
|
||||
@@ -342,17 +342,17 @@ uint32_t EmitDsSwizzleTargetLane(EmitterState& state, uint32_t subid, uint32_t c
|
||||
const auto perm = state.builder.AllocateId();
|
||||
const auto base = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane2, subid, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftLeftLogical, TypeU32(state), shift, lane2, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpShiftRightLogical, TypeU32(state), perm0, ConstantU32(state, control), shift});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), perm, perm0, ConstantU32(state, 3)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, 0xfffffffcu)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, base, perm});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane2, subid,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), shift, lane2,
|
||||
ConstantU32(state, 1));
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), perm0,
|
||||
ConstantU32(state, control), shift);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), perm, perm0,
|
||||
ConstantU32(state, 3));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), base, subid,
|
||||
ConstantU32(state, 0xfffffffcu));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, base, perm);
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -362,17 +362,17 @@ 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(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), lane, subid, ConstantU32(state, 31)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), masked, lane, ConstantU32(state, control & 0x1fu)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), ored, masked,
|
||||
ConstantU32(state, (control >> 5u) & 0x1fu)});
|
||||
state.builder.AddFunction({spv::OpBitwiseXor, TypeU32(state), xored, ored,
|
||||
ConstantU32(state, (control >> 10u) & 0x1fu)});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitwiseAnd, TypeU32(state), base, subid, ConstantU32(state, 0xffffffe0u)});
|
||||
state.builder.AddFunction({spv::OpBitwiseOr, TypeU32(state), target, base, xored});
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 31));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), masked, lane,
|
||||
ConstantU32(state, control & 0x1fu));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), ored, masked,
|
||||
ConstantU32(state, (control >> 5u) & 0x1fu));
|
||||
state.builder.AddFunction(spv::OpBitwiseXor, TypeU32(state), xored, ored,
|
||||
ConstantU32(state, (control >> 10u) & 0x1fu));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), base, subid,
|
||||
ConstantU32(state, 0xffffffe0u));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, base, xored);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
namespace {
|
||||
|
||||
uint32_t MeshArray(EmitterState& state, spv::StorageClass storage, uint32_t type, uint32_t count) {
|
||||
const auto array = state.builder.Type(spv::OpTypeArray, {type, ConstantU32(state, count)});
|
||||
const auto array = state.builder.Type(spv::OpTypeArray, type, ConstantU32(state, count));
|
||||
return state.builder.DefineGlobalVariable(TypePointer(state, storage, array), storage);
|
||||
}
|
||||
|
||||
uint32_t MeshElement(EmitterState& state, uint32_t variable, spv::StorageClass storage,
|
||||
uint32_t type, uint32_t index) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpAccessChain, TypePointer(state, storage, type), pointer, variable, index});
|
||||
state.builder.AddFunction(spv::OpAccessChain, TypePointer(state, storage, type), pointer,
|
||||
variable, index);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ uint32_t MeshLoad(EmitterState& state, uint32_t variable, spv::StorageClass stor
|
||||
uint32_t index) {
|
||||
const auto pointer = MeshElement(state, variable, storage, type, index);
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, type, value, pointer});
|
||||
state.builder.AddFunction(spv::OpLoad, type, value, pointer);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -50,17 +50,17 @@ void DefineMeshOutputs(EmitterState& state) {
|
||||
state.interface_variables.push_back(output.variable_id);
|
||||
state.builder.AddName(output.variable_id, output.debug_name.c_str());
|
||||
if (output.kind == IR::StageOutputKind::Parameter) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, output.variable_id, spv::DecorationLocation, output.location});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, output.variable_id,
|
||||
spv::DecorationLocation, output.location);
|
||||
} else {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, output.variable_id, spv::DecorationBuiltIn,
|
||||
output.kind == IR::StageOutputKind::Layer ? spv::BuiltInLayer
|
||||
: spv::BuiltInPosition});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, output.variable_id, spv::DecorationBuiltIn,
|
||||
output.kind == IR::StageOutputKind::Layer
|
||||
? spv::BuiltInLayer
|
||||
: spv::BuiltInPosition);
|
||||
}
|
||||
if (output.kind == IR::StageOutputKind::Layer) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, output.variable_id,
|
||||
spv::DecorationPerPrimitiveEXT}); // PerPrimitiveEXT
|
||||
state.builder.AddAnnotation(spv::OpDecorate, output.variable_id,
|
||||
spv::DecorationPerPrimitiveEXT); // PerPrimitiveEXT
|
||||
}
|
||||
}
|
||||
state.mesh_allocation = MeshArray(state, spv::StorageClassWorkgroup, TypeU32(state), 2);
|
||||
@@ -73,11 +73,11 @@ void DefineMeshOutputs(EmitterState& state) {
|
||||
state.interface_variables.push_back(state.mesh_primitives);
|
||||
state.interface_variables.push_back(state.mesh_cull);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.mesh_primitives, spv::DecorationBuiltIn,
|
||||
spv::BuiltInPrimitiveTriangleIndicesEXT}); // PrimitiveTriangleIndicesEXT
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.mesh_cull, spv::DecorationBuiltIn,
|
||||
spv::BuiltInCullPrimitiveEXT}); // CullPrimitiveEXT
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.mesh_cull, spv::DecorationPerPrimitiveEXT});
|
||||
spv::OpDecorate, state.mesh_primitives, spv::DecorationBuiltIn,
|
||||
spv::BuiltInPrimitiveTriangleIndicesEXT); // PrimitiveTriangleIndicesEXT
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.mesh_cull, spv::DecorationBuiltIn,
|
||||
spv::BuiltInCullPrimitiveEXT); // CullPrimitiveEXT
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.mesh_cull, spv::DecorationPerPrimitiveEXT);
|
||||
}
|
||||
|
||||
uint32_t MeshOutputPointer(EmitterState& state, IR::StageOutputKind kind, uint32_t index) {
|
||||
@@ -103,45 +103,45 @@ uint32_t MeshPrimitivePointer(EmitterState& state) {
|
||||
void EmitMeshAllocate(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
const auto first = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpIEqual, TypeBool(state), first,
|
||||
EmitLocalInvocationIndex(state), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpIEqual, TypeBool(state), first,
|
||||
EmitLocalInvocationIndex(state), ConstantU32(state, 0));
|
||||
EmitIfCondition(state, first, [&] {
|
||||
const auto allocation = ctx.Arg(inst, 0);
|
||||
for (uint32_t field = 0; field < 2; field++) {
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpBitFieldUExtract, TypeU32(state), value, allocation,
|
||||
ConstantU32(state, field * 12u),
|
||||
ConstantU32(state, field == 0 ? 10u : 11u)});
|
||||
state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(state), value, allocation,
|
||||
ConstantU32(state, field * 12u),
|
||||
ConstantU32(state, field == 0 ? 10u : 11u));
|
||||
const auto pointer =
|
||||
MeshElement(state, state.mesh_allocation, spv::StorageClassWorkgroup,
|
||||
TypeU32(state), ConstantU32(state, field));
|
||||
state.builder.AddFunction({spv::OpStore, pointer, value});
|
||||
state.builder.AddFunction(spv::OpStore, pointer, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EmitMeshEntryPoint(EmitterState& state) {
|
||||
state.builder.AddFunction({spv::OpFunction, TypeVoid(state), state.main_func,
|
||||
spv::FunctionControlMaskNone, TypeFunction(state)});
|
||||
state.builder.AddFunction(spv::OpFunction, TypeVoid(state), state.main_func,
|
||||
spv::FunctionControlMaskNone, TypeFunction(state));
|
||||
EmitLabel(state, state.builder.AllocateId());
|
||||
state.builder.AddFunction(
|
||||
{spv::OpFunctionCall, TypeVoid(state), state.builder.AllocateId(), state.mesh_guest_func});
|
||||
state.builder.AddFunction(spv::OpFunctionCall, TypeVoid(state), state.builder.AllocateId(),
|
||||
state.mesh_guest_func);
|
||||
// All guest waves finish before the uniform Vulkan allocation and output stores.
|
||||
state.builder.AddFunction({spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask |
|
||||
spv::MemorySemanticsWorkgroupMemoryMask)});
|
||||
state.builder.AddFunction(spv::OpControlBarrier, ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::ScopeWorkgroup),
|
||||
ConstantU32(state, spv::MemorySemanticsAcquireReleaseMask |
|
||||
spv::MemorySemanticsWorkgroupMemoryMask));
|
||||
const auto vertices = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup,
|
||||
TypeU32(state), ConstantU32(state, 0));
|
||||
const auto primitives = MeshLoad(state, state.mesh_allocation, spv::StorageClassWorkgroup,
|
||||
TypeU32(state), ConstantU32(state, 1));
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSetMeshOutputsEXT, vertices, primitives}); // OpSetMeshOutputsEXT
|
||||
state.builder.AddFunction(spv::OpSetMeshOutputsEXT, vertices,
|
||||
primitives); // OpSetMeshOutputsEXT
|
||||
for (uint32_t half = 0; half < state.lane_count; half++) {
|
||||
state.lane_half = half;
|
||||
const auto index = EmitLocalInvocationIndex(state);
|
||||
const auto is_vertex = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpULessThan, TypeBool(state), is_vertex, index, vertices});
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), is_vertex, index, vertices);
|
||||
EmitIfCondition(state, is_vertex, [&] {
|
||||
for (const auto& output: state.outputs) {
|
||||
if (output.kind == IR::StageOutputKind::Layer) {
|
||||
@@ -153,12 +153,12 @@ void EmitMeshEntryPoint(EmitterState& state) {
|
||||
ConstantU32(state, half));
|
||||
const auto pointer =
|
||||
MeshElement(state, output.variable_id, spv::StorageClassOutput, type, index);
|
||||
state.builder.AddFunction({spv::OpStore, pointer, value});
|
||||
state.builder.AddFunction(spv::OpStore, pointer, value);
|
||||
}
|
||||
});
|
||||
const auto is_primitive = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpULessThan, TypeBool(state), is_primitive, index, primitives});
|
||||
state.builder.AddFunction(spv::OpULessThan, TypeBool(state), is_primitive, index,
|
||||
primitives);
|
||||
EmitIfCondition(state, is_primitive, [&] {
|
||||
const auto packed = MeshLoad(state, state.mesh_primitive_data, spv::StorageClassPrivate,
|
||||
TypeU32(state), ConstantU32(state, half));
|
||||
@@ -166,25 +166,25 @@ void EmitMeshEntryPoint(EmitterState& state) {
|
||||
for (uint32_t component = 0; component < 3; component++) {
|
||||
vertex[component] = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBitFieldUExtract, TypeU32(state), vertex[component], packed,
|
||||
ConstantU32(state, component * 10u), ConstantU32(state, 10)});
|
||||
spv::OpBitFieldUExtract, TypeU32(state), vertex[component], packed,
|
||||
ConstantU32(state, component * 10u), ConstantU32(state, 10));
|
||||
}
|
||||
const auto triangle = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, TypeU32Vector(state, 3), triangle,
|
||||
vertex[0], vertex[1], vertex[2]});
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(state, 3), triangle,
|
||||
vertex[0], vertex[1], vertex[2]);
|
||||
const auto triangle_pointer =
|
||||
MeshElement(state, state.mesh_primitives, spv::StorageClassOutput,
|
||||
TypeU32Vector(state, 3), index);
|
||||
state.builder.AddFunction({spv::OpStore, triangle_pointer, triangle});
|
||||
state.builder.AddFunction(spv::OpStore, triangle_pointer, triangle);
|
||||
const auto null_bit =
|
||||
EmitBinaryU32(state, spv::OpBitwiseAnd, packed, ConstantU32(state, 0x80000000u));
|
||||
const auto culled = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), culled, null_bit, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpStore,
|
||||
MeshElement(state, state.mesh_cull, spv::StorageClassOutput,
|
||||
TypeBool(state), index),
|
||||
culled});
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), culled, null_bit,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpStore,
|
||||
MeshElement(state, state.mesh_cull, spv::StorageClassOutput,
|
||||
TypeBool(state), index),
|
||||
culled);
|
||||
for (const auto& output: state.outputs) {
|
||||
if (output.kind != IR::StageOutputKind::Layer) {
|
||||
continue;
|
||||
@@ -194,13 +194,13 @@ void EmitMeshEntryPoint(EmitterState& state) {
|
||||
vertex[state.input_info.vertex->mesh.provoking_vertex]);
|
||||
const auto pointer = MeshElement(state, output.variable_id, spv::StorageClassOutput,
|
||||
TypeU32(state), index);
|
||||
state.builder.AddFunction({spv::OpStore, pointer, layer});
|
||||
state.builder.AddFunction(spv::OpStore, pointer, layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
state.lane_half = 0;
|
||||
state.builder.AddFunction({spv::OpReturn});
|
||||
state.builder.AddFunction({spv::OpFunctionEnd});
|
||||
state.builder.AddFunction(spv::OpReturn);
|
||||
state.builder.AddFunction(spv::OpFunctionEnd);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter
|
||||
@@ -13,11 +13,11 @@ uint32_t TypeBool(EmitterState& state) {
|
||||
}
|
||||
|
||||
uint32_t TypeBoolVector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(spv::OpTypeVector, {TypeBool(state), components});
|
||||
return state.builder.Type(spv::OpTypeVector, TypeBool(state), components);
|
||||
}
|
||||
|
||||
uint32_t TypeU32(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeInt, {32, 0});
|
||||
return state.builder.Type(spv::OpTypeInt, 32, 0);
|
||||
}
|
||||
|
||||
uint32_t TypeU64(EmitterState& state) {
|
||||
@@ -25,29 +25,29 @@ uint32_t TypeU64(EmitterState& state) {
|
||||
}
|
||||
|
||||
uint32_t TypeScalarU64(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeInt, {64, 0});
|
||||
return state.builder.Type(spv::OpTypeInt, 64, 0);
|
||||
}
|
||||
|
||||
uint32_t TypeU32Pair(EmitterState& state) {
|
||||
const auto element = TypeU32(state);
|
||||
return state.builder.Type(spv::OpTypeStruct, {element, element});
|
||||
return state.builder.Type(spv::OpTypeStruct, element, element);
|
||||
}
|
||||
|
||||
uint32_t TypeI32(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeInt, {32, 1});
|
||||
return state.builder.Type(spv::OpTypeInt, 32, 1);
|
||||
}
|
||||
|
||||
uint32_t TypeI32Pair(EmitterState& state) {
|
||||
const auto element = TypeI32(state);
|
||||
return state.builder.Type(spv::OpTypeStruct, {element, element});
|
||||
return state.builder.Type(spv::OpTypeStruct, element, element);
|
||||
}
|
||||
|
||||
uint32_t TypeF32(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeFloat, {32});
|
||||
return state.builder.Type(spv::OpTypeFloat, 32);
|
||||
}
|
||||
|
||||
uint32_t TypeU32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(spv::OpTypeVector, {TypeU32(state), components});
|
||||
return state.builder.Type(spv::OpTypeVector, TypeU32(state), components);
|
||||
}
|
||||
|
||||
uint32_t TypeU32Composite(EmitterState& state, uint32_t components) {
|
||||
@@ -56,31 +56,32 @@ uint32_t TypeU32Composite(EmitterState& state, uint32_t components) {
|
||||
}
|
||||
|
||||
uint32_t TypeI32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(spv::OpTypeVector, {TypeI32(state), components});
|
||||
return state.builder.Type(spv::OpTypeVector, TypeI32(state), components);
|
||||
}
|
||||
|
||||
uint32_t TypeF32Vector(EmitterState& state, uint32_t components) {
|
||||
return state.builder.Type(spv::OpTypeVector, {TypeF32(state), components});
|
||||
return state.builder.Type(spv::OpTypeVector, TypeF32(state), components);
|
||||
}
|
||||
|
||||
uint32_t TypePointer(EmitterState& state, spv::StorageClass storage_class, uint32_t pointee) {
|
||||
return state.builder.Type(spv::OpTypePointer, {storage_class, pointee});
|
||||
return state.builder.Type(spv::OpTypePointer, storage_class, pointee);
|
||||
}
|
||||
|
||||
uint32_t TypeFunction(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeFunction, {TypeVoid(state)});
|
||||
return state.builder.Type(spv::OpTypeFunction, TypeVoid(state));
|
||||
}
|
||||
|
||||
uint32_t StorageRuntimeArrayType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(
|
||||
spv::OpTypeRuntimeArray, {TypeU32(state)},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
spv::OpTypeRuntimeArray,
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}}, TypeU32(state));
|
||||
}
|
||||
|
||||
uint32_t StorageBufferType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct, {StorageRuntimeArrayType(state)},
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct,
|
||||
{{spv::OpMemberDecorate, {0, spv::DecorationOffset, 0}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}},
|
||||
StorageRuntimeArrayType(state));
|
||||
}
|
||||
|
||||
uint32_t TypeStorageBufferPointer(EmitterState& state) {
|
||||
@@ -93,14 +94,15 @@ uint32_t TypeStorageBufferElementPointer(EmitterState& state) {
|
||||
|
||||
uint32_t StorageU64RuntimeArrayType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(
|
||||
spv::OpTypeRuntimeArray, {TypeScalarU64(state)},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint64_t)}}});
|
||||
spv::OpTypeRuntimeArray,
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint64_t)}}}, TypeScalarU64(state));
|
||||
}
|
||||
|
||||
uint32_t StorageBufferU64Type(EmitterState& state) {
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct, {StorageU64RuntimeArrayType(state)},
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct,
|
||||
{{spv::OpMemberDecorate, {0, spv::DecorationOffset, 0}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}},
|
||||
StorageU64RuntimeArrayType(state));
|
||||
}
|
||||
|
||||
uint32_t TypeStorageBufferU64Pointer(EmitterState& state) {
|
||||
@@ -122,7 +124,7 @@ uint32_t TypePushConstantElementPointer(EmitterState& state) {
|
||||
uint32_t TypeU32ArrayPointer(EmitterState& state, spv::StorageClass storage_class,
|
||||
uint32_t dwords) {
|
||||
const auto count = ConstantU32(state, std::max(dwords, 1u));
|
||||
const auto array = state.builder.Type(spv::OpTypeArray, {TypeU32(state), count});
|
||||
const auto array = state.builder.Type(spv::OpTypeArray, TypeU32(state), count);
|
||||
return TypePointer(state, storage_class, array);
|
||||
}
|
||||
|
||||
@@ -135,29 +137,31 @@ namespace {
|
||||
uint32_t PushConstantArrayType(EmitterState& state) {
|
||||
const auto count = ConstantU32(state, IR::PushData::DwordCount);
|
||||
return state.builder.DecoratedType(
|
||||
spv::OpTypeArray, {TypeU32(state), count},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
spv::OpTypeArray, {{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}},
|
||||
TypeU32(state), count);
|
||||
}
|
||||
|
||||
uint32_t PushConstantBlockType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct, {PushConstantArrayType(state)},
|
||||
return state.builder.DecoratedType(spv::OpTypeStruct,
|
||||
{{spv::OpMemberDecorate, {0, spv::DecorationOffset, 0}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}},
|
||||
PushConstantArrayType(state));
|
||||
}
|
||||
|
||||
uint32_t PerVertexType(EmitterState& state) {
|
||||
return state.builder.DecoratedType(
|
||||
spv::OpTypeStruct, {TypeF32Vector(state, 4)},
|
||||
spv::OpTypeStruct,
|
||||
{{spv::OpMemberDecorate, {0, spv::DecorationBuiltIn, spv::BuiltInPosition}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}},
|
||||
TypeF32Vector(state, 4));
|
||||
}
|
||||
|
||||
uint32_t SampleMaskArrayType(EmitterState& state) {
|
||||
return state.builder.Type(spv::OpTypeArray, {TypeI32(state), ConstantU32(state, 1)});
|
||||
return state.builder.Type(spv::OpTypeArray, TypeI32(state), ConstantU32(state, 1));
|
||||
}
|
||||
|
||||
uint32_t F32ArrayType(EmitterState& state, uint32_t count) {
|
||||
return state.builder.Type(spv::OpTypeArray, {TypeF32(state), ConstantU32(state, count)});
|
||||
return state.builder.Type(spv::OpTypeArray, TypeF32(state), ConstantU32(state, count));
|
||||
}
|
||||
|
||||
void DefineDescriptors(EmitterState& state) {
|
||||
@@ -174,16 +178,15 @@ void DefineDescriptors(EmitterState& state) {
|
||||
const auto variable =
|
||||
state.builder.DefineGlobalVariable(TypePointer(state, storage, type), storage);
|
||||
state.builder.AddName(variable, name);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, variable, spv::DecorationDescriptorSet, 0});
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationBinding,
|
||||
IR::NativeBinding(state.program.stage, binding.kind)});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationDescriptorSet, 0);
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationBinding,
|
||||
IR::NativeBinding(state.program.stage, binding.kind));
|
||||
return variable;
|
||||
};
|
||||
const auto ArrayType = [&](uint32_t type) {
|
||||
return state.builder.Type(
|
||||
spv::OpTypeArray,
|
||||
{type, ConstantU32(state, static_cast<uint32_t>(binding.resources.size()))});
|
||||
spv::OpTypeArray, type,
|
||||
ConstantU32(state, static_cast<uint32_t>(binding.resources.size())));
|
||||
};
|
||||
switch (binding.kind) {
|
||||
case IR::DescriptorBindingKind::Buffers:
|
||||
@@ -192,10 +195,10 @@ void DefineDescriptors(EmitterState& state) {
|
||||
if (state.requirements.buffer_int64_atomics) {
|
||||
state.storage_buffer_u64_variable =
|
||||
Define(ArrayType(StorageBufferU64Type(state)), "buffers_u64");
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, state.storage_buffer_variable, spv::DecorationAliased});
|
||||
state.builder.AddAnnotation({spv::OpDecorate, state.storage_buffer_u64_variable,
|
||||
spv::DecorationAliased});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.storage_buffer_variable,
|
||||
spv::DecorationAliased);
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.storage_buffer_u64_variable,
|
||||
spv::DecorationAliased);
|
||||
}
|
||||
break;
|
||||
case IR::DescriptorBindingKind::BdaPagetable:
|
||||
@@ -242,15 +245,15 @@ void DefineDescriptors(EmitterState& state) {
|
||||
} // namespace
|
||||
|
||||
uint32_t ConstantU32(EmitterState& state, uint32_t value) {
|
||||
return state.builder.Constant(spv::OpConstant, TypeU32(state), {value});
|
||||
return state.builder.Constant(spv::OpConstant, TypeU32(state), value);
|
||||
}
|
||||
|
||||
uint32_t ConstantI32(EmitterState& state, int32_t value) {
|
||||
return state.builder.Constant(spv::OpConstant, TypeI32(state), {static_cast<uint32_t>(value)});
|
||||
return state.builder.Constant(spv::OpConstant, TypeI32(state), static_cast<uint32_t>(value));
|
||||
}
|
||||
|
||||
uint32_t ConstantF32(EmitterState& state, uint32_t bits) {
|
||||
return state.builder.Constant(spv::OpConstant, TypeF32(state), {bits});
|
||||
return state.builder.Constant(spv::OpConstant, TypeF32(state), bits);
|
||||
}
|
||||
|
||||
uint32_t FloatBits(float value) {
|
||||
@@ -270,8 +273,8 @@ uint32_t ConstantBool(EmitterState& state, bool value) {
|
||||
|
||||
uint32_t ConstantU64(EmitterState& state, uint64_t value) {
|
||||
return state.builder.Constant(spv::OpConstantComposite, TypeU64(state),
|
||||
{ConstantU32(state, static_cast<uint32_t>(value)),
|
||||
ConstantU32(state, static_cast<uint32_t>(value >> 32u))});
|
||||
ConstantU32(state, static_cast<uint32_t>(value)),
|
||||
ConstantU32(state, static_cast<uint32_t>(value >> 32u)));
|
||||
}
|
||||
|
||||
uint32_t ConstantU32CompositeZero(EmitterState& state, uint32_t components) {
|
||||
@@ -400,11 +403,11 @@ void DefineInputs(EmitterState& state) {
|
||||
state, VertexParameterScalarKind(state, input.location));
|
||||
const auto components = VertexParameterComponentCount(input);
|
||||
if (components > 1u) {
|
||||
type = state.builder.Type(spv::OpTypeVector, {type, components});
|
||||
type = state.builder.Type(spv::OpTypeVector, type, components);
|
||||
}
|
||||
} else if (input.per_vertex) {
|
||||
type = state.builder.Type(spv::OpTypeArray,
|
||||
{TypeF32Vector(state, 4), ConstantU32(state, 3)});
|
||||
type = state.builder.Type(spv::OpTypeArray, TypeF32Vector(state, 4),
|
||||
ConstantU32(state, 3));
|
||||
} else {
|
||||
type = TypeF32Vector(state, 4);
|
||||
}
|
||||
@@ -414,38 +417,37 @@ void DefineInputs(EmitterState& state) {
|
||||
input.variable_id =
|
||||
DefineInterfaceVariable(state, type, spv::StorageClassInput, input.debug_name.c_str());
|
||||
if (input.kind == IR::StageInputKind::Layer || input.kind == IR::StageInputKind::SampleId) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, input.variable_id, spv::DecorationFlat});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id, spv::DecorationFlat);
|
||||
}
|
||||
if (input.kind == IR::StageInputKind::Parameter) {
|
||||
const auto flat = PixelParameterIsFlat(state, input.location);
|
||||
if (input.per_vertex) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationPerVertexKHR});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id,
|
||||
spv::DecorationPerVertexKHR);
|
||||
} else if (flat) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationFlat});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id,
|
||||
spv::DecorationFlat);
|
||||
}
|
||||
if (state.program.stage == ShaderType::Pixel &&
|
||||
state.input_info.pixel->ps_no_perspective && !flat && !input.per_vertex) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationNoPerspective});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id,
|
||||
spv::DecorationNoPerspective);
|
||||
}
|
||||
state.builder.AddAnnotation({spv::OpDecorate, input.variable_id,
|
||||
spv::DecorationLocation,
|
||||
PixelParameterLocation(state, input.location)});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id, spv::DecorationLocation,
|
||||
PixelParameterLocation(state, input.location));
|
||||
} else if (const auto builtin = BuiltInForInput(input.kind); builtin != UINT32_MAX) {
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, input.variable_id, spv::DecorationBuiltIn, builtin});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, input.variable_id, spv::DecorationBuiltIn,
|
||||
builtin);
|
||||
}
|
||||
}
|
||||
if (state.requirements.subgroup_local_invocation_id) {
|
||||
const auto variable = DefineInterfaceVariable(state, TypeU32(state), spv::StorageClassInput,
|
||||
"gl_SubgroupInvocationID");
|
||||
state.subgroup_local_invocation_id_variable = variable;
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationBuiltIn,
|
||||
spv::BuiltInSubgroupLocalInvocationId});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationBuiltIn,
|
||||
spv::BuiltInSubgroupLocalInvocationId);
|
||||
if (state.program.stage == ShaderType::Pixel) {
|
||||
state.builder.AddAnnotation({spv::OpDecorate, variable, spv::DecorationFlat});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationFlat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -470,8 +472,7 @@ void DefineOutputs(EmitterState& state) {
|
||||
spv::BuiltIn builtin) {
|
||||
if (variable == 0) {
|
||||
variable = DefineInterfaceVariable(state, type, spv::StorageClassOutput, name);
|
||||
state.builder.AddAnnotation(
|
||||
{spv::OpDecorate, variable, spv::DecorationBuiltIn, builtin});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationBuiltIn, builtin);
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
@@ -527,8 +528,8 @@ void DefineOutputs(EmitterState& state) {
|
||||
const auto type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
|
||||
binding.variable_id = DefineInterfaceVariable(state, type, spv::StorageClassOutput,
|
||||
binding.debug_name.c_str());
|
||||
state.builder.AddAnnotation({spv::OpDecorate, binding.variable_id,
|
||||
spv::DecorationLocation, binding.location});
|
||||
state.builder.AddAnnotation(spv::OpDecorate, binding.variable_id,
|
||||
spv::DecorationLocation, binding.location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -556,12 +557,12 @@ void DefineModule(EmitterState& state) {
|
||||
state.mesh_guest_func = state.builder.AllocateId();
|
||||
state.builder.RequireCapability(spv::CapabilityMeshShadingEXT); // MeshShadingEXT
|
||||
state.builder.RequireExtension("SPV_EXT_mesh_shader");
|
||||
state.builder.AddExecutionMode(
|
||||
{state.main_func, spv::ExecutionModeOutputTrianglesEXT}); // OutputTrianglesEXT
|
||||
state.builder.AddExecutionMode({state.main_func, spv::ExecutionModeOutputVertices,
|
||||
state.input_info.vertex->mesh.max_vertices});
|
||||
state.builder.AddExecutionMode({state.main_func, spv::ExecutionModeOutputPrimitivesEXT,
|
||||
state.input_info.vertex->mesh.max_primitives});
|
||||
state.builder.AddExecutionMode(state.main_func,
|
||||
spv::ExecutionModeOutputTrianglesEXT); // OutputTrianglesEXT
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputVertices,
|
||||
state.input_info.vertex->mesh.max_vertices);
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputPrimitivesEXT,
|
||||
state.input_info.vertex->mesh.max_primitives);
|
||||
}
|
||||
state.entry_label = state.builder.AllocateId();
|
||||
|
||||
@@ -621,14 +622,14 @@ void DefineModule(EmitterState& state) {
|
||||
state.builder.RequireExtension("SPV_KHR_fragment_shader_barycentric");
|
||||
}
|
||||
state.builder.RequireExtension("SPV_KHR_float_controls");
|
||||
state.builder.AddMemoryModel({state.program.info.uses_dma
|
||||
? spv::AddressingModelPhysicalStorageBuffer64
|
||||
: spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450});
|
||||
state.builder.AddMemoryModel(state.program.info.uses_dma
|
||||
? spv::AddressingModelPhysicalStorageBuffer64
|
||||
: spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450);
|
||||
// GCN/RDNA arithmetic preserves 32-bit signed zero, infinity, and NaN. Declaring that
|
||||
// contract prevents host compilers from treating synthesized IEEE values as finite.
|
||||
state.builder.AddExecutionMode(
|
||||
{state.main_func, spv::ExecutionModeSignedZeroInfNanPreserve, 32u});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeSignedZeroInfNanPreserve,
|
||||
32u);
|
||||
if (const auto* cs = ShaderWorkgroupInput(state.program.stage, state.input_info)) {
|
||||
uint32_t local_x = state.requirements.compute_derivatives ? 2u : 1u;
|
||||
uint32_t local_y = state.requirements.compute_derivatives ? 2u : 1u;
|
||||
@@ -644,23 +645,22 @@ void DefineModule(EmitterState& state) {
|
||||
local_x = 2u;
|
||||
}
|
||||
}
|
||||
state.builder.AddExecutionMode(
|
||||
{state.main_func, spv::ExecutionModeLocalSize, local_x, local_y, local_z});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeLocalSize, local_x,
|
||||
local_y, local_z);
|
||||
}
|
||||
if (state.program.stage == ShaderType::Pixel) {
|
||||
state.builder.AddExecutionMode({state.main_func, spv::ExecutionModeOriginUpperLeft});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOriginUpperLeft);
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.AddExecutionMode({state.main_func, spv::ExecutionModeDepthReplacing});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeDepthReplacing);
|
||||
}
|
||||
if (state.input_info.pixel->ps_early_z && !state.input_info.pixel->ps_pixel_kill_enable &&
|
||||
!state.input_info.pixel->ps_depth_export_enable &&
|
||||
!state.input_info.pixel->ps_sample_mask_export_enable) {
|
||||
state.builder.AddExecutionMode({state.main_func, spv::ExecutionModeEarlyFragmentTests});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeEarlyFragmentTests);
|
||||
}
|
||||
}
|
||||
if (state.requirements.compute_derivatives && state.program.stage == ShaderType::Compute) {
|
||||
state.builder.AddExecutionMode(
|
||||
{state.main_func, spv::ExecutionModeDerivativeGroupQuadsKHR});
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeDerivativeGroupQuadsKHR);
|
||||
}
|
||||
state.builder.AddName(state.main_func, "main");
|
||||
if (state.requirements.function_lds) {
|
||||
|
||||
@@ -17,11 +17,11 @@ 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({spv::OpLogicalNot, TypeBool(state), inactive, active});
|
||||
state.builder.AddFunction({spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction({spv::OpBranchConditional, inactive, kill_label, merge_label});
|
||||
state.builder.AddFunction(spv::OpLogicalNot, TypeBool(state), inactive, active);
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, merge_label, spv::SelectionControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, inactive, kill_label, merge_label);
|
||||
EmitLabel(state, kill_label);
|
||||
state.builder.AddFunction({spv::OpKill});
|
||||
state.builder.AddFunction(spv::OpKill);
|
||||
EmitLabel(state, merge_label);
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ void EmitKillIfPixelValidMaskInactive(EmitterState& state) {
|
||||
|
||||
const auto mask_value = state.builder.AllocateId();
|
||||
const auto active = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpLoad, TypeU32(state), mask_value, state.pixel_valid_mask_variable});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), active, mask_value, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeU32(state), mask_value,
|
||||
state.pixel_valid_mask_variable);
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), active, mask_value,
|
||||
ConstantU32(state, 0));
|
||||
EmitKillIfBoolFalse(state, active);
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ void StoreDispatcherPhiEdge(ValueEmitContext& ctx, const DispatcherFunctionState
|
||||
}
|
||||
for (size_t index = 0; index < phi.NumArgs(); index++) {
|
||||
if (phi.PhiBlock(index) == from) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpStore, dispatcher.spills[ctx.half].at(&phi), ctx.Def(phi.Arg(index))});
|
||||
ctx.state.builder.AddFunction(spv::OpStore, dispatcher.spills[ctx.half].at(&phi),
|
||||
ctx.Def(phi.Arg(index)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ const IR::Block* TargetBlock(const IR::Program& program, uint32_t id) {
|
||||
|
||||
void EmitReturn(ValueEmitContext& ctx) {
|
||||
EmitKillIfPixelValidMaskInactive(ctx.state);
|
||||
ctx.state.builder.AddFunction({spv::OpReturn});
|
||||
ctx.state.builder.AddFunction(spv::OpReturn);
|
||||
}
|
||||
|
||||
uint32_t BranchCondition(ValueEmitContext& ctx, const IR::BlockInfo& info) {
|
||||
@@ -108,16 +108,16 @@ uint32_t BranchCondition(ValueEmitContext& ctx, const IR::BlockInfo& info) {
|
||||
const auto low = ctx.state.builder.AllocateId();
|
||||
const auto high = ctx.state.builder.AllocateId();
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(ctx.state), low, ballot, 0});
|
||||
ctx.state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(ctx.state), high, ballot, 1});
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), low, ballot, 0);
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state), high, ballot, 1);
|
||||
const auto kind = info.terminator.condition;
|
||||
const bool zero = kind == CFG::BranchCondition::ExecZero ||
|
||||
kind == CFG::BranchCondition::VccZero ||
|
||||
kind == CFG::BranchCondition::SccZero;
|
||||
const auto combined =
|
||||
EmitBinaryU32(ctx.state, zero ? spv::OpBitwiseAnd : spv::OpBitwiseOr, low, high);
|
||||
ctx.state.builder.AddFunction({zero ? spv::OpIEqual : spv::OpINotEqual, TypeBool(ctx.state),
|
||||
result, combined, ConstantU32(ctx.state, zero ? ~0u : 0u)});
|
||||
ctx.state.builder.AddFunction(zero ? spv::OpIEqual : spv::OpINotEqual, TypeBool(ctx.state),
|
||||
result, combined, ConstantU32(ctx.state, zero ? ~0u : 0u));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -130,14 +130,14 @@ void EmitStructuredTerminator(ValueEmitContext& ctx, const IR::Block* block,
|
||||
const auto* merge = TargetBlock(program, term.merge_block);
|
||||
const auto* cont = TargetBlock(program, term.continue_block);
|
||||
if (merge != nullptr && cont != nullptr) {
|
||||
ctx.state.builder.AddFunction({spv::OpLoopMerge, ctx.Label(merge), ctx.Label(cont),
|
||||
spv::LoopControlMaskNone});
|
||||
ctx.state.builder.AddFunction(spv::OpLoopMerge, ctx.Label(merge), ctx.Label(cont),
|
||||
spv::LoopControlMaskNone);
|
||||
}
|
||||
} else if (term.kind == CFG::TerminatorKind::ConditionalBranch &&
|
||||
term.merge_block != UINT32_MAX) {
|
||||
if (const auto* merge = TargetBlock(program, term.merge_block); merge != nullptr) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpSelectionMerge, ctx.Label(merge), spv::SelectionControlMaskNone});
|
||||
ctx.state.builder.AddFunction(spv::OpSelectionMerge, ctx.Label(merge),
|
||||
spv::SelectionControlMaskNone);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -150,7 +150,7 @@ void EmitStructuredTerminator(ValueEmitContext& ctx, const IR::Block* block,
|
||||
return;
|
||||
}
|
||||
emit_merge();
|
||||
ctx.state.builder.AddFunction({spv::OpBranch, ctx.Label(target)});
|
||||
ctx.state.builder.AddFunction(spv::OpBranch, ctx.Label(target));
|
||||
return;
|
||||
}
|
||||
case CFG::TerminatorKind::ConditionalBranch: {
|
||||
@@ -162,8 +162,8 @@ void EmitStructuredTerminator(ValueEmitContext& ctx, const IR::Block* block,
|
||||
}
|
||||
const auto condition = BranchCondition(ctx, info);
|
||||
emit_merge();
|
||||
ctx.state.builder.AddFunction({spv::OpBranchConditional, condition,
|
||||
ctx.Label(true_block), ctx.Label(false_block)});
|
||||
ctx.state.builder.AddFunction(spv::OpBranchConditional, condition,
|
||||
ctx.Label(true_block), ctx.Label(false_block));
|
||||
return;
|
||||
}
|
||||
default: EmitReturn(ctx); return;
|
||||
@@ -192,10 +192,9 @@ uint32_t EmitDispatcherNextPc(ValueEmitContext& ctx, const DispatcherFunctionSta
|
||||
EmitDispatcherTarget(ctx, dispatcher, block, term.true_block);
|
||||
EmitDispatcherTarget(ctx, dispatcher, block, term.false_block);
|
||||
const auto selected = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({spv::OpSelect, TypeU32(ctx.state), selected,
|
||||
BranchCondition(ctx, info),
|
||||
ConstantU32(ctx.state, term.true_block),
|
||||
ConstantU32(ctx.state, term.false_block)});
|
||||
ctx.state.builder.AddFunction(
|
||||
spv::OpSelect, TypeU32(ctx.state), selected, BranchCondition(ctx, info),
|
||||
ConstantU32(ctx.state, term.true_block), ConstantU32(ctx.state, term.false_block));
|
||||
return selected;
|
||||
}
|
||||
case CFG::TerminatorKind::IndirectBranch: {
|
||||
@@ -214,12 +213,10 @@ uint32_t EmitDispatcherNextPc(ValueEmitContext& ctx, const DispatcherFunctionSta
|
||||
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({spv::OpIEqual, TypeBool(ctx.state), match,
|
||||
selector,
|
||||
ConstantU32(ctx.state, values[index])});
|
||||
ctx.state.builder.AddFunction({spv::OpSelect, TypeU32(ctx.state), next, match,
|
||||
ConstantU32(ctx.state, targets[index]),
|
||||
selected});
|
||||
ctx.state.builder.AddFunction(spv::OpIEqual, TypeBool(ctx.state), match,
|
||||
selector, ConstantU32(ctx.state, values[index]));
|
||||
ctx.state.builder.AddFunction(spv::OpSelect, TypeU32(ctx.state), next, match,
|
||||
ConstantU32(ctx.state, targets[index]), selected);
|
||||
selected = next;
|
||||
}
|
||||
}
|
||||
@@ -307,15 +304,15 @@ void EmitDispatcherInstruction(ValueEmitContext& ctx, const DispatcherFunctionSt
|
||||
if (type == 0) {
|
||||
ctx.Fail(inst, "cannot be loaded by the dispatcher");
|
||||
}
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpLoad, type, ctx.Result(inst), dispatcher.spills[ctx.half].at(&inst)});
|
||||
ctx.state.builder.AddFunction(spv::OpLoad, type, ctx.Result(inst),
|
||||
dispatcher.spills[ctx.half].at(&inst));
|
||||
return;
|
||||
}
|
||||
EmitDirectInstruction(ctx, inst);
|
||||
if (const auto found = dispatcher.spills[ctx.half].find(&inst);
|
||||
found != dispatcher.spills[ctx.half].end()) {
|
||||
ctx.state.builder.AddFunction(
|
||||
{spv::OpStore, found->second, ctx.Def(IR::Value(const_cast<IR::Inst*>(&inst)))});
|
||||
ctx.state.builder.AddFunction(spv::OpStore, found->second,
|
||||
ctx.Def(IR::Value(const_cast<IR::Inst*>(&inst))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +359,7 @@ void PatchStructuredPhis(ValueEmitContext& ctx, StructuredFunctionState& structu
|
||||
void EmitStructuredFunction(ValueEmitContext& ctx) {
|
||||
const auto& program = ctx.state.program;
|
||||
StructuredFunctionState structured;
|
||||
ctx.state.builder.AddFunction({spv::OpBranch, ctx.Label(program.blocks.front())});
|
||||
ctx.state.builder.AddFunction(spv::OpBranch, ctx.Label(program.blocks.front()));
|
||||
for (size_t index = 0; index < program.blocks.size(); index++) {
|
||||
const auto* block = program.blocks[index];
|
||||
EmitBlock(ctx, block, [&](ValueEmitContext& lane, const IR::Inst& inst) {
|
||||
@@ -377,31 +374,31 @@ void EmitStructuredFunction(ValueEmitContext& ctx) {
|
||||
void EmitDispatcherFunction(ValueEmitContext& ctx, const DispatcherFunctionState& dispatcher) {
|
||||
auto& state = ctx.state;
|
||||
const auto* entry = state.program.blocks.front();
|
||||
state.builder.AddFunction({spv::OpBranch, ctx.Label(entry)});
|
||||
state.builder.AddFunction(spv::OpBranch, ctx.Label(entry));
|
||||
EmitBlock(ctx, entry, [&](ValueEmitContext& lane, const IR::Inst& inst) {
|
||||
EmitDispatcherInstruction(lane, dispatcher, inst);
|
||||
});
|
||||
const auto initial_pc =
|
||||
EmitDispatcherNextPc(ctx, dispatcher, entry, state.program.block_info.front());
|
||||
const auto initial_parent = state.current_label;
|
||||
state.builder.AddFunction({spv::OpBranch, dispatcher.header_label});
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.header_label);
|
||||
|
||||
EmitLabel(state, dispatcher.header_label);
|
||||
const auto pc = state.builder.AllocateId();
|
||||
const auto next_pc = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpPhi, TypeU32(state), pc, initial_pc, initial_parent, next_pc,
|
||||
dispatcher.continue_label});
|
||||
state.builder.AddFunction(spv::OpPhi, TypeU32(state), pc, initial_pc, initial_parent, next_pc,
|
||||
dispatcher.continue_label);
|
||||
const auto done = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpIEqual, TypeBool(state), done, pc, ConstantU32(ctx.state, UINT32_MAX)});
|
||||
state.builder.AddFunction({spv::OpLoopMerge, dispatcher.merge_label, dispatcher.continue_label,
|
||||
spv::LoopControlMaskNone});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpBranchConditional, done, dispatcher.merge_label, dispatcher.select_label});
|
||||
state.builder.AddFunction(spv::OpIEqual, TypeBool(state), done, pc,
|
||||
ConstantU32(ctx.state, UINT32_MAX));
|
||||
state.builder.AddFunction(spv::OpLoopMerge, dispatcher.merge_label, dispatcher.continue_label,
|
||||
spv::LoopControlMaskNone);
|
||||
state.builder.AddFunction(spv::OpBranchConditional, done, dispatcher.merge_label,
|
||||
dispatcher.select_label);
|
||||
|
||||
EmitLabel(state, dispatcher.select_label);
|
||||
state.builder.AddFunction(
|
||||
{spv::OpSelectionMerge, dispatcher.after_switch_label, spv::SelectionControlMaskNone});
|
||||
state.builder.AddFunction(spv::OpSelectionMerge, dispatcher.after_switch_label,
|
||||
spv::SelectionControlMaskNone);
|
||||
std::vector<uint32_t> words {spv::OpSwitch, pc, dispatcher.after_switch_label};
|
||||
for (size_t index = 1; index < state.program.blocks.size(); index++) {
|
||||
words.push_back(state.program.block_info[index].id);
|
||||
@@ -420,13 +417,13 @@ void EmitDispatcherFunction(ValueEmitContext& ctx, const DispatcherFunctionState
|
||||
state.program.block_info[index]);
|
||||
next_pc_words.push_back(selected);
|
||||
next_pc_words.push_back(state.current_label);
|
||||
state.builder.AddFunction({spv::OpBranch, dispatcher.after_switch_label});
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.after_switch_label);
|
||||
}
|
||||
EmitLabel(state, dispatcher.after_switch_label);
|
||||
state.builder.AddFunction(next_pc_words);
|
||||
state.builder.AddFunction({spv::OpBranch, dispatcher.continue_label});
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.continue_label);
|
||||
EmitLabel(state, dispatcher.continue_label);
|
||||
state.builder.AddFunction({spv::OpBranch, dispatcher.header_label});
|
||||
state.builder.AddFunction(spv::OpBranch, dispatcher.header_label);
|
||||
EmitLabel(state, dispatcher.merge_label);
|
||||
EmitReturn(ctx);
|
||||
}
|
||||
@@ -478,7 +475,8 @@ uint32_t ValueEmitContext::Def(IR::Value value) {
|
||||
return loaded->second.second;
|
||||
}
|
||||
const auto id = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpLoad, TypeId(state, inst->GetType()), id, found->second});
|
||||
state.builder.AddFunction(spv::OpLoad, TypeId(state, inst->GetType()), id,
|
||||
found->second);
|
||||
dispatcher_block_loads.insert_or_assign(inst, std::pair {state.current_label, id});
|
||||
return id;
|
||||
}
|
||||
@@ -498,9 +496,9 @@ uint32_t ValueEmitContext::Ballot(IR::Value predicate) {
|
||||
const auto ballot_type = TypeU32Vector(state, 4);
|
||||
const auto scope = ConstantU32(state, spv::ScopeSubgroup);
|
||||
const auto low = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpGroupNonUniformBallot, ballot_type, low, scope,
|
||||
other_half == nullptr || half == 0 ? Def(predicate) : other_half->Def(predicate)});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformBallot, ballot_type, low, scope,
|
||||
other_half == nullptr || half == 0 ? Def(predicate)
|
||||
: other_half->Def(predicate));
|
||||
if (other_half == nullptr) {
|
||||
return low;
|
||||
}
|
||||
@@ -508,20 +506,20 @@ uint32_t ValueEmitContext::Ballot(IR::Value predicate) {
|
||||
const auto low_word = state.builder.AllocateId();
|
||||
const auto high_word = state.builder.AllocateId();
|
||||
const auto ballot = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpGroupNonUniformBallot, ballot_type, high, scope,
|
||||
half == 1 ? Def(predicate) : other_half->Def(predicate)});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), low_word, low, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), high_word, high, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeConstruct, ballot_type, ballot, low_word, high_word,
|
||||
ConstantU32(state, 0), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformBallot, ballot_type, high, scope,
|
||||
half == 1 ? Def(predicate) : other_half->Def(predicate));
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), low_word, low, 0);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), high_word, high, 0);
|
||||
state.builder.AddFunction(spv::OpCompositeConstruct, ballot_type, ballot, low_word, high_word,
|
||||
ConstantU32(state, 0), ConstantU32(state, 0));
|
||||
return ballot;
|
||||
}
|
||||
|
||||
uint32_t ValueEmitContext::FirstLane(uint32_t ballot) {
|
||||
if (other_half == nullptr) {
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpGroupNonUniformBallotFindLSB, TypeU32(state), result,
|
||||
ConstantU32(state, spv::ScopeSubgroup), ballot});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformBallotFindLSB, TypeU32(state), result,
|
||||
ConstantU32(state, spv::ScopeSubgroup), ballot);
|
||||
return result;
|
||||
}
|
||||
const auto low = state.builder.AllocateId();
|
||||
@@ -530,16 +528,16 @@ uint32_t ValueEmitContext::FirstLane(uint32_t ballot) {
|
||||
const auto high_first = state.builder.AllocateId();
|
||||
const auto low_active = state.builder.AllocateId();
|
||||
const auto result = state.builder.AllocateId();
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), low, ballot, 0});
|
||||
state.builder.AddFunction({spv::OpCompositeExtract, TypeU32(state), high, ballot, 1});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpExtInst, TypeU32(state), low_first, GlslStd450(state), GLSLstd450FindILsb, low});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpExtInst, TypeU32(state), high_first, GlslStd450(state), GLSLstd450FindILsb, high});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), low_active, low, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpSelect, TypeU32(state), result, low_active, low_first,
|
||||
EmitAddU32(state, high_first, ConstantU32(state, 32))});
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), low, ballot, 0);
|
||||
state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(state), high, ballot, 1);
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeU32(state), low_first, GlslStd450(state),
|
||||
GLSLstd450FindILsb, low);
|
||||
state.builder.AddFunction(spv::OpExtInst, TypeU32(state), high_first, GlslStd450(state),
|
||||
GLSLstd450FindILsb, high);
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), low_active, low,
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), result, low_active, low_first,
|
||||
EmitAddU32(state, high_first, ConstantU32(state, 32)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -548,8 +546,8 @@ uint32_t ValueEmitContext::Shuffle(const IR::Inst& inst, size_t index, uint32_t
|
||||
const auto scope = ConstantU32(state, spv::ScopeSubgroup);
|
||||
const auto low = state.builder.AllocateId();
|
||||
if (other_half == nullptr) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpGroupNonUniformShuffle, type, low, scope, Arg(inst, index), lane});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, type, low, scope, Arg(inst, index),
|
||||
lane);
|
||||
return low;
|
||||
}
|
||||
const auto physical_lane =
|
||||
@@ -557,15 +555,14 @@ uint32_t ValueEmitContext::Shuffle(const IR::Inst& inst, size_t index, uint32_t
|
||||
const auto high = state.builder.AllocateId();
|
||||
const auto in_high = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpGroupNonUniformShuffle, type, low, scope, HalfArg(inst, index, 0), physical_lane});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpGroupNonUniformShuffle, type, high, scope, HalfArg(inst, index, 1), physical_lane});
|
||||
state.builder.AddFunction(
|
||||
{spv::OpINotEqual, TypeBool(state), in_high,
|
||||
EmitBinaryU32(state, spv::OpBitwiseAnd, lane, ConstantU32(state, 32)),
|
||||
ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({spv::OpSelect, type, value, in_high, high, low});
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, type, low, scope,
|
||||
HalfArg(inst, index, 0), physical_lane);
|
||||
state.builder.AddFunction(spv::OpGroupNonUniformShuffle, type, high, scope,
|
||||
HalfArg(inst, index, 1), physical_lane);
|
||||
state.builder.AddFunction(spv::OpINotEqual, TypeBool(state), in_high,
|
||||
EmitBinaryU32(state, spv::OpBitwiseAnd, lane, ConstantU32(state, 32)),
|
||||
ConstantU32(state, 0));
|
||||
state.builder.AddFunction(spv::OpSelect, type, value, in_high, high, low);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -581,8 +578,8 @@ uint32_t ValueEmitContext::Result(const IR::Inst& inst) {
|
||||
uint32_t ValueEmitContext::Define(const IR::Inst& inst, uint32_t value) {
|
||||
if (const auto found = definitions.find(&inst); found != definitions.end()) {
|
||||
if (found->second != value) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpCopyObject, TypeId(state, inst.GetType()), found->second, value});
|
||||
state.builder.AddFunction(spv::OpCopyObject, TypeId(state, inst.GetType()),
|
||||
found->second, value);
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
@@ -718,28 +715,28 @@ void EmitProgram(EmitterState& state) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.builder.AddFunction({spv::OpFunction, TypeVoid(state),
|
||||
state.mesh_guest_func != 0 ? state.mesh_guest_func : state.main_func,
|
||||
spv::FunctionControlMaskNone, TypeFunction(state)});
|
||||
state.builder.AddFunction(spv::OpFunction, TypeVoid(state),
|
||||
state.mesh_guest_func != 0 ? state.mesh_guest_func : state.main_func,
|
||||
spv::FunctionControlMaskNone, TypeFunction(state));
|
||||
EmitLabel(state, state.entry_label);
|
||||
if (state.requirements.function_lds) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpVariable,
|
||||
TypeU32ArrayPointer(state, spv::StorageClassFunction, LdsDwordCount(state)),
|
||||
state.lds_variable, spv::StorageClassFunction});
|
||||
spv::OpVariable,
|
||||
TypeU32ArrayPointer(state, spv::StorageClassFunction, LdsDwordCount(state)),
|
||||
state.lds_variable, spv::StorageClassFunction);
|
||||
}
|
||||
if (state.requirements.function_scratch) {
|
||||
for (uint32_t half = 0; half < state.lane_count; half++) {
|
||||
state.builder.AddFunction({spv::OpVariable,
|
||||
TypeU32ArrayPointer(state, spv::StorageClassFunction,
|
||||
state.program.scratch_dwords),
|
||||
state.scratch_variable[half], spv::StorageClassFunction});
|
||||
state.builder.AddFunction(
|
||||
spv::OpVariable,
|
||||
TypeU32ArrayPointer(state, spv::StorageClassFunction, state.program.scratch_dwords),
|
||||
state.scratch_variable[half], spv::StorageClassFunction);
|
||||
}
|
||||
}
|
||||
if (state.pixel_valid_mask_variable != 0) {
|
||||
state.builder.AddFunction({spv::OpVariable,
|
||||
TypePointer(state, spv::StorageClassFunction, TypeU32(state)),
|
||||
state.pixel_valid_mask_variable, spv::StorageClassFunction});
|
||||
state.builder.AddFunction(spv::OpVariable,
|
||||
TypePointer(state, spv::StorageClassFunction, TypeU32(state)),
|
||||
state.pixel_valid_mask_variable, spv::StorageClassFunction);
|
||||
}
|
||||
for (uint32_t half = 0; half < state.lane_count; half++) {
|
||||
auto& lane = half == 0 ? ctx : high;
|
||||
@@ -748,27 +745,27 @@ void EmitProgram(EmitterState& state) {
|
||||
for (const auto& inst: *block) {
|
||||
if (const auto found = dispatcher->spills[half].find(&inst);
|
||||
found != dispatcher->spills[half].end()) {
|
||||
state.builder.AddFunction({spv::OpVariable,
|
||||
SpillPointerType(lane, inst.GetType()),
|
||||
found->second, spv::StorageClassFunction});
|
||||
state.builder.AddFunction(spv::OpVariable,
|
||||
SpillPointerType(lane, inst.GetType()),
|
||||
found->second, spv::StorageClassFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lane.scratch_u32_variable != 0) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpVariable, TypePointer(state, spv::StorageClassFunction, TypeU32(state)),
|
||||
lane.scratch_u32_variable, spv::StorageClassFunction});
|
||||
state.builder.AddFunction(spv::OpVariable,
|
||||
TypePointer(state, spv::StorageClassFunction, TypeU32(state)),
|
||||
lane.scratch_u32_variable, spv::StorageClassFunction);
|
||||
}
|
||||
}
|
||||
if (state.gds_variable != 0) {
|
||||
state.gds_length = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{spv::OpArrayLength, TypeU32(state), state.gds_length, state.gds_variable, 0});
|
||||
state.builder.AddFunction(spv::OpArrayLength, TypeU32(state), state.gds_length,
|
||||
state.gds_variable, 0);
|
||||
}
|
||||
if (state.pixel_valid_mask_variable != 0) {
|
||||
state.builder.AddFunction(
|
||||
{spv::OpStore, state.pixel_valid_mask_variable, ConstantU32(state, 1)});
|
||||
state.builder.AddFunction(spv::OpStore, state.pixel_valid_mask_variable,
|
||||
ConstantU32(state, 1));
|
||||
}
|
||||
EmitMemoryOffsets(state);
|
||||
if (program.blocks.empty()) {
|
||||
@@ -778,7 +775,7 @@ void EmitProgram(EmitterState& state) {
|
||||
} else {
|
||||
EmitStructuredFunction(ctx);
|
||||
}
|
||||
state.builder.AddFunction({spv::OpFunctionEnd});
|
||||
state.builder.AddFunction(spv::OpFunctionEnd);
|
||||
if (state.program.stage == ShaderType::Mesh) {
|
||||
EmitMeshEntryPoint(state);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ constexpr OpcodeMap SOP2_OPCODE_LIST[] = {
|
||||
{0x31u, Opcode::S_LSHL4_ADD_U32}, {0x32u, Opcode::S_PACK_LL_B32_B16},
|
||||
{0x33u, Opcode::S_PACK_LH_B32_B16}, {0x34u, Opcode::S_PACK_HH_B32_B16},
|
||||
{0x35u, Opcode::S_MUL_HI_U32},
|
||||
{0x36u, Opcode::S_MUL_HI_I32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
|
||||
|
||||
@@ -108,6 +108,7 @@ enum class Opcode {
|
||||
S_ASHR_I32,
|
||||
S_MUL_I32,
|
||||
S_MUL_HI_U32,
|
||||
S_MUL_HI_I32,
|
||||
S_MULK_I32,
|
||||
S_BFE_U32,
|
||||
S_BFE_I32,
|
||||
@@ -189,6 +190,7 @@ enum class Opcode {
|
||||
V_CEIL_F16,
|
||||
V_TRUNC_F16,
|
||||
V_RNDNE_F16,
|
||||
V_FRACT_F16,
|
||||
V_SIN_F16,
|
||||
V_COS_F16,
|
||||
V_SIN_F32,
|
||||
@@ -394,6 +396,7 @@ enum class Opcode {
|
||||
V_CMP_EQ_U16,
|
||||
V_CMP_LE_U16,
|
||||
V_CMP_GT_U16,
|
||||
V_CMPX_LT_U16,
|
||||
V_CMPX_GT_U16,
|
||||
V_CMP_NE_U16,
|
||||
V_CMP_GE_U16,
|
||||
|
||||
@@ -139,6 +139,7 @@ constexpr OpcodeMap VOP1_OPCODE_LIST[] = {
|
||||
{0x5cu, Opcode::V_CEIL_F16},
|
||||
{0x5du, Opcode::V_TRUNC_F16},
|
||||
{0x5eu, Opcode::V_RNDNE_F16},
|
||||
{0x5fu, Opcode::V_FRACT_F16},
|
||||
{0x60u, Opcode::V_SIN_F16},
|
||||
{0x61u, Opcode::V_COS_F16},
|
||||
};
|
||||
@@ -192,6 +193,7 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = {
|
||||
{0x5cu, Opcode::V_CEIL_F16},
|
||||
{0x5du, Opcode::V_TRUNC_F16},
|
||||
{0x5eu, Opcode::V_RNDNE_F16},
|
||||
{0x5fu, Opcode::V_FRACT_F16},
|
||||
{0x60u, Opcode::V_SIN_F16},
|
||||
{0x61u, Opcode::V_COS_F16},
|
||||
};
|
||||
@@ -233,6 +235,7 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = {
|
||||
{0xa9u, Opcode::V_CMP_LT_U16}, {0xaau, Opcode::V_CMP_EQ_U16},
|
||||
{0xabu, Opcode::V_CMP_LE_U16}, {0xacu, Opcode::V_CMP_GT_U16},
|
||||
{0xadu, Opcode::V_CMP_NE_U16}, {0xaeu, Opcode::V_CMP_GE_U16},
|
||||
{0xb9u, Opcode::V_CMPX_LT_U16, false},
|
||||
{0xbcu, Opcode::V_CMPX_GT_U16}, {0xc0u, Opcode::V_CMP_F_U32},
|
||||
{0xc1u, Opcode::V_CMP_LT_U32}, {0xc2u, Opcode::V_CMP_EQ_U32},
|
||||
{0xc3u, Opcode::V_CMP_LE_U32}, {0xc4u, Opcode::V_CMP_GT_U32},
|
||||
@@ -479,6 +482,7 @@ bool IsVop1FloatSourceOpcode(Opcode opcode) {
|
||||
case Opcode::V_CEIL_F16:
|
||||
case Opcode::V_TRUNC_F16:
|
||||
case Opcode::V_RNDNE_F16:
|
||||
case Opcode::V_FRACT_F16:
|
||||
case Opcode::V_SIN_F16:
|
||||
case Opcode::V_COS_F16:
|
||||
case Opcode::V_SIN_F32:
|
||||
@@ -548,6 +552,8 @@ constexpr Vop1SdwaRule VOP1_SDWA_RULES[] = {
|
||||
SdwaSelWords() | SdwaSelFull(), true},
|
||||
{Opcode::V_RNDNE_F16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(),
|
||||
SdwaSelWords() | SdwaSelFull(), true},
|
||||
{Opcode::V_FRACT_F16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(),
|
||||
SdwaSelWords() | SdwaSelFull(), true},
|
||||
{Opcode::V_SIN_F16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(),
|
||||
SdwaSelWords() | SdwaSelFull(), true},
|
||||
{Opcode::V_COS_F16, SdwaSelWords() | SdwaSelFull(), SdwaSelWords(),
|
||||
@@ -773,6 +779,7 @@ bool IsVop1FloatResultOpcode(Opcode opcode) {
|
||||
case Opcode::V_CEIL_F16:
|
||||
case Opcode::V_TRUNC_F16:
|
||||
case Opcode::V_RNDNE_F16:
|
||||
case Opcode::V_FRACT_F16:
|
||||
case Opcode::V_SIN_F16:
|
||||
case Opcode::V_COS_F16:
|
||||
case Opcode::V_SIN_F32:
|
||||
@@ -1434,6 +1441,7 @@ bool IsVopcCompareExec(Opcode opcode) {
|
||||
case Opcode::V_CMPX_GE_U32:
|
||||
case Opcode::V_CMPX_NE_I64:
|
||||
case Opcode::V_CMPX_NE_U64:
|
||||
case Opcode::V_CMPX_LT_U16:
|
||||
case Opcode::V_CMPX_GT_U16:
|
||||
case Opcode::V_CMPX_LT_F16:
|
||||
case Opcode::V_CMPX_EQ_F16:
|
||||
|
||||
@@ -138,6 +138,8 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
|
||||
return SimpleInteger(inst, IR::ValueOpcode::IMul32, IR::Type::U32, false, false, false);
|
||||
case O::S_MUL_HI_U32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::UMulHi, IR::Type::U32, false, false, false);
|
||||
case O::S_MUL_HI_I32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::SMulHi, IR::Type::U32, false, false, false);
|
||||
case O::S_AND_B32:
|
||||
return SimpleInteger(inst, IR::ValueOpcode::BitwiseAnd32, IR::Type::U32, false, false,
|
||||
true);
|
||||
|
||||
@@ -138,6 +138,9 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
|
||||
case O::V_CMP_LT_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::ULessThan32, false, false);
|
||||
return true;
|
||||
case O::V_CMPX_LT_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::ULessThan32, false, true);
|
||||
return true;
|
||||
case O::V_CMP_LE_U16:
|
||||
EmitInteger16Compare(inst, IR::ValueOpcode::ULessThanEqual32, false, false);
|
||||
return true;
|
||||
@@ -370,6 +373,7 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
|
||||
case O::V_CEIL_F16: return Float16Unary(inst, IR::ValueOpcode::FPCeil32, false);
|
||||
case O::V_TRUNC_F16: return Float16Unary(inst, IR::ValueOpcode::FPTrunc32, false);
|
||||
case O::V_RNDNE_F16: return Float16Unary(inst, IR::ValueOpcode::FPRoundEven32, false);
|
||||
case O::V_FRACT_F16: return Float16Unary(inst, IR::ValueOpcode::FPFract32, false);
|
||||
case O::V_SIN_F16: return Float16Trig(inst, IR::ValueOpcode::FPSin);
|
||||
case O::V_COS_F16: return Float16Trig(inst, IR::ValueOpcode::FPCos);
|
||||
case O::V_MIN3_F16: return Float16Ternary(inst, IR::ValueOpcode::FPMinTri32, false, false);
|
||||
|
||||
@@ -55,7 +55,7 @@ class RectListEmitter {
|
||||
public:
|
||||
RectListEmitter(const std::vector<Parameter>& parameters_, spv::ExecutionModel model)
|
||||
: parameters(parameters_) {
|
||||
builder.AddMemoryModel({spv::AddressingModelLogical, spv::MemoryModelGLSL450});
|
||||
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
|
||||
void_type = Type(spv::OpTypeVoid);
|
||||
uint_type = Type(spv::OpTypeInt, 32u, 0u);
|
||||
@@ -65,9 +65,10 @@ public:
|
||||
function_type = Type(spv::OpTypeFunction, void_type);
|
||||
|
||||
per_vertex_type = builder.DecoratedType(
|
||||
spv::OpTypeStruct, {vec4_float_type},
|
||||
spv::OpTypeStruct,
|
||||
{{spv::OpMemberDecorate, {0u, spv::DecorationBuiltIn, spv::BuiltInPosition}},
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}});
|
||||
{spv::OpDecorate, {spv::DecorationBlock}}},
|
||||
vec4_float_type);
|
||||
|
||||
ptr_input_vec4_float = Pointer(spv::StorageClassInput, vec4_float_type);
|
||||
ptr_output_vec4_float = Pointer(spv::StorageClassOutput, vec4_float_type);
|
||||
@@ -188,11 +189,11 @@ public:
|
||||
private:
|
||||
template <typename... Args>
|
||||
uint32_t Type(spv::Op opcode, Args... operands) {
|
||||
return builder.Type(opcode, {operands...});
|
||||
return builder.Type(opcode, operands...);
|
||||
}
|
||||
|
||||
uint32_t Constant(uint32_t type, uint32_t value) {
|
||||
return builder.Constant(spv::OpConstant, type, {value});
|
||||
return builder.Constant(spv::OpConstant, type, value);
|
||||
}
|
||||
|
||||
uint32_t Pointer(spv::StorageClass storage, uint32_t type) {
|
||||
@@ -206,20 +207,20 @@ private:
|
||||
template <typename... Args>
|
||||
uint32_t Result(spv::Op opcode, uint32_t type, Args... operands) {
|
||||
const auto id = builder.AllocateId();
|
||||
builder.AddFunction({opcode, type, id, operands...});
|
||||
builder.AddFunction(opcode, type, id, operands...);
|
||||
return id;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
uint32_t ResultWithoutType(spv::Op opcode, Args... operands) {
|
||||
const auto id = builder.AllocateId();
|
||||
builder.AddFunction({opcode, id, operands...});
|
||||
builder.AddFunction(opcode, id, operands...);
|
||||
return id;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Emit(spv::Op opcode, Args... operands) {
|
||||
builder.AddFunction({opcode, operands...});
|
||||
builder.AddFunction(opcode, operands...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -242,7 +243,7 @@ private:
|
||||
}
|
||||
|
||||
void Decorate(uint32_t target, spv::Decoration decoration, uint32_t value) {
|
||||
builder.AddAnnotation({spv::OpDecorate, target, decoration, value});
|
||||
builder.AddAnnotation(spv::OpDecorate, target, decoration, value);
|
||||
}
|
||||
|
||||
void DefineEntry(spv::ExecutionModel model) {
|
||||
@@ -250,11 +251,11 @@ private:
|
||||
builder.RequireCapability(spv::CapabilityTessellation);
|
||||
main = Result(spv::OpFunction, void_type, spv::FunctionControlMaskNone, function_type);
|
||||
if (model == spv::ExecutionModelTessellationControl) {
|
||||
builder.AddExecutionMode({main, spv::ExecutionModeOutputVertices, 4u});
|
||||
builder.AddExecutionMode(main, spv::ExecutionModeOutputVertices, 4u);
|
||||
} else {
|
||||
builder.AddExecutionMode({main, spv::ExecutionModeQuads});
|
||||
builder.AddExecutionMode({main, spv::ExecutionModeSpacingEqual});
|
||||
builder.AddExecutionMode({main, spv::ExecutionModeVertexOrderCw});
|
||||
builder.AddExecutionMode(main, spv::ExecutionModeQuads);
|
||||
builder.AddExecutionMode(main, spv::ExecutionModeSpacingEqual);
|
||||
builder.AddExecutionMode(main, spv::ExecutionModeVertexOrderCw);
|
||||
}
|
||||
DefineInputs(model);
|
||||
DefineOutputs(model);
|
||||
@@ -296,10 +297,10 @@ private:
|
||||
gl_out = AddInterface(spv::StorageClassOutput, Array(per_vertex_type, 4u));
|
||||
tess_inner = AddInterface(spv::StorageClassOutput, Array(float_type, 2u));
|
||||
Decorate(tess_inner, spv::DecorationBuiltIn, spv::BuiltInTessLevelInner);
|
||||
builder.AddAnnotation({spv::OpDecorate, tess_inner, spv::DecorationPatch});
|
||||
builder.AddAnnotation(spv::OpDecorate, tess_inner, spv::DecorationPatch);
|
||||
tess_outer = AddInterface(spv::StorageClassOutput, Array(float_type, 4u));
|
||||
Decorate(tess_outer, spv::DecorationBuiltIn, spv::BuiltInTessLevelOuter);
|
||||
builder.AddAnnotation({spv::OpDecorate, tess_outer, spv::DecorationPatch});
|
||||
builder.AddAnnotation(spv::OpDecorate, tess_outer, spv::DecorationPatch);
|
||||
} else {
|
||||
gl_out = AddInterface(spv::StorageClassOutput, per_vertex_type);
|
||||
}
|
||||
|
||||
@@ -458,6 +458,7 @@ int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode) {
|
||||
file->real_name = g_mount_points->ResolvePath(file->name);
|
||||
|
||||
if (trunc && rw_mode == Common::File::Mode::Read) {
|
||||
g_files->DeleteDescriptor(descriptor);
|
||||
return KERNEL_ERROR_EACCES;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,13 +229,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_profiler_direction">
|
||||
<property name="text"><string>Profiler:</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox_profiler_direction">
|
||||
<property name="toolTip"><string>Enable or disable profiler. If enabled may decrease emulator performance</string></property>
|
||||
<widget class="QCheckBox" name="checkBox_profiler">
|
||||
<property name="toolTip"><string>Enable the Tracy profiler. Profiling may decrease emulator performance</string></property>
|
||||
<property name="text"><string>Tracy profiler</string></property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
|
||||
@@ -66,12 +66,6 @@ public:
|
||||
enum class PresentMode { Fifo, Mailbox, Immediate };
|
||||
Q_ENUM(PresentMode)
|
||||
|
||||
enum class ShaderLogDirection { Silent, Console, File };
|
||||
Q_ENUM(ShaderLogDirection)
|
||||
|
||||
enum class ProfilerDirection { None, Network };
|
||||
Q_ENUM(ProfilerDirection)
|
||||
|
||||
enum class LogDirection { Silent, Console, File };
|
||||
Q_ENUM(LogDirection)
|
||||
|
||||
@@ -93,7 +87,7 @@ public:
|
||||
Resolution screen_resolution = Resolution::R1280X720;
|
||||
QString user_name = "Kyty";
|
||||
int user_id = Config::DEFAULT_USER_ID;
|
||||
PresentMode present_mode = PresentMode::Fifo;
|
||||
PresentMode present_mode = PresentMode::Mailbox;
|
||||
int gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
bool readback_linear_images = false;
|
||||
@@ -102,13 +96,13 @@ public:
|
||||
bool vulkan_validation_enabled = false;
|
||||
bool shader_validation_enabled = true;
|
||||
ShaderOptimizationType shader_optimization_type = ShaderOptimizationType::Performance;
|
||||
ShaderLogDirection shader_log_direction = ShaderLogDirection::Silent;
|
||||
LogDirection shader_log_direction = LogDirection::Silent;
|
||||
QString shader_log_folder = "_Shaders";
|
||||
bool command_buffer_dump_enabled = false;
|
||||
QString command_buffer_dump_folder = "_Buffers";
|
||||
LogDirection printf_direction = LogDirection::Silent;
|
||||
QString printf_output_file = "_kyty.txt";
|
||||
ProfilerDirection profiler_direction = ProfilerDirection::None;
|
||||
bool profiler_enabled = false;
|
||||
bool renderdoc_enabled = false;
|
||||
#if defined(_WIN32)
|
||||
bool red_zone_protection_enabled = false;
|
||||
@@ -136,7 +130,7 @@ public:
|
||||
command_buffer_dump_folder = other.command_buffer_dump_folder;
|
||||
printf_direction = other.printf_direction;
|
||||
printf_output_file = other.printf_output_file;
|
||||
profiler_direction = other.profiler_direction;
|
||||
profiler_enabled = other.profiler_enabled;
|
||||
renderdoc_enabled = other.renderdoc_enabled;
|
||||
#if defined(_WIN32)
|
||||
red_zone_protection_enabled = other.red_zone_protection_enabled;
|
||||
@@ -181,7 +175,7 @@ public:
|
||||
KYTY_CFG_SET(command_buffer_dump_folder);
|
||||
KYTY_CFG_SET(printf_direction);
|
||||
KYTY_CFG_SET(printf_output_file);
|
||||
KYTY_CFG_SET(profiler_direction);
|
||||
KYTY_CFG_SET(profiler_enabled);
|
||||
KYTY_CFG_SET(renderdoc_enabled);
|
||||
#if defined(_WIN32)
|
||||
KYTY_CFG_SET(red_zone_protection_enabled);
|
||||
@@ -205,7 +199,7 @@ public:
|
||||
KYTY_CFG_GET(present_mode);
|
||||
gpu_index = s->value("gpu_index", -1).toInt();
|
||||
if (EnumToText(present_mode).isEmpty()) {
|
||||
present_mode = PresentMode::Fifo;
|
||||
present_mode = PresentMode::Mailbox;
|
||||
}
|
||||
KYTY_CFG_GET(fullscreen_enabled);
|
||||
KYTY_CFG_GET(readback_linear_images);
|
||||
@@ -223,7 +217,7 @@ public:
|
||||
KYTY_CFG_GET(command_buffer_dump_folder);
|
||||
KYTY_CFG_GET(printf_direction);
|
||||
KYTY_CFG_GET(printf_output_file);
|
||||
KYTY_CFG_GET(profiler_direction);
|
||||
KYTY_CFG_GET(profiler_enabled);
|
||||
KYTY_CFG_GET(renderdoc_enabled);
|
||||
#if defined(_WIN32)
|
||||
red_zone_protection_enabled =
|
||||
|
||||
@@ -110,9 +110,9 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p
|
||||
connect(m_ui->clear_button, &QPushButton::clicked, this, &ConfigurationEditDialog::clear);
|
||||
connect(m_ui->comboBox_shader_log_direction, &QComboBox::currentTextChanged, this,
|
||||
[this](const QString& text) {
|
||||
auto log = TextToEnum<Configuration::ShaderLogDirection>(text);
|
||||
auto log = TextToEnum<Configuration::LogDirection>(text);
|
||||
m_ui->lineEdit_shader_log_folder->setEnabled(
|
||||
log == Configuration::ShaderLogDirection::File);
|
||||
log == Configuration::LogDirection::File);
|
||||
});
|
||||
connect(m_ui->checkBox_cmd_dump, &QCheckBox::toggled, this,
|
||||
[this](bool flag) { m_ui->lineEdit_cmd_dump_folder->setEnabled(flag); });
|
||||
@@ -222,7 +222,7 @@ void ConfigurationEditDialog::Init(const Configuration& info) {
|
||||
ListInit(m_ui->comboBox_shader_log_direction, info.shader_log_direction);
|
||||
m_ui->lineEdit_shader_log_folder->setText(info.shader_log_folder);
|
||||
m_ui->lineEdit_shader_log_folder->setEnabled(info.shader_log_direction ==
|
||||
Configuration::ShaderLogDirection::File);
|
||||
Configuration::LogDirection::File);
|
||||
m_ui->checkBox_cmd_dump->setChecked(info.command_buffer_dump_enabled);
|
||||
m_ui->lineEdit_cmd_dump_folder->setText(info.command_buffer_dump_folder);
|
||||
m_ui->lineEdit_cmd_dump_folder->setEnabled(info.command_buffer_dump_enabled);
|
||||
@@ -230,7 +230,7 @@ void ConfigurationEditDialog::Init(const Configuration& info) {
|
||||
m_ui->lineEdit_printf_file->setText(info.printf_output_file);
|
||||
m_ui->lineEdit_printf_file->setEnabled(info.printf_direction ==
|
||||
Configuration::LogDirection::File);
|
||||
ListInit(m_ui->comboBox_profiler_direction, info.profiler_direction);
|
||||
m_ui->checkBox_profiler->setChecked(info.profiler_enabled);
|
||||
}
|
||||
|
||||
void ConfigurationEditDialog::InitGameDirectories() {
|
||||
@@ -357,7 +357,7 @@ static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
|
||||
#endif
|
||||
info.shader_optimization_type = TextToEnum<Configuration::ShaderOptimizationType>(
|
||||
ui.comboBox_shader_optimization_type->currentText());
|
||||
info.shader_log_direction = TextToEnum<Configuration::ShaderLogDirection>(
|
||||
info.shader_log_direction = TextToEnum<Configuration::LogDirection>(
|
||||
ui.comboBox_shader_log_direction->currentText());
|
||||
info.shader_log_folder = ui.lineEdit_shader_log_folder->text();
|
||||
info.command_buffer_dump_enabled = ui.checkBox_cmd_dump->isChecked();
|
||||
@@ -365,8 +365,7 @@ static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
|
||||
info.printf_direction =
|
||||
TextToEnum<Configuration::LogDirection>(ui.comboBox_printf_direction->currentText());
|
||||
info.printf_output_file = ui.lineEdit_printf_file->text();
|
||||
info.profiler_direction =
|
||||
TextToEnum<Configuration::ProfilerDirection>(ui.comboBox_profiler_direction->currentText());
|
||||
info.profiler_enabled = ui.checkBox_profiler->isChecked();
|
||||
}
|
||||
|
||||
void ConfigurationEditDialog::update_info() {
|
||||
|
||||
@@ -247,7 +247,9 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
|
||||
args << "--command-buffer-dump-folder" << info.command_buffer_dump_folder;
|
||||
args << "--printf-direction" << EnumToText(info.printf_direction);
|
||||
args << "--printf-output-file" << info.printf_output_file;
|
||||
args << "--profiler-direction" << EnumToText(info.profiler_direction);
|
||||
if (info.profiler_enabled) {
|
||||
args << "--profile";
|
||||
}
|
||||
args << "--spirv-debug-printf" << "false";
|
||||
#if defined(_WIN32)
|
||||
if (info.red_zone_protection_enabled) {
|
||||
|
||||
+1
-1
@@ -241,7 +241,7 @@ struct CommandBuffer {
|
||||
|
||||
void DbgDump() const {
|
||||
if (!Config::GraphicsDebugDumpEnabled() ||
|
||||
Config::GetPrintfDirection() == Config::OutputDirection::Silent) {
|
||||
Config::GetPrintfDirection() == Config::LogDirection::Silent) {
|
||||
return;
|
||||
}
|
||||
static std::atomic<uint32_t> log_count {0};
|
||||
|
||||
@@ -1006,6 +1006,21 @@ static int32_t KYTY_SYSV_ABI JsonValueCount(const JsonValue* self) {
|
||||
}
|
||||
}
|
||||
|
||||
static void KYTY_SYSV_ABI JsonValueClearMethod(void* self) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t self = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(self));
|
||||
|
||||
auto* value = reinterpret_cast<JsonValue*>(self);
|
||||
if (value != nullptr) {
|
||||
auto* parent = value->parent;
|
||||
auto* rootparam = value->rootparam;
|
||||
JsonValueClear(value);
|
||||
value->parent = parent;
|
||||
value->rootparam = rootparam;
|
||||
}
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitNet_1_Json2) {
|
||||
LIB_FUNC("-hJRce8wn1U", LibJson2::JsonMemAllocatorCtor);
|
||||
LIB_FUNC("WSOuge5IsCg", LibJson2::JsonInitParameter2Ctor);
|
||||
@@ -1076,6 +1091,7 @@ LIB_DEFINE(InitNet_1_Json2) {
|
||||
LIB_FUNC("RBw+4NukeGQ", LibJson2::JsonValueCount);
|
||||
LIB_FUNC("+drDFyAS6u4", LibJson2::JsonInitializerSetGlobalNullAccessCallback);
|
||||
LIB_FUNC("00oCq0RwSAY", LibJson2::JsonInitializerSetGlobalNullAccessCallback);
|
||||
LIB_FUNC("FIjXN2TkuTs", LibJson2::JsonValueClearMethod);
|
||||
}
|
||||
|
||||
} // namespace LibJson2
|
||||
|
||||
+12
-7
@@ -2025,22 +2025,27 @@ int64_t KYTY_SYSV_ABI Recvfrom(int s, void* buf, uint64_t len, int flags, void*
|
||||
|
||||
const auto host_len = static_cast<SocketIoLength>(
|
||||
std::min<uint64_t>(len, std::numeric_limits<SocketIoLength>::max()));
|
||||
int64_t result = 0;
|
||||
sockaddr_storage host_addr {};
|
||||
SocketLength host_addrlen = sizeof(host_addr);
|
||||
int64_t result = 0;
|
||||
if (addr == nullptr) {
|
||||
result = ::recv(socket, static_cast<char*>(buf), host_len, host_flags);
|
||||
} else {
|
||||
sockaddr_storage host_addr {};
|
||||
SocketLength host_addrlen = sizeof(host_addr);
|
||||
result = ::recvfrom(socket, static_cast<char*>(buf), host_len, host_flags,
|
||||
reinterpret_cast<sockaddr*>(&host_addr), &host_addrlen);
|
||||
if (result >= 0 &&
|
||||
ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
if (result < 0 && WSAGetLastError() == WSAEMSGSIZE) {
|
||||
// Winsock copied the datagram prefix; POSIX reports its length as success.
|
||||
result = host_len;
|
||||
}
|
||||
#endif
|
||||
if (result < 0) {
|
||||
return SetHostSocketError();
|
||||
}
|
||||
if (addr != nullptr && ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+7
-7
@@ -50,7 +50,7 @@ static void PrintUsage() {
|
||||
::printf(" --user-id <num> Local user ID. Default: %d.\n",
|
||||
Config::DEFAULT_USER_ID);
|
||||
::printf(
|
||||
" --present-mode <value> Fifo, Mailbox, or Immediate. Default: Fifo.\n");
|
||||
" --present-mode <value> Fifo, Mailbox, or Immediate. Default: Mailbox.\n");
|
||||
::printf(
|
||||
" --gpu <index> Vulkan physical device index. Default: auto.\n");
|
||||
::printf(" --fullscreen Run in borderless desktop fullscreen.\n");
|
||||
@@ -68,7 +68,7 @@ static void PrintUsage() {
|
||||
::printf(" --graphics-debug-dump <true|false> Enable graphics debug dumps.\n");
|
||||
::printf(" --printf-direction <value> Silent, Console, or File.\n");
|
||||
::printf(" --printf-output-file <path> Guest printf output file.\n");
|
||||
::printf(" --profiler-direction <value> None or Network.\n");
|
||||
::printf(" --profile Enable the Tracy profiler.\n");
|
||||
::printf(" --spirv-debug-printf <true|false> Enable SPIR-V debug printf.\n");
|
||||
::printf(
|
||||
" --readback-linear-images <true|false> Read back writable linear images on submit.\n");
|
||||
@@ -166,6 +166,11 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--profile") {
|
||||
options.config.profiler_enabled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
if (arg == "--redzone") {
|
||||
options.config.red_zone_protection_enabled = true;
|
||||
@@ -292,11 +297,6 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
}
|
||||
} else if (arg == "--printf-output-file") {
|
||||
options.config.printf_output_file = value;
|
||||
} else if (arg == "--profiler-direction") {
|
||||
if (!ParseEnum(value, options.config.profiler_direction)) {
|
||||
::printf("invalid profiler direction: %s\n", value.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (arg == "--spirv-debug-printf") {
|
||||
if (!ParseBool(value, options.config.spirv_debug_printf_enabled)) {
|
||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||
|
||||
@@ -371,7 +371,7 @@ int main() {
|
||||
Common::Subsystems subsystems;
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
options.printf_direction = Config::LogDirection::Silent;
|
||||
Config::Load(options);
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
|
||||
|
||||
@@ -926,7 +926,7 @@ void EnsureConfigInitialized() {
|
||||
Common::InitializeThreads();
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
options.printf_direction = Config::LogDirection::Silent;
|
||||
Config::Load(options);
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
|
||||
@@ -1603,30 +1603,29 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
|
||||
Builder b;
|
||||
const auto void_type = b.Type(spv::OpTypeVoid);
|
||||
const auto uint_type = b.Type(spv::OpTypeInt, {32, 0});
|
||||
const auto int_type = b.Type(spv::OpTypeInt, {32, 1});
|
||||
const auto float_type = b.Type(spv::OpTypeFloat, {32});
|
||||
const auto vec2_type = b.Type(spv::OpTypeVector, {float_type, 2});
|
||||
const auto vec4_type = b.Type(spv::OpTypeVector, {float_type, 4});
|
||||
const auto uint_type = b.Type(spv::OpTypeInt, 32, 0);
|
||||
const auto int_type = b.Type(spv::OpTypeInt, 32, 1);
|
||||
const auto float_type = b.Type(spv::OpTypeFloat, 32);
|
||||
const auto vec2_type = b.Type(spv::OpTypeVector, float_type, 2);
|
||||
const auto vec4_type = b.Type(spv::OpTypeVector, float_type, 4);
|
||||
const auto per_vertex_type =
|
||||
b.DecoratedType(spv::OpTypeStruct, {vec4_type},
|
||||
{{spv::OpDecorate, {spv::DecorationBlock}},
|
||||
b.DecoratedType(spv::OpTypeStruct, {{spv::OpDecorate, {spv::DecorationBlock}},
|
||||
{spv::OpMemberDecorate,
|
||||
{0, spv::DecorationBuiltIn, spv::BuiltInPosition}}});
|
||||
{0, spv::DecorationBuiltIn, spv::BuiltInPosition}}}, vec4_type);
|
||||
const auto ptr_input_vec2 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, vec2_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, vec2_type);
|
||||
const auto ptr_input_vec4 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, vec4_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, vec4_type);
|
||||
const auto ptr_output_vec4 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, vec4_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, vec4_type);
|
||||
const auto ptr_output_per_vertex =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, per_vertex_type});
|
||||
const auto func_type = b.Type(spv::OpTypeFunction, {void_type});
|
||||
const auto const_u32_0 = b.Constant(spv::OpConstant, uint_type, {0});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, per_vertex_type);
|
||||
const auto func_type = b.Type(spv::OpTypeFunction, void_type);
|
||||
const auto const_u32_0 = b.Constant(spv::OpConstant, uint_type, 0);
|
||||
const auto const_f32_0 =
|
||||
b.Constant(spv::OpConstant, float_type, {0x00000000u});
|
||||
b.Constant(spv::OpConstant, float_type, 0x00000000u);
|
||||
const auto const_f32_w =
|
||||
b.Constant(spv::OpConstant, float_type, {std::bit_cast<u32>(clip_w)});
|
||||
b.Constant(spv::OpConstant, float_type, std::bit_cast<u32>(clip_w));
|
||||
const auto in_pos =
|
||||
b.DefineGlobalVariable(ptr_input_vec2, spv::StorageClassInput);
|
||||
const auto in_color =
|
||||
@@ -1640,15 +1639,14 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
std::vector<u32> interfaces = {in_pos, in_color, per_vertex, out_color};
|
||||
if (layered) {
|
||||
instance = b.DefineGlobalVariable(
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, int_type}),
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, int_type),
|
||||
spv::StorageClassInput);
|
||||
layer = b.DefineGlobalVariable(
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, int_type}),
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, int_type),
|
||||
spv::StorageClassOutput);
|
||||
b.AddAnnotation({spv::OpDecorate, instance, spv::DecorationBuiltIn,
|
||||
spv::BuiltInInstanceIndex});
|
||||
b.AddAnnotation(
|
||||
{spv::OpDecorate, layer, spv::DecorationBuiltIn, spv::BuiltInLayer});
|
||||
b.AddAnnotation(spv::OpDecorate, instance, spv::DecorationBuiltIn,
|
||||
spv::BuiltInInstanceIndex);
|
||||
b.AddAnnotation(spv::OpDecorate, layer, spv::DecorationBuiltIn, spv::BuiltInLayer);
|
||||
b.RequireVersion(0x00010500u);
|
||||
b.RequireCapability(spv::CapabilityShaderLayer);
|
||||
interfaces.insert(interfaces.end(), {instance, layer});
|
||||
@@ -1663,32 +1661,32 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
const auto position_ptr = b.AllocateId();
|
||||
|
||||
b.RequireCapability(spv::CapabilityShader);
|
||||
b.AddMemoryModel({spv::AddressingModelLogical, spv::MemoryModelGLSL450});
|
||||
b.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
b.AddEntryPoint(spv::ExecutionModelVertex, main, "main", interfaces);
|
||||
b.AddAnnotation({spv::OpDecorate, in_pos, spv::DecorationLocation, 0});
|
||||
b.AddAnnotation({spv::OpDecorate, in_color, spv::DecorationLocation, 1});
|
||||
b.AddAnnotation({spv::OpDecorate, out_color, spv::DecorationLocation, 0});
|
||||
b.AddAnnotation(spv::OpDecorate, in_pos, spv::DecorationLocation, 0);
|
||||
b.AddAnnotation(spv::OpDecorate, in_color, spv::DecorationLocation, 1);
|
||||
b.AddAnnotation(spv::OpDecorate, out_color, spv::DecorationLocation, 0);
|
||||
|
||||
b.AddFunction({spv::OpFunction, void_type, main, spv::FunctionControlMaskNone,
|
||||
func_type});
|
||||
b.AddFunction({spv::OpLabel, label});
|
||||
b.AddFunction({spv::OpLoad, vec2_type, pos2, in_pos});
|
||||
b.AddFunction({spv::OpLoad, vec4_type, color4, in_color});
|
||||
b.AddFunction({spv::OpCompositeExtract, float_type, pos_x, pos2, 0});
|
||||
b.AddFunction({spv::OpCompositeExtract, float_type, pos_y, pos2, 1});
|
||||
b.AddFunction({spv::OpCompositeConstruct, vec4_type, position, pos_x, pos_y,
|
||||
const_f32_0, const_f32_w});
|
||||
b.AddFunction({spv::OpAccessChain, ptr_output_vec4, position_ptr, per_vertex,
|
||||
const_u32_0});
|
||||
b.AddFunction({spv::OpStore, position_ptr, position});
|
||||
b.AddFunction({spv::OpStore, out_color, color4});
|
||||
b.AddFunction(spv::OpFunction, void_type, main, spv::FunctionControlMaskNone,
|
||||
func_type);
|
||||
b.AddFunction(spv::OpLabel, label);
|
||||
b.AddFunction(spv::OpLoad, vec2_type, pos2, in_pos);
|
||||
b.AddFunction(spv::OpLoad, vec4_type, color4, in_color);
|
||||
b.AddFunction(spv::OpCompositeExtract, float_type, pos_x, pos2, 0);
|
||||
b.AddFunction(spv::OpCompositeExtract, float_type, pos_y, pos2, 1);
|
||||
b.AddFunction(spv::OpCompositeConstruct, vec4_type, position, pos_x, pos_y,
|
||||
const_f32_0, const_f32_w);
|
||||
b.AddFunction(spv::OpAccessChain, ptr_output_vec4, position_ptr, per_vertex,
|
||||
const_u32_0);
|
||||
b.AddFunction(spv::OpStore, position_ptr, position);
|
||||
b.AddFunction(spv::OpStore, out_color, color4);
|
||||
if (layered) {
|
||||
const auto index = b.AllocateId();
|
||||
b.AddFunction({spv::OpLoad, int_type, index, instance});
|
||||
b.AddFunction({spv::OpStore, layer, index});
|
||||
b.AddFunction(spv::OpLoad, int_type, index, instance);
|
||||
b.AddFunction(spv::OpStore, layer, index);
|
||||
}
|
||||
b.AddFunction({spv::OpReturn});
|
||||
b.AddFunction({spv::OpFunctionEnd});
|
||||
b.AddFunction(spv::OpReturn);
|
||||
b.AddFunction(spv::OpFunctionEnd);
|
||||
return b.Build();
|
||||
}
|
||||
|
||||
@@ -17837,6 +17835,91 @@ TestCase VectorSpecialF16Ops() {
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase VectorFractF16CapturedAndEdges() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
// RDNA2 section 12.8: x - floor(x), rounded to half precision.
|
||||
// Load at runtime to exercise the emitted operation, including half subnormals.
|
||||
const std::array<u32, 18> inputs{
|
||||
0x3d00u, 0xbd00u, 0x0000u, 0x8000u, 0x0001u, 0x8001u,
|
||||
0x03ffu, 0x83ffu, 0x7bffu, 0xfbffu, 0x3800u, 0xb800u,
|
||||
0x8c00u, 0x8c01u, 0x7c00u, 0xfc00u, 0x7e55u, 0x7d01u};
|
||||
const std::array<u32, 18> fractions{
|
||||
0x3400u, 0x3a00u, 0x0000u, 0x0000u, 0x0001u, 0x3c00u,
|
||||
0x03ffu, 0x3c00u, 0x0000u, 0x0000u, 0x3800u, 0x3800u,
|
||||
0x3c00u, 0x3bffu, 0x7e00u, 0x7e00u, 0x7e00u, 0x7e00u};
|
||||
TestCase test;
|
||||
test.name = "VectorFractF16CapturedAndEdges";
|
||||
for (u32 bits : inputs) {
|
||||
test.initial.push_back(0x42000000u | bits); // Distinct high half must be ignored.
|
||||
}
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
for (u32 i = 0; i < inputs.size(); i++) {
|
||||
AppendVMovU32(&code, 30, i * 4u);
|
||||
AppendBufferLoadDword(&code, 7, 30);
|
||||
AppendVMovLiteral(&code, 9, 0xa5a51234u);
|
||||
code.push_back(0x7e12bf07u); // Captured v_fract_f16 v9, v7.
|
||||
if (i >= 14u) {
|
||||
// Check quiet NaN class without constraining its sign or payload.
|
||||
code.push_back(EncodeVop2(0x1b, 9, 255u, 9));
|
||||
code.push_back(0xffff7e00u);
|
||||
}
|
||||
AppendStoreVgpr(&code, 9, static_cast<u32>(inputs.size()) + i);
|
||||
test.expected.push_back(0xa5a50000u | fractions[i]);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_FRACT_F16,
|
||||
O::V_AND_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.decoded_counts = {{"V_FRACT_F16 v9, v7", inputs.size()}};
|
||||
test.ir_counts = {{" = FPFract32 ", inputs.size()}};
|
||||
test.required_spirv = {" Fract ", " PackHalf2x16 ", " UnpackHalf2x16 "};
|
||||
test.forbidden_spirv = {"OpCapability Float16"};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorFractF16Modifiers() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
std::vector<u32> code;
|
||||
AppendVMovLiteral(&code, 7, 0xbd003d00u); // high=-1.25h, low=+1.25h
|
||||
for (u32 dst = 10; dst <= 19; dst++) {
|
||||
AppendVMovLiteral(&code, dst, 0xabcd1234u);
|
||||
}
|
||||
code.push_back(EncodeVop1(0x5f, 10, 249));
|
||||
code.push_back(EncodeVop1Sdwa(7, 5, 2, 5)); // high -> high, preserve low
|
||||
code.push_back(EncodeVop1(0x5f, 11, 249));
|
||||
code.push_back(EncodeVop1Sdwa(7, 4, 0, 5, 0, 1, 1)); // -abs(-1.25), pad high
|
||||
code.push_back(EncodeVop1(0x5f, 12, 249));
|
||||
code.push_back(EncodeVop1Sdwa(7, 4, 2, 5, 0, 0, 1)); // abs(-1.25)
|
||||
code.push_back(EncodeVop1(0x5f, 13, 249));
|
||||
code.push_back(EncodeVop1Sdwa(7, 4, 2, 5, 0, 0, 0, 0, 1, 1)); // *2, clamp
|
||||
code.push_back(EncodeVop1(0x5f, 14, 250));
|
||||
code.push_back(EncodeVop1Dpp(7, 0x0e4) | (1u << 20u)); // DPP identity, negate
|
||||
AppendVop3(&code, 0x1df, 15, Vgpr(7), 0, 0, 1, 0, true, 1, 1);
|
||||
code.push_back(EncodeVop1(0x5f, 16, 255));
|
||||
code.push_back(0x4200bd00u); // literal -1.25h
|
||||
code.push_back(EncodeVop1(0x5f, 17, 240)); // inline +0.5, interpreted as FP16
|
||||
AppendSMovLiteral(&code, 20, 0x4200bd00u);
|
||||
code.push_back(EncodeVop1(0x5f, 18, 20)); // SGPR source
|
||||
AppendVop3(&code, 0x1df, 19, Vgpr(7), 0, 0, 0, 0, false, 3); // *0.5
|
||||
for (u32 i = 0; i < 10; i++) {
|
||||
AppendStoreVgpr(&code, 10 + i, i);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
|
||||
TestCase test{"VectorFractF16Modifiers", code, {},
|
||||
{0x3a001234u, 0x00003a00u, 0xabcd3400u, 0xabcd3c00u,
|
||||
0xabcd3a00u, 0xabcd3c00u, 0xabcd3a00u, 0xabcd3800u,
|
||||
0xabcd3a00u, 0xabcd3000u},
|
||||
{O::V_MOV_B32, O::S_MOV_B32, O::V_FRACT_F16,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
test.decoded_counts = {{"V_FRACT_F16", 10}};
|
||||
test.ir_counts = {{" = FPFract32 ", 10}};
|
||||
test.required_spirv = {" Fract ", " PackHalf2x16 "};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorCosF16CapturedSdwaAndEdges() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -19595,6 +19678,69 @@ TestCase VectorVopcCmpxGtU16CapturedSdwaExecMask() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorVopcCmpxLtU16CapturedSdwaExecMask() {
|
||||
using O = ShaderOpcode;
|
||||
struct CompareCase {
|
||||
u32 lhs;
|
||||
u32 rhs;
|
||||
u32 incoming_exec;
|
||||
u32 expected_exec;
|
||||
u32 encoding = 0; // Captured SDWA, compact, VOP3, WORD_1 src0/src1.
|
||||
};
|
||||
const std::array<CompareCase, 12> cases{{
|
||||
{0xffff0000u, 0x12340001u, 1, 1}, // Ignore high halves.
|
||||
{0xabcd0001u, 0x12340001u, 1, 0}, // Strict comparison: equal is false.
|
||||
{0x0000ffffu, 0x12340001u, 1, 0}, // Unsigned, not signed -1.
|
||||
{0x00007fffu, 0x12348000u, 1, 1},
|
||||
{0x00008000u, 0x12347fffu, 1, 0},
|
||||
{0x12340000u, 0x56780000u, 1, 0},
|
||||
{0x0000fffeu, 0x1234ffffu, 1, 1},
|
||||
{0x00000000u, 0x12340001u, 0, 0}, // CMPX cannot reactivate an inactive lane.
|
||||
{0x00008000u, 0x0000ffffu, 1, 1, 1},
|
||||
{0x0000ffffu, 0x00008000u, 1, 0, 2},
|
||||
{0x0001ffffu, 0x12340002u, 1, 1, 3},
|
||||
{0x00000001u, 0x00020000u, 1, 1, 4},
|
||||
}};
|
||||
constexpr u32 vcc_hi = 0x89abcdefu;
|
||||
TestCase test;
|
||||
test.name = "VectorVopcCmpxLtU16CapturedSdwaExecMask";
|
||||
for (const auto &entry : cases) {
|
||||
test.initial.push_back(entry.lhs);
|
||||
}
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
for (u32 i = 0; i < cases.size(); ++i) {
|
||||
const auto &entry = cases[i];
|
||||
AppendVMovU32(&code, 30, i * 4u);
|
||||
AppendBufferLoadDword(&code, 0, 30); // Runtime input prevents constant folding.
|
||||
AppendVMovU32(&code, 1, entry.rhs);
|
||||
AppendSMovLiteral(&code, 106, entry.rhs);
|
||||
AppendSMovLiteral(&code, 107, vcc_hi);
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(entry.incoming_exec)));
|
||||
switch (entry.encoding) {
|
||||
case 1: code.push_back(0x7d720300u); break; // compact v0, v1
|
||||
case 2: code.insert(code.end(), {0xd4b9007eu, 0x00020300u}); break;
|
||||
case 3: code.insert(code.end(), {0x7d72d4f9u, 0x86050000u}); break;
|
||||
case 4: code.insert(code.end(), {0x7d72d4f9u, 0x85060000u}); break;
|
||||
default: code.insert(code.end(), {0x7d72d4f9u, 0x86060000u}); break;
|
||||
}
|
||||
code.push_back(EncodeSMovB32(20, 126)); // Snapshot EXEC before restoring it.
|
||||
code.push_back(EncodeSMovB32(21, 127));
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(1)));
|
||||
const u32 out = static_cast<u32>(cases.size()) + i * 4u;
|
||||
AppendStoreSgprPair(&code, 20, out);
|
||||
AppendStoreSgprPair(&code, 106, out + 2u); // CMPX must not overwrite either VCC half.
|
||||
test.expected.insert(test.expected.end(),
|
||||
{entry.expected_exec, 0u, entry.rhs, vcc_hi});
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
|
||||
O::V_CMPX_LT_U16, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.decoded_counts = {{"V_CMPX_LT_U16", cases.size()}};
|
||||
test.required_spirv = {"OpULessThan"};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorVopcCmpxNgtF16CapturedSdwaExecMask() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -24930,6 +25076,8 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(NativeAndSdwa16BitDestinationWrites);
|
||||
AddCase(VectorMinMaxMed3F16Ops);
|
||||
AddCase(VectorSpecialF16Ops);
|
||||
AddCase(VectorFractF16CapturedAndEdges);
|
||||
AddCase(VectorFractF16Modifiers);
|
||||
AddCase(VectorCosF16CapturedSdwaAndEdges);
|
||||
AddCase(VectorSinF16SdwaAndEdges);
|
||||
AddCase(VectorWritelaneIgnoresExecMask);
|
||||
@@ -24982,6 +25130,7 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(VectorVop3CmpxWritesExecMask);
|
||||
AddCase(VectorVopcSdwaCmpxWritesExecMask);
|
||||
AddCase(VectorVopcCmpxGtU16CapturedSdwaExecMask);
|
||||
AddCase(VectorVopcCmpxLtU16CapturedSdwaExecMask);
|
||||
AddCase(VectorVopcCmpxNgtF16CapturedSdwaExecMask);
|
||||
AddCase(VectorCompareInvertedMaskSelect);
|
||||
AddCase(BranchSelect);
|
||||
@@ -29206,6 +29355,26 @@ int main(int argc, char **argv) {
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
EnsureConfigInitialized();
|
||||
CheckLeastRecentlyUsedCacheOrdering();
|
||||
if (argc == 2 && std::strcmp(argv[1], "--cmpx-lt-u16-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, VectorVopcCmpxLtU16CapturedSdwaExecMask());
|
||||
RunCase(&vulkan, VectorVopcCmpxGtU16CapturedSdwaExecMask());
|
||||
RunCase(&vulkan, VectorVopcSdwaCmpxWritesExecMask());
|
||||
RunCase(&vulkan, VectorVop3CmpxWritesExecMask());
|
||||
RunCase(&vulkan, VectorVopcSdwaCmpxClassF32CapturedExecMask());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--fract-f16-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, VectorFractF16CapturedAndEdges());
|
||||
RunCase(&vulkan, VectorFractF16Modifiers());
|
||||
RunCase(&vulkan, NativeAndSdwa16BitDestinationWrites());
|
||||
RunCase(&vulkan, VectorSpecialF16Ops());
|
||||
RunCase(&vulkan, VectorCosF16CapturedSdwaAndEdges());
|
||||
RunCase(&vulkan, VectorSinF16SdwaAndEdges());
|
||||
RunCase(&vulkan, VectorFloatConversionOps());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--packed-texture-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckPackedTextureComponents();
|
||||
|
||||
@@ -102,7 +102,7 @@ void InitSubsystems() {
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
options.printf_direction = Config::LogDirection::Silent;
|
||||
Config::Load(options);
|
||||
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
|
||||
+207
-16
@@ -1021,7 +1021,7 @@ void EnsureConfigInitialized() {
|
||||
Common::InitializeThreads();
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
options.printf_direction = Config::LogDirection::Silent;
|
||||
Config::Load(options);
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
ShaderInit();
|
||||
@@ -1812,6 +1812,7 @@ void TestNewShaderRecompilerScalarVectorAlu() {
|
||||
EncodeSop2(0x30, 11, 10, 1), // s_lshl3_add_u32 s11, s10, s1
|
||||
EncodeSop2(0x31, 12, 11, 1), // s_lshl4_add_u32 s12, s11, s1
|
||||
EncodeSop2(0x35, 13, 12, 1), // s_mul_hi_u32 s13, s12, s1
|
||||
EncodeSop2(0x36, 15, 12, 1), // s_mul_hi_i32 s15, s12, s1
|
||||
EncodeSopc(0x08, 8, 1), // s_cmp_gt_u32 s8, s1
|
||||
EncodeSop2(0x04, 14, 13, 129), // s_addc_u32 s14, s13, 1
|
||||
EncodeVop2(0x03, 1, 242, 0), // v_add_f32 v1, 1.0, v0
|
||||
@@ -1848,6 +1849,8 @@ void TestNewShaderRecompilerScalarVectorAlu() {
|
||||
"new decoder did not decode old-backed S_LSHL4_ADD_U32");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "s_mul_hi_u32 s13, s12, s1"),
|
||||
"new decoder did not decode old-backed S_MUL_HI_U32");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "s_mul_hi_i32 s15, s12, s1"),
|
||||
"new decoder did not decode old-backed S_MUL_HI_I32");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_add_f32 v1"),
|
||||
"new decoder did not decode VOP2 float add");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cndmask_b32 v5"),
|
||||
@@ -1884,6 +1887,8 @@ void TestNewShaderRecompilerScalarVectorAlu() {
|
||||
"S_LSHL4_ADD_U32 did not lower through carry-writing shift-left-add IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "UMulHighU32 s13, s12, s1"),
|
||||
"S_MUL_HI_U32 did not lower to unsigned high-multiply IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "SMulHighI32 s15, s12, s1"),
|
||||
"S_MUL_HI_I32 did not lower to signed high-multiply IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareGtU32"),
|
||||
"SOPC compare did not lower to IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "FAddF32 v1"),
|
||||
@@ -4165,6 +4170,24 @@ void TestNewShaderDecoderArchitecture() {
|
||||
!sin_f16.src0.absolute,
|
||||
"decoder rejected the VOP1 SDWA V_SIN_F16 instruction");
|
||||
|
||||
std::vector<uint32_t> fract_f16_code(0x9b0u / 4u, EncodeSopp(0x00));
|
||||
fract_f16_code.push_back(0x7e12bf07u);
|
||||
fract_f16_code.push_back(EncodeSopp(0x01));
|
||||
Instruction fract_f16;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(fract_f16_code, 0x9b0u / 4u,
|
||||
fract_f16);
|
||||
Check(fract_f16.pc == 0x9b0u && fract_f16.family == Family::VOP1 &&
|
||||
fract_f16.opcode == Opcode::V_FRACT_F16 &&
|
||||
fract_f16.opcode_id == 0x5fu && fract_f16.word_count == 1u &&
|
||||
fract_f16.dst.kind == OperandKind::Vgpr && fract_f16.dst.reg == 9u &&
|
||||
fract_f16.src_count == 1u &&
|
||||
fract_f16.src0.kind == OperandKind::Vgpr && fract_f16.src0.reg == 7u,
|
||||
"decoder rejected captured V_FRACT_F16 at pc 0x9b0");
|
||||
ShaderRecompiler::Decoder::Program fract_program;
|
||||
ShaderRecompiler::Decoder::DecodeProgram(fract_f16_code, fract_program);
|
||||
Check(!ShaderRecompiler::CFG::BuildGraph(fract_program).unsupported,
|
||||
"captured V_FRACT_F16 still fails CFG construction");
|
||||
|
||||
const uint32_t literal_code[] = {EncodeVop1(0x01, 2, 255u), 0x12345678u};
|
||||
Instruction literal;
|
||||
ShaderRecompiler::Decoder::DecodeInstruction(literal_code, 0u, literal);
|
||||
@@ -4411,6 +4434,62 @@ void TestNewShaderRecompilerCapturedVopcSdwaCmpxClass() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerCapturedVopcSdwaCmpxLtU16() {
|
||||
using namespace ShaderRecompiler;
|
||||
|
||||
const uint32_t shader[] = {
|
||||
0x7d72d4f9u, 0x86060000u, // v_cmpx_lt_u16 v0, vcc_lo (SDWA)
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
Decoder::Instruction decoded;
|
||||
Decoder::DecodeInstruction(shader, 0u, decoded);
|
||||
Check(decoded.family == Decoder::Family::VOPC &&
|
||||
decoded.opcode == Decoder::Opcode::V_CMPX_LT_U16 &&
|
||||
decoded.opcode_id == 0xb9u && decoded.word_count == 2u &&
|
||||
decoded.raw[0] == shader[0] && decoded.raw[1] == shader[1] &&
|
||||
decoded.dst.kind == Decoder::OperandKind::ExecLo &&
|
||||
decoded.src_count == 2u &&
|
||||
decoded.src0.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded.src0.reg == 0u && decoded.src0.sdwa_sel == 6u &&
|
||||
decoded.src1.kind == Decoder::OperandKind::VccLo &&
|
||||
decoded.src1.sdwa_sel == 6u &&
|
||||
!decoded.src0.sdwa_sext && !decoded.src1.sdwa_sext &&
|
||||
!decoded.src0.negate && !decoded.src1.negate &&
|
||||
!decoded.src0.absolute && !decoded.src1.absolute,
|
||||
"decoder rejected captured SDWA V_CMPX_LT_U16 fields");
|
||||
|
||||
Decoder::Program program;
|
||||
Decoder::DecodeProgram(shader, program);
|
||||
Check(!CFG::BuildGraph(program).unsupported,
|
||||
"captured SDWA V_CMPX_LT_U16 still fails CFG construction");
|
||||
auto result = RecompileForTest(shader, MakeCompileOptions(ShaderType::Pixel));
|
||||
Check(Common::ContainsStr(result.decoded_dump,
|
||||
"V_CMPX_LT_U16 exec_lo, v0, vcc_lo"),
|
||||
"captured SDWA V_CMPX_LT_U16 is missing from decoded dump");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
// Independently assembled gfx1030 compact and VOP3 encodings.
|
||||
const uint32_t compact[] = {0x7d720300u};
|
||||
const uint32_t vop3[] = {0xd4b9007eu, 0x00020300u};
|
||||
for (auto words : {std::span<const uint32_t>(compact),
|
||||
std::span<const uint32_t>(vop3)}) {
|
||||
Decoder::DecodeInstruction(words, 0u, decoded);
|
||||
Check(decoded.opcode == Decoder::Opcode::V_CMPX_LT_U16 &&
|
||||
decoded.dst.kind == Decoder::OperandKind::ExecLo &&
|
||||
decoded.src0.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded.src0.reg == 0u &&
|
||||
decoded.src1.kind == Decoder::OperandKind::Vgpr &&
|
||||
decoded.src1.reg == 1u,
|
||||
"compact/VOP3 V_CMPX_LT_U16 does not decode to an EXEC compare");
|
||||
}
|
||||
const uint32_t dpp[] = {EncodeVopc(0xb9u, 250u, 1u), EncodeVop2Dpp(0u)};
|
||||
Decoder::DecodeInstruction(dpp, 0u, decoded);
|
||||
Check(decoded.opcode == Decoder::Opcode::UNSUPPORTED &&
|
||||
Common::ContainsStr(decoded.unsupported_reason,
|
||||
"VOPC DPP modifier is not supported for opcode"),
|
||||
"V_CMPX_LT_U16 accepted an unsupported DPP encoding");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerIrLookupMissFailsExplicitly() {
|
||||
namespace Decoder = ShaderRecompiler::Decoder;
|
||||
namespace CFG = ShaderRecompiler::CFG;
|
||||
@@ -10020,11 +10099,120 @@ void TestNewShaderRecompilerAuxPositionExports() {
|
||||
"PA_CL_VS_OUT_CNTL is absent from the vertex shader cache key");
|
||||
}
|
||||
|
||||
void TestTypedSpirvSerialization() {
|
||||
// Parameters exercise runtime enums, which cannot narrow implicitly to a
|
||||
// uint32_t initializer list when the enum uses the Windows signed ABI.
|
||||
const auto check_serialization = [](spv::StorageClass storage_class,
|
||||
spv::FunctionControlMask control,
|
||||
spv::Decoration decoration,
|
||||
GLSLstd450 glsl_opcode,
|
||||
int32_t signed_literal,
|
||||
uint32_t high_bit_literal) {
|
||||
ShaderRecompiler::Spirv::Builder builder;
|
||||
builder.RequireCapability(spv::CapabilityShader);
|
||||
const auto glsl = builder.Import("GLSL.std.450");
|
||||
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
const auto void_type = builder.Type(spv::OpTypeVoid);
|
||||
const std::vector<uint32_t> uint_operands{32u, 0u};
|
||||
const auto uint_type = builder.Type(spv::OpTypeInt, uint_operands);
|
||||
Check(uint_type == builder.Type(spv::OpTypeInt, 32u, 0u) &&
|
||||
uint_type == builder.Type(spv::OpTypeInt,
|
||||
std::span<const uint32_t>{uint_operands}),
|
||||
"typed, vector and span type operands produced different declarations");
|
||||
const auto float_type = builder.Type(spv::OpTypeFloat, 32u);
|
||||
const auto vector_type = builder.Type(spv::OpTypeVector, uint_type, 2u);
|
||||
const auto pointer_type =
|
||||
builder.Type(spv::OpTypePointer, storage_class, uint_type);
|
||||
const auto function_type = builder.Type(spv::OpTypeFunction, void_type);
|
||||
const auto all_bits =
|
||||
builder.Constant(spv::OpConstant, uint_type, signed_literal);
|
||||
Check(all_bits == builder.Constant(spv::OpConstant, uint_type, UINT32_MAX),
|
||||
"signed and unsigned constant operands produced different declarations");
|
||||
const auto high_bit =
|
||||
builder.Constant(spv::OpConstant, uint_type, high_bit_literal);
|
||||
const auto one = builder.Constant(spv::OpConstant, float_type, 0x3f800000u);
|
||||
const std::vector<uint32_t> components{all_bits, high_bit};
|
||||
const auto constant_vector = builder.Constant(
|
||||
spv::OpConstantComposite, vector_type,
|
||||
std::span<const uint32_t>{components});
|
||||
Check(constant_vector == builder.Constant(spv::OpConstantComposite,
|
||||
vector_type, components),
|
||||
"vector and span constant operands produced different declarations");
|
||||
const auto variable =
|
||||
builder.DefineGlobalVariable(pointer_type, storage_class);
|
||||
const auto function = builder.AllocateId();
|
||||
const auto label = builder.AllocateId();
|
||||
const auto absolute = builder.AllocateId();
|
||||
const auto constructed = builder.AllocateId();
|
||||
const auto shuffled = builder.AllocateId();
|
||||
const auto loaded = builder.AllocateId();
|
||||
builder.AddEntryPoint(spv::ExecutionModelGLCompute, function, "main", {});
|
||||
builder.AddExecutionMode(function, spv::ExecutionModeLocalSize, 1u, 2u, 3u);
|
||||
builder.AddAnnotation(spv::OpDecorate, one, decoration);
|
||||
builder.AddFunction(spv::OpFunction, void_type, function, control,
|
||||
function_type);
|
||||
const std::vector<uint32_t> label_words{248u, label};
|
||||
builder.AddFunction(label_words);
|
||||
builder.AddFunction(spv::OpExtInst, float_type, absolute, glsl, glsl_opcode,
|
||||
one);
|
||||
builder.AddFunction(spv::OpCompositeConstruct, vector_type, constructed,
|
||||
components);
|
||||
const std::array<uint32_t, 2> selectors{1u, 2u};
|
||||
builder.AddFunction(spv::OpVectorShuffle, vector_type, shuffled,
|
||||
constant_vector, constructed,
|
||||
std::span<const uint32_t>{selectors});
|
||||
builder.AddFunction(spv::OpLoad, uint_type, loaded, variable,
|
||||
spv::MemoryAccessAlignedMask, 4u);
|
||||
builder.AddFunction(std::vector<uint32_t>{});
|
||||
const std::array<uint32_t, 1> return_words{253u};
|
||||
builder.AddFunction(std::span<const uint32_t>{return_words});
|
||||
builder.AddFunction(spv::OpFunctionEnd);
|
||||
|
||||
// Literal headers and enum values keep this independent of the builder's
|
||||
// instruction word counts, operand conversion and range flattening.
|
||||
const std::vector<uint32_t> expected{
|
||||
0x07230203u, 0x00010300u, 0u, loaded + 1u, 0u,
|
||||
0x00020011u, 1u, // OpCapability Shader
|
||||
0x0006000bu, glsl, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0u,
|
||||
0x0003000eu, 0u, 1u, // OpMemoryModel Logical GLSL450
|
||||
0x0005000fu, 5u, function, 0x6e69616du, 0u,
|
||||
0x00060010u, function, 17u, 1u, 2u, 3u,
|
||||
0x00030047u, one, 0u, // OpDecorate RelaxedPrecision
|
||||
0x00020013u, void_type,
|
||||
0x00040015u, uint_type, 32u, 0u,
|
||||
0x00030016u, float_type, 32u,
|
||||
0x00040017u, vector_type, uint_type, 2u,
|
||||
0x00040020u, pointer_type, 6u, uint_type,
|
||||
0x00030021u, function_type, void_type,
|
||||
0x0004002bu, uint_type, all_bits, 0xffffffffu,
|
||||
0x0004002bu, uint_type, high_bit, 0x80000000u,
|
||||
0x0004002bu, float_type, one, 0x3f800000u,
|
||||
0x0005002cu, vector_type, constant_vector, all_bits, high_bit,
|
||||
0x0004003bu, pointer_type, variable, 6u,
|
||||
0x00050036u, void_type, function, 0u, function_type,
|
||||
0x000200f8u, label,
|
||||
0x0006000cu, float_type, absolute, glsl, 4u, one,
|
||||
0x00050050u, vector_type, constructed, all_bits, high_bit,
|
||||
0x0007004fu, vector_type, shuffled, constant_vector, constructed, 1u, 2u,
|
||||
0x0006003du, uint_type, loaded, variable, 2u, 4u,
|
||||
0x000100fdu,
|
||||
0x00010038u,
|
||||
};
|
||||
const auto binary = builder.Build();
|
||||
Check(binary == expected,
|
||||
"typed SPIR-V serialization changed instruction words or operand order");
|
||||
CheckSpirvBinaryValidates(binary);
|
||||
};
|
||||
check_serialization(spv::StorageClassPrivate, spv::FunctionControlMaskNone,
|
||||
spv::DecorationRelaxedPrecision, GLSLstd450FAbs, -1,
|
||||
0x80000000u);
|
||||
}
|
||||
|
||||
void TestDeferredSpirvPhiPatching() {
|
||||
ShaderRecompiler::Spirv::Builder builder;
|
||||
const auto type = builder.Type(spv::OpTypeInt, {32u, 0u});
|
||||
const auto zero = builder.Constant(spv::OpConstant, type, {0u});
|
||||
const auto one = builder.Constant(spv::OpConstant, type, {1u});
|
||||
const auto type = builder.Type(spv::OpTypeInt, 32u, 0u);
|
||||
const auto zero = builder.Constant(spv::OpConstant, type, 0u);
|
||||
const auto one = builder.Constant(spv::OpConstant, type, 1u);
|
||||
const auto left = builder.AllocateId();
|
||||
const auto right = builder.AllocateId();
|
||||
const auto result = builder.AllocateId();
|
||||
@@ -10075,35 +10263,36 @@ void TestDemandDrivenSpirvDeclarations() {
|
||||
using ShaderRecompiler::Spirv::Builder;
|
||||
|
||||
Builder declarations;
|
||||
const auto uint_type = declarations.Type(spv::OpTypeInt, {32u, 0u});
|
||||
Check(uint_type == declarations.Type(spv::OpTypeInt, {32u, 0u}),
|
||||
const auto uint_type = declarations.Type(spv::OpTypeInt, 32u, 0u);
|
||||
Check(uint_type == declarations.Type(spv::OpTypeInt, 32u, 0u),
|
||||
"structural type interning returned different IDs");
|
||||
const auto zero = declarations.Constant(spv::OpConstant, uint_type, {0u});
|
||||
Check(zero == declarations.Constant(spv::OpConstant, uint_type, {0u}),
|
||||
const auto zero = declarations.Constant(spv::OpConstant, uint_type, 0u);
|
||||
Check(zero == declarations.Constant(spv::OpConstant, 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(spv::CapabilityShader);
|
||||
declarations.RequireCapability(spv::CapabilityShader);
|
||||
const auto plain_array =
|
||||
declarations.Type(spv::OpTypeArray, {uint_type, zero});
|
||||
const auto plain_array = declarations.Type(spv::OpTypeArray, uint_type, zero);
|
||||
const auto decorated_array = declarations.DecoratedType(
|
||||
spv::OpTypeArray, {uint_type, zero},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
spv::OpTypeArray,
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}},
|
||||
uint_type, zero);
|
||||
Check(decorated_array ==
|
||||
declarations.DecoratedType(
|
||||
spv::OpTypeArray, {uint_type, zero},
|
||||
spv::OpTypeArray,
|
||||
{{spv::OpDecorate,
|
||||
{spv::DecorationArrayStride, sizeof(uint32_t)}}}),
|
||||
{spv::DecorationArrayStride, sizeof(uint32_t)}}},
|
||||
uint_type, zero),
|
||||
"decorated type interning returned different IDs");
|
||||
Check(plain_array != decorated_array,
|
||||
"decorated and undecorated aggregate types were aliased");
|
||||
Check(declarations.DecoratedType(spv::OpTypeArray, {uint_type, zero}, {}) ==
|
||||
Check(declarations.DecoratedType(spv::OpTypeArray, {}, uint_type, zero) ==
|
||||
plain_array,
|
||||
"empty decorated type request bypassed structural interning");
|
||||
const auto ptr = declarations.Type(spv::OpTypePointer,
|
||||
{spv::StorageClassFunction, uint_type});
|
||||
spv::StorageClassFunction, uint_type);
|
||||
Check(declarations.DefineGlobalVariable(ptr, spv::StorageClassFunction) !=
|
||||
declarations.DefineGlobalVariable(ptr, spv::StorageClassFunction),
|
||||
"distinct variables were structurally interned");
|
||||
@@ -13015,6 +13204,7 @@ int main() {
|
||||
TestNativeShaderResourceDependencies();
|
||||
TestNormalizedImageContracts();
|
||||
TestSpirvRequirementsAnalysis();
|
||||
TestTypedSpirvSerialization();
|
||||
TestDeferredSpirvPhiPatching();
|
||||
TestCompilerStageInputOwnership();
|
||||
TestSpirvEmissionOwnsRequirements();
|
||||
@@ -13040,6 +13230,7 @@ int main() {
|
||||
TestImageAddressOperands();
|
||||
TestSopkCompareImmediateExtension();
|
||||
TestNewShaderRecompilerCapturedVopcSdwaCmpxClass();
|
||||
TestNewShaderRecompilerCapturedVopcSdwaCmpxLtU16();
|
||||
TestNewShaderRecompilerIrLookupMissFailsExplicitly();
|
||||
TestNewShaderRecompilerRejectsDppOn64BitCompares();
|
||||
TestPsInputCountRegisterDecode();
|
||||
|
||||
Reference in new issue
Block a user