mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-01 21:44:17 +01:00
implement texture readback
This commit is contained in:
parent
e2ec602c43
commit
d3249dc324
@ -548,6 +548,8 @@ if(ENABLE_METAL)
|
||||
HW/Latte/Renderer/Metal/LatteTextureMtl.h
|
||||
HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp
|
||||
HW/Latte/Renderer/Metal/LatteTextureViewMtl.h
|
||||
HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp
|
||||
HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h
|
||||
HW/Latte/Renderer/Metal/RendererShaderMtl.cpp
|
||||
HW/Latte/Renderer/Metal/RendererShaderMtl.h
|
||||
HW/Latte/Renderer/Metal/CachedFBOMtl.cpp
|
||||
|
@ -9,7 +9,7 @@
|
||||
class LatteTextureMtl : public LatteTexture
|
||||
{
|
||||
public:
|
||||
LatteTextureMtl(class MetalRenderer* vkRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,
|
||||
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);
|
||||
~LatteTextureMtl();
|
||||
|
||||
|
43
src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp
Normal file
43
src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
|
||||
#include "HW/Latte/Renderer/Metal/LatteToMtl.h"
|
||||
|
||||
LatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl()
|
||||
{
|
||||
}
|
||||
|
||||
void LatteTextureReadbackInfoMtl::StartTransfer()
|
||||
{
|
||||
cemu_assert(m_textureView);
|
||||
|
||||
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);
|
||||
|
||||
size_t bytesPerRow = GetMtlTextureBytesPerRow(baseTexture->format, baseTexture->IsDepth(), baseTexture->width);
|
||||
size_t bytesPerImage = GetMtlTextureBytesPerImage(baseTexture->format, baseTexture->IsDepth(), baseTexture->height, bytesPerRow);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool LatteTextureReadbackInfoMtl::IsFinished()
|
||||
{
|
||||
// TODO: implement
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LatteTextureReadbackInfoMtl::ForceFinish()
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
uint8* LatteTextureReadbackInfoMtl::GetData()
|
||||
{
|
||||
return (uint8*)m_mtlr->GetTextureReadbackBuffer()->contents() + m_bufferOffset;
|
||||
}
|
22
src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h
Normal file
22
src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h"
|
||||
|
||||
class LatteTextureReadbackInfoMtl : public LatteTextureReadbackInfo
|
||||
{
|
||||
public:
|
||||
LatteTextureReadbackInfoMtl(class MetalRenderer* mtlRenderer, LatteTextureView* textureView, uint32 bufferOffset) : LatteTextureReadbackInfo(textureView), m_mtlr{mtlRenderer}, m_bufferOffset{bufferOffset} {}
|
||||
~LatteTextureReadbackInfoMtl();
|
||||
|
||||
void StartTransfer() override;
|
||||
|
||||
bool IsFinished() override;
|
||||
void ForceFinish() override;
|
||||
|
||||
uint8* GetData() override;
|
||||
|
||||
private:
|
||||
class MetalRenderer* m_mtlr;
|
||||
|
||||
uint32 m_bufferOffset = 0;
|
||||
};
|
@ -6,6 +6,7 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
|
||||
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h"
|
||||
@ -35,6 +36,9 @@ MetalRenderer::MetalRenderer()
|
||||
m_pipelineCache = new MetalPipelineCache(this);
|
||||
m_depthStencilCache = new MetalDepthStencilCache(this);
|
||||
|
||||
// Texture readback
|
||||
m_readbackBuffer = m_device->newBuffer(TEXTURE_READBACK_SIZE, MTL::StorageModeShared);
|
||||
|
||||
// Initialize state
|
||||
for (uint32 i = 0; i < (uint32)LatteConst::ShaderType::TotalCount; i++)
|
||||
{
|
||||
@ -53,6 +57,8 @@ MetalRenderer::~MetalRenderer()
|
||||
|
||||
m_nearestSampler->release();
|
||||
|
||||
m_readbackBuffer->release();
|
||||
|
||||
m_commandQueue->release();
|
||||
m_device->release();
|
||||
}
|
||||
@ -407,9 +413,17 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
|
||||
|
||||
LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView)
|
||||
{
|
||||
debug_printf("MetalRenderer::texture_createReadback not implemented\n");
|
||||
size_t uploadSize = static_cast<LatteTextureMtl*>(textureView->baseTexture)->GetTexture()->allocatedSize();
|
||||
|
||||
return nullptr;
|
||||
if ((m_readbackBufferWriteOffset + uploadSize) > TEXTURE_READBACK_SIZE)
|
||||
{
|
||||
m_readbackBufferWriteOffset = 0;
|
||||
}
|
||||
|
||||
auto* result = new LatteTextureReadbackInfoMtl(this, textureView, m_readbackBufferWriteOffset);
|
||||
m_readbackBufferWriteOffset += uploadSize;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)
|
||||
@ -801,6 +815,9 @@ void MetalRenderer::CommitCommandBuffer()
|
||||
m_commandBuffer->release();
|
||||
m_commandBuffer = nullptr;
|
||||
|
||||
// TODO: where should this be called?
|
||||
LatteTextureReadback_UpdateFinishedTransfers(false);
|
||||
|
||||
// Debug
|
||||
m_commandQueue->insertDebugCaptureBoundary();
|
||||
}
|
||||
|
@ -49,9 +49,36 @@ enum class MetalEncoderType
|
||||
Blit,
|
||||
};
|
||||
|
||||
class LatteQueryObjectMtl : public LatteQueryObject
|
||||
{
|
||||
public:
|
||||
LatteQueryObjectMtl(class MetalRenderer* mtlRenderer) : m_mtlr{mtlRenderer} {}
|
||||
|
||||
bool getResult(uint64& numSamplesPassed) override
|
||||
{
|
||||
cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::getResult: occlusion queries are not yet supported on Metal");
|
||||
return false;
|
||||
}
|
||||
|
||||
void begin() override
|
||||
{
|
||||
cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::begin: occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void end() override
|
||||
{
|
||||
cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::end: occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
private:
|
||||
class MetalRenderer* m_mtlr;
|
||||
};
|
||||
|
||||
class MetalRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
static const inline int TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB
|
||||
|
||||
MetalRenderer();
|
||||
~MetalRenderer() override;
|
||||
|
||||
@ -178,23 +205,43 @@ public:
|
||||
|
||||
// occlusion queries
|
||||
LatteQueryObject* occlusionQuery_create() override {
|
||||
cemuLog_log(LogType::MetalLogging, "Occlusion queries are not yet supported on Metal");
|
||||
cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_create: Occlusion queries are not yet supported on Metal");
|
||||
|
||||
return nullptr;
|
||||
return new LatteQueryObjectMtl(this);
|
||||
}
|
||||
|
||||
void occlusionQuery_destroy(LatteQueryObject* queryObj) override {
|
||||
cemuLog_log(LogType::MetalLogging, "Occlusion queries are not yet supported on Metal");
|
||||
cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_destroy: occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_flush() override {
|
||||
cemuLog_log(LogType::MetalLogging, "Occlusion queries are not yet supported on Metal");
|
||||
cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_flush: occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_updateState() override {
|
||||
cemuLog_log(LogType::MetalLogging, "Occlusion queries are not yet supported on Metal");
|
||||
cemuLog_log(LogType::MetalLogging, "MetalRenderer::occlusionQuery_updateState: occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
// Helpers
|
||||
void EnsureCommandBuffer();
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate = false, bool rebindStateIfNewEncoder = true);
|
||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder();
|
||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
||||
void EndEncoding();
|
||||
void CommitCommandBuffer();
|
||||
|
||||
bool AcquireNextDrawable();
|
||||
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader);
|
||||
void RebindRenderState(MTL::RenderCommandEncoder* renderCommandEncoder);
|
||||
|
||||
void ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a);
|
||||
|
||||
// Getters
|
||||
MTL::Buffer* GetTextureReadbackBuffer()
|
||||
{
|
||||
return m_readbackBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
CA::MetalLayer* m_metalLayer;
|
||||
@ -213,6 +260,10 @@ private:
|
||||
// Basic
|
||||
MTL::SamplerState* m_nearestSampler;
|
||||
|
||||
// Texture readback
|
||||
MTL::Buffer* m_readbackBuffer;
|
||||
uint32 m_readbackBufferWriteOffset = 0;
|
||||
|
||||
// Active objects
|
||||
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
||||
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
||||
@ -221,19 +272,4 @@ private:
|
||||
|
||||
// State
|
||||
MetalState m_state;
|
||||
|
||||
// Helpers
|
||||
void EnsureCommandBuffer();
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget, bool forceRecreate = false, bool rebindStateIfNewEncoder = true);
|
||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder();
|
||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder();
|
||||
void EndEncoding();
|
||||
void CommitCommandBuffer();
|
||||
|
||||
bool AcquireNextDrawable();
|
||||
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader);
|
||||
void RebindRenderState(MTL::RenderCommandEncoder* renderCommandEncoder);
|
||||
|
||||
void ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user