[surface/canvas cleanup]

- Make build-time and runtime backend selection a bit easier
- Reorganized backend-specific files with slightly more coherent naming scheme
This commit is contained in:
martinfouilleul 2023-02-10 16:56:10 +01:00
parent f54f639db5
commit 80ea8db687
34 changed files with 13006 additions and 13501 deletions

View File

@ -6,5 +6,5 @@ set glsl_shaders=src\glsl_shaders\common.glsl src\glsl_shaders\blit_vertex.glsl
call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_shaders.h
set INCLUDES=/I src /I src/util /I src/platform /I ext
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c
lib bin/milepost.obj /OUT:bin/milepost.lib

164
build.sh
View File

@ -1,82 +1,82 @@
#!/bin/bash
DEBUG_FLAGS="-g -DDEBUG -DLOG_COMPILE_DEBUG"
#DEBUG_FLAGS="-O3"
#--------------------------------------------------------------
# set target
#--------------------------------------------------------------
target="$1"
if [ -z $target ] ; then
target='lib'
fi
shaderFlagParam="$2"
#--------------------------------------------------------------
# Detect OS and set environment variables accordingly
#--------------------------------------------------------------
OS=$(uname -s)
if [ $OS = "Darwin" ] ; then
#echo "Target '$target' for macOS"
CC=clang
CXX=clang++
DYLIB_SUFFIX='dylib'
SYS_LIBS=''
FLAGS="-mmacos-version-min=10.15.4 -DMG_IMPLEMENTS_BACKEND_METAL -DMG_IMPLEMENTS_BACKEND_GLES -maes"
CFLAGS="-std=c11"
elif [ $OS = "Linux" ] ; then
echo "Error: Linux is not supported yet"
exit -1
else
echo "Error: Unsupported OS $OS"
exit -1
fi
#--------------------------------------------------------------
# Set paths
#--------------------------------------------------------------
BINDIR="./bin"
SRCDIR="./src"
EXTDIR="./ext"
RESDIR="./resources"
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$EXTDIR/angle_headers"
#--------------------------------------------------------------
# Build
#--------------------------------------------------------------
if [ ! \( -e bin \) ] ; then
mkdir ./bin
fi
if [ $target = 'lib' ] ; then
# compile metal shader
xcrun -sdk macosx metal $shaderFlagParam -c -o $BINDIR/metal_shader.air $SRCDIR/metal_shader.metal
xcrun -sdk macosx metallib -o $RESDIR/metal_shader.metallib $BINDIR/metal_shader.air
# compile milepost. We use one compilation unit for all C code, and one compilation
# unit for all ObjectiveC code
$CC $DEBUG_FLAGS -c -o $BINDIR/milepost_c.o $CFLAGS $FLAGS $INCLUDES $SRCDIR/milepost.c
$CC $DEBUG_FLAGS -c -o $BINDIR/milepost_objc.o $FLAGS $INCLUDES $SRCDIR/milepost.m
# build the static library
libtool -static -o $BINDIR/libmilepost.a $BINDIR/milepost_c.o $BINDIR/milepost_objc.o
else
# additional targets
if [ $target = 'test' ] ; then
pushd examples/test_app
./build.sh
popd
elif [ $target = 'clean' ] ; then
rm -r ./bin
else
echo "unrecognized target $target"
exit -1
fi
fi
#!/bin/bash
DEBUG_FLAGS="-g -DDEBUG -DLOG_COMPILE_DEBUG"
#DEBUG_FLAGS="-O3"
#--------------------------------------------------------------
# set target
#--------------------------------------------------------------
target="$1"
if [ -z $target ] ; then
target='lib'
fi
shaderFlagParam="$2"
#--------------------------------------------------------------
# Detect OS and set environment variables accordingly
#--------------------------------------------------------------
OS=$(uname -s)
if [ $OS = "Darwin" ] ; then
#echo "Target '$target' for macOS"
CC=clang
CXX=clang++
DYLIB_SUFFIX='dylib'
SYS_LIBS=''
FLAGS="-mmacos-version-min=10.15.4 -maes"
CFLAGS="-std=c11"
elif [ $OS = "Linux" ] ; then
echo "Error: Linux is not supported yet"
exit -1
else
echo "Error: Unsupported OS $OS"
exit -1
fi
#--------------------------------------------------------------
# Set paths
#--------------------------------------------------------------
BINDIR="./bin"
SRCDIR="./src"
EXTDIR="./ext"
RESDIR="./resources"
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$EXTDIR/angle_headers"
#--------------------------------------------------------------
# Build
#--------------------------------------------------------------
if [ ! \( -e bin \) ] ; then
mkdir ./bin
fi
if [ $target = 'lib' ] ; then
# compile metal shader
xcrun -sdk macosx metal $shaderFlagParam -c -o $BINDIR/metal_shader.air $SRCDIR/metal_shader.metal
xcrun -sdk macosx metallib -o $RESDIR/metal_shader.metallib $BINDIR/metal_shader.air
# compile milepost. We use one compilation unit for all C code, and one compilation
# unit for all ObjectiveC code
$CC $DEBUG_FLAGS -c -o $BINDIR/milepost_c.o $CFLAGS $FLAGS $INCLUDES $SRCDIR/milepost.c
$CC $DEBUG_FLAGS -c -o $BINDIR/milepost_objc.o $FLAGS $INCLUDES $SRCDIR/milepost.m
# build the static library
libtool -static -o $BINDIR/libmilepost.a $BINDIR/milepost_c.o $BINDIR/milepost_objc.o
else
# additional targets
if [ $target = 'test' ] ; then
pushd examples/test_app
./build.sh
popd
elif [ $target = 'clean' ] ; then
rm -r ./bin
else
echo "unrecognized target $target"
exit -1
fi
fi

View File

@ -1,3 +1,4 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_canvas.exe
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /out:../../bin/example_canvas.exe

View File

@ -1,11 +1,11 @@
#!/bin/bash
BINDIR=../../bin
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"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG -Wl,-dead_strip -DMG_IMPLEMENTS_BACKEND_METAL"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_canvas main.c
#!/bin/bash
BINDIR=../../bin
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"
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

View File

@ -8,6 +8,7 @@
*****************************************************************/
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
#include<math.h>
@ -16,6 +17,7 @@
#define LOG_SUBSYSTEM "Main"
mg_font create_font()
{
//NOTE(martin): create font
@ -25,7 +27,7 @@ mg_font create_font()
FILE* fontFile = fopen(fontPathCString, "r");
if(!fontFile)
{
LOG_ERROR("Could not load font file '%s'\n", fontPathCString);
LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno));
return(mg_font_nil());
}
unsigned char* fontData = 0;
@ -53,22 +55,26 @@ int main()
LogLevel(LOG_LEVEL_DEBUG);
mp_init();
mp_clock_init();
mp_clock_init(); //TODO put that in mp_init()?
mp_rect rect = {.x = 100, .y = 100, .w = 800, .h = 600};
mp_window window = mp_window_create(rect, "test", 0);
mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610};
mp_window window = mp_window_create(windowRect, "test", 0);
mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface
#if defined(OS_MACOS)
mg_surface surface = mg_metal_surface_create_for_window(window);
#elif defined(OS_WIN64)
mg_surface surface = mg_gl_surface_create_for_window(window);
#else
#error "unsupported OS"
#endif
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface_swap_interval(surface, 0);
//TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface);
if(mg_canvas_is_nil(canvas))
{
printf("Error: couldn't create canvas\n");
return(-1);
}
mg_font font = create_font();
// start app
@ -76,7 +82,8 @@ int main()
mp_window_focus(window);
f32 x = 400, y = 300;
f32 dx = 5, dy = 5;
f32 speed = 0;
f32 dx = speed, dy = speed;
f64 frameTime = 0;
while(!mp_should_quit())
@ -94,37 +101,39 @@ 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_KEYBOARD_KEY:
{
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
{
/*
if(event.key.code == MP_KEY_LEFT)
{
dx-=5.1;
if(x - 200 > 0)
{
x-=5;
}
}
else if(event.key.code == MP_KEY_RIGHT)
{
dx+=5.1;
if(x + 200 < contentRect.w)
{
x+=5;
}
}
else if(event.key.code == MP_KEY_UP)
{
dy+=5.1;
if(y + 200 < contentRect.h)
{
y+=5;
}
}
else if(event.key.code == MP_KEY_DOWN)
{
dy-=5.1;
if(y - 200 > 0)
{
y-=5;
}
}
*/
//*/
}
} break;
@ -135,19 +144,23 @@ int main()
if(x-200 < 0)
{
dx = 5;
x = 200;
dx = speed;
}
if(x+200 > 800)
if(x+200 > contentRect.w)
{
dx = -5;
x = contentRect.w - 200;
dx = -speed;
}
if(y-200 < 0)
{
dy = 5;
y = 200;
dy = speed;
}
if(y+200 > 550)
if(y+200 > contentRect.h)
{
dy = -5;
y = contentRect.h - 200;
dy = -speed;
}
x += dx;
y += dy;
@ -166,7 +179,6 @@ int main()
f32 frown = frameTime > 0.033 ? 100 : 0;
mg_set_color_rgba(0, 0, 0, 1);
mg_set_width(20);
mg_move_to(x-100, y-100);
mg_cubic_to(x-50, y-150+frown, x+50, y-150+frown, x+100, y-100);
@ -198,9 +210,13 @@ int main()
mem_arena_clear(mem_scratch());
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
}
mg_font_destroy(font);
mg_canvas_destroy(canvas);
mg_surface_destroy(surface);
mp_window_destroy(window);
mp_terminate();
return(0);

View File

@ -1,4 +1,4 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /out:../../bin/perf_text.exe
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /out:../../bin/perf_text.exe

View File

@ -63,10 +63,8 @@ static const char* TEST_STRING =
mg_font create_font()
{
//NOTE(martin): create font
/* str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf");
str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf");
char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath);
*/
char* fontPathCString = "resources/OpenSansLatinSubset.ttf";
FILE* fontFile = fopen(fontPathCString, "r");
if(!fontFile)
@ -107,13 +105,7 @@ int main()
//NOTE: create surface, canvas and font
#if defined(OS_MACOS)
mg_surface surface = mg_metal_surface_create_for_window(window);
#elif defined(OS_WIN64)
mg_surface surface = mg_gl_surface_create_for_window(window);
#else
#error "unsupported OS"
#endif
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface_swap_interval(surface, 0);
mg_canvas canvas = mg_canvas_create(surface);
@ -300,6 +292,11 @@ int main()
mem_arena_clear(mem_scratch());
}
mg_font_destroy(font);
mg_canvas_destroy(canvas);
mg_surface_destroy(surface);
mp_window_destroy(window);
mp_terminate();
return(0);

View File

@ -1,3 +0,0 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /out:../../bin/example_canvas.exe

View File

@ -1,11 +0,0 @@
#!/bin/bash
BINDIR=../../bin
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"
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

View File

@ -1,247 +0,0 @@
/************************************************************//**
*
* @file: main.cpp
* @author: Martin Fouilleul
* @date: 30/07/2022
* @revision:
*
*****************************************************************/
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
#include<math.h>
#include"milepost.h"
#define LOG_SUBSYSTEM "Main"
mg_font create_font()
{
//NOTE(martin): create font
str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf");
char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath);
FILE* fontFile = fopen(fontPathCString, "r");
if(!fontFile)
{
LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno));
return(mg_font_nil());
}
unsigned char* fontData = 0;
fseek(fontFile, 0, SEEK_END);
u32 fontDataSize = ftell(fontFile);
rewind(fontFile);
fontData = (unsigned char*)malloc(fontDataSize);
fread(fontData, 1, fontDataSize, fontFile);
fclose(fontFile);
unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN,
UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
UNICODE_RANGE_LATIN_EXTENDED_A,
UNICODE_RANGE_LATIN_EXTENDED_B,
UNICODE_RANGE_SPECIALS};
mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges);
free(fontData);
return(font);
}
int main()
{
LogLevel(LOG_LEVEL_DEBUG);
mp_init();
mp_clock_init(); //TODO put that in mp_init()?
mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610};
mp_window window = mp_window_create(windowRect, "test", 0);
mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface
#if defined(OS_MACOS)
mg_surface surface = mg_metal_surface_create_for_window(window);
#elif defined(OS_WIN64)
mg_surface surface = mg_gl_surface_create_for_window(window);
#else
#error "unsupported OS"
#endif
mg_surface_swap_interval(surface, 0);
//TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface);
if(mg_canvas_is_nil(canvas))
{
printf("Error: couldn't create canvas\n");
return(-1);
}
mg_font font = create_font();
// start app
mp_window_bring_to_front(window);
mp_window_focus(window);
f32 x = 400, y = 300;
f32 speed = 0;
f32 dx = speed, dy = speed;
f64 frameTime = 0;
while(!mp_should_quit())
{
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0);
mp_event event = {0};
while(mp_next_event(&event))
{
switch(event.type)
{
case MP_EVENT_WINDOW_CLOSE:
{
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_KEYBOARD_KEY:
{
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
{
//*
if(event.key.code == MP_KEY_LEFT)
{
if(x - 200 > 0)
{
x-=5;
}
}
else if(event.key.code == MP_KEY_RIGHT)
{
if(x + 200 < contentRect.w)
{
x+=5;
}
}
else if(event.key.code == MP_KEY_UP)
{
if(y + 200 < contentRect.h)
{
y+=5;
}
}
else if(event.key.code == MP_KEY_DOWN)
{
if(y - 200 > 0)
{
y-=5;
}
}
//*/
}
} break;
default:
break;
}
}
if(x-200 < 0)
{
x = 200;
dx = speed;
}
if(x+200 > contentRect.w)
{
x = contentRect.w - 200;
dx = -speed;
}
if(y-200 < 0)
{
y = 200;
dy = speed;
}
if(y+200 > contentRect.h)
{
y = contentRect.h - 200;
dy = -speed;
}
x += dx;
y += dy;
mg_surface_prepare(surface);
// background
mg_set_color_rgba(0, 1, 1, 1);
mg_clear();
// mg_clip_push(100, 100, contentRect.w - 200, contentRect.h - 200);
// head
mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 200);
/*
mg_clip_pop();
mg_set_width(2);
mg_set_color_rgba(1, 0, 0, 1);
mg_rectangle_stroke(100, 100, contentRect.w - 200, contentRect.h - 200);
*/
// smile
f32 frown = frameTime > 0.033 ? 100 : 0;
mg_set_color_rgba(0, 0, 0, 1);
mg_set_width(20);
mg_move_to(x-100, y-100);
mg_cubic_to(x-50, y-150+frown, x+50, y-150+frown, x+100, y-100);
mg_stroke();
// eyes
mg_ellipse_fill(x-70, y+50, 30, 50);
mg_ellipse_fill(x+70, y+50, 30, 50);
// text
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font_size(12);
mg_move_to(50, 50);
str8 text = str8_pushf(mem_scratch(),
"Milepost vector graphics test program (frame time = %fs, fps = %f)...",
frameTime,
1./frameTime);
mg_text_outlines(text);
mg_fill();
printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n",
frameTime,
1./frameTime);
mg_flush();
mg_surface_present(surface);
mem_arena_clear(mem_scratch());
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
}
mg_font_destroy(font);
mg_canvas_destroy(canvas);
mg_surface_destroy(surface);
mp_window_destroy(window);
mp_terminate();
return(0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -38,17 +38,6 @@ typedef struct mg_gl_canvas_backend
} mg_gl_canvas_backend;
mg_gl_surface* mg_gl_canvas_get_surface(mg_gl_canvas_backend* canvas)
{
mg_gl_surface* res = 0;
mg_surface_data* data = mg_surface_data_from_handle(canvas->surface);
if(data && data->backend == MG_BACKEND_GL)
{
res = (mg_gl_surface*)data;
}
return(res);
}
//NOTE: debugger
typedef struct debug_vertex
{
@ -140,11 +129,6 @@ void mg_gl_send_buffers(mg_gl_canvas_backend* backend, int shapeCount, int verte
void mg_gl_canvas_begin(mg_canvas_backend* interface)
{
mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface;
mg_gl_surface* surface = mg_gl_canvas_get_surface(backend);
if(!surface)
{
return;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
@ -157,11 +141,6 @@ void mg_gl_canvas_end(mg_canvas_backend* interface)
void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
{
mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface;
mg_gl_surface* surface = mg_gl_canvas_get_surface(backend);
if(!surface)
{
return;
}
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
glClear(GL_COLOR_BUFFER_BIT);
@ -170,11 +149,6 @@ void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 vertexCount, u32 indexCount)
{
mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface;
mg_gl_surface* surface = mg_gl_canvas_get_surface(backend);
if(!surface)
{
return;
}
/*NOTE: if we want debug_vertex while debugging, the following ensures the struct def doesn't get stripped away
debug_vertex vertex;
@ -390,8 +364,6 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
if(surfaceData && surfaceData->backend == MG_BACKEND_GL)
{
mg_gl_surface* glSurface = (mg_gl_surface*)surfaceData;
backend = malloc_type(mg_gl_canvas_backend);
memset(backend, 0, sizeof(mg_gl_canvas_backend));
backend->surface = surface;

View File

@ -290,6 +290,89 @@ mg_font_data* mg_font_data_from_handle(mg_font font)
// surface API
//---------------------------------------------------------------
#if MG_COMPILE_BACKEND_GL
#if defined(OS_WIN64)
#include"wgl_surface.h"
#define gl_surface_create_for_window mg_wgl_surface_create_for_window
#elif defined(OS_MACOS)
/*
#include"nsgl_surface.h"
#define gl_surface_create_for_window nsgl_surface_create_for_window
*/
#endif
#endif
#if MG_COMPILE_BACKEND_METAL
#include"mtl_surface.h"
#endif
bool mg_is_surface_backend_available(mg_backend_id backend)
{
bool result = false;
switch(backend)
{
#if MG_COMPILE_BACKEND_METAL
case MG_BACKEND_METAL:
#endif
#if MG_COMPILE_BACKEND_GL
case MG_BACKEND_GL:
#endif
#if MG_COMPILE_BACKEND_GLES
case MG_BACKEND_GLES:
#endif
result = true;
break;
default:
break;
}
return(result);
}
bool mg_is_canvas_backend_available(mg_backend_id backend)
{
bool result = false;
switch(backend)
{
#if MG_COMPILE_BACKEND_METAL
case MG_BACKEND_METAL:
#endif
#if MG_COMPILE_BACKEND_GL && defined(OS_WIN64)
case MG_BACKEND_GL:
#endif
result = true;
break;
default:
break;
}
return(result);
}
mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend)
{
mg_surface surface = mg_surface_nil();
switch(backend)
{
#if MG_COMPILE_BACKEND_GL
case MG_BACKEND_GL:
surface = gl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_BACKEND_METAL
case MG_METAL_BACKEND:
surface = mg_mtl_surface_create_for_window(window);
break;
#endif
default:
break;
}
return(surface);
}
void mg_surface_destroy(mg_surface handle)
{
DEBUG_ASSERT(__mgData.init);
@ -2563,19 +2646,14 @@ mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text)
//NOTE(martin): graphics canvas API
//------------------------------------------------------------------------------------------
#ifdef MG_IMPLEMENTS_BACKEND_METAL
mg_canvas_backend* mg_metal_canvas_create(mg_surface surface);
#ifdef MG_COMPILE_BACKEND_METAL
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface);
#endif
#ifdef MG_IMPLEMENTS_BACKEND_GLES
mg_canvas_backend* mg_gles_canvas_create(mg_surface surface);
#endif
#ifdef MG_IMPLEMENTS_BACKEND_GL
#ifdef MG_COMPILE_BACKEND_GL
mg_canvas_backend* mg_gl_canvas_create(mg_surface surface);
#endif
mg_canvas mg_canvas_create(mg_surface surface)
{
mg_canvas canvas = mg_canvas_nil();
@ -2585,20 +2663,13 @@ mg_canvas mg_canvas_create(mg_surface surface)
mg_canvas_backend* backend = 0;
switch(surfaceData->backend)
{
#ifdef MG_IMPLEMENTS_BACKEND_METAL
#ifdef MG_COMPILE_BACKEND_METAL
case MG_BACKEND_METAL:
backend = mg_metal_canvas_create(surface);
backend = mg_mtl_canvas_create(surface);
break;
#endif
/*
#ifdef MG_IMPLEMENTS_BACKEND_GLES
case MG_BACKEND_GLES:
backend = mg_gles_canvas_create(surface);
break;
#endif
*/
#ifdef MG_IMPLEMENTS_BACKEND_GL
#ifdef MG_COMPILE_BACKEND_GL
case MG_BACKEND_GL:
backend = mg_gl_canvas_create(surface);
break;

View File

@ -9,6 +9,72 @@
#ifndef __GRAPHICS_H_
#define __GRAPHICS_H_
#include"typedefs.h"
#include"platform.h"
//------------------------------------------------------------------------------------------
//NOTE(martin): backends selection
//------------------------------------------------------------------------------------------
typedef enum {
MG_BACKEND_NONE,
MG_BACKEND_METAL,
MG_BACKEND_GL,
MG_BACKEND_GLES } mg_backend_id;
//NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line
#if defined(OS_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1
#endif
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#if MG_COMPILE_BACKEND_METAL
#define MG_BACKEND_DEFAULT MG_BACKEND_METAL
#elif MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_WIN64)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#if MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_LINUX)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost
#ifdef MG_EXPOSE_SURFACE_METAL
#include"mtl_surface.h"
#endif
#ifdef MG_EXPOSE_SURFACE_WGL
#include"wgl_surface.h"
#endif
//TODO: expose nsgl surface when supported, expose egl surface, etc...
//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
bool mg_is_surface_backend_available(mg_backend_id id);
bool mg_is_canvas_backend_available(mg_backend_id id);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics surface
//------------------------------------------------------------------------------------------
@ -17,6 +83,7 @@ typedef struct mg_surface { u64 h; } mg_surface;
mg_surface mg_surface_nil();
bool mg_surface_is_nil(mg_surface surface);
mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend);
void mg_surface_destroy(mg_surface surface);
void mg_surface_prepare(mg_surface surface);
void mg_surface_present(mg_surface surface);

View File

@ -15,13 +15,6 @@
extern "C" {
#endif
typedef enum { MG_BACKEND_DUMMY,
MG_BACKEND_METAL,
MG_BACKEND_GL,
MG_BACKEND_GLES,
//...
} mg_backend_id;
typedef struct mg_surface_data mg_surface_data;
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);

View File

@ -1,26 +0,0 @@
/************************************************************//**
*
* @file: metal_surface.h
* @author: Martin Fouilleul
* @date: 25/12/2022
* @revision:
*
*****************************************************************/
#ifndef __METAL_SURFACE_H_
#define __METAL_SURFACE_H_
#include"graphics.h"
#ifdef __OBJC__
#import<Metal/Metal.h>
#endif
mg_surface mg_metal_surface_create_for_window(mp_window window);
void* mg_metal_surface_render_encoder(mg_surface surface);
void* mg_metal_surface_compute_encoder(mg_surface surface);
void* mg_metal_surface_layer(mg_surface surface);
void* mg_metal_surface_drawable(mg_surface surface);
void* mg_metal_surface_command_buffer(mg_surface surface);
#endif //__METAL_SURFACE_H_

View File

@ -48,23 +48,21 @@
#endif
//---------------------------------------------------------------
// application layer
// app/graphics layer
//---------------------------------------------------------------
#if defined(OS_WIN64)
#include"win32_app.c"
#include"win32_gl_surface.c"
#include"gl_canvas.c"
// #include"win32_gles_surface.c"
// #include"gles_canvas.c"
#include"graphics.c"
#if MG_COMPILE_BACKEND_GL
#include"wgl_surface.c"
#include"gl_canvas.c"
#endif
#elif defined(OS_MACOS)
//NOTE: macos application layer is defined in milepost.m
//NOTE: macos application layer and graphics backends are defined in milepost.m
#include"graphics.c"
#else
#error "Unsupported platform"
#endif
//---------------------------------------------------------------
// graphics/ui layer
//---------------------------------------------------------------
#include"graphics.c"
//#include"ui.c"

View File

@ -33,34 +33,17 @@
*/
//----------------------------------------------------------------
// application layer
// application/graphics layer
//----------------------------------------------------------------
#include"mp_app.h"
#if defined(OS_WIN64) || defined(OS_WIN32)
#if MG_IMPLEMENTS_BACKEND_GLES
#include"win32_gles_surface.h"
#endif
#if MG_IMPLEMENTS_BACKEND_GL
#define WIN32_GL_LOADER_API
#include"win32_gl_loader.h"
#undef WIN32_GL_LOADER_API
#include"win32_gl_surface.h"
#endif
#endif
#if MG_IMPLEMENTS_BACKEND_METAL
#include"metal_surface.h"
#endif
//----------------------------------------------------------------
// graphics/ui layer
//----------------------------------------------------------------
#include"graphics.h"
#if defined(OS_WIN64)
#define WIN32_GL_LOADER_API
#include"wgl_loader.h"
#undef WIN32_GL_LOADER_API
#endif
//#include"ui.h"
#endif //__MILEPOST_H_

View File

@ -1,19 +1,24 @@
/************************************************************//**
*
* @file: milepost.m
* @author: Martin Fouilleul
* @date: 13/02/2021
* @revision:
*
*****************************************************************/
#include"osx_app.m"
#include"metal_surface.m"
#include"metal_canvas.m"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include"osx_gles_surface.m"
#pragma clang diagnostic pop
//#include"osx_surface_client.m"
/************************************************************//**
*
* @file: milepost.m
* @author: Martin Fouilleul
* @date: 13/02/2021
* @revision:
*
*****************************************************************/
#include"osx_app.m"
#include"graphics.h"
#if MG_COMPILE_BACKEND_METAL
#include"mtl_surface.m"
#include"mtl_canvas.m"
#endif
/*
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include"osx_gles_surface.m"
#pragma clang diagnostic pop
*/
//#include"osx_surface_client.m"

View File

@ -1,6 +1,6 @@
/************************************************************//**
*
* @file: metal_canvas.m
* @file: mtl_canvas.m
* @author: Martin Fouilleul
* @date: 12/07/2020
* @revision: 24/01/2023
@ -14,13 +14,13 @@
#include"macro_helpers.h"
#include"osx_app.h"
#include"metal_shader.h"
#include"mtl_shader.h"
#define LOG_SUBSYSTEM "Graphics"
static const int MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH = 4<<20;
static const int MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH = 4<<20;
typedef struct mg_metal_canvas_backend
typedef struct mg_mtl_canvas_backend
{
mg_canvas_backend interface;
mg_surface surface;
@ -47,36 +47,36 @@ typedef struct mg_metal_canvas_backend
id<MTLBuffer> triangleArray;
id<MTLBuffer> boxArray;
} mg_metal_canvas_backend;
} mg_mtl_canvas_backend;
mg_metal_surface* mg_metal_canvas_get_surface(mg_metal_canvas_backend* canvas)
mg_mtl_surface* mg_mtl_canvas_get_surface(mg_mtl_canvas_backend* canvas)
{
mg_metal_surface* res = 0;
mg_mtl_surface* res = 0;
mg_surface_data* data = mg_surface_data_from_handle(canvas->surface);
if(data && data->backend == MG_BACKEND_METAL)
{
res = (mg_metal_surface*)data;
res = (mg_mtl_surface*)data;
}
return(res);
}
void mg_metal_canvas_begin(mg_canvas_backend* interface)
void mg_mtl_canvas_begin(mg_canvas_backend* interface)
{}
void mg_metal_canvas_end(mg_canvas_backend* interface)
void mg_mtl_canvas_end(mg_canvas_backend* interface)
{}
void mg_metal_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
void mg_mtl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
{
//TODO
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
backend->clearColor = clearColor;
}
void mg_metal_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, u32 shapeCount)
void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, u32 shapeCount)
{
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend);
if(!surface)
{
return;
@ -86,7 +86,7 @@ void mg_metal_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u
{
if(surface->commandBuffer == nil || surface->commandBuffer == nil)
{
mg_metal_surface_acquire_drawable_and_command_buffer(surface);
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
}
ASSERT(indexCount * sizeof(i32) < [backend->indexBuffer length]);
@ -205,10 +205,10 @@ void mg_metal_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u
}
/*
void mg_metal_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort)
void mg_mtl_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort)
{
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend);
if(!surface)
{
return;
@ -236,15 +236,15 @@ void mg_metal_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort)
}
*/
void mg_metal_canvas_update_vertex_layout(mg_metal_canvas_backend* backend)
void mg_mtl_canvas_update_vertex_layout(mg_mtl_canvas_backend* backend)
{
char* vertexBase = (char*)[backend->vertexBuffer contents];
char* shapeBase = (char*)[backend->shapeBuffer contents];
char* indexBase = (char*)[backend->indexBuffer contents];
backend->interface.vertexLayout = (mg_vertex_layout){
.maxVertexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
.maxIndexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
.maxVertexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH,
.maxIndexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH,
.cubicBuffer = vertexBase + offsetof(mg_vertex, cubic),
.cubicStride = sizeof(mg_vertex),
.posBuffer = vertexBase + offsetof(mg_vertex, pos),
@ -263,9 +263,9 @@ void mg_metal_canvas_update_vertex_layout(mg_metal_canvas_backend* backend)
.indexStride = sizeof(int)};
}
void mg_metal_canvas_destroy(mg_canvas_backend* interface)
void mg_mtl_canvas_destroy(mg_canvas_backend* interface)
{
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
@autoreleasepool
{
@ -280,9 +280,9 @@ void mg_metal_canvas_destroy(mg_canvas_backend* interface)
}
}
void mg_metal_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes)
void mg_mtl_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes)
{@autoreleasepool{
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
MTLRegion region = MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h);
[backend->atlasTexture replaceRegion:region
@ -291,25 +291,25 @@ void mg_metal_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8
bytesPerRow: 4 * rect.w];
}}
mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
{
mg_metal_canvas_backend* backend = 0;
mg_mtl_canvas_backend* backend = 0;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
mg_mtl_surface* metalSurface = (mg_mtl_surface*)surfaceData;
backend = malloc_type(mg_metal_canvas_backend);
backend = malloc_type(mg_mtl_canvas_backend);
backend->surface = surface;
//NOTE(martin): setup interface functions
backend->interface.destroy = mg_metal_canvas_destroy;
backend->interface.begin = mg_metal_canvas_begin;
backend->interface.end = mg_metal_canvas_end;
backend->interface.clear = mg_metal_canvas_clear;
backend->interface.drawBatch = mg_metal_canvas_draw_batch;
backend->interface.atlasUpload = mg_metal_canvas_atlas_upload;
backend->interface.destroy = mg_mtl_canvas_destroy;
backend->interface.begin = mg_mtl_canvas_begin;
backend->interface.end = mg_mtl_canvas_end;
backend->interface.clear = mg_mtl_canvas_clear;
backend->interface.drawBatch = mg_mtl_canvas_draw_batch;
backend->interface.atlasUpload = mg_mtl_canvas_atlas_upload;
mp_rect frame = mg_surface_get_frame(surface);
backend->viewPort = (mp_rect){0, 0, frame.w, frame.h};
@ -352,22 +352,22 @@ mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
| MTLResourceStorageModeShared;
backend->indexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(int)
backend->indexBuffer = [metalSurface->device newBufferWithLength: MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(int)
options: bufferOptions];
backend->vertexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_vertex)
backend->vertexBuffer = [metalSurface->device newBufferWithLength: MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_vertex)
options: bufferOptions];
backend->shapeBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_shape)
backend->shapeBuffer = [metalSurface->device newBufferWithLength: MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_shape)
options: bufferOptions];
backend->tilesArray = [metalSurface->device newBufferWithLength: RENDERER_TILE_BUFFER_SIZE*sizeof(int)*RENDERER_MAX_TILES
options: MTLResourceStorageModePrivate];
backend->triangleArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_triangle_data)
backend->triangleArray = [metalSurface->device newBufferWithLength: MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_triangle_data)
options: MTLResourceStorageModePrivate];
backend->boxArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(vector_float4)
backend->boxArray = [metalSurface->device newBufferWithLength: MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(vector_float4)
options: MTLResourceStorageModePrivate];
//TODO(martin): retain ?
@ -387,7 +387,7 @@ mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
//-----------------------------------------------------------
//TODO(martin): filepath magic to find metallib path when not in the working directory
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "../resources/metal_shader.metallib");
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "../resources/mtl_shader.metallib");
NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
NSError* err = 0;
id<MTLLibrary> library = [metalSurface->device newLibraryWithFile: metalFileName error:&err];
@ -460,7 +460,7 @@ mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
}
}
mg_metal_canvas_update_vertex_layout(backend);
mg_mtl_canvas_update_vertex_layout(backend);
}
return((mg_canvas_backend*)backend);

View File

@ -1,13 +1,13 @@
/************************************************************//**
*
* @file: metal_shader.h
* @file: mtl_shader.h
* @author: Martin Fouilleul
* @date: 01/08/2022
* @revision:
*
*****************************************************************/
#ifndef __METAL_RENDERER_H_
#define __METAL_RENDERER_H_
#ifndef __MTL_RENDERER_H_
#define __MTL_RENDERER_H_
#include<simd/simd.h>
@ -50,4 +50,4 @@ typedef struct mg_triangle_data
} mg_triangle_data;
#endif //__METAL_RENDERER_H_
#endif //__MTL_RENDERER_H_

View File

@ -2,7 +2,7 @@
#include<metal_stdlib>
#include<simd/simd.h>
#include"metal_shader.h"
#include"mtl_shader.h"
using namespace metal;

26
src/mtl_surface.h Normal file
View File

@ -0,0 +1,26 @@
/************************************************************//**
*
* @file: mtl_surface.h
* @author: Martin Fouilleul
* @date: 25/12/2022
* @revision:
*
*****************************************************************/
#ifndef __MTL_SURFACE_H_
#define __MTL_SURFACE_H_
#include"graphics.h"
#ifdef __OBJC__
#import<Mtl/Metal.h>
#endif
mg_surface mg_mtl_surface_create_for_window(mp_window window);
void* mg_mtl_surface_render_encoder(mg_surface surface);
void* mg_mtl_surface_compute_encoder(mg_surface surface);
void* mg_mtl_surface_layer(mg_surface surface);
void* mg_mtl_surface_drawable(mg_surface surface);
void* mg_mtl_surface_command_buffer(mg_surface surface);
#endif //__MTL_SURFACE_H_

View File

@ -17,16 +17,16 @@
#define LOG_SUBSYSTEM "Graphics"
static const u32 MP_METAL_MAX_DRAWABLES_IN_FLIGHT = 3;
static const u32 MP_MTL_MAX_DRAWABLES_IN_FLIGHT = 3;
typedef struct mg_metal_surface
typedef struct mg_mtl_surface
{
mg_surface_data interface;
// permanent metal resources
// permanent mtl resources
NSView* view;
id<MTLDevice> device;
CAMetalLayer* metalLayer;
CAMetalLayer* mtlLayer;
id<MTLCommandQueue> commandQueue;
// transient metal resources
@ -35,21 +35,21 @@ typedef struct mg_metal_surface
dispatch_semaphore_t drawableSemaphore;
} mg_metal_surface;
} mg_mtl_surface;
void mg_metal_surface_destroy(mg_surface_data* interface)
void mg_mtl_surface_destroy(mg_surface_data* interface)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
[surface->commandQueue release];
[surface->metalLayer release];
[surface->mtlLayer release];
[surface->device release];
}
}
void mg_metal_surface_acquire_drawable_and_command_buffer(mg_metal_surface* surface)
void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface)
{@autoreleasepool{
/*WARN(martin): this is super important
When the app is put in the background, it seems that if there are buffers in flight, the drawables to
@ -76,7 +76,7 @@ void mg_metal_surface_acquire_drawable_and_command_buffer(mg_metal_surface* surf
*/
dispatch_semaphore_wait(surface->drawableSemaphore, DISPATCH_TIME_FOREVER);
surface->drawable = [surface->metalLayer nextDrawable];
surface->drawable = [surface->mtlLayer nextDrawable];
ASSERT(surface->drawable != nil);
//TODO: make this a weak reference if we use ARC
@ -92,10 +92,10 @@ void mg_metal_surface_acquire_drawable_and_command_buffer(mg_metal_surface* surf
[surface->drawable retain];
}}
void mg_metal_surface_prepare(mg_surface_data* interface)
void mg_mtl_surface_prepare(mg_surface_data* interface)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_metal_surface_acquire_drawable_and_command_buffer(surface);
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
@autoreleasepool
{
@ -109,9 +109,9 @@ void mg_metal_surface_prepare(mg_surface_data* interface)
}
}
void mg_metal_surface_present(mg_surface_data* interface)
void mg_mtl_surface_present(mg_surface_data* interface)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
//NOTE(martin): present drawable and commit command buffer
@ -127,32 +127,32 @@ void mg_metal_surface_present(mg_surface_data* interface)
}
}
void mg_metal_surface_swap_interval(mg_surface_data* interface, int swap)
void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
////////////////////////////////////////////////////////////////
//TODO
////////////////////////////////////////////////////////////////
}
void mg_metal_surface_set_frame(mg_surface_data* interface, mp_rect frame)
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
[surface->view setFrame: cgFrame];
f32 scale = surface->metalLayer.contentsScale;
f32 scale = surface->mtlLayer.contentsScale;
CGSize drawableSize = (CGSize){.width = frame.w * scale, .height = frame.h * scale};
surface->metalLayer.drawableSize = drawableSize;
surface->mtlLayer.drawableSize = drawableSize;
}
}
mp_rect mg_metal_surface_get_frame(mg_surface_data* interface)
mp_rect mg_mtl_surface_get_frame(mg_surface_data* interface)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
@ -161,31 +161,31 @@ mp_rect mg_metal_surface_get_frame(mg_surface_data* interface)
}
}
void mg_metal_surface_set_hidden(mg_surface_data* interface, bool hidden)
void mg_mtl_surface_set_hidden(mg_surface_data* interface, bool hidden)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[surface->metalLayer setHidden:hidden];
[surface->mtlLayer setHidden:hidden];
[CATransaction commit];
}
}
bool mg_metal_surface_get_hidden(mg_surface_data* interface)
bool mg_mtl_surface_get_hidden(mg_surface_data* interface)
{
mg_metal_surface* surface = (mg_metal_surface*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
return([surface->metalLayer isHidden]);
return([surface->mtlLayer isHidden]);
}
}
//TODO fix that according to real scaling, depending on the monitor settings
static const f32 MG_METAL_SURFACE_CONTENTS_SCALING = 2;
static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2;
mg_surface mg_metal_surface_create_for_window(mp_window window)
mg_surface mg_mtl_surface_create_for_window(mp_window window)
{
mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(!windowData)
@ -194,18 +194,18 @@ mg_surface mg_metal_surface_create_for_window(mp_window window)
}
else
{
mg_metal_surface* surface = (mg_metal_surface*)malloc(sizeof(mg_metal_surface));
mg_mtl_surface* surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface));
//NOTE(martin): setup interface functions
surface->interface.backend = MG_BACKEND_METAL;
surface->interface.destroy = mg_metal_surface_destroy;
surface->interface.prepare = mg_metal_surface_prepare;
surface->interface.present = mg_metal_surface_present;
surface->interface.swapInterval = mg_metal_surface_swap_interval;
surface->interface.getFrame = mg_metal_surface_get_frame;
surface->interface.setFrame = mg_metal_surface_set_frame;
surface->interface.getHidden = mg_metal_surface_get_hidden;
surface->interface.setHidden = mg_metal_surface_set_hidden;
surface->interface.backend = MG_BACKEND_MTL;
surface->interface.destroy = mg_mtl_surface_destroy;
surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.getFrame = mg_mtl_surface_get_frame;
surface->interface.setFrame = mg_mtl_surface_set_frame;
surface->interface.getHidden = mg_mtl_surface_get_hidden;
surface->interface.setHidden = mg_mtl_surface_set_hidden;
@autoreleasepool
{
@ -215,37 +215,37 @@ mg_surface mg_metal_surface_create_for_window(mp_window window)
[[windowData->osx.nsWindow contentView] addSubview: surface->view];
surface->drawableSemaphore = dispatch_semaphore_create(MP_METAL_MAX_DRAWABLES_IN_FLIGHT);
surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT);
//-----------------------------------------------------------
//NOTE(martin): create a metal device and a metal layer and
//NOTE(martin): create a mtl device and a mtl layer and
//-----------------------------------------------------------
surface->device = MTLCreateSystemDefaultDevice();
[surface->device retain];
surface->metalLayer = [CAMetalLayer layer];
[surface->metalLayer retain];
[surface->metalLayer setOpaque:NO];
surface->mtlLayer = [CAMtlLayer layer];
[surface->mtlLayer retain];
[surface->mtlLayer setOpaque:NO];
surface->metalLayer.device = surface->device;
surface->mtlLayer.device = surface->device;
//-----------------------------------------------------------
//NOTE(martin): set the size and scaling
//-----------------------------------------------------------
CGSize size = surface->view.bounds.size;
size.width *= MG_METAL_SURFACE_CONTENTS_SCALING;
size.height *= MG_METAL_SURFACE_CONTENTS_SCALING;
surface->metalLayer.drawableSize = size;
surface->metalLayer.contentsScale = MG_METAL_SURFACE_CONTENTS_SCALING;
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size;
surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING;
surface->metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
surface->view.wantsLayer = YES;
surface->view.layer = surface->metalLayer;
surface->view.layer = surface->mtlLayer;
//NOTE(martin): handling resizing
surface->view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
surface->metalLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->metalLayer.needsDisplayOnBoundsChange = YES;
surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->mtlLayer.needsDisplayOnBoundsChange = YES;
//-----------------------------------------------------------
//NOTE(martin): create a command queue
@ -263,13 +263,13 @@ mg_surface mg_metal_surface_create_for_window(mp_window window)
}
}
void* mg_metal_surface_layer(mg_surface surface)
void* mg_mtl_surface_layer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
if(surfaceData && surfaceData->backend == MG_BACKEND_MTL)
{
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
return(metalSurface->metalLayer);
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->mtlLayer);
}
else
{
@ -277,13 +277,13 @@ void* mg_metal_surface_layer(mg_surface surface)
}
}
void* mg_metal_surface_drawable(mg_surface surface)
void* mg_mtl_surface_drawable(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
if(surfaceData && surfaceData->backend == MG_BACKEND_MTL)
{
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
return(metalSurface->drawable);
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->drawable);
}
else
{
@ -291,13 +291,13 @@ void* mg_metal_surface_drawable(mg_surface surface)
}
}
void* mg_metal_surface_command_buffer(mg_surface surface)
void* mg_mtl_surface_command_buffer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
if(surfaceData && surfaceData->backend == MG_BACKEND_MTL)
{
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
return(metalSurface->commandBuffer);
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->commandBuffer);
}
else
{

View File

@ -1,32 +0,0 @@
/************************************************************//**
*
* @file: osx_gles_surface.cpp
* @author: Martin Fouilleul
* @date: 18/08/2022
* @revision:
*
*****************************************************************/
//#include<Cocoa/Cocoa.h>
//#include <Foundation/Foundation.h>
#include <QuartzCore/QuartzCore.h>
#include<GLES3/gl3.h>
#define EGL_EGLEXT_PROTOTYPES
#include<EGL/egl.h>
#include<EGL/eglext.h>
#include"graphics_internal.h"
typedef struct mg_gles_surface
{
mg_surface_data interface;
NSView* view;
CALayer* layer;
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
EGLSurface eglSurface;
EGLint numConfigs;
} mg_gles_surface;

View File

@ -1,184 +0,0 @@
/************************************************************//**
*
* @file: osx_gles_surface.cpp
* @author: Martin Fouilleul
* @date: 18/08/2022
* @revision:
*
*****************************************************************/
//#include<Cocoa/Cocoa.h>
//#include <Foundation/Foundation.h>
#include <QuartzCore/QuartzCore.h>
#include<GLES3/gl3.h>
#define EGL_EGLEXT_PROTOTYPES
#include<EGL/egl.h>
#include<EGL/eglext.h>
#include"graphics_internal.h"
#include"osx_gles_surface.h"
void mg_gles_surface_destroy(mg_surface_data* interface)
{
//////////////////////////////////////////////////
//TODO
//////////////////////////////////////////////////
}
void mg_gles_surface_prepare(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
}
void mg_gles_surface_present(mg_surface_data* interface)
{
//TODO: eglSwapBuffers seem to never block in macOS (ie eglSwapInterval doesn't seem to have any effect)
// We need to use a CVDisplayLink to time this if we want surface present to block
mg_gles_surface* surface = (mg_gles_surface*)interface;
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
}
void mg_gles_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
f32 scale = surface->layer.contentsScale;
CGRect bounds = (CGRect){{frame.x * scale, frame.y * scale}, {.width = frame.w*scale, .height = frame.h*scale}};
[surface->layer setBounds: bounds];
}
mp_rect mg_gles_surface_get_frame(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
f32 scale = surface->layer.contentsScale;
CGRect bounds = [surface->layer bounds];
mp_rect rect = {bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale};
return(rect);
}
void mg_gles_surface_set_hidden(mg_surface_data* interface, bool hidden)
{
//TODO: doesn't make sense for an offscreen surface?
}
bool mg_gles_surface_get_hidden(mg_surface_data* interface)
{
//TODO: doesn't make sense for an offscreen surface?
return(false);
}
vec2 mg_gles_surface_get_size(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
CGRect bounds = [surface->layer bounds];
f32 scale = surface->layer.contentsScale;
vec2 res = {bounds.size.width/scale, bounds.size.height/scale};
return(res);
}
mg_surface mg_gles_surface_create_with_view(u32 width, u32 height, NSView* view)
{
mg_gles_surface* surface = malloc_type(mg_gles_surface);
memset(surface, 0, sizeof(mg_gles_surface));
surface->interface.backend = MG_BACKEND_GLES;
surface->interface.destroy = mg_gles_surface_destroy;
surface->interface.prepare = mg_gles_surface_prepare;
surface->interface.present = mg_gles_surface_present;
surface->interface.getFrame = mg_gles_surface_get_frame;
surface->interface.setFrame = mg_gles_surface_set_frame;
surface->interface.getHidden = mg_gles_surface_get_hidden;
surface->interface.setHidden = mg_gles_surface_set_hidden;
surface->view = view;
@autoreleasepool
{
surface->layer = [[CALayer alloc] init];
[surface->layer retain];
[surface->layer setBounds:CGRectMake(0, 0, width, height)];
if(surface->view)
{
[surface->view setWantsLayer: YES];
surface->view.layer = surface->layer;
}
}
EGLAttrib displayAttribs[] = {
//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
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 };
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &surface->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, //NOTE: Angle can't create a GLES 3.1 context on macOS
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);
eglSwapInterval(surface->eglDisplay, 1);
mg_surface handle = mg_surface_alloc_handle((mg_surface_data*)surface);
return(handle);
}
mg_surface mg_gles_surface_create_offscreen(u32 width, u32 height)
{
return(mg_gles_surface_create_with_view(width, height, 0));
}
mg_surface mg_gles_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)
{
@autoreleasepool
{
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
NSView* view = [[NSView alloc] initWithFrame: frame];
res = mg_gles_surface_create_with_view(frame.size.width, frame.size.height, view);
if(!mg_surface_is_nil(res))
{
[[windowData->osx.nsWindow contentView] addSubview: view];
}
}
}
return(res);
}

View File

@ -1,6 +1,6 @@
/************************************************************//**
*
* @file: win32_gl_loader.h
* @file: wgl_loader.h
* @author: Martin Fouilleul
* @date: 01/08/2022
* @revision:
@ -56,7 +56,7 @@
GL_PROC(GLUNMAPBUFFER, glUnmapBuffer)
#ifdef WIN32_GL_LOADER_API
#ifdef WGL_LOADER_API
//NOTE: pointer declarations
#define GL_PROC(type, name) extern _cat3_(PFN, type, PROC) name;
GL_PROC_LIST
@ -64,7 +64,7 @@
#endif
#ifdef WIN32_GL_LOADER_IMPL
#ifdef WGL_LOADER_IMPL
#define GL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0;
GL_PROC_LIST
#undef GL_PROC

View File

@ -1,18 +1,18 @@
/************************************************************//**
*
* @file: win32_gl_surface.c
* @file: wgl_surface.c
* @author: Martin Fouilleul
* @date: 01/08/2022
* @revision:
*
*****************************************************************/
#define WIN32_GL_LOADER_IMPL
#include"win32_gl_loader.h"
#define WGL_LOADER_IMPL
#include"wgl_loader.h"
#include"win32_app.h"
#include"graphics_internal.h"
typedef struct mg_gl_surface
typedef struct mg_wgl_surface
{
mg_surface_data interface;
@ -21,11 +21,11 @@ typedef struct mg_gl_surface
HGLRC glContext;
vec2 contentsScaling;
} mg_gl_surface;
} mg_wgl_surface;
void mg_gl_surface_destroy(mg_surface_data* interface)
void mg_wgl_surface_destroy(mg_surface_data* interface)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
if(surface->glContext == wglGetCurrentContext())
{
@ -35,34 +35,34 @@ void mg_gl_surface_destroy(mg_surface_data* interface)
free(surface);
}
void mg_gl_surface_prepare(mg_surface_data* interface)
void mg_wgl_surface_prepare(mg_surface_data* interface)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
wglMakeCurrent(surface->hDC, surface->glContext);
}
void mg_gl_surface_present(mg_surface_data* interface)
void mg_wgl_surface_present(mg_surface_data* interface)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
SwapBuffers(surface->hDC);
}
void mg_gl_surface_swap_interval(mg_surface_data* interface, int swap)
void mg_wgl_surface_swap_interval(mg_surface_data* interface, int swap)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
wglSwapIntervalEXT(swap);
}
vec2 mg_gl_contents_scaling(mg_surface_data* interface)
vec2 mg_wgl_contents_scaling(mg_surface_data* interface)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
return(surface->contentsScaling);
}
mp_rect mg_gl_surface_get_frame(mg_surface_data* interface)
mp_rect mg_wgl_surface_get_frame(mg_surface_data* interface)
{
mg_gl_surface* surface = (mg_gl_surface*)interface;
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
RECT rect = {0};
GetClientRect(surface->hWnd, &rect);
@ -75,7 +75,7 @@ mp_rect mg_gl_surface_get_frame(mg_surface_data* interface)
return(res);
}
mg_surface mg_gl_surface_create_for_window(mp_window window)
mg_surface mg_wgl_surface_create_for_window(mp_window window)
{
mg_surface surfaceHandle = mg_surface_nil();
@ -211,14 +211,14 @@ mg_surface mg_gl_surface_create_for_window(mp_window window)
wglSwapIntervalEXT(1);
//TODO save important info in surface_data and return a handle
mg_gl_surface* surface = malloc_type(mg_gl_surface);
mg_wgl_surface* surface = malloc_type(mg_wgl_surface);
surface->interface.backend = MG_BACKEND_GL;
surface->interface.destroy = mg_gl_surface_destroy;
surface->interface.prepare = mg_gl_surface_prepare;
surface->interface.present = mg_gl_surface_present;
surface->interface.swapInterval = mg_gl_surface_swap_interval;
surface->interface.contentsScaling = mg_gl_contents_scaling;
surface->interface.getFrame = mg_gl_surface_get_frame;
surface->interface.destroy = mg_wgl_surface_destroy;
surface->interface.prepare = mg_wgl_surface_prepare;
surface->interface.present = mg_wgl_surface_present;
surface->interface.swapInterval = mg_wgl_surface_swap_interval;
surface->interface.contentsScaling = mg_wgl_contents_scaling;
surface->interface.getFrame = mg_wgl_surface_get_frame;
//TODO: get/set frame/hidden
surface->hWnd = windowData->win32.hWnd;

View File

@ -1,16 +1,16 @@
/************************************************************//**
*
* @file: win32_gl_surface.c
* @file: wgl_surface.c
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __WIN32_GL_SURFACE_H_
#define __WIN32_GL_SURFACE_H_
#ifndef __WGL_SURFACE_H_
#define __WGL_SURFACE_H_
#include"graphics.h"
mg_surface mg_gl_surface_create_for_window(mp_window window);
mg_surface mg_wgl_surface_create_for_window(mp_window window);
#endif // __WIN32_GL_SURFACE_H_

View File

@ -1,133 +0,0 @@
/************************************************************//**
*
* @file: osx_gles_surface.cpp
* @author: Martin Fouilleul
* @date: 18/08/2022
* @revision:
*
*****************************************************************/
#include<GLES3/gl31.h>
#define EGL_EGLEXT_PROTOTYPES
#include<EGL/egl.h>
#include<EGL/eglext.h>
#include"graphics_internal.h"
typedef struct mg_gles_surface
{
mg_surface_data interface;
HWND hWnd;
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
EGLSurface eglSurface;
} mg_gles_surface;
void mg_gles_surface_destroy(mg_surface_data* interface)
{
//////////////////////////////////////////////////
//TODO
//////////////////////////////////////////////////
}
void mg_gles_surface_prepare(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
}
void mg_gles_surface_present(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
}
/*
void mg_gles_surface_set_frame(mg_surface_data* interface, mp_rect frame);
void mg_gles_surface_set_hidden(mg_surface_data* interface, bool hidden);
bool mg_gles_surface_get_hidden(mg_surface_data* interface);
*/
mp_rect mg_gles_surface_get_frame(mg_surface_data* interface)
{
mg_gles_surface* surface = (mg_gles_surface*)interface;
RECT rect = {0};
GetClientRect(surface->hWnd, &rect);
mp_rect res = {rect.left, rect.bottom, rect.right - rect.left, rect.bottom - rect.top};
return(res);
}
mg_surface mg_gles_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_gles_surface* surface = malloc_type(mg_gles_surface);
memset(surface, 0, sizeof(mg_gles_surface));
surface->interface.backend = MG_BACKEND_GLES;
surface->interface.destroy = mg_gles_surface_destroy;
surface->interface.prepare = mg_gles_surface_prepare;
surface->interface.present = mg_gles_surface_present;
surface->interface.getFrame = mg_gles_surface_get_frame;
/*TODO
surface->interface.setFrame = mg_gles_surface_set_frame;
surface->interface.getHidden = mg_gles_surface_get_hidden;
surface->interface.setHidden = mg_gles_surface_set_hidden;
*/
surface->hWnd = windowData->win32.hWnd;
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};
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->hWnd, surfaceAttributes);
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
EGL_CONTEXT_MINOR_VERSION_KHR, 1,
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);
//TODO: reactivate this when finished testing!
// eglSwapInterval(surface->eglDisplay, 1);
eglSwapInterval(surface->eglDisplay, 0);
res = mg_surface_alloc_handle((mg_surface_data*)surface);
}
return(res);
}

View File

@ -1,17 +0,0 @@
/************************************************************//**
*
* @file: win32_gles_surface.h
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __WIN32_GLES_SURFACE_H_
#define __WIN32_GLES_SURFACE_H_
#include"graphics.h"
#include"mp_app.h"
mg_surface mg_gles_surface_create_for_window(mp_window window);
#endif // __WIN32_GLES_SURFACE_H_

View File

@ -5,6 +5,13 @@ Overview
[.] 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
[x] surface/canvas functions that take a backend id
[x] feature-detection functions to know what surface/canvas backends are available at run-time
[>] drop the "mg_" prefix for internal functions (and declare them static)
[>] write doc about these options
[ ] Image API and backend
[ ] Build image atlas on top
@ -17,6 +24,11 @@ Overview
[ ] Delegated drawing API+Impl
[ ] Make building apps simpler
[ ] single include path
[ ] script for embedding dependencies / create app bundle
Clean+Fixes
-----------

View File

@ -94,3 +94,20 @@ Quick measurement on perf_text.exe
-> May be worth it to try persistently mapped buffers later.
* Splitting vertex data and shape data (using glBufferData) --> ~10ms
Backend Selection
-----------------
* We need define macros to select which backends are compiled into milepost.lib
-> define default backends and allow override with user compile defines
* We also need define macros to select which backend-specific functions and/or graphics APIs to include when building an app with milepost (e.g.\ include opengl headers or not, etc.).
* For now, we intend to statically link milepost.lib (or dynamically load to an embedded dll), so at application compile time the supported backends are known and calling a backend-specific function for a backend that has not been compiled in milepost results in a link error. (No need to defines for that)
* However, if we want to provide a nice abstraction for creation function, this means it is possible for user to pass a backend that does not exists in the lib (resulting in a runtime error). It would be nice to have some way to runtime check which backends are available. That can be a function compiled in the lib.
* We also might want to access backend-specific functions in the app, so we need to include those conditionally.
* We also might want to include graphics API, eg OpenGL, in a uniform way. -> See later how we manage GLES/GL co-existence