From 3f9161fb74a1dea1a6d26b7ebc6462ed1f5d24c9 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Tue, 6 Sep 2022 18:16:25 +0100 Subject: [PATCH] Transition vertex input state to pipeline cache key Also adds dirty tracking and removes it from direct state while we're at it. Since we no longer use Vulkan structs directly there's no benefit to it. --- .../maxwell_3d/pipeline_state.cpp | 79 +++---------------- .../interconnect/maxwell_3d/pipeline_state.h | 53 +++++++------ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 25 ------ 3 files changed, 39 insertions(+), 118 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp index 46cb3de9..31992ee1 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.cpp @@ -213,63 +213,23 @@ namespace skyline::gpu::interconnect::maxwell3d { } /* Vertex Input State */ + // TODO: check if better individually void VertexInputState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { - ranges::for_each(vertexStreamRegisters, [&](const auto ®s) { manager.Bind(handle, regs.format, regs.frequency); }); + ranges::for_each(vertexStreams, [&](const auto ®s) { manager.Bind(handle, regs.format, regs.frequency); }); auto bindFull{[&](const auto ®s) { manager.Bind(handle, regs); }}; - ranges::for_each(vertexStreamInstanceRegisters, bindFull); - ranges::for_each(vertexAttributesRegisters, bindFull); + ranges::for_each(vertexStreamInstance, bindFull); + ranges::for_each(vertexAttributes, bindFull); } - vk::StructureChain VertexInputState::Build(InterconnectContext &ctx, const EngineRegisters &engine) { - activeBindingDivisorDescs.clear(); - activeAttributeDescs.clear(); + VertexInputState::VertexInputState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {} - for (size_t i{}; i < engine::VertexStreamCount; i++) { - if (bindingDescs[i].inputRate == vk::VertexInputRate::eInstance) { - if (!ctx.gpu.traits.supportsVertexAttributeDivisor) [[unlikely]] - Logger::Warn("Vertex attribute divisor used on guest without host support"); - else if (!ctx.gpu.traits.supportsVertexAttributeZeroDivisor && bindingDivisorDescs[i].divisor == 0) [[unlikely]] - Logger::Warn("Vertex attribute zero divisor used on guest without host support"); - else - activeBindingDivisorDescs.push_back(bindingDivisorDescs[i]); - } - } + void VertexInputState::Flush(Key &key) { + for (u32 i{}; i < engine::VertexStreamCount; i++) + key.SetVertexBinding(i, engine->vertexStreams[i], engine->vertexStreamInstance[i]); - // TODO: check shader inputs - for (size_t i{}; i < engine::VertexAttributeCount; i++) - if (engine.vertexAttributesRegisters[i].source == engine::VertexAttribute::Source::Active) - activeAttributeDescs.push_back(attributeDescs[i]); - - vk::StructureChain chain{ - vk::PipelineVertexInputStateCreateInfo{ - .vertexBindingDescriptionCount = static_cast(bindingDescs.size()), - .pVertexBindingDescriptions = bindingDescs.data(), - .vertexAttributeDescriptionCount = static_cast(activeAttributeDescs.size()), - .pVertexAttributeDescriptions = activeAttributeDescs.data(), - }, - vk::PipelineVertexInputDivisorStateCreateInfoEXT{ - .vertexBindingDivisorCount = static_cast(activeBindingDivisorDescs.size()), - .pVertexBindingDivisors = activeBindingDivisorDescs.data(), - }, - }; - - if (activeBindingDivisorDescs.empty()) - chain.unlink(); - - return chain; - } - - void VertexInputState::SetStride(u32 index, u32 stride) { - bindingDescs[index].stride = stride; - } - - void VertexInputState::SetInputRate(u32 index, engine::VertexStreamInstance instance) { - bindingDescs[index].inputRate = instance.isInstanced ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex; - } - - void VertexInputState::SetDivisor(u32 index, u32 divisor) { - bindingDivisorDescs[index].divisor = divisor; + for (u32 i{}; i < engine::VertexAttributeCount; i++) + key.vertexAttributes[i] = engine->vertexAttributes[i]; } static vk::Format ConvertVertexInputAttributeFormat(engine::VertexAttribute::ComponentBitWidths componentBitWidths, engine::VertexAttribute::NumericalType numericalType) { @@ -354,20 +314,6 @@ namespace skyline::gpu::interconnect::maxwell3d { return Shader::AttributeType::Disabled; } } - - void VertexInputState::SetAttribute(u32 index, engine::VertexAttribute attribute) { - auto &vkAttribute{attributeDescs[index]}; - if (attribute.source == engine::VertexAttribute::Source::Active) { - vkAttribute.binding = attribute.stream; - vkAttribute.format = ConvertVertexInputAttributeFormat(attribute.componentBitWidths, attribute.numericalType); - vkAttribute.offset = attribute.offset; - - - // UpdateRuntimeInformation(runtimeInfo.generic_input_types[index], ConvertShaderGenericInputType(attribute.numericalType), maxwell3d::PipelineStage::Vertex); - } else { - // UpdateRuntimeInformation(runtimeInfo.generic_input_types[index], Shader::AttributeType::Disabled, maxwell3d::PipelineStage::Vertex); - } - } /* Input Assembly State */ void InputAssemblyState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { @@ -830,13 +776,12 @@ namespace skyline::gpu::interconnect::maxwell3d { : engine{manager, dirtyHandle, engine}, colorRenderTargets{util::MergeInto, engine::ColorTargetCount>(manager, engine.colorRenderTargetsRegisters, util::IncrementingT{})}, depthRenderTarget{manager, engine.depthRenderTargetRegisters}, + vertexInput{manager, engine.vertexInputRegisters}, rasterization{manager, engine.rasterizationRegisters}, depthStencil{manager, engine.depthStencilRegisters}, colorBlend{manager, engine.colorBlendRegisters} {} void PipelineState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder) { - Key key; - boost::container::static_vector colorAttachments; for (auto &colorRenderTarget : colorRenderTargets) if (auto view{colorRenderTarget.UpdateGet(ctx, key).view}; view) @@ -844,7 +789,7 @@ namespace skyline::gpu::interconnect::maxwell3d { TextureView *depthAttachment{depthRenderTarget.UpdateGet(ctx, key).view.get()}; - auto vertexInputState{directState.vertexInput.Build(ctx, engine->vertexInputRegisters)}; + vertexInput.Update(key); const auto &inputAssemblyState{directState.inputAssembly.Build()}; const auto &tessellationState{directState.tessellation.Build()}; const auto &rasterizationState{rasterization.UpdateGet().rasterizationState}; diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h index 9587c128..df7bc85c 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_state.h @@ -14,7 +14,17 @@ namespace skyline::gpu::interconnect::maxwell3d { u8 ztFormat : 5; // ZtFormat - 0xA as u8 }; + struct VertexBinding { + u16 stride : 12; + bool instanced : 1; + bool enable : 1; + u8 _pad_ : 2; + u32 divisor; + }; + static_assert(sizeof(VertexBinding) == 0x8); + std::array ctFormats; //!< ColorTarget::Format as u8 + std::array vertexBindings; public: std::array vertexAttributes; @@ -26,6 +36,13 @@ namespace skyline::gpu::interconnect::maxwell3d { void SetZtFormat(engine::ZtFormat format) { ztFormat = static_cast(format) - static_cast(engine::ZtFormat::ZF32); } + + void SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance) { + vertexBindings[index].stride = stream.format.stride; + vertexBindings[index].instanced = instance.isInstanced; + vertexBindings[index].enable = stream.format.enable; + vertexBindings[index].divisor = stream.frequency; + } }; class ColorRenderTargetState : dirty::ManualDirty { @@ -73,39 +90,23 @@ namespace skyline::gpu::interconnect::maxwell3d { void Flush(InterconnectContext &ctx, Key &key); }; - struct VertexInputState { - private: - std::array bindingDescs{ - util::MergeInto(util::IncrementingT{}) - }; - std::array bindingDivisorDescs{ - util::MergeInto(util::IncrementingT{}) - }; - std::array attributeDescs{ - util::MergeInto(util::IncrementingT{}) - }; - - boost::container::static_vector activeBindingDivisorDescs; - boost::container::static_vector activeAttributeDescs; - + class VertexInputState : dirty::ManualDirty { public: struct EngineRegisters { - const std::array &vertexStreamRegisters; - const std::array &vertexStreamInstanceRegisters; - const std::array &vertexAttributesRegisters; + const std::array &vertexStreams; + const std::array &vertexStreamInstance; + const std::array &vertexAttributes; void DirtyBind(DirtyManager &manager, dirty::Handle handle) const; }; - vk::StructureChain Build(InterconnectContext &ctx, const EngineRegisters &engine); + private: + dirty::BoundSubresource engine; - void SetStride(u32 index, u32 stride); + public: + VertexInputState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine); - void SetInputRate(u32 index, engine::VertexStreamInstance instance); - - void SetDivisor(u32 index, u32 divisor); - - void SetAttribute(u32 index, engine::VertexAttribute attribute); + void Flush(Key &key); }; struct InputAssemblyState { @@ -158,7 +159,6 @@ namespace skyline::gpu::interconnect::maxwell3d { * @brief Holds pipeline state that is directly written by the engine code, without using dirty tracking */ struct DirectPipelineState { - VertexInputState vertexInput; InputAssemblyState inputAssembly; TessellationState tessellation; }; @@ -269,6 +269,7 @@ namespace skyline::gpu::interconnect::maxwell3d { std::array, engine::ColorTargetCount> colorRenderTargets; dirty::ManualDirtyState depthRenderTarget; + dirty::ManualDirtyState vertexInput; dirty::ManualDirtyState rasterization; dirty::ManualDirtyState depthStencil; dirty::ManualDirtyState colorBlend; diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 8056b3f4..d472a64b 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -153,31 +153,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d { dirtyManager.MarkDirty(method); switch (method) { - #define VERTEX_STREAM_CALLBACKS(z, idx, data) \ - ENGINE_ARRAY_STRUCT_CASE(vertexStreams, idx, format, { \ - interconnect.directState.vertexInput.SetStride(idx, format.stride); \ - }) \ - ENGINE_ARRAY_STRUCT_CASE(vertexStreams, idx, frequency, { \ - interconnect.directState.vertexInput.SetDivisor(idx, frequency); \ - }) \ - ENGINE_ARRAY_CASE(vertexStreamInstance, idx, { \ - interconnect.directState.vertexInput.SetInputRate(idx, vertexStreamInstance); \ - }) - - BOOST_PP_REPEAT(16, VERTEX_STREAM_CALLBACKS, 0) - static_assert(type::VertexStreamCount == 16 && type::VertexStreamCount < BOOST_PP_LIMIT_REPEAT); - #undef VERTEX_STREAM_CALLBACKS - - - #define VERTEX_ATTRIBUTE_CALLBACKS(z, idx, data) \ - ENGINE_ARRAY_CASE(vertexAttributes, idx, { \ - interconnect.directState.vertexInput.SetAttribute(idx, vertexAttributes); \ - }) - - BOOST_PP_REPEAT(16, VERTEX_ATTRIBUTE_CALLBACKS, 0) - static_assert(type::VertexAttributeCount == 32 && type::VertexAttributeCount < BOOST_PP_LIMIT_REPEAT); - #undef VERTEX_ATTRIBUTE_CALLBACKS - ENGINE_CASE(primitiveRestartEnable, { interconnect.directState.inputAssembly.SetPrimitiveRestart(primitiveRestartEnable != 0);