From eb7c10e89f27d04b5f8a13886ee3c64244a08bfd Mon Sep 17 00:00:00 2001 From: Samuliak Date: Fri, 13 Sep 2024 10:41:03 +0200 Subject: [PATCH] implement occlusion queries --- .../HW/Latte/Renderer/Metal/CachedFBOMtl.cpp | 9 ++-- .../HW/Latte/Renderer/Metal/CachedFBOMtl.h | 7 +--- .../HW/Latte/Renderer/Metal/MetalQuery.cpp | 14 +++++-- src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h | 5 ++- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 34 ++++++++++++--- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 41 +++++++++++++++++++ 6 files changed, 91 insertions(+), 19 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp index a9e673f6..85adbfb9 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp @@ -1,9 +1,9 @@ #include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h" #include "Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h" -#include "HW/Latte/Renderer/Metal/LatteToMtl.h" -#include "Metal/MTLRenderPass.hpp" +#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" +#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" -void CachedFBOMtl::CreateRenderPass() +CachedFBOMtl::CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key) : LatteCachedFBO(key) { m_renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); @@ -39,6 +39,9 @@ void CachedFBOMtl::CreateRenderPass() stencilAttachment->setStoreAction(MTL::StoreActionStore); } } + + // Visibility buffer + m_renderPassDescriptor->setVisibilityResultBuffer(metalRenderer->GetOcclusionQueryResultBuffer()); } CachedFBOMtl::~CachedFBOMtl() diff --git a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h index 0d926e7e..f1221eb2 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h @@ -8,10 +8,7 @@ class CachedFBOMtl : public LatteCachedFBO { public: - CachedFBOMtl(uint64 key) : LatteCachedFBO(key) - { - CreateRenderPass(); - } + CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key); ~CachedFBOMtl(); @@ -22,6 +19,4 @@ public: private: MTL::RenderPassDescriptor* m_renderPassDescriptor = nullptr; - - void CreateRenderPass(); }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp index 40c73fd4..c27a5620 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp @@ -1,17 +1,25 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalQuery.h" +#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" +#include "HW/Latte/Renderer/Metal/MetalCommon.h" bool LatteQueryObjectMtl::getResult(uint64& numSamplesPassed) { - cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::getResult: occlusion queries are not yet supported on Metal"); + if (!m_mtlr->CommandBufferCompleted(m_commandBuffer)) + return false; + + numSamplesPassed = m_mtlr->GetOcclusionQueryResultsPtr()[m_queryIndex]; + return true; } void LatteQueryObjectMtl::begin() { - cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::begin: occlusion queries are not yet supported on Metal"); + m_queryIndex = m_mtlr->GetAvailableOcclusionQueryIndex(); + m_mtlr->SetActiveOcclusionQueryIndex(m_queryIndex); } void LatteQueryObjectMtl::end() { - cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::end: occlusion queries are not yet supported on Metal"); + m_mtlr->SetActiveOcclusionQueryIndex(INVALID_UINT32); + // TODO: request soon submit of the command buffer } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h index ea2be227..8fa53497 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h @@ -4,7 +4,6 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h" -// HACK: Dummy occlusion query object class LatteQueryObjectMtl : public LatteQueryObject { public: @@ -16,4 +15,8 @@ public: private: class MetalRenderer* m_mtlr; + + uint32 m_queryIndex; + MTL::CommandBuffer* m_commandBuffer; + uint64 m_acccumulatedSum; }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index ffb8fb72..045ca77e 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -21,12 +21,14 @@ #include "HW/Latte/Renderer/Metal/MetalCommon.h" #include "HW/Latte/Renderer/Metal/MetalLayerHandle.h" #include "HW/Latte/Renderer/Renderer.h" +#include "Metal/MTLRenderCommandEncoder.hpp" #define IMGUI_IMPL_METAL_CPP #include "imgui/imgui_extension.h" #include "imgui/imgui_impl_metal.h" #define COMMIT_TRESHOLD 256 +#define OCCLUSION_QUERY_POOL_SIZE 1024 extern bool hasValidFramebufferAttached; @@ -94,6 +96,17 @@ MetalRenderer::MetalRenderer() m_xfbRingBuffer->setLabel(GetLabel("Transform feedback buffer", m_xfbRingBuffer)); #endif + // Occlusion queries + m_occlusionQuery.m_resultBuffer = m_device->newBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), MTL::ResourceStorageModeShared); +#ifdef CEMU_DEBUG_ASSERT + m_occlusionQuery.m_resultBuffer->setLabel(GetLabel("Occlusion query result buffer", m_occlusionQuery.m_resultBuffer)); +#endif + m_occlusionQuery.m_resultsPtr = (uint64*)m_occlusionQuery.m_resultBuffer->contents(); + + m_occlusionQuery.m_availableIndices.reserve(OCCLUSION_QUERY_POOL_SIZE); + for (uint32 i = 0; i < OCCLUSION_QUERY_POOL_SIZE; i++) + m_occlusionQuery.m_availableIndices.push_back(i); + // Initialize state for (uint32 i = 0; i < METAL_SHADER_TYPE_TOTAL; i++) { @@ -467,7 +480,7 @@ void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, si LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) { - return new CachedFBOMtl(key); + return new CachedFBOMtl(this, key); } void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo) @@ -1042,6 +1055,14 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 encoderState.m_depthClipEnable = zClipEnable; } + // Visibility result mode + if (m_occlusionQuery.m_activeIndex != encoderState.m_visibilityResultOffset) + { + auto mode = (m_occlusionQuery.m_activeIndex == INVALID_UINT32 ? MTL::VisibilityResultModeDisabled : MTL::VisibilityResultModeCounting); + renderCommandEncoder->setVisibilityResultMode(mode, m_occlusionQuery.m_activeIndex); + encoderState.m_visibilityResultOffset = m_occlusionQuery.m_activeIndex; + } + // todo - how does culling behave with rects? // right now we just assume that their winding is always CW if (isPrimitiveRect) @@ -1284,21 +1305,20 @@ void MetalRenderer::indexData_uploadIndexMemory(uint32 bufferIndex, uint32 offse } LatteQueryObject* MetalRenderer::occlusionQuery_create() { - cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_create: Occlusion queries are not yet supported on Metal"); - return new LatteQueryObjectMtl(this); } void MetalRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj) { - cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_destroy: occlusion queries are not yet supported on Metal"); + // TODO: do something? } void MetalRenderer::occlusionQuery_flush() { - cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_flush: occlusion queries are not yet supported on Metal"); + // TODO: implement + debug_printf("Occlusion query flush is not implemented\n"); } void MetalRenderer::occlusionQuery_updateState() { - cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_updateState: occlusion queries are not yet supported on Metal"); + // TODO } void MetalRenderer::SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index) @@ -1574,6 +1594,8 @@ void MetalRenderer::CommitCommandBuffer() m_memoryManager->GetTemporaryBufferAllocator().SetActiveCommandBuffer(nullptr); + m_occlusionQuery.m_availableIndices.insert(m_occlusionQuery.m_availableIndices.end(), m_occlusionQuery.m_crntCmdBuffIndices.begin(), m_occlusionQuery.m_crntCmdBuffIndices.end()); + // Debug //m_commandQueue->insertDebugCaptureBoundary(); } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index f00f814c..4f7376b6 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -99,6 +99,7 @@ struct MetalEncoderState uint32 m_depthSlope = 0; uint32 m_depthClamp = 0; bool m_depthClipEnable = true; + uint32 m_visibilityResultOffset = INVALID_UINT32; struct { MTL::Buffer* m_buffer; size_t m_offset; @@ -376,6 +377,36 @@ public: return m_readbackBuffer; } + MTL::Buffer* GetOcclusionQueryResultBuffer() const + { + return m_occlusionQuery.m_resultBuffer; + } + + uint64* GetOcclusionQueryResultsPtr() + { + return m_occlusionQuery.m_resultsPtr; + } + + uint32 GetAvailableOcclusionQueryIndex() + { + if (m_occlusionQuery.m_availableIndices.empty()) + { + cemuLog_log(LogType::Force, "No occlusion query index available"); + return 0; + } + + uint32 queryIndex = m_occlusionQuery.m_availableIndices.back(); + m_occlusionQuery.m_availableIndices.pop_back(); + m_occlusionQuery.m_crntCmdBuffIndices.push_back(queryIndex); + + return queryIndex; + } + + void SetActiveOcclusionQueryIndex(uint32 queryIndex) + { + m_occlusionQuery.m_activeIndex = queryIndex; + } + private: MetalLayerHandle m_mainLayer; MetalLayerHandle m_padLayer; @@ -423,6 +454,16 @@ private: // Transform feedback MTL::Buffer* m_xfbRingBuffer; + // Occlusion queries + struct + { + MTL::Buffer* m_resultBuffer; + uint64* m_resultsPtr; + std::vector m_availableIndices; + std::vector m_crntCmdBuffIndices; + uint32 m_activeIndex = INVALID_UINT32; + } m_occlusionQuery; + // Active objects std::vector m_commandBuffers; MetalEncoderType m_encoderType = MetalEncoderType::None;