mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-03 19:51:53 +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{};
|
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) {
|
static Pipeline::DescriptorInfo MakePipelineDescriptorInfo(const Pipeline::ShaderStage &stage) {
|
||||||
|
@ -35,8 +35,10 @@ namespace skyline::gpu {
|
|||||||
for (const auto &entry : std::filesystem::directory_iterator{replacementDirPath}) {
|
for (const auto &entry : std::filesystem::directory_iterator{replacementDirPath}) {
|
||||||
if (entry.is_regular_file()) {
|
if (entry.is_regular_file()) {
|
||||||
// Parse hash from filename
|
// Parse hash from filename
|
||||||
u64 hash{std::stoull(entry.path().filename().string(), nullptr, 16)};
|
auto path{entry.path()};
|
||||||
auto it{shaderReplacements.insert({hash, {}})};
|
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
|
// Read file into map entry
|
||||||
std::ifstream file{entry.path(), std::ios::binary | std::ios::ate};
|
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) {
|
span<u8> ShaderManager::ProcessShaderBinary(bool spv, u64 hash, span<u8> binary) {
|
||||||
auto it{shaderReplacements.find(hash)};
|
auto &replacementMap{spv ? hostShaderReplacements : guestShaderReplacements};
|
||||||
if (it != shaderReplacements.end()) {
|
auto it{replacementMap.find(hash)};
|
||||||
|
if (it != replacementMap.end()) {
|
||||||
Logger::Info("Replacing shader with hash: 0x{:X}", hash);
|
Logger::Info("Replacing shader with hash: 0x{:X}", hash);
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
@ -58,7 +61,7 @@ namespace skyline::gpu {
|
|||||||
if (DumpShaders) {
|
if (DumpShaders) {
|
||||||
std::scoped_lock lock{dumpMutex};
|
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)) {
|
if (!std::filesystem::exists(shaderPath)) {
|
||||||
std::ofstream file{shaderPath, std::ios::binary};
|
std::ofstream file{shaderPath, std::ios::binary};
|
||||||
file.write(reinterpret_cast<const char *>(binary.data()), static_cast<std::streamsize>(binary.size()));
|
file.write(reinterpret_cast<const char *>(binary.data()), static_cast<std::streamsize>(binary.size()));
|
||||||
@ -368,7 +371,7 @@ namespace skyline::gpu {
|
|||||||
u32 textureConstantBufferIndex,
|
u32 textureConstantBufferIndex,
|
||||||
bool viewportTransformEnabled,
|
bool viewportTransformEnabled,
|
||||||
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
||||||
binary = ProcessShaderBinary(hash, binary);
|
binary = ProcessShaderBinary(false, hash, binary);
|
||||||
|
|
||||||
std::scoped_lock lock{poolMutex};
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
@ -395,13 +398,13 @@ namespace skyline::gpu {
|
|||||||
u32 localMemorySize, u32 sharedMemorySize,
|
u32 localMemorySize, u32 sharedMemorySize,
|
||||||
std::array<u32, 3> workgroupDimensions,
|
std::array<u32, 3> workgroupDimensions,
|
||||||
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
const ConstantBufferRead &constantBufferRead, const GetTextureType &getTextureType) {
|
||||||
binary = ProcessShaderBinary(hash, binary);
|
binary = ProcessShaderBinary(false, hash, binary);
|
||||||
|
|
||||||
std::scoped_lock lock{poolMutex};
|
std::scoped_lock lock{poolMutex};
|
||||||
|
|
||||||
ComputeEnvironment environment{binary, baseOffset, textureConstantBufferIndex, localMemorySize, sharedMemorySize, workgroupDimensions, constantBufferRead, getTextureType};
|
ComputeEnvironment environment{binary, baseOffset, textureConstantBufferIndex, localMemorySize, sharedMemorySize, workgroupDimensions, constantBufferRead, getTextureType};
|
||||||
Shader::Maxwell::Flow::CFG cfg{environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset)}};
|
Shader::Maxwell::Flow::CFG cfg{environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset)}};
|
||||||
return Shader::Maxwell::TranslateProgram(instructionPool, blockPool, environment, cfg, hostTranslateInfo);
|
return Shader::Maxwell::TranslateProgram(instructionPool, blockPool, environment, cfg, hostTranslateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ShaderModule ShaderManager::CompileShader(const Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings, u64 hash) {
|
vk::ShaderModule ShaderManager::CompileShader(const Shader::RuntimeInfo &runtimeInfo, Shader::IR::Program &program, Shader::Backend::Bindings &bindings, u64 hash) {
|
||||||
@ -410,11 +413,12 @@ namespace skyline::gpu {
|
|||||||
if (program.info.loads.Legacy() || program.info.stores.Legacy())
|
if (program.info.loads.Legacy() || program.info.stores.Legacy())
|
||||||
Shader::Maxwell::ConvertLegacyToGeneric(program, runtimeInfo);
|
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{
|
vk::ShaderModuleCreateInfo createInfo{
|
||||||
.pCode = spirv.data(),
|
.pCode = spirv.data(),
|
||||||
.codeSize = spirv.size() * sizeof(u32),
|
.codeSize = spirv.size_bytes(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (*gpu.vkDevice).createShaderModule(createInfo, nullptr, *gpu.vkDevice.getDispatcher());
|
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::Maxwell::Flow::Block> flowBlockPool;
|
||||||
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
Shader::ObjectPool<Shader::IR::Inst> instructionPool;
|
||||||
Shader::ObjectPool<Shader::IR::Block> blockPool;
|
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::mutex poolMutex;
|
||||||
std::filesystem::path dumpPath;
|
std::filesystem::path dumpPath;
|
||||||
std::mutex dumpMutex;
|
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
|
* @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
|
* @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:
|
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
|
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