Desktop opengl 4.3 canvas
This commit is contained in:
parent
91780b12c7
commit
5788cdbcda
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include<math.h>
|
||||
|
||||
#include"milepost.h"
|
||||
#include"win32_gl_surface.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "Main"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
|
@ -1,4 +1,4 @@
|
|||
#version 310 es
|
||||
#version 430
|
||||
|
||||
precision mediump float;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 310 es
|
||||
#version 430
|
||||
|
||||
precision mediump float;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
/*
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include<windows.h>
|
||||
#include<GL/gl.h>
|
||||
#include"GL/glext.h"
|
||||
#include"GL/wglext.h"
|
||||
#include<GL/glext.h>
|
||||
#include<GL/wglext.h>
|
||||
|
||||
#include"macro_helpers.h"
|
||||
|
||||
|
@ -38,7 +38,15 @@
|
|||
GL_PROC(GLBUFFERDATA, glBufferData) \
|
||||
GL_PROC(GLUNIFORMMATRIX4FV, glUniformMatrix4fv) \
|
||||
GL_PROC(GLVERTEXATTRIBPOINTER, glVertexAttribPointer) \
|
||||
GL_PROC(GLENABLEVERTEXATTRIBARRAY, glEnableVertexAttribArray)
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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?
|
||||
|
|
Loading…
Reference in New Issue