fix: 3D texture copies & fix: present filter

This commit is contained in:
Samuliak 2024-08-13 11:44:49 +02:00
parent 3f52f3acfe
commit 4b7c01ee2a
6 changed files with 38 additions and 18 deletions

View File

@ -699,6 +699,7 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count + 1; outputCount = count + 1;
} }
/*
else if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal) else if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal)
{ {
if (indexType == LatteIndexType::AUTO) if (indexType == LatteIndexType::AUTO)
@ -722,6 +723,7 @@ void LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32
cemu_assert_debug(false); cemu_assert_debug(false);
outputCount = count; outputCount = count;
} }
*/
else else
{ {
if (indexType == LatteIndexType::U16_BE) if (indexType == LatteIndexType::U16_BE)

View File

@ -934,7 +934,7 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa
{ {
sint32 scaling_filter = downscaling ? GetConfig().downscale_filter : GetConfig().upscale_filter; sint32 scaling_filter = downscaling ? GetConfig().downscale_filter : GetConfig().upscale_filter;
if (g_renderer->GetType() == RendererAPI::Vulkan) if (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)
{ {
// force linear or nearest neighbor filter // force linear or nearest neighbor filter
if(scaling_filter != kLinearFilter && scaling_filter != kNearestNeighborFilter) if(scaling_filter != kLinearFilter && scaling_filter != kNearestNeighborFilter)

View File

@ -6,10 +6,12 @@
LatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) LatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_baseTexture(texture) : LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_baseTexture(texture)
{ {
m_rgbaView = CreateSwizzledView(RGBA_SWIZZLE);
} }
LatteTextureViewMtl::~LatteTextureViewMtl() LatteTextureViewMtl::~LatteTextureViewMtl()
{ {
m_rgbaView->release();
for (sint32 i = 0; i < std::size(m_viewCache); i++) for (sint32 i = 0; i < std::size(m_viewCache); i++)
{ {
if (m_viewCache[i].key != INVALID_SWIZZLE) if (m_viewCache[i].key != INVALID_SWIZZLE)
@ -30,7 +32,7 @@ MTL::Texture* LatteTextureViewMtl::GetSwizzledView(uint32 gpuSamplerSwizzle)
// RGBA swizzle == no swizzle // RGBA swizzle == no swizzle
if (gpuSamplerSwizzle == RGBA_SWIZZLE) if (gpuSamplerSwizzle == RGBA_SWIZZLE)
{ {
return m_baseTexture->GetTexture(); return m_rgbaView;
} }
// First, try to find a view in the cache // First, try to find a view in the cache

View File

@ -26,6 +26,7 @@ private:
class LatteTextureMtl* m_baseTexture; class LatteTextureMtl* m_baseTexture;
MTL::Texture* m_rgbaView;
struct { struct {
uint32 key; uint32 key;
MTL::Texture* texture; MTL::Texture* texture;

View File

@ -16,7 +16,6 @@
#include "Cafe/HW/Latte/Core/LatteIndices.h" #include "Cafe/HW/Latte/Core/LatteIndices.h"
#include "Cemu/Logging/CemuDebugLogging.h" #include "Cemu/Logging/CemuDebugLogging.h"
#include "Common/precompiled.h" #include "Common/precompiled.h"
#include "Metal/MTLPixelFormat.hpp"
#include "gui/guiWrapper.h" #include "gui/guiWrapper.h"
#define COMMIT_TRESHOLD 256 #define COMMIT_TRESHOLD 256
@ -32,6 +31,10 @@ MetalRenderer::MetalRenderer()
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init(); MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
m_nearestSampler = m_device->newSamplerState(samplerDescriptor); m_nearestSampler = m_device->newSamplerState(samplerDescriptor);
samplerDescriptor->setMinFilter(MTL::SamplerMinMagFilterLinear);
samplerDescriptor->setMagFilter(MTL::SamplerMinMagFilterLinear);
m_linearSampler = m_device->newSamplerState(samplerDescriptor);
samplerDescriptor->release(); samplerDescriptor->release();
m_memoryManager = new MetalMemoryManager(this); m_memoryManager = new MetalMemoryManager(this);
@ -109,6 +112,7 @@ MetalRenderer::~MetalRenderer()
delete m_memoryManager; delete m_memoryManager;
m_nearestSampler->release(); m_nearestSampler->release();
m_linearSampler->release();
m_readbackBuffer->release(); m_readbackBuffer->release();
@ -200,25 +204,26 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
if (!AcquireNextDrawable(!padView)) if (!AcquireNextDrawable(!padView))
return; return;
if (clearBackground)
ClearColorbuffer(padView);
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView(); MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView();
// Create render pass // Create render pass
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
renderPassDescriptor->colorAttachments()->object(0)->setTexture(m_drawable->texture()); auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
colorAttachment->setTexture(m_drawable->texture());
// TODO: shouldn't it be LoadActionLoad when not clearing?
colorAttachment->setLoadAction(clearBackground ? MTL::LoadActionClear : MTL::LoadActionDontCare);
colorAttachment->setStoreAction(MTL::StoreActionStore);
MTL::Texture* colorRenderTargets[8] = {nullptr}; MTL::Texture* colorRenderTargets[8] = {nullptr};
colorRenderTargets[0] = m_drawable->texture(); colorRenderTargets[0] = m_drawable->texture();
// If there was already an encoder with these attachment, we should set the viewport and scissor to default, but that shouldn't happen // If there was already an encoder with these attachment, we should set the viewport and scissor to default, but that shouldn't happen
auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, nullptr, false, false); auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, nullptr, clearBackground, false);
renderPassDescriptor->release(); renderPassDescriptor->release();
// Draw to Metal layer // Draw to Metal layer
renderCommandEncoder->setRenderPipelineState(m_state.m_usesSRGB ? m_presentPipelineSRGB : m_presentPipelineLinear); renderCommandEncoder->setRenderPipelineState(m_state.m_usesSRGB ? m_presentPipelineSRGB : m_presentPipelineLinear);
renderCommandEncoder->setFragmentTexture(presentTexture, 0); renderCommandEncoder->setFragmentTexture(presentTexture, 0);
renderCommandEncoder->setFragmentSamplerState(m_nearestSampler, 0); renderCommandEncoder->setFragmentSamplerState((useLinearTexFilter ? m_linearSampler : m_nearestSampler), 0);
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3)); renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3));
} }
@ -314,11 +319,19 @@ void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIn
void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize)
{ {
auto mtlTexture = (LatteTextureMtl*)hostTexture; auto textureMtl = (LatteTextureMtl*)hostTexture;
size_t bytesPerRow = GetMtlTextureBytesPerRow(mtlTexture->GetFormat(), mtlTexture->IsDepth(), width); uint32 offsetZ = 0;
size_t bytesPerImage = GetMtlTextureBytesPerImage(mtlTexture->GetFormat(), mtlTexture->IsDepth(), height, bytesPerRow); if (textureMtl->Is3DTexture())
mtlTexture->GetTexture()->replaceRegion(MTL::Region(0, 0, width, height), mipIndex, sliceIndex, pixelData, bytesPerRow, bytesPerImage); {
offsetZ = sliceIndex;
sliceIndex = 0;
}
size_t bytesPerRow = GetMtlTextureBytesPerRow(textureMtl->GetFormat(), textureMtl->IsDepth(), width);
// No need to calculate bytesPerImage for 3D textures, since we always load just one slice
//size_t bytesPerImage = GetMtlTextureBytesPerImage(textureMtl->GetFormat(), textureMtl->IsDepth(), height, bytesPerRow);
textureMtl->GetTexture()->replaceRegion(MTL::Region(0, 0, offsetZ, width, height, 1), mipIndex, sliceIndex, pixelData, bytesPerRow, 0);
} }
void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)
@ -409,11 +422,12 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
// If copying whole textures, we can do a more efficient copy // If copying whole textures, we can do a more efficient copy
if (effectiveSrcX == 0 && effectiveSrcY == 0 && effectiveDstX == 0 && effectiveDstY == 0 && if (effectiveSrcX == 0 && effectiveSrcY == 0 && effectiveDstX == 0 && effectiveDstY == 0 &&
effectiveCopyWidth == src->GetMipWidth(srcMip) && effectiveCopyHeight == src->GetMipHeight(srcMip) && srcOffsetZ == 0 && dstOffsetZ == 0 &&
effectiveCopyWidth == dst->GetMipWidth(dstMip) && effectiveCopyHeight == dst->GetMipHeight(dstMip) && effectiveCopyWidth == src->GetMipWidth(srcMip) && effectiveCopyHeight == src->GetMipHeight(srcMip) && srcDepth == src->GetMipDepth(srcMip) &&
effectiveCopyWidth == dst->GetMipWidth(dstMip) && effectiveCopyHeight == dst->GetMipHeight(dstMip) && dstDepth == dst->GetMipDepth(dstMip) &&
srcLayerCount == dstLayerCount) srcLayerCount == dstLayerCount)
{ {
blitCommandEncoder->copyFromTexture(mtlSrc, srcSlice, srcMip, mtlDst, dstSlice, dstMip, srcLayerCount, 1); blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer, srcMip, mtlDst, dstBaseLayer, dstMip, srcLayerCount, 1);
} }
else else
{ {
@ -421,7 +435,7 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
{ {
for (uint32 i = 0; i < srcLayerCount; i++) for (uint32 i = 0; i < srcLayerCount; i++)
{ {
blitCommandEncoder->copyFromTexture(mtlSrc, srcSlice + i, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, 1), mtlDst, dstSlice + i, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ)); blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer + i, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, srcDepth), mtlDst, dstBaseLayer + i, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ));
} }
} }
else else
@ -438,7 +452,7 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
else else
dstSlice++; dstSlice++;
blitCommandEncoder->copyFromTexture(mtlSrc, srcSlice, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, 1), mtlDst, dstSlice, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ)); blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, 1), mtlDst, dstBaseLayer, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ));
} }
} }
} }

View File

@ -288,6 +288,7 @@ private:
// Basic // Basic
MTL::SamplerState* m_nearestSampler; MTL::SamplerState* m_nearestSampler;
MTL::SamplerState* m_linearSampler;
// Texture readback // Texture readback
MTL::Buffer* m_readbackBuffer; MTL::Buffer* m_readbackBuffer;