Introduce pipeline shader stage state

Simple state that generates a hash that can be used in the packed state and spans over the binary for pipeline creation.
This commit is contained in:
Billy Laws 2022-09-10 20:55:55 +01:00
parent a6bb716123
commit 0c6fa22c6b
3 changed files with 78 additions and 4 deletions

View File

@ -211,6 +211,44 @@ namespace skyline::gpu::interconnect::maxwell3d {
view = ctx.executor.AcquireTextureManager().FindOrCreate(guest, ctx.executor.tag);
}
/* Pipeline Stages */
void PipelineStageState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
manager.Bind(handle, pipeline, programRegion);
}
PipelineStageState::PipelineStageState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine, u8 shaderType)
: engine{manager, dirtyHandle, engine},
shaderType{static_cast<engine::Pipeline::Shader::Type>(shaderType)} {}
void PipelineStageState::Flush(InterconnectContext &ctx) {
if (engine->pipeline.shader.type != shaderType)
throw exception("Shader type mismatch: {} != {}!", engine->pipeline.shader.type, static_cast<u8>(shaderType));
if (!engine->pipeline.shader.enable && shaderType != engine::Pipeline::Shader::Type::Vertex) {
hash = 0;
return;
}
binary.binary = ctx.channelCtx.asCtx->gmmu.ReadTill(shaderBacking, engine->programRegion + engine->pipeline.programOffset, [](span<u8> data) -> std::optional<size_t> {
// We attempt to find the shader size by looking for "BRA $" (Infinite Loop) which is used as padding at the end of the shader
// UAM Shader Compiler Reference: https://github.com/devkitPro/uam/blob/5a5afc2bae8b55409ab36ba45be63fcb73f68993/source/compiler_iface.cpp#L319-L351
constexpr u64 BraSelf1{0xE2400FFFFF87000F}, BraSelf2{0xE2400FFFFF07000F};
span<u64> shaderInstructions{data.cast<u64, std::dynamic_extent, true>()};
for (auto it{shaderInstructions.begin()}; it != shaderInstructions.end(); it++) {
auto instruction{*it};
if (instruction == BraSelf1 || instruction == BraSelf2) [[unlikely]]
// It is far more likely that the instruction doesn't match so this is an unlikely case
return static_cast<size_t>(std::distance(shaderInstructions.begin(), it)) * sizeof(u64);
}
return std::nullopt;
});
binary.baseOffset = engine->pipeline.programOffset;
hash = XXH64(binary.binary.data(), binary.binary.size_bytes(), 0);
}
/* Vertex Input State */
// TODO: check if better individually
void VertexInputState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
@ -502,7 +540,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
PipelineState::PipelineState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine)
: engine{manager, dirtyHandle, engine},
shaders{util::MergeInto<dirty::ManualDirtyState<IndividualShaderState>, engine::PipelineCount>(manager, engine.shadersRegisters, util::IncrementingT<u8>{})},
pipelineStages{util::MergeInto<dirty::ManualDirtyState<PipelineStageState>, engine::PipelineCount>(manager, engine.pipelineStageRegisters, util::IncrementingT<u8>{})},
colorRenderTargets{util::MergeInto<dirty::ManualDirtyState<ColorRenderTargetState>, engine::ColorTargetCount>(manager, engine.colorRenderTargetsRegisters, util::IncrementingT<size_t>{})},
depthRenderTarget{manager, engine.depthRenderTargetRegisters},
vertexInput{manager, engine.vertexInputRegisters},
@ -514,6 +552,13 @@ namespace skyline::gpu::interconnect::maxwell3d {
globalShaderConfig{engine.globalShaderConfigRegisters} {}
void PipelineState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder) {
std::array<ShaderBinary, engine::PipelineCount> shaderBinaries;
for (size_t i{}; i < engine::PipelineCount; i++) {
const auto &stage{pipelineStages[i].UpdateGet(ctx)};
packedState.shaderHashes[i] = stage.hash;
shaderBinaries[i] = stage.binary;
}
boost::container::static_vector<TextureView *, engine::ColorTargetCount> colorAttachments;
for (auto &colorRenderTarget : colorRenderTargets)
if (auto view{colorRenderTarget.UpdateGet(ctx, packedState).view}; view)

View File

@ -56,6 +56,32 @@ namespace skyline::gpu::interconnect::maxwell3d {
void Flush(InterconnectContext &ctx, PackedPipelineState &packedState);
};
class PipelineStageState : dirty::ManualDirty {
public:
struct EngineRegisters {
const engine::Pipeline &pipeline;
const soc::gm20b::engine::Address &programRegion;
void DirtyBind(DirtyManager &manager, dirty::Handle handle) const;
};
private:
dirty::BoundSubresource<EngineRegisters> engine;
engine::Pipeline::Shader::Type shaderType;
constexpr static size_t MaxShaderBytecodeSize{1 * 1024 * 1024}; //!< The largest shader binary that we support (1 MiB)
std::array<u8, MaxShaderBytecodeSize> shaderBacking;
public:
ShaderBinary binary;
u64 hash;
PipelineStageState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine, u8 shaderType);
void Flush(InterconnectContext &ctx);
};
class VertexInputState : dirty::ManualDirty {
public:
struct EngineRegisters {
@ -223,7 +249,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
class PipelineState : dirty::ManualDirty {
public:
struct EngineRegisters {
std::array<IndividualShaderState::EngineRegisters, engine::PipelineCount> shadersRegisters;
std::array<PipelineStageState::EngineRegisters, engine::PipelineCount> pipelineStageRegisters;
std::array<ColorRenderTargetState::EngineRegisters, engine::ColorTargetCount> colorRenderTargetsRegisters;
DepthRenderTargetState::EngineRegisters depthRenderTargetRegisters;
VertexInputState::EngineRegisters vertexInputRegisters;
@ -238,11 +264,14 @@ namespace skyline::gpu::interconnect::maxwell3d {
};
private:
PipelineManager pipelineManager{};
Pipeline *pipeline{};
PackedPipelineState packedState{};
dirty::BoundSubresource<EngineRegisters> engine;
std::array<dirty::ManualDirtyState<IndividualShaderState>, engine::PipelineCount> shaders;
std::array<dirty::ManualDirtyState<PipelineStageState>, engine::PipelineCount> pipelineStages;
std::array<dirty::ManualDirtyState<ColorRenderTargetState>, engine::ColorTargetCount> colorRenderTargets;
dirty::ManualDirtyState<DepthRenderTargetState> depthRenderTarget;
dirty::ManualDirtyState<VertexInputState> vertexInput;

View File

@ -14,7 +14,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
static gpu::interconnect::maxwell3d::PipelineState::EngineRegisters MakePipelineStateRegisters(const Maxwell3D::Registers &registers) {
return {
.shadersRegisters = util::MergeInto<REGTYPE(IndividualShaderState), type::PipelineCount>(*registers.pipelines, *registers.programRegion),
.pipelineStageRegisters = util::MergeInto<REGTYPE(PipelineStageState), type::PipelineCount>(*registers.pipelines, *registers.programRegion),
.colorRenderTargetsRegisters = util::MergeInto<REGTYPE(ColorRenderTargetState), type::ColorTargetCount>(*registers.colorTargets),
.depthRenderTargetRegisters = {*registers.ztSize, *registers.ztOffset, *registers.ztFormat, *registers.ztBlockSize, *registers.ztArrayPitch, *registers.ztSelect, *registers.ztLayer},
.vertexInputRegisters = {*registers.vertexStreams, *registers.vertexStreamInstance, *registers.vertexAttributes},