[mtl canvas] render to an intermediate texture and acquire the drawable and blit to it only at the end of all compute passes

This commit is contained in:
Martin Fouilleul 2023-03-16 10:25:56 +01:00
parent f14f397c99
commit 1d36088302
2 changed files with 89 additions and 45 deletions

View File

@ -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<fontCount; i++)
{
extents[i] = mg_font_get_extents(fonts[i]);
fontScales[i] = mg_font_get_scale_for_em_pixels(fonts[i], 14);
lineHeights[i] = fontScales[i]*(extents[i].ascent + extents[i].descent + extents[i].leading);
}
int codePointCount = utf8_codepoint_count_for_string(STR8((char*)TEST_STRING));
u32* codePoints = malloc_array(utf32, codePointCount);
@ -140,7 +151,7 @@ int main()
f32 zoom = 1;
f32 startX = 10;
f32 startY = 10 + lineHeight;
f32 startY = 10 + lineHeights[fontIndex];
while(!mp_should_quit())
{
@ -188,6 +199,14 @@ int main()
startY = mousePos.y/zoom - trackY;
} break;
case MP_EVENT_KEYBOARD_KEY:
{
if(event.key.code == MP_KEY_SPACE && event.key.action == MP_KEY_PRESS)
{
fontIndex = (fontIndex+1)%fontCount;
}
} break;
default:
break;
}
@ -219,7 +238,7 @@ int main()
mg_set_color_rgba(1, 1, 1, 1);
mg_clear();
mg_set_font(font);
mg_set_font(fonts[fontIndex]);
mg_set_font_size(14);
mg_set_color_rgba(0, 0, 0, 1);
@ -239,12 +258,12 @@ int main()
}
u32 glyphs[512];
mg_font_get_glyph_indices(font, (str32){subIndex, codePoints+startIndex}, (str32){512, glyphs});
mg_font_get_glyph_indices(fonts[fontIndex], (str32){subIndex, codePoints+startIndex}, (str32){512, glyphs});
mg_glyph_outlines((str32){subIndex, glyphs});
mg_fill();
textY += lineHeight;
textY += lineHeights[fontIndex];
mg_move_to(textX, textY);
startIndex++;
@ -254,9 +273,9 @@ int main()
mg_matrix_pop();
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font(fonts[fontIndex]);
mg_set_font_size(14);
mg_move_to(10, contentRect.h - 10 - lineHeight);
mg_move_to(10, contentRect.h - 10 - lineHeights[fontIndex]);
str8 text = str8_pushf(mem_scratch(),
"Test program: %i glyphs, frame time = %fs, fps = %f",
@ -290,7 +309,10 @@ int main()
}
mg_font_destroy(font);
for(int i=0; i<fontCount; i++)
{
mg_font_destroy(fonts[i]);
}
mg_canvas_destroy(canvas);
mg_surface_destroy(surface);
mp_window_destroy(window);

View File

@ -31,6 +31,8 @@ typedef struct mg_mtl_canvas_backend
u32 indexBufferOffset;
u32 shapeBufferOffset;
mg_color clearColor;
// permanent metal resources
id<MTLComputePipelineState> tilingPipeline;
id<MTLComputePipelineState> sortingPipeline;
@ -44,7 +46,7 @@ typedef struct mg_mtl_canvas_backend
dispatch_semaphore_t bufferSemaphore;
// textures and buffers
id<MTLTexture> framebuffer;
id<MTLTexture> backbuffer;
id<MTLTexture> outTexture;
id<MTLBuffer> 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<MTLRenderCommandEncoder> renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderEncoder endEncoding];
}
else
{
backend->framebuffer = nil;
}
id<MTLRenderCommandEncoder> 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<MTLCommandBuffer> 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<MTLRenderCommandEncoder> 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<MTLCommandBuffer> 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 ?
//-----------------------------------------------------------