[surface] extracted common layer functionality from osx surfaces. Use layer in platform-agnostic egl surface.

This commit is contained in:
Martin Fouilleul 2023-02-21 13:40:30 +01:00
parent 9ea9ea7636
commit 94373d12ae
6 changed files with 101 additions and 234 deletions

View File

@ -1,6 +1,6 @@
/************************************************************//**
*
* @file: win32_egl_surface.cpp
* @file: egl_surface.cpp
* @author: Martin Fouilleul
* @date: 17/02/2023
* @revision:
@ -121,8 +121,15 @@ mg_surface mg_egl_surface_create_for_window(mp_window window)
mp_layer_init_for_window(&surface->layer, windowData);
#if OS_MACOS
//NOTE: using EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
#else
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
#endif
EGLAttrib displayAttribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_ANGLE, MG_EGL_PLATFORM_ANGLE_TYPE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE};
@ -154,7 +161,7 @@ mg_surface mg_egl_surface_create_for_window(mp_window window)
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
EGL_CONTEXT_MINOR_VERSION_KHR, 1,
EGL_CONTEXT_MINOR_VERSION_KHR, 0,
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,

View File

@ -17,7 +17,7 @@
#if MG_COMPILE_BACKEND_GLES
#include"gl_loader.c"
#include"osx_egl_surface.m"
#include"egl_surface.c"
#endif
/*

View File

@ -23,6 +23,8 @@ typedef struct mg_mtl_surface
{
mg_surface_data interface;
mp_layer layer;
// permanent mtl resources
id<MTLDevice> device;
CAMetalLayer* mtlLayer;
@ -47,6 +49,7 @@ void mg_mtl_surface_destroy(mg_surface_data* interface)
[surface->mtlLayer release];
[surface->device release];
}
//NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
}
void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface)
@ -136,51 +139,38 @@ void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
////////////////////////////////////////////////////////////////
}
vec2 mg_mtl_surface_contents_scaling(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
return(mp_layer_contents_scaling(&surface->layer));
}
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mp_layer_set_frame(&surface->layer, frame);
vec2 scale = mp_layer_contents_scaling(&surface->layer);
@autoreleasepool
{
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
[surface->mtlLayer setFrame: cgFrame];
f32 scale = surface->mtlLayer.contentsScale;
CGSize drawableSize = (CGSize){.width = frame.w * scale, .height = frame.h * scale};
surface->mtlLayer.drawableSize = drawableSize;
}
CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y};
surface->mtlLayer.drawableSize = drawableSize;
}
mp_rect mg_mtl_surface_get_frame(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
CGRect frame = surface->mtlLayer.frame;
return((mp_rect){frame.origin.x, frame.origin.y, frame.size.width, frame.size.height});
}
return(mp_layer_get_frame(&surface->layer));
}
void mg_mtl_surface_set_hidden(mg_surface_data* interface, bool hidden)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[surface->mtlLayer setHidden:hidden];
[CATransaction commit];
}
mp_layer_set_hidden(&surface->layer, hidden);
}
bool mg_mtl_surface_get_hidden(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
return([surface->mtlLayer isHidden]);
}
return(mp_layer_get_hidden(&surface->layer));
}
//TODO fix that according to real scaling, depending on the monitor settings
@ -203,6 +193,7 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.contentsScaling = mg_mtl_surface_contents_scaling;
surface->interface.getFrame = mg_mtl_surface_get_frame;
surface->interface.setFrame = mg_mtl_surface_set_frame;
surface->interface.getHidden = mg_mtl_surface_get_hidden;
@ -220,9 +211,11 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
[surface->device retain];
surface->mtlLayer = [CAMetalLayer layer];
[surface->mtlLayer retain];
[surface->mtlLayer setOpaque:NO];
surface->mtlLayer.device = surface->device;
[surface->mtlLayer setOpaque:NO];
surface->layer.caLayer = (CALayer*)surface->mtlLayer;
//-----------------------------------------------------------
//NOTE(martin): set the size and scaling

View File

@ -20,6 +20,7 @@
#define NSObject void
#define NSTimer void
#define NSCursor void
#define CALayer void
#endif
#include<Carbon/Carbon.h>
@ -32,6 +33,11 @@ typedef struct osx_window_data
} osx_window_data;
typedef struct mp_layer
{
CALayer* caLayer;
} mp_layer;
#define MP_PLATFORM_WINDOW_DATA osx_window_data osx;
const u32 MP_APP_MAX_VIEWS = 128;

View File

@ -8,6 +8,8 @@
//
//*****************************************************************
#import <QuartzCore/QuartzCore.h> //CATransaction
#include<stdlib.h> // malloc/free
#include"lists.h"
@ -1713,6 +1715,68 @@ void mp_window_set_content_size(mp_window window, int width, int height)
}
}
//--------------------------------------------------------------------
// layers
//--------------------------------------------------------------------
void mp_layer_init_for_window(mp_layer* layer, mp_window_data* window)
{@autoreleasepool{
layer->caLayer = [[CALayer alloc] init];
[layer->caLayer retain];
NSRect frame = [[window->osx.nsWindow contentView] frame];
CGSize size = frame.size;
layer->caLayer.frame = (CGRect){{0, 0}, size};
[window->osx.nsView.layer addSublayer: layer->caLayer];
}}
void mp_layer_cleanup(mp_layer* layer)
{@autoreleasepool{
[layer->caLayer release];
}}
void* mp_layer_native_surface(mp_layer* layer)
{
return((void*)layer->caLayer);
}
vec2 mp_layer_contents_scaling(mp_layer* layer)
{@autoreleasepool{
f32 contentsScale = [layer->caLayer contentsScale];
vec2 res = {contentsScale, contentsScale};
return(res);
}}
mp_rect mp_layer_get_frame(mp_layer* layer)
{@autoreleasepool{
CGRect frame = layer->caLayer.frame;
mp_rect res = {frame.origin.x,
frame.origin.y,
frame.size.width,
frame.size.height};
return(res);
}}
void mp_layer_set_frame(mp_layer* layer, mp_rect frame)
{@autoreleasepool{
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
[layer->caLayer setFrame: cgFrame];
}}
void mp_layer_set_hidden(mp_layer* layer, bool hidden)
{@autoreleasepool{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[layer->caLayer setHidden:hidden];
[CATransaction commit];
}}
bool mp_layer_get_hidden(mp_layer* layer)
{@autoreleasepool{
return([layer->caLayer isHidden]);
}}
//--------------------------------------------------------------------
// view management
//--------------------------------------------------------------------

View File

@ -1,203 +0,0 @@
/************************************************************//**
*
* @file: osx_egl_surface.m
* @author: Martin Fouilleul
* @date: 17/02/2023
* @revision:
*
*****************************************************************/
#define EGL_EGLEXT_PROTOTYPES
#include<EGL/egl.h>
#include<EGL/eglext.h>
#include"mp_app_internal.h"
#include"graphics_internal.h"
#include"gl_loader.h"
typedef struct mg_egl_surface
{
mg_surface_data interface;
CALayer* layer;
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
EGLSurface eglSurface;
mg_gl_api api;
} mg_egl_surface;
void mg_egl_surface_destroy(mg_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
if(&surface->api == mg_gl_get_api())
{
mg_gl_select_api(0);
}
if(eglGetCurrentContext() == surface->eglContext)
{
eglMakeCurrent(surface->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
eglDestroyContext(surface->eglDisplay, surface->eglContext);
eglDestroySurface(surface->eglDisplay, surface->eglSurface);
@autoreleasepool
{
[surface->layer release];
}
free(surface);
}
void mg_egl_surface_prepare(mg_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
mg_gl_select_api(&surface->api);
}
void mg_egl_surface_present(mg_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
}
void mg_egl_surface_swap_interval(mg_surface_data* interface, int swap)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
eglSwapInterval(surface->eglDisplay, 1);
}
void mg_egl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
@autoreleasepool
{
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
[surface->layer setFrame: cgFrame];
}
}
mp_rect mg_egl_surface_get_frame(mg_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
@autoreleasepool
{
CGRect frame = surface->layer.frame;
return((mp_rect){frame.origin.x, frame.origin.y, frame.size.width, frame.size.height});
}
}
void mg_egl_surface_set_hidden(mg_surface_data* interface, bool hidden)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
@autoreleasepool
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[surface->layer setHidden:hidden];
[CATransaction commit];
}
}
bool mg_egl_surface_get_hidden(mg_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
@autoreleasepool
{
return([surface->layer isHidden]);
}
}
/*
mp_rect mg_egl_surface_get_frame(mg_surface_data* interface);
void mg_egl_surface_set_frame(mg_surface_data* interface, mp_rect frame);
void mg_egl_surface_set_hidden(mg_surface_data* interface, bool hidden);
bool mg_egl_surface_get_hidden(mg_surface_data* interface);
*/
mg_surface mg_egl_surface_create_for_window(mp_window window)
{
mg_surface res = mg_surface_nil();
mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData)
{
mg_egl_surface* surface = malloc_type(mg_egl_surface);
memset(surface, 0, sizeof(mg_egl_surface));
surface->interface.backend = MG_BACKEND_GLES;
surface->interface.destroy = mg_egl_surface_destroy;
surface->interface.prepare = mg_egl_surface_prepare;
surface->interface.present = mg_egl_surface_present;
surface->interface.getFrame = mg_egl_surface_get_frame;
surface->interface.setFrame = mg_egl_surface_set_frame;
surface->interface.getHidden = mg_egl_surface_get_hidden;
surface->interface.setHidden = mg_egl_surface_set_hidden;
surface->interface.swapInterval = mg_egl_surface_swap_interval;
@autoreleasepool
{
surface->layer = [[CALayer alloc] init];
[surface->layer retain];
[windowData->osx.nsView.layer addSublayer: surface->layer];
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size;
surface->layer.frame = (CGRect){{0, 0}, size};
}
EGLAttrib displayAttribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE};
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
eglInitialize(surface->eglDisplay, NULL, NULL);
EGLint const configAttributes[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_SAMPLE_BUFFERS, 0,
EGL_SAMPLES, EGL_DONT_CARE,
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
EGL_NONE };
int numConfigs = 0;
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &numConfigs);
EGLint const surfaceAttributes[] = {EGL_NONE};
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay, surface->eglConfig, surface->layer, surfaceAttributes);
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
EGL_CONTEXT_MINOR_VERSION_KHR, 0,
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
EGL_NONE};
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
mg_gl_load_gles32(&surface->api, (mg_gl_load_proc)eglGetProcAddress);
eglSwapInterval(surface->eglDisplay, 1);
res = mg_surface_alloc_handle((mg_surface_data*)surface);
}
return(res);
}