// SPDX-License-Identifier: MPL-2.0 // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once #include #include #include #include "common.h" #include "packed_pipeline_state.h" #include "pipeline_manager.h" namespace skyline::gpu::interconnect::maxwell3d { class ColorRenderTargetState : dirty::ManualDirty { public: struct EngineRegisters { const engine::ColorTarget &colorTarget; const engine::SurfaceClip &surfaceClip; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; size_t index; public: ColorRenderTargetState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine, size_t index); std::shared_ptr view; engine::ColorTarget::Format format{engine::ColorTarget::Format::Disabled}; void Flush(InterconnectContext &ctx, PackedPipelineState &packedState); }; class DepthRenderTargetState : dirty::ManualDirty { public: struct EngineRegisters { const engine::ZtSize &ztSize; const soc::gm20b::engine::Address &ztOffset; const engine::ZtFormat &ztFormat; const engine::ZtBlockSize &ztBlockSize; const u32 &ztArrayPitchLsr2; const engine::ZtSelect &ztSelect; const engine::ZtLayer &ztLayer; const engine::SurfaceClip &surfaceClip; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; u32 ZtArrayPitch() const { return ztArrayPitchLsr2 << 2; } }; private: dirty::BoundSubresource engine; public: DepthRenderTargetState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); std::shared_ptr view; void Flush(InterconnectContext &ctx, PackedPipelineState &packedState); }; class PipelineStageState : dirty::RefreshableManualDirty, dirty::CachedManualDirty { public: struct EngineRegisters { const engine::Pipeline &pipeline; const soc::gm20b::engine::Address &programRegion; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; engine::Pipeline::Shader::Type shaderType; ShaderCache cache; public: ShaderBinary binary; u64 hash; PipelineStageState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine, u8 shaderType); void Flush(InterconnectContext &ctx); bool Refresh(InterconnectContext &ctx); void PurgeCaches(); }; class VertexInputState : dirty::ManualDirty { public: struct EngineRegisters { const std::array &vertexStreams; const std::array &vertexStreamInstance; const std::array &vertexAttributes; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; public: VertexInputState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(PackedPipelineState &packedState); }; class InputAssemblyState { public: struct EngineRegisters { const u32 &primitiveRestartEnable; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: EngineRegisters engine; vk::PipelineInputAssemblyStateCreateInfo inputAssemblyState{}; engine::DrawTopology currentEngineTopology{}; public: InputAssemblyState(const EngineRegisters &engine); void Update(PackedPipelineState &packedState); void SetPrimitiveTopology(engine::DrawTopology topology); engine::DrawTopology GetPrimitiveTopology() const; bool NeedsQuadConversion() const; }; class TessellationState { public: struct EngineRegisters { const u32 &patchSize; const engine::TessellationParameters &tessellationParameters; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: EngineRegisters engine; public: TessellationState(const EngineRegisters &engine); void Update(PackedPipelineState &packedState); }; /** * @brief Holds pipeline state that is directly written by the engine code, without using dirty tracking */ struct DirectPipelineState { InputAssemblyState inputAssembly; }; class RasterizationState : dirty::ManualDirty { public: struct EngineRegisters { const u32 &rasterEnable; const engine::PolygonMode &frontPolygonMode; const engine::PolygonMode &backPolygonMode; const u32 &oglCullEnable; const engine::CullFace &oglCullFace; const engine::WindowOrigin &windowOrigin; const engine::FrontFace &oglFrontFace; const engine::ViewportClipControl &viewportClipControl; const engine::PolyOffset &polyOffset; const engine::ProvokingVertex &provokingVertex; const float &pointSize; const engine::ZClipRange &zClipRange; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; public: vk::StructureChain rasterizationState{}; RasterizationState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(PackedPipelineState &packedState); }; class DepthStencilState : dirty::ManualDirty { public: struct EngineRegisters { const u32 &depthTestEnable; const u32 &depthWriteEnable; const engine::CompareFunc &depthFunc; const u32 &depthBoundsTestEnable; const u32 &stencilTestEnable; const u32 &twoSidedStencilTestEnable; const engine::StencilOps &stencilOps; const engine::StencilOps &stencilBack; const u32 &alphaTestEnable; const engine::CompareFunc &alphaFunc; const float &alphaRef; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; public: DepthStencilState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(PackedPipelineState &packedState); }; class ColorBlendState : dirty::ManualDirty { public: struct EngineRegisters { const engine::LogicOp &logicOp; const u32 &singleCtWriteControl; const std::array &ctWrites; const u32 &blendStatePerTargetEnable; const std::array &blendPerTargets; const engine::Blend &blend; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; public: std::bitset writtenCtMask{}; ColorBlendState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(PackedPipelineState &packedState); }; class TransformFeedbackState : dirty::ManualDirty { public: struct EngineRegisters { const u32 &streamOutputEnable; const std::array &streamOutControls; const std::array, engine::StreamOutBufferCount> &streamOutLayoutSelect; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: dirty::BoundSubresource engine; public: TransformFeedbackState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(PackedPipelineState &packedState); }; class GlobalShaderConfigState { public: struct EngineRegisters { const std::array &postVtgShaderAttributeSkipMask; const engine_common::BindlessTexture &bindlessTexture; const u32 &apiMandatedEarlyZ; const u32 &viewportScaleOffsetEnable; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: EngineRegisters engine; public: GlobalShaderConfigState(const EngineRegisters &engine); void Update(PackedPipelineState &packedState); }; /** * @brief Holds all GPU state for a pipeline, any changes to this will result in a pipeline cache lookup */ class PipelineState : dirty::CachedManualDirty { public: struct EngineRegisters { std::array pipelineStageRegisters; std::array colorRenderTargetsRegisters; DepthRenderTargetState::EngineRegisters depthRenderTargetRegisters; VertexInputState::EngineRegisters vertexInputRegisters; InputAssemblyState::EngineRegisters inputAssemblyRegisters; TessellationState::EngineRegisters tessellationRegisters; RasterizationState::EngineRegisters rasterizationRegisters; DepthStencilState::EngineRegisters depthStencilRegisters; ColorBlendState::EngineRegisters colorBlendRegisters; TransformFeedbackState::EngineRegisters transformFeedbackRegisters; GlobalShaderConfigState::EngineRegisters globalShaderConfigRegisters; const engine::CtSelect &ctSelect; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; private: PackedPipelineState packedState{}; dirty::BoundSubresource engine; std::array, engine::PipelineCount> pipelineStages; std::array, engine::ColorTargetCount> colorRenderTargets; dirty::ManualDirtyState depthRenderTarget; dirty::ManualDirtyState vertexInput; TessellationState tessellation; dirty::ManualDirtyState rasterization; dirty::ManualDirtyState depthStencil; dirty::ManualDirtyState colorBlend; dirty::ManualDirtyState transformFeedback; GlobalShaderConfigState globalShaderConfig; const engine::CtSelect &ctSelect; public: DirectPipelineState directState; Pipeline *pipeline{}; boost::container::static_vector colorAttachments; TextureView *depthAttachment{}; PipelineState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); void Flush(InterconnectContext &ctx, Textures &textures, ConstantBufferSet &constantBuffers, StateUpdateBuilder &builder); void PurgeCaches(); std::shared_ptr GetColorRenderTargetForClear(InterconnectContext &ctx, size_t index); std::shared_ptr GetDepthRenderTargetForClear(InterconnectContext &ctx); }; }