mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 19:51:52 +01:00
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:
parent
a6bb716123
commit
0c6fa22c6b
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -14,7 +14,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
|
||||
static gpu::interconnect::maxwell3d::PipelineState::EngineRegisters MakePipelineStateRegisters(const Maxwell3D::Registers ®isters) {
|
||||
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},
|
||||
|
Loading…
Reference in New Issue
Block a user