diff --git a/src/graphics.c b/src/graphics.c index 34ab941..c76748a 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -227,12 +227,13 @@ typedef struct mg_canvas_data //NOTE: these are used at render time mp_rect clip; mg_mat2x3 transform; + mg_mat2x3 prevTransform; //TODO: [cleanup] use only one transform + mg_image currentImage; mp_rect currentSrcRegion; vec4 shapeExtents; u32 nextShapeIndex; - u32 shapeFirstVertexIndex; u32 vertexCount; u32 indexCount; @@ -784,7 +785,8 @@ void mg_finalize_shape(mg_canvas_data* canvas) 0, srcRegion.h/destRegion.h, 0}; mg_mat2x3 userToDestRegion = {1, 0, -destRegion.x, 0, 1, -destRegion.y}; - mg_mat2x3 screenToUser = mg_mat2x3_inv(canvas->transform); + + mg_mat2x3 screenToUser = mg_mat2x3_inv(canvas->prevTransform); mg_mat2x3 uvTransform = srcRegionToTexture; uvTransform = mg_mat2x3_mul_m(uvTransform, destRegionToSrcRegion); @@ -794,7 +796,9 @@ void mg_finalize_shape(mg_canvas_data* canvas) int index = canvas->nextShapeIndex-1; mg_vertex_layout* layout = &canvas->backend->vertexLayout; *(mg_mat2x3*)(layout->uvTransformBuffer + index*layout->uvTransformStride) = uvTransform; + } + canvas->prevTransform = canvas->transform; } u32 mg_next_shape(mg_canvas_data* canvas, mg_attributes* attributes) @@ -802,11 +806,11 @@ u32 mg_next_shape(mg_canvas_data* canvas, mg_attributes* attributes) mg_finalize_shape(canvas); canvas->currentSrcRegion = attributes->srcRegion; + canvas->shapeExtents = (vec4){FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX}; mg_vertex_layout* layout = &canvas->backend->vertexLayout; int index = canvas->nextShapeIndex; canvas->nextShapeIndex++; - canvas->shapeFirstVertexIndex = canvas->vertexCount; mp_rect clip = {canvas->clip.x, canvas->clip.y, @@ -2854,7 +2858,7 @@ void mg_do_clip_push(mg_canvas_data* canvas, mp_rect clip) mg_clip_stack_push(canvas, r); } -void mg_flush_batch(mg_canvas_data* canvas, mg_image_data* image) +void mg_draw_batch(mg_canvas_data* canvas, mg_image_data* image) { mg_finalize_shape(canvas); @@ -2863,9 +2867,9 @@ void mg_flush_batch(mg_canvas_data* canvas, mg_image_data* image) canvas->backend->drawBatch(canvas->backend, image, canvas->nextShapeIndex, canvas->vertexCount, canvas->indexCount); } mg_reset_shape_index(canvas); + canvas->vertexCount = 0; canvas->indexCount = 0; - canvas->shapeFirstVertexIndex = 0; } void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt* pathElements) @@ -2898,14 +2902,13 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt mg_primitive* primitive = &(primitives[nextIndex]); nextIndex++; - canvas->transform = primitive->transform; - if(i && primitive->attributes.image.h != canvas->currentImage.h) { mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->currentImage); - mg_flush_batch(canvas, imageData); + mg_draw_batch(canvas, imageData); canvas->currentImage = primitive->attributes.image; } + canvas->transform = primitive->transform; switch(primitive->cmd) { @@ -2994,7 +2997,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt exit_command_loop: ; mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->currentImage); - mg_flush_batch(canvas, imageData); + mg_draw_batch(canvas, imageData); canvas->backend->end(canvas->backend); diff --git a/examples/image/main.c b/src/main.c similarity index 88% rename from examples/image/main.c rename to src/main.c index ff4f9a6..518ee75 100644 --- a/examples/image/main.c +++ b/src/main.c @@ -46,6 +46,10 @@ int main() mg_image image = mg_image_create_from_file(imagePath, true); vec2 imageSize = mg_image_size(image); + str8 imagePath2 = mp_app_get_resource_path(mem_scratch(), "../resources/Top512.png"); + mg_image image2 = mg_image_create_from_file(imagePath2, true); + vec2 imageSize2 = mg_image_size(image2); + // start app mp_window_bring_to_front(window); mp_window_focus(window); @@ -82,7 +86,7 @@ int main() mg_set_image(image); mg_set_image_source_region((mp_rect){500, 500, 2000, 1400}); -// mg_rectangle_fill(100, 100, imageSize.x/8, imageSize.y/8); + //mg_rectangle_fill(100, 100, imageSize.x/8, imageSize.y/8); mg_move_to(0, 0); mg_line_to(200, 0); @@ -96,6 +100,8 @@ int main() mg_matrix_pop(); + mg_image_draw(image2, (mp_rect){200, 200, 300, 300}); + mg_flush(); mg_surface_present(surface); diff --git a/src/mtl_canvas.m b/src/mtl_canvas.m index 2a43f2d..117fcd7 100644 --- a/src/mtl_canvas.m +++ b/src/mtl_canvas.m @@ -26,6 +26,9 @@ typedef struct mg_mtl_canvas_backend mg_surface surface; mg_color clearColor; + u32 vertexBufferOffset; + u32 indexBufferOffset; + u32 shapeBufferOffset; // permanent metal resources id tilingPipeline; @@ -66,8 +69,65 @@ mg_mtl_surface* mg_mtl_canvas_get_surface(mg_mtl_canvas_backend* canvas) return(res); } +void mg_mtl_canvas_update_vertex_layout(mg_mtl_canvas_backend* backend) +{ + char* vertexBase = (char*)[backend->vertexBuffer contents] + backend->vertexBufferOffset; + char* shapeBase = (char*)[backend->shapeBuffer contents] + backend->shapeBufferOffset; + char* indexBase = (char*)[backend->indexBuffer contents] + backend->indexBufferOffset; + + backend->interface.vertexLayout = (mg_vertex_layout){ + .maxVertexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH, + .maxIndexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH, + .cubicBuffer = vertexBase + offsetof(mg_vertex, cubic), + .cubicStride = sizeof(mg_vertex), + .posBuffer = vertexBase + offsetof(mg_vertex, pos), + .posStride = sizeof(mg_vertex), + .shapeIndexBuffer = vertexBase + offsetof(mg_vertex, shapeIndex), + .shapeIndexStride = sizeof(mg_vertex), + + .colorBuffer = shapeBase + offsetof(mg_shape, color), + .colorStride = sizeof(mg_shape), + .clipBuffer = shapeBase + offsetof(mg_shape, clip), + .clipStride = sizeof(mg_shape), + .uvTransformBuffer = shapeBase + offsetof(mg_shape, uvTransform), + .uvTransformStride = sizeof(mg_shape), + + .indexBuffer = indexBase, + .indexStride = sizeof(int)}; +} + void mg_mtl_canvas_begin(mg_canvas_backend* interface) -{} +{ + mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; + mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend); + if(!surface) + { + return; + } + @autoreleasepool + { + if(surface->commandBuffer == nil || surface->commandBuffer == nil) + { + mg_mtl_surface_acquire_drawable_and_command_buffer(surface); + } + + backend->vertexBufferOffset = 0; + backend->indexBufferOffset = 0; + backend->shapeBufferOffset = 0; + mg_mtl_canvas_update_vertex_layout(backend); + + MTLClearColor clearColor = MTLClearColorMake(backend->clearColor.r, backend->clearColor.g, backend->clearColor.b, backend->clearColor.a); + + MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture; + renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; + renderPassDescriptor.colorAttachments[0].clearColor = clearColor; + renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; + + id renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; + [renderEncoder endEncoding]; + } +} void mg_mtl_canvas_end(mg_canvas_backend* interface) {} @@ -90,11 +150,6 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image @autoreleasepool { - if(surface->commandBuffer == nil || surface->commandBuffer == nil) - { - mg_mtl_surface_acquire_drawable_and_command_buffer(surface); - } - ASSERT(indexCount * sizeof(i32) < [backend->indexBuffer length]); f32 scale = surface->mtlLayer.contentsScale; @@ -112,9 +167,11 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image //----------------------------------------------------------- id boxEncoder = [surface->commandBuffer computeCommandEncoder]; [boxEncoder setComputePipelineState: backend->boxingPipeline]; - [boxEncoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0]; - [boxEncoder setBuffer: backend->indexBuffer offset:0 atIndex: 1]; - [boxEncoder setBuffer: backend->shapeBuffer offset:0 atIndex: 2]; + + [boxEncoder setBuffer: backend->vertexBuffer offset:backend->vertexBufferOffset atIndex: 0]; + [boxEncoder setBuffer: backend->indexBuffer offset:backend->indexBufferOffset atIndex: 1]; + [boxEncoder setBuffer: backend->shapeBuffer offset:backend->shapeBufferOffset atIndex: 2]; + [boxEncoder setBuffer: backend->triangleArray offset:0 atIndex: 3]; [boxEncoder setBuffer: backend->boxArray offset:0 atIndex: 4]; [boxEncoder setBytes: &scale length: sizeof(float) atIndex: 5]; @@ -162,6 +219,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image //----------------------------------------------------------- //NOTE(martin): encode drawing pass //----------------------------------------------------------- + //TODO: remove that vector_float4 clearColorVec4 = {backend->clearColor.r, backend->clearColor.g, backend->clearColor.b, backend->clearColor.a}; id encoder = [surface->commandBuffer computeCommandEncoder]; @@ -175,8 +233,9 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image useTexture = 1; } - [encoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0]; - [encoder setBuffer: backend->shapeBuffer offset:0 atIndex: 1]; + [boxEncoder setBuffer: backend->vertexBuffer offset:backend->vertexBufferOffset atIndex: 0]; + [boxEncoder setBuffer: backend->shapeBuffer offset:backend->shapeBufferOffset atIndex: 1]; + [encoder setBuffer: backend->tileCounters offset:0 atIndex: 2]; [encoder setBuffer: backend->tilesArray offset:0 atIndex: 3]; [encoder setBuffer: backend->triangleArray offset:0 atIndex: 4]; @@ -194,7 +253,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image [encoder endEncoding]; //----------------------------------------------------------- - //NOTE(martin): acquire drawable, create render encoder to blit texture to framebuffer + //NOTE(martin): blit texture to framebuffer //----------------------------------------------------------- MTLViewport viewport = {backend->viewPort.x * scale, @@ -206,6 +265,7 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image 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]; @@ -217,6 +277,12 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image vertexCount: 3 ]; [renderEncoder endEncoding]; } + + backend->vertexBufferOffset += vertexCount * sizeof(mg_vertex); + backend->indexBufferOffset += indexCount * sizeof(int); + backend->shapeBufferOffset += shapeCount * sizeof(mg_shape); + + mg_mtl_canvas_update_vertex_layout(backend); } /* @@ -251,33 +317,6 @@ void mg_mtl_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort) } */ -void mg_mtl_canvas_update_vertex_layout(mg_mtl_canvas_backend* backend) -{ - char* vertexBase = (char*)[backend->vertexBuffer contents]; - char* shapeBase = (char*)[backend->shapeBuffer contents]; - char* indexBase = (char*)[backend->indexBuffer contents]; - - backend->interface.vertexLayout = (mg_vertex_layout){ - .maxVertexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH, - .maxIndexCount = MG_MTL_CANVAS_DEFAULT_BUFFER_LENGTH, - .cubicBuffer = vertexBase + offsetof(mg_vertex, cubic), - .cubicStride = sizeof(mg_vertex), - .posBuffer = vertexBase + offsetof(mg_vertex, pos), - .posStride = sizeof(mg_vertex), - .shapeIndexBuffer = vertexBase + offsetof(mg_vertex, shapeIndex), - .shapeIndexStride = sizeof(mg_vertex), - - .colorBuffer = shapeBase + offsetof(mg_shape, color), - .colorStride = sizeof(mg_shape), - .clipBuffer = shapeBase + offsetof(mg_shape, clip), - .clipStride = sizeof(mg_shape), - .uvTransformBuffer = shapeBase + offsetof(mg_shape, uvTransform), - .uvTransformStride = sizeof(mg_shape), - - .indexBuffer = indexBase, - .indexStride = sizeof(int)}; -} - void mg_mtl_canvas_destroy(mg_canvas_backend* interface) { mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; @@ -432,7 +471,6 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface) id blitEncoder = [commandBuffer blitCommandEncoder]; [blitEncoder fillBuffer: backend->tileCounters range: NSMakeRange(0, RENDERER_MAX_TILES*sizeof(uint)) value: 0]; [blitEncoder endEncoding]; - [commandBuffer commit]; //----------------------------------------------------------- //NOTE(martin): load the library @@ -499,6 +537,14 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface) pipelineStateDescriptor.vertexFunction = vertexFunction; pipelineStateDescriptor.fragmentFunction = fragmentFunction; pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalSurface->mtlLayer.pixelFormat; + pipelineStateDescriptor.colorAttachments[0].blendingEnabled = YES; + pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + + pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorZero; + pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne; // create render pipeline backend->renderPipeline = [metalSurface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err]; diff --git a/src/mtl_shader.metal b/src/mtl_shader.metal index 6c2ad0b..5de0ed6 100644 --- a/src/mtl_shader.metal +++ b/src/mtl_shader.metal @@ -23,7 +23,7 @@ vertex vs_out VertexShader(ushort vid [[vertex_id]]) fragment float4 FragmentShader(vs_out i [[stage_in]], texture2d tex [[texture(0)]]) { constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); - return(float4(tex.sample(smp, i.uv).rgb, 1)); + return(tex.sample(smp, i.uv)); } @@ -239,8 +239,8 @@ kernel void RenderKernel(texture2d outTexture [[texture(0) { zIndices[i] = -1; flipCounts[i] = 0; - pixelColors[i] = *clearColor; - nextColors[i] = *clearColor; + pixelColors[i] = float4(0, 0, 0, 0); + nextColors[i] = float4(0, 0, 0, 0); } for(uint tileBufferIndex=0; tileBufferIndex < tileBufferSize; tileBufferIndex++) @@ -340,6 +340,6 @@ kernel void RenderKernel(texture2d outTexture [[texture(0) } out += pixelColors[i]; } - out = float4(out.xyz/6, 1); + out = out/6.; outTexture.write(out, gid); }