Latte: Add support for texture readback with non-zero slice index

This commit is contained in:
Exzap
2026-07-24 18:24:50 +02:00
parent b235696189
commit 73001002e0
6 changed files with 12 additions and 17 deletions

View File

@@ -704,7 +704,7 @@ void optimizedLinearReadbackWriteLoop(LatteTextureLoaderCtx* textureLoader, uint
sint32 yc = y;
sint32 pixelOffset = yc * pitch;
copyType* rowPixelData = (copyType*)(linearPixelData + pixelOffset * sizeof(copyType));
copyType* blockData = (copyType*)LatteTextureLoader_getInputLinearOptimized_(textureLoader, 0, y, 1, 1, sizeof(copyType) * 8, 0, 1, 0, textureLoader->pitch, textureLoader->height);
copyType* blockData = (copyType*)LatteTextureLoader_getInputLinearOptimized_(textureLoader, 0, y, 1, 1, sizeof(copyType) * 8, textureLoader->sliceIndex, 1, 0, textureLoader->pitch, textureLoader->surfaceInfoHeight);
if constexpr (sizeof(copyType) == 4)
{
memcpy_dwords(blockData, rowPixelData, textureLoader->width);
@@ -726,10 +726,6 @@ void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* tex
LatteTextureLoaderCtx textureLoader = { 0 };
LatteTextureLoader_begin(&textureLoader, sliceIndex, mipIndex, textureData->physAddress, textureData->physMipAddress, textureData->format, textureData->dim, textureData->width, textureData->height, textureData->depth, textureData->mipLevels, textureData->pitch, textureData->tileMode, textureData->swizzle);
#ifdef CEMU_DEBUG_ASSERT
if (textureData->depth != 1)
cemuLog_log(LogType::Force, "_writeReadbackTextureToMemory(): Texture has multiple slices (not supported)");
#endif
if (textureLoader.physAddress == MPTR_NULL)
{
cemuLog_log(LogType::Force, "_writeReadbackTextureToMemory(): Texture has invalid address");

View File

@@ -145,7 +145,7 @@ void LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish)
}
#endif
uint8* pixelData = readbackInfo->GetData();
LatteTextureLoader_writeReadbackTextureToMemory(&readbackInfo->hostTextureCopy, 0, 0, pixelData);
LatteTextureLoader_writeReadbackTextureToMemory(&readbackInfo->hostTextureCopy, readbackInfo->m_firstSlice, 0, pixelData);
readbackInfo->ReleaseData();
// get the original texture if it still exists and invalidate the current data hash
LatteTextureView* origTexView = LatteTextureViewLookupCache::lookupSlice(readbackInfo->hostTextureCopy.physAddress, readbackInfo->hostTextureCopy.width, readbackInfo->hostTextureCopy.height, readbackInfo->hostTextureCopy.pitch, 0, 0, readbackInfo->hostTextureCopy.format);
@@ -180,4 +180,4 @@ bool LatteTextureReadback_ReadbackToLinearBlocking(LatteTextureView* sourceView,
info->ReleaseData();
delete info;
return true;
}
}

View File

@@ -7,7 +7,7 @@ class LatteTextureReadbackInfo
{
public:
LatteTextureReadbackInfo(LatteTextureView* textureView)
: hostTextureCopy(textureView->baseTexture), m_textureView(textureView)
: hostTextureCopy(textureView->baseTexture), m_firstSlice(textureView->firstSlice), m_textureView(textureView)
{}
virtual ~LatteTextureReadbackInfo() = default;
@@ -24,6 +24,7 @@ public:
bool forceFinish{ false }; // set to true if not finished in time for dependent operation
// texture info
LatteTextureDefinition hostTextureCopy{};
sint32 m_firstSlice{};
protected:
LatteTextureView* m_textureView;

View File

@@ -15,7 +15,6 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
auto* baseTexture = (LatteTextureMtl*)m_textureView->baseTexture;
cemu_assert_debug(m_textureView->firstSlice == 0);
cemu_assert_debug(m_textureView->firstMip == 0);
cemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);
@@ -24,7 +23,7 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), 0, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), m_firstSlice, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();
// TODO: uncomment?

View File

@@ -1,7 +1,5 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h"
LatteTextureReadbackInfoGL::LatteTextureReadbackInfoGL(LatteTextureView* textureView)
: LatteTextureReadbackInfo(textureView)
@@ -94,13 +92,15 @@ LatteTextureReadbackInfoGL::~LatteTextureReadbackInfoGL()
void LatteTextureReadbackInfoGL::StartTransfer()
{
cemu_assert(m_textureView);
((OpenGLRenderer*)g_renderer.get())->texture_bindAndActivate(m_textureView, 0);
LatteTextureGL* baseTexture = (LatteTextureGL*)m_textureView->baseTexture;
cemu_assert_debug(m_textureView->firstMip == 0);
cemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);
// create unsynchronized buffer
glGenBuffers(1, &texImageBufferGL);
glBindBuffer(GL_PIXEL_PACK_BUFFER, texImageBufferGL);
glBufferData(GL_PIXEL_PACK_BUFFER, m_image_size, NULL, GL_DYNAMIC_READ);
// request texture read into buffer
glGetTexImage(((LatteTextureViewGL*)m_textureView)->glTexTarget, 0, m_texFormatGL, m_texDataTypeGL, NULL);
glGetTextureSubImage(baseTexture->glId_texture, 0, 0, 0, m_firstSlice, baseTexture->width, baseTexture->height, 1, m_texFormatGL, m_texDataTypeGL, m_image_size, NULL);
glFlush();
// create fence sync (so we can check if the image copy operation finished)
imageCopyFinSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

View File

@@ -102,7 +102,6 @@ void LatteTextureReadbackInfoVk::StartTransfer()
auto* baseTexture = (LatteTextureVk*)m_textureView->baseTexture;
baseTexture->GetImageObj()->flagForCurrentCommandBuffer();
cemu_assert_debug(m_textureView->firstSlice == 0);
cemu_assert_debug(m_textureView->firstMip == 0);
cemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);
@@ -112,7 +111,7 @@ void LatteTextureReadbackInfoVk::StartTransfer()
region.bufferImageHeight = baseTexture->height;
region.imageSubresource.aspectMask = baseTexture->GetImageAspect();
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.baseArrayLayer = m_firstSlice;
region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = 0;