From 69958cba9d0732cf0646dfd8c0ec929fb7dcaef4 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Tue, 26 Apr 2022 22:59:02 +0300 Subject: [PATCH] [GPU] shader-compiler: Accept little-endian ucode --- src/xenia/gpu/d3d12/d3d12_shader.cc | 9 ++++++--- src/xenia/gpu/d3d12/d3d12_shader.h | 5 +++-- src/xenia/gpu/dxbc_shader.cc | 8 +++++--- src/xenia/gpu/dxbc_shader.h | 5 +++-- src/xenia/gpu/shader.cc | 10 ++++++++-- src/xenia/gpu/shader.h | 6 +++++- src/xenia/gpu/shader_compiler_main.cc | 9 ++++++++- src/xenia/gpu/vulkan/vulkan_shader.cc | 10 +++++++--- src/xenia/gpu/vulkan/vulkan_shader.h | 5 +++-- 9 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_shader.cc b/src/xenia/gpu/d3d12/d3d12_shader.cc index eef4ca7de..7c2027cc3 100644 --- a/src/xenia/gpu/d3d12/d3d12_shader.cc +++ b/src/xenia/gpu/d3d12/d3d12_shader.cc @@ -22,9 +22,12 @@ namespace xe { namespace gpu { namespace d3d12 { -D3D12Shader::D3D12Shader(xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count) - : DxbcShader(shader_type, data_hash, dword_ptr, dword_count) {} +D3D12Shader::D3D12Shader(xenos::ShaderType shader_type, + uint64_t ucode_data_hash, const uint32_t* ucode_dwords, + size_t ucode_dword_count, + std::endian ucode_source_endian) + : DxbcShader(shader_type, ucode_data_hash, ucode_dwords, ucode_dword_count, + ucode_source_endian) {} void D3D12Shader::D3D12Translation::DisassembleDxbcAndDxil( const ui::d3d12::D3D12Provider& provider, bool disassemble_dxbc, diff --git a/src/xenia/gpu/d3d12/d3d12_shader.h b/src/xenia/gpu/d3d12/d3d12_shader.h index b64681dc7..c33c486a1 100644 --- a/src/xenia/gpu/d3d12/d3d12_shader.h +++ b/src/xenia/gpu/d3d12/d3d12_shader.h @@ -33,8 +33,9 @@ class D3D12Shader : public DxbcShader { IDxcCompiler* dxc_compiler = nullptr); }; - D3D12Shader(xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count); + D3D12Shader(xenos::ShaderType shader_type, uint64_t ucode_data_hash, + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian = std::endian::big); // For owning subsystem like the pipeline cache, accessors for unique // identifiers (used instead of hashes to make sure collisions can't happen) diff --git a/src/xenia/gpu/dxbc_shader.cc b/src/xenia/gpu/dxbc_shader.cc index 9b0243fca..937d82ffa 100644 --- a/src/xenia/gpu/dxbc_shader.cc +++ b/src/xenia/gpu/dxbc_shader.cc @@ -14,9 +14,11 @@ namespace xe { namespace gpu { -DxbcShader::DxbcShader(xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count) - : Shader(shader_type, data_hash, dword_ptr, dword_count) {} +DxbcShader::DxbcShader(xenos::ShaderType shader_type, uint64_t ucode_data_hash, + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian) + : Shader(shader_type, ucode_data_hash, ucode_dwords, ucode_dword_count, + ucode_source_endian) {} Shader::Translation* DxbcShader::CreateTranslationInstance( uint64_t modification) { diff --git a/src/xenia/gpu/dxbc_shader.h b/src/xenia/gpu/dxbc_shader.h index 477dfdc5d..b14d48d5f 100644 --- a/src/xenia/gpu/dxbc_shader.h +++ b/src/xenia/gpu/dxbc_shader.h @@ -28,8 +28,9 @@ class DxbcShader : public Shader { : Translation(shader, modification) {} }; - DxbcShader(xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count); + DxbcShader(xenos::ShaderType shader_type, uint64_t ucode_data_hash, + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian = std::endian::big); // Resource bindings are gathered after the successful translation of any // modification for simplicity of translation (and they don't depend on diff --git a/src/xenia/gpu/shader.cc b/src/xenia/gpu/shader.cc index 5d38dbfd7..1f8bd57b1 100644 --- a/src/xenia/gpu/shader.cc +++ b/src/xenia/gpu/shader.cc @@ -25,11 +25,17 @@ namespace gpu { using namespace ucode; Shader::Shader(xenos::ShaderType shader_type, uint64_t ucode_data_hash, - const uint32_t* ucode_dwords, size_t ucode_dword_count) + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian) : shader_type_(shader_type), ucode_data_hash_(ucode_data_hash) { // We keep ucode data in host native format so it's easier to work with. ucode_data_.resize(ucode_dword_count); - xe::copy_and_swap(ucode_data_.data(), ucode_dwords, ucode_dword_count); + if (std::endian::native != ucode_source_endian) { + xe::copy_and_swap(ucode_data_.data(), ucode_dwords, ucode_dword_count); + } else { + std::memcpy(ucode_data_.data(), ucode_dwords, + sizeof(uint32_t) * ucode_dword_count); + } } Shader::~Shader() { diff --git a/src/xenia/gpu/shader.h b/src/xenia/gpu/shader.h index 8422cafdc..d33baf565 100644 --- a/src/xenia/gpu/shader.h +++ b/src/xenia/gpu/shader.h @@ -19,6 +19,7 @@ #include #include +#include "xenia/base/byte_order.h" #include "xenia/base/math.h" #include "xenia/base/string_buffer.h" #include "xenia/gpu/ucode.h" @@ -810,8 +811,11 @@ class Shader { std::string host_disassembly_; }; + // ucode_source_endian specifies the endianness of the ucode_dwords argument - + // inside the Shader, the ucode will be stored with the native byte order. Shader(xenos::ShaderType shader_type, uint64_t ucode_data_hash, - const uint32_t* ucode_dwords, size_t ucode_dword_count); + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian = std::endian::big); virtual ~Shader(); // Whether the shader is identified as a vertex or pixel shader. diff --git a/src/xenia/gpu/shader_compiler_main.cc b/src/xenia/gpu/shader_compiler_main.cc index a3f9a7110..61d1e3686 100644 --- a/src/xenia/gpu/shader_compiler_main.cc +++ b/src/xenia/gpu/shader_compiler_main.cc @@ -33,6 +33,11 @@ DEFINE_path(shader_input, "", "Input shader binary file path.", "GPU"); DEFINE_string(shader_input_type, "", "'vs', 'ps', or unspecified to infer from the given filename.", "GPU"); +DEFINE_bool( + shader_input_little_endian, false, + "Whether the input shader binary is little-endian (from an Arm device with " + "the Qualcomm Adreno 200, for instance).", + "GPU"); DEFINE_path(shader_output, "", "Output shader file path.", "GPU"); DEFINE_string(shader_output_type, "ucode", "Translator to use: [ucode, spirv, spirvtext, dxbc, dxbctext].", @@ -104,7 +109,9 @@ int shader_compiler_main(const std::vector& args) { // TODO(benvanik): hash? need to return the data to big-endian format first. uint64_t ucode_data_hash = 0; auto shader = std::make_unique( - shader_type, ucode_data_hash, ucode_dwords.data(), ucode_dwords.size()); + shader_type, ucode_data_hash, ucode_dwords.data(), ucode_dwords.size(), + cvars::shader_input_little_endian ? std::endian::little + : std::endian::big); StringBuffer ucode_disasm_buffer; shader->AnalyzeUcode(ucode_disasm_buffer); diff --git a/src/xenia/gpu/vulkan/vulkan_shader.cc b/src/xenia/gpu/vulkan/vulkan_shader.cc index e23de068e..535389ceb 100644 --- a/src/xenia/gpu/vulkan/vulkan_shader.cc +++ b/src/xenia/gpu/vulkan/vulkan_shader.cc @@ -22,9 +22,13 @@ namespace vulkan { using xe::ui::vulkan::util::CheckResult; VulkanShader::VulkanShader(const ui::vulkan::VulkanProvider& provider, - xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count) - : Shader(shader_type, data_hash, dword_ptr, dword_count), + xenos::ShaderType shader_type, + uint64_t ucode_data_hash, + const uint32_t* ucode_dwords, + size_t ucode_dword_count, + std::endian ucode_source_endian) + : Shader(shader_type, ucode_data_hash, ucode_dwords, ucode_dword_count, + ucode_source_endian), provider_(provider) {} VulkanShader::VulkanTranslation::~VulkanTranslation() { diff --git a/src/xenia/gpu/vulkan/vulkan_shader.h b/src/xenia/gpu/vulkan/vulkan_shader.h index 00e913923..d6515df30 100644 --- a/src/xenia/gpu/vulkan/vulkan_shader.h +++ b/src/xenia/gpu/vulkan/vulkan_shader.h @@ -37,8 +37,9 @@ class VulkanShader : public Shader { }; VulkanShader(const ui::vulkan::VulkanProvider& provider, - xenos::ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count); + xenos::ShaderType shader_type, uint64_t ucode_data_hash, + const uint32_t* ucode_dwords, size_t ucode_dword_count, + std::endian ucode_source_endian = std::endian::big); protected: Translation* CreateTranslationInstance(uint64_t modification) override;