gpu: drop global barriers for PM4 flush events and releases, ordering buffer-writing draws like dispatches

This commit is contained in:
nmzik
2026-10-21 01:33:10 +02:00
parent ea1b032c59
commit 70668fbd98
6 changed files with 31 additions and 64 deletions
@@ -104,7 +104,6 @@ public:
uint32_t value);
void PrepareCpuFlip(uint64_t request_id);
void SynchronizeGpu();
void EmitGlobalBarrier();
void TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id);
void DispatchDirect(uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_z,
uint32_t mode);
@@ -71,12 +71,6 @@ constexpr uint32_t NormalizeRegisterOffset(uint32_t raw_offset) {
return raw_offset & ~RegisterSelectorMask;
}
bool ReleaseMemGcrNeedsBarrier(uint32_t eop_event_type, uint32_t gcr_cntl) {
return eop_event_type != 0x28u ||
(gcr_cntl & (GcrGl2MetadataInvalidate | GcrGl0VectorInvalidate | GcrGl1Invalidate |
GcrGl2Invalidate | GcrGl2Writeback)) != 0;
}
uint32_t ReleaseMemCacheActionFromGcr(uint32_t gcr_cntl) {
return ((gcr_cntl & GcrGl2Writeback) != 0 ? 0x38u : 0x00u);
}
@@ -2259,30 +2253,14 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
}
};
if (data_sel == 0 || interrupt_selector == 4) {
if (eop_event_type != 0x28 || gcr_cntl != 0) {
cp.EmitGlobalBarrier();
}
// Cache actions only order GPU work, which the renderer's resource barriers already order.
if (data_sel == 0 || interrupt_selector == 4 ||
(release_dst == ReleaseMemDstMemory && dst_gpu_addr == nullptr)) {
trigger_interrupt();
return 7;
}
if (release_dst == ReleaseMemDstMemory && dst_gpu_addr == nullptr) {
if (eop_event_type != 0x28 || gcr_cntl != 0) {
cp.EmitGlobalBarrier();
}
trigger_interrupt();
return 7;
}
if (ReleaseMemGcrNeedsBarrier(eop_event_type, gcr_cntl)) {
cp.EmitGlobalBarrier();
}
auto cache_action = ReleaseMemCacheActionFromGcr(gcr_cntl);
cache_policy = 0;
+5 -27
View File
@@ -607,7 +607,6 @@ bool GuestGpu::Process(Submission& submission) {
case SubmissionType::SuspendPoint:
// Age caches at the frame boundary, not once per command list.
m_renderer.RunGarbageCollector();
cp.EmitGlobalBarrier();
m_renderer.GetCommandScheduler().DeferPriorityOperation(
[ready = m_suspend_point_ready] { ready->release(); });
cp.BufferFlush();
@@ -1222,22 +1221,6 @@ void CommandProcessor::WriteAtEndOfPipe64(uint32_t cache_policy, uint32_t event_
interrupt_context_id);
}
void CommandProcessor::EmitGlobalBarrier() {
Common::LockGuard lock(m_renderer.GetMutex());
vk::MemoryBarrier2 barrier {};
barrier.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.srcAccessMask = vk::AccessFlagBits2::eMemoryWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite;
vk::DependencyInfo dependency {};
dependency.memoryBarrierCount = 1;
dependency.pMemoryBarriers = &barrier;
GetScheduler().EndRendering();
CurrentBuffer().Handle().pipelineBarrier2(dependency);
}
void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id) {
(void)CurrentBuffer().Handle();
GetScheduler().DeferPriorityOperation(
@@ -1257,21 +1240,17 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index,
}
const auto valid_cache_event_index = event_index == 0x00000000 || event_index == 0x00000007;
// Partial flushes and cache writebacks only order GPU work, which the renderer's resource
// barriers already order.
switch (event_type) {
// CsPartialFlush, GsPartialFlush, PsPartialFlush.
case 0x00000007:
case 0x0000000f:
case 0x00000010: EmitGlobalBarrier(); break;
// CbDbDataWritebackInvalidate, CbDataWritebackInvalidate.
case 0x00000010: break;
// CbDbDataWritebackInvalidate, CbDataWritebackInvalidate, DbDataWritebackInvalidate,
// DbMetadataWritebackInvalidate, CbMetadataWritebackInvalidate.
case 0x00000016:
case 0x00000031:
if (!valid_cache_event_index) {
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type,
event_index);
}
EmitGlobalBarrier();
break;
// DbDataWritebackInvalidate, DbMetadataWritebackInvalidate, CbMetadataWritebackInvalidate.
case 0x0000002a:
case 0x0000002c:
case 0x0000002e:
@@ -1279,7 +1258,6 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index,
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type,
event_index);
}
EmitGlobalBarrier();
break;
case 0x0000000d:
case 0x0000000e:
+7 -1
View File
@@ -104,8 +104,14 @@ void CommandBuffer::BeginRendering(const RenderState& state) const {
rendering.pDepthAttachment = depth_stencil.has_depth ? &depth : nullptr;
rendering.pStencilAttachment = depth_stencil.has_stencil ? &stencil : nullptr;
Handle().beginRendering(rendering);
// The open pass holds the cleared contents, so a later clear begins a new pass.
m_render_state = state;
m_rendering = true;
for (auto& color: m_render_state.color_attachments) {
color.is_clear = false;
}
m_render_state.depth_stencil_attachment.depth_clear = false;
m_render_state.depth_stencil_attachment.stencil_clear = false;
m_rendering = true;
}
void CommandBuffer::EndRendering() const {
@@ -92,7 +92,8 @@ bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
const auto& program = *runtime.program;
const auto& resources = *runtime.resources;
EXIT_IF(resources.buffers.size() != program.info.buffers.size());
bool has_writes = false;
// Address writes reach memory outside the bound buffer descriptors.
bool has_writes = program.has_address_writes;
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
if (!program.info.buffers[i].written) {
continue;
+14 -9
View File
@@ -1227,6 +1227,20 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
dynamic_state.SetAttachmentFeedbackLoopAspects(feedback_aspects);
dynamic_state.Commit(m_context.GetGraphics(), vk_buffer);
vk::PipelineStageFlags shader_write_stages = {};
for (const auto& stage: vertex_stages) {
if (HasShaderBufferWrites(stage.stage)) {
shader_write_stages |= ShaderPipelineStages(NativeShaderStage(stage.logical_stage));
}
}
if (state.ps_active && HasShaderBufferWrites(state.ps_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
}
if (shader_write_stages) {
// As for dispatches, buffer writes wait for earlier accesses to the memory.
m_context.GetCommandScheduler().EndRendering();
ShaderWriteHazardBarrier(vk_buffer, shader_write_stages);
}
LogDrawPhase(draw.Name(), "BeginRendering");
if (!draw.IsIndexed()) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x400u);
@@ -1247,15 +1261,6 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
if (!draw.IsIndexed()) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x600u);
}
vk::PipelineStageFlags shader_write_stages = {};
for (const auto& stage: vertex_stages) {
if (HasShaderBufferWrites(stage.stage)) {
shader_write_stages |= ShaderPipelineStages(NativeShaderStage(stage.logical_stage));
}
}
if (state.ps_active && HasShaderBufferWrites(state.ps_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
}
if (shader_write_stages) {
m_context.GetCommandScheduler().EndRendering();
ShaderWriteBarrier(vk_buffer, shader_write_stages);