Browse Source

[VK] Rework SPIRV Shader Optimization (#238)

The actual SPIRV Shader Optimization option doesn't seem to do anything as long as it isn't vinculed, so let's rework it to make it work

Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com>
Co-authored-by: echosys <echosys@noreply.localhost>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/238
pull/21/head
Gamer64 7 months ago
parent
commit
a002730d68
No known key found for this signature in database GPG Key ID: BA8734FD0EE46976
  1. 3
      .gitmodules
  2. 7
      CMakeLists.txt
  3. 6
      externals/CMakeLists.txt
  4. 1
      externals/SPIRV-Tools
  5. 2
      externals/Vulkan-Headers
  6. 2
      externals/Vulkan-Utility-Libraries
  7. 2
      externals/VulkanMemoryAllocator
  8. 3
      externals/dynarmic/src/dynarmic/backend/x64/abi.cpp
  9. 2
      externals/sirit/externals/SPIRV-Headers
  10. 3
      src/core/arm/nce/arm_nce.cpp
  11. 3
      src/core/hle/service/sockets/sfdnsres.cpp
  12. 8
      src/shader_recompiler/CMakeLists.txt
  13. 27
      src/shader_recompiler/backend/spirv/emit_spirv.cpp
  14. 10
      src/shader_recompiler/backend/spirv/emit_spirv.h
  15. 3
      src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp
  16. 3
      src/shader_recompiler/ir_opt/texture_pass.cpp
  17. 3
      src/video_core/buffer_cache/buffer_cache.h
  18. 3
      src/video_core/buffer_cache/buffer_cache_base.h
  19. 3
      src/video_core/cdma_pusher.cpp
  20. 3
      src/video_core/delayed_destruction_ring.h
  21. 3
      src/video_core/host1x/ffmpeg/ffmpeg.h
  22. 13
      src/video_core/renderer_opengl/gl_shader_cache.cpp
  23. 3
      src/video_core/renderer_vulkan/present/layer.cpp
  24. 12
      src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
  25. 3
      src/video_core/texture_cache/texture_cache.h
  26. 3
      src/video_core/texture_cache/texture_cache_base.h
  27. 3
      src/video_core/vulkan_common/vulkan_memory_allocator.cpp
  28. 1
      src/yuzu/configuration/shared_translation.cpp

3
.gitmodules

@ -64,3 +64,6 @@
[submodule "externals/sirit/externals/SPIRV-Headers"]
path = externals/sirit/externals/SPIRV-Headers
url = https://github.com/KhronosGroup/SPIRV-Headers.git
[submodule "externals/SPIRV-Tools"]
path = externals/SPIRV-Tools
url = https://github.com/KhronosGroup/SPIRV-Tools.git

7
CMakeLists.txt

@ -49,6 +49,8 @@ option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
option(YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ON)
option(YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS "Use SPIRV-Tools from externals" ON)
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
@ -329,6 +331,11 @@ if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
find_package(VulkanUtilityLibraries REQUIRED)
endif()
if (NOT YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SPIRV-Tools REQUIRED SPIRV-Tools)
endif()
if (ENABLE_LIBUSB)
find_package(libusb 1.0.24 MODULE)
endif()

6
externals/CMakeLists.txt

@ -160,6 +160,12 @@ if (YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
add_subdirectory(Vulkan-Utility-Libraries)
endif()
# SPIRV-Tools
if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS)
set(SPIRV_SKIP_EXECUTABLES ON)
add_subdirectory(SPIRV-Tools)
endif()
# Boost headers
add_subdirectory(boost-headers)

1
externals/SPIRV-Tools

@ -0,0 +1 @@
Subproject commit 40eb301f320e1d85ce3bc12798022149eae3eee3

2
externals/Vulkan-Headers

@ -1 +1 @@
Subproject commit 409c16be502e39fe70dd6fe2d9ad4842ef2c9a53
Subproject commit 16cedde3564629c43808401ad1eb3ca6ef24709a

2
externals/Vulkan-Utility-Libraries

@ -1 +1 @@
Subproject commit 4e246c56ec5afb5ad66b9b04374d39ac04675c8e
Subproject commit f216bb107bfc6d99a9605572963613e828b10880

2
externals/VulkanMemoryAllocator

@ -1 +1 @@
Subproject commit 539c0a8d8e3733c9f25ea9a184c85c77504f1653
Subproject commit 6ec8481c8a13db586d7b3ba58f4eb9bbf017edf0

3
externals/dynarmic/src/dynarmic/backend/x64/abi.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2020 MerryMage
* SPDX-License-Identifier: 0BSD

2
externals/sirit/externals/SPIRV-Headers

@ -1 +1 @@
Subproject commit 3f17b2af6784bfa2c5aa5dbb8e0e74a607dd8b3b
Subproject commit 04b76709bf40a7ce8df3382060ef3620f19de566

3
src/core/arm/nce/arm_nce.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

3
src/core/hle/service/sockets/sfdnsres.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

8
src/shader_recompiler/CMakeLists.txt

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

27
src/shader_recompiler/backend/spirv/emit_spirv.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -6,6 +9,7 @@
#include <type_traits>
#include <utility>
#include <vector>
#include <spirv-tools/optimizer.hpp>
#include "common/settings.h"
#include "shader_recompiler/backend/spirv/emit_spirv.h"
@ -481,7 +485,7 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
} // Anonymous namespace
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};
const Id main{DefineMain(ctx, program)};
DefineEntryPoint(program, ctx, main);
@ -493,7 +497,28 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
SetupCapabilities(profile, program.info, ctx);
SetupTransformFeedbackCapabilities(ctx, main);
PatchPhiNodes(program, ctx);
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) {

10
src/shader_recompiler/backend/spirv/emit_spirv.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -31,11 +34,12 @@ constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, do
constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area);
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
IR::Program& program, Bindings& bindings);
IR::Program& program, Bindings& bindings, 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;
return EmitSPIRV(profile, {}, program, binding);
return EmitSPIRV(profile, {}, program, binding, optimize);
}
} // namespace Shader::Backend::SPIRV

3
src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

3
src/shader_recompiler/ir_opt/texture_pass.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

3
src/video_core/buffer_cache/buffer_cache.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

3
src/video_core/buffer_cache/buffer_cache_base.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

3
src/video_core/cdma_pusher.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Ryujinx Team and Contributors
// SPDX-License-Identifier: MIT

3
src/video_core/delayed_destruction_ring.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

3
src/video_core/host1x/ffmpeg/ffmpeg.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

13
src/video_core/renderer_opengl/gl_shader_cache.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -178,6 +181,7 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
state_tracker{state_tracker_}, shader_notify{shader_notify_},
use_asynchronous_shaders{device.UseAsynchronousShaders()},
strict_context_required{device.StrictContextRequired()},
optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never},
profile{
.supported_spirv = 0x00010000,
@ -344,6 +348,10 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
if (!use_asynchronous_shaders) {
workers.reset();
}
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
this->optimize_spirv_output = false;
}
}
GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
@ -537,7 +545,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
break;
case Settings::ShaderBackend::SpirV:
ConvertLegacyToGeneric(program, runtime_info);
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
sources_spirv[stage_index] =
EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output);
break;
}
previous_program = &program;
@ -596,7 +605,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
code = EmitGLASM(profile, info, program);
break;
case Settings::ShaderBackend::SpirV:
code_spirv = EmitSPIRV(profile, program);
code_spirv = EmitSPIRV(profile, program, this->optimize_spirv_output);
break;
}

3
src/video_core/renderer_vulkan/present/layer.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

12
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -311,6 +314,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
texture_cache{texture_cache_}, shader_notify{shader_notify_},
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},
optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never},
workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(),
"VkPipelineBuilder"),
serialization_thread(1, "VkPipelineSerialization") {
@ -579,6 +583,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
if (state.statistics) {
state.statistics->Report();
}
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
this->optimize_spirv_output = false;
}
}
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
@ -688,7 +696,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
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, this->optimize_spirv_output)};
device.SaveShader(code);
modules[stage_index] = BuildShader(device, code);
if (device.HasDebuggingToolAttached()) {
@ -782,7 +790,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
}
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, this->optimize_spirv_output)};
device.SaveShader(code);
vk::ShaderModule spv_module{BuildShader(device, code)};
if (device.HasDebuggingToolAttached()) {

3
src/video_core/texture_cache/texture_cache.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

3
src/video_core/texture_cache/texture_cache_base.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

3
src/video_core/vulkan_common/vulkan_memory_allocator.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

1
src/yuzu/configuration/shared_translation.cpp

@ -463,6 +463,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent)
PAIR(AppletMode, HLE, tr("Custom frontend")),
PAIR(AppletMode, LLE, tr("Real applet")),
}});
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
{
PAIR(SpirvOptimizeMode, Never, tr("Never")),

Loading…
Cancel
Save