[canvas cleanup] cleanup canvas resources on creation failure
This commit is contained in:
parent
35e396e4c4
commit
af7cbae1fa
|
@ -77,6 +77,13 @@ int main()
|
||||||
|
|
||||||
//TODO: create canvas
|
//TODO: create canvas
|
||||||
mg_canvas canvas = mg_canvas_create(surface);
|
mg_canvas canvas = mg_canvas_create(surface);
|
||||||
|
|
||||||
|
if(mg_canvas_is_nil(canvas))
|
||||||
|
{
|
||||||
|
printf("Error: couldn't create canvas\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
mg_font font = create_font();
|
mg_font font = create_font();
|
||||||
|
|
||||||
// start app
|
// start app
|
||||||
|
|
|
@ -86,26 +86,26 @@ enum {
|
||||||
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
|
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
|
||||||
LAYOUT_UV_OFFSET = LayoutNext(CLIP, VEC4, VEC2),
|
LAYOUT_UV_OFFSET = LayoutNext(CLIP, VEC4, VEC2),
|
||||||
LAYOUT_SHAPE_ALIGN = 16,
|
LAYOUT_SHAPE_ALIGN = 16,
|
||||||
LAYOUT_SHAPE_SIZE = LayoutNext(UV, VEC2, SHAPE)
|
LAYOUT_SHAPE_SIZE = LayoutNext(UV, VEC2, SHAPE),
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
MG_GL_CANVAS_MAX_BUFFER_LENGTH = 1<<20,
|
||||||
MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH = 1<<20,
|
MG_GL_CANVAS_MAX_SHAPE_BUFFER_SIZE = LAYOUT_SHAPE_SIZE * MG_GL_CANVAS_MAX_BUFFER_LENGTH,
|
||||||
MG_GL_CANVAS_VERTEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_VERTEX_SIZE,
|
MG_GL_CANVAS_MAX_VERTEX_BUFFER_SIZE = LAYOUT_VERTEX_SIZE * MG_GL_CANVAS_MAX_BUFFER_LENGTH,
|
||||||
MG_GL_CANVAS_SHAPE_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_SHAPE_SIZE,
|
MG_GL_CANVAS_MAX_INDEX_BUFFER_SIZE = LAYOUT_INT_SIZE * MG_GL_CANVAS_MAX_BUFFER_LENGTH,
|
||||||
MG_GL_CANVAS_INDEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_INT_SIZE,
|
|
||||||
MG_GL_CANVAS_TILE_COUNTER_BUFFER_LENGTH = 65536,
|
//TODO: actually size this dynamically
|
||||||
MG_GL_CANVAS_TILE_COUNTER_BUFFER_SIZE = sizeof(int)*MG_GL_CANVAS_TILE_COUNTER_BUFFER_LENGTH,
|
MG_GL_CANVAS_MAX_TILE_COUNT = 65536, //NOTE: this allows for 256*256 tiles (e.g. 4096*4096 pixels)
|
||||||
MG_GL_CANVAS_TILE_ARRAY_LENGTH = 1<<10,
|
MG_GL_CANVAS_TILE_COUNTER_BUFFER_SIZE = LAYOUT_INT_SIZE * MG_GL_CANVAS_MAX_TILE_COUNT,
|
||||||
MG_GL_CANVAS_TILE_ARRAY_SIZE = sizeof(int)*MG_GL_CANVAS_TILE_ARRAY_LENGTH,
|
|
||||||
MG_GL_CANVAS_TILE_ARRAY_BUFFER_SIZE = MG_GL_CANVAS_TILE_COUNTER_BUFFER_LENGTH * MG_GL_CANVAS_TILE_ARRAY_SIZE,
|
MG_GL_CANVAS_TILE_ARRAY_LENGTH = 1<<10, // max overlapping triangles per tiles
|
||||||
|
MG_GL_CANVAS_TILE_ARRAY_BUFFER_SIZE = LAYOUT_INT_SIZE * MG_GL_CANVAS_MAX_TILE_COUNT * MG_GL_CANVAS_TILE_ARRAY_LENGTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend)
|
void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend)
|
||||||
{
|
{
|
||||||
backend->interface.vertexLayout = (mg_vertex_layout){
|
backend->interface.vertexLayout = (mg_vertex_layout){
|
||||||
.maxVertexCount = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
.maxVertexCount = MG_GL_CANVAS_MAX_BUFFER_LENGTH,
|
||||||
.maxIndexCount = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
.maxIndexCount = MG_GL_CANVAS_MAX_BUFFER_LENGTH,
|
||||||
.posBuffer = backend->vertexMapping + LAYOUT_POS_OFFSET,
|
.posBuffer = backend->vertexMapping + LAYOUT_POS_OFFSET,
|
||||||
.posStride = LAYOUT_VERTEX_SIZE,
|
.posStride = LAYOUT_VERTEX_SIZE,
|
||||||
.cubicBuffer = backend->vertexMapping + LAYOUT_CUBIC_OFFSET,
|
.cubicBuffer = backend->vertexMapping + LAYOUT_CUBIC_OFFSET,
|
||||||
|
@ -188,7 +188,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 v
|
||||||
const int tileSize = 16;
|
const int tileSize = 16;
|
||||||
const int tileCountX = (frame.w*contentsScaling.x + tileSize - 1)/tileSize;
|
const int tileCountX = (frame.w*contentsScaling.x + tileSize - 1)/tileSize;
|
||||||
const int tileCountY = (frame.h*contentsScaling.y + tileSize - 1)/tileSize;
|
const int tileCountY = (frame.h*contentsScaling.y + tileSize - 1)/tileSize;
|
||||||
const int tileArraySize = MG_GL_CANVAS_TILE_ARRAY_LENGTH;
|
const int tileArrayLength = MG_GL_CANVAS_TILE_ARRAY_LENGTH;
|
||||||
|
|
||||||
//TODO: ensure there's enough space in tile buffer
|
//TODO: ensure there's enough space in tile buffer
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 v
|
||||||
glUniform1ui(0, indexCount);
|
glUniform1ui(0, indexCount);
|
||||||
glUniform2ui(1, tileCountX, tileCountY);
|
glUniform2ui(1, tileCountX, tileCountY);
|
||||||
glUniform1ui(2, tileSize);
|
glUniform1ui(2, tileSize);
|
||||||
glUniform1ui(3, tileArraySize);
|
glUniform1ui(3, tileArrayLength);
|
||||||
glUniform2f(4, contentsScaling.x, contentsScaling.y);
|
glUniform2f(4, contentsScaling.x, contentsScaling.y);
|
||||||
|
|
||||||
u32 threadCount = indexCount/3;
|
u32 threadCount = indexCount/3;
|
||||||
|
@ -222,7 +222,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 v
|
||||||
glUniform1ui(0, indexCount);
|
glUniform1ui(0, indexCount);
|
||||||
glUniform2ui(1, tileCountX, tileCountY);
|
glUniform2ui(1, tileCountX, tileCountY);
|
||||||
glUniform1ui(2, tileSize);
|
glUniform1ui(2, tileSize);
|
||||||
glUniform1ui(3, tileArraySize);
|
glUniform1ui(3, tileArrayLength);
|
||||||
|
|
||||||
glDispatchCompute(tileCountX * tileCountY, 1, 1);
|
glDispatchCompute(tileCountX * tileCountY, 1, 1);
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 v
|
||||||
glUniform1ui(0, indexCount);
|
glUniform1ui(0, indexCount);
|
||||||
glUniform2ui(1, tileCountX, tileCountY);
|
glUniform2ui(1, tileCountX, tileCountY);
|
||||||
glUniform1ui(2, tileSize);
|
glUniform1ui(2, tileSize);
|
||||||
glUniform1ui(3, tileArraySize);
|
glUniform1ui(3, tileArrayLength);
|
||||||
glUniform2f(4, contentsScaling.x, contentsScaling.y);
|
glUniform2f(4, contentsScaling.x, contentsScaling.y);
|
||||||
|
|
||||||
glDispatchCompute(tileCountX, tileCountY, 1);
|
glDispatchCompute(tileCountX, tileCountY, 1);
|
||||||
|
@ -370,6 +370,9 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
|
||||||
{
|
{
|
||||||
mg_gl_canvas_backend* backend = 0;
|
mg_gl_canvas_backend* backend = 0;
|
||||||
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
if(surfaceData && surfaceData->backend == MG_BACKEND_GL)
|
if(surfaceData && surfaceData->backend == MG_BACKEND_GL)
|
||||||
{
|
{
|
||||||
mg_gl_surface* glSurface = (mg_gl_surface*)surfaceData;
|
mg_gl_surface* glSurface = (mg_gl_surface*)surfaceData;
|
||||||
|
@ -396,16 +399,8 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
||||||
|
|
||||||
glGenBuffers(1, &backend->vertexBuffer);
|
glGenBuffers(1, &backend->vertexBuffer);
|
||||||
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);
|
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);
|
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);
|
|
||||||
|
|
||||||
glGenBuffers(1, &backend->tileCounterBuffer);
|
glGenBuffers(1, &backend->tileCounterBuffer);
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileCounterBuffer);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileCounterBuffer);
|
||||||
|
@ -425,18 +420,41 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
//NOTE: create programs
|
//NOTE: create programs
|
||||||
mg_gl_canvas_compile_compute_program(glsl_clear_counters, &backend->clearCounterProgram);
|
err |= mg_gl_canvas_compile_compute_program(glsl_clear_counters, &backend->clearCounterProgram);
|
||||||
mg_gl_canvas_compile_compute_program(glsl_tile, &backend->tileProgram);
|
err |= mg_gl_canvas_compile_compute_program(glsl_tile, &backend->tileProgram);
|
||||||
mg_gl_canvas_compile_compute_program(glsl_sort, &backend->sortProgram);
|
err |= mg_gl_canvas_compile_compute_program(glsl_sort, &backend->sortProgram);
|
||||||
mg_gl_canvas_compile_compute_program(glsl_draw, &backend->drawProgram);
|
err |= mg_gl_canvas_compile_compute_program(glsl_draw, &backend->drawProgram);
|
||||||
mg_gl_canvas_compile_render_program("blit", glsl_blit_vertex, glsl_blit_fragment, &backend->blitProgram);
|
err |= mg_gl_canvas_compile_render_program("blit", glsl_blit_vertex, glsl_blit_fragment, &backend->blitProgram);
|
||||||
|
|
||||||
backend->vertexMapping = malloc_array(char, 1<<30);
|
if(glGetError() != GL_NO_ERROR)
|
||||||
backend->shapeMapping = malloc_array(char, 1<<30);
|
{
|
||||||
backend->indexMapping = malloc_array(char, 1<<30);
|
err |= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
backend->shapeMapping = malloc_array(char, MG_GL_CANVAS_MAX_SHAPE_BUFFER_SIZE);
|
||||||
|
backend->vertexMapping = malloc_array(char, MG_GL_CANVAS_MAX_VERTEX_BUFFER_SIZE);
|
||||||
|
backend->indexMapping = malloc_array(char, MG_GL_CANVAS_MAX_INDEX_BUFFER_SIZE);
|
||||||
|
|
||||||
|
if( !backend->shapeMapping
|
||||||
|
|| !backend->shapeMapping
|
||||||
|
|| !backend->shapeMapping)
|
||||||
|
{
|
||||||
|
err |= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
free(backend->shapeMapping);
|
||||||
|
free(backend->vertexMapping);
|
||||||
|
free(backend->indexMapping);
|
||||||
|
free(backend);
|
||||||
|
backend = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mg_gl_canvas_update_vertex_layout(backend);
|
mg_gl_canvas_update_vertex_layout(backend);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return((mg_canvas_backend*)backend);
|
return((mg_canvas_backend*)backend);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,8 @@ typedef struct mg_text_extents
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
//NOTE(martin): graphics canvas
|
//NOTE(martin): graphics canvas
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
|
mg_canvas mg_canvas_nil();
|
||||||
|
bool mg_canvas_is_nil(mg_canvas canvas);
|
||||||
|
|
||||||
mg_canvas mg_canvas_create(mg_surface surface);
|
mg_canvas mg_canvas_create(mg_surface surface);
|
||||||
void mg_canvas_destroy(mg_canvas canvas);
|
void mg_canvas_destroy(mg_canvas canvas);
|
||||||
|
|
21
todo.txt
21
todo.txt
|
@ -16,27 +16,30 @@ Overview
|
||||||
|
|
||||||
Clean+Fixes
|
Clean+Fixes
|
||||||
-----------
|
-----------
|
||||||
[.] Clean canvas code
|
|
||||||
[x] rename zIndex with "shapeIndex" everywhere
|
|
||||||
[x] make shapeIndex implicit when calling push_vertex
|
|
||||||
[x] remove color args in functions that don't need it anymore
|
|
||||||
[x] remove or rename "_with_zindex" functions
|
|
||||||
|
|
||||||
[ ] Rename MG_GL_CANVAS_TILE_ARRAY_SIZE/LENGTH unambiguously and make it consistent between C and glsl code
|
[x] Rename MG_GL_CANVAS_TILE_ARRAY_SIZE/LENGTH unambiguously and make it consistent between C and glsl code
|
||||||
|
|
||||||
[.] Clean shaders (folder/filenames, version string, debug flags, ...)
|
[.] Clean shaders (folder/filenames, version string, debug flags, ...)
|
||||||
[x] Simplify shader names, prefix embedded strings by "glsl_"
|
[x] Simplify shader names, prefix embedded strings by "glsl_"
|
||||||
[x] Extract shader compilation in a function
|
[x] Extract shader compilation in a function
|
||||||
[x] Add version strings/common structs in canvas code (maybe revisit later when we have multiple versions, but ok for now)
|
[x] Add version strings/common structs in canvas code (maybe revisit later when we have multiple versions, but ok for now)
|
||||||
[!] Check return of compilation and decide how to handle error more cleanly
|
[x] Check return of compilation. If failed, cleanup and return NULL backend
|
||||||
|
|
||||||
[!] Clean-up context on error and set error flags in handle
|
[x] Clean-up context on error and return nil handle
|
||||||
|
[/] Could return non-nil "invalid" handle and set error flags in handle
|
||||||
|
|
||||||
|
[>] Make surface backend and canvas backend compile-time and run-time selections easier
|
||||||
|
|
||||||
[ ] Make surface backend and canvas backend compile-time and run-time selections easier
|
|
||||||
[ ] GL loader: allow using different GL versions (eg using a desktop GL surface and a GLES surface in the same app).
|
[ ] GL loader: allow using different GL versions (eg using a desktop GL surface and a GLES surface in the same app).
|
||||||
|
[ ] Allow selection different versions of GL/GLES
|
||||||
|
|
||||||
|
[!] Decide what to do when user exceeds the limit of triangles
|
||||||
|
[?] Size tile arrays dynamically when canvas size changes?
|
||||||
|
|
||||||
Bug hunt
|
Bug hunt
|
||||||
--------
|
--------
|
||||||
|
[!] Check if very slow shader can crash the driver and what we might to to prevent that (eg waiting for compute to finish before blit? because slow compute shader should certainly _not_ crash?) or break shader invocation into multiple passes when there's a lot of tiles/triangles
|
||||||
|
|
||||||
[!] Investigate artifact when shifting positions of vertices by (0.5, 0.5) before multiplying
|
[!] Investigate artifact when shifting positions of vertices by (0.5, 0.5) before multiplying
|
||||||
by subpixel precision and truncating... -> ie sampling at the middle of pixels vs at integer coordinates...
|
by subpixel precision and truncating... -> ie sampling at the middle of pixels vs at integer coordinates...
|
||||||
> seems to happen on tile boundaries
|
> seems to happen on tile boundaries
|
||||||
|
|
Loading…
Reference in New Issue