Remove requirement on dxbc

This commit is contained in:
CamilleLaVey
2026-08-15 01:08:37 -04:00
parent aae469118e
commit f0a0f12767
8 changed files with 41 additions and 114 deletions
-6
View File
@@ -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",
-4
View File
@@ -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)
-1
View File
@@ -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)
+20 -42
View File
@@ -278,14 +278,8 @@ template <typename Map>
}
[[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 <typename Map>
@@ -297,14 +291,18 @@ template <typename Map>
});
}
[[nodiscard]] ShaderVariant SelectVariant(const ResourceSpans& resources, bool prefer_fp16) {
[[nodiscard]] std::optional<ShaderVariant> 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 <typename Map>
if (hit == resources.end()) {
return LosslessStatus::MissingShaders;
}
if (variant != ShaderVariant::TranslatedDxbc) {
std::vector<u32> adopted = AdoptSpirvModule(hit->second);
if (adopted.empty()) {
return LosslessStatus::TranslationFailed;
}
out_modules.emplace(id, std::move(adopted));
continue;
}
std::vector<u32> words = TranslateComputeShader(hit->second);
if (words.empty()) {
std::vector<u32> 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<u8> 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<u8> 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<ShaderVariant> variant = SelectVariant(spans, allow_fp16, prefer_fp16);
if (!variant) {
return LosslessStatus::MissingShaders;
}
if (ReadShaderCache(cache_path, source_size, source_hash, static_cast<u32>(variant),
if (ReadShaderCache(cache_path, source_size, source_hash, static_cast<u32>(*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<u32>(out_modules.size()),
.variant = static_cast<u32>(variant),
.variant = static_cast<u32>(*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() {
+3 -5
View File
@@ -29,9 +29,8 @@ using ShaderResources = std::map<u32, std::vector<u8>>;
using ShaderModules = std::map<u32, std::vector<u32>>;
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();
+15 -51
View File
@@ -6,37 +6,23 @@
#include <map>
#include <tuple>
#include <dxbc_modinfo.h>
#include <dxbc_module.h>
#include <dxbc_reader.h>
#include <thirdparty/spirv.hpp>
#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<u32> 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<u32>(i);
}
}
void RenumberBindingsInOrder(std::vector<u32>& words) {
struct Slot {
u32 set;
@@ -49,18 +35,18 @@ void RenumberBindingsInOrder(std::vector<u32>& 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<const u8> blob) {
}
u32 magic{};
std::memcpy(&magic, blob.data(), sizeof(magic));
return magic == spv::MagicNumber;
return magic == SPIRV_MAGIC;
}
std::vector<u32> AdoptSpirvModule(std::span<const u8> blob) {
@@ -104,26 +90,4 @@ std::vector<u32> AdoptSpirvModule(std::span<const u8> blob) {
return words;
}
std::vector<u32> TranslateComputeShader(std::span<const u8> dxbc) {
if (dxbc.empty()) {
return {};
}
try {
dxvk::DxbcReader reader{reinterpret_cast<const char*>(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<u32>{code.data(), code.data() + code.dwords()};
} catch (...) {
return {};
}
}
} // namespace VideoCore::FrameGen
@@ -14,6 +14,4 @@ namespace VideoCore::FrameGen {
[[nodiscard]] std::vector<u32> AdoptSpirvModule(std::span<const u8> blob);
[[nodiscard]] std::vector<u32> TranslateComputeShader(std::span<const u8> dxbc);
} // namespace VideoCore::FrameGen
@@ -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;
}