diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 8dd401b7..c7360458 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -558,6 +558,8 @@ if(ENABLE_METAL) HW/Latte/Renderer/Metal/MetalBufferAllocator.h HW/Latte/Renderer/Metal/MetalMemoryManager.cpp HW/Latte/Renderer/Metal/MetalMemoryManager.h + HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp + HW/Latte/Renderer/Metal/MetalOutputShaderCache.h HW/Latte/Renderer/Metal/MetalPipelineCache.cpp HW/Latte/Renderer/Metal/MetalPipelineCache.h HW/Latte/Renderer/Metal/MetalDepthStencilCache.cpp diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp new file mode 100644 index 00000000..8a69a442 --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp @@ -0,0 +1,38 @@ +#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" +#include "Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h" + +MetalOutputShaderCache::~MetalOutputShaderCache() +{ + for (uint8 i = 0; i < METAL_OUTPUT_SHADER_CACHE_SIZE; i++) + { + if (m_cache[i]) + m_cache[i]->release(); + } +} + +MTL::RenderPipelineState* MetalOutputShaderCache::GetPipeline(RendererOutputShader* shader, uint8 shaderIndex, bool usesSRGB) +{ + uint8 cacheIndex = (usesSRGB ? METAL_SHADER_TYPE_COUNT : 0) + shaderIndex; + auto& renderPipelineState = m_cache[cacheIndex]; + if (renderPipelineState) + return renderPipelineState; + + // Create a new render pipeline state + auto vertexShaderMtl = static_cast(shader->GetVertexShader())->GetFunction(); + auto fragmentShaderMtl = static_cast(shader->GetFragmentShader())->GetFunction(); + + auto renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); + renderPipelineDescriptor->setVertexFunction(vertexShaderMtl); + renderPipelineDescriptor->setFragmentFunction(fragmentShaderMtl); + renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(usesSRGB ? MTL::PixelFormatBGRA8Unorm_sRGB : MTL::PixelFormatBGRA8Unorm); + + NS::Error* error = nullptr; + renderPipelineState = m_mtlr->GetDevice()->newRenderPipelineState(renderPipelineDescriptor, &error); + if (error) + { + cemuLog_log(LogType::Force, "error creating output render pipeline state: {}", error->localizedDescription()->utf8String()); + error->release(); + } + + return renderPipelineState; +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h new file mode 100644 index 00000000..85b9e8b2 --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" + +constexpr uint8 METAL_SHADER_TYPE_COUNT = 6; +constexpr uint8 METAL_OUTPUT_SHADER_CACHE_SIZE = 2 * METAL_SHADER_TYPE_COUNT; + +class MetalOutputShaderCache +{ +public: + MetalOutputShaderCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} + ~MetalOutputShaderCache(); + + MTL::RenderPipelineState* GetPipeline(RendererOutputShader* shader, uint8 shaderIndex, bool usesSRGB); + +private: + class MetalRenderer* m_mtlr; + + MTL::RenderPipelineState* m_cache[METAL_OUTPUT_SHADER_CACHE_SIZE] = {nullptr}; +}; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 9e0b4641..11724544 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -4,6 +4,7 @@ #include "Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h" #include "Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h" #include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h" +#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h" @@ -81,6 +82,7 @@ MetalRenderer::MetalRenderer() textureDescriptor->release(); m_memoryManager = new MetalMemoryManager(this); + m_outputShaderCache = new MetalOutputShaderCache(this); m_pipelineCache = new MetalPipelineCache(this); m_depthStencilCache = new MetalDepthStencilCache(this); m_samplerCache = new MetalSamplerCache(this); @@ -174,6 +176,7 @@ MetalRenderer::~MetalRenderer() m_presentPipelineLinear->release(); m_presentPipelineSRGB->release(); + delete m_outputShaderCache; delete m_pipelineCache; delete m_depthStencilCache; delete m_samplerCache; @@ -276,7 +279,6 @@ void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC) m_performanceMonitor.ResetPerFrameData(); } -// TODO: use `shader` for drawing void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground) @@ -299,21 +301,20 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput renderPassDescriptor->release(); // Get a render pipeline - auto vertexShaderMtl = static_cast(shader->GetVertexShader())->GetFunction(); - auto fragmentShaderMtl = static_cast(shader->GetFragmentShader())->GetFunction(); - auto renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init(); - renderPipelineDescriptor->setVertexFunction(vertexShaderMtl); - renderPipelineDescriptor->setFragmentFunction(fragmentShaderMtl); - renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(m_state.m_usesSRGB ? MTL::PixelFormatBGRA8Unorm_sRGB : MTL::PixelFormatBGRA8Unorm); + // Find out which shader we are using + uint8 shaderIndex = 255; + if (shader == RendererOutputShader::s_copy_shader) shaderIndex = 0; + else if (shader == RendererOutputShader::s_bicubic_shader) shaderIndex = 1; + else if (shader == RendererOutputShader::s_hermit_shader) shaderIndex = 2; + else if (shader == RendererOutputShader::s_copy_shader_ud) shaderIndex = 3; + else if (shader == RendererOutputShader::s_bicubic_shader_ud) shaderIndex = 4; + else if (shader == RendererOutputShader::s_hermit_shader_ud) shaderIndex = 5; - NS::Error* error = nullptr; - auto renderPipelineState = m_device->newRenderPipelineState(renderPipelineDescriptor, &error); - if (error) - { - printf("AAA: %s\n", error->localizedDescription()->utf8String()); - error->release(); - } + uint8 shaderType = shaderIndex % 3; + + // Get the render pipeline state + auto renderPipelineState = m_outputShaderCache->GetPipeline(shader, shaderIndex, m_state.m_usesSRGB); // Draw to Metal layer renderCommandEncoder->setRenderPipelineState(renderPipelineState); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 8eb0e319..04956ac7 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -4,6 +4,7 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h" +#include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" struct MetalBufferAllocation { @@ -460,6 +461,7 @@ private: // Managers and caches class MetalMemoryManager* m_memoryManager; + class MetalOutputShaderCache* m_outputShaderCache; class MetalPipelineCache* m_pipelineCache; class MetalDepthStencilCache* m_depthStencilCache; class MetalSamplerCache* m_samplerCache;