[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:
parent
f14f397c99
commit
1d36088302
|
@ -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);
|
||||
|
|
|
@ -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 ?
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue