refactor fbos

This commit is contained in:
Samuliak 2024-10-15 17:15:46 +02:00
parent 6b47d4f61e
commit cd21d957b3
No known key found for this signature in database
9 changed files with 143 additions and 75 deletions

View File

@ -534,6 +534,7 @@ if(APPLE)
endif() endif()
if(ENABLE_METAL) if(ENABLE_METAL)
# TODO: sort alphabetically
target_sources(CemuCafe PRIVATE target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/Metal/MetalRenderer.cpp HW/Latte/Renderer/Metal/MetalRenderer.cpp
HW/Latte/Renderer/Metal/MetalRenderer.h HW/Latte/Renderer/Metal/MetalRenderer.h
@ -555,6 +556,8 @@ if(ENABLE_METAL)
HW/Latte/Renderer/Metal/RendererShaderMtl.h HW/Latte/Renderer/Metal/RendererShaderMtl.h
HW/Latte/Renderer/Metal/CachedFBOMtl.cpp HW/Latte/Renderer/Metal/CachedFBOMtl.cpp
HW/Latte/Renderer/Metal/CachedFBOMtl.h HW/Latte/Renderer/Metal/CachedFBOMtl.h
HW/Latte/Renderer/Metal/MetalAttachmentsInfo.cpp
HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h
HW/Latte/Renderer/Metal/MetalBufferAllocator.h HW/Latte/Renderer/Metal/MetalBufferAllocator.h
HW/Latte/Renderer/Metal/MetalMemoryManager.cpp HW/Latte/Renderer/Metal/MetalMemoryManager.cpp
HW/Latte/Renderer/Metal/MetalMemoryManager.h HW/Latte/Renderer/Metal/MetalMemoryManager.h

View File

@ -0,0 +1,48 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
#include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
MetalAttachmentsInfo::MetalAttachmentsInfo(class CachedFBOMtl* fbo)
{
for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)
{
const auto& colorBuffer = fbo->colorBuffer[i];
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);
if (!texture)
continue;
colorFormats[i] = texture->format;
}
// Depth stencil attachment
if (fbo->depthBuffer.texture)
{
auto texture = static_cast<LatteTextureViewMtl*>(fbo->depthBuffer.texture);
depthFormat = texture->format;
hasStencil = fbo->depthBuffer.hasStencil;
}
}
MetalAttachmentsInfo::MetalAttachmentsInfo(const LatteContextRegister& lcr, const LatteDecompilerShader* pixelShader)
{
uint8 cbMask = LatteMRT::GetActiveColorBufferMask(pixelShader, lcr);
bool dbMask = LatteMRT::GetActiveDepthBufferMask(lcr);
// Color attachments
for (int i = 0; i < 8; ++i)
{
if ((cbMask & (1 << i)) == 0)
continue;
colorFormats[i] = LatteMRT::GetColorBufferFormat(i, lcr);
}
// Depth stencil attachment
if (dbMask)
{
Latte::E_GX2SURFFMT format = LatteMRT::GetDepthBufferFormat(lcr);
depthFormat = format;
hasStencil = GetMtlPixelFormatInfo(format, true).hasStencil;
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
class MetalAttachmentsInfo
{
public:
MetalAttachmentsInfo() = default;
MetalAttachmentsInfo(class CachedFBOMtl* fbo);
MetalAttachmentsInfo(const LatteContextRegister& lcr, const class LatteDecompilerShader* pixelShader);
Latte::E_GX2SURFFMT colorFormats[LATTE_NUM_COLOR_TARGET] = {Latte::E_GX2SURFFMT::INVALID_FORMAT};
Latte::E_GX2SURFFMT depthFormat = Latte::E_GX2SURFFMT::INVALID_FORMAT;
bool hasStencil = false;
};

View File

@ -11,6 +11,9 @@
#include "Cafe/HW/Latte/Core/LatteShaderCache.h" #include "Cafe/HW/Latte/Core/LatteShaderCache.h"
#include "Cemu/FileCache/FileCache.h" #include "Cemu/FileCache/FileCache.h"
#include "HW/Latte/Core/LatteShader.h" #include "HW/Latte/Core/LatteShader.h"
#include "HW/Latte/ISA/LatteReg.h"
#include "HW/Latte/Renderer/Metal/LatteToMtl.h"
#include "HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
#include "util/helpers/helpers.h" #include "util/helpers/helpers.h"
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
#include <openssl/sha.h> #include <openssl/sha.h>
@ -35,15 +38,15 @@ MetalPipelineCache::~MetalPipelineCache()
} }
} }
MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)
{ {
uint64 hash = CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr); uint64 hash = CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);
auto& pipeline = m_pipelineCache[hash]; auto& pipeline = m_pipelineCache[hash];
if (pipeline) if (pipeline)
return pipeline; return pipeline;
MetalPipelineCompiler compiler(m_mtlr); MetalPipelineCompiler compiler(m_mtlr);
compiler.InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr); compiler.InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);
pipeline = compiler.Compile(false, true); pipeline = compiler.Compile(false, true);
if (!HasPipelineCached(vertexShader->baseHash, hash)) if (!HasPipelineCached(vertexShader->baseHash, hash))
@ -52,33 +55,32 @@ MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const Latte
return pipeline; return pipeline;
} }
uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)
{ {
// Hash // Hash
uint64 stateHash = 0; uint64 stateHash = 0;
for (int i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; ++i) for (int i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; ++i)
{ {
auto textureView = static_cast<LatteTextureViewMtl*>(lastUsedFBO->colorBuffer[i].texture); Latte::E_GX2SURFFMT format = lastUsedAttachmentsInfo.colorFormats[i];
if (!textureView) if (format == Latte::E_GX2SURFFMT::INVALID_FORMAT)
continue; continue;
stateHash += textureView->GetRGBAView()->pixelFormat() + i * 31; stateHash += GetMtlPixelFormat(format, false) + i * 31;
stateHash = std::rotl<uint64>(stateHash, 7); stateHash = std::rotl<uint64>(stateHash, 7);
if (activeFBO->colorBuffer[i].texture) if (activeAttachmentsInfo.colorFormats[i] == Latte::E_GX2SURFFMT::INVALID_FORMAT)
{ {
stateHash += 1; stateHash += 1;
stateHash = std::rotl<uint64>(stateHash, 1); stateHash = std::rotl<uint64>(stateHash, 1);
} }
} }
if (lastUsedFBO->depthBuffer.texture) if (lastUsedAttachmentsInfo.depthFormat != Latte::E_GX2SURFFMT::INVALID_FORMAT)
{ {
auto textureView = static_cast<LatteTextureViewMtl*>(lastUsedFBO->depthBuffer.texture); stateHash += GetMtlPixelFormat(lastUsedAttachmentsInfo.depthFormat, true);
stateHash += textureView->GetRGBAView()->pixelFormat();
stateHash = std::rotl<uint64>(stateHash, 7); stateHash = std::rotl<uint64>(stateHash, 7);
if (activeFBO->depthBuffer.texture) if (activeAttachmentsInfo.depthFormat == Latte::E_GX2SURFFMT::INVALID_FORMAT)
{ {
stateHash += 1; stateHash += 1;
stateHash = std::rotl<uint64>(stateHash, 1); stateHash = std::rotl<uint64>(stateHash, 1);
@ -347,33 +349,28 @@ void MetalPipelineCache::LoadPipelineFromCache(std::span<uint8> fileData)
return; return;
} }
// create pipeline info MetalAttachmentsInfo attachmentsInfo(*lcr, pixelShader);
m_pipelineIsCachedLock.lock();
m_pipelineIsCachedLock.unlock();
throw;
// TODO: uncomment
/*
// compile // compile
{ {
MetalPipelineCompiler pp(m_mtlr); MetalPipelineCompiler pp(m_mtlr);
if (!pp.InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, activeFBO, activeFBO, *lcr)) pp.InitFromState(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, attachmentsInfo, attachmentsInfo, *lcr);
{ //{
s_spinlockSharedInternal.lock(); // s_spinlockSharedInternal.lock();
delete lcr; // delete lcr;
delete cachedPipeline; // delete cachedPipeline;
s_spinlockSharedInternal.unlock(); // s_spinlockSharedInternal.unlock();
return; // return;
} //}
pp.Compile(true, true); pp.Compile(true, true);
// destroy pp early // destroy pp early
} }
// on success, calculate pipeline hash and flag as present in cache // on success, calculate pipeline hash and flag as present in cache
uint64 pipelineBaseHash = vertexShader->baseHash; uint64 pipelineBaseHash = vertexShader->baseHash;
uint64 pipelineStateHash = CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, activeFBO, activeFBO, *lcr); uint64 pipelineStateHash = CalculatePipelineHash(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, attachmentsInfo, attachmentsInfo, *lcr);
m_pipelineIsCachedLock.lock(); m_pipelineIsCachedLock.lock();
m_pipelineIsCached.emplace(pipelineBaseHash, pipelineStateHash); m_pipelineIsCached.emplace(pipelineBaseHash, pipelineStateHash);
m_pipelineIsCachedLock.unlock(); m_pipelineIsCachedLock.unlock();
*/
// clean up // clean up
s_spinlockSharedInternal.lock(); s_spinlockSharedInternal.lock();

View File

@ -36,7 +36,7 @@ public:
MetalPipelineCache(class MetalRenderer* metalRenderer); MetalPipelineCache(class MetalRenderer* metalRenderer);
~MetalPipelineCache(); ~MetalPipelineCache();
MTL::RenderPipelineState* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); MTL::RenderPipelineState* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
// Cache loading // Cache loading
uint32 BeginLoading(uint64 cacheTitleId); // returns count of pipelines stored in cache uint32 BeginLoading(uint64 cacheTitleId); // returns count of pipelines stored in cache
@ -70,7 +70,7 @@ private:
ConcurrentQueue<std::vector<uint8>> m_compilationQueue; ConcurrentQueue<std::vector<uint8>> m_compilationQueue;
std::atomic_uint32_t m_compilationCount; std::atomic_uint32_t m_compilationCount;
static uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); static uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
int CompilerThread(); int CompilerThread();
void WorkerThread(); void WorkerThread();

View File

@ -10,6 +10,8 @@
#include "Cafe/HW/Latte/ISA/RegDefines.h" #include "Cafe/HW/Latte/ISA/RegDefines.h"
#include "Cafe/HW/Latte/Core/LatteConst.h" #include "Cafe/HW/Latte/Core/LatteConst.h"
#include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LatteShader.h"
#include "HW/Latte/ISA/LatteReg.h"
#include "Metal/MTLPixelFormat.hpp"
static void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister) static void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister)
{ {
@ -189,7 +191,7 @@ extern std::atomic_int g_compiled_shaders_total;
extern std::atomic_int g_compiled_shaders_async; extern std::atomic_int g_compiled_shaders_async;
template<typename T> template<typename T>
void SetFragmentState(T* desc, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFBO, const LatteDecompilerShader* pixelShader, const LatteContextRegister& lcr) void SetFragmentState(T* desc, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteDecompilerShader* pixelShader, const LatteContextRegister& lcr)
{ {
// Rasterization // Rasterization
bool rasterizationEnabled = !lcr.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL(); bool rasterizationEnabled = !lcr.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL();
@ -222,17 +224,16 @@ void SetFragmentState(T* desc, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFB
uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK(); uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();
for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++) for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)
{ {
const auto& colorBuffer = lastUsedFBO->colorBuffer[i]; Latte::E_GX2SURFFMT format = lastUsedAttachmentsInfo.colorFormats[i];
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture); if (format == Latte::E_GX2SURFFMT::INVALID_FORMAT)
if (!texture)
{
continue; continue;
}
MTL::PixelFormat pixelFormat = GetMtlPixelFormat(format, false);
auto colorAttachment = desc->colorAttachments()->object(i); auto colorAttachment = desc->colorAttachments()->object(i);
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat()); colorAttachment->setPixelFormat(pixelFormat);
// Disable writes if not in the active FBO // Disable writes if not in the active FBO
if (!activeFBO->colorBuffer[i].texture) if (activeAttachmentsInfo.colorFormats[i] == Latte::E_GX2SURFFMT::INVALID_FORMAT)
{ {
colorAttachment->setWriteMask(MTL::ColorWriteMaskNone); colorAttachment->setWriteMask(MTL::ColorWriteMaskNone);
continue; continue;
@ -243,7 +244,7 @@ void SetFragmentState(T* desc, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFB
// Blending // Blending
bool blendEnabled = ((blendEnableMask & (1 << i))) != 0; bool blendEnabled = ((blendEnableMask & (1 << i))) != 0;
// Only float data type is blendable // Only float data type is blendable
if (blendEnabled && GetMtlPixelFormatInfo(texture->format, false).dataType == MetalDataType::FLOAT) if (blendEnabled && GetMtlPixelFormatInfo(format, false).dataType == MetalDataType::FLOAT)
{ {
colorAttachment->setBlendingEnabled(true); colorAttachment->setBlendingEnabled(true);
@ -272,14 +273,12 @@ void SetFragmentState(T* desc, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFB
} }
// Depth stencil attachment // Depth stencil attachment
if (lastUsedFBO->depthBuffer.texture) if (lastUsedAttachmentsInfo.depthFormat != Latte::E_GX2SURFFMT::INVALID_FORMAT)
{ {
auto texture = static_cast<LatteTextureViewMtl*>(lastUsedFBO->depthBuffer.texture); MTL::PixelFormat pixelFormat = GetMtlPixelFormat(lastUsedAttachmentsInfo.depthFormat, true);
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat()); desc->setDepthAttachmentPixelFormat(pixelFormat);
if (lastUsedFBO->depthBuffer.hasStencil) if (lastUsedAttachmentsInfo.hasStencil)
{ desc->setStencilAttachmentPixelFormat(pixelFormat);
desc->setStencilAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
}
} }
} }
@ -306,7 +305,7 @@ MetalPipelineCompiler::~MetalPipelineCompiler()
m_pipelineDescriptor->release(); m_pipelineDescriptor->release();
} }
void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)
{ {
const LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); const LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]);
bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);
@ -314,9 +313,9 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c
m_usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect); m_usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect);
if (m_usesGeometryShader) if (m_usesGeometryShader)
InitFromStateMesh(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedFBO, activeFBO, lcr); InitFromStateMesh(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);
else else
InitFromStateRender(fetchShader, vertexShader, pixelShader, lastUsedFBO, activeFBO, lcr); InitFromStateRender(fetchShader, vertexShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);
} }
MTL::RenderPipelineState* MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread) MTL::RenderPipelineState* MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread)
@ -358,7 +357,7 @@ MTL::RenderPipelineState* MetalPipelineCompiler::Compile(bool forceCompile, bool
} }
} }
void MetalPipelineCompiler::InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) void MetalPipelineCompiler::InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)
{ {
// Shaders // Shaders
auto vertexShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader); auto vertexShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader);
@ -437,7 +436,7 @@ void MetalPipelineCompiler::InitFromStateRender(const LatteFetchShader* fetchSha
vertexDescriptor->release(); vertexDescriptor->release();
} }
SetFragmentState(desc, lastUsedFBO, activeFBO, pixelShader, lcr); SetFragmentState(desc, lastUsedAttachmentsInfo, activeAttachmentsInfo, pixelShader, lcr);
m_pipelineDescriptor = desc; m_pipelineDescriptor = desc;
@ -498,7 +497,7 @@ void MetalPipelineCompiler::InitFromStateRender(const LatteFetchShader* fetchSha
*/ */
} }
void MetalPipelineCompiler::InitFromStateMesh(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr) void MetalPipelineCompiler::InitFromStateMesh(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)
{ {
auto objectShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader); auto objectShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader);
RendererShaderMtl* meshShaderMtl; RendererShaderMtl* meshShaderMtl;
@ -517,7 +516,7 @@ void MetalPipelineCompiler::InitFromStateMesh(const LatteFetchShader* fetchShade
desc->setObjectFunction(objectShaderMtl->GetFunction()); desc->setObjectFunction(objectShaderMtl->GetFunction());
desc->setMeshFunction(meshShaderMtl->GetFunction()); desc->setMeshFunction(meshShaderMtl->GetFunction());
SetFragmentState(desc, lastUsedFBO, activeFBO, pixelShader, lcr); SetFragmentState(desc, lastUsedAttachmentsInfo, activeAttachmentsInfo, pixelShader, lcr);
m_pipelineDescriptor = desc; m_pipelineDescriptor = desc;

View File

@ -1,11 +1,9 @@
#pragma once #pragma once
#include <Metal/Metal.hpp> #include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
#include "Foundation/NSObject.hpp" #include "Cafe/HW/Latte/ISA/LatteReg.h"
#include "HW/Latte/ISA/LatteReg.h" #include "Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h"
#include "HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
class MetalPipelineCompiler class MetalPipelineCompiler
{ {
@ -13,7 +11,7 @@ public:
MetalPipelineCompiler(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} MetalPipelineCompiler(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}
~MetalPipelineCompiler(); ~MetalPipelineCompiler();
void InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); void InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
MTL::RenderPipelineState* Compile(bool forceCompile, bool isRenderThread); MTL::RenderPipelineState* Compile(bool forceCompile, bool isRenderThread);
@ -30,9 +28,9 @@ private:
*/ */
NS::Object* m_pipelineDescriptor; NS::Object* m_pipelineDescriptor;
void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
void InitFromStateMesh(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* lastUsedFBO, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr); void InitFromStateMesh(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);
//void TryLoadBinaryArchive(); //void TryLoadBinaryArchive();
}; };

View File

@ -23,6 +23,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalCommon.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
#include "config/CemuConfig.h" #include "config/CemuConfig.h"
#define IMGUI_IMPL_METAL_CPP #define IMGUI_IMPL_METAL_CPP
@ -511,13 +512,13 @@ LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key)
void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo) void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)
{ {
if (cfbo == (LatteCachedFBO*)m_state.m_activeFBO) if (cfbo == (LatteCachedFBO*)m_state.m_activeFBO.m_fbo)
m_state.m_activeFBO = nullptr; m_state.m_activeFBO = {nullptr};
} }
void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo)
{ {
m_state.m_activeFBO = (CachedFBOMtl*)cfbo; m_state.m_activeFBO = {(CachedFBOMtl*)cfbo, MetalAttachmentsInfo((CachedFBOMtl*)cfbo)};
} }
void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size)
@ -1008,7 +1009,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
// Disable depth write when there is no depth attachment // Disable depth write when there is no depth attachment
auto& depthControl = LatteGPUState.contextNew.DB_DEPTH_CONTROL; auto& depthControl = LatteGPUState.contextNew.DB_DEPTH_CONTROL;
bool depthWriteEnable = depthControl.get_Z_WRITE_ENABLE(); bool depthWriteEnable = depthControl.get_Z_WRITE_ENABLE();
if (!m_state.m_activeFBO->depthBuffer.texture) if (!m_state.m_activeFBO.m_fbo->depthBuffer.texture)
depthControl.set_Z_WRITE_ENABLE(false); depthControl.set_Z_WRITE_ENABLE(false);
MTL::DepthStencilState* depthStencilState = m_depthStencilCache->GetDepthStencilState(LatteGPUState.contextNew); MTL::DepthStencilState* depthStencilState = m_depthStencilCache->GetDepthStencilState(LatteGPUState.contextNew);
@ -1222,7 +1223,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
//} //}
// Render pipeline state // Render pipeline state
MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetRenderPipelineState(fetchShader, vertexShader, geometryShader, pixelShader, m_state.m_lastUsedFBO, m_state.m_activeFBO, LatteGPUState.contextNew); MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetRenderPipelineState(fetchShader, vertexShader, geometryShader, pixelShader, m_state.m_lastUsedFBO.m_attachmentsInfo, m_state.m_activeFBO.m_attachmentsInfo, LatteGPUState.contextNew);
if (!renderPipelineState) if (!renderPipelineState)
return; return;
@ -1524,12 +1525,12 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr
{ {
if (m_encoderType == MetalEncoderType::Render) if (m_encoderType == MetalEncoderType::Render)
{ {
bool needsNewRenderPass = (m_state.m_lastUsedFBO == nullptr); bool needsNewRenderPass = (m_state.m_lastUsedFBO.m_fbo == nullptr);
if (!needsNewRenderPass) if (!needsNewRenderPass)
{ {
for (uint8 i = 0; i < 8; i++) for (uint8 i = 0; i < 8; i++)
{ {
if (m_state.m_activeFBO->colorBuffer[i].texture && m_state.m_activeFBO->colorBuffer[i].texture != m_state.m_lastUsedFBO->colorBuffer[i].texture) if (m_state.m_activeFBO.m_fbo->colorBuffer[i].texture && m_state.m_activeFBO.m_fbo->colorBuffer[i].texture != m_state.m_lastUsedFBO.m_fbo->colorBuffer[i].texture)
{ {
needsNewRenderPass = true; needsNewRenderPass = true;
break; break;
@ -1539,7 +1540,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr
if (!needsNewRenderPass) if (!needsNewRenderPass)
{ {
if (m_state.m_activeFBO->depthBuffer.texture && (m_state.m_activeFBO->depthBuffer.texture != m_state.m_lastUsedFBO->depthBuffer.texture || ( m_state.m_activeFBO->depthBuffer.hasStencil && !m_state.m_lastUsedFBO->depthBuffer.hasStencil))) if (m_state.m_activeFBO.m_fbo->depthBuffer.texture && (m_state.m_activeFBO.m_fbo->depthBuffer.texture != m_state.m_lastUsedFBO.m_fbo->depthBuffer.texture || ( m_state.m_activeFBO.m_fbo->depthBuffer.hasStencil && !m_state.m_lastUsedFBO.m_fbo->depthBuffer.hasStencil)))
{ {
needsNewRenderPass = true; needsNewRenderPass = true;
} }
@ -1557,7 +1558,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr
auto commandBuffer = GetCommandBuffer(); auto commandBuffer = GetCommandBuffer();
auto renderCommandEncoder = commandBuffer->renderCommandEncoder(m_state.m_activeFBO->GetRenderPassDescriptor()); auto renderCommandEncoder = commandBuffer->renderCommandEncoder(m_state.m_activeFBO.m_fbo->GetRenderPassDescriptor());
#ifdef CEMU_DEBUG_ASSERT #ifdef CEMU_DEBUG_ASSERT
renderCommandEncoder->setLabel(GetLabel("Render command encoder", renderCommandEncoder)); renderCommandEncoder->setLabel(GetLabel("Render command encoder", renderCommandEncoder));
#endif #endif
@ -1716,7 +1717,7 @@ bool MetalRenderer::CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader)
// If the texture is also used in the current render pass, we need to end the render pass to "flush" the texture // If the texture is also used in the current render pass, we need to end the render pass to "flush" the texture
for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++) for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)
{ {
auto colorTarget = m_state.m_activeFBO->colorBuffer[i].texture; auto colorTarget = m_state.m_activeFBO.m_fbo->colorBuffer[i].texture;
if (colorTarget && colorTarget->baseTexture == baseTexture) if (colorTarget && colorTarget->baseTexture == baseTexture)
return true; return true;
} }

View File

@ -5,6 +5,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h"
struct MetalBufferAllocation struct MetalBufferAllocation
{ {
@ -121,6 +122,12 @@ struct MetalStreamoutState
sint32 verticesPerInstance; sint32 verticesPerInstance;
}; };
struct MetalActiveFBOState
{
class CachedFBOMtl* m_fbo = nullptr;
MetalAttachmentsInfo m_attachmentsInfo;
};
struct MetalState struct MetalState
{ {
MetalEncoderState m_encoderState{}; MetalEncoderState m_encoderState{};
@ -130,9 +137,9 @@ struct MetalState
bool m_skipDrawSequence = false; bool m_skipDrawSequence = false;
bool m_isFirstDrawInRenderPass = true; bool m_isFirstDrawInRenderPass = true;
class CachedFBOMtl* m_activeFBO = nullptr; MetalActiveFBOState m_activeFBO;
// If the FBO changes, but it's the same FBO as the last one with some omitted attachments, this FBO doesn't change' // If the FBO changes, but it's the same FBO as the last one with some omitted attachments, this FBO doesn't change
class CachedFBOMtl* m_lastUsedFBO = nullptr; MetalActiveFBOState m_lastUsedFBO;
MetalBoundBuffer m_vertexBuffers[MAX_MTL_BUFFERS] = {{}}; MetalBoundBuffer m_vertexBuffers[MAX_MTL_BUFFERS] = {{}};
// TODO: find out what is the max number of bound textures on the Wii U // TODO: find out what is the max number of bound textures on the Wii U