mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-03 18:41:48 +01:00
Add host shader replacement and dumping support
This is useful for debugging, but shouldn't generally be used as bindings in SPIR-V etc are unstable.
This commit is contained in:
parent
02786839a5
commit
2e64199640
@ -25,7 +25,7 @@ namespace skyline::gpu::interconnect::kepler_compute {
|
||||
|
||||
Shader::Backend::Bindings bindings{};
|
||||
|
||||
return {ctx.gpu.shader->CompileShader({}, program, bindings), program.info};
|
||||
return {ctx.gpu.shader->CompileShader({}, program, bindings, packedState.shaderHash), program.info};
|
||||
}
|
||||
|
||||
static Pipeline::DescriptorInfo MakePipelineDescriptorInfo(const Pipeline::ShaderStage &stage) {
|
||||
|
@ -35,8 +35,10 @@ namespace skyline::gpu {
|
||||
for (const auto &entry : std::filesystem::directory_iterator{replacementDirPath}) {
|
||||
if (entry.is_regular_file()) {
|
||||
// Parse hash from filename
|
||||
u64 hash{std::stoull(entry.path().filename().string(), nullptr, 16)};
|
||||
auto it{shaderReplacements.insert({hash, {}})};
|
||||
auto path{entry.path()};
|
||||
auto &replacementMap{path.extension().string() == ".spv" ? hostShaderReplacements : guestShaderReplacements};
|
||||
u64 hash{std::stoull(path.stem().string(), nullptr, 16)};
|
||||
auto it{replacementMap.insert({hash, {}})};
|
||||
|
||||
// Read file into map entry
|
||||
std::ifstream file{entry.path(), std::ios::binary | std::ios::ate};
|
||||
@ -48,9 +50,10 @@ namespace skyline::gpu {
|
||||
}
|
||||
}
|
||||
|
||||
span<u8> ShaderManager::ProcessShaderBinary(u64 hash, span<u8> binary) {
|
||||
auto it{shaderReplacements.find(hash)};
|
||||
if (it != shaderReplacements.end()) {
|
||||
span<u8> ShaderManager::ProcessShaderBinary(bool spv, u64 hash, span<u8> binary) {
|
||||
auto &replacementMap{spv ? hostShaderReplacements : guestShaderReplacements};
|
||||
auto it{replacementMap.find(hash)};
|
||||
if (it != replacementMap.end()) {
|
||||
Logger::Info("Replacing shader with hash: 0x{:X}", hash);
|
||||
return it->second;
|
||||
}
|
||||
@ -58,7 +61,7 @@ namespace skyline::gpu {
|
||||
if (DumpShaders) {
|
||||
std::scoped_lock lock{dumpMutex};
|
||||
|
||||
auto shaderPath{dumpPath / fmt::format("{:016X}", hash)};
|
||||
auto shaderPath{dumpPath / fmt::format("{:016X}{}", hash, spv ? ".spv" : "")};
|
||||
if (!std::filesystem::exists(shaderPath)) {
|
||||
std::ofstream file{shaderPath, std::ios::binary};
|
||||
file.write(reinterpret_cast<const char *>(binary.data()), static_cast<std::streamsize>(binary.size()));
|
||||
@ -368,7 +371,7 @@ namespace skyline::gpu {
|
||||
u32 textureConstantBufferIndex,
|
||||
bool viewportTransformEnabled,
|
||||
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
||||
binary = ProcessShaderBinary(hash, binary);
|
||||
binary = ProcessShaderBinary(false, hash, binary);
|
||||
|
||||
std::scoped_lock lock{poolMutex};
|
||||
|
||||
@ -395,7 +398,7 @@ namespace skyline::gpu {
|
||||
u32 localMemorySize, u32 sharedMemorySize,
|
||||
std::array<u32, 3> workgroupDimensions,
|
||||
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
||||
binary = ProcessShaderBinary(hash, binary);
|
||||
binary = ProcessShaderBinary(false, hash, binary);
|
||||
|
||||
std::scoped_lock lock{poolMutex};
|
||||
|
||||
@ -410,11 +413,12 @@ namespace skyline::gpu {
|
||||
if (program.info.loads.Legacy() || program.info.stores.Legacy())
|
||||
Shader::Maxwell::ConvertLegacyToGeneric(program, runtimeInfo);
|
||||
|
||||
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)};
|
||||
auto spirvEmitted{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)};
|
||||
auto spirv{ProcessShaderBinary(true, hash, span<u32>{spirvEmitted}.cast<u8>()).cast<u32>()};
|
||||
|
||||
vk::ShaderModuleCreateInfo createInfo{
|
||||
.pCode = spirv.data(),
|
||||
.codeSize = spirv.size() * sizeof(u32),
|
||||
.codeSize = spirv.size_bytes(),
|
||||
};
|
||||
|
||||
return (*gpu.vkDevice).createShaderModule(createInfo, nullptr, *gpu.vkDevice.getDispatcher());
|
||||
|
@ -28,7 +28,9 @@ namespace skyline::gpu {
|
||||
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
|
||||
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
||||
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
||||
std::unordered_map<u64, std::vector<u8>> shaderReplacements; //!< Map of shader hash -> replacement shader binary, populated at init time and must not be modified after
|
||||
std::unordered_map<u64, std::vector<u8>> guestShaderReplacements; //!< Map of guest shader hash -> replacement guest shader binary, populated at init time and must not be modified after
|
||||
std::unordered_map<u64, std::vector<u8>> hostShaderReplacements; //!< ^^ same as above but for host
|
||||
|
||||
std::mutex poolMutex;
|
||||
std::filesystem::path dumpPath;
|
||||
std::mutex dumpMutex;
|
||||
@ -42,7 +44,7 @@ namespace skyline::gpu {
|
||||
* @brief Returns the raw binary of shader replacement for the given hash, if no replacement is found the input binary is returned
|
||||
* @note This will also dump the binary to disk if dumping is enabled
|
||||
*/
|
||||
span<u8> ProcessShaderBinary(u64 hash, span<u8> binary);
|
||||
span<u8> ProcessShaderBinary(bool spv, u64 hash, span<u8> binary);
|
||||
|
||||
public:
|
||||
using ConstantBufferRead = std::function<u32(u32 index, u32 offset)>; //!< A function which reads a constant buffer at the specified offset and returns the value
|
||||
|
Loading…
Reference in New Issue
Block a user