mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-03-27 13:41:33 +00:00
lsfg-vk-v3.1: move out shader extraction to surrounding project
This commit is contained in:
parent
53d73ce610
commit
7e1d46189e
7 changed files with 193 additions and 54 deletions
26
include/extract/extract.hpp
Normal file
26
include/extract/extract.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Extract {
|
||||
|
||||
///
|
||||
/// Extract all known shaders.
|
||||
///
|
||||
/// @throws std::runtime_error if shader extraction fails.
|
||||
///
|
||||
void extractShaders();
|
||||
|
||||
///
|
||||
/// Get a shader by name.
|
||||
///
|
||||
/// @param name The name of the shader to get.
|
||||
/// @return The shader bytecode.
|
||||
///
|
||||
/// @throws std::runtime_error if the shader is not found.
|
||||
///
|
||||
std::vector<uint8_t> getShader(const std::string& name);
|
||||
|
||||
}
|
||||
16
include/extract/trans.hpp
Normal file
16
include/extract/trans.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Extract {
|
||||
|
||||
///
|
||||
/// Translate DXBC bytecode to SPIR-V bytecode.
|
||||
///
|
||||
/// @param bytecode The DXBC bytecode to translate.
|
||||
/// @return The translated SPIR-V bytecode.
|
||||
///
|
||||
std::vector<uint8_t> translateShader(std::vector<uint8_t> bytecode);
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace LSFG::Utils::Trans {
|
||||
|
||||
///
|
||||
/// Translate shader bytecode to SPIR-V.
|
||||
///
|
||||
/// @param bytecode The shader bytecode to translate.
|
||||
/// @return A vector containing the translated SPIR-V bytecode.
|
||||
///
|
||||
[[nodiscard]] std::vector<uint8_t> translateShader(std::vector<uint8_t> bytecode);
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
#include "core/shadermodule.hpp"
|
||||
#include "core/device.hpp"
|
||||
#include "core/pipeline.hpp"
|
||||
#include "utils/trans.hpp"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
|
|
@ -27,12 +26,8 @@ Core::ShaderModule ShaderPool::getShader(
|
|||
if (bytecode.empty())
|
||||
throw std::runtime_error("Shader code is empty: " + name);
|
||||
|
||||
// create the translated shader module
|
||||
auto spirvBytecode = Utils::Trans::translateShader(bytecode);
|
||||
if (spirvBytecode.empty())
|
||||
throw std::runtime_error("Shader code translation failed: " + name);
|
||||
|
||||
Core::ShaderModule shader(device, spirvBytecode, types);
|
||||
// create the shader module
|
||||
Core::ShaderModule shader(device, bytecode, types);
|
||||
shaders[name] = shader;
|
||||
return shader;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
#include "utils/trans.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace LSFG::Utils;
|
||||
|
||||
std::vector<uint8_t> Trans::translateShader(std::vector<uint8_t> bytecode) {
|
||||
return bytecode; // on windows we expect the bytecode to be spir-v
|
||||
// // compile the shader
|
||||
// dxvk::DxbcReader reader(reinterpret_cast<const char*>(bytecode.data()), bytecode.size());
|
||||
// dxvk::DxbcModule module(reader);
|
||||
// const dxvk::DxbcModuleInfo info{};
|
||||
// auto shader = module.compile(info, "CS");
|
||||
|
||||
// // extract spir-v from d3d11 shader
|
||||
// auto code = shader->getRawCode();
|
||||
|
||||
// // patch binding offsets
|
||||
// #pragma clang diagnostic push
|
||||
// #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
// for (size_t i = 0; i < shader->m_bindingOffsets.size(); i++)
|
||||
// code.data()[shader->m_bindingOffsets.at(i).bindingOffset] = static_cast<uint8_t>(i); // NOLINT
|
||||
// #pragma clang diagnostic pop
|
||||
|
||||
// std::vector<uint8_t> spirvBytecode(code.size());
|
||||
// std::copy_n(reinterpret_cast<uint8_t*>(code.data()),
|
||||
// code.size(), spirvBytecode.data());
|
||||
// return spirvBytecode;
|
||||
// #endif
|
||||
}
|
||||
114
src/extract/extract.cpp
Normal file
114
src/extract/extract.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include "extract/extract.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <pe-parse/parse.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace Extract;
|
||||
|
||||
const std::unordered_map<std::string, uint32_t> nameHashTable = {{
|
||||
{ "mipmaps", 0xe365474d },
|
||||
{ "alpha[0]", 0xf37c8aa8 },
|
||||
{ "alpha[1]", 0xeb7a52d4 },
|
||||
{ "alpha[2]", 0x8901788e },
|
||||
{ "alpha[3]", 0xa06a5e36 },
|
||||
{ "beta[0]", 0x63c16b89 },
|
||||
{ "beta[1]", 0xe3967ed5 },
|
||||
{ "beta[2]", 0x570085ee },
|
||||
{ "beta[3]", 0x4f4530db },
|
||||
{ "beta[4]", 0x39727389 },
|
||||
{ "gamma[0]", 0x94c4edf6 },
|
||||
{ "gamma[1]", 0xf4e32702 },
|
||||
{ "gamma[2]", 0xa3dc56fc },
|
||||
{ "gamma[3]", 0x8b5ed8f6 },
|
||||
{ "gamma[4]", 0x1cbf3c4d },
|
||||
{ "delta[0]", 0x94c4edf6 },
|
||||
{ "delta[1]", 0xacfd805b },
|
||||
{ "delta[2]", 0x891dc48b },
|
||||
{ "delta[3]", 0x98536d9d },
|
||||
{ "delta[4]", 0x8e3f2155 },
|
||||
{ "delta[5]", 0x8f0e70a1 },
|
||||
{ "delta[6]", 0xd5eca8f1 },
|
||||
{ "delta[7]", 0xa9e54e37 },
|
||||
{ "delta[8]", 0x1dee8b84 },
|
||||
{ "delta[9]", 0x1576c3f5 },
|
||||
{ "generate", 0x5c040bd5 }
|
||||
}};
|
||||
|
||||
namespace {
|
||||
std::unordered_map<uint32_t, std::vector<uint8_t>> shaderData;
|
||||
|
||||
uint32_t fnv1a_hash(const std::vector<uint8_t>& data) {
|
||||
uint32_t hash = 0x811C9DC5;
|
||||
for (auto byte : data) {
|
||||
hash ^= byte;
|
||||
hash *= 0x01000193;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
int on_resource(void* data, const peparse::resource& res) { // NOLINT
|
||||
if (res.type != peparse::RT_RCDATA || res.buf == nullptr || res.buf->bufLen <= 0)
|
||||
return 0;
|
||||
std::vector<uint8_t> resource_data(res.buf->bufLen);
|
||||
std::copy_n(res.buf->buf, res.buf->bufLen, resource_data.data());
|
||||
|
||||
const uint32_t hash = fnv1a_hash(resource_data);
|
||||
shaderData[hash] = resource_data;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Extract::extractShaders() {
|
||||
if (shaderData.size() > 0)
|
||||
return;
|
||||
|
||||
// find path to dll (absolutely beautiful code)
|
||||
char* dllPath = getenv("LSFG_DLL_PATH");
|
||||
std::string dllPathStr;
|
||||
if (dllPath && *dllPath != '\0') {
|
||||
dllPathStr = std::string(dllPath);
|
||||
} else {
|
||||
const char* dataDir = getenv("XDG_DATA_HOME");
|
||||
if (dataDir && *dataDir != '\0') {
|
||||
dllPathStr = std::string(dataDir) +
|
||||
"/Steam/steamapps/common/Lossless Scaling/Lossless.dll";
|
||||
} else {
|
||||
const char* homeDir = getenv("HOME");
|
||||
if (homeDir && *homeDir != '\0') {
|
||||
dllPathStr = std::string(homeDir) +
|
||||
"/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll";
|
||||
} else {
|
||||
dllPathStr = "Lossless.dll";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse the dll
|
||||
peparse::parsed_pe* dll = peparse::ParsePEFromFile(dllPathStr.c_str());
|
||||
if (!dll)
|
||||
throw std::runtime_error("Unable to read Lossless.dll, is it installed?");
|
||||
peparse::IterRsrc(dll, on_resource, nullptr);
|
||||
peparse::DestructParsedPE(dll);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Extract::getShader(const std::string& name) {
|
||||
if (shaderData.empty())
|
||||
throw std::runtime_error("Shaders are not loaded.");
|
||||
|
||||
auto hit = nameHashTable.find(name);
|
||||
if (hit == nameHashTable.end())
|
||||
throw std::runtime_error("Shader not found: " + name);
|
||||
|
||||
auto sit = shaderData.find(hit->second);
|
||||
if (sit == shaderData.end())
|
||||
throw std::runtime_error("Shader not found: " + name);
|
||||
|
||||
return sit->second;
|
||||
}
|
||||
35
src/extract/trans.cpp
Normal file
35
src/extract/trans.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "extract/trans.hpp"
|
||||
|
||||
#include <dxbc/dxbc_modinfo.h>
|
||||
#include <dxbc/dxbc_module.h>
|
||||
#include <dxbc/dxbc_reader.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using namespace Extract;
|
||||
|
||||
std::vector<uint8_t> Extract::translateShader(std::vector<uint8_t> bytecode) {
|
||||
// compile the shader
|
||||
dxvk::DxbcReader reader(reinterpret_cast<const char*>(bytecode.data()), bytecode.size());
|
||||
dxvk::DxbcModule module(reader);
|
||||
const dxvk::DxbcModuleInfo info{};
|
||||
auto shader = module.compile(info, "CS");
|
||||
|
||||
// extract spir-v from d3d11 shader
|
||||
auto code = shader->getRawCode();
|
||||
|
||||
// patch binding offsets
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
for (size_t i = 0; i < shader->m_bindingOffsets.size(); i++)
|
||||
code.data()[shader->m_bindingOffsets.at(i).bindingOffset] // NOLINT
|
||||
= static_cast<uint8_t>(i);
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
// return the new bytecode
|
||||
std::vector<uint8_t> spirvBytecode(code.size());
|
||||
std::copy_n(reinterpret_cast<uint8_t*>(code.data()),
|
||||
code.size(), spirvBytecode.data());
|
||||
return spirvBytecode;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue