draw with geometry shaders

This commit is contained in:
Samuliak 2024-08-20 20:14:02 +02:00
parent 2f4ceb33e0
commit 97f441ecf1
7 changed files with 332 additions and 304 deletions

View file

@ -9,6 +9,8 @@
#include "HW/Latte/Core/FetchShader.h"
#include "HW/Latte/ISA/RegDefines.h"
#include "Metal/MTLDevice.hpp"
#include "Metal/MTLRenderPipeline.hpp"
#include "config/ActiveSettings.h"
#define INVALID_TITLE_ID 0xFFFFFFFFFFFFFFFF
@ -18,6 +20,68 @@ uint64 s_cacheTitleId = INVALID_TITLE_ID;
extern std::atomic_int g_compiled_shaders_total;
extern std::atomic_int g_compiled_shaders_async;
template<typename T>
void SetFragmentState(T* desc, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{
// Color attachments
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;
uint32 blendEnableMask = colorControlReg.get_BLEND_MASK();
uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();
for (uint8 i = 0; i < 8; i++)
{
const auto& colorBuffer = activeFBO->colorBuffer[i];
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);
if (!texture)
{
continue;
}
auto colorAttachment = desc->colorAttachments()->object(i);
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
colorAttachment->setWriteMask(GetMtlColorWriteMask((renderTargetMask >> (i * 4)) & 0xF));
// Blending
bool blendEnabled = ((blendEnableMask & (1 << i))) != 0;
// Only float data type is blendable
if (blendEnabled && GetMtlPixelFormatInfo(texture->format, false).dataType == MetalDataType::FLOAT)
{
colorAttachment->setBlendingEnabled(true);
const auto& blendControlReg = lcr.CB_BLENDN_CONTROL[i];
auto rgbBlendOp = GetMtlBlendOp(blendControlReg.get_COLOR_COMB_FCN());
auto srcRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_SRCBLEND());
auto dstRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_DSTBLEND());
colorAttachment->setRgbBlendOperation(rgbBlendOp);
colorAttachment->setSourceRGBBlendFactor(srcRgbBlendFactor);
colorAttachment->setDestinationRGBBlendFactor(dstRgbBlendFactor);
if (blendControlReg.get_SEPARATE_ALPHA_BLEND())
{
colorAttachment->setAlphaBlendOperation(GetMtlBlendOp(blendControlReg.get_ALPHA_COMB_FCN()));
colorAttachment->setSourceAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()));
colorAttachment->setDestinationAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));
}
else
{
colorAttachment->setAlphaBlendOperation(rgbBlendOp);
colorAttachment->setSourceAlphaBlendFactor(srcRgbBlendFactor);
colorAttachment->setDestinationAlphaBlendFactor(dstRgbBlendFactor);
}
}
}
// Depth stencil attachment
if (activeFBO->depthBuffer.texture)
{
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
if (activeFBO->depthBuffer.hasStencil)
{
desc->setStencilAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
}
}
}
void MetalPipelineCache::ShaderCacheLoading_begin(uint64 cacheTitleId)
{
s_cacheTitleId = cacheTitleId;
@ -53,9 +117,9 @@ MetalPipelineCache::~MetalPipelineCache()
m_binaryArchiveURL->release();
}
MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
MTL::RenderPipelineState* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{
uint64 stateHash = CalculatePipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
uint64 stateHash = CalculateRenderPipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
auto& pipeline = m_pipelineCache[stateHash];
if (pipeline)
return pipeline;
@ -127,65 +191,18 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
// TODO: don't always set the vertex descriptor?
desc->setVertexDescriptor(vertexDescriptor);
// Color attachments
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;
uint32 blendEnableMask = colorControlReg.get_BLEND_MASK();
uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();
for (uint8 i = 0; i < 8; i++)
{
const auto& colorBuffer = activeFBO->colorBuffer[i];
auto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);
if (!texture)
{
continue;
}
auto colorAttachment = desc->colorAttachments()->object(i);
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
colorAttachment->setWriteMask(GetMtlColorWriteMask((renderTargetMask >> (i * 4)) & 0xF));
SetFragmentState(desc, activeFBO, lcr);
// Blending
bool blendEnabled = ((blendEnableMask & (1 << i))) != 0;
// Only float data type is blendable
if (blendEnabled && GetMtlPixelFormatInfo(texture->format, false).dataType == MetalDataType::FLOAT)
{
colorAttachment->setBlendingEnabled(true);
TryLoadBinaryArchive();
const auto& blendControlReg = lcr.CB_BLENDN_CONTROL[i];
auto rgbBlendOp = GetMtlBlendOp(blendControlReg.get_COLOR_COMB_FCN());
auto srcRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_SRCBLEND());
auto dstRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_DSTBLEND());
colorAttachment->setRgbBlendOperation(rgbBlendOp);
colorAttachment->setSourceRGBBlendFactor(srcRgbBlendFactor);
colorAttachment->setDestinationRGBBlendFactor(dstRgbBlendFactor);
if (blendControlReg.get_SEPARATE_ALPHA_BLEND())
{
colorAttachment->setAlphaBlendOperation(GetMtlBlendOp(blendControlReg.get_ALPHA_COMB_FCN()));
colorAttachment->setSourceAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()));
colorAttachment->setDestinationAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));
}
else
{
colorAttachment->setAlphaBlendOperation(rgbBlendOp);
colorAttachment->setSourceAlphaBlendFactor(srcRgbBlendFactor);
colorAttachment->setDestinationAlphaBlendFactor(dstRgbBlendFactor);
}
}
}
// Depth stencil attachment
if (activeFBO->depthBuffer.texture)
{
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
if (activeFBO->depthBuffer.hasStencil)
{
desc->setStencilAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
}
}
LoadBinary(desc);
// Load binary
if (m_binaryArchive)
{
NS::Object* binArchives[] = {m_binaryArchive};
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
desc->setBinaryArchives(binaryArchives);
binaryArchives->release();
}
NS::Error* error = nullptr;
#ifdef CEMU_DEBUG_ASSERT
@ -211,10 +228,21 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
{
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
error->release();
return nullptr;
}
else
{
SaveBinary(desc);
// Save binary
if (m_binaryArchive)
{
NS::Error* error = nullptr;
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
if (error)
{
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
error->release();
}
}
}
//newPipelineCount++;
@ -230,7 +258,57 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
return pipeline;
}
uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
MTL::RenderPipelineState* MetalPipelineCache::GetMeshPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, CachedFBOMtl* activeFBO, const LatteContextRegister& lcr, Renderer::INDEX_TYPE hostIndexType)
{
uint64 stateHash = CalculateRenderPipelineHash(fetchShader, vertexShader, pixelShader, activeFBO, lcr);
stateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];
stateHash = std::rotl<uint64>(stateHash, 7);
stateHash += (uint8)hostIndexType;
stateHash = std::rotl<uint64>(stateHash, 7); // TODO: 7?s
auto& pipeline = m_pipelineCache[stateHash];
if (pipeline)
return pipeline;
auto mtlObjectShader = static_cast<RendererShaderMtl*>(vertexShader->shader);
auto mtlMeshShader = static_cast<RendererShaderMtl*>(geometryShader->shader);
auto mtlPixelShader = static_cast<RendererShaderMtl*>(pixelShader->shader);
mtlObjectShader->CompileObjectFunction(lcr, fetchShader, vertexShader, hostIndexType);
mtlMeshShader->CompileMeshFunction(lcr, fetchShader);
mtlPixelShader->CompileFragmentFunction(activeFBO);
// Render pipeline state
MTL::MeshRenderPipelineDescriptor* desc = MTL::MeshRenderPipelineDescriptor::alloc()->init();
desc->setObjectFunction(mtlObjectShader->GetFunction());
desc->setMeshFunction(mtlMeshShader->GetFunction());
desc->setFragmentFunction(mtlPixelShader->GetFunction());
SetFragmentState(desc, activeFBO, lcr);
TryLoadBinaryArchive();
// Load binary
// TODO: no binary archives? :(
NS::Error* error = nullptr;
#ifdef CEMU_DEBUG_ASSERT
desc->setLabel(GetLabel("Mesh pipeline state", desc));
#endif
pipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionNone, nullptr, &error);
if (error)
{
debug_printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String());
error->release();
return nullptr;
}
desc->release();
return pipeline;
}
uint64 MetalPipelineCache::CalculateRenderPipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* pixelShader, class CachedFBOMtl* activeFBO, const LatteContextRegister& lcr)
{
// Hash
uint64 stateHash = 0;
@ -261,9 +339,6 @@ uint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchSh
stateHash += fetchShader->getVkPipelineHashFragment();
stateHash = std::rotl<uint64>(stateHash, 7);
stateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];
stateHash = std::rotl<uint64>(stateHash, 7);
stateHash += lcr.GetRawView()[mmVGT_STRMOUT_EN];
stateHash = std::rotl<uint64>(stateHash, 7);
@ -340,30 +415,3 @@ void MetalPipelineCache::TryLoadBinaryArchive()
}
desc->release();
}
void MetalPipelineCache::LoadBinary(MTL::RenderPipelineDescriptor* desc)
{
TryLoadBinaryArchive();
if (!m_binaryArchive)
return;
NS::Object* binArchives[] = {m_binaryArchive};
auto binaryArchives = NS::Array::alloc()->init(binArchives, 1);
desc->setBinaryArchives(binaryArchives);
binaryArchives->release();
}
void MetalPipelineCache::SaveBinary(MTL::RenderPipelineDescriptor* desc)
{
if (!m_binaryArchive)
return;
NS::Error* error = nullptr;
m_binaryArchive->addRenderPipelineFunctions(desc, &error);
if (error)
{
debug_printf("error saving render pipeline functions: %s\n", error->localizedDescription()->utf8String());
error->release();
}
}