Skip to content

Commit

Permalink
Initial ImGui Driver
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacMarovitz committed Dec 29, 2024
1 parent b734a91 commit eef9d80
Show file tree
Hide file tree
Showing 18 changed files with 1,080 additions and 17 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1478,7 +1478,9 @@ if(APPLE AND USE_METAL)
core/rend/metal/metal_shaders.h
core/rend/metal/metal_shaders.cpp
core/rend/metal/metal_texture.h
core/rend/metal/metal_texture.cpp)
core/rend/metal/metal_texture.cpp
core/deps/imgui/backends/imgui_impl_metal.h
core/deps/imgui/backends/imgui_impl_metal.mm)
endif()

if(WIN32 AND USE_DX9 AND NOT LIBRETRO AND NOT WINDOWS_STORE AND ("x86" IN_LIST ARCHITECTURE OR "x86_64" IN_LIST ARCHITECTURE))
Expand Down
2 changes: 2 additions & 0 deletions core/cfg/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ class RendererOption : public Option<RenderType> {
RenderType::DirectX11
#elif defined(USE_DX9)
RenderType::DirectX9
#elif defined(USE_METAL)
RenderType::Metal
#elif !defined(USE_OPENGL)
RenderType::Vulkan
#else
Expand Down
74 changes: 74 additions & 0 deletions core/deps/imgui/backends/imgui_impl_metal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// dear imgui: Renderer Backend for Metal
// This needs to be used along with a Platform Backend (e.g. OSX)

// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).

// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp

#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE

//-----------------------------------------------------------------------------
// ObjC API
//-----------------------------------------------------------------------------

#ifdef __OBJC__

@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;

// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
id<MTLCommandBuffer> commandBuffer,
id<MTLRenderCommandEncoder> commandEncoder);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();

#endif

//-----------------------------------------------------------------------------
// C++ API
//-----------------------------------------------------------------------------

// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/

#ifdef IMGUI_IMPL_METAL_CPP
#include <Metal/Metal.hpp>
#ifndef __OBJC__

// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
MTL::CommandBuffer* commandBuffer,
MTL::RenderCommandEncoder* commandEncoder);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();

#endif
#endif

//-----------------------------------------------------------------------------

#endif // #ifndef IMGUI_DISABLE
592 changes: 592 additions & 0 deletions core/deps/imgui/backends/imgui_impl_metal.mm

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions core/deps/imgui/imconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

#pragma once


#ifdef USE_METAL
#define IMGUI_IMPL_METAL_CPP
#endif

//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
Expand Down
6 changes: 6 additions & 0 deletions core/hw/pvr/Renderer_if.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ Renderer* rend_norend();
Renderer* rend_Vulkan();
Renderer* rend_OITVulkan();
Renderer* rend_DirectX9();
Renderer* rend_Metal();
Renderer* rend_DirectX11();
Renderer* rend_OITDirectX11();

Expand Down Expand Up @@ -302,6 +303,11 @@ static void rend_create_renderer()
renderer = rend_DirectX9();
break;
#endif
#ifdef USE_METAL
case RenderType::Metal:
renderer = rend_Metal();
break;
#endif
#ifdef USE_DX11
case RenderType::DirectX11:
renderer = rend_DirectX11();
Expand Down
55 changes: 55 additions & 0 deletions core/rend/metal/metal_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,58 @@ Copyright 2024 flyinghead
*/

#include "metal_context.h"
#include "metal_driver.h"
#include "sdl/sdl.h"
#include "ui/imgui_driver.h"

MetalContext *MetalContext::contextInstance;

bool MetalContext::init() {
GraphicsContext::instance = this;

#if defined(USE_SDL)
if (!sdl_recreate_window(SDL_WINDOW_METAL))
return false;

auto view = SDL_Metal_CreateView((SDL_Window *)window);

if (view == nullptr) {
term();
ERROR_LOG(RENDERER, "Failed to create SDL Metal View");
return false;
}

layer = static_cast<CA::MetalLayer *>(SDL_Metal_GetLayer(view));
#endif

if (!device) {
term();
NOTICE_LOG(RENDERER, "Metal Device is null.");
return false;
}

NOTICE_LOG(RENDERER, "Created Metal view.");

imguiDriver = std::unique_ptr<ImGuiDriver>(new MetalDriver());
return true;
}

void MetalContext::resize() {

}

void MetalContext::term() {
GraphicsContext::instance = nullptr;
imguiDriver.reset();
}

MetalContext::MetalContext() {
verify(contextInstance == nullptr);
contextInstance = this;
}

MetalContext::~MetalContext() {
verify(contextInstance == this);
contextInstance = nullptr;
}

42 changes: 41 additions & 1 deletion core/rend/metal/metal_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,44 @@ Copyright 2024 flyinghead
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#pragma once
#include <Metal/Metal.hpp>
#include <QuartzCore/QuartzCore.hpp>

#include "wsi/context.h"

class MetalContext : public GraphicsContext
{
public:
MetalContext();
~MetalContext() override;

bool init();
void term() override;

MTL::Device* GetDevice() const { return device; }

void resize() override;

std::string getDriverName() override {
return device->name()->utf8String();
}

std::string getDriverVersion() override {
return "";
}

bool isAMD() override {
return false;
}

bool hasPerPixel() override {
return true;
}

static MetalContext* Instance() { return contextInstance; }
private:
MTL::Device* device = MTL::CreateSystemDefaultDevice();
CA::MetalLayer* layer;
static MetalContext* contextInstance;
};
19 changes: 19 additions & 0 deletions core/rend/metal/metal_driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Copyright 2024 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "metal_driver.h"
81 changes: 81 additions & 0 deletions core/rend/metal/metal_driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
Copyright 2024 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui/imgui_driver.h"
#include "imgui_impl_metal.h"
#include "metal_context.h"
#include <unordered_map>

class MetalDriver final : public ImGuiDriver {
public:
void reset() override
{
ImGuiDriver::reset();
ImGui_ImplMetal_Shutdown();
}

void newFrame() override {

}

void renderDrawData(ImDrawData *drawData, bool gui_open) override {

}

void present() override {

}

ImTextureID getTexture(const std::string &name) override {
auto it = textures.find(name);
if (it != textures.end())
return &it->second.texture;
else
return ImTextureID{};
}

ImTextureID updateTexture(const std::string &name, const u8 *data, int width, int height, bool nearestSampling) override {
Texture& texture = textures[name];
texture.texture->setPurgeableState(MTL::PurgeableStateEmpty);

MTL::TextureDescriptor *desc = MTL::TextureDescriptor::alloc()->init();
desc->setWidth(width);
desc->setHeight(height);

MTL::Region region = MTL::Region { 0, 0, static_cast<NS::UInteger>(width), static_cast<NS::UInteger>(height) };
texture.texture = MetalContext::Instance()->GetDevice()->newTexture(desc);
texture.texture->replaceRegion(region, 0, data, width * 4);

return texture.texture;
}

void deleteTexture(const std::string &name) override {
auto it = textures.find(name);
it->second.texture->setPurgeableState(MTL::PurgeableStateEmpty);
textures.erase(name);
}

private:
struct Texture {
MTL::Texture *texture;
};

bool frameRendered = false;
std::unordered_map<std::string, Texture> textures;
};
17 changes: 15 additions & 2 deletions core/rend/metal/metal_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,33 @@
bool MetalRenderer::Init()
{
NOTICE_LOG(RENDERER, "Metal renderer initializing");

shaders = MetalShaders();
samplers = MetalSamplers();

frameRendered = false;

return true;
}

void MetalRenderer::Term() {

shaders.term();
samplers.term();
}

void MetalRenderer::Process(TA_context *ctx) {

}

bool MetalRenderer::Render() {

return true;
}

void MetalRenderer::RenderFramebuffer(const FramebufferInfo &info) {

}

Renderer* rend_Metal()
{
return new MetalRenderer();
}
10 changes: 9 additions & 1 deletion core/rend/metal/metal_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "metal_shaders.h"
#include "metal_texture.h"
#include "hw/pvr/Renderer_if.h"

struct MetalRenderer final : public Renderer
class MetalRenderer final : public Renderer
{
public:
bool Init() override;
void Term() override;
void Process(TA_context* ctx) override;
bool Render() override;
void RenderFramebuffer(const FramebufferInfo& info) override;

protected:
MetalShaders shaders;
MetalSamplers samplers;
bool frameRendered = false;
};
Loading

0 comments on commit eef9d80

Please sign in to comment.