Skip to content

Commit

Permalink
Work on Glfw + Metal
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Dec 20, 2023
1 parent 47b01b5 commit 1762d7b
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 34 deletions.
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ include(hello_imgui_add_app)
# - HELLOIMGUI_USE_SDL_OPENGL3 will be used for Android, iOS and emscripten
#------------------------------------------------------------------------------
# Use Glfw3 + OpenGl3
option(HELLOIMGUI_USE_GLFW_OPENGL3 "Build HelloImGui for GLFW+OpenGL3" OFF)
option(HELLOIMGUI_USE_GLFW_OPENGL3 "Build HelloImGui for Glfw3+OpenGL3" OFF)
# Use SDL2 + OpenGL3
option(HELLOIMGUI_USE_SDL_OPENGL3 "Build HelloImGui for SDL+OpenGL3" OFF)
option(HELLOIMGUI_USE_SDL_OPENGL3 "Build HelloImGui for SDL2+OpenGL3" OFF)
# Use Glfw3 + Metal (Apple only)
option(HELLOIMGUI_USE_GLFW_METAL "Build HelloImGui for Glfw3+Metal" OFF)
# Use SDL2 + Metal (Apple only)
option(HELLOIMGUI_USE_SDL_METAL "Build HelloImGui for SDL+Metal" OFF)
option(HELLOIMGUI_USE_SDL_METAL "Build HelloImGui for SDL2+Metal" OFF)
# Note: Metal and OpenGl3 are mutually exclusive!


Expand Down
24 changes: 16 additions & 8 deletions src/hello_imgui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,10 @@ function(him_sanity_checks)
set(backend_message "
HelloImGui: no backend selected!
In order to select your own backend, use one of the cmake options below:
-DHELLOIMGUI_WITH_GLFW=ON # To download and build glfw automatically
-DHELLOIMGUI_WITH_SDL=ON # To download and build SDL automatically
-DHELLOIMGUI_USE_GLFW_OPENGL3=ON # To use your own version of GLFW (it should be findable via find_package(glfw3))
-DHELLOIMGUI_USE_SDL_OPENGL3=ON # To use your own version of SDL (it should be findable via find_package(SDL2))
-DHELLOIMGUI_USE_SDL_METAL=ON # To use SDL2 + Metal
(Note: under Linux, it is advised to use system-wide libraries, and not to use
-DHELLOIMGUI_WITH_GLFW=ON or -DHELLOIMGUI_WITH_SDL=ON)
-DHELLOIMGUI_USE_GLFW_OPENGL3=ON # Glfw3 + OpenGL3
-DHELLOIMGUI_USE_SDL_OPENGL3=ON # SDL2 + OpenGL3
-DHELLOIMGUI_USE_GLFW_METAL # Glfw3 + Metal
-DHELLOIMGUI_USE_SDL_METAL=ON # SDL2 + Metal
")
message(STATUS "${backend_message}")

Expand All @@ -134,6 +130,7 @@ function(_him_check_if_no_backend_selected)
if (NOT HELLOIMGUI_USE_SDL_OPENGL3
AND NOT HELLOIMGUI_USE_GLFW_OPENGL3
AND NOT HELLOIMGUI_USE_SDL_METAL
AND NOT HELLOIMGUI_USE_GLFW_METAL
)
set(HELLOIMGUI_NO_BACKEND_SELECTED ON CACHE INTERNAL "")
endif()
Expand Down Expand Up @@ -179,6 +176,7 @@ function(_him_try_select_glfw_if_no_backend_selected)
endif()
endfunction()


###################################################################################################
# Apple related options: API = him_add_apple_options
###################################################################################################
Expand Down Expand Up @@ -274,6 +272,7 @@ function(him_add_android_options)
endif()
endfunction()


###################################################################################################
# Emscripten related options: API = him_add_emscripten_options
###################################################################################################
Expand Down Expand Up @@ -323,6 +322,7 @@ function(_him_link_opengles_sdl target)
)
endfunction()


###################################################################################################
# Metal Rendering backend: API = him_use_metal_backend
###################################################################################################
Expand All @@ -337,6 +337,7 @@ function(him_use_metal_backend target)
"-framework Metal -framework MetalKit -framework QuartzCore")
endfunction()


###################################################################################################
# SDL Windowing backend: API = him_use_sdl2_backend
###################################################################################################
Expand Down Expand Up @@ -551,6 +552,13 @@ function(him_main)
target_compile_definitions(${helloimgui_target} PUBLIC HELLOIMGUI_USE_SDL_METAL)
endif()

if(HELLOIMGUI_USE_GLFW_METAL)
him_use_metal_backend(${helloimgui_target})
him_use_glfw_backend(${helloimgui_target})
target_compile_definitions(${helloimgui_target} PUBLIC HELLOIMGUI_USE_GLFW_METAL)
endif()


if(HELLOIMGUI_HAS_METAL AND HELLOIMGUI_HAS_OPENGL)
message(FATAL_ERROR "HelloImGui: cannot have both Metal and OpenGL backends at the same time")
endif()
Expand Down
37 changes: 34 additions & 3 deletions src/hello_imgui/internal/backend_impls/rendering_metal.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,27 @@ struct SDL_Renderer;
struct SDL_Window;
#endif

#ifdef HELLOIMGUI_USE_GLFW3
struct GLFWwindow;
#endif

#include "hello_imgui/internal/backend_impls/rendering_callbacks.h"

namespace HelloImGui
{
RenderingCallbacks CreateBackendCallbacks_Metal();

#ifdef HELLOIMGUI_USE_SDL2
void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* window);
void PrepareSdLForMetal_PosImGuiInit();
RenderingCallbacks CreateBackendCallbacks_SdlMetal();

void PrepareSdlForMetal_WithWindow_PreImGuiInit(SDL_Window* window);
void PrepareSdlForMetal_PosImGuiInit();
void SwapSdlMetalBuffers();

struct SdlMetalGlobals
{
SDL_Window* sdlWindow = nullptr;
SDL_Renderer* sdlRenderer = nullptr;

CAMetalLayer* caMetalLayer = nullptr;
id<CAMetalDrawable> caMetalDrawable = nullptr;
id<MTLCommandBuffer> mtlCommandBuffer = nullptr;
Expand All @@ -34,6 +40,31 @@ namespace HelloImGui

SdlMetalGlobals& GetSdlMetalGlobals();
#endif

#ifdef HELLOIMGUI_USE_GLFW3
RenderingCallbacks CreateBackendCallbacks_GlfwMetal();

void PrepareGlfwForMetal_WithWindow_PreImGuiInit(GLFWwindow* window);
void PrepareGlfwForMetal_PosImGuiInit();
void SwapGlfwMetalBuffers();

struct GlfwMetalGlobals
{
GLFWwindow* glfwWindow = nullptr;

id <MTLDevice> mtlDevice = nullptr;

CAMetalLayer* caMetalLayer = nullptr;
id<CAMetalDrawable> caMetalDrawable = nullptr;
id<MTLCommandBuffer> mtlCommandBuffer = nullptr;
id<MTLCommandQueue> mtlCommandQueue = nullptr;
MTLRenderPassDescriptor* mtlRenderPassDescriptor = nullptr;
id <MTLRenderCommandEncoder> mtlRenderCommandEncoder = nullptr;
};

GlfwMetalGlobals& GetGlfwMetalGlobals();
#endif

}

#endif // HELLOIMGUI_HAS_METAL
122 changes: 122 additions & 0 deletions src/hello_imgui/internal/backend_impls/rendering_metal_glfw.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#ifdef HELLOIMGUI_HAS_METAL
#ifdef HELLOIMGUI_USE_GLFW3

#include "rendering_metal.h"

#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#include <backends/imgui_impl_metal.h>
#include <array>

#include "hello_imgui/hello_imgui.h"

#define GLFW_INCLUDE_NONE
#define GLFW_EXPOSE_NATIVE_COCOA
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <backends/imgui_impl_glfw.h>


namespace HelloImGui
{
GlfwMetalGlobals gGlfwMetalGlobals;

void PrepareGlfwForMetal_WithWindow_PreImGuiInit(GLFWwindow* glfwWindow)
{
gGlfwMetalGlobals.glfwWindow = glfwWindow;
// gGlfwMetalGlobals.sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// if (gGlfwMetalGlobals.sdlRenderer == nullptr)
// {
// bool Error_SdlCreateRenderer_For_Metal = false;
// IM_ASSERT(Error_SdlCreateRenderer_For_Metal);
// exit(-3);
// }

// Setup Platform/Renderer backends
// gGlfwMetalGlobals.caMetalLayer = (__bridge CAMetalLayer*)SDL_RenderGetMetalLayer(gGlfwMetalGlobals.sdlRenderer);
// gGlfwMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;

gGlfwMetalGlobals.mtlDevice = MTLCreateSystemDefaultDevice();
gGlfwMetalGlobals.mtlCommandQueue = [gGlfwMetalGlobals.mtlDevice newCommandQueue];
}

void PrepareGlfwForMetal_PosImGuiInit()
{
ImGui_ImplGlfw_InitForOther(gGlfwMetalGlobals.glfwWindow, true);
ImGui_ImplMetal_Init(gGlfwMetalGlobals.mtlDevice);

NSWindow *nswin = glfwGetCocoaWindow(gGlfwMetalGlobals.glfwWindow);
gGlfwMetalGlobals.caMetalLayer = [CAMetalLayer layer];
gGlfwMetalGlobals.caMetalLayer.device = gGlfwMetalGlobals.mtlDevice;
gGlfwMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
nswin.contentView.layer = gGlfwMetalGlobals.caMetalLayer;
nswin.contentView.wantsLayer = YES;

gGlfwMetalGlobals.mtlRenderPassDescriptor = [MTLRenderPassDescriptor new];
}

void SwapGlfwMetalBuffers()
{
[gGlfwMetalGlobals.mtlRenderCommandEncoder popDebugGroup];
[gGlfwMetalGlobals.mtlRenderCommandEncoder endEncoding];

[gGlfwMetalGlobals.mtlCommandBuffer presentDrawable:gGlfwMetalGlobals.caMetalDrawable];
[gGlfwMetalGlobals.mtlCommandBuffer commit];
}

RenderingCallbacks CreateBackendCallbacks_GlfwMetal()
{
RenderingCallbacks callbacks;

callbacks.Impl_NewFrame_3D = []
{
auto Vec4_To_Array = [](ImVec4 v) { return std::array<float, 4>{ v.x, v.y, v.z, v.w }; };

int width, height;
glfwGetFramebufferSize(gGlfwMetalGlobals.glfwWindow, &width, &height);
gGlfwMetalGlobals.caMetalLayer.drawableSize = CGSizeMake(width, height);
gGlfwMetalGlobals.caMetalDrawable = [gGlfwMetalGlobals.caMetalLayer nextDrawable];

gGlfwMetalGlobals.mtlCommandBuffer = [gGlfwMetalGlobals.mtlCommandQueue commandBuffer];
auto clearColor = Vec4_To_Array(HelloImGui::GetRunnerParams()->imGuiWindowParams.backgroundColor);
gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(clearColor[0] * clearColor[3], clearColor[1] * clearColor[3], clearColor[2] * clearColor[3], clearColor[3]);
gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].texture = gGlfwMetalGlobals.caMetalDrawable.texture;
gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
gGlfwMetalGlobals.mtlRenderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
gGlfwMetalGlobals.mtlRenderCommandEncoder = [
gGlfwMetalGlobals.mtlCommandBuffer renderCommandEncoderWithDescriptor:gGlfwMetalGlobals.mtlRenderPassDescriptor];
[gGlfwMetalGlobals.mtlRenderCommandEncoder pushDebugGroup:@"ImGui demo"];

// Start the Dear ImGui frame
ImGui_ImplMetal_NewFrame(gGlfwMetalGlobals.mtlRenderPassDescriptor);
ImGui_ImplGlfw_NewFrame();
};

callbacks.Impl_RenderDrawData_To_3D = []
{
ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), gGlfwMetalGlobals.mtlCommandBuffer, gGlfwMetalGlobals.mtlRenderCommandEncoder);
};

// Not implemented for Metal
//callbacks.Impl_ScreenshotRgb = []() { ...;};

// This is done at Impl_NewFrame_3D
callbacks.Impl_Frame_3D_ClearColor = [](ImVec4 clearColor) { };

callbacks.Impl_Shutdown_3D = []
{
ImGui_ImplMetal_Shutdown();
};
return callbacks;
}

GlfwMetalGlobals& GetGlfwMetalGlobals()
{
return gGlfwMetalGlobals;
}


} // namespace HelloImGui

#endif // HELLOIMGUI_USE_GLFW3
#endif // HELLOIMGUI_HAS_METAL
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#ifdef HELLOIMGUI_HAS_METAL
#ifdef HELLOIMGUI_USE_SDL2
#include "rendering_metal.h"

#import <Metal/Metal.h>
Expand All @@ -10,19 +11,15 @@
#include "hello_imgui/internal/stb_image.h"
#include "hello_imgui/hello_imgui.h"

#ifdef HELLOIMGUI_USE_SDL2
#include <SDL.h>
#include <backends/imgui_impl_sdl2.h>
#endif


namespace HelloImGui
{
#ifdef HELLOIMGUI_USE_SDL2

SdlMetalGlobals gSdlMetalGlobals;

void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow)
void PrepareSdlForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow)
{
gSdlMetalGlobals.sdlWindow = sdlWindow;
gSdlMetalGlobals.sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
Expand All @@ -38,7 +35,7 @@ void PrepareSdLForMetal_WithWindow_PreImGuiInit(SDL_Window* sdlWindow)
gSdlMetalGlobals.caMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
}

void PrepareSdLForMetal_PosImGuiInit()
void PrepareSdlForMetal_PosImGuiInit()
{
ImGui_ImplMetal_Init(gSdlMetalGlobals.caMetalLayer.device);
ImGui_ImplSDL2_InitForMetal(gSdlMetalGlobals.sdlWindow);
Expand All @@ -56,7 +53,7 @@ void SwapSdlMetalBuffers()
[gSdlMetalGlobals.mtlCommandBuffer commit];
}

RenderingCallbacks CreateBackendCallbacks_Metal()
RenderingCallbacks CreateBackendCallbacks_SdlMetal()
{
RenderingCallbacks callbacks;

Expand Down Expand Up @@ -108,10 +105,7 @@ RenderingCallbacks CreateBackendCallbacks_Metal()
return gSdlMetalGlobals;
}


#endif // #ifdef HELLOIMGUI_USE_SDL2


} // namespace HelloImGui

#endif // HELLOIMGUI_USE_SDL2
#endif // HELLOIMGUI_HAS_METAL
Loading

0 comments on commit 1762d7b

Please sign in to comment.