back osx surfaces by CALayer

This commit is contained in:
Martin Fouilleul 2023-02-20 16:49:44 +01:00
parent 2232b647ed
commit 4306d0a01c
13 changed files with 280 additions and 135 deletions

View File

@ -5,7 +5,12 @@ RESDIR=../../resources
SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore -L$BINDIR -lEGL -lGLESv2"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG -Wl,-dead_strip"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_canvas main.c
# change dynamic libraries install name
#TODO: this shouldn't be needed for apps using only metal backend...
install_name_tool -change "./libEGL.dylib" "@loader_path/libEGL.dylib" $BINDIR/example_canvas
install_name_tool -change "./libGLESv2.dylib" "@loader_path/libGLESv2.dylib" $BINDIR/example_canvas

View File

@ -5,10 +5,16 @@ RESDIR=../../resources
SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore -L$BINDIR -lEGL -lGLESv2"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG -Wl,-dead_strip"
xcrun -sdk macosx metal -c -o shader.air shader.metal
xcrun -sdk macosx metallib -o shader.metallib shader.air
cp shader.metallib $BINDIR/triangle_shader.metallib
clang -g $FLAGS $LIBS $INCLUDES -o test main.m
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_metal_triangle main.m
# change dynamic libraries install name
#TODO: this shouldn't be needed for apps using only metal backend...
install_name_tool -change "./libEGL.dylib" "@loader_path/libEGL.dylib" $BINDIR/example_metal_triangle
install_name_tool -change "./libGLESv2.dylib" "@loader_path/libGLESv2.dylib" $BINDIR/example_metal_triangle

View File

@ -13,7 +13,7 @@
#include<math.h>
#include"milepost.h"
#include"metal_surface.h"
#include"mtl_surface.h"
#define LOG_SUBSYSTEM "Main"
@ -36,13 +36,14 @@ int main()
mp_window window = mp_window_create(rect, "test", 0);
//NOTE: create surface
mg_surface surface = mg_metal_surface_create_for_window(window);
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_METAL);
//NOTE(martin): load the library
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
const char* shaderPath = "shader.metallib";
NSString* metalFileName = [[NSString alloc] initWithCString: shaderPath encoding: NSUTF8StringEncoding];
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "triangle_shader.metallib");
const char* shaderPathCString = str8_to_cstring(mem_scratch(), shaderPath);
NSString* metalFileName = [[NSString alloc] initWithCString: shaderPathCString encoding: NSUTF8StringEncoding];
NSError* err = 0;
id<MTLLibrary> library = [device newLibraryWithFile: metalFileName error:&err];
if(err != nil)
@ -60,7 +61,7 @@ int main()
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
CAMetalLayer* layer = mg_metal_surface_layer(surface);
CAMetalLayer* layer = mg_mtl_surface_layer(surface);
pipelineStateDescriptor.colorAttachments[0].pixelFormat = layer.pixelFormat;
id<MTLRenderPipelineState> pipelineState = [device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
@ -89,69 +90,6 @@ int main()
mp_request_quit();
} break;
case MP_EVENT_WINDOW_RESIZE:
{
printf("resized, rect = {%f, %f, %f, %f}\n",
event.frame.rect.x,
event.frame.rect.y,
event.frame.rect.w,
event.frame.rect.h);
} break;
case MP_EVENT_WINDOW_MOVE:
{
printf("moved, rect = {%f, %f, %f, %f}\n",
event.frame.rect.x,
event.frame.rect.y,
event.frame.rect.w,
event.frame.rect.h);
} break;
case MP_EVENT_MOUSE_MOVE:
{
printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n",
event.move.x,
event.move.y,
event.move.deltaX,
event.move.deltaY);
} break;
case MP_EVENT_MOUSE_WHEEL:
{
printf("mouse wheel, delta = {%f, %f}\n",
event.move.deltaX,
event.move.deltaY);
} break;
case MP_EVENT_MOUSE_ENTER:
{
printf("mouse enter\n");
} break;
case MP_EVENT_MOUSE_LEAVE:
{
printf("mouse leave\n");
} break;
case MP_EVENT_MOUSE_BUTTON:
{
printf("mouse button %i: %i\n",
event.key.code,
event.key.action == MP_KEY_PRESS ? 1 : 0);
} break;
case MP_EVENT_KEYBOARD_KEY:
{
printf("key %i: %s\n",
event.key.code,
event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
} break;
case MP_EVENT_KEYBOARD_CHAR:
{
printf("entered char %s\n", event.character.sequence);
} break;
default:
break;
}
@ -162,8 +100,8 @@ int main()
viewportSize.y = 600;
mg_surface_prepare(surface);
id<CAMetalDrawable> drawable = mg_metal_surface_drawable(surface);
id<MTLCommandBuffer> commandBuffer = mg_metal_surface_command_buffer(surface);
id<CAMetalDrawable> drawable = mg_mtl_surface_drawable(surface);
id<MTLCommandBuffer> commandBuffer = mg_mtl_surface_command_buffer(surface);
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;

View File

@ -30,22 +30,6 @@ typedef struct mg_egl_surface
} mg_egl_surface;
#if OS_MACOS
#include"osx_app.h"
void* mg_egl_get_native_surface(mp_window_data* window)
{
return((void*)window->osx.nsView.layer);
}
#elif OS_WIN64
#include"win32_app.h"
void* mg_egl_get_native_surface(mp_window_data* window)
{
return((void*)window->win32.hWnd);
}
#endif
void mg_egl_surface_destroy(mg_surface_data* interface)
{
//////////////////////////////////////////////////
@ -73,11 +57,23 @@ void mg_egl_surface_set_hidden(mg_surface_data* interface, bool hidden);
bool mg_egl_surface_get_hidden(mg_surface_data* interface);
*/
#if OS_MACOS
//NOTE: on macOS we need to explicitly set EGL_PLATFORM_ANGLE_TYPE_ANGLE to EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, because
// EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE defaults to using CGL, and eglSetSwapInterval is broken for this backend
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
#elif OS_WIN64
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
#endif
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)
//TODO: just need to check that the handle is valid
// then get native pointer from window handle
void* nativeSurface = mg_egl_get_native_surface(window);
if(nativeSurface)
{
mg_egl_surface* surface = malloc_type(mg_egl_surface);
memset(surface, 0, sizeof(mg_egl_surface));
@ -93,22 +89,12 @@ mg_surface mg_egl_surface_create_for_window(mp_window window)
surface->interface.setHidden = mg_egl_surface_set_hidden;
*/
surface->nativeSurface = mg_egl_get_native_surface(windowData);
surface->nativeSurface = nativeSurface;
#if OS_MACOS
//NOTE: we need to explicitly set EGL_PLATFORM_ANGLE_TYPE_ANGLE to EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, because
// EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE defaults to using CGL, and eglSetSwapInterval is broken for this backend
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};
#else
EGLAttrib displayAttribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE};
#endif
EGLAttrib displayAttribs[] = {
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};
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
eglInitialize(surface->eglDisplay, NULL, NULL);

View File

@ -15,6 +15,9 @@
extern "C" {
#endif
//---------------------------------------------------------------
// surface data
//---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data;
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);

View File

@ -60,7 +60,7 @@
#endif
#if MG_COMPILE_BACKEND_GL
#include"wgl_surface.c"
= #include"wgl_surface.c"
#include"gl_canvas.c"
#endif

View File

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

View File

@ -9,6 +9,8 @@
#ifndef __MP_APP_INTERNAL_H_
#define __MP_APP_INTERNAL_H_
#include"mp_app.h"
#include"platform.h"
#include"ringbuffer.h"
@ -148,6 +150,4 @@ typedef struct mp_app
MP_PLATFORM_APP_DATA
} mp_app;
mp_window_data* mp_window_ptr_from_handle(mp_window handle);
#endif // __MP_APP_INTERNAL_H_

View File

@ -24,7 +24,6 @@ typedef struct mg_mtl_surface
mg_surface_data interface;
// permanent mtl resources
NSView* view;
id<MTLDevice> device;
CAMetalLayer* mtlLayer;
id<MTLCommandQueue> commandQueue;
@ -44,6 +43,7 @@ void mg_mtl_surface_destroy(mg_surface_data* interface)
@autoreleasepool
{
[surface->commandQueue release];
[surface->mtlLayer removeFromSuperlayer];
[surface->mtlLayer release];
[surface->device release];
}
@ -143,7 +143,8 @@ void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
@autoreleasepool
{
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
[surface->view setFrame: cgFrame];
[surface->mtlLayer setFrame: cgFrame];
f32 scale = surface->mtlLayer.contentsScale;
CGSize drawableSize = (CGSize){.width = frame.w * scale, .height = frame.h * scale};
surface->mtlLayer.drawableSize = drawableSize;
@ -156,7 +157,7 @@ mp_rect mg_mtl_surface_get_frame(mg_surface_data* interface)
@autoreleasepool
{
CGRect frame = surface->view.frame;
CGRect frame = surface->mtlLayer.frame;
return((mp_rect){frame.origin.x, frame.origin.y, frame.size.width, frame.size.height});
}
}
@ -209,17 +210,12 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
@autoreleasepool
{
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
surface->view = [[NSView alloc] initWithFrame: frame];
[surface->view setWantsLayer:YES];
[[windowData->osx.nsWindow contentView] addSubview: surface->view];
surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT);
//-----------------------------------------------------------
//NOTE(martin): create a mtl device and a mtl layer and
//-----------------------------------------------------------
surface->device = MTLCreateSystemDefaultDevice();
[surface->device retain];
surface->mtlLayer = [CAMetalLayer layer];
@ -231,7 +227,9 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
//-----------------------------------------------------------
//NOTE(martin): set the size and scaling
//-----------------------------------------------------------
CGSize size = surface->view.bounds.size;
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size;
surface->mtlLayer.frame = (CGRect){{0, 0}, size};
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size;
@ -239,11 +237,9 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
surface->view.wantsLayer = YES;
surface->view.layer = surface->mtlLayer;
[windowData->osx.nsView.layer addSublayer: surface->mtlLayer];
//NOTE(martin): handling resizing
surface->view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->mtlLayer.needsDisplayOnBoundsChange = YES;

View File

@ -729,6 +729,7 @@ static void mp_update_key_mods(mp_key_mods mods)
window = mpWindow;
mpWindow->osx.nsView = self;
[mpWindow->osx.nsView setWantsLayer:YES];
mpWindow->osx.nsView.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
NSTrackingAreaOptions trackingOptions = NSTrackingMouseEnteredAndExited
| NSTrackingMouseMoved

194
src/osx_egl_surface.m Normal file
View File

@ -0,0 +1,194 @@
/************************************************************//**
*
* @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;
@autoreleasepool
{
[surface->layer release];
}
//////////////////////////////////////////////////
//TODO
//////////////////////////////////////////////////
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);
}

View File

@ -822,4 +822,15 @@ str8 mp_app_get_resource_path(mem_arena* arena, const char* name)
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void* mg_egl_get_native_surface(mp_window_data* window)
{
void* res = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData)
{
res = (void*)windowData->win32.hWnd;
}
return(res);
}
#undef LOG_SUBSYSTEM

View File

@ -1,17 +1,11 @@
Overview
--------
[x] Pan/Zoom on text example
[.] Clean+Fixes of canvas code and examples
[.] Make backend selection easier
[x] rename backend-specific files with api prefix (e.g. egl_, nsgl_, wgl_, mtl_, ...)
[x] option macros to select surface/canvas backends to compile into milepost lib
[.] option macros to select backend-specific APIs to include when building an app
(ie, include gl_api.h when using gl backend)
[x] surface/canvas functions that take a backend id
[x] feature-detection functions to know what surface/canvas backends are available at run-time
[>] write doc about these options
[ ] error on bad option macro combinations
[ ] write doc about backend option macros
[>] Image API and backend
[ ] Build image atlas on top
@ -24,25 +18,36 @@ Overview
[/] Keep dummy window/dummy context around for gl context creation, and don't reload wgl functions every time
[.] Reintroduce GLES surface
[ ] See how we can isolate platform-specific stuff and just deal with egl there..
[?] See how we can isolate platform-specific stuff and just deal with egl there...
[>] Back surface by child windows and implement moving frame/hiding/overlay
[.] Back surface by child windows and implement moving frame/hiding/overlay
[x] osx gles surface
[ ] Sort out gles contents scaling for high dpi
[ ] win32 opengl surfaces
[ ] win32 gles surface
[>] Check that we can make GLES and GL surfaces co-exist in the app
[/] could have an internal, per-platform mp_layer struct that handles resizing/hiding etc...
-> avoid duplication of frame/hiding and duplication of egl code.
[?] Backport canvas to GLES
[ ] then check that we can make GLES and GL surfaces co-exist in the app
[!] Make linking with libEGL optional, even if EGL backend is compiled in milepost?
[!] Bundle examples with their own resources?? (e.g. avoiding clashes in metal libs files in bin directory)
[!] Fix canvas shader precision issue on OSX
[!] Fix canvas perf issue on OSX
[!] osx: Remove need to include objc defs from osx_app.h in egl impl. Also properly guard angle backend attribute (must be metal on osx and default on win32)
[ ] Delegated drawing API+Impl
[ ] Make building apps simpler
[ ] single include path
[ ] script for embedding dependencies / create app bundle
[?] Backport canvas to GLES
Clean+Fixes
-----------