diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index ce6738d8..379b9857 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -521,7 +521,10 @@ add_library(CemuCafe ) if(APPLE) - target_sources(CemuCafe PRIVATE "HW/Latte/Renderer/Vulkan/CocoaSurface.mm") + target_sources(CemuCafe PRIVATE + HW/Latte/Renderer/Vulkan/CocoaSurface.mm + HW/Latte/Renderer/MetalView.mm + ) endif() if(ENABLE_METAL) @@ -530,6 +533,8 @@ if(ENABLE_METAL) HW/Latte/Renderer/Metal/MetalRenderer.cpp HW/Latte/Renderer/Metal/MetalRenderer.h HW/Latte/Renderer/Metal/MetalCppImpl.cpp + HW/Latte/Renderer/Metal/MetalLayer.mm + HW/Latte/Renderer/Metal/MetalLayer.h HW/Latte/Renderer/Metal/LatteTextureMtl.cpp HW/Latte/Renderer/Metal/LatteTextureMtl.h HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp index d2c41b73..4e053821 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp @@ -65,6 +65,7 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM } m_texture = mtlRenderer->GetDevice()->newTexture(desc); + desc->release(); } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.h new file mode 100644 index 00000000..56a30224 --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.h @@ -0,0 +1,3 @@ +#pragma once + +void* CreateMetalLayer(void* handle); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.mm b/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.mm new file mode 100644 index 00000000..8ce3202e --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.mm @@ -0,0 +1,16 @@ +#include "Cafe/HW/Latte/Renderer/Metal/MetalLayer.h" + +#include "Cafe/HW/Latte/Renderer/MetalView.h" + +void* CreateMetalLayer(void* handle) +{ + NSView* view = (NSView*)handle; + + MetalView* childView = [[MetalView alloc] initWithFrame:view.bounds]; + childView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + childView.wantsLayer = YES; + + [view addSubview:childView]; + + return childView.layer; +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 8e203c50..cdd3b05c 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -1,43 +1,48 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" - +#include "Cafe/HW/Latte/Renderer/Metal/MetalLayer.h" #include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h" -void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) { - /* - const auto& windowInfo = gui_getWindowInfo().window_main; +#include "gui/guiWrapper.h" - NSView* view = (NS::View*)handle; - - MetalView* childView = [[MetalView alloc] initWithFrame:view.bounds]; - childView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - childView.wantsLayer = YES; - - [view addSubview:childView]; - - VkMetalSurfaceCreateInfoEXT surface; - surface.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - surface.pNext = NULL; - surface.flags = 0; - surface.pLayer = (CAMetalLayer*)childView.layer; - */ -} - -void MetalRenderer::Initialize() { +MetalRenderer::MetalRenderer() +{ m_device = MTL::CreateSystemDefaultDevice(); m_commandQueue = m_device->newCommandQueue(); } -void MetalRenderer::Shutdown() { +MetalRenderer::~MetalRenderer() +{ + m_commandQueue->release(); + m_device->release(); +} + +// TODO: don't ignore "mainWindow" argument +void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) +{ + const auto& windowInfo = gui_getWindowInfo().window_main; + + m_metalLayer = (CA::MetalLayer*)CreateMetalLayer(windowInfo.handle); + m_metalLayer->setDevice(m_device); +} + +void MetalRenderer::Initialize() +{ +} + +void MetalRenderer::Shutdown() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -bool MetalRenderer::IsPadWindowActive() { +bool MetalRenderer::IsPadWindowActive() +{ cemuLog_logDebug(LogType::Force, "not implemented"); return false; } -bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const { +bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const +{ cemuLog_logDebug(LogType::Force, "not implemented"); usageInMB = 1024; @@ -46,177 +51,228 @@ bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const { return false; } -void MetalRenderer::ClearColorbuffer(bool padView) { +void MetalRenderer::ClearColorbuffer(bool padView) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::DrawEmptyFrame(bool mainWindow) { +void MetalRenderer::DrawEmptyFrame(bool mainWindow) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC) { - cemuLog_logDebug(LogType::Force, "not implemented"); +void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC) +{ + CA::MetalDrawable* drawable = m_metalLayer->nextDrawable(); + if (!drawable) + { + return; + } + + MTL::CommandBuffer* commandBuffer = m_commandQueue->commandBuffer(); + commandBuffer->presentDrawable(drawable); + commandBuffer->commit(); + + commandBuffer->release(); } void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, - bool padView, bool clearBackground) { + bool padView, bool clearBackground) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -bool MetalRenderer::BeginFrame(bool mainWindow) { + +bool MetalRenderer::BeginFrame(bool mainWindow) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return false; } -void MetalRenderer::Flush(bool waitIdle) { +void MetalRenderer::Flush(bool waitIdle) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::NotifyLatteCommandProcessorIdle() { +void MetalRenderer::NotifyLatteCommandProcessorIdle() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::AppendOverlayDebugInfo() { +void MetalRenderer::AppendOverlayDebugInfo() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ) { +void MetalRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) { +void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) { +LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) { +void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) { +void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) { +void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem) { +void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -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) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) { +void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) { +void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) { +void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) { +void MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -LatteTexture* MetalRenderer::texture_createTextureEx(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) { +LatteTexture* MetalRenderer::texture_createTextureEx(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) +{ return new LatteTextureMtl(this, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); } -void MetalRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) { +void MetalRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) { +void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView) { +LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -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) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::bufferCache_init(const sint32 bufferSize) { +void MetalRenderer::bufferCache_init(const sint32 bufferSize) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) { +void MetalRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) { +void MetalRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) { +void MetalRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) { +void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) { +void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) { +RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -void MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) { +void MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::streamout_begin() { +void MetalRenderer::streamout_begin() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::streamout_rendererFinishDrawcall() { +void MetalRenderer::streamout_rendererFinishDrawcall() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::draw_beginSequence() { +void MetalRenderer::draw_beginSequence() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -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) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void MetalRenderer::draw_endSequence() { +void MetalRenderer::draw_endSequence() +{ cemuLog_logDebug(LogType::Force, "not implemented"); } -void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) { +void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) +{ cemuLog_logDebug(LogType::Force, "not implemented"); return nullptr; } -void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size) { +void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size) +{ cemuLog_logDebug(LogType::Force, "not implemented"); } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index dd214a9c..4cc06f57 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -9,7 +9,8 @@ class MetalRenderer : public Renderer { public: - ~MetalRenderer() = default; + MetalRenderer(); + ~MetalRenderer() override; RendererAPI GetType() override { diff --git a/src/Cafe/HW/Latte/Renderer/MetalView.h b/src/Cafe/HW/Latte/Renderer/MetalView.h new file mode 100644 index 00000000..43e5c7b3 --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/MetalView.h @@ -0,0 +1,7 @@ +#pragma once + +#import +#import + +@interface MetalView : NSView +@end diff --git a/src/Cafe/HW/Latte/Renderer/MetalView.mm b/src/Cafe/HW/Latte/Renderer/MetalView.mm new file mode 100644 index 00000000..5ca17b5e --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/MetalView.mm @@ -0,0 +1,26 @@ +#include "Cafe/HW/Latte/Renderer/MetalView.h" + +@implementation MetalView + +-(BOOL) wantsUpdateLayer { return YES; } + ++(Class) layerClass { return [CAMetalLayer class]; } + +// copied from https://github.com/KhronosGroup/MoltenVK/blob/master/Demos/Cube/macOS/DemoViewController.m + +-(CALayer*) makeBackingLayer +{ + CALayer* layer = [self.class.layerClass layer]; + CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; + layer.contentsScale = MIN(viewScale.width, viewScale.height); + return layer; +} + +-(BOOL) layer: (CALayer *)layer shouldInheritContentsScale: (CGFloat)newScale fromWindow: (NSWindow *)window +{ + if (newScale == layer.contentsScale) { return NO; } + + layer.contentsScale = newScale; + return YES; +} +@end diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm b/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm index 731a6a26..a68174c9 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm @@ -1,36 +1,7 @@ #include "Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h" -#import -#import - -@interface MetalView : NSView -@end - -@implementation MetalView - --(BOOL) wantsUpdateLayer { return YES; } - -+(Class) layerClass { return [CAMetalLayer class]; } - -// copied from https://github.com/KhronosGroup/MoltenVK/blob/master/Demos/Cube/macOS/DemoViewController.m - --(CALayer*) makeBackingLayer -{ - CALayer* layer = [self.class.layerClass layer]; - CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; - layer.contentsScale = MIN(viewScale.width, viewScale.height); - return layer; -} - --(BOOL) layer: (CALayer *)layer shouldInheritContentsScale: (CGFloat)newScale fromWindow: (NSWindow *)window -{ - if (newScale == layer.contentsScale) { return NO; } - - layer.contentsScale = newScale; - return YES; -} -@end +#include "Cafe/HW/Latte/Renderer/MetalView.h" VkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle) {