mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-29 20:44:18 +01:00
present
This commit is contained in:
parent
35eea12950
commit
7ae29a74cd
@ -6,11 +6,12 @@
|
|||||||
#include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.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/Core/FetchShader.h"
|
#include "Cafe/HW/Latte/Core/FetchShader.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteShader.h"
|
#include "Cafe/HW/Latte/Core/LatteShader.h"
|
||||||
#include "Cafe/HW/Latte/Core/LatteIndices.h"
|
#include "Cafe/HW/Latte/Core/LatteIndices.h"
|
||||||
#include "Metal/MTLSampler.hpp"
|
#include "Foundation/NSTypes.hpp"
|
||||||
#include "Metal/MTLVertexDescriptor.hpp"
|
|
||||||
#include "gui/guiWrapper.h"
|
#include "gui/guiWrapper.h"
|
||||||
|
|
||||||
extern bool hasValidFramebufferAttached;
|
extern bool hasValidFramebufferAttached;
|
||||||
@ -43,6 +44,35 @@ void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow)
|
|||||||
|
|
||||||
m_metalLayer = (CA::MetalLayer*)CreateMetalLayer(windowInfo.handle);
|
m_metalLayer = (CA::MetalLayer*)CreateMetalLayer(windowInfo.handle);
|
||||||
m_metalLayer->setDevice(m_device);
|
m_metalLayer->setDevice(m_device);
|
||||||
|
|
||||||
|
// Present pipeline
|
||||||
|
NS::Error* error = nullptr;
|
||||||
|
MTL::Library* presentLibrary = m_device->newLibrary(NS::String::string(presentLibrarySource, NS::ASCIIStringEncoding), nullptr, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
printf("failed to create present library (error: %s)\n", error->localizedDescription()->utf8String());
|
||||||
|
error->release();
|
||||||
|
throw;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MTL::Function* presentVertexFunction = presentLibrary->newFunction(NS::String::string("presentVertex", NS::ASCIIStringEncoding));
|
||||||
|
MTL::Function* presentFragmentFunction = presentLibrary->newFunction(NS::String::string("presentFragment", NS::ASCIIStringEncoding));
|
||||||
|
presentLibrary->release();
|
||||||
|
|
||||||
|
MTL::RenderPipelineDescriptor* renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();
|
||||||
|
renderPipelineDescriptor->setVertexFunction(presentVertexFunction);
|
||||||
|
renderPipelineDescriptor->setFragmentFunction(presentFragmentFunction);
|
||||||
|
renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(m_metalLayer->pixelFormat());
|
||||||
|
m_presentPipeline = m_device->newRenderPipelineState(renderPipelineDescriptor, &error);
|
||||||
|
presentVertexFunction->release();
|
||||||
|
presentFragmentFunction->release();
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
printf("failed to create present pipeline (error: %s)\n", error->localizedDescription()->utf8String());
|
||||||
|
error->release();
|
||||||
|
throw;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::Initialize()
|
void MetalRenderer::Initialize()
|
||||||
@ -83,40 +113,48 @@ void MetalRenderer::DrawEmptyFrame(bool mainWindow)
|
|||||||
|
|
||||||
void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
||||||
{
|
{
|
||||||
if (m_renderCommandEncoder)
|
EndEncoding();
|
||||||
{
|
|
||||||
m_renderCommandEncoder->endEncoding();
|
|
||||||
m_renderCommandEncoder->release();
|
|
||||||
m_renderCommandEncoder = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
CA::MetalDrawable* drawable = m_metalLayer->nextDrawable();
|
if (m_drawable)
|
||||||
if (drawable)
|
|
||||||
{
|
{
|
||||||
ensureCommandBuffer();
|
EnsureCommandBuffer();
|
||||||
m_commandBuffer->presentDrawable(drawable);
|
m_commandBuffer->presentDrawable(m_drawable);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
printf("skipped present!\n");
|
printf("skipped present!\n");
|
||||||
}
|
}
|
||||||
|
m_drawable = nullptr;
|
||||||
|
|
||||||
if (m_commandBuffer)
|
CommitCommandBuffer();
|
||||||
{
|
|
||||||
m_commandBuffer->commit();
|
|
||||||
|
|
||||||
m_commandBuffer->release();
|
|
||||||
m_commandBuffer = nullptr;
|
|
||||||
|
|
||||||
// Debug
|
|
||||||
m_commandQueue->insertDebugCaptureBoundary();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||||
bool padView, bool clearBackground)
|
bool padView, bool clearBackground)
|
||||||
{
|
{
|
||||||
printf("MetalRenderer::DrawBackbufferQuad not implemented\n");
|
// Acquire drawable
|
||||||
|
m_drawable = m_metalLayer->nextDrawable();
|
||||||
|
if (!m_drawable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetTexture();
|
||||||
|
|
||||||
|
// Create render pass
|
||||||
|
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||||
|
renderPassDescriptor->colorAttachments()->object(0)->setTexture(m_drawable->texture());
|
||||||
|
|
||||||
|
MTL::Texture* colorRenderTargets[8] = {nullptr};
|
||||||
|
colorRenderTargets[0] = m_drawable->texture();
|
||||||
|
BeginRenderPassIfNeeded(renderPassDescriptor, colorRenderTargets, nullptr);
|
||||||
|
|
||||||
|
// Draw to Metal layer
|
||||||
|
m_renderCommandEncoder->setRenderPipelineState(m_presentPipeline);
|
||||||
|
m_renderCommandEncoder->setFragmentTexture(presentTexture, 0);
|
||||||
|
m_renderCommandEncoder->setFragmentSamplerState(m_nearestSampler, 0);
|
||||||
|
|
||||||
|
m_renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetalRenderer::BeginFrame(bool mainWindow)
|
bool MetalRenderer::BeginFrame(bool mainWindow)
|
||||||
@ -178,7 +216,6 @@ void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem)
|
|||||||
|
|
||||||
TextureDecoder* MetalRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height)
|
TextureDecoder* MetalRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
printf("decoding format %u\n", (uint32)format);
|
|
||||||
// TODO: move to LatteToMtl
|
// TODO: move to LatteToMtl
|
||||||
if (isDepth)
|
if (isDepth)
|
||||||
{
|
{
|
||||||
@ -468,7 +505,6 @@ void MetalRenderer::draw_beginSequence()
|
|||||||
|
|
||||||
void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst)
|
void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst)
|
||||||
{
|
{
|
||||||
ensureCommandBuffer();
|
|
||||||
// TODO: uncomment
|
// TODO: uncomment
|
||||||
//if (m_state.skipDrawSequence)
|
//if (m_state.skipDrawSequence)
|
||||||
//{
|
//{
|
||||||
@ -484,7 +520,22 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto renderPassDescriptor = m_state.activeFBO->GetRenderPassDescriptor();
|
auto renderPassDescriptor = m_state.activeFBO->GetRenderPassDescriptor();
|
||||||
beginRenderPassIfNeeded(renderPassDescriptor);
|
MTL::Texture* colorRenderTargets[8] = {nullptr};
|
||||||
|
MTL::Texture* depthRenderTarget = nullptr;
|
||||||
|
for (uint32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
auto colorTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->colorBuffer[i].texture);
|
||||||
|
if (colorTexture)
|
||||||
|
{
|
||||||
|
colorRenderTargets[i] = colorTexture->GetTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto depthTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->depthBuffer.texture);
|
||||||
|
if (depthTexture)
|
||||||
|
{
|
||||||
|
depthRenderTarget = depthTexture->GetTexture();
|
||||||
|
}
|
||||||
|
BeginRenderPassIfNeeded(renderPassDescriptor, colorRenderTargets, depthRenderTarget);
|
||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
LatteSHRC_UpdateActiveShaders();
|
LatteSHRC_UpdateActiveShaders();
|
||||||
@ -598,7 +649,8 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
|||||||
if (vertexBufferRange.needsRebind)
|
if (vertexBufferRange.needsRebind)
|
||||||
{
|
{
|
||||||
m_renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), vertexBufferRange.offset, GET_MTL_VERTEX_BUFFER_INDEX(i));
|
m_renderCommandEncoder->setVertexBuffer(m_memoryManager->GetBufferCache(), vertexBufferRange.offset, GET_MTL_VERTEX_BUFFER_INDEX(i));
|
||||||
vertexBufferRange.needsRebind = false;
|
// TODO: uncomment
|
||||||
|
//vertexBufferRange.needsRebind = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
#include "Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h"
|
||||||
#include "Metal/MTLRenderCommandEncoder.hpp"
|
#include "Metal/MTLRenderCommandEncoder.hpp"
|
||||||
#include "Metal/MTLRenderPass.hpp"
|
#include "Metal/MTLRenderPass.hpp"
|
||||||
|
#include "Metal/MTLRenderPipeline.hpp"
|
||||||
|
|
||||||
#define MAX_MTL_BUFFERS 31
|
#define MAX_MTL_BUFFERS 31
|
||||||
#define GET_MTL_VERTEX_BUFFER_INDEX(index) (MAX_MTL_BUFFERS - index - 2)
|
#define GET_MTL_VERTEX_BUFFER_INDEX(index) (MAX_MTL_BUFFERS - index - 2)
|
||||||
@ -28,6 +29,8 @@ struct MetalState
|
|||||||
class CachedFBOMtl* activeFBO = nullptr;
|
class CachedFBOMtl* activeFBO = nullptr;
|
||||||
MetalBufferRange vertexBuffers[MAX_MTL_BUFFERS] = {{}};
|
MetalBufferRange vertexBuffers[MAX_MTL_BUFFERS] = {{}};
|
||||||
class LatteTextureViewMtl* textures[MAX_MTL_TEXTURES] = {nullptr};
|
class LatteTextureViewMtl* textures[MAX_MTL_TEXTURES] = {nullptr};
|
||||||
|
MTL::Texture* colorRenderTargets[8] = {nullptr};
|
||||||
|
MTL::Texture* depthRenderTarget = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MetalRenderer : public Renderer
|
class MetalRenderer : public Renderer
|
||||||
@ -186,18 +189,22 @@ private:
|
|||||||
MTL::Device* m_device;
|
MTL::Device* m_device;
|
||||||
MTL::CommandQueue* m_commandQueue;
|
MTL::CommandQueue* m_commandQueue;
|
||||||
|
|
||||||
|
// Pipelines
|
||||||
|
MTL::RenderPipelineState* m_presentPipeline;
|
||||||
|
|
||||||
// Basic
|
// Basic
|
||||||
MTL::SamplerState* m_nearestSampler;
|
MTL::SamplerState* m_nearestSampler;
|
||||||
|
|
||||||
// Active objects
|
// Active objects
|
||||||
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
MTL::CommandBuffer* m_commandBuffer = nullptr;
|
||||||
MTL::RenderCommandEncoder* m_renderCommandEncoder = nullptr;
|
MTL::RenderCommandEncoder* m_renderCommandEncoder = nullptr;
|
||||||
|
CA::MetalDrawable* m_drawable;
|
||||||
|
|
||||||
// State
|
// State
|
||||||
MetalState m_state;
|
MetalState m_state;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
void ensureCommandBuffer()
|
void EnsureCommandBuffer()
|
||||||
{
|
{
|
||||||
if (!m_commandBuffer)
|
if (!m_commandBuffer)
|
||||||
{
|
{
|
||||||
@ -208,11 +215,64 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor)
|
void BeginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorRenderTargets[8], MTL::Texture* depthRenderTarget)
|
||||||
{
|
{
|
||||||
if (!m_renderCommandEncoder)
|
EnsureCommandBuffer();
|
||||||
|
|
||||||
|
// Check if we need to begin a new render pass
|
||||||
|
if (m_renderCommandEncoder)
|
||||||
{
|
{
|
||||||
m_renderCommandEncoder = m_commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
bool needsNewRenderPass = false;
|
||||||
|
for (uint8 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (colorRenderTargets[i] && (colorRenderTargets[i] != m_state.colorRenderTargets[i]))
|
||||||
|
{
|
||||||
|
needsNewRenderPass = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needsNewRenderPass)
|
||||||
|
{
|
||||||
|
if (depthRenderTarget && (depthRenderTarget != m_state.depthRenderTarget))
|
||||||
|
{
|
||||||
|
needsNewRenderPass = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needsNewRenderPass)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderCommandEncoder = m_commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndEncoding()
|
||||||
|
{
|
||||||
|
if (m_renderCommandEncoder)
|
||||||
|
{
|
||||||
|
m_renderCommandEncoder->endEncoding();
|
||||||
|
m_renderCommandEncoder->release();
|
||||||
|
m_renderCommandEncoder = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommitCommandBuffer()
|
||||||
|
{
|
||||||
|
EndEncoding();
|
||||||
|
|
||||||
|
if (m_commandBuffer)
|
||||||
|
{
|
||||||
|
m_commandBuffer->commit();
|
||||||
|
m_commandBuffer->release();
|
||||||
|
m_commandBuffer = nullptr;
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
m_commandQueue->insertDebugCaptureBoundary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type
|
|||||||
MTL::Library* library = mtlRenderer->GetDevice()->newLibrary(NS::String::string(mslCode.c_str(), NS::ASCIIStringEncoding), nullptr, &error);
|
MTL::Library* library = mtlRenderer->GetDevice()->newLibrary(NS::String::string(mslCode.c_str(), NS::ASCIIStringEncoding), nullptr, &error);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
printf("Failed to create library (error: %s) -> source:\n%s\n", error->localizedDescription()->utf8String(), mslCode.c_str());
|
printf("failed to create library (error: %s) -> source:\n%s\n", error->localizedDescription()->utf8String(), mslCode.c_str());
|
||||||
error->release();
|
error->release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type
|
|||||||
m_function = library->newFunction(desc, &error);
|
m_function = library->newFunction(desc, &error);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
printf("Failed to create function (error: %s)\n", error->localizedDescription()->utf8String());
|
printf("failed to create function (error: %s)\n", error->localizedDescription()->utf8String());
|
||||||
error->release();
|
error->release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
23
src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h
Normal file
23
src/Cafe/HW/Latte/Renderer/Metal/ShaderSourcePresent.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <cmath>
|
||||||
|
const char* presentLibrarySource = \
|
||||||
|
"#include <metal_stdlib>\n" \
|
||||||
|
"using namespace metal;\n" \
|
||||||
|
"\n" \
|
||||||
|
"constant float2 positions[] = {float2(-1.0, -3.0), float2(-1.0, 1.0), float2(3.0, 1.0)};\n"
|
||||||
|
"\n" \
|
||||||
|
"struct VertexOut {\n" \
|
||||||
|
" float4 position [[position]];\n" \
|
||||||
|
" float2 texCoord;\n" \
|
||||||
|
"};\n" \
|
||||||
|
"\n" \
|
||||||
|
"vertex VertexOut presentVertex(ushort vid [[vertex_id]]) {\n" \
|
||||||
|
" VertexOut out;\n" \
|
||||||
|
" out.position = float4(positions[vid], 0.0, 1.0);\n" \
|
||||||
|
" out.texCoord = positions[vid] * 0.5 + 0.5;\n" \
|
||||||
|
"\n" \
|
||||||
|
" return out;\n" \
|
||||||
|
"}\n" \
|
||||||
|
"\n" \
|
||||||
|
"fragment float4 presentFragment(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler samplr [[sampler(0)]]) {\n" \
|
||||||
|
" return tex.sample(samplr, in.texCoord);\n" \
|
||||||
|
"}\n";
|
Loading…
Reference in New Issue
Block a user