From 85df8265b0e16deb1d5121dfaeefdc8001c7ee9e Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Fri, 19 Apr 2024 01:16:16 -0500 Subject: [PATCH] use opengl instead of egl lol --- shaders/ui_rect_fragment.glsl | 19 ++++ shaders/ui_rect_vertex.glsl | 50 +++++++++ src/ed_array.h | 137 +++++++++++++------------ src/gfx.h | 184 +++++++++++++++++++++++++++++----- src/main.c | 4 +- 5 files changed, 302 insertions(+), 92 deletions(-) create mode 100644 shaders/ui_rect_fragment.glsl create mode 100644 shaders/ui_rect_vertex.glsl diff --git a/shaders/ui_rect_fragment.glsl b/shaders/ui_rect_fragment.glsl new file mode 100644 index 0000000..7b2c372 --- /dev/null +++ b/shaders/ui_rect_fragment.glsl @@ -0,0 +1,19 @@ +#version 320 es + +struct UiRectFragment { + highp vec4 device_position; + highp vec2 position; + highp vec2 size; + highp vec2 border_size; + highp vec2 screen_size; + highp vec2 tex_coord; + highp vec4 color; +}; + +in UiRectFragment out_rect; + +layout(location = 0) out highp vec4 color; + +void main() { + color = out_rect.color; +} diff --git a/shaders/ui_rect_vertex.glsl b/shaders/ui_rect_vertex.glsl new file mode 100644 index 0000000..bddfa3e --- /dev/null +++ b/shaders/ui_rect_vertex.glsl @@ -0,0 +1,50 @@ +#version 320 es + +struct Vertex { + vec2 position; + vec2 tex_coord; +}; + +struct UiRect { + vec4 position; + vec4 size; + vec4 border_size; + vec4 color; +}; + +struct UiRectFragment { + highp vec4 device_position; + highp vec2 position; + highp vec2 size; + highp vec2 border_size; + highp vec2 screen_size; + highp vec2 tex_coord; + highp vec4 color; +}; + +layout(std430, binding = 0) readonly buffer VertexBlock { + Vertex verticies[]; +}; + +layout(std430, binding = 1) readonly buffer RectBlock { + UiRect rects[]; +}; +layout(std430, binding = 2) readonly buffer ParamsBlock { + vec2 screen_size; +}; + +out UiRectFragment out_rect; + +void main() { + UiRect rect = rects[gl_InstanceID]; + + out_rect.device_position = vec4(verticies[gl_VertexID].position, 1, 1); + out_rect.position = rect.position.xy; + out_rect.size = rect.size.xy; + out_rect.border_size = rect.border_size.xy; + out_rect.screen_size = screen_size; + out_rect.tex_coord = verticies[gl_VertexID].tex_coord; + out_rect.color = rect.color; + + gl_Position = vec4(verticies[gl_VertexID].position, 1, 1); +} diff --git a/src/ed_array.h b/src/ed_array.h index 025223e..a7b196e 100644 --- a/src/ed_array.h +++ b/src/ed_array.h @@ -1,80 +1,85 @@ #ifndef ED_ARRAY_INCLUDED #define ED_ARRAY_INCLUDED -#include -#include #include #include +#include +#include -#define array(T) struct T ## _Array -#define arrayTemplate(T) array(T) {\ - size_t size, capacity;\ - T *data;\ -};\ -array(T) T ## _ArrayConstruct(size_t size) {\ - array(T) this;\ - this.size = 0;\ - this.capacity = size;\ - this.data = malloc(size * sizeof(T));\ - if (!this.data) {\ - assert("failed to allocate memory for array");\ - }\ - return this;\ -};\ -void T ## _PushArray(array(T) *arr, T value) {\ - if (arr->size+1 <= arr->capacity) {\ - arr->data[arr->size] = value;\ - arr->size += 1;\ - } else {\ - fprintf(stderr, "failed to push to u8 array, size+num > capacity\n");\ - }\ -};\ -void T ## _PushArrayMulti(array(T) *arr, T *values, size_t len) {\ - for (size_t i = 0; i < len; ++i) {\ - T ## _PushArray(arr, values[i]);\ - }\ -};\ -void T ## _InsertArrayAt(array(T) *arr, size_t loc, T value) {\ - if (arr->size == arr->capacity) {\ - arr->capacity *= 2;\ - void *new_data = realloc(arr->data, arr->capacity);\ - if (new_data == NULL) {\ - fprintf(stderr, "out of memory when reallocating array\n");\ - }\ - arr->data = new_data;\ - }\ - memcpy(&arr->data[loc+1], &arr->data[loc], arr->size * sizeof(T));\ - arr->data[loc] = value;\ - arr->size += 1;\ -}; +#define array(T) struct T##_Array +#define arrayTemplate(T) \ + array(T) { \ + size_t size, capacity; \ + T *data; \ + }; \ + array(T) T##_ArrayConstruct(size_t size) { \ + array(T) this; \ + this.size = 0; \ + this.capacity = size; \ + this.data = malloc(size * sizeof(T)); \ + if (!this.data) { \ + assert("failed to allocate memory for array"); \ + } \ + return this; \ + }; \ + void T##_PushArray(array(T) * arr, T value) { \ + if (arr->size + 1 <= arr->capacity) { \ + arr->data[arr->size] = value; \ + arr->size += 1; \ + } else { \ + fprintf(stderr, \ + "failed to push to u8 array, size+num > capacity\n"); \ + } \ + }; \ + void T##_PushArrayMulti(array(T) * arr, T * values, size_t len) { \ + for (size_t i = 0; i < len; ++i) { \ + T##_PushArray(arr, values[i]); \ + } \ + }; \ + void T##_InsertArrayAt(array(T) * arr, size_t loc, T value) { \ + if (arr->size == arr->capacity) { \ + arr->capacity *= 2; \ + void *new_data = realloc(arr->data, arr->capacity); \ + if (new_data == NULL) { \ + fprintf(stderr, "out of memory when reallocating array\n"); \ + } \ + arr->data = new_data; \ + } \ + memcpy(&arr->data[loc + 1], &arr->data[loc], arr->size * sizeof(T)); \ + arr->data[loc] = value; \ + arr->size += 1; \ + }; -#define slice(T) struct T ## _Slice -#define sliceTemplate(T) slice(T) {\ - size_t len;\ - T *data;\ -};\ -array(T) T ## _FromSlice(slice(T) s) {\ - array(T) arr = T ## _ArrayConstruct(s.len);\ - memcpy(arr.data, s.data, sizeof(T) * s.len);\ - arr.size = s.len;\ - return arr;\ -}\ -slice(T) T ## _SliceConstruct(void *data, size_t len) {\ - slice(T) this;\ - this.len = len;\ - this.data = data;\ - return this;\ -} +#define slice(T) struct T##_Slice +#define sliceTemplate(T) \ + slice(T) { \ + size_t len; \ + T *data; \ + }; \ + array(T) T##_FromSlice(slice(T) s) { \ + array(T) arr = T##_ArrayConstruct(s.len); \ + memcpy(arr.data, s.data, sizeof(T) * s.len); \ + arr.size = s.len; \ + return arr; \ + } \ + slice(T) T##_SliceConstruct(void *data, size_t len) { \ + slice(T) this; \ + this.len = len; \ + this.data = data; \ + return this; \ + } -#define newArray(T, size) T ## _ArrayConstruct(size) -#define newArrayFromSlice(T, s) T ## _FromSlice(s) -#define pushArray(T, arr, value) T ## _PushArray(arr, (value)) -#define pushArrayMulti(T, arr, values, len) T ## _PushArrayMulti(arr, values, len) +#define newArray(T, size) T##_ArrayConstruct(size) +#define newArrayFromSlice(T, s) T##_FromSlice(s) +#define pushArray(T, arr, value) T##_PushArray(arr, (value)) +#define pushArrayMulti(T, arr, values, len) T##_PushArrayMulti(arr, values, len) -#define insertArrayAt(T, arr, loc, value) T ## _InsertArrayAt(arr, loc, (value)) +#define insertArrayAt(T, arr, loc, value) T##_InsertArrayAt(arr, loc, (value)) -#define newSlice(T, data, len) T ## _SliceConstruct(data, len) +#define newSlice(T, data, len) T##_SliceConstruct(data, len) arrayTemplate(uint8_t); sliceTemplate(uint8_t); +arrayTemplate(uint32_t); +sliceTemplate(uint32_t); #endif diff --git a/src/gfx.h b/src/gfx.h index 2922345..10debe6 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -85,7 +85,10 @@ typedef struct { #include #include +#include "file_io.h" + // And I thought MacOS needed a lot of state to create a window +arrayTemplate(GLuint); typedef struct { struct wl_display *display; struct wl_registry *registry; @@ -99,6 +102,7 @@ typedef struct { struct xdg_toplevel *xdg_toplevel; struct wl_seat *seat; struct wl_pointer *pointer; + uint8_t *pixels; EGLDisplay egl_display; EGLConfig egl_config; @@ -108,8 +112,18 @@ typedef struct { int mouse_x, mouse_y; int mouse_left_down, mouse_right_down; + + GLuint vao; + GLuint ui_rect_vertex_shader; + GLuint ui_rect_fragment_shader; + GLuint text_atlas_vertex_shader; + GLuint text_atlas_fragment_shader; + GLuint ui_rect_shader_program; + array(GLuint) buffers; } _opengl_gfx_context_wayland; +static void _opengl_gfx_present_wayland(_opengl_gfx_context_wayland *cx); + typedef struct { Display *display; Window window; @@ -734,6 +748,71 @@ static const struct wl_registry_listener registry_listener = { _wayland_registry_handle_global_remove, }; +static void _opengl_gfx_message_callback(GLenum source, GLenum type, GLenum id, + GLenum severity, GLsizei length, + const GLchar *message, + const void *user_param) { + fprintf(stderr, + "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", + type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "", type, severity, + message); +} + +static void _opengl_gfx_check_shader_error(string msg, GLuint shader, + GLuint status) { + GLint good = 0; + glGetShaderiv(shader, status, &good); + if (good == GL_FALSE) { + GLint max_length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); + + uint8_t *log_buffer = malloc(max_length + 1); + glGetShaderInfoLog(shader, max_length, &max_length, log_buffer); + glDeleteShader(shader); + + fprintf(stderr, "%.*s: %.*s\n", msg.len, msg.data, max_length, + log_buffer); + exit(1); + } +} + +static void _opengl_gfx_check_shader_program_error(string msg, + GLuint shader_program, + GLuint status) { + GLint good = 0; + glGetProgramiv(shader_program, status, &good); + if (good == GL_FALSE) { + GLint max_length = 0; + glGetProgramiv(shader_program, GL_INFO_LOG_LENGTH, &max_length); + + uint8_t *log_buffer = malloc(max_length + 1); + glGetProgramInfoLog(shader_program, max_length, &max_length, + log_buffer); + glDeleteProgram(shader_program); + + fprintf(stderr, "%.*s: %.*s\n", msg.len, msg.data, max_length, + log_buffer); + exit(1); + } +} + +static GLuint _opengl_gfx_compile_shader(string file_path, GLuint shader_type) { + GLuint shader = glCreateShader(shader_type); + size_t shader_file_size = get_file_size(file_path); + uint8_t *shader_file_data = malloc(shader_file_size + 1); + load_file(file_path, shader_file_size, shader_file_data); + shader_file_data[shader_file_size] = 0; + // fprintf(stderr, "%s\n", shader_file_data); + + glShaderSource(shader, 1, &shader_file_data, NULL); + glCompileShader(shader); + + _opengl_gfx_check_shader_error(_String("failed to compile shader"), shader, + GL_COMPILE_STATUS); + + return shader; +} + static _opengl_gfx_context_wayland _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { _opengl_gfx_context_wayland cx = {0}; @@ -773,10 +852,10 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { int fd = syscall(SYS_memfd_create, "buffer", 0); ftruncate(fd, buffer_size); - uint8_t *data = + cx.pixels = mmap(NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - for (int i = 0; i < buffer_size; ++i) { - data[i] = 255; + for (int i = 0; i < buffer_size; i++) { + cx.pixels[i] = 0; } cx.shared_memory_pool = @@ -805,7 +884,7 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { 8, // EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, + EGL_OPENGL_BIT, // EGL_NONE, }; @@ -813,7 +892,7 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - cx.egl_display = eglGetDisplay((EGLNativeDisplayType)cx.display); + cx.egl_display = eglGetDisplay(cx.display); if (cx.egl_display == EGL_NO_DISPLAY) { fprintf(stderr, "Failed to create EGL display\n"); exit(1); @@ -842,6 +921,7 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { break; } + eglBindAPI(EGL_OPENGL_API); cx.egl_context = eglCreateContext(cx.egl_display, cx.egl_config, EGL_NO_CONTEXT, context_attribs); @@ -859,13 +939,22 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { fprintf(stderr, "eglMakeCurrent() failed\n"); } - glClearColor(1.0f, 0.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - glFlush(); + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(_opengl_gfx_message_callback, NULL); - if (eglSwapBuffers(cx.egl_display, cx.egl_surface) != EGL_TRUE) { - fprintf(stderr, "eglSwapBuffers() failed\n"); - } + cx.ui_rect_vertex_shader = _opengl_gfx_compile_shader( + _String("shaders/ui_rect_vertex.glsl"), GL_VERTEX_SHADER); + cx.ui_rect_fragment_shader = _opengl_gfx_compile_shader( + _String("shaders/ui_rect_fragment.glsl"), GL_FRAGMENT_SHADER); + cx.ui_rect_shader_program = glCreateProgram(); + glAttachShader(cx.ui_rect_shader_program, cx.ui_rect_vertex_shader); + glAttachShader(cx.ui_rect_shader_program, cx.ui_rect_fragment_shader); + glLinkProgram(cx.ui_rect_shader_program); + _opengl_gfx_check_shader_program_error( + _String("failed to link shader program"), cx.ui_rect_shader_program, + GL_LINK_STATUS); + + cx.buffers = newArray(GLuint, 8); /* ******** */ return cx; @@ -898,11 +987,8 @@ static _opengl_gfx_context_x11 _opengl_gfx_init_context_11(uint32_t width, static void _opengl_gfx_send_events_wayland(_opengl_gfx_context_wayland *cx) { wl_display_dispatch(cx->display); - // TODO: move this to present() - _gfx_context.gpu_glyphs.size = 0; - _gfx_context.gpu_ui_rects.size = 0; - _gfx_context.frame_func(cx->mouse_x, cx->mouse_y, cx->mouse_left_down, - cx->mouse_right_down); + // TODO: don't just render like crazy, limit framerate + _opengl_gfx_present_wayland(cx); } static void _opengl_gfx_send_events_x11(_opengl_gfx_context_x11 *cx) { @@ -921,14 +1007,57 @@ static void _opengl_gfx_send_events_x11(_opengl_gfx_context_x11 *cx) { } static void _opengl_gfx_present_wayland(_opengl_gfx_context_wayland *cx) { - // TODO + _gfx_context.gpu_glyphs.size = 0; + _gfx_context.gpu_ui_rects.size = 0; + _gfx_context.frame_func(cx->mouse_x, cx->mouse_y, cx->mouse_left_down, + cx->mouse_right_down); + + if (_gfx_context.gpu_glyphs.size > 0) { + gfx_update_buffer(&_gfx_context, 2, _gfx_context.gpu_glyphs.data, + _gfx_context.gpu_glyphs.size * sizeof(GpuGlyph)); + } + if (_gfx_context.gpu_ui_rects.size > 0) { + gfx_update_buffer(&_gfx_context, 4, _gfx_context.gpu_ui_rects.data, + _gfx_context.gpu_ui_rects.size * sizeof(GpuUiRect)); + } + + GpuUniformParams gpu_uniform_params = { + .screen_size = + { + (float)_gfx_context.frame_width, + (float)_gfx_context.frame_height, + }, + }; + + gfx_update_buffer(&_gfx_context, 3, &gpu_uniform_params, + sizeof(GpuUniformParams)); + + if (_gfx_context.gpu_ui_rects.size > 0) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cx->buffers.data[0]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, cx->buffers.data[4]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, cx->buffers.data[3]); + glUseProgram(cx->ui_rect_shader_program); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, _gfx_context.frame_width, _gfx_context.frame_height); + + const uint16_t indices[] = {0, 1, 2, 0, 2, 3}; + glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices, + _gfx_context.gpu_ui_rects.size); + + glFlush(); + + if (eglSwapBuffers(cx->egl_display, cx->egl_surface) != EGL_TRUE) { + fprintf(stderr, "eglSwapBuffers() failed\n"); + } + } } static size_t _opengl_gfx_push_texture_buffer_wayland(_opengl_gfx_context_wayland *cx, uint32_t width, uint32_t height, const void *data, size_t len) { - // TODO return 0; } @@ -942,20 +1071,27 @@ _opengl_gfx_resize_texture_buffer_wayland(_opengl_gfx_context_wayland *cx, size_t _opengl_gfx_push_vertex_buffer_wayland(_opengl_gfx_context_wayland *cx, const void *data, size_t len) { + pushArray(GLuint, &cx->buffers, 0); + glCreateBuffers(1, &cx->buffers.data[cx->buffers.size - 1]); + glNamedBufferStorage(cx->buffers.data[cx->buffers.size - 1], len, data, + GL_DYNAMIC_STORAGE_BIT); - // TODO - return 0; + return cx->buffers.size - 1; } static size_t _opengl_gfx_allocate_vertex_buffer_wayland(_opengl_gfx_context_wayland *cx, size_t len) { - // TODO - return 0; + pushArray(GLuint, &cx->buffers, 0); + glCreateBuffers(1, &cx->buffers.data[cx->buffers.size - 1]); + glNamedBufferStorage(cx->buffers.data[cx->buffers.size - 1], len, (void *)0, + GL_DYNAMIC_STORAGE_BIT); + + return cx->buffers.size - 1; } static void _opengl_gfx_update_buffer_wayland(_opengl_gfx_context_wayland *cx, size_t buffer_index, const void *data, size_t len) { - // TODO + glNamedBufferSubData(cx->buffers.data[buffer_index], 0, len, data); } #endif @@ -1072,7 +1208,7 @@ void *gfx_init_context(_gfx_frame_func frame_func, uint32_t width, _gfx_context.gpu_glyphs = newArray(GpuGlyph, 8192 * 32); _gfx_context.glyph_cache = newArray(GpuGlyph, 97); - float vertices[] = { + const float vertices[] = { // positions texture coords -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, diff --git a/src/main.c b/src/main.c index 4fad040..94bb8d8 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,7 @@ static struct { gfx_context_t *gfx_cx; } state; -void ed_init(_gfx_frame_func frame_func) { +void init(_gfx_frame_func frame_func) { state.gfx_cx = gfx_init_context(frame_func, 640, 480); state.ui_cx = ui_init_context(); @@ -211,7 +211,7 @@ int main(int argc, char *argv[]) { return 0; */ - ed_init(ed_frame); + init(ed_frame); while (keep_running) { gfx_run_events(state.gfx_cx);