From 41864bcfcf9055fc5c6f78014c4f969024cba943 Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 12 May 2026 16:45:11 +0100 Subject: [PATCH] Metal: specify blit options when copying to textures --- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 8c2da361..5c374ddd 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -745,6 +745,31 @@ void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIn } } +MTL::BlitOption GetBlitOptionForTexture(const LatteTextureMtl* texture) { + switch (texture->GetTexture()->pixelFormat()) { + case MTL::PixelFormatDepth16Unorm: + case MTL::PixelFormatDepth32Float: + return MTL::BlitOptionDepthFromDepthStencil; + + case MTL::PixelFormatStencil8: + return MTL::BlitOptionStencilFromDepthStencil; + + case MTL::PixelFormatDepth24Unorm_Stencil8: + case MTL::PixelFormatDepth32Float_Stencil8: + // Can't copy both in one call — caller must specify. + // Default to depth + return MTL::BlitOptionDepthFromDepthStencil; + + default: + return MTL::BlitOptionNone; + } +} + +bool IsDepthStencilFormat(MTL::PixelFormat format) { + return format == MTL::PixelFormatDepth24Unorm_Stencil8 || + format == MTL::PixelFormatDepth32Float_Stencil8; +} + // TODO: do a cpu copy on Apple Silicon? void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) { @@ -774,9 +799,14 @@ void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, s memcpy(allocation.memPtr, pixelData, compressedImageSize); bufferAllocator.FlushReservation(allocation); - // TODO: specify blit options when copying to a depth stencil texture? // Copy the data from the temporary buffer to the texture - blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, bytesPerRow, 0, MTL::Size(width, height, 1), textureMtl->GetTexture(), sliceIndex, mipIndex, MTL::Origin(0, 0, offsetZ)); + if (IsDepthStencilFormat(textureMtl->GetTexture()->pixelFormat())) { + // Metal doesn't allow copying depth and stencil data at the same time, so we need to do two copies for combined depth/stencil formats + blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, bytesPerRow, 0, MTL::Size(width, height, 1), textureMtl->GetTexture(), sliceIndex, mipIndex, MTL::Origin(0, 0, offsetZ), MTL::BlitOptionDepthFromDepthStencil); + blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, bytesPerRow, 0, MTL::Size(width, height, 1), textureMtl->GetTexture(), sliceIndex, mipIndex, MTL::Origin(0, 0, offsetZ), MTL::BlitOptionStencilFromDepthStencil); + } else { + blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, bytesPerRow, 0, MTL::Size(width, height, 1), textureMtl->GetTexture(), sliceIndex, mipIndex, MTL::Origin(0, 0, offsetZ), GetBlitOptionForTexture(textureMtl)); + } //} }