experimental optimization for spirv

This commit is contained in:
Crimson-Hawk 2024-04-25 21:14:30 +08:00
parent e4ae2030ec
commit 4b54749954
No known key found for this signature in database
GPG key ID: 0804DD39BB9BF5AC
10 changed files with 64 additions and 10 deletions

3
.gitmodules vendored
View file

@ -67,3 +67,6 @@
[submodule "Vulkan-Utility-Libraries"] [submodule "Vulkan-Utility-Libraries"]
path = externals/Vulkan-Utility-Libraries path = externals/Vulkan-Utility-Libraries
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
[submodule "externals/SPIRV-Tools"]
path = externals/SPIRV-Tools
url = https://github.com/KhronosGroup/SPIRV-Tools.git

View file

@ -40,6 +40,8 @@ option(SUYU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")
option(SUYU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) option(SUYU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
option(SUYU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS "Use SPIRV-Tools from externals" ON)
option(SUYU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ON) option(SUYU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ON)
option(SUYU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) option(SUYU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
@ -320,6 +322,11 @@ if (NOT SUYU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
find_package(VulkanUtilityLibraries REQUIRED) find_package(VulkanUtilityLibraries REQUIRED)
endif() endif()
if (NOT SUYU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SPIRV-Tools REQUIRED SPIRV-Tools)
endif()
if (ENABLE_LIBUSB) if (ENABLE_LIBUSB)
find_package(libusb 1.0.24 MODULE) find_package(libusb 1.0.24 MODULE)
endif() endif()

View file

@ -160,6 +160,11 @@ if (SUYU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
add_subdirectory(Vulkan-Utility-Libraries) add_subdirectory(Vulkan-Utility-Libraries)
endif() endif()
# SPIRV-Tools
if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS)
add_subdirectory(SPIRV-Tools)
endif()
# TZDB (Time Zone Database) # TZDB (Time Zone Database)
add_subdirectory(nx_tzdb) add_subdirectory(nx_tzdb)

View file

@ -277,6 +277,8 @@ struct Values {
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache", SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
Category::Renderer}; Category::Renderer};
SwitchableSetting<bool> optimize_spirv_output{linkage, false, "optimize_spirv_output",
Category::Renderer};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{ SwitchableSetting<bool> use_asynchronous_gpu_emulation{
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage, SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,

View file

@ -242,7 +242,13 @@ add_library(shader_recompiler STATIC
varying_state.h varying_state.h
) )
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit) if (SUYU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS)
set(SPIRV_TOOLS_LIBRARY SPIRV-Tools-opt)
else()
set(SPIRV_TOOLS_LIBRARY SPIRV-Tools SPIRV-Tools-opt)
endif()
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit ${SPIRV_TOOLS_LIBRARY})
if (MSVC) if (MSVC)
target_compile_options(shader_recompiler PRIVATE target_compile_options(shader_recompiler PRIVATE

View file

@ -6,6 +6,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <spirv-tools/optimizer.hpp>
#include "common/settings.h" #include "common/settings.h"
#include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv.h"
@ -481,7 +482,7 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
} // Anonymous namespace } // Anonymous namespace
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
IR::Program& program, Bindings& bindings) { IR::Program& program, Bindings& bindings, bool optimize) {
EmitContext ctx{profile, runtime_info, program, bindings}; EmitContext ctx{profile, runtime_info, program, bindings};
const Id main{DefineMain(ctx, program)}; const Id main{DefineMain(ctx, program)};
DefineEntryPoint(program, ctx, main); DefineEntryPoint(program, ctx, main);
@ -493,7 +494,28 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
SetupCapabilities(profile, program.info, ctx); SetupCapabilities(profile, program.info, ctx);
SetupTransformFeedbackCapabilities(ctx, main); SetupTransformFeedbackCapabilities(ctx, main);
PatchPhiNodes(program, ctx); PatchPhiNodes(program, ctx);
return ctx.Assemble();
if (!optimize) {
return ctx.Assemble();
} else {
std::vector<u32> spirv = ctx.Assemble();
spvtools::Optimizer spv_opt(SPV_ENV_VULKAN_1_3);
spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&,
const char* m) { LOG_ERROR(HW_GPU, "spirv-opt: {}", m); });
spv_opt.RegisterPerformancePasses();
spvtools::OptimizerOptions opt_options;
opt_options.set_run_validator(false);
std::vector<u32> result;
if (!spv_opt.Run(spirv.data(), spirv.size(), &result, opt_options)) {
LOG_ERROR(HW_GPU,
"Failed to optimize SPIRV shader output, continuing without optimization");
result = std::move(spirv);
}
return result;
}
} }
Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { Id EmitPhi(EmitContext& ctx, IR::Inst* inst) {

View file

@ -31,11 +31,12 @@ constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, do
constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area); constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area);
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, [[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
IR::Program& program, Bindings& bindings); IR::Program& program, Bindings& bindingss, bool optimize);
[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) { [[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program,
bool optimize) {
Bindings binding; Bindings binding;
return EmitSPIRV(profile, {}, program, binding); return EmitSPIRV(profile, {}, program, binding, optimize);
} }
} // namespace Shader::Backend::SPIRV } // namespace Shader::Backend::SPIRV

View file

@ -143,6 +143,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
tr("Allows saving shaders to storage for faster loading on following game " tr("Allows saving shaders to storage for faster loading on following game "
"boots.\nDisabling " "boots.\nDisabling "
"it is only intended for debugging.")); "it is only intended for debugging."));
INSERT(Settings, optimize_spirv_output, tr("Optimize SPIRV output shader"),
tr("Runs an additional optimization pass over generated SPIRV shaders.\n"
"Will increase time required for shader compilation.\nMay slightly improve "
"performance.\nThis feature is experimental."));
INSERT( INSERT(
Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"), Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled.")); tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled."));

View file

@ -537,7 +537,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
break; break;
case Settings::ShaderBackend::SpirV: case Settings::ShaderBackend::SpirV:
ConvertLegacyToGeneric(program, runtime_info); ConvertLegacyToGeneric(program, runtime_info);
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding); sources_spirv[stage_index] =
EmitSPIRV(profile, runtime_info, program, binding,
Settings::values.optimize_spirv_output.GetValue());
break; break;
} }
previous_program = &program; previous_program = &program;
@ -596,7 +598,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
code = EmitGLASM(profile, info, program); code = EmitGLASM(profile, info, program);
break; break;
case Settings::ShaderBackend::SpirV: case Settings::ShaderBackend::SpirV:
code_spirv = EmitSPIRV(profile, program); code_spirv = EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue());
break; break;
} }

View file

@ -673,7 +673,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)}; const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
ConvertLegacyToGeneric(program, runtime_info); ConvertLegacyToGeneric(program, runtime_info);
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)}; const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding,
Settings::values.optimize_spirv_output.GetValue())};
device.SaveShader(code); device.SaveShader(code);
modules[stage_index] = BuildShader(device, code); modules[stage_index] = BuildShader(device, code);
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
@ -767,7 +768,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
} }
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
const std::vector<u32> code{EmitSPIRV(profile, program)}; const std::vector<u32> code{
EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue())};
device.SaveShader(code); device.SaveShader(code);
vk::ShaderModule spv_module{BuildShader(device, code)}; vk::ShaderModule spv_module{BuildShader(device, code)};
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {