Implement Graphics Shader Compilation in ShaderManager

Graphics shaders can now be compiled using the shader compiler and emit SPIR-V that can be used on the host. The binding state isn't currently handled alongside constant buffers and textures support in `GraphicsEnvironment` yet.
This commit is contained in:
PixelyIon 2021-12-07 01:53:29 +05:30
parent 353ca8ec84
commit 08afda6ac4
2 changed files with 84 additions and 0 deletions

View File

@ -4,6 +4,8 @@
#include <gpu.h>
#include <shader_compiler/common/settings.h>
#include <shader_compiler/common/log.h>
#include <shader_compiler/frontend/maxwell/translate_program.h>
#include <shader_compiler/backend/spirv/emit_spirv.h>
#include "shader_manager.h"
namespace Shader::Log {
@ -75,4 +77,73 @@ namespace skyline::gpu {
},
};
}
/**
* @brief A shader environment for all graphics pipeline stages
*/
class GraphicsEnvironment : public Shader::Environment {
private:
std::vector<u8> binary;
u32 baseOffset;
public:
explicit GraphicsEnvironment(std::vector<u8> pBinary, u32 baseOffset, Shader::Stage pStage) : binary(std::move(pBinary)), baseOffset(baseOffset) {
sph = *reinterpret_cast<Shader::ProgramHeader *>(binary.data());
start_address = baseOffset;
stage = pStage;
}
[[nodiscard]] u64 ReadInstruction(u32 address) final {
address -= baseOffset;
if (binary.size() < (address + sizeof(u64)))
throw exception("Out of bounds instruction read: 0x{:X}", address);
return *reinterpret_cast<u64 *>(binary.data() + address);
}
[[nodiscard]] u32 ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) final {
throw exception("Not implemented");
}
[[nodiscard]] Shader::TextureType ReadTextureType(u32 raw_handle) final {
throw exception("Not implemented");
}
[[nodiscard]] u32 TextureBoundBuffer() const final {
throw exception("Not implemented");
}
[[nodiscard]] u32 LocalMemorySize() const final {
return static_cast<u32>(sph.LocalMemorySize()) + sph.common3.shader_local_memory_crs_size;
}
[[nodiscard]] u32 SharedMemorySize() const final {
return 0; // Shared memory size is only relevant for compute shaders
}
[[nodiscard]] std::array<u32, 3> WorkgroupSize() const final {
return {0, 0, 0}; // Workgroup size is only relevant for compute shaders
}
};
vk::raii::ShaderModule ShaderManager::CompileGraphicsShader(const std::vector<u8> &binary, Shader::Stage stage, u32 baseOffset, Shader::RuntimeInfo& runtimeInfo) {
GraphicsEnvironment environment{binary, baseOffset, stage};
Shader::Maxwell::Flow::CFG cfg(environment, flowBlockPool, Shader::Maxwell::Location{static_cast<u32>(baseOffset + sizeof(Shader::ProgramHeader))});
auto program{Shader::Maxwell::TranslateProgram(instPool, blockPool, environment, cfg, hostTranslateInfo)};
Shader::Backend::Bindings bindings{};
auto spirv{Shader::Backend::SPIRV::EmitSPIRV(profile, runtimeInfo, program, bindings)};
runtimeInfo.previous_stage_stores = program.info.stores;
if (program.is_geometry_passthrough)
runtimeInfo.previous_stage_stores.mask |= program.info.passthrough.mask;
vk::ShaderModuleCreateInfo createInfo{
.pCode = spirv.data(),
.codeSize = spirv.size() * sizeof(u32),
};
vk::raii::ShaderModule shaderModule(gpu.vkDevice, createInfo);
return shaderModule;
}
}

View File

@ -4,6 +4,11 @@
#pragma once
#include <vulkan/vulkan.hpp>
#include <shader_compiler/object_pool.h>
#include <shader_compiler/frontend/maxwell/control_flow.h>
#include <shader_compiler/frontend/ir/value.h>
#include <shader_compiler/frontend/ir/basic_block.h>
#include <shader_compiler/runtime_info.h>
#include <shader_compiler/host_translate_info.h>
#include <shader_compiler/profile.h>
#include <common.h>
@ -15,10 +20,18 @@ namespace skyline::gpu {
class ShaderManager {
private:
GPU &gpu;
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flowBlockPool;
Shader::ObjectPool<Shader::IR::Inst> instPool;
Shader::ObjectPool<Shader::IR::Block> blockPool;
Shader::HostTranslateInfo hostTranslateInfo;
Shader::Profile profile;
public:
ShaderManager(const DeviceState& state, GPU &gpu);
/**
* @note `runtimeInfo::previous_stage_stores` will automatically be updated for the next stage
*/
vk::raii::ShaderModule CompileGraphicsShader(const std::vector<u8> &binary, Shader::Stage stage, u32 baseOffset, Shader::RuntimeInfo& runtimeInfo);
};
}