[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:
parent
32d7d91893
commit
346979a21a
|
@ -52,8 +52,6 @@ mg_font create_font()
|
|||
|
||||
int main()
|
||||
{
|
||||
LogLevel(LOG_LEVEL_WARNING);
|
||||
|
||||
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);
|
||||
|
||||
//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);
|
||||
|
||||
//TODO: create canvas
|
||||
mg_canvas canvas = mg_canvas_create(surface);
|
||||
mg_canvas canvas = mg_canvas_create();
|
||||
|
||||
if(mg_canvas_is_nil(canvas))
|
||||
{
|
||||
|
@ -91,10 +88,10 @@ int main()
|
|||
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
|
||||
|
||||
mp_pump_events(0);
|
||||
mp_event event = {0};
|
||||
while(mp_next_event(&event))
|
||||
mp_event* event = 0;
|
||||
while((event = mp_next_event(mem_scratch())) != 0)
|
||||
{
|
||||
switch(event.type)
|
||||
switch(event->type)
|
||||
{
|
||||
case MP_EVENT_WINDOW_CLOSE:
|
||||
{
|
||||
|
@ -103,23 +100,23 @@ int main()
|
|||
|
||||
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;
|
||||
}
|
||||
else if(event.key.code == MP_KEY_RIGHT)
|
||||
else if(event->key.code == MP_KEY_RIGHT)
|
||||
{
|
||||
x+=0.3*factor;
|
||||
}
|
||||
else if(event.key.code == MP_KEY_UP)
|
||||
else if(event->key.code == MP_KEY_UP)
|
||||
{
|
||||
y-=0.3*factor;
|
||||
}
|
||||
else if(event.key.code == MP_KEY_DOWN)
|
||||
else if(event->key.code == MP_KEY_DOWN)
|
||||
{
|
||||
y+=0.3*factor;
|
||||
}
|
||||
|
@ -154,55 +151,47 @@ int main()
|
|||
x += dx;
|
||||
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);
|
||||
|
||||
// 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_flush(surface);
|
||||
mg_surface_present(surface);
|
||||
|
||||
mem_arena_clear(mem_scratch());
|
||||
|
|
|
@ -94,7 +94,6 @@ mg_font create_font(const char* path)
|
|||
|
||||
int main()
|
||||
{
|
||||
LogLevel(LOG_LEVEL_MESSAGE);
|
||||
mp_init();
|
||||
mp_clock_init();
|
||||
|
||||
|
@ -105,10 +104,10 @@ int main()
|
|||
|
||||
//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_canvas canvas = mg_canvas_create(surface);
|
||||
mg_canvas canvas = mg_canvas_create();
|
||||
|
||||
const int fontCount = 3;
|
||||
int fontIndex = 0;
|
||||
|
@ -153,15 +152,19 @@ int main()
|
|||
f32 startX = 10;
|
||||
f32 startY = 10 + lineHeights[fontIndex];
|
||||
|
||||
mp_input_state inputState = {0};
|
||||
|
||||
while(!mp_should_quit())
|
||||
{
|
||||
f64 startFrameTime = mp_get_time(MP_CLOCK_MONOTONIC);
|
||||
|
||||
mp_pump_events(0);
|
||||
mp_event event = {0};
|
||||
while(mp_next_event(&event))
|
||||
mp_event* event = 0;
|
||||
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:
|
||||
{
|
||||
|
@ -170,12 +173,12 @@ int main()
|
|||
|
||||
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;
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
trackPoint.x = mousePos.x/zoom - startX;
|
||||
trackPoint.y = mousePos.y/zoom - startY;
|
||||
}
|
||||
|
@ -188,11 +191,11 @@ int main()
|
|||
|
||||
case MP_EVENT_MOUSE_WHEEL:
|
||||
{
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
f32 trackX = mousePos.x/zoom - startX;
|
||||
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);
|
||||
|
||||
startX = mousePos.x/zoom - trackX;
|
||||
|
@ -201,7 +204,7 @@ int main()
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -214,7 +217,7 @@ int main()
|
|||
|
||||
if(tracked)
|
||||
{
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
startX = mousePos.x/zoom - trackPoint.x;
|
||||
startY = mousePos.y/zoom - trackPoint.y;
|
||||
}
|
||||
|
@ -289,8 +292,7 @@ int main()
|
|||
f64 startFlushTime = mp_get_time(MP_CLOCK_MONOTONIC);
|
||||
|
||||
mg_surface_prepare(surface);
|
||||
|
||||
mg_flush();
|
||||
mg_flush(surface);
|
||||
|
||||
f64 startPresentTime = mp_get_time(MP_CLOCK_MONOTONIC);
|
||||
mg_surface_present(surface);
|
||||
|
@ -306,6 +308,7 @@ int main()
|
|||
(startPresentTime - startFlushTime)*1000,
|
||||
(endFrameTime - startPresentTime)*1000);
|
||||
|
||||
mp_input_next_frame(&inputState);
|
||||
mem_arena_clear(mem_scratch());
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
#include"milepost.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "Main"
|
||||
|
||||
#include"tiger.c"
|
||||
|
||||
mg_font create_font()
|
||||
|
@ -53,8 +51,6 @@ mg_font create_font()
|
|||
|
||||
int main()
|
||||
{
|
||||
LogLevel(LOG_LEVEL_WARNING);
|
||||
|
||||
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);
|
||||
|
||||
//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);
|
||||
|
||||
//TODO: create canvas
|
||||
mg_canvas canvas = mg_canvas_create(surface);
|
||||
mg_canvas canvas = mg_canvas_create();
|
||||
|
||||
if(mg_canvas_is_nil(canvas))
|
||||
{
|
||||
|
@ -92,15 +88,19 @@ int main()
|
|||
|
||||
f64 frameTime = 0;
|
||||
|
||||
mp_input_state inputState = {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))
|
||||
mp_event* event = 0;
|
||||
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:
|
||||
{
|
||||
|
@ -109,18 +109,18 @@ int main()
|
|||
|
||||
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);
|
||||
} break;
|
||||
|
||||
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;
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
trackPoint.x = (mousePos.x - startX)/zoom;
|
||||
trackPoint.y = (mousePos.y - startY)/zoom;
|
||||
}
|
||||
|
@ -133,11 +133,11 @@ int main()
|
|||
|
||||
case MP_EVENT_MOUSE_WHEEL:
|
||||
{
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
f32 pinX = (mousePos.x - startX)/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);
|
||||
|
||||
startX = mousePos.x - pinX*zoom;
|
||||
|
@ -146,9 +146,9 @@ int main()
|
|||
|
||||
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:
|
||||
singlePath = !singlePath;
|
||||
|
@ -156,7 +156,7 @@ int main()
|
|||
|
||||
case MP_KEY_UP:
|
||||
{
|
||||
if(event.key.mods & MP_KEYMOD_SHIFT)
|
||||
if(event->key.mods & MP_KEYMOD_SHIFT)
|
||||
{
|
||||
singlePathIndex++;
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ int main()
|
|||
|
||||
case MP_KEY_DOWN:
|
||||
{
|
||||
if(event.key.mods & MP_KEYMOD_SHIFT)
|
||||
if(event->key.mods & MP_KEYMOD_SHIFT)
|
||||
{
|
||||
singlePathIndex--;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ int main()
|
|||
|
||||
if(tracked)
|
||||
{
|
||||
vec2 mousePos = mp_mouse_position();
|
||||
vec2 mousePos = mp_mouse_position(&inputState);
|
||||
startX = mousePos.x - trackPoint.x*zoom;
|
||||
startY = mousePos.y - trackPoint.y*zoom;
|
||||
}
|
||||
|
@ -228,9 +228,10 @@ int main()
|
|||
frameTime,
|
||||
1./frameTime);
|
||||
|
||||
mg_flush();
|
||||
mg_flush(surface);
|
||||
mg_surface_present(surface);
|
||||
|
||||
mp_input_next_frame(&inputState);
|
||||
mem_arena_clear(mem_scratch());
|
||||
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
|
||||
}
|
||||
|
|
1952
src/graphics.c
1952
src/graphics.c
File diff suppressed because it is too large
Load Diff
|
@ -27,43 +27,51 @@ typedef enum {
|
|||
|
||||
//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(PLATFORM_MACOS)
|
||||
#ifndef MG_COMPILE_BACKEND_METAL
|
||||
#define MG_COMPILE_BACKEND_METAL 1
|
||||
#if PLATFORM_MACOS
|
||||
#ifndef MG_COMPILE_METAL
|
||||
#define MG_COMPILE_METAL 1
|
||||
#endif
|
||||
|
||||
#ifndef MG_COMPILE_BACKEND_GLES
|
||||
#define MG_COMPILE_BACKEND_GLES 1
|
||||
#ifndef MG_COMPILE_GLES
|
||||
#define MG_COMPILE_GLES 1
|
||||
#endif
|
||||
|
||||
#ifndef MG_COMPILE_BACKEND_CANVAS
|
||||
#define MG_COMPILE_BACKEND_CANVAS 1
|
||||
#ifndef MG_COMPILE_CANVAS
|
||||
#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
|
||||
|
||||
#define MG_COMPILE_BACKEND_GL 0
|
||||
#define MG_COMPILE_GL 0
|
||||
|
||||
#elif defined(PLATFORM_WIN64)
|
||||
#ifndef MG_COMPILE_BACKEND_GL
|
||||
#define MG_COMPILE_BACKEND_GL 1
|
||||
#elif PLATFORM_WINDOWS
|
||||
#ifndef MG_COMPILE_GL
|
||||
#define MG_COMPILE_GL 1
|
||||
#endif
|
||||
|
||||
#ifndef MG_COMPILE_BACKEND_GLES
|
||||
#define MG_COMPILE_BACKEND_GLES 1
|
||||
#ifndef MG_COMPILE_GLES
|
||||
#define MG_COMPILE_GLES 1
|
||||
#endif
|
||||
|
||||
#ifndef MG_COMPILE_BACKEND_CANVAS
|
||||
#define MG_COMPILE_BACKEND_CANVAS 1
|
||||
#ifndef MG_COMPILE_CANVAS
|
||||
#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
|
||||
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
#ifndef MG_COMPILE_BACKEND_GL
|
||||
#define MG_COMPILE_BACKEND_GL 1
|
||||
#elif PLATFORM_LINUX
|
||||
#ifndef MG_COMPILE_GL
|
||||
#define MG_COMPILE_GL 1
|
||||
#endif
|
||||
|
||||
#ifndef MG_COMPILE_BACKEND_CANVAS
|
||||
#define MG_COMPILE_BACKEND_CANVAS 1
|
||||
#ifndef MG_COMPILE_CANVAS
|
||||
#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
|
||||
|
||||
//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 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);
|
||||
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
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
@ -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 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_from_rgba8(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_file(str8 path, bool flip);
|
||||
MP_API mg_image mg_image_create(mg_surface surface, u32 width, u32 height);
|
||||
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(mg_surface surface, str8 data, 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);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ extern "C" {
|
|||
// surface interface
|
||||
//---------------------------------------------------------------
|
||||
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_prepare_proc)(mg_surface_data* surface);
|
||||
|
@ -51,6 +52,9 @@ typedef struct mg_surface_data
|
|||
mg_surface_native_layer_proc nativeLayer;
|
||||
mg_surface_remote_id_proc remoteID;
|
||||
mg_surface_host_connect_proc hostConnect;
|
||||
|
||||
mg_canvas_backend* backend;
|
||||
|
||||
} mg_surface_data;
|
||||
|
||||
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
|
||||
|
@ -69,6 +73,7 @@ typedef struct mg_image_data
|
|||
{
|
||||
list_elt listElt;
|
||||
u32 generation;
|
||||
mg_surface surface;
|
||||
vec2 size;
|
||||
|
||||
} mg_image_data;
|
||||
|
@ -104,7 +109,6 @@ typedef struct 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_begin_proc)(mg_canvas_backend* backend, mg_color clearColor);
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
|
||||
#include"platform/std_log.c"
|
||||
|
||||
#if defined(PLATFORM_WIN64)
|
||||
#if PLATFORM_WINDOWS
|
||||
#include"platform/win32_memory.c"
|
||||
#include"platform/win32_clock.c"
|
||||
//TODO
|
||||
#elif defined(PLATFORM_MACOS)
|
||||
#elif PLATFORM_MACOS
|
||||
#include"platform/unix_memory.c"
|
||||
#include"platform/osx_clock.c"
|
||||
/*
|
||||
|
@ -27,7 +27,7 @@
|
|||
#include"platform/posix_socket.c"
|
||||
*/
|
||||
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
#elif PLATFORM_LINUX
|
||||
#include"platform/unix_base_memory.c"
|
||||
#include"platform/linux_clock.c"
|
||||
/*
|
||||
|
@ -52,24 +52,27 @@
|
|||
// app/graphics layer
|
||||
//---------------------------------------------------------------
|
||||
|
||||
#if defined(PLATFORM_WIN64)
|
||||
#if PLATFORM_WINDOWS
|
||||
#include"win32_app.c"
|
||||
#include"graphics.c"
|
||||
|
||||
#if MG_COMPILE_BACKEND_GL || MG_COMPILE_BACKEND_GLES
|
||||
#if MG_COMPILE_GL || MG_COMPILE_GLES
|
||||
#include"gl_loader.c"
|
||||
#endif
|
||||
|
||||
#if MG_COMPILE_BACKEND_GL
|
||||
#if MG_COMPILE_GL
|
||||
#include"wgl_surface.c"
|
||||
#endif
|
||||
|
||||
#if MG_COMPILE_CANVAS
|
||||
#include"gl_canvas.c"
|
||||
#endif
|
||||
|
||||
#if MG_COMPILE_BACKEND_GLES
|
||||
#if MG_COMPILE_GLES
|
||||
#include"egl_surface.c"
|
||||
#endif
|
||||
|
||||
#elif defined(PLATFORM_MACOS)
|
||||
#elif PLATFORM_MACOS
|
||||
//NOTE: macos application layer and graphics backends are defined in milepost.m
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
|
|
|
@ -10,21 +10,15 @@
|
|||
#include"osx_app.m"
|
||||
#include"graphics.c"
|
||||
|
||||
#if MG_COMPILE_BACKEND_METAL
|
||||
#if MG_COMPILE_METAL
|
||||
#include"mtl_surface.m"
|
||||
// #include"mtl_canvas.m"
|
||||
#endif
|
||||
|
||||
#if MG_COMPILE_CANVAS
|
||||
#include"mtl_renderer.m"
|
||||
#endif
|
||||
|
||||
#if MG_COMPILE_BACKEND_GLES
|
||||
#if MG_COMPILE_GLES
|
||||
#include"gl_loader.c"
|
||||
#include"egl_surface.c"
|
||||
#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"
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include"platform.h"
|
||||
#include"ringbuffer.h"
|
||||
|
||||
#if defined(PLATFORM_WIN64) || defined(PLATFORM_WIN32)
|
||||
#if PLATFORM_WINDOWS
|
||||
#include"win32_app.h"
|
||||
#elif defined(PLATFORM_MACOS)
|
||||
#elif PLATFORM_MACOS
|
||||
#include"osx_app.h"
|
||||
#else
|
||||
#error "platform not supported yet"
|
||||
|
|
|
@ -23,7 +23,7 @@ const int MG_MTL_INPUT_BUFFERS_COUNT = 3,
|
|||
typedef struct mg_mtl_canvas_backend
|
||||
{
|
||||
mg_canvas_backend interface;
|
||||
mg_surface surface;
|
||||
mg_mtl_surface* surface;
|
||||
|
||||
id<MTLComputePipelineState> pathPipeline;
|
||||
id<MTLComputePipelineState> segmentPipeline;
|
||||
|
@ -64,15 +64,6 @@ typedef struct mg_mtl_image_data
|
|||
id<MTLTexture> texture;
|
||||
} 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)
|
||||
{
|
||||
char* log = [logBuffer contents];
|
||||
|
@ -106,6 +97,14 @@ typedef struct 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface);
|
||||
if(surface)
|
||||
@autoreleasepool
|
||||
{
|
||||
@autoreleasepool
|
||||
if(backend->screenTilesBuffer)
|
||||
{
|
||||
if(backend->screenTilesBuffer)
|
||||
{
|
||||
[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;
|
||||
[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 = [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
|
||||
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface);
|
||||
ASSERT(surface && surface->interface.api == MG_METAL);
|
||||
mg_mtl_surface* surface = backend->surface;
|
||||
|
||||
mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface);
|
||||
|
||||
mp_rect frame = mg_surface_get_frame(backend->surface);
|
||||
f32 scale = surface->mtlLayer.contentsScale;
|
||||
vec2 viewportSize = {frame.w * scale, frame.h * scale};
|
||||
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_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);
|
||||
if(image)
|
||||
image->texture = [surface->device newTextureWithDescriptor:texDesc];
|
||||
if(image->texture != nil)
|
||||
{
|
||||
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->texture = [surface->device newTextureWithDescriptor:texDesc];
|
||||
if(image->texture != nil)
|
||||
{
|
||||
[image->texture retain];
|
||||
image->interface.size = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(image);
|
||||
image = 0;
|
||||
}
|
||||
[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_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_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
||||
if(surfaceData && surfaceData->api == MG_METAL)
|
||||
{
|
||||
mg_mtl_surface* metalSurface = (mg_mtl_surface*)surfaceData;
|
||||
backend = malloc_type(mg_mtl_canvas_backend);
|
||||
memset(backend, 0, sizeof(mg_mtl_canvas_backend));
|
||||
|
||||
backend = malloc_type(mg_mtl_canvas_backend);
|
||||
memset(backend, 0, sizeof(mg_mtl_canvas_backend));
|
||||
backend->msaaCount = MG_MTL_MSAA_COUNT;
|
||||
backend->surface = surface;
|
||||
|
||||
backend->msaaCount = MG_MTL_MSAA_COUNT;
|
||||
backend->surface = surface;
|
||||
//NOTE(martin): setup interface functions
|
||||
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
|
||||
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;
|
||||
@autoreleasepool{
|
||||
//NOTE: load metal library
|
||||
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 = [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: load metal library
|
||||
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
|
||||
NSError* error = NULL;
|
||||
|
||||
//NOTE: create pipelines
|
||||
NSError* error = NULL;
|
||||
backend->pathPipeline = [surface->device newComputePipelineStateWithFunction: pathFunction
|
||||
error:&error];
|
||||
|
||||
backend->pathPipeline = [metalSurface->device newComputePipelineStateWithFunction: pathFunction
|
||||
error:&error];
|
||||
backend->segmentPipeline = [surface->device newComputePipelineStateWithFunction: segmentFunction
|
||||
error:&error];
|
||||
|
||||
backend->segmentPipeline = [metalSurface->device newComputePipelineStateWithFunction: segmentFunction
|
||||
error:&error];
|
||||
backend->backpropPipeline = [surface->device newComputePipelineStateWithFunction: backpropFunction
|
||||
error:&error];
|
||||
|
||||
backend->backpropPipeline = [metalSurface->device newComputePipelineStateWithFunction: backpropFunction
|
||||
error:&error];
|
||||
backend->mergePipeline = [surface->device newComputePipelineStateWithFunction: mergeFunction
|
||||
error:&error];
|
||||
|
||||
backend->mergePipeline = [metalSurface->device newComputePipelineStateWithFunction: mergeFunction
|
||||
error:&error];
|
||||
backend->rasterPipeline = [surface->device newComputePipelineStateWithFunction: rasterFunction
|
||||
error:&error];
|
||||
|
||||
backend->rasterPipeline = [metalSurface->device newComputePipelineStateWithFunction: rasterFunction
|
||||
error:&error];
|
||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
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];
|
||||
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 = [surface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
|
||||
|
||||
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
|
||||
mp_rect frame = mg_surface_get_frame(surface);
|
||||
f32 scale = metalSurface->mtlLayer.contentsScale;
|
||||
backend->frameSize = (vec2){frame.w*scale, frame.h*scale};
|
||||
|
||||
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];
|
||||
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 = [surface->device newTextureWithDescriptor:texDesc];
|
||||
|
||||
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);
|
||||
backend->bufferIndex = 0;
|
||||
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
|
||||
| MTLResourceStorageModeShared;
|
||||
|
||||
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
|
||||
| MTLResourceStorageModeShared;
|
||||
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
|
||||
{
|
||||
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->pathBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
backend->elementBuffer[i] = [surface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
}
|
||||
|
||||
backend->elementBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
}
|
||||
bufferOptions = MTLResourceStorageModePrivate;
|
||||
backend->segmentBuffer = [surface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
|
||||
bufferOptions = MTLResourceStorageModePrivate;
|
||||
backend->segmentBuffer = [metalSurface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
backend->segmentCountBuffer = [surface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
|
||||
backend->segmentCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
backend->pathQueueBuffer = [surface->device newBufferWithLength: MG_MTL_PATH_QUEUE_BUFFER_SIZE
|
||||
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
|
||||
options: bufferOptions];
|
||||
backend->tileQueueCountBuffer = [surface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
|
||||
backend->tileQueueBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_QUEUE_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
backend->tileOpBuffer = [surface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
|
||||
backend->tileQueueCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
backend->tileOpCountBuffer = [surface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
|
||||
backend->tileOpBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE
|
||||
options: bufferOptions];
|
||||
int tileSize = MG_MTL_TILE_SIZE;
|
||||
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)
|
||||
options: bufferOptions];
|
||||
bufferOptions = MTLResourceStorageModeShared;
|
||||
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;
|
||||
int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize;
|
||||
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];
|
||||
}
|
||||
backend->logOffsetBuffer[i] = [surface->device newBufferWithLength: sizeof(int)
|
||||
options: bufferOptions];
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
// OS identification
|
||||
//-----------------------------------------------------------------
|
||||
#if defined(_WIN64)
|
||||
#define PLATFORM_WIN64 1
|
||||
#define PLATFORM_WINDOWS 1
|
||||
#elif defined(_WIN32)
|
||||
#error "Unsupported OS (32bit only version of Windows)"
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include<stdio.h>
|
||||
#include"platform_log.c"
|
||||
|
||||
#if PLATFORM_WIN32 || PLATFORM_WIN64
|
||||
#if PLATFORM_WINDOWS
|
||||
#include<io.h>
|
||||
#define isatty _isatty
|
||||
#define fileno _fileno
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue