From 1d360883026a7b6952684976c9e9ccb66a113f93 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Thu, 16 Mar 2023 10:25:56 +0100 Subject: [PATCH] [mtl canvas] render to an intermediate texture and acquire the drawable and blit to it only at the end of all compute passes --- examples/perf_text/main.c | 50 ++++++++++++++++------- src/mtl_canvas.m | 84 ++++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 45 deletions(-) diff --git a/examples/perf_text/main.c b/examples/perf_text/main.c index 76bc57a..010e30c 100644 --- a/examples/perf_text/main.c +++ b/examples/perf_text/main.c @@ -60,10 +60,10 @@ static const char* TEST_STRING = "sit amet, malesuada enim. Mauris ultricies nibh orci."; -mg_font create_font() +mg_font create_font(const char* path) { //NOTE(martin): create font - str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf"); + str8 fontPath = mp_app_get_resource_path(mem_scratch(), path); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); @@ -106,15 +106,26 @@ int main() //NOTE: create surface, canvas and font mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); - mg_surface_swap_interval(surface, 0); + mg_surface_swap_interval(surface, 1); mg_canvas canvas = mg_canvas_create(surface); - mg_font font = create_font(); - mg_font_extents extents = mg_font_get_extents(font); - f32 fontScale = mg_font_get_scale_for_em_pixels(font, 14); + const int fontCount = 3; + int fontIndex = 0; + mg_font fonts[fontCount] = {create_font("../resources/OpenSansLatinSubset.ttf"), + create_font("../resources/CMUSerif-Roman.ttf"), + create_font("../resources/courier.ttf")}; - f32 lineHeight = fontScale*(extents.ascent + extents.descent + extents.leading); + mg_font_extents extents[fontCount]; + f32 fontScales[fontCount]; + f32 lineHeights[fontCount]; + + for(int i=0; i tilingPipeline; id sortingPipeline; @@ -44,7 +46,7 @@ typedef struct mg_mtl_canvas_backend dispatch_semaphore_t bufferSemaphore; // textures and buffers - id framebuffer; + id backbuffer; id outTexture; id shapeBuffer[MG_MTL_MAX_BUFFERS_IN_FLIGHT]; @@ -109,6 +111,7 @@ void mg_mtl_canvas_begin(mg_canvas_backend* interface, mg_color clearColor) { return; } + backend->clearColor = clearColor; backend->vertexBufferOffset = 0; backend->indexBufferOffset = 0; @@ -121,29 +124,20 @@ void mg_mtl_canvas_begin(mg_canvas_backend* interface, mg_color clearColor) @autoreleasepool { - if(surface->commandBuffer == nil || surface->drawable == nil) - { - mg_mtl_surface_acquire_drawable_and_command_buffer(surface); - } - if(surface->drawable != nil) - { - backend->framebuffer = surface->drawable.texture; + MTLClearColor mtlClearColor = MTLClearColorMake(clearColor.r, + clearColor.g, + clearColor.b, + clearColor.a); - MTLClearColor mtlClearColor = MTLClearColorMake(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + renderPassDescriptor.colorAttachments[0].texture = backend->backbuffer; + renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; + renderPassDescriptor.colorAttachments[0].clearColor = mtlClearColor; + renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; - MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; - renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture; - renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; - renderPassDescriptor.colorAttachments[0].clearColor = mtlClearColor; - renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; - - id renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; - [renderEncoder endEncoding]; - } - else - { - backend->framebuffer = nil; - } + id renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; + renderEncoder.label = @"clear pass"; + [renderEncoder endEncoding]; } } @@ -156,12 +150,39 @@ void mg_mtl_canvas_end(mg_canvas_backend* interface) { @autoreleasepool { - [surface->commandBuffer addCompletedHandler:^(id commandBuffer) - { - dispatch_semaphore_signal(backend->bufferSemaphore); - } - ]; - } + mg_mtl_surface_acquire_drawable_and_command_buffer(surface); + if(surface->drawable != nil) + { + f32 scale = surface->mtlLayer.contentsScale; + MTLViewport viewport = {backend->viewPort.x * scale, + backend->viewPort.y * scale, + backend->viewPort.w * scale, + backend->viewPort.h * scale, + 0, + 1}; + + MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture; + renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad; + renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; + + id renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; + renderEncoder.label = @"blit pass"; + [renderEncoder setViewport: viewport]; + [renderEncoder setRenderPipelineState: backend->renderPipeline]; + [renderEncoder setFragmentTexture: backend->backbuffer atIndex: 0]; + [renderEncoder drawPrimitives: MTLPrimitiveTypeTriangle + vertexStart: 0 + vertexCount: 3 ]; + [renderEncoder endEncoding]; + + [surface->commandBuffer addCompletedHandler:^(id commandBuffer) + { + dispatch_semaphore_signal(backend->bufferSemaphore); + } + ]; + } + } } } @@ -170,7 +191,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend); - if(!surface || (backend->framebuffer == nil)) + if(!surface || (backend->backbuffer == nil)) { return; } @@ -264,7 +285,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image [drawEncoder endEncoding]; //----------------------------------------------------------- - //NOTE(martin): blit texture to framebuffer + //NOTE(martin): blit texture to backbuffer //----------------------------------------------------------- MTLViewport viewport = {backend->viewPort.x * scale, @@ -275,7 +296,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image 1}; MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; - renderPassDescriptor.colorAttachments[0].texture = backend->framebuffer; + renderPassDescriptor.colorAttachments[0].texture = backend->backbuffer; renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad; renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; @@ -453,6 +474,7 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface) texDesc.height = drawableSize.height; backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc]; + backend->backbuffer = [metalSurface->device newTextureWithDescriptor:texDesc]; //TODO(martin): retain ? //-----------------------------------------------------------