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/LatteTextureMtl.h
|
||||||
HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp
|
HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp
|
||||||
HW/Latte/Renderer/Metal/LatteTextureViewMtl.h
|
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.cpp
|
||||||
HW/Latte/Renderer/Metal/RendererShaderMtl.h
|
HW/Latte/Renderer/Metal/RendererShaderMtl.h
|
||||||
HW/Latte/Renderer/Metal/CachedFBOMtl.cpp
|
HW/Latte/Renderer/Metal/CachedFBOMtl.cpp
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
class LatteTextureMtl : public LatteTexture
|
class LatteTextureMtl : public LatteTexture
|
||||||
{
|
{
|
||||||
public:
|
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);
|
uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);
|
||||||
~LatteTextureMtl();
|
~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/CachedFBOMtl.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.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/LatteToMtl.h"
|
||||||
|
|
||||||
#include "Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h"
|
||||||
@ -35,6 +36,9 @@ MetalRenderer::MetalRenderer()
|
|||||||
m_pipelineCache = new MetalPipelineCache(this);
|
m_pipelineCache = new MetalPipelineCache(this);
|
||||||
m_depthStencilCache = new MetalDepthStencilCache(this);
|
m_depthStencilCache = new MetalDepthStencilCache(this);
|
||||||
|
|
||||||
|
// Texture readback
|
||||||
|
m_readbackBuffer = m_device->newBuffer(TEXTURE_READBACK_SIZE, MTL::StorageModeShared);
|
||||||
|
|
||||||
// Initialize state
|
// Initialize state
|
||||||
for (uint32 i = 0; i < (uint32)LatteConst::ShaderType::TotalCount; i++)
|
for (uint32 i = 0; i < (uint32)LatteConst::ShaderType::TotalCount; i++)
|
||||||
{
|
{
|
||||||
@ -53,6 +57,8 @@ MetalRenderer::~MetalRenderer()
|
|||||||
|
|
||||||
m_nearestSampler->release();
|
m_nearestSampler->release();
|
||||||
|
|
||||||
|
m_readbackBuffer->release();
|
||||||
|
|
||||||
m_commandQueue->release();
|
m_commandQueue->release();
|
||||||
m_device->release();
|
m_device->release();
|
||||||
}
|
}
|
||||||
@ -407,9 +413,17 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
|
|||||||
|
|
||||||
LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView)
|
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)
|
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->release();
|
||||||
m_commandBuffer = nullptr;
|
m_commandBuffer = nullptr;
|
||||||
|
|
||||||
|
// TODO: where should this be called?
|
||||||
|
LatteTextureReadback_UpdateFinishedTransfers(false);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
m_commandQueue->insertDebugCaptureBoundary();
|
m_commandQueue->insertDebugCaptureBoundary();
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,36 @@ enum class MetalEncoderType
|
|||||||
Blit,
|
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
|
class MetalRenderer : public Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static const inline int TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB
|
||||||
|
|
||||||
MetalRenderer();
|
MetalRenderer();
|
||||||
~MetalRenderer() override;
|
~MetalRenderer() override;
|
||||||
|
|
||||||
@ -178,23 +205,43 @@ public:
|
|||||||
|
|
||||||
// occlusion queries
|
// occlusion queries
|
||||||
LatteQueryObject* occlusionQuery_create() override {
|
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 {
|
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 {
|
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 {
|
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:
|
private:
|
||||||
CA::MetalLayer* m_metalLayer;
|
CA::MetalLayer* m_metalLayer;
|
||||||
@ -213,6 +260,10 @@ private:
|
|||||||
// Basic
|
// Basic
|
||||||
MTL::SamplerState* m_nearestSampler;
|
MTL::SamplerState* m_nearestSampler;
|
||||||
|
|
||||||
|
// Texture readback
|
||||||
|
MTL::Buffer* m_readbackBuffer;
|
||||||
|
uint32 m_readbackBufferWriteOffset = 0;
|
||||||
|
|
||||||
// Active objects
|
// Active objects
|
||||||
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
||||||
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
MetalEncoderType m_encoderType = MetalEncoderType::None;
|
||||||
@ -221,19 +272,4 @@ private:
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
MetalState m_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