[SPIR-V] Version, float controls
This commit is contained in:
parent
cacf702948
commit
52a8ed8e6d
|
@ -108,9 +108,10 @@ 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;
|
||||
SpirvShaderTranslator::Features spirv_features(true);
|
||||
if (cvars::shader_output_type == "spirv" ||
|
||||
cvars::shader_output_type == "spirvtext") {
|
||||
translator = std::make_unique<SpirvShaderTranslator>();
|
||||
translator = std::make_unique<SpirvShaderTranslator>(spirv_features);
|
||||
} else if (cvars::shader_output_type == "dxbc" ||
|
||||
cvars::shader_output_type == "dxbctext") {
|
||||
translator = std::make_unique<DxbcShaderTranslator>(
|
||||
|
@ -161,7 +162,7 @@ int shader_compiler_main(const std::vector<std::string>& args) {
|
|||
spv::Disassemble(spirv_disasm_stream, spirv_source);
|
||||
spirv_disasm = std::move(spirv_disasm_stream.str());
|
||||
ui::vulkan::SpirvToolsContext spirv_tools_context;
|
||||
if (spirv_tools_context.Initialize()) {
|
||||
if (spirv_tools_context.Initialize(spirv_features.spirv_version)) {
|
||||
std::string spirv_validation_error;
|
||||
spirv_tools_context.Validate(
|
||||
reinterpret_cast<const uint32_t*>(spirv_source.data()),
|
||||
|
|
|
@ -20,10 +20,34 @@
|
|||
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) {}
|
||||
SpirvShaderTranslator::Features::Features(bool all)
|
||||
: spirv_version(all ? spv::Spv_1_5 : spv::Spv_1_0),
|
||||
clip_distance(all),
|
||||
cull_distance(all),
|
||||
float_controls(all) {}
|
||||
|
||||
SpirvShaderTranslator::Features::Features(
|
||||
const ui::vulkan::VulkanProvider& provider)
|
||||
: clip_distance(provider.device_features().shaderClipDistance),
|
||||
cull_distance(provider.device_features().shaderCullDistance) {
|
||||
uint32_t device_version = provider.device_properties().apiVersion;
|
||||
const ui::vulkan::VulkanProvider::DeviceExtensions& device_extensions =
|
||||
provider.device_extensions();
|
||||
if (device_version >= VK_MAKE_VERSION(1, 2, 0)) {
|
||||
spirv_version = spv::Spv_1_5;
|
||||
} else if (device_extensions.khr_spirv_1_4) {
|
||||
spirv_version = spv::Spv_1_4;
|
||||
} else if (device_version >= VK_MAKE_VERSION(1, 1, 0)) {
|
||||
spirv_version = spv::Spv_1_3;
|
||||
} else {
|
||||
spirv_version = spv::Spv_1_0;
|
||||
}
|
||||
float_controls = spirv_version >= spv::Spv_1_4 ||
|
||||
device_extensions.khr_shader_float_controls;
|
||||
}
|
||||
|
||||
SpirvShaderTranslator::SpirvShaderTranslator(const Features& features)
|
||||
: features_(features) {}
|
||||
|
||||
void SpirvShaderTranslator::Reset() {
|
||||
ShaderTranslator::Reset();
|
||||
|
@ -32,6 +56,7 @@ void SpirvShaderTranslator::Reset() {
|
|||
|
||||
uniform_float_constants_ = spv::NoResult;
|
||||
|
||||
main_interface_.clear();
|
||||
var_main_registers_ = spv::NoResult;
|
||||
|
||||
main_switch_op_.reset();
|
||||
|
@ -45,10 +70,16 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
// Tool ID 26 "Xenia Emulator Microcode Translator".
|
||||
// https://github.com/KhronosGroup/SPIRV-Headers/blob/c43a43c7cc3af55910b9bec2a71e3e8a622443cf/include/spirv/spir-v.xml#L79
|
||||
// TODO(Triang3l): Logger.
|
||||
builder_ = std::make_unique<spv::Builder>(1 << 16, (26 << 16) | 1, nullptr);
|
||||
builder_ = std::make_unique<spv::Builder>(features_.spirv_version,
|
||||
(26 << 16) | 1, nullptr);
|
||||
|
||||
builder_->addCapability(IsSpirvTessEvalShader() ? spv::CapabilityTessellation
|
||||
: spv::CapabilityShader);
|
||||
if (features_.spirv_version < spv::Spv_1_4) {
|
||||
if (features_.float_controls) {
|
||||
builder_->addExtension("SPV_KHR_float_controls");
|
||||
}
|
||||
}
|
||||
ext_inst_glsl_std_450_ = builder_->import("GLSL.std.450");
|
||||
builder_->setMemoryModel(spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450);
|
||||
|
@ -133,6 +164,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
: kDescriptorSetFloatConstantsVertex));
|
||||
builder_->addDecoration(uniform_float_constants_, spv::DecorationBinding,
|
||||
0);
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_float_constants_);
|
||||
}
|
||||
}
|
||||
|
||||
// Common uniform buffer - bool and loop constants.
|
||||
|
@ -168,6 +202,9 @@ void SpirvShaderTranslator::StartTranslation() {
|
|||
int(kDescriptorSetBoolLoopConstants));
|
||||
builder_->addDecoration(uniform_bool_loop_constants_, spv::DecorationBinding,
|
||||
0);
|
||||
if (features_.spirv_version >= spv::Spv_1_4) {
|
||||
main_interface_.push_back(uniform_bool_loop_constants_);
|
||||
}
|
||||
|
||||
if (IsSpirvVertexOrTessEvalShader()) {
|
||||
StartVertexOrTessEvalShaderBeforeMain();
|
||||
|
@ -364,11 +401,23 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
|||
? spv::ExecutionModelTessellationEvaluation
|
||||
: spv::ExecutionModelVertex;
|
||||
}
|
||||
if (features_.float_controls) {
|
||||
// Flush to zero, similar to the real hardware, also for things like Shader
|
||||
// Model 3 multiplication emulation.
|
||||
builder_->addCapability(spv::CapabilityDenormFlushToZero);
|
||||
builder_->addExecutionMode(function_main_,
|
||||
spv::ExecutionModeDenormFlushToZero, 32);
|
||||
// Signed zero used to get VFACE from ps_param_gen, also special behavior
|
||||
// for infinity in certain instructions (such as logarithm, reciprocal,
|
||||
// muls_prev2).
|
||||
builder_->addCapability(spv::CapabilitySignedZeroInfNanPreserve);
|
||||
builder_->addExecutionMode(function_main_,
|
||||
spv::ExecutionModeSignedZeroInfNanPreserve, 32);
|
||||
}
|
||||
spv::Instruction* entry_point =
|
||||
builder_->addEntryPoint(execution_model, function_main_, "main");
|
||||
|
||||
if (IsSpirvVertexOrTessEvalShader()) {
|
||||
CompleteVertexOrTessEvalShaderAfterMain(entry_point);
|
||||
for (spv::Id interface_id : main_interface_) {
|
||||
entry_point->addIdOperand(interface_id);
|
||||
}
|
||||
|
||||
// TODO(Triang3l): Avoid copy?
|
||||
|
@ -721,11 +770,13 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
|||
spv::NoPrecision, spv::StorageClassInput, type_int_, "gl_PrimitiveID");
|
||||
builder_->addDecoration(input_primitive_id_, spv::DecorationBuiltIn,
|
||||
spv::BuiltInPrimitiveId);
|
||||
main_interface_.push_back(input_primitive_id_);
|
||||
} else {
|
||||
input_vertex_index_ = builder_->createVariable(
|
||||
spv::NoPrecision, spv::StorageClassInput, type_int_, "gl_VertexIndex");
|
||||
builder_->addDecoration(input_vertex_index_, spv::DecorationBuiltIn,
|
||||
spv::BuiltInVertexIndex);
|
||||
main_interface_.push_back(input_vertex_index_);
|
||||
}
|
||||
|
||||
// Create the entire GLSL 4.50 gl_PerVertex output similar to what glslang
|
||||
|
@ -733,10 +784,10 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
|||
// 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_) {
|
||||
if (features_.clip_distance) {
|
||||
builder_->addCapability(spv::CapabilityClipDistance);
|
||||
}
|
||||
if (supports_cull_distance_) {
|
||||
if (features_.cull_distance) {
|
||||
builder_->addCapability(spv::CapabilityCullDistance);
|
||||
}
|
||||
std::vector<spv::Id> struct_per_vertex_members;
|
||||
|
@ -746,7 +797,7 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
|||
// 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),
|
||||
type_float_, builder_->makeUintConstant(features_.clip_distance ? 6 : 1),
|
||||
0));
|
||||
struct_per_vertex_members.push_back(
|
||||
builder_->makeArrayType(type_float_, builder_->makeUintConstant(1), 0));
|
||||
|
@ -777,6 +828,7 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
|||
output_per_vertex_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_struct_per_vertex, "xe_out_gl_PerVertex");
|
||||
main_interface_.push_back(output_per_vertex_);
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||
|
@ -787,16 +839,6 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
|||
|
||||
void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {}
|
||||
|
||||
void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderAfterMain(
|
||||
spv::Instruction* entry_point) {
|
||||
if (IsSpirvTessEvalShader()) {
|
||||
entry_point->addIdOperand(input_primitive_id_);
|
||||
} else {
|
||||
entry_point->addIdOperand(input_vertex_index_);
|
||||
}
|
||||
entry_point->addIdOperand(output_per_vertex_);
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::UpdateExecConditionals(
|
||||
ParsedExecInstruction::Type type, uint32_t bool_constant_index,
|
||||
bool condition) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
||||
#include "xenia/gpu/shader_translator.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
@ -46,8 +47,16 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
kDescriptorSetSharedMemoryAndEdram,
|
||||
kDescriptorSetCount,
|
||||
};
|
||||
SpirvShaderTranslator(bool supports_clip_distance = true,
|
||||
bool supports_cull_distance = true);
|
||||
|
||||
struct Features {
|
||||
explicit Features(const ui::vulkan::VulkanProvider& provider);
|
||||
explicit Features(bool all = false);
|
||||
unsigned int spirv_version;
|
||||
bool clip_distance;
|
||||
bool cull_distance;
|
||||
bool float_controls;
|
||||
};
|
||||
SpirvShaderTranslator(const Features& features);
|
||||
|
||||
protected:
|
||||
void Reset() override;
|
||||
|
@ -90,7 +99,6 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
void StartVertexOrTessEvalShaderBeforeMain();
|
||||
void StartVertexOrTessEvalShaderInMain();
|
||||
void CompleteVertexOrTessEvalShaderInMain();
|
||||
void CompleteVertexOrTessEvalShaderAfterMain(spv::Instruction* entry_point);
|
||||
|
||||
// Updates the current flow control condition (to be called in the beginning
|
||||
// of exec and in jumps), closing the previous conditionals if needed.
|
||||
|
@ -148,8 +156,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
spv::Id ProcessVectorAluOperation(const ParsedAluInstruction& instr,
|
||||
bool& predicate_written);
|
||||
|
||||
bool supports_clip_distance_;
|
||||
bool supports_cull_distance_;
|
||||
Features features_;
|
||||
|
||||
std::unique_ptr<spv::Builder> builder_;
|
||||
|
||||
|
@ -223,6 +230,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
|||
};
|
||||
spv::Id output_per_vertex_;
|
||||
|
||||
std::vector<spv::Id> main_interface_;
|
||||
spv::Function* function_main_;
|
||||
// bool.
|
||||
spv::Id var_main_predicate_;
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace xe {
|
|||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
bool SpirvToolsContext::Initialize() {
|
||||
bool SpirvToolsContext::Initialize(unsigned int spirv_version) {
|
||||
const char* vulkan_sdk_env = std::getenv("VULKAN_SDK");
|
||||
if (!vulkan_sdk_env) {
|
||||
XELOGE("SPIRV-Tools: Failed to get the VULKAN_SDK environment variable");
|
||||
|
@ -63,7 +63,17 @@ bool SpirvToolsContext::Initialize() {
|
|||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
context_ = fn_spvContextCreate_(SPV_ENV_VULKAN_1_0);
|
||||
spv_target_env target_env;
|
||||
if (spirv_version >= 0x10500) {
|
||||
target_env = SPV_ENV_VULKAN_1_2;
|
||||
} else if (spirv_version >= 0x10400) {
|
||||
target_env = SPV_ENV_VULKAN_1_1_SPIRV_1_4;
|
||||
} else if (spirv_version >= 0x10300) {
|
||||
target_env = SPV_ENV_VULKAN_1_1;
|
||||
} else {
|
||||
target_env = SPV_ENV_VULKAN_1_0;
|
||||
}
|
||||
context_ = fn_spvContextCreate_(target_env);
|
||||
if (!context_) {
|
||||
XELOGE("SPIRV-Tools: Failed to create a Vulkan 1.0 context");
|
||||
Shutdown();
|
||||
|
|
|
@ -32,7 +32,7 @@ class SpirvToolsContext {
|
|||
SpirvToolsContext(const SpirvToolsContext& context) = delete;
|
||||
SpirvToolsContext& operator=(const SpirvToolsContext& context) = delete;
|
||||
~SpirvToolsContext() { Shutdown(); }
|
||||
bool Initialize();
|
||||
bool Initialize(unsigned int spirv_version);
|
||||
void Shutdown();
|
||||
|
||||
spv_result_t Validate(const uint32_t* words, size_t num_words,
|
||||
|
|
|
@ -392,6 +392,10 @@ bool VulkanProvider::Initialize() {
|
|||
std::memset(&device_extensions_, 0, sizeof(device_extensions_));
|
||||
if (device_properties_.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
|
||||
device_extensions_.khr_dedicated_allocation = true;
|
||||
if (device_properties_.apiVersion >= VK_MAKE_VERSION(1, 2, 0)) {
|
||||
device_extensions_.khr_shader_float_controls = true;
|
||||
device_extensions_.khr_spirv_1_4 = true;
|
||||
}
|
||||
}
|
||||
bool device_supports_swapchain = false;
|
||||
for (const VkExtensionProperties& device_extension :
|
||||
|
@ -405,6 +409,13 @@ bool VulkanProvider::Initialize() {
|
|||
!std::strcmp(device_extension_name,
|
||||
"VK_KHR_dedicated_allocation")) {
|
||||
device_extensions_.khr_dedicated_allocation = true;
|
||||
} else if (!device_extensions_.khr_shader_float_controls &&
|
||||
!std::strcmp(device_extension_name,
|
||||
"VK_KHR_shader_float_controls")) {
|
||||
device_extensions_.khr_shader_float_controls = true;
|
||||
} else if (!device_extensions_.khr_spirv_1_4 &&
|
||||
!std::strcmp(device_extension_name, "VK_KHR_spirv_1_4")) {
|
||||
device_extensions_.khr_spirv_1_4 = true;
|
||||
} else if (!device_supports_swapchain &&
|
||||
!std::strcmp(device_extension_name, "VK_KHR_swapchain")) {
|
||||
device_supports_swapchain = true;
|
||||
|
@ -466,6 +477,10 @@ bool VulkanProvider::Initialize() {
|
|||
device_extensions_.ext_fragment_shader_interlock ? "yes" : "no");
|
||||
XELOGVK("* VK_KHR_dedicated_allocation: {}",
|
||||
device_extensions_.khr_dedicated_allocation ? "yes" : "no");
|
||||
XELOGVK("* VK_KHR_shader_float_controls: {}",
|
||||
device_extensions_.khr_shader_float_controls ? "yes" : "no");
|
||||
XELOGVK("* VK_KHR_spirv_1_4: {}",
|
||||
device_extensions_.khr_spirv_1_4 ? "yes" : "no");
|
||||
// TODO(Triang3l): Report properties, features.
|
||||
|
||||
// Create the device.
|
||||
|
@ -493,9 +508,17 @@ bool VulkanProvider::Initialize() {
|
|||
if (device_extensions_.ext_fragment_shader_interlock) {
|
||||
device_extensions_enabled.push_back("VK_EXT_fragment_shader_interlock");
|
||||
}
|
||||
if (device_properties_.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
|
||||
if (device_extensions_.khr_dedicated_allocation) {
|
||||
device_extensions_enabled.push_back("VK_KHR_dedicated_allocation");
|
||||
if (device_properties_.apiVersion < VK_MAKE_VERSION(1, 2, 0)) {
|
||||
if (device_properties_.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
|
||||
if (device_extensions_.khr_dedicated_allocation) {
|
||||
device_extensions_enabled.push_back("VK_KHR_dedicated_allocation");
|
||||
}
|
||||
}
|
||||
if (device_extensions_.khr_shader_float_controls) {
|
||||
device_extensions_enabled.push_back("VK_KHR_shader_float_controls");
|
||||
}
|
||||
if (device_extensions_.khr_spirv_1_4) {
|
||||
device_extensions_enabled.push_back("VK_KHR_spirv_1_4");
|
||||
}
|
||||
}
|
||||
VkDeviceCreateInfo device_create_info;
|
||||
|
|
|
@ -104,6 +104,10 @@ class VulkanProvider : public GraphicsProvider {
|
|||
bool ext_fragment_shader_interlock;
|
||||
// Core since 1.1.0.
|
||||
bool khr_dedicated_allocation;
|
||||
// Core since 1.2.0.
|
||||
bool khr_shader_float_controls;
|
||||
// Core since 1.2.0.
|
||||
bool khr_spirv_1_4;
|
||||
};
|
||||
const DeviceExtensions& device_extensions() const {
|
||||
return device_extensions_;
|
||||
|
|
Loading…
Reference in New Issue