From fb60bd5f32cb08a985bbbc2ee389568ffe8fb4da Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Sat, 20 Apr 2024 18:27:56 -0500 Subject: [PATCH] and we have the linux wayland backend usable (sorta) --- justfile | 2 +- shaders/text_atlas_fragment.glsl | 18 +++++++++ shaders/text_atlas_vertex.glsl | 55 +++++++++++++++++++++++++ shaders/ui_rect_fragment.glsl | 2 +- shaders/ui_rect_vertex.glsl | 10 ++--- src/gfx.h | 69 ++++++++++++++++++++++++++------ 6 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 shaders/text_atlas_fragment.glsl create mode 100644 shaders/text_atlas_vertex.glsl diff --git a/justfile b/justfile index face83e..13e309a 100644 --- a/justfile +++ b/justfile @@ -4,7 +4,7 @@ alias r := run c_flags := if os() == "macos" { "$(curl-config --libs) -framework Cocoa -framework QuartzCore -framework CoreImage -framework Metal -framework MetalKit -ObjC" } else if os_family() == "unix" { - "$(curl-config --libs) -lEGL -lGLESv2 -lGL -lm -lwayland-client -lwayland-egl -lX11 -lXi -lXcursor" + "$(curl-config --libs) -lEGL -lGLESv2 -lGL -lm -lwayland-client -lwayland-egl -lX11 -lXi -lXcursor -Wno-implicit-function-declaration" } else { "" } [macos] diff --git a/shaders/text_atlas_fragment.glsl b/shaders/text_atlas_fragment.glsl new file mode 100644 index 0000000..de14d3a --- /dev/null +++ b/shaders/text_atlas_fragment.glsl @@ -0,0 +1,18 @@ +#version 440 core + +struct VertexOutput { + vec4 position; + vec2 tex_coord; +}; + + +layout(location = 0) in VertexOutput out_vertex; +layout(location = 1) uniform highp sampler2D atlas_texture; + +out vec4 color; + +void main() { + float text_color = texture(atlas_texture, out_vertex.tex_coord).r; + + color = vec4(text_color * vec3(1,1,1), text_color); +} diff --git a/shaders/text_atlas_vertex.glsl b/shaders/text_atlas_vertex.glsl new file mode 100644 index 0000000..c404622 --- /dev/null +++ b/shaders/text_atlas_vertex.glsl @@ -0,0 +1,55 @@ +#version 440 core + +struct Vertex { + vec2 position; + vec2 tex_coord; +}; + +struct VertexOutput { + vec4 position; + vec2 tex_coord; +}; + +struct Glyph { + vec2 atlas_position; + vec2 size; + vec2 target_position; + float y_offset; + float _haha_alignment; +}; + +layout(std430, binding = 0) readonly buffer VertexBlock { + Vertex vertices[]; +}; + +layout(std430, binding = 1) readonly buffer GlyphBlock { + Glyph glyphs[]; +}; + +layout(std430, binding = 2) readonly buffer ParamsBlock { + vec2 screen_size; +}; + +vec4 to_device_position(vec2 position, vec2 size) { + return vec4(((position / size) * 2.0) - vec2(1.0), 1.0, 1.0); +} + +layout(location = 0) out VertexOutput out_vertex; + +void main() { + Glyph glyph = glyphs[gl_InstanceID]; + + vec2 scaled_size = ((vertices[gl_VertexID].position + 1.0) / 2.0) * (glyph.size/2.0); + vec2 scaled_size_2 = ((vertices[gl_VertexID].position + 1.0) / 2.0) * (glyph.size); + vec2 glyph_pos = scaled_size + glyph.target_position + vec2(0, glyph.y_offset/2.0+24); + + vec4 device_position = to_device_position(glyph_pos, screen_size); + vec2 atlas_position = (scaled_size_2 + glyph.atlas_position) / 512.0; + + device_position.y = -device_position.y; + + out_vertex.position = device_position; + out_vertex.tex_coord = atlas_position; + + gl_Position = device_position; +} diff --git a/shaders/ui_rect_fragment.glsl b/shaders/ui_rect_fragment.glsl index 21fa67c..50a2eb9 100644 --- a/shaders/ui_rect_fragment.glsl +++ b/shaders/ui_rect_fragment.glsl @@ -1,4 +1,4 @@ -#version 320 es +#version 440 core struct UiRectFragment { highp vec4 device_position; diff --git a/shaders/ui_rect_vertex.glsl b/shaders/ui_rect_vertex.glsl index bddfa3e..3a599df 100644 --- a/shaders/ui_rect_vertex.glsl +++ b/shaders/ui_rect_vertex.glsl @@ -1,4 +1,4 @@ -#version 320 es +#version 440 core struct Vertex { vec2 position; @@ -23,7 +23,7 @@ struct UiRectFragment { }; layout(std430, binding = 0) readonly buffer VertexBlock { - Vertex verticies[]; + Vertex vertices[]; }; layout(std430, binding = 1) readonly buffer RectBlock { @@ -38,13 +38,13 @@ out UiRectFragment out_rect; void main() { UiRect rect = rects[gl_InstanceID]; - out_rect.device_position = vec4(verticies[gl_VertexID].position, 1, 1); + out_rect.device_position = vec4(vertices[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.tex_coord = vertices[gl_VertexID].tex_coord; out_rect.color = rect.color; - gl_Position = vec4(verticies[gl_VertexID].position, 1, 1); + gl_Position = vec4(vertices[gl_VertexID].position, 1, 1); } diff --git a/src/gfx.h b/src/gfx.h index 10debe6..df2938a 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -113,13 +113,15 @@ 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; + GLuint text_atlas_shader_program; + array(GLuint) buffers; + array(GLuint) textures; } _opengl_gfx_context_wayland; static void _opengl_gfx_present_wayland(_opengl_gfx_context_wayland *cx); @@ -942,6 +944,10 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(_opengl_gfx_message_callback, NULL); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + 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( @@ -951,10 +957,23 @@ _opengl_gfx_init_context_wayland(uint32_t width, uint32_t height) { 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); + _String("failed to link ui_rect shader program"), + cx.ui_rect_shader_program, GL_LINK_STATUS); + + cx.text_atlas_vertex_shader = _opengl_gfx_compile_shader( + _String("shaders/text_atlas_vertex.glsl"), GL_VERTEX_SHADER); + cx.text_atlas_fragment_shader = _opengl_gfx_compile_shader( + _String("shaders/text_atlas_fragment.glsl"), GL_FRAGMENT_SHADER); + cx.text_atlas_shader_program = glCreateProgram(); + glAttachShader(cx.text_atlas_shader_program, cx.text_atlas_vertex_shader); + glAttachShader(cx.text_atlas_shader_program, cx.text_atlas_fragment_shader); + glLinkProgram(cx.text_atlas_shader_program); + _opengl_gfx_check_shader_program_error( + _String("failed to link text_atlas shader program"), + cx.text_atlas_shader_program, GL_LINK_STATUS); cx.buffers = newArray(GLuint, 8); + cx.textures = newArray(GLuint, 8); /* ******** */ return cx; @@ -1031,6 +1050,9 @@ static void _opengl_gfx_present_wayland(_opengl_gfx_context_wayland *cx) { gfx_update_buffer(&_gfx_context, 3, &gpu_uniform_params, sizeof(GpuUniformParams)); + 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); if (_gfx_context.gpu_ui_rects.size > 0) { glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cx->buffers.data[0]); @@ -1038,19 +1060,26 @@ static void _opengl_gfx_present_wayland(_opengl_gfx_context_wayland *cx) { 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 (_gfx_context.gpu_glyphs.size > 0) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cx->buffers.data[0]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, cx->buffers.data[2]); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, cx->buffers.data[3]); + glUseProgram(cx->text_atlas_shader_program); - if (eglSwapBuffers(cx->egl_display, cx->egl_surface) != EGL_TRUE) { - fprintf(stderr, "eglSwapBuffers() failed\n"); - } + const uint16_t indices[] = {0, 1, 2, 0, 2, 3}; + glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices, + _gfx_context.gpu_glyphs.size); + } + + glFlush(); + + if (eglSwapBuffers(cx->egl_display, cx->egl_surface) != EGL_TRUE) { + fprintf(stderr, "eglSwapBuffers() failed\n"); } } @@ -1058,8 +1087,21 @@ 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; + pushArray(GLuint, &cx->textures, 0); + glCreateTextures(GL_TEXTURE_2D, 1, + &cx->textures.data[cx->textures.size - 1]); + glTextureParameteri(cx->textures.data[cx->textures.size - 1], + GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTextureParameteri(cx->textures.data[cx->textures.size - 1], + GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTextureStorage2D(cx->textures.data[cx->textures.size - 1], 1, GL_RGBA8, + width, height); + glTextureSubImage2D(cx->textures.data[cx->textures.size - 1], 0, 0, 0, + width, height, GL_RED, GL_UNSIGNED_BYTE, data); + glBindTextureUnit(cx->textures.size - 1, + cx->textures.data[cx->textures.size - 1]); + + return cx->textures.size - 1; } static void @@ -1067,6 +1109,7 @@ _opengl_gfx_resize_texture_buffer_wayland(_opengl_gfx_context_wayland *cx, uint32_t width, size_t texture_index, uint32_t height) { // TODO + assert(false && "_opengl_gfx_resize_texture_buffer_wayland unimplemented"); } size_t _opengl_gfx_push_vertex_buffer_wayland(_opengl_gfx_context_wayland *cx,