[Vulkan] Remove runtime dependency on SPIRV-Tools

This commit is contained in:
Herman S.
2026-04-16 00:46:13 +09:00
parent ede37f016a
commit f1dfb08dda
12 changed files with 28 additions and 384 deletions
+2 -2
View File
@@ -79,7 +79,7 @@ jobs:
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-21 main"
sudo apt-get -y update
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-21 lld-21 ninja-build cmake spirv-tools libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-cursor0 libxcb-shape0 libfontconfig1-dev libxtst-dev
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-21 lld-21 ninja-build cmake libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-cursor0 libxcb-shape0 libfontconfig1-dev libxtst-dev
# Install Vulkan SDK
if [ '${{ steps.cache-vulkan-sdk-linux.outputs.cache-hit }}' != 'true' ]; then
@@ -244,7 +244,7 @@ jobs:
- name: Setup
run: |
# Install Vulkan SDK which includes spirv-tools
# Install Vulkan SDK for headers + loader
if (Test-Path -Path "C:\VulkanSDK") {
echo "Vulkan SDK found in cache."
} else {
+6 -6
View File
@@ -60,11 +60,11 @@ file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/scratch")
find_package(Python3 REQUIRED COMPONENTS Interpreter)
# Debug/Checked/Valgrind are compiled against the release CRT (/MD) so we
# can link the Vulkan SDK's release-only SPIRV-Tools libs. Force any
# imported library (Qt6::*, etc.) to resolve to its Release variant in
# those configs too — otherwise Qt6*d.dll drags in /MDd and the process
# ends up mixing two CRTs, corrupting std::string/QString allocations.
# Debug/Checked/Valgrind are compiled against the release CRT (/MD) so
# we can link Qt's release-only prebuilt DLLs — Qt6*d.dll drags in /MDd
# and mixing two CRTs in one process corrupts std::string/QString
# allocations. Force any imported library (Qt6::*, etc.) to resolve to
# its Release variant in those configs too.
# NOCONFIG is the fallback for imported targets that ship without a
# configuration suffix (FindOpenGL on Linux creates OpenGL::OpenGL this
# way — without NOCONFIG in the map we fail to resolve it in Debug et al).
@@ -193,7 +193,7 @@ if(MSVC)
# Debug: /RTC1 requires the debug CRT, so strip it — we're on /MD. Pin
# _ITERATOR_DEBUG_LEVEL=0 so our STL object layouts match release-CRT
# prebuilts (Vulkan SDK SPIRV-Tools) and we don't hit LNK2038.
# prebuilts (Qt, etc.) and we don't hit LNK2038.
string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
add_compile_definitions(
+11 -14
View File
@@ -130,20 +130,17 @@ set(_edge_game_patches_src "${PROJECT_SOURCE_DIR}/.data_repos/game-patches/patch
# release Qt (root CMakeLists maps Debug/Checked/Valgrind imported
# configs to Release), so deploying Qt6Cored.dll would pull in the
# debug CRT and corrupt Qt/STL objects at runtime.
if(WIN32)
set(XE_QT_DIR "$ENV{QT_DIR}")
if(XE_QT_DIR AND EXISTS "${XE_QT_DIR}/bin/windeployqt.exe")
add_custom_command(TARGET xenia-app POST_BUILD
COMMAND "${XE_QT_DIR}/bin/windeployqt.exe"
--release
--no-translations
--no-system-d3d-compiler
--no-opengl-sw
--no-compiler-runtime
"$<TARGET_FILE:xenia-app>"
VERBATIM
)
endif()
if(WIN32 AND TARGET Qt6::windeployqt)
add_custom_command(TARGET xenia-app POST_BUILD
COMMAND Qt6::windeployqt
--release
--no-translations
--no-system-d3d-compiler
--no-opengl-sw
--no-compiler-runtime
"$<TARGET_FILE:xenia-app>"
VERBATIM
)
endif()
# Stage runtime assets (fonts, game patches, optimized settings) next to
-7
View File
@@ -4,10 +4,6 @@ target_include_directories(xenia-gpu PRIVATE
${PROJECT_SOURCE_DIR}/third_party/Vulkan-Headers/include
${PROJECT_SOURCE_DIR}/third_party/glslang
)
# Windows: SPIRV-Tools headers come from the Vulkan SDK
if(WIN32 AND DEFINED ENV{VULKAN_SDK})
target_include_directories(xenia-gpu PRIVATE "$ENV{VULKAN_SDK}/Include")
endif()
target_link_libraries(xenia-gpu PUBLIC dxbc fmt glslang-spirv snappy xxhash xenia-base xenia-ui)
xe_target_defaults(xenia-gpu)
@@ -27,9 +23,6 @@ if(XENIA_BUILD_MISC)
${PROJECT_SOURCE_DIR}/third_party/Vulkan-Headers/include
${PROJECT_SOURCE_DIR}/third_party/glslang
)
if(WIN32 AND DEFINED ENV{VULKAN_SDK})
target_include_directories(xenia-gpu-shader-compiler PRIVATE "$ENV{VULKAN_SDK}/Include")
endif()
target_link_libraries(xenia-gpu-shader-compiler PRIVATE
dxbc fmt glslang-spirv snappy xenia-base xenia-gpu xenia-ui xenia-ui-vulkan
)
-12
View File
@@ -24,7 +24,6 @@
#include "xenia/gpu/shader_translator.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/spirv_tools_context.h"
// For D3DDisassemble:
#if XE_PLATFORM_WIN32
@@ -197,17 +196,6 @@ int shader_compiler_main(const std::vector<std::string>& args) {
source_data_size / sizeof(unsigned int));
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(spirv_features.spirv_version)) {
std::string spirv_validation_error;
spirv_tools_context.Validate(
reinterpret_cast<const uint32_t*>(spirv_source.data()),
spirv_source.size(), &spirv_validation_error);
if (!spirv_validation_error.empty()) {
spirv_disasm.append(1, '\n');
spirv_disasm.append(spirv_validation_error);
}
}
source_data = spirv_disasm.c_str();
source_data_size = spirv_disasm.size();
}
-19
View File
@@ -22,7 +22,6 @@
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/spirv_compatibility.h"
#include "xenia/gpu/spirv_shader.h"
#include "xenia/ui/vulkan/spirv_tools_context.h"
DEFINE_string(spirv_version_override, "1.0",
"Override the SPIR-V version used in shader translation.\n"
@@ -958,24 +957,6 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
std::vector<unsigned int> module_uints;
builder_->dump(module_uints);
// Optimize the SPIR-V if optimization is enabled and tools are available
if (spirv_optimize_ && spirv_tools_context_) {
size_t original_size = module_uints.size();
std::vector<uint32_t> optimized_module;
spv_result_t result = spirv_tools_context_->Optimize(
module_uints.data(), module_uints.size(), optimized_module, true);
if (result == SPV_SUCCESS && !optimized_module.empty()) {
size_t optimized_size = optimized_module.size();
module_uints = std::move(optimized_module);
XELOGI("SPIR-V shader optimized: {} -> {} words ({:.1f}% reduction)",
original_size, optimized_size,
100.0f * (1.0f - float(optimized_size) / float(original_size)));
} else {
XELOGW("SPIR-V shader optimization failed with error code: {}",
static_cast<int>(result));
}
}
std::vector<uint8_t> module_bytes;
module_bytes.reserve(sizeof(unsigned int) * module_uints.size());
module_bytes.insert(module_bytes.cend(),
+7 -17
View File
@@ -23,11 +23,6 @@
#include "xenia/ui/vulkan/vulkan_device.h"
namespace xe {
namespace ui {
namespace vulkan {
class SpirvToolsContext;
} // namespace vulkan
} // namespace ui
namespace gpu {
class SpirvShaderTranslator : public ShaderTranslator {
@@ -398,21 +393,18 @@ class SpirvShaderTranslator : public ShaderTranslator {
bool fragment_shader_barycentric;
};
SpirvShaderTranslator(
const Features& features, bool native_2x_msaa_with_attachments,
bool native_2x_msaa_no_attachments, bool edram_fragment_shader_interlock,
uint32_t draw_resolution_scale_x = 1,
uint32_t draw_resolution_scale_y = 1,
ui::vulkan::SpirvToolsContext* spirv_tools_context = nullptr,
bool spirv_optimize = true)
SpirvShaderTranslator(const Features& features,
bool native_2x_msaa_with_attachments,
bool native_2x_msaa_no_attachments,
bool edram_fragment_shader_interlock,
uint32_t draw_resolution_scale_x = 1,
uint32_t draw_resolution_scale_y = 1)
: features_(features),
native_2x_msaa_with_attachments_(native_2x_msaa_with_attachments),
native_2x_msaa_no_attachments_(native_2x_msaa_no_attachments),
edram_fragment_shader_interlock_(edram_fragment_shader_interlock),
draw_resolution_scale_x_(draw_resolution_scale_x),
draw_resolution_scale_y_(draw_resolution_scale_y),
spirv_tools_context_(spirv_tools_context),
spirv_optimize_(spirv_optimize) {}
draw_resolution_scale_y_(draw_resolution_scale_y) {}
uint64_t GetDefaultVertexShaderModification(
uint32_t dynamic_addressable_register_count,
@@ -787,8 +779,6 @@ class SpirvShaderTranslator : public ShaderTranslator {
bool native_2x_msaa_no_attachments_;
uint32_t draw_resolution_scale_x_;
uint32_t draw_resolution_scale_y_;
ui::vulkan::SpirvToolsContext* spirv_tools_context_;
bool spirv_optimize_;
// For safety with different drivers (even though fragment shader interlock in
// SPIR-V only has one control flow requirement - that both begin and end must
+2 -107
View File
@@ -33,7 +33,6 @@
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/vulkan/vulkan_shared_memory.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/spirv_tools_context.h"
#include "xenia/ui/vulkan/vulkan_util.h"
// Shader bytecode.
@@ -62,13 +61,6 @@ DEFINE_int32(
"0 to disable multithreaded pipeline creation.",
"Vulkan");
DEFINE_bool(
vulkan_spirv_optimization, false,
"Enable SPIR-V shader optimization. When enabled, shaders are optimized "
"on pipeline creation threads before the shader module is created. This "
"only affects async pipeline creation and does not block the main thread.",
"Vulkan");
DECLARE_bool(vulkan_dynamic_rendering);
namespace xe {
@@ -98,24 +90,13 @@ bool VulkanPipelineCache::Initialize() {
render_target_cache_.GetPath() ==
RenderTargetCache::Path::kPixelShaderInterlock;
// Initialize SPIRV-Tools (used for validation and optional optimization)
spirv_tools_context_ = std::make_unique<ui::vulkan::SpirvToolsContext>();
if (!spirv_tools_context_->Initialize(spirv_version_)) {
XELOGE("Failed to initialize SPIRV-Tools");
// Continue without SPIRV-Tools
spirv_tools_context_.reset();
} else {
XELOGI("SPIRV-Tools initialized successfully");
}
shader_translator_ = std::make_unique<SpirvShaderTranslator>(
SpirvShaderTranslator::Features(vulkan_device),
render_target_cache_.msaa_2x_attachments_supported(),
render_target_cache_.msaa_2x_no_attachments_supported(),
edram_fragment_shader_interlock,
render_target_cache_.draw_resolution_scale_x(),
render_target_cache_.draw_resolution_scale_y(), nullptr,
false); // Never optimize during initial translation
render_target_cache_.draw_resolution_scale_y());
if (edram_fragment_shader_interlock) {
std::vector<uint8_t> depth_only_fragment_shader_code =
@@ -845,13 +826,6 @@ void VulkanPipelineCache::CreationThread() {
creation_arguments.pixel_shader)) {
XELOGE("Failed to translate shaders for pipeline creation");
} else {
// Optimize shaders on the creation thread before creating the pipeline.
// This keeps the main thread fast while still benefiting from
// optimization.
OptimizeTranslationIfNeeded(*creation_arguments.vertex_shader);
if (creation_arguments.pixel_shader) {
OptimizeTranslationIfNeeded(*creation_arguments.pixel_shader);
}
if (!EnsurePipelineCreated(creation_arguments)) {
XELOGE("Failed to create Vulkan pipeline");
}
@@ -905,32 +879,6 @@ bool VulkanPipelineCache::TranslateAnalyzedShader(
return false;
}
#ifndef NDEBUG
// Validate SPIR-V before creating shader module to get detailed error
// messages. This is a warning only - we still try to create the shader
// module to see if the driver accepts it.
if (spirv_tools_context_) {
std::string validation_error;
spv_result_t validation_result = spirv_tools_context_->Validate(
reinterpret_cast<const uint32_t*>(
translation.translated_binary().data()),
translation.translated_binary().size() / sizeof(uint32_t),
&validation_error);
if (validation_result != SPV_SUCCESS) {
XELOGW(
"VulkanPipelineCache: SPIR-V validation warning for shader {:016X} "
"modification {:016X}: {}",
shader.ucode_data_hash(), translation.modification(),
validation_error);
// Dump the shader for debugging if dump path is set
if (!cvars::dump_shaders.empty()) {
translation.Dump(cvars::dump_shaders, "vulkan_warning");
}
// Continue anyway - the driver might accept it
}
}
#endif // NDEBUG
if (translation.GetOrCreateShaderModule() == VK_NULL_HANDLE) {
return false;
}
@@ -1044,8 +992,7 @@ void VulkanPipelineCache::TranslateShadersForStorage(
// Each thread needs its own translator.
SpirvShaderTranslator translator(
SpirvShaderTranslator::Features(vulkan_device), msaa_2x_attachments,
msaa_2x_no_attachments, edram_fsi_used, draw_res_x, draw_res_y, nullptr,
false); // Don't optimize during parallel translation
msaa_2x_no_attachments, edram_fsi_used, draw_res_x, draw_res_y);
while (true) {
size_t index = translation_index.fetch_add(1);
@@ -3173,58 +3120,6 @@ void VulkanPipelineCache::ProcessDeferredDestructions() {
}
}
void VulkanPipelineCache::OptimizeTranslationIfNeeded(
VulkanShader::VulkanTranslation& translation) {
// Only optimize if enabled and spirv-tools is available.
if (!cvars::vulkan_spirv_optimization || !spirv_tools_context_) {
return;
}
// Only optimize if the shader module hasn't been created yet.
// Once created, we can't replace it without the complexity of the old
// background optimization system.
if (translation.shader_module() != VK_NULL_HANDLE) {
return;
}
if (!translation.is_valid()) {
return;
}
const std::vector<uint8_t>& unoptimized_binary =
translation.translated_binary();
if (unoptimized_binary.empty()) {
return;
}
// Reinterpret the byte vector as uint32_t for SPIRV-Tools
const uint32_t* spirv_words =
reinterpret_cast<const uint32_t*>(unoptimized_binary.data());
size_t word_count = unoptimized_binary.size() / sizeof(uint32_t);
std::vector<uint32_t> optimized_spirv;
spv_result_t result = spirv_tools_context_->Optimize(spirv_words, word_count,
optimized_spirv, true);
if (result == SPV_SUCCESS && !optimized_spirv.empty()) {
// Convert back to byte vector and replace the translated binary
std::vector<uint8_t> optimized_binary;
optimized_binary.resize(optimized_spirv.size() * sizeof(uint32_t));
std::memcpy(optimized_binary.data(), optimized_spirv.data(),
optimized_binary.size());
translation.SetOptimizedBinary(std::move(optimized_binary));
size_t original_size = word_count;
size_t optimized_size = optimized_spirv.size();
XELOGI("SPIRV optimization: {} -> {} words ({:.1f}% reduction)",
original_size, optimized_size,
100.0f * (1.0f - float(optimized_size) / float(original_size)));
} else {
XELOGW("SPIRV optimization failed with error code: {}",
static_cast<int>(result));
}
}
void VulkanPipelineCache::InitializeShaderStorage(
const std::filesystem::path& cache_root, uint32_t title_id, bool blocking,
std::function<void()> completion_callback) {
@@ -41,11 +41,6 @@
#include "xenia/ui/vulkan/vulkan_api.h"
namespace xe {
namespace ui {
namespace vulkan {
class SpirvToolsContext;
} // namespace vulkan
} // namespace ui
namespace gpu {
namespace vulkan {
@@ -399,11 +394,6 @@ class VulkanPipelineCache {
return EnsurePipelineCreated(creation_arguments, placeholder_pixel_shader_);
}
// Optimizes a shader's SPIR-V binary if optimization is enabled and the
// shader module hasn't been created yet. Called from creation threads.
void OptimizeTranslationIfNeeded(
VulkanShader::VulkanTranslation& translation);
VulkanCommandProcessor& command_processor_;
const RegisterFile& register_file_;
VulkanRenderTargetCache& render_target_cache_;
@@ -414,8 +404,6 @@ class VulkanPipelineCache {
// Temporary storage for AnalyzeUcode calls on the processor thread.
StringBuffer ucode_disasm_buffer_;
// SPIRV-Tools context for optimizing shaders.
std::unique_ptr<ui::vulkan::SpirvToolsContext> spirv_tools_context_;
// Reusable shader translator on the command processor thread.
std::unique_ptr<SpirvShaderTranslator> shader_translator_;
-10
View File
@@ -7,16 +7,6 @@ target_include_directories(xenia-ui-vulkan PRIVATE
${PROJECT_SOURCE_DIR}/third_party/glslang
)
target_link_libraries(xenia-ui-vulkan PUBLIC xenia-base xenia-ui)
# SPIRV-Tools: Vulkan SDK on Windows (headers + libs under $VULKAN_SDK),
# system package on Linux (libspirv-tools-*).
if(WIN32 AND DEFINED ENV{VULKAN_SDK})
target_include_directories(xenia-ui-vulkan PRIVATE "$ENV{VULKAN_SDK}/Include")
target_link_directories(xenia-ui-vulkan PUBLIC "$ENV{VULKAN_SDK}/Lib")
target_link_libraries(xenia-ui-vulkan PUBLIC SPIRV-Tools-opt SPIRV-Tools)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(xenia-ui-vulkan PUBLIC SPIRV-Tools-opt SPIRV-Tools)
endif()
xe_target_defaults(xenia-ui-vulkan)
if(XENIA_BUILD_MISC)
-126
View File
@@ -1,126 +0,0 @@
/**
******************************************************************************
* 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/ui/vulkan/spirv_tools_context.h"
#include <cstdlib>
#include <spirv-tools/optimizer.hpp>
#include "xenia/base/logging.h"
#include "xenia/base/platform.h"
namespace xe {
namespace ui {
namespace vulkan {
bool SpirvToolsContext::Initialize(unsigned int spirv_version) {
// Determine target environment based on SPIR-V version
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;
}
// Create SPIR-V context
context_ = spvContextCreate(target_env_);
if (!context_) {
XELOGE("SPIRV-Tools: Failed to create context for target environment");
return false;
}
XELOGI("SPIRV-Tools: Initialized successfully with static linking");
return true;
}
void SpirvToolsContext::Shutdown() {
if (context_) {
spvContextDestroy(context_);
context_ = nullptr;
}
}
spv_result_t SpirvToolsContext::Validate(const uint32_t* words,
size_t num_words,
std::string* error) const {
if (error) {
error->clear();
}
if (!context_) {
return SPV_UNSUPPORTED;
}
// Create validator options with scalar block layout to match modern Vulkan
// driver behavior. This is the most permissive layout option and matches
// what VK_EXT_scalar_block_layout provides.
spv_validator_options options = spvValidatorOptionsCreate();
spvValidatorOptionsSetScalarBlockLayout(options, true);
// Create binary struct for the validation API
spv_const_binary_t binary = {words, num_words};
spv_diagnostic diagnostic = nullptr;
spv_result_t result =
spvValidateWithOptions(context_, options, &binary, &diagnostic);
spvValidatorOptionsDestroy(options);
if (diagnostic) {
if (error && diagnostic->error) {
*error = diagnostic->error;
}
spvDiagnosticDestroy(diagnostic);
}
return result;
}
spv_result_t SpirvToolsContext::Optimize(const uint32_t* words,
size_t num_words,
std::vector<uint32_t>& optimized_words,
bool performance_passes) {
optimized_words.clear();
if (!context_) {
return SPV_UNSUPPORTED;
}
// Use the C++ optimizer API for better integration
spvtools::Optimizer optimizer(target_env_);
// Set up message consumer for error reporting
optimizer.SetMessageConsumer([](spv_message_level_t level, const char* source,
const spv_position_t& position,
const char* message) {
if (level == SPV_MSG_ERROR || level == SPV_MSG_FATAL ||
level == SPV_MSG_INTERNAL_ERROR) {
XELOGE("SPIRV-Tools optimizer: {} {}", source ? source : "",
message ? message : "");
}
});
// Register optimization passes
if (performance_passes) {
optimizer.RegisterPerformancePasses();
} else {
optimizer.RegisterSizePasses();
}
// Run optimizer
if (!optimizer.Run(words, num_words, &optimized_words)) {
return SPV_ERROR_INVALID_BINARY;
}
return SPV_SUCCESS;
}
} // namespace vulkan
} // namespace ui
} // namespace xe
-52
View File
@@ -1,52 +0,0 @@
/**
******************************************************************************
* 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_UI_VULKAN_SPIRV_TOOLS_CONTEXT_H_
#define XENIA_UI_VULKAN_SPIRV_TOOLS_CONTEXT_H_
#include <cstdint>
#include <string>
#include <vector>
#include <spirv-tools/libspirv.h>
#include <spirv-tools/optimizer.hpp>
#include "xenia/base/platform.h"
namespace xe {
namespace ui {
namespace vulkan {
class SpirvToolsContext {
public:
SpirvToolsContext() {}
SpirvToolsContext(const SpirvToolsContext& context) = delete;
SpirvToolsContext& operator=(const SpirvToolsContext& context) = delete;
~SpirvToolsContext() { Shutdown(); }
bool Initialize(unsigned int spirv_version);
void Shutdown();
spv_result_t Validate(const uint32_t* words, size_t num_words,
std::string* error) const;
// Optimizes SPIR-V code. Returns SPV_SUCCESS on successful optimization.
// The optimized binary is returned in optimized_words.
spv_result_t Optimize(const uint32_t* words, size_t num_words,
std::vector<uint32_t>& optimized_words,
bool performance_passes = true);
private:
spv_context context_ = nullptr;
spv_target_env target_env_ = SPV_ENV_UNIVERSAL_1_0;
};
} // namespace vulkan
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VULKAN_SPIRV_TOOLS_CONTEXT_H_