From 04cea9239f2f195c93a25ce447517d845dd11160 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 22 Sep 2022 00:11:35 +0100 Subject: [PATCH] Implement descriptor set updating through StateUpdater Will automatically resolve buffer views at record-time into descriptor write/copy structures then apply the write and bind the set. --- .../gpu/interconnect/maxwell_3d/common.h | 11 +++ .../interconnect/maxwell_3d/maxwell_3d.cpp | 35 +++++-- .../gpu/interconnect/maxwell_3d/maxwell_3d.h | 2 + .../maxwell_3d/pipeline_manager.cpp | 48 +++++++--- .../maxwell_3d/pipeline_manager.h | 4 +- .../interconnect/maxwell_3d/state_updater.h | 92 +++++++++++++++---- 6 files changed, 149 insertions(+), 43 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/common.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/common.h index 301ca6e0..af9edd8c 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/common.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/common.h @@ -69,4 +69,15 @@ namespace skyline::gpu::interconnect::maxwell3d { using DirtyManager = dirty::Manager; class StateUpdateBuilder; + + struct DescriptorUpdateInfo { + span copies; //!< These will be performed before writes + span writes; + span bufferDescs; + span bufferDescDynamicBindings; + vk::PipelineLayout pipelineLayout; + vk::DescriptorSetLayout descriptorSetLayout; + vk::PipelineBindPoint bindPoint; + u32 descriptorSetIndex; + }; } diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp index 16704615..32f20c8a 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.cpp @@ -169,14 +169,29 @@ namespace skyline::gpu::interconnect::maxwell3d { activeState.Update(ctx, builder, indexed, topology, count); Pipeline *pipeline{activeState.GetPipeline()}; - if (((oldPipeline == pipeline) || (oldPipeline && oldPipeline->CheckBindingMatch(pipeline))) && constantBuffers.quickBindEnabled) { - // If bindings between the old and new pipelines are the same we can reuse the descriptor sets given that quick bind is enabled (meaning that no buffer updates or calls to non-graphics engines have occurred that could invalidate them) - if (constantBuffers.quickBind) - // If only a single constant buffer has been rebound between draws we can perform a partial descriptor update - pipeline->SyncDescriptorsQuickBind(ctx, constantBuffers.boundConstantBuffers, *constantBuffers.quickBind); - } else { - // If bindings have changed or quick bind is disabled, perform a full descriptor update - pipeline->SyncDescriptors(ctx, constantBuffers.boundConstantBuffers); + auto *descUpdateInfo{[&]() -> DescriptorUpdateInfo * { + if (((oldPipeline == pipeline) || (oldPipeline && oldPipeline->CheckBindingMatch(pipeline))) && constantBuffers.quickBindEnabled) { + // If bindings between the old and new pipelines are the same we can reuse the descriptor sets given that quick bind is enabled (meaning that no buffer updates or calls to non-graphics engines have occurred that could invalidate them) + if (constantBuffers.quickBind) + // If only a single constant buffer has been rebound between draws we can perform a partial descriptor update + return pipeline->SyncDescriptorsQuickBind(ctx, constantBuffers.boundConstantBuffers, *constantBuffers.quickBind); + else + return nullptr; + } else { + // If bindings have changed or quick bind is disabled, perform a full descriptor update + return pipeline->SyncDescriptors(ctx, constantBuffers.boundConstantBuffers); + } + }()}; + + if (descUpdateInfo) { + auto newSet{std::make_shared(ctx.gpu.descriptor.AllocateSet(descUpdateInfo->descriptorSetLayout))}; + ctx.executor.cycle->AttachObject(newSet); + + // Descriptor set lifetime is bound to the current cycle so we can safely use a raw pointer from now on + auto *oldSet{activeDescriptorSet}; + activeDescriptorSet = newSet.get(); + + builder.SetDescriptorSetWithUpdate(descUpdateInfo, activeDescriptorSet, oldSet); } const auto &surfaceClip{clearEngineRegisters.surfaceClip}; @@ -186,8 +201,8 @@ namespace skyline::gpu::interconnect::maxwell3d { }; auto stateUpdater{builder.Build()}; - ctx.executor.AddSubpass([stateUpdater](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &, GPU &, vk::RenderPass, u32) { - stateUpdater.RecordAll(commandBuffer); + ctx.executor.AddSubpass([stateUpdater](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &, GPU &gpu, vk::RenderPass, u32) { + stateUpdater.RecordAll(gpu, commandBuffer); }, scissor, {}, activeState.GetColorAttachments(), activeState.GetDepthAttachment()); constantBuffers.ResetQuickBind(); diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.h index 5bc713cb..68ed94b5 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/maxwell_3d.h @@ -39,6 +39,8 @@ namespace skyline::gpu::interconnect::maxwell3d { ClearEngineRegisters clearEngineRegisters; ConstantBuffers constantBuffers; + DescriptorAllocator::ActiveDescriptorSet *activeDescriptorSet{}; + vk::Rect2D GetClearScissor(); public: diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.cpp b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.cpp index d9015c89..593f20df 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.cpp @@ -609,7 +609,7 @@ namespace skyline::gpu::interconnect::maxwell3d { } // TODO: EXEC ID FOR STORAGE BUFS PURGE REMAP - void Pipeline::SyncDescriptors(InterconnectContext &ctx, ConstantBufferSet &constantBuffers) { + DescriptorUpdateInfo *Pipeline::SyncDescriptors(InterconnectContext &ctx, ConstantBufferSet &constantBuffers) { u32 bindingIdx{}; u32 writeIdx{}; u32 bufferIdx{}; @@ -617,7 +617,7 @@ namespace skyline::gpu::interconnect::maxwell3d { auto writes{ctx.executor.allocator->AllocateUntracked(descriptorInfo.writeDescCount)}; auto bufferDescs{ctx.executor.allocator->AllocateUntracked(descriptorInfo.totalBufferDescCount)}; - auto bufferDescViews{ctx.executor.allocator->AllocateUntracked(descriptorInfo.totalBufferDescCount)}; + auto bufferDescDynamicBindings{ctx.executor.allocator->AllocateUntracked(descriptorInfo.totalBufferDescCount)}; auto writeBufferDescs{[&](vk::DescriptorType type, const auto &descs, u32 count, auto getBufferCb) { if (!descs.empty()) { @@ -631,7 +631,7 @@ namespace skyline::gpu::interconnect::maxwell3d { for (size_t descIdx{}; descIdx < descs.size(); descIdx++) { const auto &shaderDesc{descs[descIdx]}; for (size_t arrayIdx{}; arrayIdx < shaderDesc.count; arrayIdx++) - bufferDescViews[bufferIdx++] = getBufferCb(shaderDesc, descIdx, arrayIdx); + bufferDescDynamicBindings[bufferIdx++] = getBufferCb(shaderDesc, descIdx, arrayIdx); } } }}; @@ -652,22 +652,35 @@ namespace skyline::gpu::interconnect::maxwell3d { return GetStorageBufferBinding(ctx, stage.info, constantBuffers[i][desc.cbuf_index], storageBufferViews[descIdx], descIdx); }); } + + return ctx.executor.allocator->EmplaceUntracked(DescriptorUpdateInfo{ + .writes = writes, + .bufferDescs = bufferDescs, + .bufferDescDynamicBindings = bufferDescDynamicBindings, + .pipelineLayout = compiledPipeline.pipelineLayout, + .descriptorSetLayout = compiledPipeline.descriptorSetLayout, + .bindPoint = vk::PipelineBindPoint::eGraphics, + .descriptorSetIndex = 0, + }); } - void Pipeline::SyncDescriptorsQuickBind(InterconnectContext &ctx, ConstantBufferSet &constantBuffers, ConstantBuffers::QuickBind quickBind) { - const auto &cbufUsageInfo{descriptorInfo.cbufUsages[static_cast(quickBind.stage)][quickBind.index]}; - const auto &shaderInfo{shaderStages[static_cast(quickBind.stage)].info}; - auto &stageConstantBuffers{constantBuffers[static_cast(quickBind.stage)]}; - auto copy{ctx.executor.allocator->AllocateUntracked()}; + DescriptorUpdateInfo *Pipeline::SyncDescriptorsQuickBind(InterconnectContext &ctx, ConstantBufferSet &constantBuffers, ConstantBuffers::QuickBind quickBind) { + size_t stageIndex{static_cast(quickBind.stage)}; + + const auto &cbufUsageInfo{descriptorInfo.cbufUsages[stageIndex][quickBind.index]}; + const auto &shaderInfo{shaderStages[stageIndex].info}; + auto &stageConstantBuffers{constantBuffers[stageIndex]}; + auto copies{ctx.executor.allocator->AllocateUntracked(1)}; auto writes{ctx.executor.allocator->AllocateUntracked(cbufUsageInfo.writeDescCount)}; + size_t writeIdx{}; size_t bufferIdx{}; auto bufferDescs{ctx.executor.allocator->AllocateUntracked(cbufUsageInfo.totalBufferDescCount)}; - auto bufferDescViews{ctx.executor.allocator->AllocateUntracked(cbufUsageInfo.totalBufferDescCount)}; + auto bufferDescDynamicBindings{ctx.executor.allocator->AllocateUntracked(cbufUsageInfo.totalBufferDescCount)}; - // TODO: opt this to do partial copy - *copy = vk::CopyDescriptorSet{ + // TODO: opt this to do partial copy and avoid updating twice + copies[0] = vk::CopyDescriptorSet{ .srcBinding = 0, .srcArrayElement = 0, .dstBinding = 0, @@ -687,7 +700,7 @@ namespace skyline::gpu::interconnect::maxwell3d { }; for (size_t i{}; i < shaderDesc.count; i++) - bufferDescViews[bufferIdx++] = getBufferCb(shaderDesc, usage.shaderDescIdx, i); + bufferDescDynamicBindings[bufferIdx++] = getBufferCb(shaderDesc, usage.shaderDescIdx, i); } }}; @@ -701,6 +714,17 @@ namespace skyline::gpu::interconnect::maxwell3d { [&](const Shader::StorageBufferDescriptor &desc, size_t descIdx, size_t arrayIdx) { return GetStorageBufferBinding(ctx, shaderInfo, stageConstantBuffers[desc.cbuf_index], storageBufferViews[bufferIdx], descIdx); }); + + return ctx.executor.allocator->EmplaceUntracked(DescriptorUpdateInfo{ + .copies = copies, + .writes = writes, + .bufferDescs = bufferDescs, + .bufferDescDynamicBindings = bufferDescDynamicBindings, + .pipelineLayout = compiledPipeline.pipelineLayout, + .descriptorSetLayout = compiledPipeline.descriptorSetLayout, + .bindPoint = vk::PipelineBindPoint::eGraphics, + .descriptorSetIndex = 0, + }); } } diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.h index c82bb027..85a8ce89 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/pipeline_manager.h @@ -94,9 +94,9 @@ namespace skyline::gpu::interconnect::maxwell3d { bool CheckBindingMatch(Pipeline *other); - void SyncDescriptors(InterconnectContext &ctx, ConstantBufferSet &constantBuffers); + DescriptorUpdateInfo *SyncDescriptors(InterconnectContext &ctx, ConstantBufferSet &constantBuffers); - void SyncDescriptorsQuickBind(InterconnectContext &ctx, ConstantBufferSet &constantBuffers, ConstantBuffers::QuickBind quickBind); + DescriptorUpdateInfo *SyncDescriptorsQuickBind(InterconnectContext &ctx, ConstantBufferSet &constantBuffers, ConstantBuffers::QuickBind quickBind); }; class PipelineManager { diff --git a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/state_updater.h b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/state_updater.h index c65f37b2..3152543a 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/state_updater.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/maxwell_3d/state_updater.h @@ -12,7 +12,7 @@ namespace skyline::gpu::interconnect::maxwell3d { */ struct StateUpdateCmdHeader { StateUpdateCmdHeader *next; - using RecordFunc = void (*)(vk::raii::CommandBuffer &commandBuffer, StateUpdateCmdHeader *header); + using RecordFunc = void (*)(GPU &gpu, vk::raii::CommandBuffer &commandBuffer, StateUpdateCmdHeader *header); RecordFunc record; }; @@ -30,13 +30,13 @@ namespace skyline::gpu::interconnect::maxwell3d { CmdHolder() = default; - static void Record(vk::raii::CommandBuffer &commandBuffer, StateUpdateCmdHeader *header) { - reinterpret_cast(header)->cmd.Record(commandBuffer); + static void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer, StateUpdateCmdHeader *header) { + reinterpret_cast(header)->cmd.Record(gpu, commandBuffer); } }; struct SetVertexBuffersCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.bindVertexBuffers(firstBinding, span(buffers).subspan(firstBinding, bindingCount), span(offsets).subspan(firstBinding, bindingCount)); @@ -50,7 +50,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetVertexBuffersCmd = CmdHolder; struct SetVertexBuffersDynamicCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { for (u32 i{base.firstBinding}; i < base.firstBinding + base.bindingCount; i++) { base.buffers[i] = views[i].GetBuffer()->GetBacking(); base.offsets[i] = views[i].GetOffset(); @@ -59,13 +59,13 @@ namespace skyline::gpu::interconnect::maxwell3d { base.Record(commandBuffer); } - SetVertexBuffersCmdImpl base; + SetVertexBuffersCmdImpl base{}; std::array views; }; using SetVertexBuffersDynamicCmd = CmdHolder; struct SetIndexBufferCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.bindIndexBuffer(buffer, offset, indexType); } @@ -76,7 +76,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetIndexBufferCmd = CmdHolder; struct SetIndexBufferDynamicCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { base.buffer = view.GetBuffer()->GetBacking(); base.offset = view.GetOffset(); base.Record(commandBuffer); @@ -88,7 +88,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetIndexBufferDynamicCmd = CmdHolder; struct SetTransformFeedbackBufferCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.bindTransformFeedbackBuffersEXT(binding, buffer, offset, size); } @@ -100,7 +100,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetTransformFeedbackBufferCmd = CmdHolder; struct SetTransformFeedbackBufferDynamicCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { base.buffer = view.GetBuffer()->GetBacking(); base.offset = view.GetOffset(); base.Record(commandBuffer); @@ -112,7 +112,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetTransformFeedbackBufferDynamicCmd = CmdHolder; struct SetViewportCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setViewport(index, viewport); } @@ -122,7 +122,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetViewportCmd = CmdHolder; struct SetScissorCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setScissor(index, scissor); } @@ -132,7 +132,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetScissorCmd = CmdHolder; struct SetLineWidthCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setLineWidth(lineWidth); } @@ -141,7 +141,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetLineWidthCmd = CmdHolder; struct SetDepthBiasCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setDepthBias(depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); } @@ -152,7 +152,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetDepthBiasCmd = CmdHolder; struct SetBlendConstantsCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setBlendConstants(blendConstants.data()); } @@ -161,7 +161,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetBlendConstantsCmd = CmdHolder; struct SetDepthBoundsCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setDepthBounds(minDepthBounds, maxDepthBounds); } @@ -171,7 +171,7 @@ namespace skyline::gpu::interconnect::maxwell3d { using SetDepthBoundsCmd = CmdHolder; struct SetBaseStencilStateCmdImpl { - void Record(vk::raii::CommandBuffer &commandBuffer) { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { commandBuffer.setStencilCompareMask(flags, funcMask); commandBuffer.setStencilReference(flags, funcRef); commandBuffer.setStencilWriteMask(flags, mask); @@ -184,6 +184,52 @@ namespace skyline::gpu::interconnect::maxwell3d { }; using SetBaseStencilStateCmd = CmdHolder; + struct SetDescriptorSetWithUpdateCmdImpl { + void Record(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) { + // Resolve descriptor infos from dynamic bindings + for (size_t i{}; i < updateInfo->bufferDescDynamicBindings.size(); i++) { + auto &dynamicBinding{updateInfo->bufferDescDynamicBindings[i]}; + if (auto view{std::get_if(&dynamicBinding)}) { + updateInfo->bufferDescs[i] = vk::DescriptorBufferInfo{ + .buffer = view->GetBuffer()->GetBacking(), + .offset = view->GetOffset(), + .range = view->size + }; + } else if (auto binding{std::get_if(&dynamicBinding)}) { + updateInfo->bufferDescs[i] = vk::DescriptorBufferInfo{ + .buffer = binding->buffer, + .offset = binding->offset, + .range = binding->size + }; + } + } + + // Set the destination/(source) descriptor set(s) for all writes/(copies) + for (auto &write : updateInfo->writes) + write.dstSet = **dstSet; + + for (auto © : updateInfo->copies) { + copy.dstSet = **dstSet; + copy.srcSet = **srcSet; + } + + // Perform the updates, doing copies first to avoid overwriting + if (!updateInfo->copies.empty()) + gpu.vkDevice.updateDescriptorSets({}, updateInfo->copies); + + if (!updateInfo->writes.empty()) + gpu.vkDevice.updateDescriptorSets(updateInfo->writes, {}); + + // Bind the updated descriptor set and we're done! + commandBuffer.bindDescriptorSets(updateInfo->bindPoint, updateInfo->pipelineLayout, updateInfo->descriptorSetIndex, **dstSet, 0); + } + + DescriptorUpdateInfo *updateInfo; + DescriptorAllocator::ActiveDescriptorSet *srcSet; + DescriptorAllocator::ActiveDescriptorSet *dstSet; + }; + using SetDescriptorSetWithUpdateCmd = CmdHolder; + /** * @brief Single-use helper for recording a batch of state updates into a command buffer */ @@ -197,9 +243,9 @@ namespace skyline::gpu::interconnect::maxwell3d { /** * @brief Records all contained state updates into the given command buffer */ - void RecordAll(vk::raii::CommandBuffer &commandBuffer) const { + void RecordAll(GPU &gpu, vk::raii::CommandBuffer &commandBuffer) const { for (StateUpdateCmdHeader *cmd{first}; cmd; cmd = cmd->next) - cmd->record(commandBuffer, cmd); + cmd->record(gpu, commandBuffer, cmd); } }; @@ -359,5 +405,13 @@ namespace skyline::gpu::interconnect::maxwell3d { .mask = mask, }); } + + void SetDescriptorSetWithUpdate(DescriptorUpdateInfo *updateInfo, DescriptorAllocator::ActiveDescriptorSet *dstSet, DescriptorAllocator::ActiveDescriptorSet *srcSet) { + AppendCmd({ + .updateInfo = updateInfo, + .srcSet = srcSet, + .dstSet = dstSet, + }); + } }; }