[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.";
|
"sit amet, malesuada enim. Mauris ultricies nibh orci.";
|
||||||
|
|
||||||
|
|
||||||
mg_font create_font()
|
mg_font create_font(const char* path)
|
||||||
{
|
{
|
||||||
//NOTE(martin): create font
|
//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);
|
char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath);
|
||||||
|
|
||||||
FILE* fontFile = fopen(fontPathCString, "r");
|
FILE* fontFile = fopen(fontPathCString, "r");
|
||||||
|
@ -106,15 +106,26 @@ int main()
|
||||||
//NOTE: create surface, canvas and font
|
//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_BACKEND_DEFAULT);
|
||||||
mg_surface_swap_interval(surface, 0);
|
mg_surface_swap_interval(surface, 1);
|
||||||
|
|
||||||
mg_canvas canvas = mg_canvas_create(surface);
|
mg_canvas canvas = mg_canvas_create(surface);
|
||||||
|
|
||||||
mg_font font = create_font();
|
const int fontCount = 3;
|
||||||
mg_font_extents extents = mg_font_get_extents(font);
|
int fontIndex = 0;
|
||||||
f32 fontScale = mg_font_get_scale_for_em_pixels(font, 14);
|
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));
|
int codePointCount = utf8_codepoint_count_for_string(STR8((char*)TEST_STRING));
|
||||||
u32* codePoints = malloc_array(utf32, codePointCount);
|
u32* codePoints = malloc_array(utf32, codePointCount);
|
||||||
|
@ -140,7 +151,7 @@ int main()
|
||||||
f32 zoom = 1;
|
f32 zoom = 1;
|
||||||
|
|
||||||
f32 startX = 10;
|
f32 startX = 10;
|
||||||
f32 startY = 10 + lineHeight;
|
f32 startY = 10 + lineHeights[fontIndex];
|
||||||
|
|
||||||
while(!mp_should_quit())
|
while(!mp_should_quit())
|
||||||
{
|
{
|
||||||
|
@ -188,6 +199,14 @@ int main()
|
||||||
startY = mousePos.y/zoom - trackY;
|
startY = mousePos.y/zoom - trackY;
|
||||||
} break;
|
} 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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +238,7 @@ int main()
|
||||||
mg_set_color_rgba(1, 1, 1, 1);
|
mg_set_color_rgba(1, 1, 1, 1);
|
||||||
mg_clear();
|
mg_clear();
|
||||||
|
|
||||||
mg_set_font(font);
|
mg_set_font(fonts[fontIndex]);
|
||||||
mg_set_font_size(14);
|
mg_set_font_size(14);
|
||||||
mg_set_color_rgba(0, 0, 0, 1);
|
mg_set_color_rgba(0, 0, 0, 1);
|
||||||
|
|
||||||
|
@ -239,12 +258,12 @@ int main()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 glyphs[512];
|
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_glyph_outlines((str32){subIndex, glyphs});
|
||||||
mg_fill();
|
mg_fill();
|
||||||
|
|
||||||
textY += lineHeight;
|
textY += lineHeights[fontIndex];
|
||||||
mg_move_to(textX, textY);
|
mg_move_to(textX, textY);
|
||||||
startIndex++;
|
startIndex++;
|
||||||
|
|
||||||
|
@ -254,9 +273,9 @@ int main()
|
||||||
mg_matrix_pop();
|
mg_matrix_pop();
|
||||||
|
|
||||||
mg_set_color_rgba(0, 0, 1, 1);
|
mg_set_color_rgba(0, 0, 1, 1);
|
||||||
mg_set_font(font);
|
mg_set_font(fonts[fontIndex]);
|
||||||
mg_set_font_size(14);
|
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(),
|
str8 text = str8_pushf(mem_scratch(),
|
||||||
"Test program: %i glyphs, frame time = %fs, fps = %f",
|
"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_canvas_destroy(canvas);
|
||||||
mg_surface_destroy(surface);
|
mg_surface_destroy(surface);
|
||||||
mp_window_destroy(window);
|
mp_window_destroy(window);
|
||||||
|
|
|
@ -31,6 +31,8 @@ typedef struct mg_mtl_canvas_backend
|
||||||
u32 indexBufferOffset;
|
u32 indexBufferOffset;
|
||||||
u32 shapeBufferOffset;
|
u32 shapeBufferOffset;
|
||||||
|
|
||||||
|
mg_color clearColor;
|
||||||
|
|
||||||
// permanent metal resources
|
// permanent metal resources
|
||||||
id<MTLComputePipelineState> tilingPipeline;
|
id<MTLComputePipelineState> tilingPipeline;
|
||||||
id<MTLComputePipelineState> sortingPipeline;
|
id<MTLComputePipelineState> sortingPipeline;
|
||||||
|
@ -44,7 +46,7 @@ typedef struct mg_mtl_canvas_backend
|
||||||
dispatch_semaphore_t bufferSemaphore;
|
dispatch_semaphore_t bufferSemaphore;
|
||||||
|
|
||||||
// textures and buffers
|
// textures and buffers
|
||||||
id<MTLTexture> framebuffer;
|
id<MTLTexture> backbuffer;
|
||||||
id<MTLTexture> outTexture;
|
id<MTLTexture> outTexture;
|
||||||
|
|
||||||
id<MTLBuffer> shapeBuffer[MG_MTL_MAX_BUFFERS_IN_FLIGHT];
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
backend->clearColor = clearColor;
|
||||||
|
|
||||||
backend->vertexBufferOffset = 0;
|
backend->vertexBufferOffset = 0;
|
||||||
backend->indexBufferOffset = 0;
|
backend->indexBufferOffset = 0;
|
||||||
|
@ -121,30 +124,21 @@ void mg_mtl_canvas_begin(mg_canvas_backend* interface, mg_color clearColor)
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
if(surface->commandBuffer == nil || surface->drawable == nil)
|
MTLClearColor mtlClearColor = MTLClearColorMake(clearColor.r,
|
||||||
{
|
clearColor.g,
|
||||||
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
|
clearColor.b,
|
||||||
}
|
clearColor.a);
|
||||||
if(surface->drawable != nil)
|
|
||||||
{
|
|
||||||
backend->framebuffer = surface->drawable.texture;
|
|
||||||
|
|
||||||
MTLClearColor mtlClearColor = MTLClearColorMake(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
|
||||||
|
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture;
|
renderPassDescriptor.colorAttachments[0].texture = backend->backbuffer;
|
||||||
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||||
renderPassDescriptor.colorAttachments[0].clearColor = mtlClearColor;
|
renderPassDescriptor.colorAttachments[0].clearColor = mtlClearColor;
|
||||||
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
id<MTLRenderCommandEncoder> renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||||
|
renderEncoder.label = @"clear pass";
|
||||||
[renderEncoder endEncoding];
|
[renderEncoder endEncoding];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
backend->framebuffer = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mtl_canvas_end(mg_canvas_backend* interface)
|
void mg_mtl_canvas_end(mg_canvas_backend* interface)
|
||||||
|
@ -156,6 +150,32 @@ void mg_mtl_canvas_end(mg_canvas_backend* interface)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
|
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)
|
[surface->commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer)
|
||||||
{
|
{
|
||||||
dispatch_semaphore_signal(backend->bufferSemaphore);
|
dispatch_semaphore_signal(backend->bufferSemaphore);
|
||||||
|
@ -163,6 +183,7 @@ void mg_mtl_canvas_end(mg_canvas_backend* interface)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image, u32 shapeCount, u32 vertexCount, u32 indexCount)
|
void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image, u32 shapeCount, u32 vertexCount, u32 indexCount)
|
||||||
|
@ -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_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
|
||||||
mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend);
|
mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend);
|
||||||
|
|
||||||
if(!surface || (backend->framebuffer == nil))
|
if(!surface || (backend->backbuffer == nil))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +285,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image
|
||||||
[drawEncoder endEncoding];
|
[drawEncoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): blit texture to framebuffer
|
//NOTE(martin): blit texture to backbuffer
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
MTLViewport viewport = {backend->viewPort.x * scale,
|
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};
|
1};
|
||||||
|
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
renderPassDescriptor.colorAttachments[0].texture = backend->framebuffer;
|
renderPassDescriptor.colorAttachments[0].texture = backend->backbuffer;
|
||||||
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||||
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||||
|
|
||||||
|
@ -453,6 +474,7 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
|
||||||
texDesc.height = drawableSize.height;
|
texDesc.height = drawableSize.height;
|
||||||
|
|
||||||
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
||||||
|
backend->backbuffer = [metalSurface->device newTextureWithDescriptor:texDesc];
|
||||||
//TODO(martin): retain ?
|
//TODO(martin): retain ?
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue