[canvas]
- Clear final surface to clear color, and enable blending layers onto it - Fixed Batching bug where we were writing to vertex/shape buffers while the previous batch is using them - Fixed bug where uvTransform uses transform of next shape instead of that of shape being finalized
This commit is contained in:
parent
e66932e624
commit
9ed630fc55
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
126
src/mtl_canvas.m
126
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<MTLComputePipelineState> 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<MTLRenderCommandEncoder> 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<MTLComputeCommandEncoder> 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<MTLComputeCommandEncoder> 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<MTLRenderCommandEncoder> 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<MTLBlitCommandEncoder> 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];
|
||||
|
|
|
@ -23,7 +23,7 @@ vertex vs_out VertexShader(ushort vid [[vertex_id]])
|
|||
fragment float4 FragmentShader(vs_out i [[stage_in]], texture2d<float> 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<float, access::write> 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<float, access::write> outTexture [[texture(0)
|
|||
}
|
||||
out += pixelColors[i];
|
||||
}
|
||||
out = float4(out.xyz/6, 1);
|
||||
out = out/6.;
|
||||
outTexture.write(out, gid);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue