[SPIR-V] Some initial bits of the translator
This commit is contained in:
parent
3a308dedb3
commit
b3339d7e46
|
@ -9,9 +9,12 @@
|
|||
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/glslang/SPIRV/disassemble.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/main.h"
|
||||
|
@ -19,6 +22,7 @@
|
|||
#include "xenia/base/string.h"
|
||||
#include "xenia/gpu/dxbc_shader_translator.h"
|
||||
#include "xenia/gpu/shader_translator.h"
|
||||
#include "xenia/gpu/spirv_shader_translator.h"
|
||||
|
||||
// For D3DDisassemble:
|
||||
#if XE_PLATFORM_WIN32
|
||||
|
@ -31,7 +35,8 @@ DEFINE_string(shader_input_type, "",
|
|||
"GPU");
|
||||
DEFINE_path(shader_output, "", "Output shader file path.", "GPU");
|
||||
DEFINE_string(shader_output_type, "ucode",
|
||||
"Translator to use: [ucode, dxbc, dxbctext].", "GPU");
|
||||
"Translator to use: [ucode, spirv, spirvtext, dxbc, dxbctext].",
|
||||
"GPU");
|
||||
DEFINE_string(
|
||||
vertex_shader_output_type, "",
|
||||
"Type of the host interface to produce the vertex or domain shader for: "
|
||||
|
@ -102,8 +107,11 @@ int shader_compiler_main(const std::vector<std::string>& args) {
|
|||
shader_type, ucode_data_hash, ucode_dwords.data(), ucode_dwords.size());
|
||||
|
||||
std::unique_ptr<ShaderTranslator> translator;
|
||||
if (cvars::shader_output_type == "dxbc" ||
|
||||
cvars::shader_output_type == "dxbctext") {
|
||||
if (cvars::shader_output_type == "spirv" ||
|
||||
cvars::shader_output_type == "spirvtext") {
|
||||
translator = std::make_unique<SpirvShaderTranslator>();
|
||||
} else if (cvars::shader_output_type == "dxbc" ||
|
||||
cvars::shader_output_type == "dxbctext") {
|
||||
translator = std::make_unique<DxbcShaderTranslator>(
|
||||
0, cvars::shader_output_bindless_resources,
|
||||
cvars::shader_output_dxbc_rov);
|
||||
|
@ -140,6 +148,20 @@ int shader_compiler_main(const std::vector<std::string>& args) {
|
|||
const void* source_data = shader->translated_binary().data();
|
||||
size_t source_data_size = shader->translated_binary().size();
|
||||
|
||||
std::string spirv_disasm;
|
||||
if (cvars::shader_output_type == "spirvtext") {
|
||||
std::ostringstream spirv_disasm_stream;
|
||||
std::vector<unsigned int> spirv_source;
|
||||
spirv_source.reserve(source_data_size / sizeof(unsigned int));
|
||||
spirv_source.insert(spirv_source.cend(),
|
||||
reinterpret_cast<const unsigned int*>(source_data),
|
||||
reinterpret_cast<const unsigned int*>(source_data) +
|
||||
source_data_size / sizeof(unsigned int));
|
||||
spv::Disassemble(spirv_disasm_stream, spirv_source);
|
||||
spirv_disasm = std::move(spirv_disasm_stream.str());
|
||||
source_data = spirv_disasm.c_str();
|
||||
source_data_size = spirv_disasm.size();
|
||||
}
|
||||
#if XE_PLATFORM_WIN32
|
||||
ID3DBlob* dxbc_disasm_blob = nullptr;
|
||||
if (cvars::shader_output_type == "dxbctext") {
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/gpu/spirv_shader_translator.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/glslang/SPIRV/GLSL.std.450.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
SpirvShaderTranslator::SpirvShaderTranslator(bool supports_clip_distance,
|
||||
bool supports_cull_distance)
|
||||
: supports_clip_distance_(supports_clip_distance),
|
||||
supports_cull_distance_(supports_cull_distance) {}
|
||||
|
||||
void SpirvShaderTranslator::Reset() {
|
||||
ShaderTranslator::Reset();
|
||||
|
||||
builder_.reset();
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::StartTranslation() {
|
||||
// TODO(Triang3l): Once tool ID (likely 26) is registered in SPIRV-Headers,
|
||||
// use it instead.
|
||||
// TODO(Triang3l): Logger.
|
||||
builder_ = std::make_unique<spv::Builder>(0x10000, 0xFFFF0001, nullptr);
|
||||
|
||||
builder_->addCapability(IsSpirvTessEvalShader() ? spv::CapabilityTessellation
|
||||
: spv::CapabilityShader);
|
||||
ext_inst_glsl_std_450_ = builder_->import("GLSL.std.450");
|
||||
builder_->setMemoryModel(spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450);
|
||||
builder_->setSource(spv::SourceLanguageUnknown, 0);
|
||||
|
||||
type_void_ = builder_->makeVoidType();
|
||||
type_float_ = builder_->makeFloatType(32);
|
||||
type_float2_ = builder_->makeVectorType(type_float_, 2);
|
||||
type_float3_ = builder_->makeVectorType(type_float_, 3);
|
||||
type_float4_ = builder_->makeVectorType(type_float_, 4);
|
||||
type_int_ = builder_->makeIntType(32);
|
||||
|
||||
if (IsSpirvVertexOrTessEvalShader()) {
|
||||
StartVertexOrTessEvalShaderBeforeMain();
|
||||
}
|
||||
|
||||
// Begin the main function.
|
||||
std::vector<spv::Id> main_param_types;
|
||||
std::vector<std::vector<spv::Decoration>> main_precisions;
|
||||
spv::Block* main_entry;
|
||||
builder_->makeFunctionEntry(spv::NoPrecision, type_void_, "main",
|
||||
main_param_types, main_precisions, &main_entry);
|
||||
|
||||
// Begin ucode translation.
|
||||
if (register_count()) {
|
||||
var_main_registers_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassFunction,
|
||||
builder_->makeArrayType(
|
||||
type_float4_, builder_->makeUintConstant(register_count()), 0),
|
||||
"xe_r");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||
if (IsSpirvVertexOrTessEvalShader()) {
|
||||
CompleteVertexOrTessEvalShaderInMain();
|
||||
}
|
||||
|
||||
// End the main function..
|
||||
builder_->leaveFunction();
|
||||
|
||||
// TODO(Triang3l): Avoid copy?
|
||||
std::vector<unsigned int> module_uints;
|
||||
builder_->dump(module_uints);
|
||||
std::vector<uint8_t> module_bytes;
|
||||
module_bytes.reserve(sizeof(unsigned int) * module_uints.size());
|
||||
module_bytes.insert(module_bytes.cend(),
|
||||
reinterpret_cast<const uint8_t*>(module_uints.data()),
|
||||
reinterpret_cast<const uint8_t*>(module_uints.data()) +
|
||||
sizeof(unsigned int) * module_uints.size());
|
||||
return module_bytes;
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
||||
// Create the inputs.
|
||||
if (IsSpirvTessEvalShader()) {
|
||||
input_vertex_index_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassInput, type_int_, "gl_PrimitiveID");
|
||||
builder_->addDecoration(input_vertex_index_, spv::DecorationBuiltIn,
|
||||
spv::BuiltInPrimitiveId);
|
||||
} else {
|
||||
input_primitive_id_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassInput, type_int_, "gl_VertexIndex");
|
||||
builder_->addDecoration(input_primitive_id_, spv::DecorationBuiltIn,
|
||||
spv::BuiltInVertexIndex);
|
||||
}
|
||||
|
||||
// Create the entire GLSL 4.50 gl_PerVertex output similar to what glslang
|
||||
// does. Members (like gl_PointSize) don't need to be used, and also
|
||||
// ClipDistance and CullDistance may exist even if the device doesn't support
|
||||
// them, as long as the capabilities aren't enabled, and nothing is stored to
|
||||
// them.
|
||||
if (supports_clip_distance_) {
|
||||
builder_->addCapability(spv::CapabilityClipDistance);
|
||||
}
|
||||
if (supports_cull_distance_) {
|
||||
builder_->addCapability(spv::CapabilityCullDistance);
|
||||
}
|
||||
std::vector<spv::Id> struct_per_vertex_members;
|
||||
struct_per_vertex_members.reserve(kOutputPerVertexMemberCount);
|
||||
struct_per_vertex_members.push_back(type_float4_);
|
||||
struct_per_vertex_members.push_back(type_float_);
|
||||
// TODO(Triang3l): Specialization constant for ucp_cull_only_ena, for 6 + 1
|
||||
// or 1 + 7 array sizes.
|
||||
struct_per_vertex_members.push_back(builder_->makeArrayType(
|
||||
type_float_, builder_->makeUintConstant(supports_clip_distance_ ? 6 : 1),
|
||||
0));
|
||||
struct_per_vertex_members.push_back(
|
||||
builder_->makeArrayType(type_float_, builder_->makeUintConstant(1), 0));
|
||||
spv::Id type_struct_per_vertex =
|
||||
builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex");
|
||||
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||
kOutputPerVertexMemberPosition,
|
||||
spv::DecorationBuiltIn, spv::BuiltInPosition);
|
||||
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||
kOutputPerVertexMemberPointSize,
|
||||
spv::DecorationBuiltIn, spv::BuiltInPointSize);
|
||||
builder_->addMemberDecoration(
|
||||
type_struct_per_vertex, kOutputPerVertexMemberClipDistance,
|
||||
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
|
||||
builder_->addMemberDecoration(
|
||||
type_struct_per_vertex, kOutputPerVertexMemberCullDistance,
|
||||
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
|
||||
builder_->addDecoration(type_struct_per_vertex, spv::DecorationBlock);
|
||||
output_per_vertex_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_struct_per_vertex, "xe_out_gl_PerVertex");
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {}
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_GPU_SPIRV_SHADER_TRANSLATOR_H_
|
||||
#define XENIA_GPU_SPIRV_SHADER_TRANSLATOR_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
||||
#include "xenia/gpu/shader_translator.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
class SpirvShaderTranslator : public ShaderTranslator {
|
||||
public:
|
||||
SpirvShaderTranslator(bool supports_clip_distance = true,
|
||||
bool supports_cull_distance = true);
|
||||
|
||||
protected:
|
||||
void Reset() override;
|
||||
|
||||
void StartTranslation() override;
|
||||
|
||||
std::vector<uint8_t> CompleteTranslation() override;
|
||||
|
||||
private:
|
||||
// TODO(Triang3l): Depth-only pixel shader.
|
||||
bool IsSpirvVertexOrTessEvalShader() const { return is_vertex_shader(); }
|
||||
bool IsSpirvVertexShader() const {
|
||||
return IsSpirvVertexOrTessEvalShader() &&
|
||||
host_vertex_shader_type() == Shader::HostVertexShaderType::kVertex;
|
||||
}
|
||||
bool IsSpirvTessEvalShader() const {
|
||||
return IsSpirvVertexOrTessEvalShader() &&
|
||||
host_vertex_shader_type() != Shader::HostVertexShaderType::kVertex;
|
||||
}
|
||||
bool IsSpirvFragmentShader() const { return is_pixel_shader(); }
|
||||
|
||||
void StartVertexOrTessEvalShaderBeforeMain();
|
||||
void CompleteVertexOrTessEvalShaderInMain();
|
||||
|
||||
bool supports_clip_distance_;
|
||||
bool supports_cull_distance_;
|
||||
|
||||
std::unique_ptr<spv::Builder> builder_;
|
||||
|
||||
spv::Id ext_inst_glsl_std_450_;
|
||||
|
||||
spv::Id type_void_;
|
||||
spv::Id type_float_;
|
||||
spv::Id type_float2_;
|
||||
spv::Id type_float3_;
|
||||
spv::Id type_float4_;
|
||||
spv::Id type_int_;
|
||||
spv::Id type_uint_;
|
||||
|
||||
spv::Id input_vertex_index_;
|
||||
spv::Id input_primitive_id_;
|
||||
|
||||
enum OutputPerVertexMember : unsigned int {
|
||||
kOutputPerVertexMemberPosition,
|
||||
kOutputPerVertexMemberPointSize,
|
||||
kOutputPerVertexMemberClipDistance,
|
||||
kOutputPerVertexMemberCullDistance,
|
||||
kOutputPerVertexMemberCount,
|
||||
};
|
||||
spv::Id output_per_vertex_;
|
||||
|
||||
spv::Id function_main_;
|
||||
spv::Id var_main_registers_;
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_GPU_SPIRV_SHADER_TRANSLATOR_H_
|
Loading…
Reference in New Issue