initialize Metal

This commit is contained in:
Samuliak 2024-07-25 12:53:24 +02:00
parent 2477bad06b
commit 98370260d3
10 changed files with 220 additions and 26 deletions

3
.gitmodules vendored
View File

@ -16,3 +16,6 @@
[submodule "dependencies/imgui"]
path = dependencies/imgui
url = https://github.com/ocornut/imgui
[submodule "dependencies/metal-cpp"]
path = dependencies/metal-cpp
url = https://github.com/bkaradzic/metal-cpp.git

View File

@ -166,6 +166,11 @@ if (ENABLE_OPENGL)
find_package(OpenGL REQUIRED)
endif()
# TODO: handle this differently?
if (ENABLE_METAL AND APPLE)
include_directories(${CMAKE_SOURCE_DIR}/dependencies/metal-cpp)
endif()
if (ENABLE_DISCORD_RPC)
add_compile_definitions(ENABLE_DISCORD_RPC)
add_subdirectory(dependencies/discord-rpc EXCLUDE_FROM_ALL)

1
dependencies/metal-cpp vendored Submodule

@ -0,0 +1 @@
Subproject commit a63bd172ddcba73a3d87ca32032b66ad41ddb9a6

View File

@ -528,7 +528,16 @@ if(ENABLE_METAL)
if(APPLE)
target_sources(CemuCafe PRIVATE
HW/Latte/Renderer/Metal/MetalRenderer.cpp
HW/Latte/Renderer/Metal/MetalRenderer.h
HW/Latte/Renderer/Metal/MetalCppImpl.cpp
HW/Latte/Renderer/Metal/LatteTextureMtl.cpp
HW/Latte/Renderer/Metal/LatteTextureMtl.h
)
#target_link_libraries(CemuCafe PRIVATE
# "-framework Metal"
# "-framework QuartzCore"
#)
else()
message(FATAL_ERROR "Metal is only supported on macOS")
endif()

View File

@ -0,0 +1,92 @@
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
//#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
LatteTextureMtl::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)
: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer)
{
MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();
sint32 effectiveBaseWidth = width;
sint32 effectiveBaseHeight = height;
sint32 effectiveBaseDepth = depth;
if (overwriteInfo.hasResolutionOverwrite)
{
effectiveBaseWidth = overwriteInfo.width;
effectiveBaseHeight = overwriteInfo.height;
effectiveBaseDepth = overwriteInfo.depth;
}
effectiveBaseDepth = std::max(1, effectiveBaseDepth);
desc->setWidth(effectiveBaseWidth);
desc->setHeight(effectiveBaseHeight);
desc->setMipmapLevelCount(mipLevels);
if (dim == Latte::E_DIM::DIM_3D)
{
desc->setDepth(effectiveBaseDepth);
}
else
{
desc->setArrayLength(effectiveBaseDepth);
}
// TODO: uncomment
//MetalRenderer::FormatInfoMTL texFormatInfo;
//mtlRenderer->GetTextureFormatInfoMTL(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo);
//cemu_assert_debug(hasStencil == ((texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0));
//imageInfo.format = texFormatInfo.mtlPixelFormat;
desc->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
// TODO: is write needed?
MTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite;
// TODO: add more conditions
if (Latte::IsCompressedFormat(format) == false)
{
usage |= MTL::TextureUsageRenderTarget;
}
desc->setUsage(usage);
if (dim == Latte::E_DIM::DIM_2D)
desc->setTextureType(MTL::TextureType2D);
else if (dim == Latte::E_DIM::DIM_1D)
desc->setTextureType(MTL::TextureType1D);
else if (dim == Latte::E_DIM::DIM_3D)
desc->setTextureType(MTL::TextureType3D);
else if (dim == Latte::E_DIM::DIM_2D_ARRAY)
desc->setTextureType(MTL::TextureType2DArray);
else if (dim == Latte::E_DIM::DIM_CUBEMAP)
desc->setTextureType(MTL::TextureTypeCube); // TODO: is this correct?
else if (dim == Latte::E_DIM::DIM_2D_MSAA)
desc->setTextureType(MTL::TextureType2D);
else
{
cemu_assert_unimplemented();
}
m_texture = mtlRenderer->GetDevice()->newTexture(desc);
desc->release();
}
LatteTextureMtl::~LatteTextureMtl()
{
m_texture->release();
}
LatteTextureView* LatteTextureMtl::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
{
cemu_assert_debug(mipCount > 0);
cemu_assert_debug(sliceCount > 0);
cemu_assert_debug((firstMip + mipCount) <= this->mipLevels);
cemu_assert_debug((firstSlice + sliceCount) <= this->depth);
//return new LatteTextureViewMtl(m_mtlr, this, dim, format, firstMip, mipCount, firstSlice, sliceCount);
cemuLog_logDebug(LogType::Force, "not implemented");
return nullptr;
}
void LatteTextureMtl::AllocateOnHost()
{
cemuLog_logDebug(LogType::Force, "not implemented");
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <Metal/Metal.hpp>
#include "Cafe/HW/Latte/Core/LatteTexture.h"
#include "util/ChunkedHeap/ChunkedHeap.h"
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,
uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);
~LatteTextureMtl();
void AllocateOnHost() override;
protected:
LatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override;
public:
uint64 m_vkFlushIndex{}; // used to track read-write dependencies within the same renderpass
uint64 m_vkFlushIndex_read{};
uint64 m_vkFlushIndex_write{};
uint32 m_collisionCheckIndex{}; // used to track if texture is being both sampled and output to during drawcall
private:
class MetalRenderer* m_mtlr;
MTL::Texture* m_texture;
};

View File

@ -0,0 +1,6 @@
#define NS_PRIVATE_IMPLEMENTATION
#define CA_PRIVATE_IMPLEMENTATION
#define MTL_PRIVATE_IMPLEMENTATION
#include <Foundation/Foundation.hpp>
#include <QuartzCore/QuartzCore.hpp>
#include <Metal/Metal.hpp>

View File

@ -1,5 +1,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) {
/*
const auto& windowInfo = gui_getWindowInfo().window_main;
@ -21,7 +23,8 @@ void MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow) {
}
void MetalRenderer::Initialize() {
cemuLog_logDebug(LogType::Force, "not implemented");
m_device = MTL::CreateSystemDefaultDevice();
m_commandQueue = m_device->newCommandQueue();
}
void MetalRenderer::Shutdown() {
@ -30,10 +33,17 @@ void MetalRenderer::Shutdown() {
bool MetalRenderer::IsPadWindowActive() {
cemuLog_logDebug(LogType::Force, "not implemented");
return false;
}
bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const {
cemuLog_logDebug(LogType::Force, "not implemented");
usageInMB = 1024;
totalInMB = 1024;
return false;
}
void MetalRenderer::ClearColorbuffer(bool padView) {
@ -55,6 +65,8 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
}
bool MetalRenderer::BeginFrame(bool mainWindow) {
cemuLog_logDebug(LogType::Force, "not implemented");
return false;
}
void MetalRenderer::Flush(bool waitIdle) {
@ -79,6 +91,8 @@ void MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, si
LatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key) {
cemuLog_logDebug(LogType::Force, "not implemented");
return nullptr;
}
void MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) {
@ -91,6 +105,8 @@ void MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) {
void* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size) {
cemuLog_logDebug(LogType::Force, "not implemented");
return nullptr;
}
void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem) {
@ -99,6 +115,8 @@ void MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem) {
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) {
@ -118,7 +136,7 @@ void MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sl
}
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");
return new LatteTextureMtl(this, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);
}
void MetalRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) {
@ -131,6 +149,8 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
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) {
@ -163,6 +183,8 @@ void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType,
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) {
@ -191,6 +213,8 @@ void MetalRenderer::draw_endSequence() {
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) {

View File

@ -1,5 +1,9 @@
#pragma once
#include <Foundation/Foundation.hpp>
#include <QuartzCore/QuartzCore.hpp>
#include <Metal/Metal.hpp>
#include "Cafe/HW/Latte/Renderer/Renderer.h"
class MetalRenderer : public Renderer
@ -16,6 +20,11 @@ public:
return static_cast<MetalRenderer*>(g_renderer.get());
}
// Helper functions
MTL::Device* GetDevice() const {
return m_device;
}
void InitializeLayer(const Vector2i& size, bool mainWindow);
void Initialize() override;
@ -44,6 +53,8 @@ public:
// imgui
bool ImguiBegin(bool mainWindow) override {
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
return false;
};
void ImguiEnd() override {
@ -52,6 +63,8 @@ public:
ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override {
cemuLog_logDebug(LogType::Force, "Imgui is not yet supported on Metal");
return nullptr;
};
void DeleteTexture(ImTextureID id) override {
@ -122,6 +135,8 @@ public:
// occlusion queries
LatteQueryObject* occlusionQuery_create() override {
cemuLog_logDebug(LogType::Force, "Occlusion queries are not yet supported on Metal");
return nullptr;
}
void occlusionQuery_destroy(LatteQueryObject* queryObj) override {
@ -137,6 +152,10 @@ public:
}
protected:
//CA::MetalLayer* m_metalLayer;
private:
CA::MetalLayer* m_metalLayer;
// Metal objects
MTL::Device* m_device;
MTL::CommandQueue* m_commandQueue;
};

View File

@ -359,7 +359,7 @@ void RendererOutputShader::InitializeStatic()
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);
}
else
else if (g_renderer->GetType() == RendererAPI::Vulkan)
{
vertex_source = GetVulkanVertexSource(false);
vertex_source_ud = GetVulkanVertexSource(true);
@ -372,5 +372,7 @@ void RendererOutputShader::InitializeStatic()
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);*/
} else {
cemuLog_logDebug(LogType::Force, "Output shader not implemented for Metal");
}
}