diff --git a/build.bat b/build.bat index 0d36a88..48f703a 100644 --- a/build.bat +++ b/build.bat @@ -5,5 +5,5 @@ set gles_shaders=src\gles_canvas_shaders\gles_canvas_blit_vertex.glsl src\gles_c call python scripts\embed_text.py %gles_shaders% --output src\gles_canvas_shaders.h set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers -cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c +cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c lib bin/milepost.obj /OUT:bin/milepost.lib diff --git a/examples/perf_text/build.bat b/examples/perf_text/build.bat index f3cdbf2..beebece 100644 --- a/examples/perf_text/build.bat +++ b/examples/perf_text/build.bat @@ -1,4 +1,4 @@ set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers -cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/perf_text.exe +cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/perf_text.exe diff --git a/examples/perf_text/main.c b/examples/perf_text/main.c index 8daa26b..ec16b43 100644 --- a/examples/perf_text/main.c +++ b/examples/perf_text/main.c @@ -86,7 +86,7 @@ int main() #if defined(OS_MACOS) mg_surface surface = mg_metal_surface_create_for_window(window); #elif defined(OS_WIN64) - mg_surface surface = mg_gles_surface_create_for_window(window); + mg_surface surface = mg_gl_surface_create_for_window(window); #else #error "unsupported OS" #endif diff --git a/examples/triangleGL/build.bat b/examples/triangleGL/build.bat index 3e918f6..f0aee81 100644 --- a/examples/triangleGL/build.bat +++ b/examples/triangleGL/build.bat @@ -1,2 +1,2 @@ -set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext -cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib /out:test.exe +set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext +cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib /out:test.exe diff --git a/examples/triangleGL/main.c b/examples/triangleGL/main.c index 7139f1b..231318f 100644 --- a/examples/triangleGL/main.c +++ b/examples/triangleGL/main.c @@ -13,7 +13,6 @@ #include #include"milepost.h" -#include"win32_gl_surface.h" #define LOG_SUBSYSTEM "Main" diff --git a/examples/win_canvas/build.bat b/examples/win_canvas/build.bat index bf1053a..8a4c8c1 100644 --- a/examples/win_canvas/build.bat +++ b/examples/win_canvas/build.bat @@ -1,3 +1,3 @@ set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers -cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_canvas.exe +cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_canvas.exe diff --git a/examples/win_canvas/main.c b/examples/win_canvas/main.c index 27c693d..202776f 100644 --- a/examples/win_canvas/main.c +++ b/examples/win_canvas/main.c @@ -65,7 +65,7 @@ int main() #if defined(OS_MACOS) mg_surface surface = mg_metal_surface_create_for_window(window); #elif defined(OS_WIN64) - mg_surface surface = mg_gles_surface_create_for_window(window); + mg_surface surface = mg_gl_surface_create_for_window(window); #else #error "unsupported OS" #endif @@ -158,6 +158,7 @@ int main() y += dy; mg_surface_prepare(surface); + // background mg_set_color_rgba(0, 1, 1, 1); mg_clear(); @@ -196,17 +197,9 @@ int main() mg_fill(); //*/ -//* printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n", frameTime, 1./frameTime); -//*/ - -/* - mg_set_color_rgba(1, 1, 0, 1); - mg_rectangle_fill(8, 8, 100, 50); -*/ - mg_flush(); mg_surface_present(surface); diff --git a/ext/angle_install_notes.txt b/ext/angle_install_notes.txt index 8b52fc5..e6609c2 100644 --- a/ext/angle_install_notes.txt +++ b/ext/angle_install_notes.txt @@ -2,8 +2,8 @@ angle install on windows * need Python3 (can install through win app store) * need Windows SDK -* clone depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git -or download and unzip bundle at https://storage.googleapis.com/chrome-infra/depot_tools.zip +* clone depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +or download and unzip bundle at https://storage.googleapis.com/chrome-infra/depot_tools.zip * set depot_tools in path env variable through control panel>System and security>system>advanced system settings * run gclient in a cmd shell @@ -24,8 +24,21 @@ or download and unzip bundle at https://storage.googleapis.com/chrome-infra/depo angle_build_tests = false is_component_build = false + #to get debugging kinda working with renderdoc: + angle_enable_trace = true + angle_enable_annotator_run_time_checks = true + + * autoninja -C out/Debug * wait a while * link with libEGL.dll.lib and libGLESv2.dll.lib -* put libEGL.dll and libGLESv2.dll in same directory as executable \ No newline at end of file +* put libEGL.dll and libGLESv2.dll in same directory as executable + +Debugging +--------- +in renderdoc, set env variables +RENDERDOC_HOOK_EGL 0 (if you want to trace underlying native API) +RENDERDOC_HOOK_EGL 1 (if you want to trace EGL calls. You also need to put libEGL in the renderdoc folder so it's found when capturing stuff. Unfortunately though, that seems to provoke crashes...) + +ANGLE_ENABLE_DEBUG_MARKERS 1 (to turn on debug markers) diff --git a/src/gl_canvas.c b/src/gl_canvas.c new file mode 100644 index 0000000..da18816 --- /dev/null +++ b/src/gl_canvas.c @@ -0,0 +1,451 @@ +/************************************************************//** +* +* @file: gl_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_gl_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_gl_canvas_backend; + +mg_gl_surface* mg_gl_canvas_get_surface(mg_gl_canvas_backend* canvas) +{ + mg_gl_surface* res = 0; + mg_surface_data* data = mg_surface_data_from_handle(canvas->surface); + if(data && data->backend == MG_BACKEND_GL) + { + res = (mg_gl_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_GL_CANVAS_DEFAULT_BUFFER_LENGTH = 1<<20, + MG_GL_CANVAS_VERTEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_VERTEX_SIZE, + MG_GL_CANVAS_INDEX_BUFFER_SIZE = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_INT_SIZE, + MG_GL_CANVAS_TILE_COUNTER_BUFFER_SIZE = 65536, + MG_GL_CANVAS_TILE_ARRAY_SIZE = sizeof(int)*4096, + MG_GL_CANVAS_TILE_ARRAY_BUFFER_SIZE = MG_GL_CANVAS_TILE_COUNTER_BUFFER_SIZE * MG_GL_CANVAS_TILE_ARRAY_SIZE, +}; + +void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend) +{ + backend->interface.vertexLayout = (mg_vertex_layout){ + .maxVertexCount = MG_GL_CANVAS_DEFAULT_BUFFER_LENGTH, + .maxIndexCount = MG_GL_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_gl_send_buffers(mg_gl_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_gl_canvas_begin(mg_canvas_backend* interface) +{ + mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; + mg_gl_surface* surface = mg_gl_canvas_get_surface(backend); + if(!surface) + { + return; + } + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +void mg_gl_canvas_end(mg_canvas_backend* interface) +{ + //NOTE: nothing to do here... +} + +void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor) +{ + mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; + mg_gl_surface* surface = mg_gl_canvas_get_surface(backend); + if(!surface) + { + return; + } + + glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + glClear(GL_COLOR_BUFFER_BIT); +} + +void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount) +{ + mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; + mg_gl_surface* surface = mg_gl_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_gl_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_GL_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_gl_canvas_update_vertex_layout(backend); +} + +void mg_gl_canvas_destroy(mg_canvas_backend* interface) +{ + mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; + + //TODO +} + +void mg_gl_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes) +{ + //TODO +} + +static void mg_gl_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_gl_canvas_create(mg_surface surface) +{ + mg_gl_canvas_backend* backend = 0; + mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); + if(surfaceData && surfaceData->backend == MG_BACKEND_GL) + { + mg_gl_surface* glSurface = (mg_gl_surface*)surfaceData; + + backend = malloc_type(mg_gl_canvas_backend); + memset(backend, 0, sizeof(mg_gl_canvas_backend)); + backend->surface = surface; + + //NOTE(martin): setup interface functions + backend->interface.destroy = mg_gl_canvas_destroy; + backend->interface.begin = mg_gl_canvas_begin; + backend->interface.end = mg_gl_canvas_end; + backend->interface.clear = mg_gl_canvas_clear; + backend->interface.drawBatch = mg_gl_canvas_draw_batch; + backend->interface.atlasUpload = mg_gl_canvas_atlas_upload; + + mg_surface_prepare(surface); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &backend->dummyVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer); + + glGenBuffers(1, &backend->vertexBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer); +// glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GL_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_GL_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_GL_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_GL_CANVAS_TILE_ARRAY_BUFFER_SIZE, 0, GL_DYNAMIC_COPY); + + 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_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); + } + } + + backend->vertexMapping = malloc_array(char, 1<<30); + backend->indexMapping = malloc_array(char, 1<<30); + + mg_gl_canvas_update_vertex_layout(backend); + } + + return((mg_canvas_backend*)backend); +} + + +#undef LOG_SUBSYSTEM diff --git a/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl b/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl index 910bd96..4a51e91 100644 --- a/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl +++ b/src/gles_canvas_shaders/gles_canvas_blit_fragment.glsl @@ -1,4 +1,4 @@ -#version 310 es +#version 430 precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl b/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl index e4af48a..5547012 100644 --- a/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl +++ b/src/gles_canvas_shaders/gles_canvas_blit_vertex.glsl @@ -1,4 +1,4 @@ -#version 310 es +#version 430 precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl b/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl index 9e7fd01..321bf38 100644 --- a/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl +++ b/src/gles_canvas_shaders/gles_canvas_clear_counters.glsl @@ -1,4 +1,4 @@ -#version 310 es +#version 430 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_draw.glsl b/src/gles_canvas_shaders/gles_canvas_draw.glsl index 49a0512..fa0f0ae 100644 --- a/src/gles_canvas_shaders/gles_canvas_draw.glsl +++ b/src/gles_canvas_shaders/gles_canvas_draw.glsl @@ -1,8 +1,8 @@ -#version 310 es +#version 430 layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; precision mediump float; -precision mediump image2D; +//precision mediump image2D; layout(std430) buffer; @@ -59,7 +59,7 @@ void main() const float subPixelFactor = 16.; ivec2 centerPoint = ivec2(round((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor)); -/* +//* const int sampleCount = 8; ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3), centerPoint + ivec2(-1, -3), @@ -69,12 +69,13 @@ void main() centerPoint + ivec2(-7, 1), centerPoint + ivec2(3, -7), centerPoint + ivec2(7, 7)); -*/ +/*/ const int sampleCount = 4; ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6), centerPoint + ivec2(6, 2), centerPoint + ivec2(-6, -2), centerPoint + ivec2(2, -6)); +//*/ //DEBUG /* { diff --git a/src/gles_canvas_shaders/gles_canvas_sort.glsl b/src/gles_canvas_shaders/gles_canvas_sort.glsl index d7648f9..4b58e28 100644 --- a/src/gles_canvas_shaders/gles_canvas_sort.glsl +++ b/src/gles_canvas_shaders/gles_canvas_sort.glsl @@ -1,4 +1,4 @@ -#version 310 es +#version 430 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; precision mediump float; diff --git a/src/gles_canvas_shaders/gles_canvas_tile.glsl b/src/gles_canvas_shaders/gles_canvas_tile.glsl index 5d2d577..a96fe76 100644 --- a/src/gles_canvas_shaders/gles_canvas_tile.glsl +++ b/src/gles_canvas_shaders/gles_canvas_tile.glsl @@ -1,4 +1,4 @@ -#version 310 es +#version 430 layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in; precision mediump float; diff --git a/src/graphics.c b/src/graphics.c index 3747985..d65e094 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -2610,6 +2610,11 @@ mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text) mg_canvas_backend* mg_gles_canvas_create(mg_surface surface); #endif +#ifdef MG_IMPLEMENTS_BACKEND_GL + mg_canvas_backend* mg_gl_canvas_create(mg_surface surface); +#endif + + mg_canvas mg_canvas_create(mg_surface surface) { mg_canvas canvas = mg_canvas_nil(); @@ -2631,11 +2636,9 @@ mg_canvas mg_canvas_create(mg_surface surface) break; #endif - /* - case MG_BACKEND_OPENGL: - canvasData = mg_opengl_canvas_create(surface); + case MG_BACKEND_GL: + backend = mg_gl_canvas_create(surface); break; - */ default: break; } diff --git a/src/milepost.c b/src/milepost.c index 5a6b16c..e252a89 100644 --- a/src/milepost.c +++ b/src/milepost.c @@ -53,9 +53,10 @@ #if defined(OS_WIN64) #include"win32_app.c" -// #include"win32_gl_surface.c" - #include"win32_gles_surface.c" - #include"gles_canvas.c" + #include"win32_gl_surface.c" + #include"gl_canvas.c" +// #include"win32_gles_surface.c" +// #include"gles_canvas.c" #elif defined(OS_MACOS) //NOTE: macos application layer is defined in milepost.m #else diff --git a/src/milepost.h b/src/milepost.h index ed87c6a..e3f5ffc 100644 --- a/src/milepost.h +++ b/src/milepost.h @@ -38,12 +38,18 @@ #include"mp_app.h" #if defined(OS_WIN64) || defined(OS_WIN32) - #define WIN32_GL_LOADER_API -// #include"win32_gl_loader.h" #if MG_IMPLEMENTS_BACKEND_GLES #include"win32_gles_surface.h" #endif + + #if MG_IMPLEMENTS_BACKEND_GL + #define WIN32_GL_LOADER_API + #include"win32_gl_loader.h" + #undef WIN32_GL_LOADER_API + + #include"win32_gl_surface.h" + #endif #endif #if MG_IMPLEMENTS_BACKEND_METAL diff --git a/src/win32_gl_loader.h b/src/win32_gl_loader.h index 24f6ad0..769a924 100644 --- a/src/win32_gl_loader.h +++ b/src/win32_gl_loader.h @@ -1,65 +1,73 @@ -/************************************************************//** -* -* @file: win32_gl_loader.h -* @author: Martin Fouilleul -* @date: 01/08/2022 -* @revision: -* -*****************************************************************/ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include"GL/glext.h" -#include"GL/wglext.h" - -#include"macro_helpers.h" - -#define GL_PROC_LIST \ - GL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \ - GL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \ - GL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \ - GL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \ - GL_PROC(GLCREATESHADER, glCreateShader) \ - GL_PROC(GLCREATEPROGRAM, glCreateProgram) \ - GL_PROC(GLATTACHSHADER, glAttachShader) \ - GL_PROC(GLCOMPILESHADER, glCompileShader) \ - GL_PROC(GLGETSHADERIV, glGetShaderiv) \ - GL_PROC(GLGETSHADERINFOLOG, glGetShaderInfoLog) \ - GL_PROC(GLSHADERSOURCE, glShaderSource) \ - GL_PROC(GLLINKPROGRAM, glLinkProgram) \ - GL_PROC(GLGETPROGRAMIV, glGetProgramiv) \ - GL_PROC(GLGETPROGRAMINFOLOG, glGetProgramInfoLog) \ - GL_PROC(GLUSEPROGRAM, glUseProgram) \ - GL_PROC(GLGENVERTEXARRAYS, glGenVertexArrays) \ - GL_PROC(GLBINDVERTEXARRAY, glBindVertexArray) \ - GL_PROC(GLGENBUFFERS, glGenBuffers) \ - GL_PROC(GLBINDBUFFER, glBindBuffer) \ - GL_PROC(GLBUFFERDATA, glBufferData) \ - GL_PROC(GLUNIFORMMATRIX4FV, glUniformMatrix4fv) \ - GL_PROC(GLVERTEXATTRIBPOINTER, glVertexAttribPointer) \ - GL_PROC(GLENABLEVERTEXATTRIBARRAY, glEnableVertexAttribArray) - -#ifdef WIN32_GL_LOADER_API - //NOTE: pointer declarations - #define GL_PROC(type, name) extern _cat3_(PFN, type, PROC) name; - GL_PROC_LIST - #undef GL_PROC -#endif - - -#ifdef WIN32_GL_LOADER_IMPL -#define GL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0; - GL_PROC_LIST -#undef GL_PROC - -void mp_gl_load_procs() -{ - #define GL_PROC(type, name) name = (_cat3_(PFN, type, PROC))wglGetProcAddress( #name ); - GL_PROC_LIST - #undef GL_PROC -} - -#endif - -#undef GL_PROC_LIST +/************************************************************//** +* +* @file: win32_gl_loader.h +* @author: Martin Fouilleul +* @date: 01/08/2022 +* @revision: +* +*****************************************************************/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include + +#include"macro_helpers.h" + +#define GL_PROC_LIST \ + GL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \ + GL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \ + GL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \ + GL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \ + GL_PROC(GLCREATESHADER, glCreateShader) \ + GL_PROC(GLCREATEPROGRAM, glCreateProgram) \ + GL_PROC(GLATTACHSHADER, glAttachShader) \ + GL_PROC(GLCOMPILESHADER, glCompileShader) \ + GL_PROC(GLGETSHADERIV, glGetShaderiv) \ + GL_PROC(GLGETSHADERINFOLOG, glGetShaderInfoLog) \ + GL_PROC(GLSHADERSOURCE, glShaderSource) \ + GL_PROC(GLLINKPROGRAM, glLinkProgram) \ + GL_PROC(GLGETPROGRAMIV, glGetProgramiv) \ + GL_PROC(GLGETPROGRAMINFOLOG, glGetProgramInfoLog) \ + GL_PROC(GLUSEPROGRAM, glUseProgram) \ + GL_PROC(GLGENVERTEXARRAYS, glGenVertexArrays) \ + GL_PROC(GLBINDVERTEXARRAY, glBindVertexArray) \ + GL_PROC(GLGENBUFFERS, glGenBuffers) \ + GL_PROC(GLBINDBUFFER, glBindBuffer) \ + GL_PROC(GLBUFFERDATA, glBufferData) \ + GL_PROC(GLUNIFORMMATRIX4FV, glUniformMatrix4fv) \ + GL_PROC(GLVERTEXATTRIBPOINTER, glVertexAttribPointer) \ + GL_PROC(GLENABLEVERTEXATTRIBARRAY, glEnableVertexAttribArray) \ + GL_PROC(GLBINDBUFFERBASE, glBindBufferBase) \ + GL_PROC(GLDISPATCHCOMPUTE, glDispatchCompute) \ + GL_PROC(GLUNIFORM1UI, glUniform1ui) \ + GL_PROC(GLUNIFORM2UI, glUniform2ui) \ + GL_PROC(GLBINDIMAGETEXTURE, glBindImageTexture) \ + GL_PROC(GLACTIVETEXTURE, glActiveTexture) \ + GL_PROC(GLUNIFORM1I, glUniform1i) \ + GL_PROC(GLTEXSTORAGE2D, glTexStorage2D) \ + +#ifdef WIN32_GL_LOADER_API + //NOTE: pointer declarations + #define GL_PROC(type, name) extern _cat3_(PFN, type, PROC) name; + GL_PROC_LIST + #undef GL_PROC +#endif + + +#ifdef WIN32_GL_LOADER_IMPL +#define GL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0; + GL_PROC_LIST +#undef GL_PROC + +void mp_gl_load_procs() +{ + #define GL_PROC(type, name) name = (_cat3_(PFN, type, PROC))wglGetProcAddress( #name ); + GL_PROC_LIST + #undef GL_PROC +} + +#endif + +#undef GL_PROC_LIST diff --git a/src/win32_gl_surface.c b/src/win32_gl_surface.c index 1b31e70..f732cdc 100644 --- a/src/win32_gl_surface.c +++ b/src/win32_gl_surface.c @@ -13,12 +13,11 @@ #include"graphics_internal.h" #include"win32_app.h" -#define MG_IMPLEMENTS_BACKEND_GL - typedef struct mg_gl_surface { mg_surface_data interface; + HWND hWnd; HDC hDC; HGLRC glContext; @@ -44,30 +43,15 @@ void mg_gl_surface_present(mg_surface_data* interface) SwapBuffers(surface->hDC); } -PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; -PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; -PFNWGLMAKECONTEXTCURRENTARBPROC wglMakeContextCurrentARB; -PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +mp_rect mg_gl_surface_get_frame(mg_surface_data* interface) +{ + mg_gl_surface* surface = (mg_gl_surface*)interface; + RECT rect = {0}; + GetClientRect(surface->hWnd, &rect); -PFNGLCREATESHADERPROC glCreateShader; -PFNGLCREATEPROGRAMPROC glCreateProgram; -PFNGLATTACHSHADERPROC glAttachShader; -PFNGLCOMPILESHADERPROC glCompileShader; -PFNGLGETSHADERIVPROC glGetShaderiv; -PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; -PFNGLSHADERSOURCEPROC glShaderSource; -PFNGLLINKPROGRAMPROC glLinkProgram; -PFNGLGETPROGRAMIVPROC glGetProgramiv; -PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; -PFNGLUSEPROGRAMPROC glUseProgram; -PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -PFNGLGENBUFFERSPROC glGenBuffers; -PFNGLBINDBUFFERPROC glBindBuffer; -PFNGLBUFFERDATAPROC glBufferData; -PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; -PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; -PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; + mp_rect res = {rect.left, rect.bottom, rect.right - rect.left, rect.bottom - rect.top}; + return(res); +} mg_surface mg_gl_surface_create_for_window(mp_window window) { @@ -130,6 +114,7 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) wglMakeCurrent(dummyDC, dummyGLContext); //NOTE(martin): now load extension functions + /* wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); wglMakeContextCurrentARB = (PFNWGLMAKECONTEXTCURRENTARBPROC)wglGetProcAddress("wglMakeContextCurrentARB"); @@ -154,6 +139,8 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv"); glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer"); glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray"); + */ + mp_gl_load_procs(); //NOTE(martin): now create the true pixel format and gl context int pixelFormatAttrs[] = { @@ -180,6 +167,7 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) int contextAttrs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 3, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0}; HGLRC glContext = wglCreateContextAttribsARB(hDC, dummyGLContext, contextAttrs); @@ -198,7 +186,9 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) //NOTE: make gl context current wglMakeCurrent(hDC, glContext); - wglSwapIntervalEXT(1); + + //TODO: set this back to 1 after testing + wglSwapIntervalEXT(0); //TODO save important info in surface_data and return a handle mg_gl_surface* surface = malloc_type(mg_gl_surface); @@ -206,9 +196,10 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) surface->interface.destroy = mg_gl_surface_destroy; surface->interface.prepare = mg_gl_surface_prepare; surface->interface.present = mg_gl_surface_present; + surface->interface.getFrame = mg_gl_surface_get_frame; //TODO: get/set frame/hidden - + surface->hWnd = windowData->win32.hWnd; surface->hDC = hDC; surface->glContext = glContext; diff --git a/src/win32_gl_surface.h b/src/win32_gl_surface.h index a212b03..1e130ee 100644 --- a/src/win32_gl_surface.h +++ b/src/win32_gl_surface.h @@ -9,6 +9,8 @@ #ifndef __WIN32_GL_SURFACE_H_ #define __WIN32_GL_SURFACE_H_ +#include"graphics.h" + mg_surface mg_gl_surface_create_for_window(mp_window window); #endif // __WIN32_GL_SURFACE_H_ diff --git a/vector_renderer_notes.txt b/vector_renderer_notes.txt index b884241..d3a79e5 100644 --- a/vector_renderer_notes.txt +++ b/vector_renderer_notes.txt @@ -68,3 +68,15 @@ Notes: * Doing glBufferData from a small build buffer is surprisingly slow... * Angle seems to take into account only the first call to glBufferData to allocate size, and then send the full buffer??? * Not pre-allocating in creation procedure "solves" the problem with glBufferData... + +Only way seems to be to reduce buffer size: + * pack vec2 together to avoid padding + * store color, clip and uv out of band? + * eg have a shape buffer containing uv for bounding box, clip, and color? + * could also still store color as an int "for free" next to shape index + * could send pos and uv as half-floats? + +Ideally, we would do the vertex computation on the GPU (opportunity to parallelize AND avoid sending vertex buffer...) + +-> Problem profiling canvas renderer with angle (not really well supported in renderdoc) + -> Maybe use an OpenGL backend instead?