mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-01-08 08:00:44 +01:00
start metal backend
This commit is contained in:
parent
4b9c7c0d30
commit
2477bad06b
@ -78,6 +78,7 @@ endif()
|
||||
|
||||
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
|
||||
option(ENABLE_VULKAN "Enables the Vulkan backend" ON)
|
||||
option(ENABLE_METAL "Enables the Metal backend" ON)
|
||||
option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON)
|
||||
|
||||
|
||||
@ -190,9 +191,9 @@ if (ENABLE_WXWIDGETS)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
if (NOT ENABLE_VCPKG)
|
||||
find_package(cubeb)
|
||||
endif()
|
||||
#if (NOT ENABLE_VCPKG)
|
||||
#find_package(cubeb)
|
||||
#endif()
|
||||
if (NOT cubeb_FOUND)
|
||||
option(BUILD_TESTS "" OFF)
|
||||
option(BUILD_TOOLS "" OFF)
|
||||
|
@ -524,6 +524,16 @@ if(APPLE)
|
||||
target_sources(CemuCafe PRIVATE "HW/Latte/Renderer/Vulkan/CocoaSurface.mm")
|
||||
endif()
|
||||
|
||||
if(ENABLE_METAL)
|
||||
if(APPLE)
|
||||
target_sources(CemuCafe PRIVATE
|
||||
HW/Latte/Renderer/Metal/MetalRenderer.cpp
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Metal is only supported on macOS")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
target_include_directories(CemuCafe PUBLIC "../")
|
||||
|
@ -269,6 +269,8 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
m_renderer_api = RendererAPI::Vulkan;
|
||||
else if (boost::iequals(*option_rendererFilter, "opengl"))
|
||||
m_renderer_api = RendererAPI::OpenGL;
|
||||
else if (boost::iequals(*option_rendererFilter, "metal"))
|
||||
m_renderer_api = RendererAPI::Metal;
|
||||
else
|
||||
cemuLog_log(LogType::Force, "Unknown value '{}' for rendererFilter option", *option_rendererFilter);
|
||||
}
|
||||
|
198
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Normal file
198
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
|
||||
void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) {
|
||||
/*
|
||||
const auto& windowInfo = gui_getWindowInfo().window_main;
|
||||
|
||||
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() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::Shutdown() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
bool MetalRenderer::IsPadWindowActive() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::ClearColorbuffer(bool padView) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
bool MetalRenderer::BeginFrame(bool mainWindow) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::Flush(bool waitIdle) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::NotifyLatteCommandProcessorIdle() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_begin() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::streamout_rendererFinishDrawcall() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
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) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::draw_endSequence() {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void* MetalRenderer::indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
||||
|
||||
void MetalRenderer::indexData_uploadIndexMemory(uint32 offset, uint32 size) {
|
||||
cemuLog_logDebug(LogType::Force, "not implemented");
|
||||
}
|
142
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h
Normal file
142
src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h
Normal file
@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
|
||||
class MetalRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
~MetalRenderer() = default;
|
||||
|
||||
RendererAPI GetType() override
|
||||
{
|
||||
return RendererAPI::Metal;
|
||||
}
|
||||
|
||||
static MetalRenderer* GetInstance() {
|
||||
return static_cast<MetalRenderer*>(g_renderer.get());
|
||||
}
|
||||
|
||||
void InitializeLayer(const Vector2i& size, bool mainWindow);
|
||||
|
||||
void Initialize() override;
|
||||
void Shutdown() override;
|
||||
bool IsPadWindowActive() override;
|
||||
|
||||
bool GetVRAMInfo(int& usageInMB, int& totalInMB) const override;
|
||||
|
||||
void ClearColorbuffer(bool padView) override;
|
||||
void DrawEmptyFrame(bool mainWindow) override;
|
||||
void SwapBuffers(bool swapTV, bool swapDRC) override;
|
||||
|
||||
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override {
|
||||
cemuLog_logDebug(LogType::Force, "Screenshots are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
|
||||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground) override;
|
||||
bool BeginFrame(bool mainWindow) override;
|
||||
|
||||
// flush control
|
||||
void Flush(bool waitIdle = false) override; // called when explicit flush is required (e.g. by imgui)
|
||||
void NotifyLatteCommandProcessorIdle() override; // called when command processor has no more commands available or when stalled
|
||||
|
||||
// imgui
|
||||
bool ImguiBegin(bool mainWindow) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void ImguiEnd() override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void DeleteTexture(ImTextureID id) override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void DeleteFontTextures() override {
|
||||
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void AppendOverlayDebugInfo() override;
|
||||
|
||||
// rendertarget
|
||||
void renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) override;
|
||||
void renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) override;
|
||||
|
||||
LatteCachedFBO* rendertarget_createCachedFBO(uint64 key) override;
|
||||
void rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) override;
|
||||
void rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) override;
|
||||
|
||||
// texture functions
|
||||
void* texture_acquireTextureUploadBuffer(uint32 size) override;
|
||||
void texture_releaseTextureUploadBuffer(uint8* mem) override;
|
||||
|
||||
TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;
|
||||
|
||||
void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;
|
||||
void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;
|
||||
void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;
|
||||
void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;
|
||||
|
||||
LatteTexture* 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) override;
|
||||
|
||||
void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override;
|
||||
void 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) override;
|
||||
|
||||
LatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override;
|
||||
|
||||
// surface copy
|
||||
void surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) override;
|
||||
|
||||
// buffer cache
|
||||
void bufferCache_init(const sint32 bufferSize) override;
|
||||
void bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override;
|
||||
void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override;
|
||||
void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;
|
||||
|
||||
void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override;
|
||||
void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;
|
||||
|
||||
// shader
|
||||
RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) override;
|
||||
|
||||
// streamout
|
||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||
void streamout_begin() override;
|
||||
void streamout_rendererFinishDrawcall() override;
|
||||
|
||||
// core drawing logic
|
||||
void draw_beginSequence() override;
|
||||
void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override;
|
||||
void draw_endSequence() override;
|
||||
|
||||
// index
|
||||
void* indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) override;
|
||||
void indexData_uploadIndexMemory(uint32 offset, uint32 size) override;
|
||||
|
||||
// occlusion queries
|
||||
LatteQueryObject* occlusionQuery_create() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_destroy(LatteQueryObject* queryObj) override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_flush() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
void occlusionQuery_updateState() override {
|
||||
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
//CA::MetalLayer* m_metalLayer;
|
||||
};
|
@ -33,6 +33,7 @@ enum class RendererAPI
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
Metal,
|
||||
|
||||
MAX
|
||||
};
|
||||
|
@ -59,6 +59,7 @@ const std::map<LogType, std::string> g_logging_window_mapping
|
||||
{LogType::TextureReadback, "Texture readback"},
|
||||
{LogType::OpenGLLogging, "OpenGL debug output"},
|
||||
{LogType::VulkanValidation, "Vulkan validation layer"},
|
||||
{LogType::MetalLogging, "Metal debug output"},
|
||||
};
|
||||
|
||||
bool cemuLog_advancedPPCLoggingEnabled()
|
||||
|
@ -20,6 +20,7 @@ enum class LogType : sint32
|
||||
OpenGLLogging = 10, // OpenGL debug logging
|
||||
TextureCache = 11, // texture cache warnings and info
|
||||
VulkanValidation = 12, // Vulkan validation layer
|
||||
MetalLogging = 13, // Metal debug logging
|
||||
Patches = 14,
|
||||
CoreinitMem = 8, // coreinit memory functions
|
||||
CoreinitMP = 15,
|
||||
|
@ -74,6 +74,7 @@ enum GraphicAPI
|
||||
{
|
||||
kOpenGL = 0,
|
||||
kVulkan,
|
||||
kMetal,
|
||||
};
|
||||
|
||||
enum AudioChannels
|
||||
@ -530,5 +531,3 @@ struct CemuConfig
|
||||
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
|
||||
extern XMLCemuConfig_t g_config;
|
||||
inline CemuConfig& GetConfig() { return g_config.data(); }
|
||||
|
||||
|
||||
|
@ -4,6 +4,8 @@ add_library(CemuGui
|
||||
canvas/OpenGLCanvas.h
|
||||
canvas/VulkanCanvas.cpp
|
||||
canvas/VulkanCanvas.h
|
||||
canvas/MetalCanvas.cpp
|
||||
canvas/MetalCanvas.h
|
||||
CemuApp.cpp
|
||||
CemuApp.h
|
||||
CemuUpdateWindow.cpp
|
||||
|
@ -112,7 +112,11 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan" };
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan",
|
||||
#ifdef __APPLE__
|
||||
"Metal"
|
||||
#endif
|
||||
};
|
||||
m_graphic_api = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(gapi_values), gapi_values);
|
||||
first_row->Add(m_graphic_api, 0, wxALL, 5);
|
||||
|
||||
|
@ -276,12 +276,14 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
|
||||
row->Add(new wxStaticText(box, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
sint32 api_size = 1;
|
||||
wxString choices[2] = { "OpenGL" };
|
||||
wxString choices[3] = { "OpenGL" };
|
||||
if (g_vulkan_available)
|
||||
{
|
||||
choices[1] = "Vulkan";
|
||||
api_size = 2;
|
||||
choices[api_size++] = "Vulkan";
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
choices[api_size++] = "Metal";
|
||||
#endif
|
||||
|
||||
m_graphic_api = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, api_size, choices);
|
||||
m_graphic_api->SetSelection(0);
|
||||
|
@ -21,7 +21,7 @@ LoggingWindow::LoggingWindow(wxFrame* parent)
|
||||
|
||||
filter_row->Add(new wxStaticText( this, wxID_ANY, _("Filter")), 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer"};
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer", "Metal debug output"};
|
||||
m_filter = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 0 );
|
||||
m_filter->Bind(wxEVT_COMBOBOX, &LoggingWindow::OnFilterChange, this);
|
||||
m_filter->Bind(wxEVT_TEXT, &LoggingWindow::OnFilterChange, this);
|
||||
@ -97,4 +97,3 @@ void LoggingWindow::OnFilterMessageChange(wxCommandEvent& event)
|
||||
m_log_list->SetFilterMessage(m_filter_message->GetValue());
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "audio/audioDebuggerWindow.h"
|
||||
#include "gui/canvas/OpenGLCanvas.h"
|
||||
#include "gui/canvas/VulkanCanvas.h"
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/OS/libs/nfc/nfc.h"
|
||||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "gui/debugger/DebuggerWindow2.h"
|
||||
@ -1567,8 +1568,10 @@ void MainWindow::CreateCanvas()
|
||||
// create canvas
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
|
||||
// mouse events
|
||||
m_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);
|
||||
@ -2227,6 +2230,7 @@ void MainWindow::RecreateMenu()
|
||||
debugLoggingMenu->AppendSeparator();
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), _("&OpenGL debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::OpenGLLogging));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), _("&Vulkan validation layer (slow)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::VulkanValidation));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::MetalLogging), _("&Metal debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::MetalLogging));
|
||||
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, _("&Log PPC context for API"), wxEmptyString)->Check(cemuLog_advancedPPCLoggingEnabled());
|
||||
m_loggingSubmenu = debugLoggingMenu;
|
||||
// debug->dump submenu
|
||||
@ -2296,6 +2300,7 @@ void MainWindow::RecreateMenu()
|
||||
// these options cant be toggled after the renderer backend is initialized:
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), false);
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), false);
|
||||
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::MetalLogging), false);
|
||||
|
||||
UpdateNFCMenu();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "gui/canvas/OpenGLCanvas.h"
|
||||
#include "gui/canvas/VulkanCanvas.h"
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "gui/MainWindow.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
@ -74,8 +75,10 @@ void PadViewFrame::InitializeRenderCanvas()
|
||||
{
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(this, wxSize(854, 480), false);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(this, wxSize(854, 480), false);
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(this, wxSize(854, 480), false);
|
||||
sizer->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);
|
||||
}
|
||||
SetSizer(sizer);
|
||||
|
63
src/gui/canvas/MetalCanvas.cpp
Normal file
63
src/gui/canvas/MetalCanvas.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "gui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "gui/guiWrapper.h"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <helpers/wxHelpers.h>
|
||||
|
||||
MetalCanvas::MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)
|
||||
: IRenderCanvas(is_main_window), wxWindow(parent, wxID_ANY, wxDefaultPosition, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
|
||||
{
|
||||
Bind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Bind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
WindowHandleInfo& canvas = is_main_window ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
|
||||
gui_initHandleContextFromWxWidgetsWindow(canvas, this);
|
||||
|
||||
try
|
||||
{
|
||||
if (is_main_window)
|
||||
g_renderer = std::make_unique<MetalRenderer>();
|
||||
|
||||
auto metal_renderer = MetalRenderer::GetInstance();
|
||||
metal_renderer->InitializeLayer({size.x, size.y}, is_main_window);
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Error when initializing Metal renderer: {}", ex.what());
|
||||
auto msg = formatWxString(_("Error when initializing Metal renderer:\n{}"), ex.what());
|
||||
wxMessageDialog dialog(this, msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
dialog.ShowModal();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);
|
||||
}
|
||||
|
||||
MetalCanvas::~MetalCanvas()
|
||||
{
|
||||
Unbind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Unbind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
if(!m_is_main_window)
|
||||
{
|
||||
// TODO
|
||||
//MetalRenderer* vkr = (MetalRenderer*)g_renderer.get();
|
||||
//if(vkr)
|
||||
// vkr->StopUsingPadAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalCanvas::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
void MetalCanvas::OnResize(wxSizeEvent& event)
|
||||
{
|
||||
const wxSize size = GetSize();
|
||||
if (size.GetWidth() == 0 || size.GetHeight() == 0)
|
||||
return;
|
||||
|
||||
const wxRect refreshRect(size);
|
||||
RefreshRect(refreshRect, false);
|
||||
}
|
19
src/gui/canvas/MetalCanvas.h
Normal file
19
src/gui/canvas/MetalCanvas.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/canvas/IRenderCanvas.h"
|
||||
|
||||
#include <wx/frame.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
class MetalCanvas : public IRenderCanvas, public wxWindow
|
||||
{
|
||||
public:
|
||||
MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);
|
||||
~MetalCanvas();
|
||||
|
||||
private:
|
||||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
};
|
@ -85,6 +85,9 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps)
|
||||
case RendererAPI::Vulkan:
|
||||
renderer = "[Vulkan]";
|
||||
break;
|
||||
case RendererAPI::Metal:
|
||||
renderer = "[Metal]";
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ add_library(imguiImpl
|
||||
imgui_extension.h
|
||||
)
|
||||
|
||||
# TODO: add Metal
|
||||
|
||||
set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
target_include_directories(imguiImpl PUBLIC "../")
|
||||
|
Loading…
Reference in New Issue
Block a user