From 8e87837fcce495800bdd43682d4d73df3e555f58 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Tue, 31 Jan 2023 15:51:50 +0100 Subject: [PATCH] working on gles 3.1 canvas on windows --- scripts/embed_text.py | 43 ++++ src/gles_canvas.c | 238 ++++++++++++++++++ src/gles_canvas_shaders.h | 58 +++++ .../gles_canvas_fragment.glsl | 29 +++ .../gles_canvas_vertex.glsl | 11 + 5 files changed, 379 insertions(+) create mode 100644 scripts/embed_text.py create mode 100644 src/gles_canvas.c create mode 100644 src/gles_canvas_shaders.h create mode 100644 src/gles_canvas_shaders/gles_canvas_fragment.glsl create mode 100644 src/gles_canvas_shaders/gles_canvas_vertex.glsl diff --git a/scripts/embed_text.py b/scripts/embed_text.py new file mode 100644 index 0000000..006916f --- /dev/null +++ b/scripts/embed_text.py @@ -0,0 +1,43 @@ +import os +from datetime import datetime +from argparse import ArgumentParser + +parser = ArgumentParser() +parser.add_argument("inputFiles", nargs="+") +parser.add_argument("-o", "--output") + +args = parser.parse_args() + +output = open(args.output, "w") +output.write("/*********************************************************************\n") +output.write("*\n") +output.write("*\tfile: %s\n" % os.path.basename(args.output)) +output.write("*\tnote: string literals auto-generated by embed_text.py\n") +output.write("*\tdate: %s\n" % datetime.now().strftime("%d/%m%Y")) +output.write("*\n") +output.write("**********************************************************************/\n") + +outSymbol = (os.path.splitext(os.path.basename(args.output))[0]).upper() + +output.write("#ifndef __%s_H__\n" % outSymbol) +output.write("#define __%s_H__\n" % outSymbol) +output.write("\n\n") + +for fileName in args.inputFiles: + f = open(fileName, "r") + lines = f.read().splitlines() + + output.write("//NOTE: string imported from %s\n" % fileName) + + stringName = os.path.splitext(os.path.basename(fileName))[0] + output.write("const char* %s = " % stringName) + + for line in lines: + output.write("\n\"%s\\n\"" % line) + + output.write(";\n\n") + f.close() + +output.write("#endif // __%s_H__\n" % outSymbol) + +output.close() diff --git a/src/gles_canvas.c b/src/gles_canvas.c new file mode 100644 index 0000000..fb0a0b7 --- /dev/null +++ b/src/gles_canvas.c @@ -0,0 +1,238 @@ +/************************************************************//** +* +* @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 program; + + 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); +} + +void mg_gles_canvas_draw_buffers(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, 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; + } + + //WARN: dummy test code + + indexCount = 3; + *(vec2*)(interface->vertexLayout.posBuffer) = (vec2){400, 300}; + *(vec2*)(interface->vertexLayout.posBuffer + interface->vertexLayout.posStride) = (vec2){450, 300}; + *(vec2*)(interface->vertexLayout.posBuffer + 2*interface->vertexLayout.posStride) = (vec2){400, 350}; + + for(int i=0; i<3; i++) + { + *(vec4*)(interface->vertexLayout.cubicBuffer + i*interface->vertexLayout.cubicStride) = (vec4){1, 1, 1, 1}; + *(vec2*)(interface->vertexLayout.uvBuffer + i*interface->vertexLayout.uvStride) = (vec2){0, 0}; + *(vec4*)(interface->vertexLayout.colorBuffer + i*interface->vertexLayout.colorStride) = (vec4){1, 0, 0, 1}; + *(vec4*)(interface->vertexLayout.clipBuffer + i*interface->vertexLayout.clipStride) = (vec4){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX}; + *(u32*)(interface->vertexLayout.zIndexBuffer + i*interface->vertexLayout.zIndexStride) = 1; + *(u32*)(interface->vertexLayout.indexBuffer + i*interface->vertexLayout.indexStride) = i; + } + + // end dummy test code + + glUseProgram(backend->program); + glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer); + glUniform1i(0, indexCount); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +#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_CUBIC_OFFSET = LayoutNext(POS, VEC2, VEC4), + LAYOUT_UV_OFFSET = LayoutNext(CUBIC, VEC4, VEC2), + LAYOUT_COLOR_OFFSET = LayoutNext(UV, VEC2, 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, +}; + +void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend) +{ + if(backend->vertexMapping) + { + glUnmapBuffer(backend->vertexBuffer); + } + glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer); + backend->vertexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_VERTEX_BUFFER_SIZE, GL_MAP_WRITE_BIT); + + if(backend->indexMapping) + { + free(backend->indexMapping); + } + glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer); + backend->indexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_INDEX_BUFFER_SIZE, GL_MAP_WRITE_BIT); + + 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_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 +} + +void 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.drawBuffers = mg_gles_canvas_draw_buffers; + 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->dummyVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer); + + unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); + unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + backend->program = glCreateProgram(); + + compile_shader(vertexShader, gles_canvas_vertex); + compile_shader(fragmentShader, gles_canvas_fragment); + + glAttachShader(backend->program, vertexShader); + glAttachShader(backend->program, fragmentShader); + glLinkProgram(backend->program); + + int status = 0; + glGetProgramiv(backend->program, GL_LINK_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetProgramInfoLog(backend->program, 256, &size, buffer); + printf("link error: %.*s\n", size, buffer); + } + + glUseProgram(backend->program); + + mg_gles_canvas_update_vertex_layout(backend); + } + + return((mg_canvas_backend*)backend); +} + + +#undef LOG_SUBSYSTEM diff --git a/src/gles_canvas_shaders.h b/src/gles_canvas_shaders.h new file mode 100644 index 0000000..f2bb014 --- /dev/null +++ b/src/gles_canvas_shaders.h @@ -0,0 +1,58 @@ +/********************************************************************* +* +* file: gles_canvas_shaders.h +* note: string literals auto-generated by embed_text.py +* date: 31/012023 +* +**********************************************************************/ +#ifndef __GLES_CANVAS_SHADERS_H__ +#define __GLES_CANVAS_SHADERS_H__ + + +//NOTE: string imported from src\gles_canvas_shaders\gles_canvas_fragment.glsl +const char* gles_canvas_fragment = +"#version 310 es\n" +"\n" +"precision mediump float;\n" +"layout(std430) buffer;\n" +"\n" +"struct vertex {\n" +" vec2 pos;\n" +" vec4 cubic;\n" +" vec2 uv;\n" +" vec4 color;\n" +" vec4 clip;\n" +" int zIndex;\n" +"};\n" +"\n" +"layout(binding = 0) buffer vertexBufferSSBO {\n" +" vertex elements[];\n" +"} vertexBuffer ;\n" +"\n" +"layout(binding = 1) buffer indexBufferSSBO {\n" +" vec2 elements[];\n" +"} indexBuffer ;\n" +"\n" +"layout(location = 0) uniform int indexCount;\n" +"layout(location = 0) out vec4 fragColor;\n" +"\n" +"void main()\n" +"{\n" +" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" +"}\n"; + +//NOTE: string imported from src\gles_canvas_shaders\gles_canvas_vertex.glsl +const char* gles_canvas_vertex = +"#version 310 es\n" +"\n" +"precision mediump float;\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" +"}\n"; + +#endif // __GLES_CANVAS_SHADERS_H__ diff --git a/src/gles_canvas_shaders/gles_canvas_fragment.glsl b/src/gles_canvas_shaders/gles_canvas_fragment.glsl new file mode 100644 index 0000000..53c8ba6 --- /dev/null +++ b/src/gles_canvas_shaders/gles_canvas_fragment.glsl @@ -0,0 +1,29 @@ +#version 310 es + +precision mediump float; +layout(std430) buffer; + +struct vertex { + vec2 pos; + vec4 cubic; + vec2 uv; + vec4 color; + vec4 clip; + int zIndex; +}; + +layout(binding = 0) buffer vertexBufferSSBO { + vertex elements[]; +} vertexBuffer ; + +layout(binding = 1) buffer indexBufferSSBO { + vec2 elements[]; +} indexBuffer ; + +layout(location = 0) uniform int indexCount; +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/gles_canvas_shaders/gles_canvas_vertex.glsl b/src/gles_canvas_shaders/gles_canvas_vertex.glsl new file mode 100644 index 0000000..fb1eb4f --- /dev/null +++ b/src/gles_canvas_shaders/gles_canvas_vertex.glsl @@ -0,0 +1,11 @@ +#version 310 es + +precision mediump float; + +void main() +{ + float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u); + float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u); + + gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f); +}