From 4e816a838bd8a3102722bd4a6ea60f9b0348283e Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Thu, 9 Feb 2023 16:14:15 +0100 Subject: [PATCH] [Clean canvas/shaders] - Simplified shader names, prefix embedded strings by "glsl_" - Extracted shader compilation in common function - Add shader version string and common structs in canvas code rather than in every shader file - Renamed zIndex with shapeIndex everywhere --- build.bat | 5 +- scripts/embed_text.py | 3 +- src/gl_canvas.c | 223 ++++----- src/gles_canvas.c | 451 ------------------ src/glsl_shaders.h | 441 +++++++++++++++++ .../blit_fragment.glsl} | 1 - .../blit_vertex.glsl} | 1 - .../clear_counters.glsl} | 2 +- src/glsl_shaders/common.glsl | 14 + .../draw.glsl} | 30 +- .../sort.glsl} | 43 +- .../tile.glsl} | 17 +- src/graphics.c | 236 ++++----- src/graphics_internal.h | 6 +- todo.txt | 20 +- 15 files changed, 713 insertions(+), 780 deletions(-) delete mode 100644 src/gles_canvas.c create mode 100644 src/glsl_shaders.h rename src/{gles_canvas_shaders/gles_canvas_blit_fragment.glsl => glsl_shaders/blit_fragment.glsl} (85%) rename src/{gles_canvas_shaders/gles_canvas_blit_vertex.glsl => glsl_shaders/blit_vertex.glsl} (90%) rename src/{gles_canvas_shaders/gles_canvas_clear_counters.glsl => glsl_shaders/clear_counters.glsl} (92%) create mode 100644 src/glsl_shaders/common.glsl rename src/{gles_canvas_shaders/gles_canvas_draw.glsl => glsl_shaders/draw.glsl} (89%) rename src/{gles_canvas_shaders/gles_canvas_sort.glsl => glsl_shaders/sort.glsl} (65%) rename src/{gles_canvas_shaders/gles_canvas_tile.glsl => glsl_shaders/tile.glsl} (89%) diff --git a/build.bat b/build.bat index 131f00f..e2e1f60 100644 --- a/build.bat +++ b/build.bat @@ -1,8 +1,9 @@ if not exist bin mkdir bin -set gles_shaders=src\gles_canvas_shaders\gles_canvas_blit_vertex.glsl src\gles_canvas_shaders\gles_canvas_blit_fragment.glsl src\gles_canvas_shaders\gles_canvas_clear_counters.glsl src\gles_canvas_shaders\gles_canvas_tile.glsl src\gles_canvas_shaders\gles_canvas_sort.glsl src\gles_canvas_shaders\gles_canvas_draw.glsl -call python scripts\embed_text.py %gles_shaders% --output src\gles_canvas_shaders.h +set glsl_shaders=src\glsl_shaders\common.glsl src\glsl_shaders\blit_vertex.glsl src\glsl_shaders\blit_fragment.glsl src\glsl_shaders\clear_counters.glsl src\glsl_shaders\tile.glsl src\glsl_shaders\sort.glsl src\glsl_shaders\draw.glsl + +call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_shaders.h set INCLUDES=/I src /I src/util /I src/platform /I ext cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c diff --git a/scripts/embed_text.py b/scripts/embed_text.py index 006916f..777532d 100644 --- a/scripts/embed_text.py +++ b/scripts/embed_text.py @@ -5,6 +5,7 @@ from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("inputFiles", nargs="+") parser.add_argument("-o", "--output") +parser.add_argument("-p", "--prefix") args = parser.parse_args() @@ -30,7 +31,7 @@ for fileName in args.inputFiles: output.write("//NOTE: string imported from %s\n" % fileName) stringName = os.path.splitext(os.path.basename(fileName))[0] - output.write("const char* %s = " % stringName) + output.write(f"const char* {args.prefix}{stringName} = ") for line in lines: output.write("\n\"%s\\n\"" % line) diff --git a/src/gl_canvas.c b/src/gl_canvas.c index 58baf9e..b7c3e8e 100644 --- a/src/gl_canvas.c +++ b/src/gl_canvas.c @@ -8,7 +8,7 @@ *****************************************************************/ #include"graphics_internal.h" #include"macro_helpers.h" -#include"gles_canvas_shaders.h" +#include"glsl_shaders.h" #define LOG_SUBSYSTEM "Graphics" @@ -53,7 +53,7 @@ typedef struct debug_vertex { vec4 cubic; vec2 pos; - int zIndex; + int shapeIndex; u8 pad[4]; } debug_vertex; @@ -110,8 +110,8 @@ 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, - .zIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET, - .zIndexStride = LAYOUT_VERTEX_SIZE, + .shapeIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET, + .shapeIndexStride = LAYOUT_VERTEX_SIZE, .colorBuffer = backend->shapeMapping + LAYOUT_COLOR_OFFSET, .colorStride = LAYOUT_SHAPE_SIZE, @@ -263,16 +263,14 @@ void mg_gl_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* b //TODO } -static void mg_gl_compile_shader(GLuint shader, const char* source) +static int mg_gl_compile_shader(const char* name, GLuint shader, const char* source) { - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); + int res = 0; - int err = glGetError(); - if(err) - { - printf("gl error: %i\n", err); - } + const char* sources[3] = {"#version 430", glsl_common, source}; + + glShaderSource(shader, 3, sources, 0); + glCompileShader(shader); int status = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); @@ -281,10 +279,93 @@ static void mg_gl_compile_shader(GLuint shader, const char* source) char buffer[256]; int size = 0; glGetShaderInfoLog(shader, 256, &size, buffer); - printf("shader error: %.*s\n", size, buffer); + printf("Shader compile error (%s): %.*s\n", name, size, buffer); + res = -1; } + return(res); } +static int mg_gl_canvas_compile_compute_program_named(const char* name, const char* source, GLuint* outProgram) +{ + int res = 0; + *outProgram = 0; + + GLuint shader = glCreateShader(GL_COMPUTE_SHADER); + GLuint program = glCreateProgram(); + + res |= mg_gl_compile_shader(name, shader, source); + + if(!res) + { + glAttachShader(program, shader); + glLinkProgram(program); + + int status = 0; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetProgramInfoLog(program, 256, &size, buffer); + LOG_ERROR("Shader link error (%s): %.*s\n", name, size, buffer); + + res = -1; + } + else + { + *outProgram = program; + } + } + return(res); +} + +int mg_gl_canvas_compile_render_program_named(const char* progName, + const char* vertexName, + const char* fragmentName, + const char* vertexSrc, + const char* fragmentSrc, + GLuint* outProgram) +{ + int res = 0; + *outProgram = 0; + + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + GLuint program = glCreateProgram(); + + res |= mg_gl_compile_shader(vertexName, vertexShader, vertexSrc); + res |= mg_gl_compile_shader(fragmentName, fragmentShader, fragmentSrc); + + if(!res) + { + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + + int status = 0; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetProgramInfoLog(program, 256, &size, buffer); + LOG_ERROR("Shader link error (%s): %.*s\n", progName, size, buffer); + res = -1; + } + else + { + *outProgram = program; + } + } + return(res); +} + +#define mg_gl_canvas_compile_compute_program(src, out) \ + mg_gl_canvas_compile_compute_program_named(#src, src, out) + +#define mg_gl_canvas_compile_render_program(progName, shaderSrc, vertexSrc, out) \ + mg_gl_canvas_compile_render_program_named(progName, #shaderSrc, #vertexSrc, shaderSrc, vertexSrc, out) + mg_canvas_backend* mg_gl_canvas_create(mg_surface surface) { mg_gl_canvas_backend* backend = 0; @@ -343,116 +424,12 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - //NOTE: create clear program - { - GLuint clearShader = glCreateShader(GL_COMPUTE_SHADER); - backend->clearCounterProgram = glCreateProgram(); - - mg_gl_compile_shader(clearShader, gles_canvas_clear_counters); - - glAttachShader(backend->clearCounterProgram, clearShader); - glLinkProgram(backend->clearCounterProgram); - - int status = 0; - glGetProgramiv(backend->clearCounterProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->clearCounterProgram, 256, &size, buffer); - printf("link error in gl_canvas_clear_counters: %.*s\n", size, buffer); - exit(-1); - } - } - //NOTE: create tile program - { - GLuint tileShader = glCreateShader(GL_COMPUTE_SHADER); - backend->tileProgram = glCreateProgram(); - - mg_gl_compile_shader(tileShader, gles_canvas_tile); - - glAttachShader(backend->tileProgram, tileShader); - glLinkProgram(backend->tileProgram); - - int status = 0; - glGetProgramiv(backend->tileProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->tileProgram, 256, &size, buffer); - printf("link error in gl_canvas_tile: %.*s\n", size, buffer); - exit(-1); - } - } - //NOTE: create sort program - { - GLuint sortShader = glCreateShader(GL_COMPUTE_SHADER); - backend->sortProgram = glCreateProgram(); - - mg_gl_compile_shader(sortShader, gles_canvas_sort); - - glAttachShader(backend->sortProgram, sortShader); - glLinkProgram(backend->sortProgram); - - int status = 0; - glGetProgramiv(backend->sortProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->sortProgram, 256, &size, buffer); - printf("link error gl_canvas_sort: %.*s\n", size, buffer); - exit(-1); - } - } - - //NOTE: create draw program - { - GLuint shader = glCreateShader(GL_COMPUTE_SHADER); - backend->drawProgram = glCreateProgram(); - - mg_gl_compile_shader(shader, gles_canvas_draw); - - glAttachShader(backend->drawProgram, shader); - glLinkProgram(backend->drawProgram); - - int status = 0; - glGetProgramiv(backend->drawProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->drawProgram, 256, &size, buffer); - printf("link error gl_canvas_draw: %.*s\n", size, buffer); - exit(-1); - } - } - - //NOTE: create blit program - { - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - backend->blitProgram = glCreateProgram(); - - mg_gl_compile_shader(vertexShader, gles_canvas_blit_vertex); - mg_gl_compile_shader(fragmentShader, gles_canvas_blit_fragment); - - glAttachShader(backend->blitProgram, vertexShader); - glAttachShader(backend->blitProgram, fragmentShader); - glLinkProgram(backend->blitProgram); - - int status = 0; - glGetProgramiv(backend->blitProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->blitProgram, 256, &size, buffer); - printf("link error gl_canvas_blit: %.*s\n", size, buffer); - exit(-1); - } - } + //NOTE: create programs + mg_gl_canvas_compile_compute_program(glsl_clear_counters, &backend->clearCounterProgram); + mg_gl_canvas_compile_compute_program(glsl_tile, &backend->tileProgram); + mg_gl_canvas_compile_compute_program(glsl_sort, &backend->sortProgram); + 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); backend->vertexMapping = malloc_array(char, 1<<30); backend->shapeMapping = malloc_array(char, 1<<30); diff --git a/src/gles_canvas.c b/src/gles_canvas.c deleted file mode 100644 index 74a9168..0000000 --- a/src/gles_canvas.c +++ /dev/null @@ -1,451 +0,0 @@ -/************************************************************//** -* -* @file: gles_canvas.c -* @author: Martin Fouilleul -* @date: 29/01/2023 -* @revision: -* -*****************************************************************/ -#include"graphics_internal.h" -#include"macro_helpers.h" -#include"gles_canvas_shaders.h" - -#define LOG_SUBSYSTEM "Graphics" - -typedef struct mg_gles_canvas_backend -{ - mg_canvas_backend interface; - mg_surface surface; - - GLint dummyVertexBuffer; - GLint vertexBuffer; - GLint indexBuffer; - GLint tileCounterBuffer; - GLint tileArrayBuffer; - GLint clearCounterProgram; - GLint tileProgram; - GLint sortProgram; - GLint drawProgram; - GLint blitProgram; - - GLint outTexture; - - char* indexMapping; - char* vertexMapping; - -} mg_gles_canvas_backend; - -mg_gles_surface* mg_gles_canvas_get_surface(mg_gles_canvas_backend* canvas) -{ - mg_gles_surface* res = 0; - mg_surface_data* data = mg_surface_data_from_handle(canvas->surface); - if(data && data->backend == MG_BACKEND_GLES) - { - res = (mg_gles_surface*)data; - } - return(res); -} - -//NOTE: debugger -typedef struct debug_vertex -{ - vec2 pos; - vec2 uv; - vec4 cubic; - vec4 color; - vec4 clip; - int zIndex; - u8 align2[12]; -} debug_vertex; - - -#define LayoutNext(prevName, prevType, nextType) \ - AlignUpOnPow2(_cat3_(LAYOUT_, prevName, _OFFSET)+_cat3_(LAYOUT_, prevType, _SIZE), _cat3_(LAYOUT_, nextType, _ALIGN)) - -enum { - LAYOUT_VEC2_SIZE = 8, - LAYOUT_VEC2_ALIGN = 8, - LAYOUT_VEC4_SIZE = 16, - LAYOUT_VEC4_ALIGN = 16, - 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_VERTEX_ALIGN = 16, - LAYOUT_VERTEX_SIZE = LayoutNext(ZINDEX, INT, VERTEX), -}; - -enum { - MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH = 1<<20, - MG_GLES_CANVAS_VERTEX_BUFFER_SIZE = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_VERTEX_SIZE, - MG_GLES_CANVAS_INDEX_BUFFER_SIZE = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_INT_SIZE, - MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE = 65536, - MG_GLES_CANVAS_TILE_ARRAY_SIZE = sizeof(int)*4096, - MG_GLES_CANVAS_TILE_ARRAY_BUFFER_SIZE = MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE * MG_GLES_CANVAS_TILE_ARRAY_SIZE, -}; - -void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend) -{ - backend->interface.vertexLayout = (mg_vertex_layout){ - .maxVertexCount = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH, - .maxIndexCount = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH, - .posBuffer = backend->vertexMapping + LAYOUT_POS_OFFSET, - .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, - .indexBuffer = backend->indexMapping, - .indexStride = LAYOUT_INT_SIZE}; -} - -void mg_gles_send_buffers(mg_gles_canvas_backend* backend, int vertexCount, int indexCount) -{ - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_VERTEX_SIZE*vertexCount, backend->vertexMapping, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_INT_SIZE*indexCount, backend->indexMapping, GL_DYNAMIC_DRAW); -} -void mg_gles_canvas_begin(mg_canvas_backend* interface) -{ - mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface; - mg_gles_surface* surface = mg_gles_canvas_get_surface(backend); - if(!surface) - { - return; - } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -void mg_gles_canvas_end(mg_canvas_backend* interface) -{ - //NOTE: nothing to do here... -} - -void mg_gles_canvas_clear(mg_canvas_backend* interface, mg_color clearColor) -{ - mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface; - mg_gles_surface* surface = mg_gles_canvas_get_surface(backend); - if(!surface) - { - return; - } - - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT); -} - -void mg_gles_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount) -{ - mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface; - mg_gles_surface* surface = mg_gles_canvas_get_surface(backend); - if(!surface) - { - return; - } - -/*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); -//*/ - mg_gles_send_buffers(backend, vertexCount, indexCount); - - mp_rect frame = mg_surface_get_frame(backend->surface); - - const int tileSize = 16; - const int tileCountX = (frame.w + tileSize - 1)/tileSize; - const int tileCountY = (frame.h + tileSize - 1)/tileSize; - const int tileArraySize = MG_GLES_CANVAS_TILE_ARRAY_SIZE; - - //TODO: ensure there's enough space in tile buffer - - //NOTE: first clear counters - glUseProgram(backend->clearCounterProgram); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->tileCounterBuffer); - glDispatchCompute(tileCountX*tileCountY, 1, 1); - - //NOTE: we first distribute triangles into tiles: - - 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); - - glUniform1ui(0, indexCount); - glUniform2ui(1, tileCountX, tileCountY); - glUniform1ui(2, tileSize); - glUniform1ui(3, tileArraySize); - - u32 threadCount = indexCount/3; - glDispatchCompute((threadCount + 255)/256, 1, 1); - - //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); - glUniform1ui(3, tileArraySize); - - 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); - - 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); - glUniform2ui(1, tileCountX, tileCountY); - glUniform1ui(2, tileSize); - glUniform1ui(3, tileArraySize); - - glDispatchCompute(tileCountX, tileCountY, 1); - - //NOTE: now blit out texture to surface - glUseProgram(backend->blitProgram); - glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, backend->outTexture); - glUniform1i(0, 0); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - mg_gles_canvas_update_vertex_layout(backend); -} - -void mg_gles_canvas_destroy(mg_canvas_backend* interface) -{ - mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface; - - //TODO -} - -void mg_gles_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes) -{ - //TODO -} - -static void mg_gles_compile_shader(GLuint shader, const char* source) -{ - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); - - int err = glGetError(); - if(err) - { - printf("gl error: %i\n", err); - } - - int status = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetShaderInfoLog(shader, 256, &size, buffer); - printf("shader error: %.*s\n", size, buffer); - } -} - -mg_canvas_backend* mg_gles_canvas_create(mg_surface surface) -{ - mg_gles_canvas_backend* backend = 0; - mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); - if(surfaceData && surfaceData->backend == MG_BACKEND_GLES) - { - mg_gles_surface* glesSurface = (mg_gles_surface*)surfaceData; - - backend = malloc_type(mg_gles_canvas_backend); - memset(backend, 0, sizeof(mg_gles_canvas_backend)); - backend->surface = surface; - - //NOTE(martin): setup interface functions - backend->interface.destroy = mg_gles_canvas_destroy; - backend->interface.begin = mg_gles_canvas_begin; - backend->interface.end = mg_gles_canvas_end; - backend->interface.clear = mg_gles_canvas_clear; - backend->interface.drawBatch = mg_gles_canvas_draw_batch; - backend->interface.atlasUpload = mg_gles_canvas_atlas_upload; - - mg_surface_prepare(surface); - - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - glGenBuffers(1, &backend->vertexBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer); -// glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_VERTEX_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW); - - glGenBuffers(1, &backend->indexBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer); -// glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_INDEX_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW); - - glGenBuffers(1, &backend->tileCounterBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileCounterBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE, 0, GL_DYNAMIC_COPY); - - glGenBuffers(1, &backend->tileArrayBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileArrayBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_TILE_ARRAY_BUFFER_SIZE, 0, GL_DYNAMIC_COPY); - - glGenBuffers(1, &backend->dummyVertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer); - - mp_rect frame = mg_surface_get_frame(backend->surface); - glGenTextures(1, &backend->outTexture); - glBindTexture(GL_TEXTURE_2D, backend->outTexture); - glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, frame.w, frame.h); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - //NOTE: create clear program - { - GLuint clearShader = glCreateShader(GL_COMPUTE_SHADER); - backend->clearCounterProgram = glCreateProgram(); - - mg_gles_compile_shader(clearShader, gles_canvas_clear_counters); - - glAttachShader(backend->clearCounterProgram, clearShader); - glLinkProgram(backend->clearCounterProgram); - - int status = 0; - glGetProgramiv(backend->clearCounterProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->clearCounterProgram, 256, &size, buffer); - printf("link error in gl_canvas_clear_counters: %.*s\n", size, buffer); - exit(-1); - } - } - //NOTE: create tile program - { - GLuint tileShader = glCreateShader(GL_COMPUTE_SHADER); - backend->tileProgram = glCreateProgram(); - - mg_gles_compile_shader(tileShader, gles_canvas_tile); - - glAttachShader(backend->tileProgram, tileShader); - glLinkProgram(backend->tileProgram); - - int status = 0; - glGetProgramiv(backend->tileProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->tileProgram, 256, &size, buffer); - printf("link error in gl_canvas_tile: %.*s\n", size, buffer); - exit(-1); - } - } - //NOTE: create sort program - { - GLuint sortShader = glCreateShader(GL_COMPUTE_SHADER); - backend->sortProgram = glCreateProgram(); - - mg_gles_compile_shader(sortShader, gles_canvas_sort); - - glAttachShader(backend->sortProgram, sortShader); - glLinkProgram(backend->sortProgram); - - int status = 0; - glGetProgramiv(backend->sortProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->sortProgram, 256, &size, buffer); - printf("link error gl_canvas_sort: %.*s\n", size, buffer); - exit(-1); - } - } - - //NOTE: create draw program - { - GLuint shader = glCreateShader(GL_COMPUTE_SHADER); - backend->drawProgram = glCreateProgram(); - - mg_gles_compile_shader(shader, gles_canvas_draw); - - glAttachShader(backend->drawProgram, shader); - glLinkProgram(backend->drawProgram); - - int status = 0; - glGetProgramiv(backend->drawProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->drawProgram, 256, &size, buffer); - printf("link error gl_canvas_draw: %.*s\n", size, buffer); - exit(-1); - } - } - - //NOTE: create blit program - { - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - backend->blitProgram = glCreateProgram(); - - mg_gles_compile_shader(vertexShader, gles_canvas_blit_vertex); - mg_gles_compile_shader(fragmentShader, gles_canvas_blit_fragment); - - glAttachShader(backend->blitProgram, vertexShader); - glAttachShader(backend->blitProgram, fragmentShader); - glLinkProgram(backend->blitProgram); - - int status = 0; - glGetProgramiv(backend->blitProgram, GL_LINK_STATUS, &status); - if(!status) - { - char buffer[256]; - int size = 0; - glGetProgramInfoLog(backend->blitProgram, 256, &size, buffer); - printf("link error gl_canvas_blit: %.*s\n", size, buffer); - exit(-1); - } - } - - backend->vertexMapping = malloc_array(char, 1<<30); - backend->indexMapping = malloc_array(char, 1<<30); - - mg_gles_canvas_update_vertex_layout(backend); - } - - return((mg_canvas_backend*)backend); -} - - -#undef LOG_SUBSYSTEM diff --git a/src/glsl_shaders.h b/src/glsl_shaders.h new file mode 100644 index 0000000..0c847fa --- /dev/null +++ b/src/glsl_shaders.h @@ -0,0 +1,441 @@ +/********************************************************************* +* +* file: glsl_shaders.h +* note: string literals auto-generated by embed_text.py +* date: 09/022023 +* +**********************************************************************/ +#ifndef __GLSL_SHADERS_H__ +#define __GLSL_SHADERS_H__ + + +//NOTE: string imported from src\glsl_shaders\common.glsl +const char* glsl_common = +"\n" +"layout(std430) buffer;\n" +"\n" +"struct vertex {\n" +" vec4 cubic;\n" +" vec2 pos;\n" +" int shapeIndex;\n" +"};\n" +"\n" +"struct shape {\n" +" vec4 color;\n" +" vec4 clip;\n" +" vec2 uv;\n" +"};\n"; + +//NOTE: string imported from src\glsl_shaders\blit_vertex.glsl +const char* glsl_blit_vertex = +"\n" +"precision mediump float;\n" +"\n" +"out vec2 uv;\n" +"\n" +"void main()\n" +"{\n" +" float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u);\n" +" float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u);\n" +"\n" +" gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f);\n" +" uv = vec2(x, y);\n" +"}\n"; + +//NOTE: string imported from src\glsl_shaders\blit_fragment.glsl +const char* glsl_blit_fragment = +"\n" +"precision mediump float;\n" +"\n" +"in vec2 uv;\n" +"out vec4 fragColor;\n" +"\n" +"layout(location=0) uniform sampler2D tex;\n" +"\n" +"void main()\n" +"{\n" +" fragColor = texture(tex, uv);\n" +"}\n"; + +//NOTE: string imported from src\glsl_shaders\clear_counters.glsl +const char* glsl_clear_counters = +"\n" +"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" +"\n" +"precision mediump float;\n" +"layout(std430) buffer;\n" +"\n" +"layout(binding = 0) coherent restrict writeonly buffer tileCounterBufferSSBO {\n" +" uint elements[];\n" +"} tileCounterBuffer ;\n" +"\n" +"void main()\n" +"{\n" +" uint tileIndex = gl_WorkGroupID.x;\n" +" tileCounterBuffer.elements[tileIndex] = 0u;\n" +"}\n"; + +//NOTE: string imported from src\glsl_shaders\tile.glsl +const char* glsl_tile = +"\n" +"layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;\n" +"\n" +"precision mediump float;\n" +"\n" +"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" +" vertex elements[];\n" +"} vertexBuffer ;\n" +"\n" +"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" +" shape elements[];\n" +"} shapeBuffer ;\n" +"\n" +"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" +" uint elements[];\n" +"} indexBuffer ;\n" +"\n" +"layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {\n" +" uint elements[];\n" +"} tileCounterBuffer ;\n" +"\n" +"layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {\n" +" uint elements[];\n" +"} tileArrayBuffer ;\n" +"\n" +"layout(location = 0) uniform uint indexCount;\n" +"layout(location = 1) uniform uvec2 tileCount;\n" +"layout(location = 2) uniform uint tileSize;\n" +"layout(location = 3) uniform uint tileArraySize;\n" +"layout(location = 4) uniform vec2 scaling;\n" +"\n" +"void main()\n" +"{\n" +" uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;\n" +" if(triangleIndex >= indexCount)\n" +" {\n" +" return;\n" +" }\n" +"\n" +" uint i0 = indexBuffer.elements[triangleIndex];\n" +" uint i1 = indexBuffer.elements[triangleIndex+1u];\n" +" uint i2 = indexBuffer.elements[triangleIndex+2u];\n" +"\n" +" vec2 p0 = vertexBuffer.elements[i0].pos * scaling;\n" +" vec2 p1 = vertexBuffer.elements[i1].pos * scaling;\n" +" vec2 p2 = vertexBuffer.elements[i2].pos * scaling;\n" +"\n" +" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n" +" vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);\n" +"\n" +" vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x),\n" +" max(min(min(p0.y, p1.y), p2.y), clip.y),\n" +" min(max(max(p0.x, p1.x), p2.x), clip.z),\n" +" min(max(max(p0.y, p1.y), p2.y), clip.w));\n" +"\n" +" ivec4 box = ivec4(floor(fbox))/int(tileSize);\n" +"\n" +" //NOTE(martin): it's importat to do the computation with signed int, so that we can have negative xMax/yMax\n" +" // otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0.\n" +" int xMin = max(0, box.x);\n" +" int yMin = max(0, box.y);\n" +" int xMax = min(box.z, int(tileCount.x) - 1);\n" +" int yMax = min(box.w, int(tileCount.y) - 1);\n" +"\n" +" for(int y = yMin; y <= yMax; y++)\n" +" {\n" +" for(int x = xMin ; x <= xMax; x++)\n" +" {\n" +" uint tileIndex = uint(y)*tileCount.x + uint(x);\n" +" uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);\n" +" if(tileCounter < tileArraySize)\n" +" {\n" +" tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex;\n" +" }\n" +" }\n" +" }\n" +"}\n"; + +//NOTE: string imported from src\glsl_shaders\sort.glsl +const char* glsl_sort = +"\n" +"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" +"\n" +"precision mediump float;\n" +"\n" +"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" +" vertex elements[];\n" +"} vertexBuffer ;\n" +"\n" +"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" +" shape elements[];\n" +"} shapeBuffer ;\n" +"\n" +"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" +" uint elements[];\n" +"} indexBuffer ;\n" +"\n" +"layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {\n" +" uint elements[];\n" +"} tileCounterBuffer ;\n" +"\n" +"layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {\n" +" uint elements[];\n" +"} tileArrayBuffer ;\n" +"\n" +"layout(location = 0) uniform uint indexCount;\n" +"layout(location = 1) uniform uvec2 tileCount;\n" +"layout(location = 2) uniform uint tileSize;\n" +"layout(location = 3) uniform uint tileArraySize;\n" +"\n" +"int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)\n" +"{\n" +" uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];\n" +" uint i0 = indexBuffer.elements[triangleIndex];\n" +" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n" +" return(shapeIndex);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" uint tileIndex = gl_WorkGroupID.x;\n" +" uint tileArrayOffset = tileArraySize * tileIndex;\n" +" uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n" +"\n" +" for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)\n" +" {\n" +" for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)\n" +" {\n" +" int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);\n" +" int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);\n" +"\n" +" if(shapeIndex >= prevShapeIndex)\n" +" {\n" +" break;\n" +" }\n" +" uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];\n" +" tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];\n" +" tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;\n" +" }\n" +" }\n" +"}\n"; + +//NOTE: string imported from src\glsl_shaders\draw.glsl +const char* glsl_draw = +"\n" +"#extension GL_ARB_gpu_shader_int64 : require\n" +"layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n" +"\n" +"precision mediump float;\n" +"//precision mediump image2D;\n" +"\n" +"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" +" vertex elements[];\n" +"} vertexBuffer ;\n" +"\n" +"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" +" shape elements[];\n" +"} shapeBuffer ;\n" +"\n" +"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" +" uint elements[];\n" +"} indexBuffer ;\n" +"\n" +"layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {\n" +" uint elements[];\n" +"} tileCounterBuffer ;\n" +"\n" +"layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {\n" +" uint elements[];\n" +"} tileArrayBuffer ;\n" +"\n" +"layout(location = 0) uniform uint indexCount;\n" +"layout(location = 1) uniform uvec2 tileCount;\n" +"layout(location = 2) uniform uint tileSize;\n" +"layout(location = 3) uniform uint tileArraySize;\n" +"layout(location = 4) uniform vec2 scaling;\n" +"\n" +"layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\n" +"\n" +"bool is_top_left(ivec2 a, ivec2 b)\n" +"{\n" +" return( (a.y == b.y && b.x < a.x)\n" +" ||(b.y < a.y));\n" +"}\n" +"\n" +"//////////////////////////////////////////////////////////////////////////////\n" +"//TODO: we should do these computations on 64bits, because otherwise\n" +"// we might overflow for values > 2048.\n" +"// Unfortunately this is costly.\n" +"// Another way is to precompute triangle edges (b - a) in full precision\n" +"// once to avoid doing it all the time...\n" +"//////////////////////////////////////////////////////////////////////////////\n" +"int orient2d(ivec2 a, ivec2 b, ivec2 p)\n" +"{\n" +" return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));\n" +"}\n" +"\n" +"int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)\n" +"{\n" +" return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);\n" +" uvec2 tileCoord = uvec2(pixelCoord) / tileSize;\n" +" uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;\n" +" uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n" +"\n" +" const float subPixelFactor = 16.;\n" +" ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);\n" +"\n" +"//*\n" +" const int sampleCount = 8;\n" +" ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),\n" +" centerPoint + ivec2(-1, -3),\n" +" centerPoint + ivec2(5, -1),\n" +" centerPoint + ivec2(-3, 5),\n" +" centerPoint + ivec2(-5, -5),\n" +" centerPoint + ivec2(-7, 1),\n" +" centerPoint + ivec2(3, -7),\n" +" centerPoint + ivec2(7, 7));\n" +"/*/\n" +" const int sampleCount = 4;\n" +" ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),\n" +" centerPoint + ivec2(6, 2),\n" +" centerPoint + ivec2(-6, -2),\n" +" centerPoint + ivec2(2, -6));\n" +"//*/\n" +" //DEBUG\n" +"/*\n" +" {\n" +" vec4 fragColor = vec4(0);\n" +"\n" +" if( pixelCoord.x % 16 == 0\n" +" ||pixelCoord.y % 16 == 0)\n" +" {\n" +" fragColor = vec4(0, 0, 0, 1);\n" +" }\n" +" else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)\n" +" {\n" +" fragColor = vec4(1, 0, 1, 1);\n" +" }\n" +" else if(tileCounter != 0u)\n" +" {\n" +" fragColor = vec4(0, 1, 0, 1);\n" +" }\n" +" else\n" +" {\n" +" fragColor = vec4(1, 0, 0, 1);\n" +" }\n" +" imageStore(outTexture, pixelCoord, fragColor);\n" +" return;\n" +" }\n" +"//*/\n" +" //----\n" +"\n" +" vec4 sampleColor[sampleCount];\n" +" vec4 currentColor[sampleCount];\n" +" int currentShapeIndex[sampleCount];\n" +" int flipCount[sampleCount];\n" +"\n" +" for(int i=0; i clip.z\n" +" || samplePoint.y < clip.y\n" +" || samplePoint.y > clip.w)\n" +" {\n" +" continue;\n" +" }\n" +"\n" +" int w0 = orient2d(p1, p2, samplePoint);\n" +" int w1 = orient2d(p2, p0, samplePoint);\n" +" int w2 = orient2d(p0, p1, samplePoint);\n" +"\n" +" if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)\n" +" {\n" +" vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));\n" +"\n" +" float eps = 0.0001;\n" +" if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n" +" {\n" +" if(shapeIndex == currentShapeIndex[sampleIndex])\n" +" {\n" +" flipCount[sampleIndex]++;\n" +" }\n" +" else\n" +" {\n" +" if((flipCount[sampleIndex] & 0x01) != 0)\n" +" {\n" +" sampleColor[sampleIndex] = currentColor[sampleIndex];\n" +" }\n" +" currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;\n" +" currentShapeIndex[sampleIndex] = shapeIndex;\n" +" flipCount[sampleIndex] = 1;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }\n" +" vec4 pixelColor = vec4(0);\n" +" for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n" +" {\n" +" if((flipCount[sampleIndex] & 0x01) != 0)\n" +" {\n" +" sampleColor[sampleIndex] = currentColor[sampleIndex];\n" +" }\n" +" pixelColor += sampleColor[sampleIndex];\n" +" }\n" +"\n" +" imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount));\n" +"}\n"; + +#endif // __GLSL_SHADERS_H__ diff --git a/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl b/src/glsl_shaders/blit_fragment.glsl similarity index 85% rename from src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl rename to src/glsl_shaders/blit_fragment.glsl index 4a51e91..6d648f3 100644 --- a/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl +++ b/src/glsl_shaders/blit_fragment.glsl @@ -1,4 +1,3 @@ -#version 430 precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl b/src/glsl_shaders/blit_vertex.glsl similarity index 90% rename from src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl rename to src/glsl_shaders/blit_vertex.glsl index 5547012..56b48f5 100644 --- a/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl +++ b/src/glsl_shaders/blit_vertex.glsl @@ -1,4 +1,3 @@ -#version 430 precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl b/src/glsl_shaders/clear_counters.glsl similarity index 92% rename from src/gles_canvas_shaders/gles_canvas_clear_counters.glsl rename to src/glsl_shaders/clear_counters.glsl index 321bf38..f6a4d0b 100644 --- a/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl +++ b/src/glsl_shaders/clear_counters.glsl @@ -1,4 +1,4 @@ -#version 430 + layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; precision mediump float; diff --git a/src/glsl_shaders/common.glsl b/src/glsl_shaders/common.glsl new file mode 100644 index 0000000..0d96432 --- /dev/null +++ b/src/glsl_shaders/common.glsl @@ -0,0 +1,14 @@ + +layout(std430) buffer; + +struct vertex { + vec4 cubic; + vec2 pos; + int shapeIndex; +}; + +struct shape { + vec4 color; + vec4 clip; + vec2 uv; +}; diff --git a/src/gles_canvas_shaders/gles_canvas_draw.glsl b/src/glsl_shaders/draw.glsl similarity index 89% rename from src/gles_canvas_shaders/gles_canvas_draw.glsl rename to src/glsl_shaders/draw.glsl index 6d8880f..8c51699 100644 --- a/src/gles_canvas_shaders/gles_canvas_draw.glsl +++ b/src/glsl_shaders/draw.glsl @@ -1,24 +1,10 @@ -#version 430 + #extension GL_ARB_gpu_shader_int64 : require layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; precision mediump float; //precision mediump image2D; -layout(std430) buffer; - -struct vertex { - vec4 cubic; - vec2 pos; - int zIndex; -}; - -struct shape { - vec4 color; - vec4 clip; - vec2 uv; -}; - layout(binding = 0) restrict readonly buffer vertexBufferSSBO { vertex elements[]; } vertexBuffer ; @@ -127,12 +113,12 @@ void main() vec4 sampleColor[sampleCount]; vec4 currentColor[sampleCount]; - int currentZIndex[sampleCount]; + int currentShapeIndex[sampleCount]; int flipCount[sampleCount]; for(int i=0; i 0u; sortIndex--) { - int zIndex = get_zindex(tileArrayOffset, sortIndex); - int prevZIndex = get_zindex(tileArrayOffset, sortIndex-1u); + int shapeIndex = get_shape_index(tileArrayOffset, sortIndex); + int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u); - if(zIndex >= prevZIndex) + if(shapeIndex >= prevShapeIndex) { break; } @@ -71,20 +58,4 @@ void main() tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp; } } - - //DEBUG - /* - int prevZIndex = -1; - for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++) - { - int zIndex = get_zindex(tileArrayOffset, tileArrayIndex); - - if(zIndex < prevZIndex) - { - tileCounterBuffer.elements[tileIndex] = 0xffffu; - break; - } - prevZIndex = zIndex; - } - //*/ } diff --git a/src/gles_canvas_shaders/gles_canvas_tile.glsl b/src/glsl_shaders/tile.glsl similarity index 89% rename from src/gles_canvas_shaders/gles_canvas_tile.glsl rename to src/glsl_shaders/tile.glsl index 5362fea..551bfc5 100644 --- a/src/gles_canvas_shaders/gles_canvas_tile.glsl +++ b/src/glsl_shaders/tile.glsl @@ -1,20 +1,7 @@ -#version 430 + layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in; precision mediump float; -layout(std430) buffer; - -struct vertex { - vec4 cubic; - vec2 pos; - int zIndex; -}; - -struct shape { - vec4 color; - vec4 clip; - vec2 uv; -}; layout(binding = 0) restrict readonly buffer vertexBufferSSBO { vertex elements[]; @@ -58,7 +45,7 @@ void main() vec2 p1 = vertexBuffer.elements[i1].pos * scaling; vec2 p2 = vertexBuffer.elements[i2].pos * scaling; - int shapeIndex = vertexBuffer.elements[i0].zIndex; + int shapeIndex = vertexBuffer.elements[i0].shapeIndex; vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling); vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x), diff --git a/src/graphics.c b/src/graphics.c index ec3eefe..5860aac 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -447,17 +447,17 @@ void mg_path_push_element(mg_canvas_data* canvas, mg_path_elt elt) /////////////////////////////////////// WIP ///////////////////////////////////////////////////////////////////////// -void mg_reset_z_index(mg_canvas_data* canvas) +void mg_reset_shape_index(mg_canvas_data* canvas) { - canvas->nextZIndex = 1; + canvas->nextShapeIndex = 0; } u32 mg_next_shape_textured(mg_canvas_data* canvas, vec2 uv, mg_color color) { //TODO: push color, uv, clip - int index = canvas->nextZIndex; - canvas->nextZIndex++; + int index = canvas->nextShapeIndex; + canvas->nextShapeIndex++; mp_rect clip = {canvas->clip.x, canvas->clip.y, @@ -496,16 +496,16 @@ int* mg_reserve_indices(mg_canvas_data* canvas, u32 indexCount) return(base); } -void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 zIndex) +void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 shapeIndex) { mg_vertex_layout* layout = &canvas->backend->vertexLayout; DEBUG_ASSERT(canvas->vertexCount < layout->maxVertexCount); - u32 offset = canvas->vertexCount; + u32 index = canvas->vertexCount; - *(vec2*)(((char*)layout->posBuffer) + offset*layout->posStride) = pos; - *(vec4*)(((char*)layout->cubicBuffer) + offset*layout->cubicStride) = cubic; - *(u32*)(((char*)layout->zIndexBuffer) + offset*layout->zIndexStride) = zIndex; + *(vec2*)(((char*)layout->posBuffer) + index*layout->posStride) = pos; + *(vec4*)(((char*)layout->cubicBuffer) + index*layout->cubicStride) = cubic; + *(u32*)(((char*)layout->shapeIndexBuffer) + index*layout->shapeIndexStride) = shapeIndex; canvas->vertexCount++; } @@ -513,11 +513,11 @@ void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 zIndex) // Path Filling //----------------------------------------------------------------------------------------------------------- //NOTE(martin): forward declarations -void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_color color); +void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_color color); //NOTE(martin): quadratics filling -void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_color color) +void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 shapeIndex, mg_color color) { u32 baseIndex = mg_vertices_base_index(canvas); @@ -526,17 +526,17 @@ 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, (vec2){p[1].x, p[1].y}), (vec4){0.5, 0, 0.5, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, (vec2){p[2].x, p[2].y}), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -545,7 +545,7 @@ void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_ //NOTE(martin): cubic filling -void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32 zIndex, mg_color color) +void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32 shapeIndex, mg_color color) { int subVertexCount = 0; int subIndexCount = 0; @@ -580,29 +580,29 @@ 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, (vec2){split.x, split.y}), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, (vec2){p[3].x, p[3].y}), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; indices[2] = baseIndex + 2; - mg_render_fill_cubic(canvas, subPointsLow, zIndex, color); - mg_render_fill_cubic(canvas, subPointsHigh, zIndex, color); + mg_render_fill_cubic(canvas, subPointsLow, shapeIndex, color); + mg_render_fill_cubic(canvas, subPointsHigh, shapeIndex, color); return; } -void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_color color) +void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_color color) { LOG_DEBUG("graphics render fill cubic\n"); @@ -674,7 +674,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo {1.5*p[1].x - 0.5*p[0].x, 1.5*p[1].y - 0.5*p[0].y}, p[3]}; - mg_render_fill_quadratic(canvas, quadControlPoints, zIndex, color); + mg_render_fill_quadratic(canvas, quadControlPoints, shapeIndex, color); return; } else if( (discrFactor2 > 0 && d1 != 0) @@ -743,13 +743,13 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo if(sd != 0 && td/sd < 0.99 && td/sd > 0.01) { LOG_DEBUG("split curve at first double point\n"); - mg_split_and_fill_cubic(canvas, p, td/sd, zIndex, color); + mg_split_and_fill_cubic(canvas, p, td/sd, shapeIndex, color); return; } if(se != 0 && te/se < 0.99 && te/se > 0.01) { LOG_DEBUG("split curve at second double point\n"); - mg_split_and_fill_cubic(canvas, p, te/se, zIndex, color); + mg_split_and_fill_cubic(canvas, p, te/se, shapeIndex, color); return; } @@ -959,7 +959,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, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); indices[i] = baseIndex + i; } @@ -989,32 +989,32 @@ 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[1]]), (vec4){vec4_expand_xyz(testCoords[orderedHullIndices[1]]), outsideTest1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]), (vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[0]]), (vec4){vec4_expand_xyz(testCoords[orderedHullIndices[0]]), outsideTest2}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]), (vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest2}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[3]]), (vec4){vec4_expand_xyz(testCoords[orderedHullIndices[3]]), outsideTest2}, - zIndex); + shapeIndex); indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -1040,7 +1040,7 @@ 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}, - zIndex); + shapeIndex); } indices[0] = baseIndex + 0; @@ -1054,7 +1054,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo //NOTE(martin): global path fill -void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descriptor* path, u32 zIndex, mg_color color) +void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descriptor* path, u32 shapeIndex, mg_color color) { u32 eltCount = path->count; vec2 startPoint = path->startPoint; @@ -1084,14 +1084,14 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr case MG_PATH_QUADRATIC: { - mg_render_fill_quadratic(canvas, controlPoints, zIndex, color); + mg_render_fill_quadratic(canvas, controlPoints, shapeIndex, color); endPoint = controlPoints[2]; } break; case MG_PATH_CUBIC: { - mg_render_fill_cubic(canvas, controlPoints, zIndex, color); + mg_render_fill_cubic(canvas, controlPoints, shapeIndex, color); endPoint = controlPoints[3]; } break; } @@ -1109,7 +1109,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, zIndex); + mg_push_vertex(canvas, pos[i], cubic, shapeIndex); indices[i] = baseIndex + i; } @@ -1121,7 +1121,7 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr // Path Stroking //----------------------------------------------------------------------------------------------------------- -void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 zIndex, mg_attributes* attributes) +void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 shapeIndex, mg_attributes* attributes) { //NOTE(martin): get normals multiplied by halfWidth f32 halfW = attributes->width/2; @@ -1141,22 +1141,22 @@ 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); indices[0] = baseIndex; indices[1] = baseIndex + 1; @@ -1282,7 +1282,7 @@ void mg_quadratic_split(vec2 p[3], f32 t, vec2 outLeft[3], vec2 outRight[3]) } -void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_attributes* attributes) +void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_attributes* attributes) { #define CHECK_SAMPLE_COUNT 5 f32 checkSamples[CHECK_SAMPLE_COUNT] = {1./6, 2./6, 3./6, 4./6, 5./6}; @@ -1336,17 +1336,17 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m vec2 splitLeft[3]; vec2 splitRight[3]; mg_quadratic_split(p, maxOvershootParameter, splitLeft, splitRight); - mg_render_stroke_quadratic(canvas, splitLeft, zIndex, attributes); - mg_render_stroke_quadratic(canvas, splitRight, zIndex, attributes); + mg_render_stroke_quadratic(canvas, splitLeft, shapeIndex, attributes); + mg_render_stroke_quadratic(canvas, splitRight, shapeIndex, attributes); } else { //NOTE(martin): push the actual fill commands for the offset contour - u32 zIndex = mg_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); - mg_render_fill_quadratic(canvas, positiveOffsetHull, zIndex, attributes->color); - mg_render_fill_quadratic(canvas, negativeOffsetHull, zIndex, attributes->color); + mg_render_fill_quadratic(canvas, positiveOffsetHull, shapeIndex, attributes->color); + mg_render_fill_quadratic(canvas, negativeOffsetHull, shapeIndex, attributes->color); //NOTE(martin): add base triangles u32 baseIndex = mg_vertices_base_index(canvas); @@ -1355,22 +1355,22 @@ 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, positiveOffsetHull[2]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, negativeOffsetHull[2]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -1436,7 +1436,7 @@ void mg_cubic_split(vec2 p[4], f32 t, vec2 outLeft[4], vec2 outRight[4]) outRight[3] = p[3]; } -void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_attributes* attributes) +void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_attributes* attributes) { #define CHECK_SAMPLE_COUNT 5 f32 checkSamples[CHECK_SAMPLE_COUNT] = {1./6, 2./6, 3./6, 4./6, 5./6}; @@ -1490,18 +1490,18 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at vec2 splitLeft[4]; vec2 splitRight[4]; mg_cubic_split(p, maxOvershootParameter, splitLeft, splitRight); - mg_render_stroke_cubic(canvas, splitLeft, zIndex, attributes); - mg_render_stroke_cubic(canvas, splitRight, zIndex, attributes); + mg_render_stroke_cubic(canvas, splitLeft, shapeIndex, attributes); + mg_render_stroke_cubic(canvas, splitRight, shapeIndex, attributes); //TODO: render joint between the split curves } else { //NOTE(martin): push the actual fill commands for the offset contour - u32 zIndex = mg_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); - mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color); - mg_render_fill_cubic(canvas, negativeOffsetHull, zIndex, attributes->color); + mg_render_fill_cubic(canvas, positiveOffsetHull, shapeIndex, attributes->color); + mg_render_fill_cubic(canvas, negativeOffsetHull, shapeIndex, attributes->color); //NOTE(martin): add base triangles u32 baseIndex = mg_vertices_base_index(canvas); @@ -1511,22 +1511,22 @@ 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, positiveOffsetHull[3]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, negativeOffsetHull[3]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -1551,7 +1551,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_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); u32 baseIndex = mg_vertices_base_index(canvas); i32* indices = mg_reserve_indices(canvas, 6); @@ -1559,22 +1559,22 @@ 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, (vec2){p0.x - n0.x, p0.y - n0.y}), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); indices[0] = baseIndex; indices[1] = baseIndex + 1; @@ -1613,7 +1613,7 @@ void mg_stroke_joint(mg_canvas_data* canvas, n1.y *= -1; } - u32 zIndex = mg_next_shape(canvas, attributes->color); + u32 shapeIndex = 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 @@ -1639,22 +1639,22 @@ void mg_stroke_joint(mg_canvas_data* canvas, mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p0), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, mitterPoint), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); indices[0] = baseIndex; indices[1] = baseIndex + 1; @@ -1672,17 +1672,17 @@ void mg_stroke_joint(mg_canvas_data* canvas, mg_push_vertex(canvas, mg_mat2x3_mul(canvas->transform, p0), (vec4){1, 1, 1, 1}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); 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}, - zIndex); + shapeIndex); DEBUG_ASSERT(!isnan(n0.x) && !isnan(n0.y) && !isnan(n1.x) && !isnan(n1.y)); @@ -1702,22 +1702,22 @@ 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_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); switch(element->type) { case MG_PATH_LINE: - mg_render_stroke_line(canvas, controlPoints, zIndex, attributes); + mg_render_stroke_line(canvas, controlPoints, shapeIndex, attributes); endPointIndex = 1; break; case MG_PATH_QUADRATIC: - mg_render_stroke_quadratic(canvas, controlPoints, zIndex, attributes); + mg_render_stroke_quadratic(canvas, controlPoints, shapeIndex, attributes); endPointIndex = 2; break; case MG_PATH_CUBIC: - mg_render_stroke_cubic(canvas, controlPoints, zIndex, attributes); + mg_render_stroke_cubic(canvas, controlPoints, shapeIndex, attributes); endPointIndex = 3; break; @@ -1835,7 +1835,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_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); vec2 points[4] = {{rect.x, rect.y}, {rect.x + rect.w, rect.y}, @@ -1846,7 +1846,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, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); } indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -1858,11 +1858,11 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes) { - //NOTE(martin): stroke a rectangle by fill two scaled rectangles with the same zIndex. + //NOTE(martin): stroke a rectangle by fill two scaled rectangles with the same shapeIndex. u32 baseIndex = mg_vertices_base_index(canvas); i32* indices = mg_reserve_indices(canvas, 12); - u32 zIndex = mg_next_shape(canvas, attributes->color); + u32 shapeIndex = 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)); @@ -1882,13 +1882,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, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); } for(int i=0; i<4; i++) { vec2 pos = mg_mat2x3_mul(canvas->transform, innerPoints[i]); - mg_push_vertex(canvas, pos, cubic, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); } indices[0] = baseIndex + 0; @@ -1905,7 +1905,7 @@ void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribu indices[11] = baseIndex + 7; } -void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32 ry, u32 zIndex, mg_color color) +void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32 ry, u32 shapeIndex, mg_color color) { //NOTE(martin): draw a precomputed arc corner, using a bezier approximation u32 baseIndex = mg_vertices_base_index(canvas); @@ -1927,7 +1927,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], zIndex); + mg_push_vertex(canvas, pos, cubics[i], shapeIndex); } indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -1940,7 +1940,7 @@ void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32 void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas, mg_rounded_rect rect, mg_attributes* attributes, - u32 zIndex) + u32 shapeIndex) { //NOTE(martin): draw a rounded rectangle by drawing a normal rectangle and 4 corners, // approximating an arc by a precomputed bezier curve @@ -1963,7 +1963,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, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); } 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 @@ -1972,10 +1972,10 @@ void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas, indices[i] = fanIndices[i] + baseIndex; } - mg_render_fill_arc_corner(canvas, rect.x, rect.y, rect.r, rect.r, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rect.r, rect.r, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rect.r, -rect.r, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rect.r, -rect.r, zIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x, rect.y, rect.r, rect.r, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rect.r, rect.r, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rect.r, -rect.r, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rect.r, -rect.r, shapeIndex, attributes->color); } @@ -1983,30 +1983,30 @@ void mg_render_rounded_rectangle_fill(mg_canvas_data* canvas, mg_rounded_rect rect, mg_attributes* attributes) { - u32 zIndex = mg_next_shape(canvas, attributes->color); - mg_render_rounded_rectangle_fill_with_z_index(canvas, rect, attributes, zIndex); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); + mg_render_rounded_rectangle_fill_with_z_index(canvas, rect, attributes, shapeIndex); } void mg_render_rounded_rectangle_stroke(mg_canvas_data* canvas, mg_rounded_rect rect, mg_attributes* attributes) { - //NOTE(martin): stroke rounded rectangle by filling two scaled rounded rectangles with the same zIndex + //NOTE(martin): stroke rounded rectangle by filling two scaled rounded rectangles with the same shapeIndex f32 width = minimum(attributes->width, minimum(rect.w, rect.h)); f32 halfW = width/2; 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_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); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); + mg_render_rounded_rectangle_fill_with_z_index(canvas, outer, attributes, shapeIndex); + mg_render_rounded_rectangle_fill_with_z_index(canvas, inner, attributes, shapeIndex); } void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes, - u32 zIndex) + u32 shapeIndex) { //NOTE(martin): draw a filled ellipse by drawing a diamond and 4 corners, // approximating an arc by a precomputed bezier curve @@ -2027,7 +2027,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, zIndex); + mg_push_vertex(canvas, pos, cubic, shapeIndex); } indices[0] = baseIndex + 0; @@ -2037,30 +2037,30 @@ void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas, indices[4] = baseIndex + 2; indices[5] = baseIndex + 3; - mg_render_fill_arc_corner(canvas, rect.x, rect.y, rx, ry, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rx, ry, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rx, -ry, zIndex, attributes->color); - mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rx, -ry, zIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x, rect.y, rx, ry, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rx, ry, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rx, -ry, shapeIndex, attributes->color); + mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rx, -ry, shapeIndex, attributes->color); } void mg_render_ellipse_fill(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes) { - u32 zIndex = mg_next_shape(canvas, attributes->color); - mg_render_ellipse_fill_with_z_index(canvas, rect, attributes, zIndex); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); + mg_render_ellipse_fill_with_z_index(canvas, rect, attributes, shapeIndex); } void mg_render_ellipse_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes) { - //NOTE(martin): stroke by filling two scaled ellipsis with the same zIndex + //NOTE(martin): stroke by filling two scaled ellipsis with the same shapeIndex f32 width = minimum(attributes->width, minimum(rect.w, rect.h)); f32 halfW = width/2; 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_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); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); + mg_render_ellipse_fill_with_z_index(canvas, outer, attributes, shapeIndex); + mg_render_ellipse_fill_with_z_index(canvas, inner, attributes, shapeIndex); } void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect) @@ -2076,7 +2076,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_next_shape(canvas, attributes->color); + u32 shapeIndex = mg_next_shape(canvas, attributes->color); vec2 points[4] = {{rect.x, rect.y}, {rect.x + rect.w, rect.y}, @@ -2096,7 +2096,7 @@ void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect) vec2 transformedUV = {uv[i].x / MG_ATLAS_SIZE, uv[i].y / MG_ATLAS_SIZE}; vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]); - mg_push_textured_vertex(canvas, pos, cubic, transformedUV, color, zIndex); + mg_push_textured_vertex(canvas, pos, cubic, transformedUV, color, shapeIndex); } indices[0] = baseIndex + 0; indices[1] = baseIndex + 1; @@ -2660,7 +2660,7 @@ mg_canvas mg_canvas_create(mg_surface surface) canvasData->primitiveCount = 0; canvasData->path.startIndex = 0; canvasData->path.count = 0; - canvasData->nextZIndex = 1; + canvasData->nextShapeIndex = 1; canvasData->attributes.color = (mg_color){0, 0, 0, 1}; canvasData->attributes.tolerance = 1; canvasData->attributes.width = 10; @@ -2824,9 +2824,9 @@ void mg_flush_batch(mg_canvas_data* canvas) { if(canvas->backend && canvas->backend->drawBatch) { - canvas->backend->drawBatch(canvas->backend, canvas->nextZIndex, canvas->vertexCount, canvas->indexCount); + canvas->backend->drawBatch(canvas->backend, canvas->nextShapeIndex, canvas->vertexCount, canvas->indexCount); } - mg_reset_z_index(canvas); + mg_reset_shape_index(canvas); canvas->vertexCount = 0; canvas->indexCount = 0; } @@ -2843,7 +2843,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt u32 nextIndex = 0; - mg_reset_z_index(canvas); + mg_reset_shape_index(canvas); canvas->transform = (mg_mat2x3){1, 0, 0, 0, 1, 0}; canvas->clip = (mp_rect){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX}; @@ -2881,11 +2881,11 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt case MG_CMD_FILL: { - u32 zIndex = mg_next_shape(canvas, primitive->attributes.color); + u32 shapeIndex = mg_next_shape(canvas, primitive->attributes.color); mg_render_fill(canvas, pathElements + primitive->path.startIndex, &primitive->path, - zIndex, + shapeIndex, primitive->attributes.color); } break; diff --git a/src/graphics_internal.h b/src/graphics_internal.h index d408e77..213634b 100644 --- a/src/graphics_internal.h +++ b/src/graphics_internal.h @@ -212,8 +212,8 @@ typedef struct mg_vertex_layout char* colorBuffer; u32 colorStride; - char* zIndexBuffer; - u32 zIndexStride; + char* shapeIndexBuffer; + u32 shapeIndexStride; char* clipBuffer; u32 clipStride; @@ -268,7 +268,7 @@ typedef struct mg_canvas_data mp_rect clipStack[MG_CLIP_STACK_MAX_DEPTH]; u32 clipStackSize; - u32 nextZIndex; + u32 nextShapeIndex; u32 primitiveCount; mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT]; diff --git a/todo.txt b/todo.txt index 304d691..9cd5903 100644 --- a/todo.txt +++ b/todo.txt @@ -2,7 +2,7 @@ Overview -------- [x] Pan/Zoom on text example -[ ] Clean+Fixes of canvas code and examples +[.] Clean+Fixes of canvas code and examples [ ] Make backend selection easier [ ] Image API and backend @@ -10,7 +10,7 @@ Overview [ ] Baked fonts? [ ] Allow different versions of GL to co-exist -[ ] Backport canvas to GLES +[?] Backport canvas to GLES [ ] Delegated drawing API+Impl @@ -18,16 +18,24 @@ Clean+Fixes ----------- [ ] Clean canvas code [ ] make zIndex implicit when calling push_vertex - [ ] rename zIndex with "shapeIndex" everywhere + [x] rename zIndex with "shapeIndex" everywhere [ ] remove color args in functions that don't need it anymore -[ ] Clean shaders (folder/filenames, version string, debug flags, ...) +[ ] Rename MG_GL_CANVAS_TILE_ARRAY_SIZE/LENGTH unambiguously and make it consistent between C and glsl code -[x] Fix resource loading path in examples (to load font relative to executable) +[.] Clean shaders (folder/filenames, version string, debug flags, ...) + [x] Simplify shader names, prefix embedded strings by "glsl_" + [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) + [!] Check return of compilation and decide how to handle error more cleanly +[!] Clean-up context on error and set error flags in handle + +[ ] 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). -[ ] Clean up surface backend and canvas backend compile-time and run-time selections +Bug hunt +-------- [!] 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... > seems to happen on tile boundaries