opengl canvas renderer: splitting vertex data and shape data

This commit is contained in:
martinfouilleul 2023-02-07 18:59:51 +01:00
parent f0bc88c4fb
commit 2419ab7889
9 changed files with 162 additions and 149 deletions

View File

@ -80,7 +80,6 @@ int main()
f32 x = 400, y = 300;
f32 dx = 5, dy = 5;
// f32 dx = 0, dy = 0;
f64 frameTime = 0;
@ -168,7 +167,6 @@ int main()
mg_circle_fill(x, y, 200);
// smile
f32 frown = frameTime > 0.033 ? 100 : 0;
mg_set_color_rgba(0, 0, 0, 1);
@ -183,7 +181,6 @@ int main()
mg_ellipse_fill(x+70, y+50, 30, 50);
// text
//*
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font_size(12);
@ -195,7 +192,6 @@ int main()
1./frameTime);
mg_text_outlines(text);
mg_fill();
//*/
printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n",
frameTime,

View File

@ -19,6 +19,7 @@ typedef struct mg_gl_canvas_backend
GLint dummyVertexBuffer;
GLint vertexBuffer;
GLint shapeBuffer;
GLint indexBuffer;
GLint tileCounterBuffer;
GLint tileArrayBuffer;
@ -32,6 +33,7 @@ typedef struct mg_gl_canvas_backend
char* indexMapping;
char* vertexMapping;
char* shapeMapping;
} mg_gl_canvas_backend;
@ -49,15 +51,19 @@ mg_gl_surface* mg_gl_canvas_get_surface(mg_gl_canvas_backend* canvas)
//NOTE: debugger
typedef struct debug_vertex
{
vec2 pos;
vec2 uv;
vec4 cubic;
vec4 color;
vec4 clip;
vec2 pos;
int zIndex;
u8 align2[12];
u8 pad[4];
} debug_vertex;
typedef struct debug_shape
{
vec4 color;
vec4 clip;
vec2 uv;
u8 pad[8];
} debug_shape;
#define LayoutNext(prevName, prevType, nextType) \
AlignUpOnPow2(_cat3_(LAYOUT_, prevName, _OFFSET)+_cat3_(LAYOUT_, prevType, _SIZE), _cat3_(LAYOUT_, nextType, _ALIGN))
@ -70,20 +76,23 @@ enum {
LAYOUT_INT_SIZE = 4,
LAYOUT_INT_ALIGN = 4,
LAYOUT_POS_OFFSET = 0,
LAYOUT_UV_OFFSET = LayoutNext(POS, VEC2, VEC2),
LAYOUT_CUBIC_OFFSET = LayoutNext(UV, VEC2, VEC4),
LAYOUT_COLOR_OFFSET = LayoutNext(CUBIC, VEC4, VEC4),
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
LAYOUT_ZINDEX_OFFSET = LayoutNext(CLIP, VEC4, INT),
LAYOUT_CUBIC_OFFSET = 0,
LAYOUT_POS_OFFSET = LayoutNext(CUBIC, VEC4, VEC2),
LAYOUT_ZINDEX_OFFSET = LayoutNext(POS, VEC2, INT),
LAYOUT_VERTEX_ALIGN = 16,
LAYOUT_VERTEX_SIZE = LayoutNext(ZINDEX, INT, VERTEX),
LAYOUT_COLOR_OFFSET = 0,
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
LAYOUT_UV_OFFSET = LayoutNext(CLIP, VEC4, VEC2),
LAYOUT_SHAPE_ALIGN = 16,
LAYOUT_SHAPE_SIZE = LayoutNext(UV, VEC2, SHAPE)
};
enum {
MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH = 1<<20,
MG_GL_CANVAS_VERTEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_VERTEX_SIZE,
MG_GL_CANVAS_SHAPE_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_SHAPE_SIZE,
MG_GL_CANVAS_INDEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_INT_SIZE,
MG_GL_CANVAS_TILE_COUNTER_BUFFER_SIZE = 65536,
MG_GL_CANVAS_TILE_ARRAY_SIZE = sizeof(int)*4096,
@ -99,23 +108,28 @@ void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend)
.posStride = LAYOUT_VERTEX_SIZE,
.cubicBuffer = backend->vertexMapping + LAYOUT_CUBIC_OFFSET,
.cubicStride = LAYOUT_VERTEX_SIZE,
.uvBuffer = backend->vertexMapping + LAYOUT_UV_OFFSET,
.uvStride = LAYOUT_VERTEX_SIZE,
.colorBuffer = backend->vertexMapping + LAYOUT_COLOR_OFFSET,
.colorStride = LAYOUT_VERTEX_SIZE,
.clipBuffer = backend->vertexMapping + LAYOUT_CLIP_OFFSET,
.clipStride = LAYOUT_VERTEX_SIZE,
.zIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET,
.zIndexStride = LAYOUT_VERTEX_SIZE,
.colorBuffer = backend->shapeMapping + LAYOUT_COLOR_OFFSET,
.colorStride = LAYOUT_SHAPE_SIZE,
.clipBuffer = backend->shapeMapping + LAYOUT_CLIP_OFFSET,
.clipStride = LAYOUT_SHAPE_SIZE,
.uvBuffer = backend->shapeMapping + LAYOUT_UV_OFFSET,
.uvStride = LAYOUT_SHAPE_SIZE,
.indexBuffer = backend->indexMapping,
.indexStride = LAYOUT_INT_SIZE};
}
void mg_gl_send_buffers(mg_gl_canvas_backend* backend, int vertexCount, int indexCount)
void mg_gl_send_buffers(mg_gl_canvas_backend* backend, int shapeCount, int vertexCount, int indexCount)
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_VERTEX_SIZE*vertexCount, backend->vertexMapping, GL_STREAM_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->shapeBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_SHAPE_SIZE*shapeCount, backend->shapeMapping, GL_STREAM_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_INT_SIZE*indexCount, backend->indexMapping, GL_STREAM_DRAW);
}
@ -150,7 +164,7 @@ void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
glClear(GL_COLOR_BUFFER_BIT);
}
void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount)
void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 vertexCount, u32 indexCount)
{
mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface;
mg_gl_surface* surface = mg_gl_canvas_get_surface(backend);
@ -161,9 +175,10 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32
/*NOTE: if we want debug_vertex while debugging, the following ensures the struct def doesn't get stripped away
debug_vertex vertex;
printf("foo %p\n", &vertex);
debug_shape shape;
printf("foo %p, bar %p\n", &vertex, &shape);
//*/
mg_gl_send_buffers(backend, vertexCount, indexCount);
mg_gl_send_buffers(backend, shapeCount, vertexCount, indexCount);
mp_rect frame = mg_surface_get_frame(backend->surface);
@ -184,9 +199,10 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32
glUseProgram(backend->tileProgram);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->shapeBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->indexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileCounterBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, backend->tileArrayBuffer);
glUniform1ui(0, indexCount);
glUniform2ui(1, tileCountX, tileCountY);
@ -198,12 +214,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32
//NOTE: next we sort triangles in each tile
glUseProgram(backend->sortProgram);
/*
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
*/
glUniform1ui(0, indexCount);
glUniform2ui(1, tileCountX, tileCountY);
glUniform1ui(2, tileSize);
@ -211,16 +222,9 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32
glDispatchCompute(tileCountX * tileCountY, 1, 1);
//TODO: then we fire the fragment shader that will select only triangles in its tile
// glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
//NOTE: then we fire the fragment shader that will select only triangles in its tile
glUseProgram(backend->drawProgram);
/*
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
*/
glBindImageTexture(0, backend->outTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
glUniform1ui(0, indexCount);
@ -309,6 +313,10 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GL_CANVAS_VERTEX_BUFFER_SIZE, 0, GL_STREAM_DRAW);
glGenBuffers(1, &backend->shapeBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->shapeBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GL_CANVAS_SHAPE_BUFFER_SIZE, 0, GL_STREAM_DRAW);
glGenBuffers(1, &backend->indexBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GL_CANVAS_INDEX_BUFFER_SIZE, 0, GL_STREAM_DRAW);
@ -440,6 +448,7 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
}
backend->vertexMapping = malloc_array(char, 1<<30);
backend->shapeMapping = malloc_array(char, 1<<30);
backend->indexMapping = malloc_array(char, 1<<30);
mg_gl_canvas_update_vertex_layout(backend);

View File

@ -7,27 +7,34 @@ precision mediump float;
layout(std430) buffer;
struct vertex {
vec2 pos;
vec2 uv;
vec4 cubic;
vec2 pos;
int zIndex;
};
struct shape {
vec4 color;
vec4 clip;
int zIndex;
vec2 uv;
};
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer indexBufferSSBO {
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 2) restrict readonly buffer tileCounterBufferSSBO {
layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 3) restrict readonly buffer tileArrayBufferSSBO {
layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
@ -130,7 +137,7 @@ void main()
ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5));
int zIndex = vertexBuffer.elements[i0].zIndex;
vec4 color = vertexBuffer.elements[i0].color;
vec4 color = shapeBuffer.elements[zIndex].color;
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;

View File

@ -5,27 +5,34 @@ precision mediump float;
layout(std430) buffer;
struct vertex {
vec2 pos;
vec2 uv;
vec4 cubic;
vec2 pos;
int zIndex;
};
struct shape {
vec4 color;
vec4 clip;
int zIndex;
vec2 uv;
};
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer indexBufferSSBO {
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 2) coherent readonly restrict buffer tileCounterBufferSSBO {
layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 3) coherent restrict buffer tileArrayBufferSSBO {
layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;

View File

@ -5,27 +5,34 @@ precision mediump float;
layout(std430) buffer;
struct vertex {
vec2 pos;
vec2 uv;
vec4 cubic;
vec2 pos;
int zIndex;
};
struct shape {
vec4 color;
vec4 clip;
int zIndex;
vec2 uv;
};
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer indexBufferSSBO {
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 2) coherent restrict buffer tileCounterBufferSSBO {
layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 3) coherent restrict writeonly buffer tileArrayBufferSSBO {
layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;

View File

@ -422,22 +422,38 @@ void mg_path_push_element(mg_canvas_data* canvas, mg_path_elt elt)
mg_path_push_elements(canvas, 1, &elt);
}
/////////////////////////////////////// WIP /////////////////////////////////////////////////////////////////////////
void mg_reset_z_index(mg_canvas_data* canvas)
{
canvas->nextZIndex = 1;
}
u32 mg_get_next_z_index(mg_canvas_data* canvas)
u32 mg_next_shape_textured(mg_canvas_data* canvas, vec2 uv, mg_color color)
{
return(canvas->nextZIndex++);
//TODO: push color, uv, clip
int index = canvas->nextZIndex;
canvas->nextZIndex++;
mg_vertex_layout* layout = &canvas->backend->vertexLayout;
*(vec2*)(((char*)layout->uvBuffer) + index*layout->uvStride) = uv;
*(mg_color*)(((char*)layout->colorBuffer) + index*layout->colorStride) = color;
*(mp_rect*)(((char*)layout->clipBuffer) + index*layout->clipStride) = canvas->clip;
return(index);
}
/////////////////////////////////////// WIP /////////////////////////////////////////////////////////////////////////
u32 mg_next_shape(mg_canvas_data* canvas, mg_color color)
{
return(mg_next_shape_textured(canvas, (vec2){0, 0}, color));
}
//TODO(martin): rename with something more explicit
u32 mg_vertices_base_index(mg_canvas_data* canvas)
{
return(canvas->batchBaseIndex + canvas->vertexCount);
return(canvas->vertexCount);
}
int* mg_reserve_indices(mg_canvas_data* canvas, u32 indexCount)
@ -452,29 +468,19 @@ int* mg_reserve_indices(mg_canvas_data* canvas, u32 indexCount)
return(base);
}
void mg_push_textured_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, vec2 uv, mg_color color, u64 zIndex)
void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 zIndex)
{
mg_vertex_layout* layout = &canvas->backend->vertexLayout;
DEBUG_ASSERT(canvas->vertexCount < layout->maxVertexCount);
u32 offset = canvas->vertexCount;
*(vec2*)(((char*)layout->posBuffer) + offset*layout->posStride) = pos;
*(vec4*)(((char*)layout->cubicBuffer) + offset*layout->cubicStride) = cubic;
*(vec2*)(((char*)layout->uvBuffer) + offset*layout->uvStride) = uv;
*(mg_color*)(((char*)layout->colorBuffer) + offset*layout->colorStride) = color;
*(u32*)(((char*)layout->zIndexBuffer) + offset*layout->zIndexStride) = zIndex;
*(mp_rect*)(((char*)layout->clipBuffer) + offset*layout->clipStride) = canvas->clip;
canvas->vertexCount++;
}
void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, mg_color color, u64 zIndex)
{
mg_push_textured_vertex(canvas, pos, cubic, (vec2){0, 0}, color, zIndex);
}
//-----------------------------------------------------------------------------------------------------------
// Path Filling
//-----------------------------------------------------------------------------------------------------------
@ -492,19 +498,16 @@ void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x, p[0].y}),
(vec4){0, 0, 0, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x, p[1].y}),
(vec4){0.5, 0, 0.5, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[2].x, p[2].y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
indices[0] = baseIndex + 0;
@ -549,19 +552,16 @@ void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x, p[0].y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){split.x, split.y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[3].x, p[3].y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
indices[0] = baseIndex + 0;
@ -931,7 +931,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
vec2 pos = mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[i]]);
vec4 cubic = testCoords[orderedHullIndices[i]];
cubic.w = outsideTest;
mg_push_vertex(canvas, pos, cubic, color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
indices[i] = baseIndex + i;
}
@ -961,37 +961,31 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[0]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[0]]), outsideTest1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[1]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[1]]), outsideTest1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[0]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[0]]), outsideTest2},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest2},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[3]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[3]]), outsideTest2},
color,
zIndex);
indices[0] = baseIndex + 0;
@ -1018,7 +1012,6 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[i]]),
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[i]]), outsideTest},
color,
zIndex);
}
@ -1088,7 +1081,7 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr
for(int i=0; i<3; i++)
{
mg_push_vertex(canvas, pos[i], cubic, color, zIndex);
mg_push_vertex(canvas, pos[i], cubic, zIndex);
indices[i] = baseIndex + i;
}
@ -1120,25 +1113,21 @@ void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 zIndex, mg_att
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x + n0.x, p[0].y + n0.y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x + n0.x, p[1].y + n0.y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x - n0.x, p[1].y - n0.y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x - n0.x, p[0].y - n0.y}),
(vec4){1, 1, 1, 1},
color,
zIndex);
indices[0] = baseIndex;
@ -1326,7 +1315,7 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
{
//NOTE(martin): push the actual fill commands for the offset contour
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_fill_quadratic(canvas, positiveOffsetHull, zIndex, attributes->color);
mg_render_fill_quadratic(canvas, negativeOffsetHull, zIndex, attributes->color);
@ -1338,25 +1327,21 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[0]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[2]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[2]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
indices[0] = baseIndex + 0;
@ -1485,7 +1470,7 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
else
{
//NOTE(martin): push the actual fill commands for the offset contour
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color);
mg_render_fill_cubic(canvas, negativeOffsetHull, zIndex, attributes->color);
@ -1498,25 +1483,21 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[0]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[3]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[3]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
indices[0] = baseIndex + 0;
@ -1542,7 +1523,7 @@ void mg_stroke_cap(mg_canvas_data* canvas, vec2 p0, vec2 direction, mg_attribute
vec2 m0 = {alpha*direction.x,
alpha*direction.y};
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
u32 baseIndex = mg_vertices_base_index(canvas);
i32* indices = mg_reserve_indices(canvas, 6);
@ -1550,25 +1531,21 @@ void mg_stroke_cap(mg_canvas_data* canvas, vec2 p0, vec2 direction, mg_attribute
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x, p0.y + n0.y}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x + m0.x, p0.y + n0.y + m0.y}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x - n0.x + m0.x, p0.y - n0.y + m0.y}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x - n0.x, p0.y - n0.y}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
indices[0] = baseIndex;
@ -1608,7 +1585,7 @@ void mg_stroke_joint(mg_canvas_data* canvas,
n1.y *= -1;
}
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
//NOTE(martin): use the same code as hull offset to find mitter point...
/*NOTE(martin): let vector u = (n0+n1) and vector v = pIntersect - p1
@ -1634,25 +1611,21 @@ void mg_stroke_joint(mg_canvas_data* canvas,
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p0),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x*halfW, p0.y + n0.y*halfW}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, mitterPoint),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n1.x*halfW, p0.y + n1.y*halfW}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
indices[0] = baseIndex;
@ -1671,19 +1644,16 @@ void mg_stroke_joint(mg_canvas_data* canvas,
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, p0),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x*halfW, p0.y + n0.y*halfW}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
mg_push_vertex(canvas,
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n1.x*halfW, p0.y + n1.y*halfW}),
(vec4){1, 1, 1, 1},
attributes->color,
zIndex);
DEBUG_ASSERT(!isnan(n0.x) && !isnan(n0.y) && !isnan(n1.x) && !isnan(n1.y));
@ -1704,7 +1674,7 @@ void mg_render_stroke_element(mg_canvas_data* canvas,
{
vec2 controlPoints[4] = {currentPoint, element->p[0], element->p[1], element->p[2]};
int endPointIndex = 0;
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
switch(element->type)
{
@ -1837,7 +1807,7 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute
u32 baseIndex = mg_vertices_base_index(canvas);
i32* indices = mg_reserve_indices(canvas, 6);
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
vec2 points[4] = {{rect.x, rect.y},
{rect.x + rect.w, rect.y},
@ -1848,7 +1818,7 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute
for(int i=0; i<4; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
mg_push_vertex(canvas, pos, cubic, attributes->color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
}
indices[0] = baseIndex + 0;
indices[1] = baseIndex + 1;
@ -1864,7 +1834,7 @@ void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribu
u32 baseIndex = mg_vertices_base_index(canvas);
i32* indices = mg_reserve_indices(canvas, 12);
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
//NOTE(martin): limit stroke width to the minimum dimension of the rectangle
f32 width = minimum(attributes->width, minimum(rect.w, rect.h));
@ -1884,13 +1854,13 @@ void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribu
for(int i=0; i<4; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, outerPoints[i]);
mg_push_vertex(canvas, pos, cubic, attributes->color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
}
for(int i=0; i<4; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, innerPoints[i]);
mg_push_vertex(canvas, pos, cubic, attributes->color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
}
indices[0] = baseIndex + 0;
@ -1929,7 +1899,7 @@ void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32
for(int i=0; i<4; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
mg_push_vertex(canvas, pos, cubics[i], color, zIndex);
mg_push_vertex(canvas, pos, cubics[i], zIndex);
}
indices[0] = baseIndex + 0;
indices[1] = baseIndex + 1;
@ -1965,7 +1935,7 @@ void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas,
for(int i=0; i<8; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
mg_push_vertex(canvas, pos, cubic, attributes->color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
}
static const i32 fanIndices[18] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7 }; // inner fan
@ -1985,7 +1955,7 @@ void mg_render_rounded_rectangle_fill(mg_canvas_data* canvas,
mg_rounded_rect rect,
mg_attributes* attributes)
{
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_rounded_rectangle_fill_with_z_index(canvas, rect, attributes, zIndex);
}
@ -2000,7 +1970,7 @@ void mg_render_rounded_rectangle_stroke(mg_canvas_data* canvas,
mg_rounded_rect inner = {rect.x + halfW, rect.y + halfW, rect.w - width, rect.h - width, rect.r - halfW};
mg_rounded_rect outer = {rect.x - halfW, rect.y - halfW, rect.w + width, rect.h + width, rect.r + halfW};
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_rounded_rectangle_fill_with_z_index(canvas, outer, attributes, zIndex);
mg_render_rounded_rectangle_fill_with_z_index(canvas, inner, attributes, zIndex);
}
@ -2029,7 +1999,7 @@ void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas,
for(int i=0; i<4; i++)
{
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
mg_push_vertex(canvas, pos, cubic, attributes->color, zIndex);
mg_push_vertex(canvas, pos, cubic, zIndex);
}
indices[0] = baseIndex + 0;
@ -2047,7 +2017,7 @@ void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas,
void mg_render_ellipse_fill(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes)
{
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_ellipse_fill_with_z_index(canvas, rect, attributes, zIndex);
}
@ -2060,13 +2030,15 @@ void mg_render_ellipse_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribute
mp_rect inner = {rect.x + halfW, rect.y + halfW, rect.w - width, rect.h - width};
mp_rect outer = {rect.x - halfW, rect.y - halfW, rect.w + width, rect.h + width};
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
mg_render_ellipse_fill_with_z_index(canvas, outer, attributes, zIndex);
mg_render_ellipse_fill_with_z_index(canvas, inner, attributes, zIndex);
}
void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
{
//TODO
/*
mg_image_data* imageData = mg_image_ptr_from_handle(canvas, image);
if(!imageData)
{
@ -2076,7 +2048,7 @@ void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
u32 baseIndex = mg_vertices_base_index(canvas);
i32* indices = mg_reserve_indices(canvas, 6);
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, attributes->color);
vec2 points[4] = {{rect.x, rect.y},
{rect.x + rect.w, rect.y},
@ -2104,10 +2076,13 @@ void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
indices[3] = baseIndex + 0;
indices[4] = baseIndex + 2;
indices[5] = baseIndex + 3;
*/
}
void mg_render_rounded_image(mg_canvas_data* canvas, mg_image image, mg_rounded_rect rect, mg_attributes* attributes)
{
//TODO
/*
mg_image_data* imageData = mg_image_ptr_from_handle(canvas, image);
if(!imageData)
{
@ -2148,7 +2123,7 @@ void mg_render_rounded_image(mg_canvas_data* canvas, mg_image image, mg_rounded_
*uv = mappedUV;
}
*/
}
//------------------------------------------------------------------------------------------
@ -2817,10 +2792,9 @@ void mg_flush_batch(mg_canvas_data* canvas)
{
if(canvas->backend && canvas->backend->drawBatch)
{
canvas->backend->drawBatch(canvas->backend, canvas->vertexCount, canvas->indexCount);
canvas->backend->drawBatch(canvas->backend, canvas->nextZIndex, canvas->vertexCount, canvas->indexCount);
}
canvas->batchBaseIndex += canvas->vertexCount;
mg_reset_z_index(canvas);
canvas->vertexCount = 0;
canvas->indexCount = 0;
}
@ -2871,14 +2845,13 @@ void mg_flush()
//NOTE(martin): clear buffers
canvas->vertexCount = 0;
canvas->indexCount = 0;
canvas->batchBaseIndex = 0;
canvas->backend->clear(canvas->backend, primitive->attributes.color);
} break;
case MG_CMD_FILL:
{
u32 zIndex = mg_get_next_z_index(canvas);
u32 zIndex = mg_next_shape(canvas, primitive->attributes.color);
mg_render_fill(canvas,
canvas->pathElements + primitive->path.startIndex,
&primitive->path,

View File

@ -225,7 +225,7 @@ typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor);
typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend, u32 vertexCount, u32 indexCount);
typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend, u32 vertexCount, u32 shapeCount, u32 indexCount);
typedef void (*mg_canvas_backend_atlas_upload_proc)(mg_canvas_backend* backend, mp_rect rect, u8* bytes);
typedef struct mg_canvas_backend
@ -270,7 +270,6 @@ typedef struct mg_canvas_data
u32 vertexCount;
u32 indexCount;
u32 batchBaseIndex;
mg_image_data images[MG_IMAGE_MAX_COUNT];
u32 imageNextIndex;

View File

@ -1,8 +1,21 @@
WIP
---
[ ] Split vertex data into per-vertex and per-shape data. Keep only pos, cubics, and shapeID in vertex data
[?] use half-floats or short fixed-point for pos and uv, packing them in two ints
Canvas renderer perf
--------------------
[.] Perf
[x] Split vertex data into per-vertex and per-shape data. Keep only pos, cubics, and shapeID in vertex data
[>] make zIndex implicit when calling push_vertex
[>] rename zIndex with "shapeIndex" everywhere
[>] remove color args in functions that don't need it anymore
[?] use half-floats or short fixed-point for pos and uv, packing them in two ints
[?] pre-compute triangle edges/bounding boxes?
[ ] Use clip rects
[ ] Clean shaders (folder/filenames, version string, debug flags, ...)
[ ] Correctly handle surface size
[ ] Add surface scaling for high dpi surfaces
[ ] Allow setting swap interval
-----------
[.] Check changes in macos version

View File

@ -92,3 +92,5 @@ Quick measurement on perf_text.exe
-> Stutter is with GL_MAP_INVALIDATE_BUFFER_BIT isn't reassuring. Stick to glBufferData for now.
-> May be worth it to try persistently mapped buffers later.
* Splitting vertex data and shape data (using glBufferData) --> ~10ms