Skip to content

Commit

Permalink
feat: add glfw support metal
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake committed Feb 16, 2023
1 parent 7b0bf15 commit 16b71c6
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 6 deletions.
16 changes: 16 additions & 0 deletions library/include/borealis/platforms/glfw/glfw_video_metal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

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

#include <nanovg_mtl.h>

// 创建一个 metal 上下文
void *CreateMetalContext(GLFWwindow* window);
// 从 metal 上下文里取出 MetalLayer
void *GetMetalLayer(void *ctx);
// MetalLayer 画布缩放
void ResizeMetalDrawable(void *ctx, int width, int height);
// 获取窗口 dpi
float GetMetalScaleFactor(void *ctx);
7 changes: 6 additions & 1 deletion library/lib/core/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,13 @@ void Application::frame()
NVGcolor backgroundColor = frameContext.theme["brls/background"];
videoContext->beginFrame();
videoContext->clear(backgroundColor);
float scaleFactor = frameContext.pixelRatio;
#ifdef BOREALIS_USE_METAL
// metal 用 frameContext.pixelRatio 会无法铺满窗口,改用 ScaleFactor
scaleFactor = Application::getPlatform()->getVideoContext()->getScaleFactor();
#endif

nvgBeginFrame(Application::getNVGContext(), Application::windowWidth, Application::windowHeight, frameContext.pixelRatio);
nvgBeginFrame(Application::getNVGContext(), Application::windowWidth, Application::windowHeight, scaleFactor);
nvgScale(Application::getNVGContext(), Application::windowScale, Application::windowScale);

std::vector<View*> viewsToDraw;
Expand Down
4 changes: 4 additions & 0 deletions library/lib/platforms/glfw/glfw_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ void GLFWInputManager::updateMouseStates(RawMouseState* state)
state->rightButton = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;

double scaleFactor = brls::Application::getPlatform()->getVideoContext()->getScaleFactor();
#ifdef BOREALIS_USE_METAL
// 使用 metal 的 cocoa 窗口鼠标事件不需要进行 dpi 缩放。
scaleFactor = 1.0;
#endif
state->position.x = x * scaleFactor / Application::windowScale;
state->position.y = y * scaleFactor / Application::windowScale;
state->offset = pointerOffset;
Expand Down
55 changes: 53 additions & 2 deletions library/lib/platforms/glfw/glfw_video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <borealis/platforms/glfw/glfw_video.hpp>

// nanovg implementation
#ifdef BOREALIS_USE_OPENGL
#ifdef __PSV__
#define NANOVG_GLES2_IMPLEMENTATION
#else
Expand All @@ -30,6 +31,10 @@
#endif /* USE_GL2 */
#endif /* __PSV__ */
#include <nanovg_gl.h>
#elif defined(BOREALIS_USE_METAL)
static void *METAL_CONTEXT = nullptr;
#include <borealis/platforms/glfw/glfw_video_metal.hpp>
#endif

#ifdef __SWITCH__
#include <switch.h>
Expand Down Expand Up @@ -113,12 +118,24 @@ static void glfwWindowFramebufferSizeCallback(GLFWwindow* window, int width, int
{
if (!width || !height)
return;

#ifdef BOREALIS_USE_OPENGL
glViewport(0, 0, width, height);

int wWidth, wHeight;
glfwGetWindowSize(window, &wWidth, &wHeight);
scaleFactor = width * 1.0 / wWidth;
#elif defined(BOREALIS_USE_METAL)
if (METAL_CONTEXT == nullptr) {
return;
}
scaleFactor = GetMetalScaleFactor(METAL_CONTEXT);
ResizeMetalDrawable(METAL_CONTEXT, width, height);
int wWidth, wHeight;
glfwGetWindowSize(window, &wWidth, &wHeight);
// cocoa 画布大小和窗口一致
width = wWidth;
height = wHeight;
#endif

Application::onWindowResized(width, height);

if (!VideoContext::FULLSCREEN)
Expand Down Expand Up @@ -147,6 +164,7 @@ GLFWVideoContext::GLFWVideoContext(const std::string& windowTitle, uint32_t wind
}

// Create window
#ifdef BOREALIS_USE_OPENGL
#if defined(__PSV__)
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
Expand All @@ -169,6 +187,9 @@ GLFWVideoContext::GLFWVideoContext(const std::string& windowTitle, uint32_t wind
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
#endif
#elif defined(BOREALIS_USE_METAL)
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
#endif

#if defined(__APPLE__) || defined(__linux__) || defined(_WIN32)
// If the window appears outside the screen, using the default settings
Expand Down Expand Up @@ -238,10 +259,13 @@ GLFWVideoContext::GLFWVideoContext(const std::string& windowTitle, uint32_t wind
#ifdef __APPLE__
glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GLFW_TRUE);
#endif
#ifdef BOREALIS_USE_OPENGL
glfwMakeContextCurrent(window);
#endif
glfwSetFramebufferSizeCallback(window, glfwWindowFramebufferSizeCallback);
glfwSetWindowPosCallback(window, glfwWindowPositionCallback);

#ifdef BOREALIS_USE_OPENGL
#ifndef __PSV__
// Load OpenGL routines using glad
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
Expand All @@ -251,15 +275,24 @@ GLFWVideoContext::GLFWVideoContext(const std::string& windowTitle, uint32_t wind
Logger::info("glfw: GL Vendor: {}", (const char*)glGetString(GL_VENDOR));
Logger::info("glfw: GL Renderer: {}", (const char*)glGetString(GL_RENDERER));
Logger::info("glfw: GL Version: {}", (const char*)glGetString(GL_VERSION));
#endif
Logger::info("glfw: GLFW Version: {}.{}.{}", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION);

// Initialize nanovg
#ifdef BOREALIS_USE_OPENGL
#ifdef __PSV__
this->nvgContext = nvgCreateGLES2(0);
#elif defined(USE_GL2)
this->nvgContext = nvgCreateGL2(NVG_STENCIL_STROKES | NVG_ANTIALIAS);
#else
this->nvgContext = nvgCreateGL3(NVG_STENCIL_STROKES | NVG_ANTIALIAS);
#endif
#elif defined(BOREALIS_USE_METAL)
Logger::info("glfw: use metal");
void *ctx = CreateMetalContext(window);
METAL_CONTEXT = ctx;
this->nvgContext = nvgCreateMTL(GetMetalLayer(ctx), NVG_STENCIL_STROKES | NVG_ANTIALIAS);
scaleFactor = GetMetalScaleFactor(ctx);
#endif
if (!this->nvgContext)
{
Expand Down Expand Up @@ -300,27 +333,40 @@ void GLFWVideoContext::beginFrame()

void GLFWVideoContext::endFrame()
{
#ifdef BOREALIS_USE_OPENGL
glfwSwapBuffers(this->window);
#endif
}

void GLFWVideoContext::clear(NVGcolor color)
{

#ifdef BOREALIS_USE_OPENGL
glClearColor(
color.r,
color.g,
color.b,
1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
#elif defined(BOREALIS_USE_METAL)
nvgClearWithColor(nvgContext, nvgRGBAf(
color.r,
color.g,
color.b,
1.0f));
#endif
}

void GLFWVideoContext::resetState()
{
#ifdef BOREALIS_USE_OPENGL
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
#endif
}

void GLFWVideoContext::disableScreenDimming(bool disable)
Expand All @@ -340,12 +386,17 @@ GLFWVideoContext::~GLFWVideoContext()
try
{
if (this->nvgContext)
#ifdef BOREALIS_USE_OPENGL
#ifdef __PSV__
nvgDeleteGLES2(this->nvgContext);
#elif defined(USE_GL2)
nvgDeleteGL2(this->nvgContext);
#else
nvgDeleteGL3(this->nvgContext);
#endif
#elif defined(BOREALIS_USE_METAL)
nvgDeleteMTL(this->nvgContext);
METAL_CONTEXT = nullptr;
#endif
}
catch (...)
Expand Down
42 changes: 42 additions & 0 deletions library/lib/platforms/glfw/glfw_video_metal.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#include <borealis/platforms/glfw/glfw_video_metal.hpp>


struct context_mtl {
id<MTLDevice> device;
CAMetalLayer* layer;
NSWindow* win;
};

void *GetMetalLayer(void *ctx) {
struct context_mtl *c = (struct context_mtl *)ctx;
return (__bridge void *)c->layer;
}

void *CreateMetalContext(GLFWwindow* window) {
struct context_mtl* mtl = (struct context_mtl*)calloc(1, sizeof(struct context_mtl));
NSWindow* nswin = glfwGetCocoaWindow(window);
mtl->win = nswin;
mtl->device = MTLCreateSystemDefaultDevice();
mtl->layer = [CAMetalLayer layer];
mtl->layer.device = mtl->device;
mtl->layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
nswin.contentView.layer = mtl->layer;
nswin.contentView.wantsLayer = YES;
return (void *)mtl;
}

void ResizeMetalDrawable(void *ctx, int width, int height) {
struct context_mtl *c = (struct context_mtl *)ctx;
CGSize sz;
sz.width = width;
sz.height = height;
c->layer.drawableSize = sz;
}

float GetMetalScaleFactor(void *ctx) {
struct context_mtl *c = (struct context_mtl *)ctx;
float scaleFactor = [c->win backingScaleFactor];
return scaleFactor;
}
26 changes: 23 additions & 3 deletions xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ option("window")
set_showmenu(true)
option_end()

option("driver")
set_default("opengl")
set_showmenu(true)
option_end()

-- https://github.com/zeromake/nanovg
package("zeromake_nanovg")
if os.exists("../nanovg") then
Expand All @@ -38,8 +43,7 @@ add_requires("tweeny")

add_defines(
'BRLS_RESOURCES="./resources/"',
"YG_ENABLE_EVENTS",
"__GLFW__"
"YG_ENABLE_EVENTS"
)

target("borealis")
Expand All @@ -66,16 +70,28 @@ target("borealis")
}) do
add_files(path.join("library/lib/extern/libretro-common", dir, "*.c"))
end
add_files("library/lib/platforms/glfw/glfw_video_metal.mm")
local windowLib = get_config("window")
if windowLib == "glfw" then
add_files("library/lib/platforms/glfw/*.cpp")
add_files("library/lib/platforms/desktop/*.cpp")
add_packages("xfangfang_glfw", "glad")
add_packages("xfangfang_glfw")
add_defines("__GLFW__")
elseif windowLib == "sdl" then
add_files("library/lib/platforms/sdl/*.cpp")
add_files("library/lib/platforms/desktop/*.cpp")
add_packages("sdl")
end
local driver = get_config("driver")
if driver == "metal" then
add_defines("BOREALIS_USE_METAL")
add_frameworks("Metal", "MetalKit", "QuartzCore")
elseif driver == "opengl" then
add_defines("BOREALIS_USE_OPENGL")
add_packages("glad")
elseif driver == "d3d11" then
add_defines("BOREALIS_USE_D3D11")
end
add_packages("tinyxml2", "nlohmann_json", "zeromake_nanovg", "fmt", "tweeny", "yoga")

target("demo")
Expand All @@ -86,4 +102,8 @@ target("demo")
end
add_files("demo/*.cpp")
add_packages("tinyxml2", "zeromake_nanovg", "fmt", "tweeny", "yoga")
local driver = get_config("driver")
if driver == "metal" then
add_links("nanovg_metal")
end
add_deps("borealis")

0 comments on commit 16b71c6

Please sign in to comment.