mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-08-25 03:30:35 -05:00
Latte: Handle texture copy edge-case
Fixes save preview images in BotW
This commit is contained in:
@@ -125,6 +125,7 @@ void LatteTextureReadback_StartTransfer(LatteTextureView* textureView);
|
||||
bool LatteTextureReadback_Update(bool forceStart = false);
|
||||
void LatteTextureReadback_NotifyTextureDeletion(LatteTexture* texture);
|
||||
void LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish);
|
||||
bool LatteTextureReadback_ReadbackToLinearBlocking(LatteTextureView* sourceView, uint8* dstPtr, uint32 dstWidth, uint32 dstHeight, uint32 dstPitch);
|
||||
|
||||
// query
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ void LatteSurfaceCopy_CopyInRAM(const LatteSurfaceCopyParam& src, const LatteSur
|
||||
copyWidth = (copyWidth + 3) / 4;
|
||||
copyHeight = (copyHeight + 3) / 4;
|
||||
}
|
||||
|
||||
uint32 dstBpp = Latte::GetFormatBits(dstHwFormat);
|
||||
|
||||
gx2SurfaceCopySoftware((uint8*)MEMPTR<void>(src.physDataAddr).GetPtr(), src.heightInTexels, src.pitch, 1, src.sliceIndex, src.swizzle, (uint32)src.tilemode,
|
||||
@@ -44,10 +43,9 @@ void LatteSurfaceCopy_copySurfaceNew(const LatteSurfaceCopyParam& src, const Lat
|
||||
cemu_assert_debug((rect.x + rect.width) <= dst.pitch * (Latte::IsCompressedFormat(dst.surfaceFormat)?4:1));
|
||||
cemu_assert_debug((rect.x + rect.width) <= src.pitch * (Latte::IsCompressedFormat(src.surfaceFormat)?4:1));
|
||||
|
||||
if (src.tilemode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL || dst.tilemode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL)
|
||||
if (src.tilemode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL)
|
||||
{
|
||||
// todo - it's technically possible for a matching linear texture to be in the texture cache already
|
||||
// there is also a case of tiled to linear_special where we should trigger a readback without an actual destination texture
|
||||
LatteSurfaceCopy_CopyInRAM(src, dst, rect);
|
||||
return;
|
||||
}
|
||||
@@ -69,6 +67,13 @@ void LatteSurfaceCopy_copySurfaceNew(const LatteSurfaceCopyParam& src, const Lat
|
||||
LatteTexture_UpdateCacheFromDynamicTextures(sourceTexture);
|
||||
sourceTexture->reloadFromDynamicTextures = false;
|
||||
}
|
||||
// special case: RAM copy from cached texture to linear special format
|
||||
if (dst.tilemode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL)
|
||||
{
|
||||
cemu_assert_debug(rect.x == 0 && rect.y == 0);
|
||||
LatteTextureReadback_ReadbackToLinearBlocking(sourceView, MEMPTR<uint8>(dst.physDataAddr).GetPtr(), rect.width, rect.height, dst.pitch);
|
||||
return;
|
||||
}
|
||||
// look up destination texture
|
||||
LatteTexture* destinationTexture = nullptr;
|
||||
LatteTextureView* destinationView = LatteTextureViewLookupCache::lookupSliceMinSize(dst.physDataAddr, rect.x + rect.width, rect.y + rect.height, dst.pitch, 0, dst.sliceIndex, dst.surfaceFormat);
|
||||
|
||||
@@ -159,3 +159,25 @@ void LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish)
|
||||
}
|
||||
performanceMonitor.gpuTime_waitForAsync.endMeasuring();
|
||||
}
|
||||
|
||||
bool LatteTextureReadback_ReadbackToLinearBlocking(LatteTextureView* sourceView, uint8* dstPtr, uint32 dstWidth, uint32 dstHeight, uint32 dstPitch)
|
||||
{
|
||||
LatteTextureReadbackInfo* info = g_renderer->texture_createReadback(sourceView);
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
info->StartTransfer();
|
||||
info->ForceFinish();
|
||||
cemu_assert(info->IsFinished());
|
||||
|
||||
uint8* data = info->GetData(); // returned pixel format should match Latte format
|
||||
uint32 bpp = Latte::GetFormatBits(sourceView->baseTexture->format) / 8;
|
||||
uint32 srcRowBytes = sourceView->baseTexture->width * bpp;
|
||||
uint32 dstRowBytes = dstWidth * bpp;
|
||||
for (uint32 y = 0; y < dstHeight; y++)
|
||||
memcpy(dstPtr + y * dstPitch * bpp, data + y * srcRowBytes, dstRowBytes);
|
||||
|
||||
info->ReleaseData();
|
||||
delete info;
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user