From 86b1121fbe5f7b49c51379b53e07f5044c40b4b8 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Wed, 23 Aug 2023 15:06:35 +0200 Subject: [PATCH 1/3] allow enabling/disabling metal frame capture when bundling a macos app --- scripts/bundle.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/bundle.py b/scripts/bundle.py index 1997d25..44b6571 100644 --- a/scripts/bundle.py +++ b/scripts/bundle.py @@ -22,6 +22,7 @@ def init_parser(parser): parser.add_argument("-n", "--name", default="out", help="the app's name") parser.add_argument("-O", "--orca-dir", default=".") parser.add_argument("--version", default="0.0.0", help="a version number to embed in the application bundle") + parser.add_argument("--mtl-enable-capture", action='store_true', help="Enable Metal frame capture for the application bundle (macOS only)") parser.add_argument("module", help="a .wasm file containing the application's wasm module") parser.set_defaults(func=shellish(make_app)) @@ -169,9 +170,14 @@ def macos_make_app(args): icon.icns NSHighResolutionCapable True + """ + if args.mtl_enable_capture == True: + plist_contents += f""" MetalCaptureEnabled - - + """ + + plist_contents += f""" + """ From 98f131cb3076f299d062079773b8957c5732ee06 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Wed, 23 Aug 2023 15:09:06 +0200 Subject: [PATCH 2/3] Fix leak in metal surface: command buffer must not be committed if there is no surface to present it to, or it will result in a huge leak in metal resources. Also wrap oc_mtl_surface_acquire_command_buffer() in an @autoreleasepool to fix a smaller leak --- src/graphics/mtl_surface.m | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/graphics/mtl_surface.m b/src/graphics/mtl_surface.m index 2d40083..ecab941 100644 --- a/src/graphics/mtl_surface.m +++ b/src/graphics/mtl_surface.m @@ -53,10 +53,13 @@ void oc_mtl_surface_destroy(oc_surface_data* interface) void oc_mtl_surface_acquire_command_buffer(oc_mtl_surface* surface) { - if(surface->commandBuffer == nil) + @autoreleasepool { - surface->commandBuffer = [surface->commandQueue commandBuffer]; - [surface->commandBuffer retain]; + if(surface->commandBuffer == nil) + { + surface->commandBuffer = [surface->commandQueue commandBuffer]; + [surface->commandBuffer retain]; + } } } @@ -102,8 +105,9 @@ void oc_mtl_surface_present(oc_surface_data* interface) [surface->commandBuffer presentDrawable:surface->drawable]; [surface->drawable release]; surface->drawable = nil; + + [surface->commandBuffer commit]; } - [surface->commandBuffer commit]; [surface->commandBuffer release]; surface->commandBuffer = nil; } From 42738195b56cea255cb05289c86bfe8758d1d6f2 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Wed, 23 Aug 2023 16:10:52 +0200 Subject: [PATCH 3/3] Don't assume oc_scratch() is cleared at the frame boundary. Use oc_scratch_begin()/oc_scratch_end() instead --- samples/pong/src/main.c | 6 ++++- samples/ui/src/main.c | 2 ++ src/app/osx_app.m | 21 ++++++++------- src/graphics/graphics_common.c | 40 +++++++++++++++++++++-------- src/runtime_io.c | 1 - src/wasmbind/gles_api_bind_manual.c | 6 ++++- 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/samples/pong/src/main.c b/samples/pong/src/main.c index c734807..98af1e5 100644 --- a/samples/pong/src/main.c +++ b/samples/pong/src/main.c @@ -56,7 +56,9 @@ oc_str8 loadFile(oc_arena* arena, oc_str8 filename) oc_file file = oc_file_open(filename, OC_FILE_ACCESS_READ, 0); if(oc_file_last_error(file) != OC_IO_OK) { - oc_log_error("Couldn't open file %s\n", oc_str8_to_cstring(oc_scratch(), filename)); + oc_arena_scope scope = oc_arena_scope_begin(arena); + oc_log_error("Couldn't open file %s\n", oc_str8_to_cstring(arena, filename)); + oc_arena_scope_end(scope); } u64 size = oc_file_size(file); char* buffer = oc_arena_push(arena, size); @@ -347,6 +349,8 @@ ORCA_EXPORT void oc_on_frame_refresh(void) oc_surface_select(surface); oc_render(surface, canvas); oc_surface_present(surface); + + oc_arena_clear(oc_scratch()); } oc_rect blockRect(int i) diff --git a/samples/ui/src/main.c b/samples/ui/src/main.c index bf342e3..7da4677 100644 --- a/samples/ui/src/main.c +++ b/samples/ui/src/main.c @@ -393,4 +393,6 @@ ORCA_EXPORT void oc_on_frame_refresh(void) oc_ui_draw(); oc_render(surface, canvas); oc_surface_present(surface); + + oc_arena_clear(oc_scratch()); } diff --git a/src/app/osx_app.m b/src/app/osx_app.m index 331788d..bf01d83 100644 --- a/src/app/osx_app.m +++ b/src/app/osx_app.m @@ -451,15 +451,15 @@ void oc_install_keyboard_layout_listener() event.window = (oc_window){ 0 }; event.type = OC_EVENT_PATHDROP; - oc_arena* scratch = oc_scratch(); - oc_arena_scope scope = oc_arena_scope_begin(scratch); + oc_arena_scope scratch = oc_scratch_begin(); - oc_str8 path = oc_str8_push_cstring(scratch, [filename UTF8String]); - oc_str8_list_push(scratch, &event.paths, path); + oc_str8 path = oc_str8_push_cstring(scratch.arena, [filename UTF8String]); + oc_str8_list_push(scratch.arena, &event.paths, path); oc_queue_event(&event); - oc_arena_scope_end(scope); + //NOTE: oc_queue_event copies paths to the event queue, so we can clear the arena scope here + oc_scratch_end(scratch); return (YES); } @@ -472,15 +472,15 @@ void oc_install_keyboard_layout_listener() event.window = (oc_window){ 0 }; event.type = OC_EVENT_PATHDROP; - oc_arena* scratch = oc_scratch(); - oc_arena_scope scope = oc_arena_scope_begin(scratch); + oc_arena_scope scratch = oc_scratch_begin(); - oc_str8 path = oc_str8_push_cstring(scratch, [nsPath UTF8String]); - oc_str8_list_push(scratch, &event.paths, path); + oc_str8 path = oc_str8_push_cstring(scratch.arena, [nsPath UTF8String]); + oc_str8_list_push(scratch.arena, &event.paths, path); oc_queue_event(&event); - oc_arena_scope_end(scope); + //NOTE: oc_queue_event copies paths to the event queue, so we can clear the arena scope here + oc_scratch_end(scratch); } //TODO: drag and drop paths @@ -1536,7 +1536,6 @@ void oc_window_restore(oc_window window) } } - void oc_window_send_to_back(oc_window window) { @autoreleasepool diff --git a/src/graphics/graphics_common.c b/src/graphics/graphics_common.c index c963627..d050df9 100644 --- a/src/graphics/graphics_common.c +++ b/src/graphics/graphics_common.c @@ -719,8 +719,8 @@ oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 codePoin return ((oc_rect){ 0 }); } - oc_arena* scratch = oc_scratch(); - oc_str32 glyphIndices = oc_font_push_glyph_indices(font, scratch, codePoints); + oc_arena_scope scratch = oc_scratch_begin(); + oc_str32 glyphIndices = oc_font_push_glyph_indices(font, scratch.arena, codePoints); //NOTE(martin): find width of missing character //TODO(martin): should cache that at font creation... @@ -789,6 +789,8 @@ oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 codePoin f32 fontScale = oc_font_get_scale_for_em_pixels(font, fontSize); oc_rect rect = { 0, -fontData->extents.ascent * fontScale, width * fontScale, (y + lineHeight) * fontScale }; + + oc_scratch_end(scratch); return (rect); } @@ -799,9 +801,11 @@ oc_rect oc_text_bounding_box(oc_font font, f32 fontSize, oc_str8 text) return ((oc_rect){ 0 }); } - oc_arena* scratch = oc_scratch(); - oc_str32 codePoints = oc_utf8_push_to_codepoints(scratch, text); - return (oc_text_bounding_box_utf32(font, fontSize, codePoints)); + oc_arena_scope scratch = oc_scratch_begin(); + oc_str32 codePoints = oc_utf8_push_to_codepoints(scratch.arena, text); + oc_rect result = oc_text_bounding_box_utf32(font, fontSize, codePoints); + oc_scratch_end(scratch); + return (result); } //------------------------------------------------------------------------------------------ @@ -1353,8 +1357,12 @@ void oc_codepoints_outlines(oc_str32 codePoints) return; } - oc_str32 glyphIndices = oc_font_push_glyph_indices(canvas->attributes.font, oc_scratch(), codePoints); + oc_arena_scope scratch = oc_scratch_begin(); + + oc_str32 glyphIndices = oc_font_push_glyph_indices(canvas->attributes.font, scratch.arena, codePoints); oc_glyph_outlines_from_font_data(fontData, glyphIndices); + + oc_scratch_end(scratch); } void oc_text_outlines(oc_str8 text) @@ -1370,11 +1378,13 @@ void oc_text_outlines(oc_str8 text) return; } - oc_arena* scratch = oc_scratch(); - oc_str32 codePoints = oc_utf8_push_to_codepoints(scratch, text); - oc_str32 glyphIndices = oc_font_push_glyph_indices(canvas->attributes.font, scratch, codePoints); + oc_arena_scope scratch = oc_scratch_begin(); + oc_str32 codePoints = oc_utf8_push_to_codepoints(scratch.arena, text); + oc_str32 glyphIndices = oc_font_push_glyph_indices(canvas->attributes.font, scratch.arena, codePoints); oc_glyph_outlines_from_font_data(fontData, glyphIndices); + + oc_scratch_end(scratch); } //------------------------------------------------------------------------------------------ @@ -1579,7 +1589,9 @@ oc_image oc_image_create_from_file(oc_surface surface, oc_str8 path, bool flip) oc_image image = oc_image_nil(); int width, height, channels; - const char* cpath = oc_str8_to_cstring(oc_scratch(), path); + oc_arena_scope scratch = oc_scratch_begin(); + + const char* cpath = oc_str8_to_cstring(scratch.arena, path); stbi_set_flip_vertically_on_load(flip ? 1 : 0); u8* pixels = stbi_load(cpath, &width, &height, &channels, 4); @@ -1592,6 +1604,8 @@ oc_image oc_image_create_from_file(oc_surface surface, oc_str8 path, bool flip) { oc_log_error("stbi_load() failed: %s\n", stbi_failure_reason()); } + oc_scratch_end(scratch); + return (image); } @@ -1719,9 +1733,13 @@ oc_image_region oc_image_atlas_alloc_from_file(oc_rect_atlas* atlas, oc_image ba stbi_set_flip_vertically_on_load(flip ? 1 : 0); - const char* cpath = oc_str8_to_cstring(oc_scratch(), path); + oc_arena_scope scratch = oc_scratch_begin(); + + const char* cpath = oc_str8_to_cstring(scratch.arena, path); int width, height, channels; u8* pixels = stbi_load(cpath, &width, &height, &channels, 4); + oc_scratch_end(scratch); + if(pixels) { imageRgn = oc_image_atlas_alloc_from_rgba8(atlas, backingImage, width, height, pixels); diff --git a/src/runtime_io.c b/src/runtime_io.c index cfdcd90..0aad530 100644 --- a/src/runtime_io.c +++ b/src/runtime_io.c @@ -11,7 +11,6 @@ oc_io_cmp oc_runtime_io_wait_single_req(oc_io_req* wasmReq) { oc_runtime* orca = oc_runtime_get(); - oc_arena* scratch = oc_scratch(); oc_io_cmp cmp = { 0 }; oc_io_req req = *wasmReq; diff --git a/src/wasmbind/gles_api_bind_manual.c b/src/wasmbind/gles_api_bind_manual.c index 2edafd6..90de2c4 100644 --- a/src/wasmbind/gles_api_bind_manual.c +++ b/src/wasmbind/gles_api_bind_manual.c @@ -848,7 +848,9 @@ const void* glShaderSource_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint6 i32 lengthArrayOffset = *(i32*)&_sp[3]; int* stringOffsetArray = (int*)((char*)_mem + stringArrayOffset); - const char** stringArray = (const char**)oc_arena_push_array(oc_scratch(), char*, count); + + oc_arena_scope scratch = oc_scratch_begin(); + const char** stringArray = (const char**)oc_arena_push_array(scratch.arena, char*, count); for(int i = 0; i < count; i++) { stringArray[i] = (char*)_mem + stringOffsetArray[i]; @@ -857,6 +859,8 @@ const void* glShaderSource_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint6 int* lengthArray = lengthArrayOffset ? (int*)((char*)_mem + lengthArrayOffset) : 0; glShaderSource(shader, count, stringArray, lengthArray); + + oc_scratch_end(scratch); return (0); }