mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-15 03:08:28 +12:00
add: ImGui support
This commit is contained in:
parent
d4a1074425
commit
7499c3fbe7
7 changed files with 805 additions and 43 deletions
|
@ -16,6 +16,8 @@ MetalLayerHandle::~MetalLayerHandle()
|
|||
{
|
||||
if (m_layer)
|
||||
m_layer->release();
|
||||
if (m_renderPassDescriptor)
|
||||
m_renderPassDescriptor->release();
|
||||
}
|
||||
|
||||
void MetalLayerHandle::Resize(const Vector2i& size)
|
||||
|
@ -35,9 +37,27 @@ bool MetalLayerHandle::AcquireDrawable()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_renderPassDescriptor)
|
||||
{
|
||||
m_renderPassDescriptor->release();
|
||||
m_renderPassDescriptor = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetalLayerHandle::CreateRenderPassDescriptor(bool clear)
|
||||
{
|
||||
if (m_renderPassDescriptor)
|
||||
m_renderPassDescriptor->release();
|
||||
|
||||
m_renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
auto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(0);
|
||||
colorAttachment->setTexture(m_drawable->texture());
|
||||
colorAttachment->setLoadAction(clear ? MTL::LoadActionClear : MTL::LoadActionLoad);
|
||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||
}
|
||||
|
||||
void MetalLayerHandle::PresentDrawable(MTL::CommandBuffer* commandBuffer)
|
||||
{
|
||||
commandBuffer->presentDrawable(m_drawable);
|
||||
|
|
|
@ -19,15 +19,20 @@ public:
|
|||
|
||||
bool AcquireDrawable();
|
||||
|
||||
void CreateRenderPassDescriptor(bool clear);
|
||||
|
||||
void PresentDrawable(MTL::CommandBuffer* commandBuffer);
|
||||
|
||||
CA::MetalLayer* GetLayer() const { return m_layer; }
|
||||
|
||||
CA::MetalDrawable* GetDrawable() const { return m_drawable; }
|
||||
|
||||
MTL::RenderPassDescriptor* GetRenderPassDescriptor() const { return m_renderPassDescriptor; }
|
||||
|
||||
private:
|
||||
CA::MetalLayer* m_layer = nullptr;
|
||||
float m_layerScaleX, m_layerScaleY;
|
||||
|
||||
CA::MetalDrawable* m_drawable = nullptr;
|
||||
MTL::RenderPassDescriptor* m_renderPassDescriptor = nullptr;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,12 @@
|
|||
#include "HW/Latte/Core/LatteConst.h"
|
||||
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||
#include "HW/Latte/Renderer/Metal/MetalLayerHandle.h"
|
||||
#include "gui/guiWrapper.h"
|
||||
#include "HW/Latte/Renderer/Renderer.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#define IMGUI_IMPL_METAL_CPP
|
||||
#include "imgui/imgui_extension.h"
|
||||
#include "imgui/imgui_impl_metal.h"
|
||||
|
||||
#define COMMIT_TRESHOLD 256
|
||||
|
||||
|
@ -191,6 +196,8 @@ void MetalRenderer::Initialize()
|
|||
|
||||
void MetalRenderer::Shutdown()
|
||||
{
|
||||
// TODO: should shutdown both layers
|
||||
ImGui_ImplMetal_Shutdown();
|
||||
Renderer::Shutdown();
|
||||
CommitCommandBuffer();
|
||||
}
|
||||
|
@ -205,7 +212,7 @@ bool MetalRenderer::IsPadWindowActive()
|
|||
|
||||
bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const
|
||||
{
|
||||
usageInMB = m_device->currentAllocatedSize();
|
||||
usageInMB = m_device->currentAllocatedSize() / 1024 / 1024;
|
||||
totalInMB = usageInMB;
|
||||
|
||||
return true;
|
||||
|
@ -213,7 +220,7 @@ bool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const
|
|||
|
||||
void MetalRenderer::ClearColorbuffer(bool padView)
|
||||
{
|
||||
if (!AcquireNextDrawable(!padView))
|
||||
if (!AcquireDrawable(!padView))
|
||||
return;
|
||||
|
||||
ClearColorTextureInternal(GetLayer(!padView).GetDrawable()->texture(), 0, 0, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
@ -248,21 +255,16 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
|
|||
sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,
|
||||
bool padView, bool clearBackground)
|
||||
{
|
||||
if (!AcquireNextDrawable(!padView))
|
||||
if (!AcquireDrawable(!padView))
|
||||
return;
|
||||
|
||||
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView();
|
||||
|
||||
// Create render pass
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
||||
colorAttachment->setTexture(GetLayer(!padView).GetDrawable()->texture());
|
||||
// TODO: shouldn't it be LoadActionLoad when not clearing?
|
||||
colorAttachment->setLoadAction(clearBackground ? MTL::LoadActionClear : MTL::LoadActionDontCare);
|
||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||
auto& layer = GetLayer(!padView);
|
||||
layer.CreateRenderPassDescriptor(clearBackground);
|
||||
|
||||
auto renderCommandEncoder = GetTemporaryRenderCommandEncoder(renderPassDescriptor);
|
||||
renderPassDescriptor->release();
|
||||
auto renderCommandEncoder = GetTemporaryRenderCommandEncoder(layer.GetRenderPassDescriptor());
|
||||
|
||||
// Draw to Metal layer
|
||||
renderCommandEncoder->setRenderPipelineState(m_state.m_usesSRGB ? m_presentPipelineSRGB : m_presentPipelineLinear);
|
||||
|
@ -279,14 +281,14 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
|
|||
|
||||
bool MetalRenderer::BeginFrame(bool mainWindow)
|
||||
{
|
||||
return AcquireNextDrawable(mainWindow);
|
||||
return AcquireDrawable(mainWindow);
|
||||
}
|
||||
|
||||
void MetalRenderer::Flush(bool waitIdle)
|
||||
{
|
||||
if (m_recordedDrawcalls > 0)
|
||||
CommitCommandBuffer();
|
||||
if (waitIdle)
|
||||
if (waitIdle && m_commandBuffers.size() != 0)
|
||||
{
|
||||
// TODO: shouldn't we wait for all command buffers?
|
||||
WaitForCommandBufferCompletion(GetCurrentCommandBuffer());
|
||||
|
@ -299,9 +301,101 @@ void MetalRenderer::NotifyLatteCommandProcessorIdle()
|
|||
// CommitCommandBuffer();
|
||||
}
|
||||
|
||||
bool MetalRenderer::ImguiBegin(bool mainWindow)
|
||||
{
|
||||
EnsureImGuiBackend();
|
||||
|
||||
if (!Renderer::ImguiBegin(mainWindow))
|
||||
return false;
|
||||
|
||||
if (!AcquireDrawable(mainWindow))
|
||||
return false;
|
||||
|
||||
auto& layer = GetLayer(mainWindow);
|
||||
if (!layer.GetRenderPassDescriptor())
|
||||
layer.CreateRenderPassDescriptor(true); // TODO: should we clear?
|
||||
|
||||
ImGui_ImplMetal_CreateFontsTexture(m_device);
|
||||
ImGui_ImplMetal_NewFrame(layer.GetRenderPassDescriptor());
|
||||
ImGui_UpdateWindowInformation(mainWindow);
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (m_encoderType != MetalEncoderType::Render)
|
||||
GetTemporaryRenderCommandEncoder(layer.GetRenderPassDescriptor());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetalRenderer::ImguiEnd()
|
||||
{
|
||||
EnsureImGuiBackend();
|
||||
|
||||
if (m_encoderType != MetalEncoderType::Render)
|
||||
{
|
||||
debug_printf("no render command encoder, cannot draw ImGui\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), GetCurrentCommandBuffer(), (MTL::RenderCommandEncoder*)m_commandEncoder);
|
||||
//ImGui::EndFrame();
|
||||
|
||||
EndEncoding();
|
||||
}
|
||||
|
||||
ImTextureID MetalRenderer::GenerateTexture(const std::vector<uint8>& data, const Vector2i& size)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector <uint8> tmp(size.x * size.y * 4);
|
||||
for (size_t i = 0; i < data.size() / 3; ++i)
|
||||
{
|
||||
tmp[(i * 4) + 0] = data[(i * 3) + 0];
|
||||
tmp[(i * 4) + 1] = data[(i * 3) + 1];
|
||||
tmp[(i * 4) + 2] = data[(i * 3) + 2];
|
||||
tmp[(i * 4) + 3] = 0xFF;
|
||||
}
|
||||
|
||||
MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();
|
||||
desc->setTextureType(MTL::TextureType2D);
|
||||
desc->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
||||
desc->setWidth(size.x);
|
||||
desc->setHeight(size.y);
|
||||
desc->setStorageMode(MTL::StorageModeShared);
|
||||
desc->setUsage(MTL::TextureUsageShaderRead);
|
||||
|
||||
MTL::Texture* texture = m_device->newTexture(desc);
|
||||
desc->release();
|
||||
|
||||
// TODO: do a GPU copy?
|
||||
texture->replaceRegion(MTL::Region(0, 0, size.x, size.y), 0, 0, tmp.data(), size.x * 4, 0);
|
||||
|
||||
return (ImTextureID)texture;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "can't generate imgui texture: {}", ex.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalRenderer::DeleteTexture(ImTextureID id)
|
||||
{
|
||||
EnsureImGuiBackend();
|
||||
|
||||
((MTL::Texture*)id)->release();
|
||||
}
|
||||
|
||||
void MetalRenderer::DeleteFontTextures()
|
||||
{
|
||||
EnsureImGuiBackend();
|
||||
|
||||
ImGui_ImplMetal_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
void MetalRenderer::AppendOverlayDebugInfo()
|
||||
{
|
||||
debug_printf("MetalRenderer::AppendOverlayDebugInfo not implemented\n");
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// TODO: halfZ
|
||||
|
@ -1336,7 +1430,7 @@ void MetalRenderer::CommitCommandBuffer()
|
|||
}
|
||||
}
|
||||
|
||||
bool MetalRenderer::AcquireNextDrawable(bool mainWindow)
|
||||
bool MetalRenderer::AcquireDrawable(bool mainWindow)
|
||||
{
|
||||
auto& layer = GetLayer(mainWindow);
|
||||
|
||||
|
@ -1616,11 +1710,11 @@ void MetalRenderer::ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 s
|
|||
EndEncoding();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MetalRenderer::SwapBuffer(bool mainWindow)
|
||||
{
|
||||
auto& layer = GetLayer(mainWindow);
|
||||
if (!layer.AcquireDrawable())
|
||||
return;
|
||||
|
||||
if (layer.GetDrawable())
|
||||
{
|
||||
|
@ -1632,3 +1726,12 @@ void MetalRenderer::SwapBuffer(bool mainWindow)
|
|||
debug_printf("skipped present!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MetalRenderer::EnsureImGuiBackend()
|
||||
{
|
||||
if (!ImGui::GetIO().BackendRendererUserData)
|
||||
{
|
||||
ImGui_ImplMetal_Init(m_device);
|
||||
//ImGui_ImplMetal_CreateFontsTexture(m_device);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,29 +228,11 @@ public:
|
|||
void NotifyLatteCommandProcessorIdle() override; // called when command processor has no more commands available or when stalled
|
||||
|
||||
// imgui
|
||||
bool ImguiBegin(bool mainWindow) override {
|
||||
cemuLog_log(LogType::MetalLogging, "Imgui is not yet supported on Metal");
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
void ImguiEnd() override {
|
||||
cemuLog_log(LogType::MetalLogging, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override {
|
||||
cemuLog_log(LogType::MetalLogging, "Imgui is not yet supported on Metal");
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
void DeleteTexture(ImTextureID id) override {
|
||||
cemuLog_log(LogType::MetalLogging, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
|
||||
void DeleteFontTextures() override {
|
||||
cemuLog_log(LogType::MetalLogging, "Imgui is not yet supported on Metal");
|
||||
};
|
||||
bool ImguiBegin(bool mainWindow) override;
|
||||
void ImguiEnd() override;
|
||||
ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override;
|
||||
void DeleteTexture(ImTextureID id) override;
|
||||
void DeleteFontTextures() override;
|
||||
|
||||
bool UseTFViaSSBO() const override { return true; }
|
||||
void AppendOverlayDebugInfo() override;
|
||||
|
@ -383,7 +365,7 @@ public:
|
|||
void EndEncoding();
|
||||
void CommitCommandBuffer();
|
||||
|
||||
bool AcquireNextDrawable(bool mainWindow);
|
||||
bool AcquireDrawable(bool mainWindow);
|
||||
|
||||
bool CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader);
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader);
|
||||
|
@ -479,4 +461,6 @@ private:
|
|||
}
|
||||
|
||||
void SwapBuffer(bool mainWindow);
|
||||
|
||||
void EnsureImGuiBackend();
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue