Split out common parts of Maxwell 3D draws

These will be able to be shared between indirect and normal draws.
This commit is contained in:
Billy Laws 2023-03-04 21:11:35 +00:00
parent 779ba3de05
commit d5b6c68ae4
2 changed files with 92 additions and 60 deletions

View File

@ -112,6 +112,80 @@ namespace skyline::gpu::interconnect::maxwell3d {
return scissor; return scissor;
} }
vk::Rect2D Maxwell3D::GetDrawScissor() {
const auto &surfaceClip{clearEngineRegisters.surfaceClip};
vk::Rect2D scissor{{surfaceClip.horizontal.x, surfaceClip.vertical.y},
{surfaceClip.horizontal.width, surfaceClip.vertical.height}};
auto colorAttachments{activeState.GetColorAttachments()};
auto depthStencilAttachment{activeState.GetDepthAttachment()};
auto depthStencilAttachmentSpan{depthStencilAttachment ? span<TextureView *>(depthStencilAttachment) : span<TextureView *>()};
for (auto attachment : ranges::views::concat(colorAttachments, depthStencilAttachmentSpan)) {
if (attachment) {
scissor.extent.width = std::min(scissor.extent.width, static_cast<u32>(static_cast<i32>(attachment->texture->dimensions.width) - scissor.offset.x));
scissor.extent.height = std::min(scissor.extent.height, static_cast<u32>(static_cast<i32>(attachment->texture->dimensions.height) - scissor.offset.y));
}
}
return scissor;
}
void Maxwell3D::PrepareDraw(StateUpdateBuilder &builder,
engine::DrawTopology topology, bool indexed, bool estimateIndexBufferSize, u32 firstIndex, u32 count,
vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask) {
Pipeline *oldPipeline{activeState.GetPipeline()};
samplers.Update(ctx, samplerBinding.value == engine::SamplerBinding::Value::ViaHeaderBinding);
activeState.Update(ctx, textures, constantBuffers.boundConstantBuffers,
builder,
indexed, topology, estimateIndexBufferSize, firstIndex, count,
srcStageMask, dstStageMask);
Pipeline *pipeline{activeState.GetPipeline()};
activeDescriptorSetSampledImages.resize(pipeline->GetTotalSampledImageCount());
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, samplers, textures,
*constantBuffers.quickBind, activeDescriptorSetSampledImages,
srcStageMask, dstStageMask);
else
return nullptr;
} else {
// If bindings have changed or quick bind is disabled, perform a full descriptor update
return pipeline->SyncDescriptors(ctx, constantBuffers.boundConstantBuffers, samplers, textures,
activeDescriptorSetSampledImages,
srcStageMask, dstStageMask);
}
}()};
if (oldPipeline != pipeline)
// If the pipeline has changed, we need to update the pipeline state
builder.SetPipeline(pipeline->compiledPipeline.pipeline, vk::PipelineBindPoint::eGraphics);
if (descUpdateInfo) {
if (ctx.gpu.traits.supportsPushDescriptors) {
builder.SetDescriptorSetWithPush(descUpdateInfo);
} else {
if (!attachedDescriptorSets)
attachedDescriptorSets = std::make_shared<boost::container::static_vector<DescriptorAllocator::ActiveDescriptorSet, DescriptorBatchSize>>();
auto newSet{&attachedDescriptorSets->emplace_back(ctx.gpu.descriptor.AllocateSet(descUpdateInfo->descriptorSetLayout))};
auto *oldSet{activeDescriptorSet};
activeDescriptorSet = newSet;
builder.SetDescriptorSetWithUpdate(descUpdateInfo, activeDescriptorSet, oldSet);
if (attachedDescriptorSets->size() == DescriptorBatchSize) {
ctx.executor.AttachDependency(attachedDescriptorSets);
attachedDescriptorSets.reset();
}
}
}
}
void Maxwell3D::LoadConstantBuffer(span<u32> data, u32 offset) { void Maxwell3D::LoadConstantBuffer(span<u32> data, u32 offset) {
constantBuffers.Load(ctx, data, offset); constantBuffers.Load(ctx, data, offset);
} }
@ -222,9 +296,8 @@ namespace skyline::gpu::interconnect::maxwell3d {
StateUpdateBuilder builder{*ctx.executor.allocator}; StateUpdateBuilder builder{*ctx.executor.allocator};
vk::PipelineStageFlags srcStageMask{}, dstStageMask{}; vk::PipelineStageFlags srcStageMask{}, dstStageMask{};
Pipeline *oldPipeline{activeState.GetPipeline()}; PrepareDraw(builder, topology, indexed, false, first, count, srcStageMask, dstStageMask);
samplers.Update(ctx, samplerBinding.value == engine::SamplerBinding::Value::ViaHeaderBinding);
activeState.Update(ctx, textures, constantBuffers.boundConstantBuffers, builder, indexed, topology, first, count, srcStageMask, dstStageMask);
if (directState.inputAssembly.NeedsQuadConversion()) { if (directState.inputAssembly.NeedsQuadConversion()) {
count = conversion::quads::GetIndexCount(count); count = conversion::quads::GetIndexCount(count);
first = 0; first = 0;
@ -237,48 +310,6 @@ namespace skyline::gpu::interconnect::maxwell3d {
} }
} }
Pipeline *pipeline{activeState.GetPipeline()};
activeDescriptorSetSampledImages.resize(pipeline->GetTotalSampledImageCount());
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, samplers, textures, *constantBuffers.quickBind, activeDescriptorSetSampledImages, srcStageMask, dstStageMask);
else
return nullptr;
} else {
// If bindings have changed or quick bind is disabled, perform a full descriptor update
return pipeline->SyncDescriptors(ctx, constantBuffers.boundConstantBuffers, samplers, textures, activeDescriptorSetSampledImages, srcStageMask, dstStageMask);
}
}()};
if (oldPipeline != pipeline)
// If the pipeline has changed, we need to update the pipeline state
builder.SetPipeline(pipeline->compiledPipeline.pipeline, vk::PipelineBindPoint::eGraphics);
if (descUpdateInfo) {
if (ctx.gpu.traits.supportsPushDescriptors) {
builder.SetDescriptorSetWithPush(descUpdateInfo);
} else {
if (!attachedDescriptorSets)
attachedDescriptorSets = std::make_shared<boost::container::static_vector<DescriptorAllocator::ActiveDescriptorSet, DescriptorBatchSize>>();
auto newSet{&attachedDescriptorSets->emplace_back(ctx.gpu.descriptor.AllocateSet(descUpdateInfo->descriptorSetLayout))};
auto *oldSet{activeDescriptorSet};
activeDescriptorSet = newSet;
builder.SetDescriptorSetWithUpdate(descUpdateInfo, activeDescriptorSet, oldSet);
if (attachedDescriptorSets->size() == DescriptorBatchSize) {
ctx.executor.AttachDependency(attachedDescriptorSets);
attachedDescriptorSets.reset();
}
}
}
auto stateUpdater{builder.Build()}; auto stateUpdater{builder.Build()};
/** /**
@ -298,24 +329,10 @@ namespace skyline::gpu::interconnect::maxwell3d {
count, first, instanceCount, vertexOffset, firstInstance, indexed, count, first, instanceCount, vertexOffset, firstInstance, indexed,
ctx.gpu.traits.supportsTransformFeedback ? transformFeedbackEnable : false})}; ctx.gpu.traits.supportsTransformFeedback ? transformFeedbackEnable : false})};
const auto &surfaceClip{clearEngineRegisters.surfaceClip}; vk::Rect2D scissor{GetDrawScissor()};
vk::Rect2D scissor{
{surfaceClip.horizontal.x, surfaceClip.vertical.y},
{surfaceClip.horizontal.width, surfaceClip.vertical.height}
};
auto colorAttachments{activeState.GetColorAttachments()};
auto depthStencilAttachment{activeState.GetDepthAttachment()};
auto depthStencilAttachmentSpan{depthStencilAttachment ? span<TextureView *>(depthStencilAttachment) : span<TextureView *>()};
for (auto attachment : ranges::views::concat(colorAttachments, depthStencilAttachmentSpan)) {
if (attachment) {
scissor.extent.width = std::min(scissor.extent.width, static_cast<u32>(static_cast<i32>(attachment->texture->dimensions.width) - scissor.offset.x));
scissor.extent.height = std::min(scissor.extent.height, static_cast<u32>(static_cast<i32>(attachment->texture->dimensions.height) - scissor.offset.y));
}
}
constantBuffers.ResetQuickBind(); constantBuffers.ResetQuickBind();
ctx.executor.AddSubpass([drawParams](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &gpu, vk::RenderPass, u32) { ctx.executor.AddSubpass([drawParams](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &gpu, vk::RenderPass, u32) {
drawParams->stateUpdater.RecordAll(gpu, commandBuffer); drawParams->stateUpdater.RecordAll(gpu, commandBuffer);

View File

@ -57,8 +57,23 @@ namespace skyline::gpu::interconnect::maxwell3d {
size_t UpdateQuadConversionBuffer(u32 count, u32 firstVertex); size_t UpdateQuadConversionBuffer(u32 count, u32 firstVertex);
/**
* @brief A scissor derived from the current clear register state
*/
vk::Rect2D GetClearScissor(); vk::Rect2D GetClearScissor();
/**
* @brief A scissor derived from the current draw register state and bound RTs
*/
vk::Rect2D GetDrawScissor();
/**
* @brief Performs operations common across indirect and regular draws
*/
void PrepareDraw(StateUpdateBuilder &builder,
engine::DrawTopology topology, bool indexed, bool estimateIndexBufferSize, u32 firstIndex, u32 count,
vk::PipelineStageFlags &srcStageMask, vk::PipelineStageFlags &dstStageMask);
public: public:
DirectPipelineState &directState; DirectPipelineState &directState;