[canvas] change surface/canvas APIs to treat canvas a 'just another kind of surface', and split canvas implementation (managed by surface) from canvas _command buffer_ and implicit context (represented by mg_canvas)

This commit is contained in:
Martin Fouilleul 2023-04-25 19:13:15 +02:00
parent 32d7d91893
commit 346979a21a
14 changed files with 2277 additions and 2114 deletions

View File

@ -52,8 +52,6 @@ mg_font create_font()
int main() int main()
{ {
LogLevel(LOG_LEVEL_WARNING);
mp_init(); mp_init();
mp_clock_init(); //TODO put that in mp_init()? mp_clock_init(); //TODO put that in mp_init()?
@ -63,11 +61,10 @@ int main()
mp_rect contentRect = mp_window_get_content_rect(window); mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface //NOTE: create surface
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0); mg_surface_swap_interval(surface, 0);
//TODO: create canvas mg_canvas canvas = mg_canvas_create();
mg_canvas canvas = mg_canvas_create(surface);
if(mg_canvas_is_nil(canvas)) if(mg_canvas_is_nil(canvas))
{ {
@ -91,10 +88,10 @@ int main()
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event* event = 0;
while(mp_next_event(&event)) while((event = mp_next_event(mem_scratch())) != 0)
{ {
switch(event.type) switch(event->type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
@ -103,23 +100,23 @@ int main()
case MP_EVENT_KEYBOARD_KEY: case MP_EVENT_KEYBOARD_KEY:
{ {
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT) if(event->key.action == MP_KEY_PRESS || event->key.action == MP_KEY_REPEAT)
{ {
f32 factor = (event.key.mods & MP_KEYMOD_SHIFT) ? 10 : 1; f32 factor = (event->key.mods & MP_KEYMOD_SHIFT) ? 10 : 1;
if(event.key.code == MP_KEY_LEFT) if(event->key.code == MP_KEY_LEFT)
{ {
x-=0.3*factor; x-=0.3*factor;
} }
else if(event.key.code == MP_KEY_RIGHT) else if(event->key.code == MP_KEY_RIGHT)
{ {
x+=0.3*factor; x+=0.3*factor;
} }
else if(event.key.code == MP_KEY_UP) else if(event->key.code == MP_KEY_UP)
{ {
y-=0.3*factor; y-=0.3*factor;
} }
else if(event.key.code == MP_KEY_DOWN) else if(event->key.code == MP_KEY_DOWN)
{ {
y+=0.3*factor; y+=0.3*factor;
} }
@ -154,55 +151,47 @@ int main()
x += dx; x += dx;
y += dy; y += dy;
// background
mg_set_color_rgba(0, 1, 1, 1);
mg_clear();
// head
mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 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, 600-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_surface_prepare(surface); mg_surface_prepare(surface);
mg_flush(surface);
// background
mg_set_color_rgba(0, 1, 1, 1);
mg_clear();
mg_set_color_rgba(1, 0, 0, 1);
mg_set_width(2);
mg_rectangle_stroke(304, 100, 300, 250);
mg_clip_push(304, 100, 300, 250);
// head
mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 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);
mg_clip_pop();
// text
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font_size(12);
mg_move_to(50, 600-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); mg_surface_present(surface);
mem_arena_clear(mem_scratch()); mem_arena_clear(mem_scratch());

View File

@ -94,7 +94,6 @@ mg_font create_font(const char* path)
int main() int main()
{ {
LogLevel(LOG_LEVEL_MESSAGE);
mp_init(); mp_init();
mp_clock_init(); mp_clock_init();
@ -105,10 +104,10 @@ int main()
//NOTE: create surface, canvas and font //NOTE: create surface, canvas and font
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0); mg_surface_swap_interval(surface, 0);
mg_canvas canvas = mg_canvas_create(surface); mg_canvas canvas = mg_canvas_create();
const int fontCount = 3; const int fontCount = 3;
int fontIndex = 0; int fontIndex = 0;
@ -153,15 +152,19 @@ int main()
f32 startX = 10; f32 startX = 10;
f32 startY = 10 + lineHeights[fontIndex]; f32 startY = 10 + lineHeights[fontIndex];
mp_input_state inputState = {0};
while(!mp_should_quit()) while(!mp_should_quit())
{ {
f64 startFrameTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startFrameTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event* event = 0;
while(mp_next_event(&event)) while((event = mp_next_event(mem_scratch())) != 0)
{ {
switch(event.type) mp_input_process_event(&inputState, event);
switch(event->type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
@ -170,12 +173,12 @@ int main()
case MP_EVENT_MOUSE_BUTTON: case MP_EVENT_MOUSE_BUTTON:
{ {
if(event.key.code == MP_MOUSE_LEFT) if(event->key.code == MP_MOUSE_LEFT)
{ {
if(event.key.action == MP_KEY_PRESS) if(event->key.action == MP_KEY_PRESS)
{ {
tracked = true; tracked = true;
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
trackPoint.x = mousePos.x/zoom - startX; trackPoint.x = mousePos.x/zoom - startX;
trackPoint.y = mousePos.y/zoom - startY; trackPoint.y = mousePos.y/zoom - startY;
} }
@ -188,11 +191,11 @@ int main()
case MP_EVENT_MOUSE_WHEEL: case MP_EVENT_MOUSE_WHEEL:
{ {
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
f32 trackX = mousePos.x/zoom - startX; f32 trackX = mousePos.x/zoom - startX;
f32 trackY = mousePos.y/zoom - startY; f32 trackY = mousePos.y/zoom - startY;
zoom *= 1 + event.move.deltaY * 0.01; zoom *= 1 + event->move.deltaY * 0.01;
zoom = Clamp(zoom, 0.2, 10); zoom = Clamp(zoom, 0.2, 10);
startX = mousePos.x/zoom - trackX; startX = mousePos.x/zoom - trackX;
@ -201,7 +204,7 @@ int main()
case MP_EVENT_KEYBOARD_KEY: case MP_EVENT_KEYBOARD_KEY:
{ {
if(event.key.code == MP_KEY_SPACE && event.key.action == MP_KEY_PRESS) if(event->key.code == MP_KEY_SPACE && event->key.action == MP_KEY_PRESS)
{ {
fontIndex = (fontIndex+1)%fontCount; fontIndex = (fontIndex+1)%fontCount;
} }
@ -214,7 +217,7 @@ int main()
if(tracked) if(tracked)
{ {
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
startX = mousePos.x/zoom - trackPoint.x; startX = mousePos.x/zoom - trackPoint.x;
startY = mousePos.y/zoom - trackPoint.y; startY = mousePos.y/zoom - trackPoint.y;
} }
@ -289,8 +292,7 @@ int main()
f64 startFlushTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startFlushTime = mp_get_time(MP_CLOCK_MONOTONIC);
mg_surface_prepare(surface); mg_surface_prepare(surface);
mg_flush(surface);
mg_flush();
f64 startPresentTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startPresentTime = mp_get_time(MP_CLOCK_MONOTONIC);
mg_surface_present(surface); mg_surface_present(surface);
@ -306,6 +308,7 @@ int main()
(startPresentTime - startFlushTime)*1000, (startPresentTime - startFlushTime)*1000,
(endFrameTime - startPresentTime)*1000); (endFrameTime - startPresentTime)*1000);
mp_input_next_frame(&inputState);
mem_arena_clear(mem_scratch()); mem_arena_clear(mem_scratch());
} }

View File

@ -15,8 +15,6 @@
#include"milepost.h" #include"milepost.h"
#define LOG_SUBSYSTEM "Main"
#include"tiger.c" #include"tiger.c"
mg_font create_font() mg_font create_font()
@ -53,8 +51,6 @@ mg_font create_font()
int main() int main()
{ {
LogLevel(LOG_LEVEL_WARNING);
mp_init(); mp_init();
mp_clock_init(); //TODO put that in mp_init()? mp_clock_init(); //TODO put that in mp_init()?
@ -64,11 +60,11 @@ int main()
mp_rect contentRect = mp_window_get_content_rect(window); mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface //NOTE: create surface
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0); mg_surface_swap_interval(surface, 0);
//TODO: create canvas //TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface); mg_canvas canvas = mg_canvas_create();
if(mg_canvas_is_nil(canvas)) if(mg_canvas_is_nil(canvas))
{ {
@ -92,15 +88,19 @@ int main()
f64 frameTime = 0; f64 frameTime = 0;
mp_input_state inputState = {0};
while(!mp_should_quit()) while(!mp_should_quit())
{ {
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event* event = 0;
while(mp_next_event(&event)) while((event = mp_next_event(mem_scratch())) != 0)
{ {
switch(event.type) mp_input_process_event(&inputState, event);
switch(event->type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
@ -109,18 +109,18 @@ int main()
case MP_EVENT_WINDOW_RESIZE: case MP_EVENT_WINDOW_RESIZE:
{ {
mp_rect frame = {0, 0, event.frame.rect.w, event.frame.rect.h}; mp_rect frame = {0, 0, event->frame.rect.w, event->frame.rect.h};
mg_surface_set_frame(surface, frame); mg_surface_set_frame(surface, frame);
} break; } break;
case MP_EVENT_MOUSE_BUTTON: case MP_EVENT_MOUSE_BUTTON:
{ {
if(event.key.code == MP_MOUSE_LEFT) if(event->key.code == MP_MOUSE_LEFT)
{ {
if(event.key.action == MP_KEY_PRESS) if(event->key.action == MP_KEY_PRESS)
{ {
tracked = true; tracked = true;
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
trackPoint.x = (mousePos.x - startX)/zoom; trackPoint.x = (mousePos.x - startX)/zoom;
trackPoint.y = (mousePos.y - startY)/zoom; trackPoint.y = (mousePos.y - startY)/zoom;
} }
@ -133,11 +133,11 @@ int main()
case MP_EVENT_MOUSE_WHEEL: case MP_EVENT_MOUSE_WHEEL:
{ {
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
f32 pinX = (mousePos.x - startX)/zoom; f32 pinX = (mousePos.x - startX)/zoom;
f32 pinY = (mousePos.y - startY)/zoom; f32 pinY = (mousePos.y - startY)/zoom;
zoom *= 1 + event.move.deltaY * 0.01; zoom *= 1 + event->move.deltaY * 0.01;
zoom = Clamp(zoom, 0.5, 5); zoom = Clamp(zoom, 0.5, 5);
startX = mousePos.x - pinX*zoom; startX = mousePos.x - pinX*zoom;
@ -146,9 +146,9 @@ int main()
case MP_EVENT_KEYBOARD_KEY: case MP_EVENT_KEYBOARD_KEY:
{ {
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT) if(event->key.action == MP_KEY_PRESS || event->key.action == MP_KEY_REPEAT)
{ {
switch(event.key.code) switch(event->key.code)
{ {
case MP_KEY_SPACE: case MP_KEY_SPACE:
singlePath = !singlePath; singlePath = !singlePath;
@ -156,7 +156,7 @@ int main()
case MP_KEY_UP: case MP_KEY_UP:
{ {
if(event.key.mods & MP_KEYMOD_SHIFT) if(event->key.mods & MP_KEYMOD_SHIFT)
{ {
singlePathIndex++; singlePathIndex++;
} }
@ -168,7 +168,7 @@ int main()
case MP_KEY_DOWN: case MP_KEY_DOWN:
{ {
if(event.key.mods & MP_KEYMOD_SHIFT) if(event->key.mods & MP_KEYMOD_SHIFT)
{ {
singlePathIndex--; singlePathIndex--;
} }
@ -188,7 +188,7 @@ int main()
if(tracked) if(tracked)
{ {
vec2 mousePos = mp_mouse_position(); vec2 mousePos = mp_mouse_position(&inputState);
startX = mousePos.x - trackPoint.x*zoom; startX = mousePos.x - trackPoint.x*zoom;
startY = mousePos.y - trackPoint.y*zoom; startY = mousePos.y - trackPoint.y*zoom;
} }
@ -228,9 +228,10 @@ int main()
frameTime, frameTime,
1./frameTime); 1./frameTime);
mg_flush(); mg_flush(surface);
mg_surface_present(surface); mg_surface_present(surface);
mp_input_next_frame(&inputState);
mem_arena_clear(mem_scratch()); mem_arena_clear(mem_scratch());
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime; frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
} }

File diff suppressed because it is too large Load Diff

View File

@ -27,43 +27,51 @@ typedef enum {
//NOTE: these macros are used to select which backend to include when building milepost //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 // they can be overridden by passing them to the compiler command line
#if defined(PLATFORM_MACOS) #if PLATFORM_MACOS
#ifndef MG_COMPILE_BACKEND_METAL #ifndef MG_COMPILE_METAL
#define MG_COMPILE_BACKEND_METAL 1 #define MG_COMPILE_METAL 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_GLES #ifndef MG_COMPILE_GLES
#define MG_COMPILE_BACKEND_GLES 1 #define MG_COMPILE_GLES 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_CANVAS #ifndef MG_COMPILE_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1 #if !MG_COMPILE_METAL
#error "Canvas surface requires a Metal backend on macOS. Make sure you define MG_COMPILE_METAL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#endif #endif
#define MG_COMPILE_BACKEND_GL 0 #define MG_COMPILE_GL 0
#elif defined(PLATFORM_WIN64) #elif PLATFORM_WINDOWS
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_GL 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_GLES #ifndef MG_COMPILE_GLES
#define MG_COMPILE_BACKEND_GLES 1 #define MG_COMPILE_GLES 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_CANVAS #ifndef MG_COMPILE_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1 #if !MG_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Windows. Make sure you define MG_COMPILE_GL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#endif #endif
#elif defined(PLATFORM_LINUX) #elif PLATFORM_LINUX
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_GL 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_CANVAS #ifndef MG_COMPILE_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1 #if !MG_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Linux. Make sure you define MG_COMPILE_GL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#endif #endif
#endif #endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost //NOTE: these macros are used to select backend-specific APIs to include when using milepost
@ -170,14 +178,11 @@ typedef struct mg_text_extents
MP_API mg_canvas mg_canvas_nil(void); MP_API mg_canvas mg_canvas_nil(void);
MP_API bool mg_canvas_is_nil(mg_canvas canvas); MP_API bool mg_canvas_is_nil(mg_canvas canvas);
MP_API mg_canvas mg_canvas_create(mg_surface surface); MP_API mg_canvas mg_canvas_create();
MP_API void mg_canvas_destroy(mg_canvas canvas); MP_API void mg_canvas_destroy(mg_canvas canvas);
mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_flush(mg_surface surface); //TODO change to mg_canvas_render(mg_surface surface, mg_canvas canvas);
MP_API mg_canvas mg_canvas_prepare(mg_canvas canvas);
MP_API void mg_flush(void);
MP_API void mg_present(void);
MP_API vec2 mg_canvas_size(void);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): fonts //NOTE(martin): fonts
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
@ -212,10 +217,10 @@ MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text);
MP_API mg_image mg_image_nil(); MP_API mg_image mg_image_nil();
MP_API bool mg_image_is_nil(mg_image a); MP_API bool mg_image_is_nil(mg_image a);
MP_API mg_image mg_image_create(u32 width, u32 height); MP_API mg_image mg_image_create(mg_surface surface, u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels); MP_API mg_image mg_image_create_from_rgba8(mg_surface surface, u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(str8 data, bool flip); MP_API mg_image mg_image_create_from_data(mg_surface surface, str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(str8 path, bool flip); MP_API mg_image mg_image_create_from_file(mg_surface surface, str8 path, bool flip);
MP_API void mg_image_destroy(mg_image image); MP_API void mg_image_destroy(mg_image image);

View File

@ -20,6 +20,7 @@ extern "C" {
// surface interface // surface interface
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data; typedef struct mg_surface_data mg_surface_data;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface); typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);
typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface); typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface);
@ -51,6 +52,9 @@ typedef struct mg_surface_data
mg_surface_native_layer_proc nativeLayer; mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID; mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect; mg_surface_host_connect_proc hostConnect;
mg_canvas_backend* backend;
} mg_surface_data; } mg_surface_data;
mg_surface mg_surface_alloc_handle(mg_surface_data* surface); mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
@ -69,6 +73,7 @@ typedef struct mg_image_data
{ {
list_elt listElt; list_elt listElt;
u32 generation; u32 generation;
mg_surface surface;
vec2 size; vec2 size;
} mg_image_data; } mg_image_data;
@ -104,7 +109,6 @@ typedef struct mg_vertex_layout
} mg_vertex_layout; } mg_vertex_layout;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend, mg_color clearColor);

View File

@ -14,11 +14,11 @@
#include"platform/std_log.c" #include"platform/std_log.c"
#if defined(PLATFORM_WIN64) #if PLATFORM_WINDOWS
#include"platform/win32_memory.c" #include"platform/win32_memory.c"
#include"platform/win32_clock.c" #include"platform/win32_clock.c"
//TODO //TODO
#elif defined(PLATFORM_MACOS) #elif PLATFORM_MACOS
#include"platform/unix_memory.c" #include"platform/unix_memory.c"
#include"platform/osx_clock.c" #include"platform/osx_clock.c"
/* /*
@ -27,7 +27,7 @@
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
#elif defined(PLATFORM_LINUX) #elif PLATFORM_LINUX
#include"platform/unix_base_memory.c" #include"platform/unix_base_memory.c"
#include"platform/linux_clock.c" #include"platform/linux_clock.c"
/* /*
@ -52,24 +52,27 @@
// app/graphics layer // app/graphics layer
//--------------------------------------------------------------- //---------------------------------------------------------------
#if defined(PLATFORM_WIN64) #if PLATFORM_WINDOWS
#include"win32_app.c" #include"win32_app.c"
#include"graphics.c" #include"graphics.c"
#if MG_COMPILE_BACKEND_GL || MG_COMPILE_BACKEND_GLES #if MG_COMPILE_GL || MG_COMPILE_GLES
#include"gl_loader.c" #include"gl_loader.c"
#endif #endif
#if MG_COMPILE_BACKEND_GL #if MG_COMPILE_GL
#include"wgl_surface.c" #include"wgl_surface.c"
#endif
#if MG_COMPILE_CANVAS
#include"gl_canvas.c" #include"gl_canvas.c"
#endif #endif
#if MG_COMPILE_BACKEND_GLES #if MG_COMPILE_GLES
#include"egl_surface.c" #include"egl_surface.c"
#endif #endif
#elif defined(PLATFORM_MACOS) #elif PLATFORM_MACOS
//NOTE: macos application layer and graphics backends are defined in milepost.m //NOTE: macos application layer and graphics backends are defined in milepost.m
#else #else
#error "Unsupported platform" #error "Unsupported platform"

View File

@ -10,21 +10,15 @@
#include"osx_app.m" #include"osx_app.m"
#include"graphics.c" #include"graphics.c"
#if MG_COMPILE_BACKEND_METAL #if MG_COMPILE_METAL
#include"mtl_surface.m" #include"mtl_surface.m"
// #include"mtl_canvas.m" #endif
#if MG_COMPILE_CANVAS
#include"mtl_renderer.m" #include"mtl_renderer.m"
#endif #endif
#if MG_COMPILE_BACKEND_GLES #if MG_COMPILE_GLES
#include"gl_loader.c" #include"gl_loader.c"
#include"egl_surface.c" #include"egl_surface.c"
#endif #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

@ -14,9 +14,9 @@
#include"platform.h" #include"platform.h"
#include"ringbuffer.h" #include"ringbuffer.h"
#if defined(PLATFORM_WIN64) || defined(PLATFORM_WIN32) #if PLATFORM_WINDOWS
#include"win32_app.h" #include"win32_app.h"
#elif defined(PLATFORM_MACOS) #elif PLATFORM_MACOS
#include"osx_app.h" #include"osx_app.h"
#else #else
#error "platform not supported yet" #error "platform not supported yet"

View File

@ -23,7 +23,7 @@ const int MG_MTL_INPUT_BUFFERS_COUNT = 3,
typedef struct mg_mtl_canvas_backend typedef struct mg_mtl_canvas_backend
{ {
mg_canvas_backend interface; mg_canvas_backend interface;
mg_surface surface; mg_mtl_surface* surface;
id<MTLComputePipelineState> pathPipeline; id<MTLComputePipelineState> pathPipeline;
id<MTLComputePipelineState> segmentPipeline; id<MTLComputePipelineState> segmentPipeline;
@ -64,15 +64,6 @@ typedef struct mg_mtl_image_data
id<MTLTexture> texture; id<MTLTexture> texture;
} mg_mtl_image_data; } mg_mtl_image_data;
static void mg_update_path_extents(vec4* extents, vec2 p)
{
extents->x = minimum(extents->x, p.x);
extents->y = minimum(extents->y, p.y);
extents->z = maximum(extents->z, p.x);
extents->w = maximum(extents->w, p.y);
}
void mg_mtl_print_log(int bufferIndex, id<MTLBuffer> logBuffer, id<MTLBuffer> logOffsetBuffer) void mg_mtl_print_log(int bufferIndex, id<MTLBuffer> logBuffer, id<MTLBuffer> logOffsetBuffer)
{ {
char* log = [logBuffer contents]; char* log = [logBuffer contents];
@ -106,6 +97,14 @@ typedef struct mg_mtl_encoding_context
} mg_mtl_encoding_context; } mg_mtl_encoding_context;
static void mg_update_path_extents(vec4* extents, vec2 p)
{
extents->x = minimum(extents->x, p.x);
extents->y = minimum(extents->y, p.y);
extents->z = maximum(extents->z, p.x);
extents->w = maximum(extents->w, p.y);
}
void mg_mtl_canvas_encode_element(mg_mtl_encoding_context* context, mg_path_elt_type kind, vec2* p) void mg_mtl_canvas_encode_element(mg_mtl_encoding_context* context, mg_path_elt_type kind, vec2* p)
{ {
mg_mtl_path_elt* mtlElt = &context->elementBufferData[context->mtlEltCount]; mg_mtl_path_elt* mtlElt = &context->elementBufferData[context->mtlEltCount];
@ -147,6 +146,198 @@ void mg_mtl_canvas_encode_element(mg_mtl_encoding_context* context, mg_path_elt_
} }
} }
bool mg_intersect_hull_legs(vec2 p0, vec2 p1, vec2 p2, vec2 p3, vec2* intersection)
{
/*NOTE: check intersection of lines (p0-p1) and (p2-p3)
P = p0 + u(p1-p0)
P = p2 + w(p3-p2)
*/
bool found = false;
f32 den = (p0.x - p1.x)*(p2.y - p3.y) - (p0.y - p1.y)*(p2.x - p3.x);
if(fabs(den) > 0.0001)
{
f32 u = ((p0.x - p2.x)*(p2.y - p3.y) - (p0.y - p2.y)*(p2.x - p3.x))/den;
f32 w = ((p0.x - p2.x)*(p0.y - p1.y) - (p0.y - p2.y)*(p0.x - p1.x))/den;
intersection->x = p0.x + u*(p1.x - p0.x);
intersection->y = p0.y + u*(p1.y - p0.y);
found = true;
}
return(found);
}
bool mg_offset_hull(int count, vec2* p, vec2* result, f32 offset)
{
//NOTE: we should have no more than two coincident points here. This means the leg between
// those two points can't be offset, but we can set a double point at the start of first leg,
// end of first leg, or we can join the first and last leg to create a missing middle one
vec2 legs[3][2] = {0};
bool valid[3] = {0};
for(int i=0; i<count-1; i++)
{
vec2 n = {p[i].y - p[i+1].y,
p[i+1].x - p[i].x};
f32 norm = sqrt(n.x*n.x + n.y*n.y);
if(norm >= 1e-6)
{
n = vec2_mul(offset/norm, n);
legs[i][0] = vec2_add(p[i], n);
legs[i][1] = vec2_add(p[i+1], n);
valid[i] = true;
}
}
//NOTE: now we find intersections
// first point is either the start of the first or second leg
if(valid[0])
{
result[0] = legs[0][0];
}
else
{
ASSERT(valid[1]);
result[0] = legs[1][0];
}
for(int i=1; i<count-1; i++)
{
//NOTE: we're computing the control point i, at the end of leg (i-1)
if(!valid[i-1])
{
ASSERT(valid[i]);
result[i] = legs[i][0];
}
else if(!valid[i])
{
ASSERT(valid[i-1]);
result[i] = legs[i-1][0];
}
else
{
if(!mg_intersect_hull_legs(legs[i-1][0], legs[i-1][1], legs[i][0], legs[i][1], &result[i]))
{
// legs don't intersect.
return(false);
}
}
}
if(valid[count-2])
{
result[count-1] = legs[count-2][1];
}
else
{
ASSERT(valid[count-3]);
result[count-1] = legs[count-3][1];
}
return(true);
}
vec2 mg_quadratic_get_point(vec2 p[3], f32 t)
{
vec2 r;
f32 oneMt = 1-t;
f32 oneMt2 = Square(oneMt);
f32 t2 = Square(t);
r.x = oneMt2*p[0].x + 2*oneMt*t*p[1].x + t2*p[2].x;
r.y = oneMt2*p[0].y + 2*oneMt*t*p[1].y + t2*p[2].y;
return(r);
}
void mg_quadratic_split(vec2 p[3], f32 t, vec2 outLeft[3], vec2 outRight[3])
{
//DEBUG
__mgCurrentCanvas->splitCount++;
//NOTE(martin): split bezier curve p at parameter t, using De Casteljau's algorithm
// the q_n are the points along the hull's segments at parameter t
// s is the split point.
f32 oneMt = 1-t;
vec2 q0 = {oneMt*p[0].x + t*p[1].x,
oneMt*p[0].y + t*p[1].y};
vec2 q1 = {oneMt*p[1].x + t*p[2].x,
oneMt*p[1].y + t*p[2].y};
vec2 s = {oneMt*q0.x + t*q1.x,
oneMt*q0.y + t*q1.y};
outLeft[0] = p[0];
outLeft[1] = q0;
outLeft[2] = s;
outRight[0] = s;
outRight[1] = q1;
outRight[2] = p[2];
}
vec2 mg_cubic_get_point(vec2 p[4], f32 t)
{
vec2 r;
f32 oneMt = 1-t;
f32 oneMt2 = Square(oneMt);
f32 oneMt3 = oneMt2*oneMt;
f32 t2 = Square(t);
f32 t3 = t2*t;
r.x = oneMt3*p[0].x + 3*oneMt2*t*p[1].x + 3*oneMt*t2*p[2].x + t3*p[3].x;
r.y = oneMt3*p[0].y + 3*oneMt2*t*p[1].y + 3*oneMt*t2*p[2].y + t3*p[3].y;
return(r);
}
void mg_cubic_split(vec2 p[4], f32 t, vec2 outLeft[4], vec2 outRight[4])
{
//NOTE(martin): split bezier curve p at parameter t, using De Casteljau's algorithm
// the q_n are the points along the hull's segments at parameter t
// the r_n are the points along the (q_n, q_n+1) segments at parameter t
// s is the split point.
vec2 q0 = {(1-t)*p[0].x + t*p[1].x,
(1-t)*p[0].y + t*p[1].y};
vec2 q1 = {(1-t)*p[1].x + t*p[2].x,
(1-t)*p[1].y + t*p[2].y};
vec2 q2 = {(1-t)*p[2].x + t*p[3].x,
(1-t)*p[2].y + t*p[3].y};
vec2 r0 = {(1-t)*q0.x + t*q1.x,
(1-t)*q0.y + t*q1.y};
vec2 r1 = {(1-t)*q1.x + t*q2.x,
(1-t)*q1.y + t*q2.y};
vec2 s = {(1-t)*r0.x + t*r1.x,
(1-t)*r0.y + t*r1.y};;
outLeft[0] = p[0];
outLeft[1] = q0;
outLeft[2] = r0;
outLeft[3] = s;
outRight[0] = s;
outRight[1] = r1;
outRight[2] = q2;
outRight[3] = p[3];
}
void mg_mtl_render_stroke_line(mg_mtl_encoding_context* context, vec2* p) void mg_mtl_render_stroke_line(mg_mtl_encoding_context* context, vec2* p)
{ {
f32 width = context->primitive->attributes.width; f32 width = context->primitive->attributes.width;
@ -771,40 +962,36 @@ void mg_mtl_render_batch(mg_mtl_canvas_backend* backend,
void mg_mtl_canvas_resize(mg_mtl_canvas_backend* backend, vec2 size) void mg_mtl_canvas_resize(mg_mtl_canvas_backend* backend, vec2 size)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface); @autoreleasepool
if(surface)
{ {
@autoreleasepool if(backend->screenTilesBuffer)
{ {
if(backend->screenTilesBuffer) [backend->screenTilesBuffer release];
{ backend->screenTilesBuffer = nil;
[backend->screenTilesBuffer release];
backend->screenTilesBuffer = nil;
}
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(size.x + tileSize - 1)/tileSize;
int nTilesY = (int)(size.y + tileSize - 1)/tileSize;
MTLResourceOptions bufferOptions = MTLResourceStorageModePrivate;
backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
if(backend->outTexture)
{
[backend->outTexture release];
backend->outTexture = nil;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
backend->frameSize = size;
} }
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(size.x + tileSize - 1)/tileSize;
int nTilesY = (int)(size.y + tileSize - 1)/tileSize;
MTLResourceOptions bufferOptions = MTLResourceStorageModePrivate;
backend->screenTilesBuffer = [backend->surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
if(backend->outTexture)
{
[backend->outTexture release];
backend->outTexture = nil;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
backend->outTexture = [backend->surface->device newTextureWithDescriptor:texDesc];
backend->frameSize = size;
} }
} }
@ -829,10 +1016,10 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
//NOTE: prepare rendering //NOTE: prepare rendering
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface); mg_mtl_surface* surface = backend->surface;
ASSERT(surface && surface->interface.api == MG_METAL);
mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface);
mp_rect frame = mg_surface_get_frame(backend->surface);
f32 scale = surface->mtlLayer.contentsScale; f32 scale = surface->mtlLayer.contentsScale;
vec2 viewportSize = {frame.w * scale, frame.h * scale}; vec2 viewportSize = {frame.w * scale, frame.h * scale};
int tileSize = MG_MTL_TILE_SIZE; int tileSize = MG_MTL_TILE_SIZE;
@ -1068,34 +1255,31 @@ mg_image_data* mg_mtl_canvas_image_create(mg_canvas_backend* interface, vec2 siz
{ {
mg_mtl_image_data* image = 0; mg_mtl_image_data* image = 0;
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface); mg_mtl_surface* surface = backend->surface;
if(surface && surface->interface.api == MG_METAL) @autoreleasepool
{ {
@autoreleasepool{ image = malloc_type(mg_mtl_image_data);
if(image)
{
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModeManaged;
texDesc.usage = MTLTextureUsageShaderRead;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
image = malloc_type(mg_mtl_image_data); image->texture = [surface->device newTextureWithDescriptor:texDesc];
if(image) if(image->texture != nil)
{ {
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; [image->texture retain];
texDesc.textureType = MTLTextureType2D; image->interface.size = size;
texDesc.storageMode = MTLStorageModeManaged; }
texDesc.usage = MTLTextureUsageShaderRead; else
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm; {
texDesc.width = size.x; free(image);
texDesc.height = size.y; image = 0;
image->texture = [surface->device newTextureWithDescriptor:texDesc];
if(image->texture != nil)
{
[image->texture retain];
image->interface.size = size;
}
else
{
free(image);
image = 0;
}
} }
} }
} }
@ -1129,153 +1313,166 @@ const u32 MG_MTL_PATH_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_path),
MG_MTL_TILE_QUEUE_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_queue), MG_MTL_TILE_QUEUE_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_queue),
MG_MTL_TILE_OP_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_op); MG_MTL_TILE_OP_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_op);
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface) mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface)
{ {
mg_mtl_canvas_backend* backend = 0; mg_mtl_canvas_backend* backend = 0;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); backend = malloc_type(mg_mtl_canvas_backend);
if(surfaceData && surfaceData->api == MG_METAL) memset(backend, 0, sizeof(mg_mtl_canvas_backend));
{
mg_mtl_surface* metalSurface = (mg_mtl_surface*)surfaceData;
backend = malloc_type(mg_mtl_canvas_backend); backend->msaaCount = MG_MTL_MSAA_COUNT;
memset(backend, 0, sizeof(mg_mtl_canvas_backend)); backend->surface = surface;
backend->msaaCount = MG_MTL_MSAA_COUNT; //NOTE(martin): setup interface functions
backend->surface = surface; backend->interface.destroy = mg_mtl_canvas_destroy;
backend->interface.render = mg_mtl_canvas_render;
backend->interface.imageCreate = mg_mtl_canvas_image_create;
backend->interface.imageDestroy = mg_mtl_canvas_image_destroy;
backend->interface.imageUploadRegion = mg_mtl_canvas_image_upload_region;
//NOTE(martin): setup interface functions @autoreleasepool{
backend->interface.destroy = mg_mtl_canvas_destroy; //NOTE: load metal library
backend->interface.render = mg_mtl_canvas_render; str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "mtl_renderer.metallib");
backend->interface.imageCreate = mg_mtl_canvas_image_create; NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
backend->interface.imageDestroy = mg_mtl_canvas_image_destroy; NSError* err = 0;
backend->interface.imageUploadRegion = mg_mtl_canvas_image_upload_region; id<MTLLibrary> library = [surface->device newLibraryWithFile: metalFileName error:&err];
if(err != nil)
{
const char* errStr = [[err localizedDescription] UTF8String];
log_error("error : %s\n", errStr);
return(0);
}
id<MTLFunction> pathFunction = [library newFunctionWithName:@"mtl_path_setup"];
id<MTLFunction> segmentFunction = [library newFunctionWithName:@"mtl_segment_setup"];
id<MTLFunction> backpropFunction = [library newFunctionWithName:@"mtl_backprop"];
id<MTLFunction> mergeFunction = [library newFunctionWithName:@"mtl_merge"];
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
@autoreleasepool{ //NOTE: create pipelines
//NOTE: load metal library NSError* error = NULL;
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "mtl_renderer.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];
if(err != nil)
{
const char* errStr = [[err localizedDescription] UTF8String];
log_error("error : %s\n", errStr);
return(0);
}
id<MTLFunction> pathFunction = [library newFunctionWithName:@"mtl_path_setup"];
id<MTLFunction> segmentFunction = [library newFunctionWithName:@"mtl_segment_setup"];
id<MTLFunction> backpropFunction = [library newFunctionWithName:@"mtl_backprop"];
id<MTLFunction> mergeFunction = [library newFunctionWithName:@"mtl_merge"];
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
//NOTE: create pipelines backend->pathPipeline = [surface->device newComputePipelineStateWithFunction: pathFunction
NSError* error = NULL; error:&error];
backend->pathPipeline = [metalSurface->device newComputePipelineStateWithFunction: pathFunction backend->segmentPipeline = [surface->device newComputePipelineStateWithFunction: segmentFunction
error:&error]; error:&error];
backend->segmentPipeline = [metalSurface->device newComputePipelineStateWithFunction: segmentFunction backend->backpropPipeline = [surface->device newComputePipelineStateWithFunction: backpropFunction
error:&error]; error:&error];
backend->backpropPipeline = [metalSurface->device newComputePipelineStateWithFunction: backpropFunction backend->mergePipeline = [surface->device newComputePipelineStateWithFunction: mergeFunction
error:&error]; error:&error];
backend->mergePipeline = [metalSurface->device newComputePipelineStateWithFunction: mergeFunction backend->rasterPipeline = [surface->device newComputePipelineStateWithFunction: rasterFunction
error:&error]; error:&error];
backend->rasterPipeline = [metalSurface->device newComputePipelineStateWithFunction: rasterFunction MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
error:&error]; pipelineStateDescriptor.label = @"blit pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = surface->mtlLayer.pixelFormat;
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; backend->blitPipeline = [surface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
pipelineStateDescriptor.label = @"blit pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalSurface->mtlLayer.pixelFormat;
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
backend->blitPipeline = [metalSurface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err]; //NOTE: create textures
mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface);
f32 scale = surface->mtlLayer.contentsScale;
//NOTE: create textures backend->frameSize = (vec2){frame.w*scale, frame.h*scale};
mp_rect frame = mg_surface_get_frame(surface);
f32 scale = metalSurface->mtlLayer.contentsScale;
backend->frameSize = (vec2){frame.w*scale, frame.h*scale}; MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = backend->frameSize.x;
texDesc.height = backend->frameSize.y;
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = backend->frameSize.x;
texDesc.height = backend->frameSize.y;
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc]; //NOTE: create buffers
//NOTE: create buffers backend->bufferSemaphore = dispatch_semaphore_create(MG_MTL_INPUT_BUFFERS_COUNT);
backend->bufferIndex = 0;
backend->bufferSemaphore = dispatch_semaphore_create(MG_MTL_INPUT_BUFFERS_COUNT); MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
backend->bufferIndex = 0; | MTLResourceStorageModeShared;
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
| MTLResourceStorageModeShared; {
backend->pathBuffer[i] = [surface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
options: bufferOptions];
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++) backend->elementBuffer[i] = [surface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
{ options: bufferOptions];
backend->pathBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE }
options: bufferOptions];
backend->elementBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE bufferOptions = MTLResourceStorageModePrivate;
options: bufferOptions]; backend->segmentBuffer = [surface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
} options: bufferOptions];
bufferOptions = MTLResourceStorageModePrivate; backend->segmentCountBuffer = [surface->device newBufferWithLength: sizeof(int)
backend->segmentBuffer = [metalSurface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE options: bufferOptions];
options: bufferOptions];
backend->segmentCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int) backend->pathQueueBuffer = [surface->device newBufferWithLength: MG_MTL_PATH_QUEUE_BUFFER_SIZE
options: bufferOptions]; options: bufferOptions];
backend->tileQueueBuffer = [surface->device newBufferWithLength: MG_MTL_TILE_QUEUE_BUFFER_SIZE
options: bufferOptions];
backend->pathQueueBuffer = [metalSurface->device newBufferWithLength: MG_MTL_PATH_QUEUE_BUFFER_SIZE backend->tileQueueCountBuffer = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions]; options: bufferOptions];
backend->tileQueueBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_QUEUE_BUFFER_SIZE backend->tileOpBuffer = [surface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE
options: bufferOptions]; options: bufferOptions];
backend->tileQueueCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int) backend->tileOpCountBuffer = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions]; options: bufferOptions];
backend->tileOpBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE int tileSize = MG_MTL_TILE_SIZE;
options: bufferOptions]; int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize;
int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize;
backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
backend->tileOpCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int) bufferOptions = MTLResourceStorageModeShared;
options: bufferOptions]; for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->logBuffer[i] = [surface->device newBufferWithLength: 1<<20
options: bufferOptions];
int tileSize = MG_MTL_TILE_SIZE; backend->logOffsetBuffer[i] = [surface->device newBufferWithLength: sizeof(int)
int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; options: bufferOptions];
int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize;
backend->screenTilesBuffer = [metalSurface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
bufferOptions = MTLResourceStorageModeShared;
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->logBuffer[i] = [metalSurface->device newBufferWithLength: 1<<20
options: bufferOptions];
backend->logOffsetBuffer[i] = [metalSurface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
}
} }
} }
return((mg_canvas_backend*)backend); return((mg_canvas_backend*)backend);
} }
mg_surface_data* mtl_canvas_surface_create_for_window(mp_window window)
{
mg_mtl_surface* surface = (mg_mtl_surface*)mg_mtl_surface_create_for_window(window);
if(surface)
{
surface->interface.backend = mtl_canvas_backend_create(surface);
if(surface->interface.backend)
{
surface->interface.api = MG_CANVAS;
}
else
{
surface->interface.destroy((mg_surface_data*)surface);
surface = 0;
}
}
return((mg_surface_data*)surface);
}

View File

@ -33,7 +33,7 @@
// OS identification // OS identification
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(_WIN64) #if defined(_WIN64)
#define PLATFORM_WIN64 1 #define PLATFORM_WINDOWS 1
#elif defined(_WIN32) #elif defined(_WIN32)
#error "Unsupported OS (32bit only version of Windows)" #error "Unsupported OS (32bit only version of Windows)"
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)

View File

@ -8,7 +8,7 @@
#include<stdio.h> #include<stdio.h>
#include"platform_log.c" #include"platform_log.c"
#if PLATFORM_WIN32 || PLATFORM_WIN64 #if PLATFORM_WINDOWS
#include<io.h> #include<io.h>
#define isatty _isatty #define isatty _isatty
#define fileno _fileno #define fileno _fileno

1573
src/tmp_gl_canvas.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2293,7 +2293,7 @@ typedef struct ui_edit_command
} ui_edit_command; } ui_edit_command;
#if PLATFORM_WIN64 #if PLATFORM_WINDOWS
#define OS_COPY_PASTE_MOD MP_KEYMOD_CTRL #define OS_COPY_PASTE_MOD MP_KEYMOD_CTRL
#elif PLATFORM_MACOS #elif PLATFORM_MACOS
#define OS_COPY_PASTE_MOD MP_KEYMOD_CMD #define OS_COPY_PASTE_MOD MP_KEYMOD_CMD