From f0a0f12767005518b0fb5c02e1bf08da0dac24e7 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 15 Aug 2026 01:08:37 -0400 Subject: [PATCH] Remove requirement on dxbc --- cpmfile.json | 6 -- externals/CMakeLists.txt | 4 -- src/video_core/CMakeLists.txt | 1 - src/video_core/frame_gen/lossless_dll.cpp | 62 ++++++----------- src/video_core/frame_gen/lossless_dll.h | 8 +-- src/video_core/frame_gen/lsfg_translate.cpp | 66 +++++-------------- src/video_core/frame_gen/lsfg_translate.h | 2 - .../renderer_vulkan/present/lsfg_shaders.cpp | 6 +- 8 files changed, 41 insertions(+), 114 deletions(-) diff --git a/cpmfile.json b/cpmfile.json index 7035cfc040..cac6c357b0 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -65,12 +65,6 @@ "repo": "eden-emulator/discord-rpc", "version": "0d8b2d6a37" }, - "dxbc": { - "bundled": true, - "hash": "196d26c07747d7aa2ced6fb1a5ae6f665e9b917de223a540038690b037c70a1eeca51c21d42aa5bec9fff7df0a6656a75ee8b4e2cb4008469f18a6812280f831", - "repo": "PancakeTAS/dxbc", - "version": "78ab59a8aaeb43cd1b0a5e91ba86722433a10b78" - }, "enet": { "find_args": "MODULE", "hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9", diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 4b0763140e..f190f68b9d 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -92,10 +92,6 @@ AddDependentPackages(vulkan-headers vulkan-utility-libraries) # frozen AddJsonPackage(frozen) -# DXVK's DXBC compiler, used to translate the frame generation shaders -# out of a user-supplied Lossless.dll into SPIR-V -AddJsonPackage(dxbc) - # DiscordRPC if (USE_DISCORD_PRESENCE) if (ARCHITECTURE_arm64) diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 10afffb743..db397aa272 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -371,7 +371,6 @@ add_dependencies(video_core host_shaders) target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) target_link_libraries(video_core PRIVATE sirit::sirit) -target_link_libraries(video_core PRIVATE dxbc) # Header-only stuff needed by all dependent targets target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator) diff --git a/src/video_core/frame_gen/lossless_dll.cpp b/src/video_core/frame_gen/lossless_dll.cpp index 03228b8669..5d2d08ffb3 100644 --- a/src/video_core/frame_gen/lossless_dll.cpp +++ b/src/video_core/frame_gen/lossless_dll.cpp @@ -278,14 +278,8 @@ template } [[nodiscard]] u32 VariantOffset(ShaderVariant variant) { - switch (variant) { - case ShaderVariant::NativeFp16: - return PerformanceShader::NATIVE_FP16_OFFSET; - case ShaderVariant::NativeFp32: - return PerformanceShader::NATIVE_FP32_OFFSET; - default: - return 0; - } + return variant == ShaderVariant::NativeFp16 ? PerformanceShader::NATIVE_FP16_OFFSET + : PerformanceShader::NATIVE_FP32_OFFSET; } template @@ -297,14 +291,18 @@ template }); } -[[nodiscard]] ShaderVariant SelectVariant(const ResourceSpans& resources, bool prefer_fp16) { +[[nodiscard]] std::optional SelectVariant(const ResourceSpans& resources, + bool allow_fp16, bool prefer_fp16) { if (prefer_fp16 && HasNativeVariant(resources, ShaderVariant::NativeFp16)) { return ShaderVariant::NativeFp16; } if (HasNativeVariant(resources, ShaderVariant::NativeFp32)) { return ShaderVariant::NativeFp32; } - return ShaderVariant::TranslatedDxbc; + if (allow_fp16 && HasNativeVariant(resources, ShaderVariant::NativeFp16)) { + return ShaderVariant::NativeFp16; + } + return std::nullopt; } [[nodiscard]] LosslessStatus TranslateAll(const ResourceSpans& resources, @@ -317,20 +315,11 @@ template if (hit == resources.end()) { return LosslessStatus::MissingShaders; } - if (variant != ShaderVariant::TranslatedDxbc) { - std::vector adopted = AdoptSpirvModule(hit->second); - if (adopted.empty()) { - return LosslessStatus::TranslationFailed; - } - out_modules.emplace(id, std::move(adopted)); - continue; - } - - std::vector words = TranslateComputeShader(hit->second); - if (words.empty()) { + std::vector adopted = AdoptSpirvModule(hit->second); + if (adopted.empty()) { return LosslessStatus::TranslationFailed; } - out_modules.emplace(id, std::move(words)); + out_modules.emplace(id, std::move(adopted)); } return LosslessStatus::Ok; } @@ -494,21 +483,7 @@ LosslessStatus GetInstalledLosslessStatus() { return ValidateLosslessDll(GetLosslessDllPath()); } -ShaderVariant GetAvailableVariant(bool prefer_fp16) { - std::vector image; - if (ReadImageFile(GetLosslessDllPath(), image) != LosslessStatus::Ok) { - return ShaderVariant::TranslatedDxbc; - } - - ResourceSpans spans; - if (ParseShaderSpans(image, spans) != LosslessStatus::Ok) { - return ShaderVariant::TranslatedDxbc; - } - - return SelectVariant(spans, prefer_fp16); -} - -LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool prefer_fp16) { +LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool allow_fp16, bool prefer_fp16) { std::vector image; const LosslessStatus read_status = ReadImageFile(GetLosslessDllPath(), image); if (read_status != LosslessStatus::Ok) { @@ -526,14 +501,17 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool prefer_fp16) { return parse_status; } - const ShaderVariant variant = SelectVariant(spans, prefer_fp16); + const std::optional variant = SelectVariant(spans, allow_fp16, prefer_fp16); + if (!variant) { + return LosslessStatus::MissingShaders; + } - if (ReadShaderCache(cache_path, source_size, source_hash, static_cast(variant), + if (ReadShaderCache(cache_path, source_size, source_hash, static_cast(*variant), out_modules)) { return LosslessStatus::Ok; } - const LosslessStatus translate_status = TranslateAll(spans, out_modules, variant); + const LosslessStatus translate_status = TranslateAll(spans, out_modules, *variant); if (translate_status != LosslessStatus::Ok) { return translate_status; } @@ -544,7 +522,7 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool prefer_fp16) { .source_size = source_size, .source_hash = source_hash, .module_count = static_cast(out_modules.size()), - .variant = static_cast(variant), + .variant = static_cast(*variant), }; if (!WriteShaderCache(cache_path, header, out_modules)) { void(Common::FS::RemoveFile(cache_path)); @@ -556,7 +534,7 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool prefer_fp16) { LosslessStatus BuildShaderCache() { ShaderModules modules; - return LoadShaderModules(modules); + return LoadShaderModules(modules, true); } bool RemoveInstalledLosslessDll() { diff --git a/src/video_core/frame_gen/lossless_dll.h b/src/video_core/frame_gen/lossless_dll.h index 0246935f4d..1d583d008f 100644 --- a/src/video_core/frame_gen/lossless_dll.h +++ b/src/video_core/frame_gen/lossless_dll.h @@ -29,9 +29,8 @@ using ShaderResources = std::map>; using ShaderModules = std::map>; enum class ShaderVariant : u32 { - TranslatedDxbc, - NativeFp32, - NativeFp16, + NativeFp32 = 1, + NativeFp16 = 2, }; namespace PerformanceShader { @@ -59,9 +58,8 @@ constexpr u32 NATIVE_FP32_OFFSET = 98; [[nodiscard]] LosslessStatus BuildShaderCache(); -[[nodiscard]] ShaderVariant GetAvailableVariant(bool prefer_fp16); - [[nodiscard]] LosslessStatus LoadShaderModules(ShaderModules& out_modules, + bool allow_fp16 = false, bool prefer_fp16 = false); bool RemoveInstalledLosslessDll(); diff --git a/src/video_core/frame_gen/lsfg_translate.cpp b/src/video_core/frame_gen/lsfg_translate.cpp index 758711ed5d..4063465d93 100644 --- a/src/video_core/frame_gen/lsfg_translate.cpp +++ b/src/video_core/frame_gen/lsfg_translate.cpp @@ -6,37 +6,23 @@ #include #include -#include -#include -#include -#include - #include "video_core/frame_gen/lsfg_translate.h" namespace VideoCore::FrameGen { namespace { +constexpr u32 SPIRV_MAGIC = 0x07230203; +constexpr u32 SPIRV_WORD_COUNT_SHIFT = 16; +constexpr u32 SPIRV_OPCODE_MASK = 0xffff; +constexpr u32 SPIRV_OP_FUNCTION = 54; +constexpr u32 SPIRV_OP_DECORATE = 71; +constexpr u32 SPIRV_DECORATION_BINDING = 33; +constexpr u32 SPIRV_DECORATION_DESCRIPTOR_SET = 34; + constexpr u32 DECORATION_LITERAL_WORD = 3; constexpr size_t SPIRV_HEADER_WORDS = 5; -void RenumberBindings(dxvk::SpirvCodeBuffer& code) { - std::vector literal_offsets; - for (const auto instruction : code) { - if (instruction.opCode() == spv::OpFunction) { - break; - } - if (instruction.opCode() == spv::OpDecorate && - instruction.arg(2) == spv::DecorationBinding) { - literal_offsets.push_back(instruction.offset() + DECORATION_LITERAL_WORD); - } - } - - for (size_t i = 0; i < literal_offsets.size(); ++i) { - code.data()[literal_offsets[i]] = static_cast(i); - } -} - void RenumberBindingsInOrder(std::vector& words) { struct Slot { u32 set; @@ -49,18 +35,18 @@ void RenumberBindingsInOrder(std::vector& words) { size_t offset = SPIRV_HEADER_WORDS; while (offset + 1 <= words.size()) { - const u32 length = words[offset] >> spv::WordCountShift; - const u32 opcode = words[offset] & spv::OpCodeMask; + const u32 length = words[offset] >> SPIRV_WORD_COUNT_SHIFT; + const u32 opcode = words[offset] & SPIRV_OPCODE_MASK; if (length == 0 || offset + length > words.size()) { return; } - if (opcode == spv::OpFunction) { + if (opcode == SPIRV_OP_FUNCTION) { break; } - if (opcode == spv::OpDecorate && length >= 4) { - if (words[offset + 2] == spv::DecorationDescriptorSet) { + if (opcode == SPIRV_OP_DECORATE && length >= 4) { + if (words[offset + 2] == SPIRV_DECORATION_DESCRIPTOR_SET) { sets[words[offset + 1]] = words[offset + 3]; - } else if (words[offset + 2] == spv::DecorationBinding) { + } else if (words[offset + 2] == SPIRV_DECORATION_BINDING) { slots.push_back(Slot{0, words[offset + 3], offset + DECORATION_LITERAL_WORD}); } } @@ -89,7 +75,7 @@ bool IsSpirvModule(std::span blob) { } u32 magic{}; std::memcpy(&magic, blob.data(), sizeof(magic)); - return magic == spv::MagicNumber; + return magic == SPIRV_MAGIC; } std::vector AdoptSpirvModule(std::span blob) { @@ -104,26 +90,4 @@ std::vector AdoptSpirvModule(std::span blob) { return words; } -std::vector TranslateComputeShader(std::span dxbc) { - if (dxbc.empty()) { - return {}; - } - - try { - dxvk::DxbcReader reader{reinterpret_cast(dxbc.data()), dxbc.size()}; - dxvk::DxbcModule module{reader}; - - const dxvk::DxbcModuleInfo module_info{}; - dxvk::SpirvCodeBuffer code = module.compile(module_info, "CS"); - if (code.dwords() == 0) { - return {}; - } - - RenumberBindings(code); - return std::vector{code.data(), code.data() + code.dwords()}; - } catch (...) { - return {}; - } -} - } // namespace VideoCore::FrameGen diff --git a/src/video_core/frame_gen/lsfg_translate.h b/src/video_core/frame_gen/lsfg_translate.h index 291db1c4f5..5d21128c3e 100644 --- a/src/video_core/frame_gen/lsfg_translate.h +++ b/src/video_core/frame_gen/lsfg_translate.h @@ -14,6 +14,4 @@ namespace VideoCore::FrameGen { [[nodiscard]] std::vector AdoptSpirvModule(std::span blob); -[[nodiscard]] std::vector TranslateComputeShader(std::span dxbc); - } // namespace VideoCore::FrameGen diff --git a/src/video_core/renderer_vulkan/present/lsfg_shaders.cpp b/src/video_core/renderer_vulkan/present/lsfg_shaders.cpp index 0955a9aa54..aafe0d6419 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_shaders.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_shaders.cpp @@ -14,11 +14,11 @@ LsfgShaders::LsfgShaders(const Device& device) { return; } - const bool prefer_fp16 = - Settings::values.frame_gen_fp16.GetValue() && device.IsFloat16Supported(); + const bool allow_fp16 = device.IsFloat16Supported(); + const bool prefer_fp16 = allow_fp16 && Settings::values.frame_gen_fp16.GetValue(); VideoCore::FrameGen::ShaderModules code; - if (VideoCore::FrameGen::LoadShaderModules(code, prefer_fp16) != + if (VideoCore::FrameGen::LoadShaderModules(code, allow_fp16, prefer_fp16) != VideoCore::FrameGen::LosslessStatus::Ok) { return; }