[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
This commit is contained in:
martinfouilleul 2023-02-09 16:14:15 +01:00
parent 4a8c77f023
commit 4e816a838b
15 changed files with 713 additions and 780 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

441
src/glsl_shaders.h Normal file
View File

@ -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<sampleCount; i++)\n"
" {\n"
" currentShapeIndex[i] = -1;\n"
" flipCount[i] = 0;\n"
" sampleColor[i] = vec4(0, 0, 0, 0);\n"
" currentColor[i] = vec4(0, 0, 0, 0);\n"
" }\n"
"\n"
" for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)\n"
" {\n"
" uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];\n"
"\n"
" uint i0 = indexBuffer.elements[triangleIndex];\n"
" uint i1 = indexBuffer.elements[triangleIndex+1u];\n"
" uint i2 = indexBuffer.elements[triangleIndex+2u];\n"
"\n"
" ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);\n"
" ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);\n"
" ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);\n"
"\n"
" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n"
" vec4 color = shapeBuffer.elements[shapeIndex].color;\n"
" ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));\n"
"\n"
" //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
" int cw = is_clockwise(p0, p1, p2);\n"
" if(cw < 0)\n"
" {\n"
" uint tmpIndex = i1;\n"
" i1 = i2;\n"
" i2 = tmpIndex;\n"
"\n"
" ivec2 tmpPoint = p1;\n"
" p1 = p2;\n"
" p2 = tmpPoint;\n"
" }\n"
"\n"
" vec4 cubic0 = vertexBuffer.elements[i0].cubic;\n"
" vec4 cubic1 = vertexBuffer.elements[i1].cubic;\n"
" vec4 cubic2 = vertexBuffer.elements[i2].cubic;\n"
"\n"
" int bias0 = is_top_left(p1, p2) ? 0 : -1;\n"
" int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
" int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
"\n"
" for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n"
" {\n"
" ivec2 samplePoint = samplePoints[sampleIndex];\n"
"\n"
" if( samplePoint.x < clip.x\n"
" || samplePoint.x > 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__

View File

@ -1,4 +1,3 @@
#version 430
precision mediump float;

View File

@ -1,4 +1,3 @@
#version 430
precision mediump float;

View File

@ -1,4 +1,4 @@
#version 430
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
precision mediump float;

View File

@ -0,0 +1,14 @@
layout(std430) buffer;
struct vertex {
vec4 cubic;
vec2 pos;
int shapeIndex;
};
struct shape {
vec4 color;
vec4 clip;
vec2 uv;
};

View File

@ -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<sampleCount; i++)
{
currentZIndex[i] = -1;
currentShapeIndex[i] = -1;
flipCount[i] = 0;
sampleColor[i] = vec4(0, 0, 0, 0);
currentColor[i] = vec4(0, 0, 0, 0);
@ -150,9 +136,9 @@ void main()
ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);
ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);
int zIndex = vertexBuffer.elements[i0].zIndex;
vec4 color = shapeBuffer.elements[zIndex].color;
ivec4 clip = ivec4(round((shapeBuffer.elements[zIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 color = shapeBuffer.elements[shapeIndex].color;
ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = is_clockwise(p0, p1, p2);
@ -198,7 +184,7 @@ void main()
float eps = 0.0001;
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
{
if(zIndex == currentZIndex[sampleIndex])
if(shapeIndex == currentShapeIndex[sampleIndex])
{
flipCount[sampleIndex]++;
}
@ -209,7 +195,7 @@ void main()
sampleColor[sampleIndex] = currentColor[sampleIndex];
}
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;
currentZIndex[sampleIndex] = zIndex;
currentShapeIndex[sampleIndex] = shapeIndex;
flipCount[sampleIndex] = 1;
}
}

View File

@ -1,20 +1,7 @@
#version 430
layout(local_size_x = 1, 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[];
@ -41,12 +28,12 @@ layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
int get_zindex(uint tileArrayOffset, uint tileArrayIndex)
int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)
{
uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex];
int zIndex = vertexBuffer.elements[i0].zIndex;
return(zIndex);
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
return(shapeIndex);
}
void main()
@ -59,10 +46,10 @@ void main()
{
for(uint sortIndex = tileArrayIndex; sortIndex > 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;
}
//*/
}

View File

@ -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),

View File

@ -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;

View File

@ -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];

View File

@ -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