From f01130022a0fb32517cfae531fac8e28208ff2f6 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Mon, 29 Jul 2024 19:00:13 +0200 Subject: [PATCH] rework command encoder system --- .../LatteDecompilerEmitMSLHeader.hpp | 4 +- .../Latte/Renderer/Metal/LatteTextureMtl.cpp | 4 +- .../HW/Latte/Renderer/Metal/LatteTextureMtl.h | 13 +-- .../Renderer/Metal/LatteTextureViewMtl.cpp | 2 +- .../HW/Latte/Renderer/Metal/LatteToMtl.cpp | 42 ++++--- src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h | 6 +- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 47 ++++---- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 108 ++++++++++++++---- 8 files changed, 149 insertions(+), 77 deletions(-) diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp index 3bc8796e..38b15384 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp @@ -134,7 +134,7 @@ namespace LatteDecompiler //shaderSrc->addFmt("UNIFORM_BUFFER_LAYOUT({}, {}, {}) ", (sint32)decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i], (sint32)decompilerContext->output->resourceMappingVK.setIndex, (sint32)decompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i]); - shaderSrc->addFmt("struct UBuff{} {" _CRLF, i); + shaderSrc->addFmt("struct UBuff{} {{" _CRLF, i); shaderSrc->addFmt("float4 d{}[{}];" _CRLF, i, decompilerContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(decompilerContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE)); shaderSrc->add("};" _CRLF _CRLF); } @@ -307,7 +307,7 @@ namespace LatteDecompiler cemu_assert_debug(decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i] >= 0); cemu_assert_debug(decompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i] >= 0); - src->addFmt("constant UBuff{}& ubuff{} [[buffer({})]]" _CRLF, i, i, (sint32)decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i]); + src->addFmt(", constant UBuff{}& ubuff{} [[buffer({})]]", i, i, (sint32)decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i]); } } } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp index bbd714d9..9a8a3927 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp @@ -5,7 +5,7 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) - : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer), m_format(format) + : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer), m_format(format), m_isDepth(isDepth) { MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init(); desc->setStorageMode(MTL::StorageModeShared); // TODO: use private? @@ -34,7 +34,7 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM desc->setArrayLength(effectiveBaseDepth); } - auto formatInfo = GetMtlPixelFormatInfo(format); + auto formatInfo = GetMtlPixelFormatInfo(format, isDepth); desc->setPixelFormat(formatInfo.pixelFormat); // TODO: is write needed? diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h index cc08d469..e2187e1b 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h @@ -21,23 +21,20 @@ public: return m_format; } + bool IsDepth() const { + return m_isDepth; + } + void AllocateOnHost() override; protected: LatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override; -public: - uint64 m_vkFlushIndex{}; // used to track read-write dependencies within the same renderpass - - uint64 m_vkFlushIndex_read{}; - uint64 m_vkFlushIndex_write{}; - - uint32 m_collisionCheckIndex{}; // used to track if texture is being both sampled and output to during drawcall - private: class MetalRenderer* m_mtlr; MTL::Texture* m_texture; Latte::E_GX2SURFFMT m_format; + bool m_isDepth; }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp index 37399fca..34dd6f9f 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp @@ -52,7 +52,7 @@ LatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextur // TODO: swizzle - auto formatInfo = GetMtlPixelFormatInfo(format); + auto formatInfo = GetMtlPixelFormatInfo(format, texture->IsDepth()); m_texture = texture->GetTexture()->newTextureView(formatInfo.pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount)); } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp index 7c7b4187..22b8a069 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp @@ -3,8 +3,7 @@ #include "Metal/MTLPixelFormat.hpp" #include "Metal/MTLVertexDescriptor.hpp" -// TODO: separate color and depth formats -std::map MTL_FORMAT_TABLE = { +std::map MTL_COLOR_FORMAT_TABLE = { {Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatRG8Unorm, 2}}, // TODO: correct? {Latte::E_GX2SURFFMT::R5_G6_B5_UNORM, {MTL::PixelFormatB5G6R5Unorm, 2}}, // TODO: correct? {Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM, {MTL::PixelFormatBGR5A1Unorm, 2}}, // TODO: correct? @@ -60,11 +59,6 @@ std::map MTL_FORMAT_TABLE = { {Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT, {MTL::PixelFormatRGBA32Uint, 16}}, {Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT, {MTL::PixelFormatRGBA32Sint, 16}}, {Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT, {MTL::PixelFormatRGBA32Float, 16}}, - {Latte::E_GX2SURFFMT::D24_S8_UNORM, {MTL::PixelFormatDepth24Unorm_Stencil8, 4}}, // TODO: not supported on Apple sillicon, maybe find something else - {Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 4}}, // TODO: correct? - {Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 5}}, - {Latte::E_GX2SURFFMT::D16_UNORM, {MTL::PixelFormatDepth16Unorm, 2}}, - {Latte::E_GX2SURFFMT::D32_FLOAT, {MTL::PixelFormatDepth32Float, 4}}, {Latte::E_GX2SURFFMT::BC1_UNORM, {MTL::PixelFormatBC1_RGBA, 8, {4, 4}}}, // TODO: correct? {Latte::E_GX2SURFFMT::BC1_SRGB, {MTL::PixelFormatBC1_RGBA_sRGB, 8, {4, 4}}}, // TODO: correct? {Latte::E_GX2SURFFMT::BC2_UNORM, {MTL::PixelFormatBC2_RGBA, 16, {4, 4}}}, // TODO: correct? @@ -77,11 +71,29 @@ std::map MTL_FORMAT_TABLE = { {Latte::E_GX2SURFFMT::BC5_SNORM, {MTL::PixelFormatBC5_RGSnorm, 16, {4, 4}}}, // TODO: correct? }; -const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format) -{ - cemu_assert_debug(static_cast(format) < MTL_FORMAT_TABLE.size()); +std::map MTL_DEPTH_FORMAT_TABLE = { + {Latte::E_GX2SURFFMT::D24_S8_UNORM, {MTL::PixelFormatDepth24Unorm_Stencil8, 4}}, // TODO: not supported on Apple sillicon, maybe find something else + {Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 4}}, // TODO: correct? + {Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 5}}, + {Latte::E_GX2SURFFMT::D16_UNORM, {MTL::PixelFormatDepth16Unorm, 2}}, + {Latte::E_GX2SURFFMT::D32_FLOAT, {MTL::PixelFormatDepth32Float, 4}}, +}; + +const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, bool isDepth) +{ + MtlPixelFormatInfo formatInfo; + if (isDepth) + formatInfo = MTL_DEPTH_FORMAT_TABLE[format]; + else + formatInfo = MTL_COLOR_FORMAT_TABLE[format]; + + // Depth24Unorm_Stencil8 is not supported on Apple sillicon + // TODO: query if format is available instead + if (formatInfo.pixelFormat == MTL::PixelFormatDepth24Unorm_Stencil8) + { + formatInfo.pixelFormat = MTL::PixelFormatDepth32Float_Stencil8; + } - MtlPixelFormatInfo formatInfo = MTL_FORMAT_TABLE[format]; if (formatInfo.pixelFormat == MTL::PixelFormatInvalid) { printf("invalid pixel format: %u\n", (uint32)format); @@ -94,16 +106,16 @@ inline uint32 CeilDivide(uint32 a, uint32 b) { return (a + b - 1) / b; } -size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, uint32 width) +size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, bool isDepth, uint32 width) { - const auto& formatInfo = GetMtlPixelFormatInfo(format); + const auto& formatInfo = GetMtlPixelFormatInfo(format, isDepth); return CeilDivide(width, formatInfo.blockTexelSize.x) * formatInfo.bytesPerBlock; } -size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, uint32 height, size_t bytesPerRow) +size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, bool isDepth, uint32 height, size_t bytesPerRow) { - const auto& formatInfo = GetMtlPixelFormatInfo(format); + const auto& formatInfo = GetMtlPixelFormatInfo(format, isDepth); return CeilDivide(height, formatInfo.blockTexelSize.y) * bytesPerRow; } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h index a0c1b939..e9eb0b91 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h @@ -18,11 +18,11 @@ struct MtlPixelFormatInfo { Uvec2 blockTexelSize = {1, 1}; }; -const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format); +const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, bool isDepth); -size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, uint32 width); +size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, bool isDepth, uint32 width); -size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, uint32 height, size_t bytesPerRow); +size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, bool isDepth, uint32 height, size_t bytesPerRow); MTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode mode); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index cb363d61..af022a0f 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -12,6 +12,7 @@ #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LatteIndices.h" #include "Foundation/NSTypes.hpp" +#include "Metal/MTLRenderCommandEncoder.hpp" #include "gui/guiWrapper.h" extern bool hasValidFramebufferAttached; @@ -147,14 +148,14 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput MTL::Texture* colorRenderTargets[8] = {nullptr}; colorRenderTargets[0] = m_drawable->texture(); - BeginRenderPassIfNeeded(renderPassDescriptor, colorRenderTargets, nullptr); + auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, nullptr); // Draw to Metal layer - m_renderCommandEncoder->setRenderPipelineState(m_presentPipeline); - m_renderCommandEncoder->setFragmentTexture(presentTexture, 0); - m_renderCommandEncoder->setFragmentSamplerState(m_nearestSampler, 0); + renderCommandEncoder->setRenderPipelineState(m_presentPipeline); + renderCommandEncoder->setFragmentTexture(presentTexture, 0); + renderCommandEncoder->setFragmentSamplerState(m_nearestSampler, 0); - m_renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3)); + renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3)); } bool MetalRenderer::BeginFrame(bool mainWindow) @@ -351,8 +352,8 @@ void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, s { auto mtlTexture = (LatteTextureMtl*)hostTexture; - size_t bytesPerRow = GetMtlTextureBytesPerRow(mtlTexture->GetFormat(), width); - size_t bytesPerImage = GetMtlTextureBytesPerImage(mtlTexture->GetFormat(), height, bytesPerRow); + size_t bytesPerRow = GetMtlTextureBytesPerRow(mtlTexture->GetFormat(), mtlTexture->IsDepth(), width); + size_t bytesPerImage = GetMtlTextureBytesPerImage(mtlTexture->GetFormat(), mtlTexture->IsDepth(), height, bytesPerRow); mtlTexture->GetTexture()->replaceRegion(MTL::Region(0, 0, width, height), mipIndex, sliceIndex, pixelData, bytesPerRow, bytesPerImage); } @@ -535,7 +536,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 { depthRenderTarget = depthTexture->GetTexture(); } - BeginRenderPassIfNeeded(renderPassDescriptor, colorRenderTargets, depthRenderTarget); + auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, depthRenderTarget); // Shaders LatteSHRC_UpdateActiveShaders(); @@ -622,7 +623,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 printf("error creating render pipeline state: %s\n", error->localizedDescription()->utf8String()); return; } - m_renderCommandEncoder->setRenderPipelineState(renderPipelineState); + renderCommandEncoder->setRenderPipelineState(renderPipelineState); // Primitive type const LattePrimitiveMode primitiveMode = static_cast(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); @@ -648,25 +649,25 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 auto& vertexBufferRange = m_state.vertexBuffers[i]; if (vertexBufferRange.needsRebind) { - m_renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), vertexBufferRange.offset, GET_MTL_VERTEX_BUFFER_INDEX(i)); + renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), vertexBufferRange.offset, GET_MTL_VERTEX_BUFFER_INDEX(i)); // TODO: uncomment //vertexBufferRange.needsRebind = false; } } // Uniform buffers, textures and samplers - BindStageResources(vertexShader); - BindStageResources(pixelShader); + BindStageResources(renderCommandEncoder, vertexShader); + BindStageResources(renderCommandEncoder, pixelShader); // Draw if (hostIndexType != INDEX_TYPE::NONE) { auto mtlIndexType = GetMtlIndexType(hostIndexType); MTL::Buffer* indexBuffer = m_memoryManager->GetBuffer(indexBufferIndex); - m_renderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, hostIndexCount, mtlIndexType, indexBuffer, 0, instanceCount, baseVertex, baseInstance); + renderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, hostIndexCount, mtlIndexType, indexBuffer, 0, instanceCount, baseVertex, baseInstance); } else { - m_renderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, count, instanceCount, baseInstance); + renderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, count, instanceCount, baseInstance); } } @@ -689,7 +690,7 @@ void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size) printf("MetalRenderer::indexData_uploadIndexMemory not implemented\n"); } -void MetalRenderer::BindStageResources(LatteDecompilerShader* shader) +void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader) { sint32 textureCount = shader->resourceMapping.getTextureCount(); @@ -722,12 +723,12 @@ void MetalRenderer::BindStageResources(LatteDecompilerShader* shader) { case LatteConst::ShaderType::Vertex: { - m_renderCommandEncoder->setVertexSamplerState(sampler, binding); + renderCommandEncoder->setVertexSamplerState(sampler, binding); break; } case LatteConst::ShaderType::Pixel: { - m_renderCommandEncoder->setFragmentSamplerState(sampler, binding); + renderCommandEncoder->setFragmentSamplerState(sampler, binding); break; } default: @@ -739,12 +740,12 @@ void MetalRenderer::BindStageResources(LatteDecompilerShader* shader) { case LatteConst::ShaderType::Vertex: { - m_renderCommandEncoder->setVertexTexture(textureView->GetTexture(), binding); + renderCommandEncoder->setVertexTexture(textureView->GetTexture(), binding); break; } case LatteConst::ShaderType::Pixel: { - m_renderCommandEncoder->setFragmentTexture(textureView->GetTexture(), binding); + renderCommandEncoder->setFragmentTexture(textureView->GetTexture(), binding); break; } default: @@ -840,12 +841,12 @@ void MetalRenderer::BindStageResources(LatteDecompilerShader* shader) { case LatteConst::ShaderType::Vertex: { - m_renderCommandEncoder->setVertexBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING); + renderCommandEncoder->setVertexBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING); break; } case LatteConst::ShaderType::Pixel: { - m_renderCommandEncoder->setFragmentBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING); + renderCommandEncoder->setFragmentBytes(supportBufferData, sizeof(supportBufferData), MTL_SUPPORT_BUFFER_BINDING); break; } default: @@ -865,12 +866,12 @@ void MetalRenderer::BindStageResources(LatteDecompilerShader* shader) { case LatteConst::ShaderType::Vertex: { - m_renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), offset, binding); + renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), offset, binding); break; } case LatteConst::ShaderType::Pixel: { - m_renderCommandEncoder->setFragmentBuffer(m_memoryManager->GetBufferCache(), offset, binding); + renderCommandEncoder->setFragmentBuffer(m_memoryManager->GetBufferCache(), offset, binding); break; } default: diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 079e5bba..0c09ee24 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -6,6 +6,7 @@ #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h" +#include "Metal/MTLComputeCommandEncoder.hpp" #include "Metal/MTLRenderCommandEncoder.hpp" #include "Metal/MTLRenderPass.hpp" #include "Metal/MTLRenderPipeline.hpp" @@ -33,6 +34,14 @@ struct MetalState MTL::Texture* depthRenderTarget = nullptr; }; +enum class MetalEncoderType +{ + None, + Render, + Compute, + Blit, +}; + class MetalRenderer : public Renderer { public: @@ -197,7 +206,8 @@ private: // Active objects MTL::CommandBuffer* m_commandBuffer = nullptr; - MTL::RenderCommandEncoder* m_renderCommandEncoder = nullptr; + MetalEncoderType m_encoderType = MetalEncoderType::None; + MTL::CommandEncoder* m_commandEncoder = nullptr; CA::MetalDrawable* m_drawable; // State @@ -215,49 +225,101 @@ private: } } - void BeginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget) + MTL::RenderCommandEncoder* GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget) { EnsureCommandBuffer(); // Check if we need to begin a new render pass - if (m_renderCommandEncoder) + if (m_commandEncoder) { - bool needsNewRenderPass = false; - for (uint8 i = 0; i < 8; i++) + if (m_encoderType == MetalEncoderType::Render) { - if (colorRenderTargets[i] && (colorRenderTargets[i] != m_state.colorRenderTargets[i])) + bool needsNewRenderPass = false; + for (uint8 i = 0; i < 8; i++) { - needsNewRenderPass = true; - break; + if (colorRenderTargets[i] && (colorRenderTargets[i] != m_state.colorRenderTargets[i])) + { + needsNewRenderPass = true; + break; + } } - } - if (!needsNewRenderPass) - { - if (depthRenderTarget && (depthRenderTarget != m_state.depthRenderTarget)) + if (!needsNewRenderPass) { - needsNewRenderPass = true; + if (depthRenderTarget && (depthRenderTarget != m_state.depthRenderTarget)) + { + needsNewRenderPass = true; + } } - } - if (!needsNewRenderPass) - { - return; + if (!needsNewRenderPass) + { + return (MTL::RenderCommandEncoder*)m_commandEncoder; + } } EndEncoding(); } - m_renderCommandEncoder = m_commandBuffer->renderCommandEncoder(renderPassDescriptor); + // Update state + for (uint8 i = 0; i < 8; i++) + { + m_state.colorRenderTargets[i] = colorRenderTargets[i]; + } + m_state.depthRenderTarget = depthRenderTarget; + + auto renderCommandEncoder = m_commandBuffer->renderCommandEncoder(renderPassDescriptor); + m_commandEncoder = renderCommandEncoder; + m_encoderType = MetalEncoderType::Render; + + return renderCommandEncoder; + } + + MTL::ComputeCommandEncoder* GetComputeCommandEncoder() + { + if (m_commandEncoder) + { + if (m_encoderType != MetalEncoderType::Compute) + { + return (MTL::ComputeCommandEncoder*)m_commandEncoder; + } + + EndEncoding(); + } + + auto computeCommandEncoder = m_commandBuffer->computeCommandEncoder(); + m_commandEncoder = computeCommandEncoder; + m_encoderType = MetalEncoderType::Compute; + + return computeCommandEncoder; + } + + MTL::BlitCommandEncoder* GetBlitCommandEncoder() + { + if (m_commandEncoder) + { + if (m_encoderType != MetalEncoderType::Blit) + { + return (MTL::BlitCommandEncoder*)m_commandEncoder; + } + + EndEncoding(); + } + + auto blitCommandEncoder = m_commandBuffer->blitCommandEncoder(); + m_commandEncoder = blitCommandEncoder; + m_encoderType = MetalEncoderType::Blit; + + return blitCommandEncoder; } void EndEncoding() { - if (m_renderCommandEncoder) + if (m_commandEncoder) { - m_renderCommandEncoder->endEncoding(); - m_renderCommandEncoder->release(); - m_renderCommandEncoder = nullptr; + m_commandEncoder->endEncoding(); + m_commandEncoder->release(); + m_commandEncoder = nullptr; } } @@ -276,5 +338,5 @@ private: } } - void BindStageResources(LatteDecompilerShader* shader); + void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader); };