Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Cafe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@ if(ENABLE_METAL)
HW/Latte/Renderer/Metal/MetalSamplerCache.h
HW/Latte/Renderer/Metal/MetalHybridComputePipeline.cpp
HW/Latte/Renderer/Metal/MetalHybridComputePipeline.h
HW/Latte/Renderer/Metal/MetalQuery.cpp
HW/Latte/Renderer/Metal/MetalQuery.h
HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h
HW/Latte/Renderer/Metal/UtilityShaderSource.h
)
Expand Down
9 changes: 6 additions & 3 deletions src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp
Original file line number Diff line number Diff line change
@@ -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();

Expand Down Expand Up @@ -39,6 +39,9 @@ void CachedFBOMtl::CreateRenderPass()
stencilAttachment->setStoreAction(MTL::StoreActionStore);
}
}

// Visibility buffer
m_renderPassDescriptor->setVisibilityResultBuffer(metalRenderer->GetOcclusionQueryResultBuffer());
}

CachedFBOMtl::~CachedFBOMtl()
Expand Down
7 changes: 1 addition & 6 deletions src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
class CachedFBOMtl : public LatteCachedFBO
{
public:
CachedFBOMtl(uint64 key) : LatteCachedFBO(key)
{
CreateRenderPass();
}
CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key);

~CachedFBOMtl();

Expand All @@ -22,6 +19,4 @@ class CachedFBOMtl : public LatteCachedFBO

private:
MTL::RenderPassDescriptor* m_renderPassDescriptor = nullptr;

void CreateRenderPass();
};
5 changes: 3 additions & 2 deletions src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), 0, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);

m_commandBuffer = m_mtlr->GetCurrentCommandBuffer();
m_mtlr->RequestSoonCommit();
}

bool LatteTextureReadbackInfoMtl::IsFinished()
Expand All @@ -38,12 +39,12 @@ bool LatteTextureReadbackInfoMtl::IsFinished()
if (m_mtlr->GetCurrentCommandBuffer() == m_commandBuffer)
m_mtlr->CommitCommandBuffer();

return m_mtlr->CommandBufferCompleted(m_commandBuffer);
return CommandBufferCompleted(m_commandBuffer);
}

void LatteTextureReadbackInfoMtl::ForceFinish()
{
m_mtlr->WaitForCommandBufferCompletion(m_commandBuffer);
m_commandBuffer->waitUntilCompleted();
}

uint8* LatteTextureReadbackInfoMtl::GetData()
Expand Down
2 changes: 1 addition & 1 deletion src/Cafe/HW/Latte/Renderer/Metal/MetalBufferAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class MetalTemporaryBufferAllocator : public MetalBufferAllocator<MetalSyncedBuf
auto& buffer = m_buffers[i];
for (uint32_t j = 0; j < buffer.m_data.m_commandBuffers.size(); j++)
{
if (m_mtlr->CommandBufferCompleted(buffer.m_data.m_commandBuffers[j]))
if (CommandBufferCompleted(buffer.m_data.m_commandBuffers[j]))
{
if (buffer.m_data.m_commandBuffers.size() == 1)
{
Expand Down
6 changes: 6 additions & 0 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,9 @@ inline bool IsValidDepthTextureType(Latte::E_DIM dim)
{
return (dim == Latte::E_DIM::DIM_2D || dim == Latte::E_DIM::DIM_2D_MSAA || dim == Latte::E_DIM::DIM_2D_ARRAY || dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA || dim == Latte::E_DIM::DIM_CUBEMAP);
}

inline bool CommandBufferCompleted(MTL::CommandBuffer* commandBuffer)
{
auto status = commandBuffer->status();
return (status == MTL::CommandBufferStatusCompleted || status == MTL::CommandBufferStatusError);
}
41 changes: 41 additions & 0 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#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)
{
if (!m_commandBuffer)
{
numSamplesPassed = 0;
return true;
}

if (!CommandBufferCompleted(m_commandBuffer))
return false;

numSamplesPassed = m_mtlr->GetOcclusionQueryResultsPtr()[m_queryIndex];

return true;
}

LatteQueryObjectMtl::~LatteQueryObjectMtl()
{
if (m_queryIndex != INVALID_UINT32)
m_mtlr->ReleaseOcclusionQueryIndex(m_queryIndex);
}

void LatteQueryObjectMtl::begin()
{
m_queryIndex = m_mtlr->GetAvailableOcclusionQueryIndex();
m_mtlr->SetActiveOcclusionQueryIndex(m_queryIndex);
}

void LatteQueryObjectMtl::end()
{
m_mtlr->SetActiveOcclusionQueryIndex(INVALID_UINT32);
if (m_mtlr->IsCommandBufferActive())
{
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer();
m_mtlr->RequestSoonCommit();
}
}
23 changes: 23 additions & 0 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "Cafe/HW/Latte/Core/LatteQueryObject.h"

#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"

class LatteQueryObjectMtl : public LatteQueryObject
{
public:
LatteQueryObjectMtl(class MetalRenderer* mtlRenderer) : m_mtlr{mtlRenderer} {}
~LatteQueryObjectMtl();

bool getResult(uint64& numSamplesPassed) override;
void begin() override;
void end() override;

private:
class MetalRenderer* m_mtlr;

uint32 m_queryIndex = INVALID_UINT32;
// TODO: make this a list of command buffers
MTL::CommandBuffer* m_commandBuffer = nullptr;
};
66 changes: 48 additions & 18 deletions src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalHybridComputePipeline.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalQuery.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"

#include "Cafe/HW/Latte/Renderer/Metal/UtilityShaderSource.h"
Expand All @@ -20,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 DEFAULT_COMMIT_TRESHOLD 256
#define OCCLUSION_QUERY_POOL_SIZE 1024

extern bool hasValidFramebufferAttached;

Expand Down Expand Up @@ -93,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++)
{
Expand Down Expand Up @@ -320,7 +334,7 @@ void MetalRenderer::Flush(bool waitIdle)
{
cemu_assert_debug(commandBuffer.m_commited);

WaitForCommandBufferCompletion(commandBuffer.m_commandBuffer);
commandBuffer.m_commandBuffer->waitUntilCompleted();
}
}
}
Expand Down Expand Up @@ -466,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)
Expand Down Expand Up @@ -1041,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 * sizeof(uint64));
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)
Expand Down Expand Up @@ -1248,7 +1270,8 @@ void MetalRenderer::draw_endSequence()
bool hasReadback = LatteTextureReadback_Update();
m_recordedDrawcalls++;
// The number of draw calls needs to twice as big, since we are interrupting the render pass
if (m_recordedDrawcalls >= COMMIT_TRESHOLD * 2 || hasReadback)
// TODO: ucomment?
if (m_recordedDrawcalls >= m_commitTreshold * 2/* || hasReadback*/)
{
CommitCommandBuffer();

Expand Down Expand Up @@ -1282,6 +1305,23 @@ void MetalRenderer::indexData_uploadIndexMemory(uint32 bufferIndex, uint32 offse
*/
}

LatteQueryObject* MetalRenderer::occlusionQuery_create() {
return new LatteQueryObjectMtl(this);
}

void MetalRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj) {
auto queryObjMtl = static_cast<LatteQueryObjectMtl*>(queryObj);
delete queryObjMtl;
}

void MetalRenderer::occlusionQuery_flush() {
// TODO: implement
}

void MetalRenderer::occlusionQuery_updateState() {
// TODO: implement
}

void MetalRenderer::SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index)
{
auto& boundBuffer = m_state.m_encoderState.m_buffers[shaderType][index];
Expand Down Expand Up @@ -1370,6 +1410,9 @@ MTL::CommandBuffer* MetalRenderer::GetCommandBuffer()
MTL::CommandBuffer* mtlCommandBuffer = m_commandQueue->commandBuffer();
m_commandBuffers.push_back({mtlCommandBuffer});

m_recordedDrawcalls = 0;
m_commitTreshold = DEFAULT_COMMIT_TRESHOLD;

// Notify memory manager about the new command buffer
m_memoryManager->GetTemporaryBufferAllocator().SetActiveCommandBuffer(mtlCommandBuffer);

Expand All @@ -1381,17 +1424,6 @@ MTL::CommandBuffer* MetalRenderer::GetCommandBuffer()
}
}

bool MetalRenderer::CommandBufferCompleted(MTL::CommandBuffer* commandBuffer)
{
auto status = commandBuffer->status();
return (status == MTL::CommandBufferStatusCompleted || status == MTL::CommandBufferStatusError);
}

void MetalRenderer::WaitForCommandBufferCompletion(MTL::CommandBuffer* commandBuffer)
{
commandBuffer->waitUntilCompleted();
}

MTL::RenderCommandEncoder* MetalRenderer::GetTemporaryRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor)
{
EndEncoding();
Expand Down Expand Up @@ -1529,15 +1561,13 @@ void MetalRenderer::EndEncoding()
m_encoderType = MetalEncoderType::None;

// Commit the command buffer if enough draw calls have been recorded
if (m_recordedDrawcalls >= COMMIT_TRESHOLD)
if (m_recordedDrawcalls >= m_commitTreshold)
CommitCommandBuffer();
}
}

void MetalRenderer::CommitCommandBuffer()
{
m_recordedDrawcalls = 0;

if (m_commandBuffers.size() != 0)
{
EndEncoding();
Expand Down
Loading