egl backend for linux backend of opengl backend of render

This commit is contained in:
Ryan Fleury
2025-05-10 11:04:59 -07:00
parent ab5c47a0fd
commit b9350c867c
10 changed files with 402 additions and 158 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ gcc_out="-o"
# --- Per-Build Settings ------------------------------------------------------
link_dll="-fPIC"
link_os_gfx="-lX11 -lXext"
link_render="-lGL"
link_render="-lGL -lEGL"
# --- Choose Compile/Link Lines -----------------------------------------------
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
+1 -1
View File
@@ -60,7 +60,7 @@ commands =
//- rjf: running target
// .f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f3 = { .win = "wsl /mnt/c/devel/raddebugger/build/ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: local target builds
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+6 -1
View File
@@ -497,7 +497,12 @@ os_set_cursor(OS_Cursor cursor)
internal void
os_graphical_message(B32 error, String8 title, String8 message)
{
if(error)
{
fprintf(stderr, "[X] ");
}
fprintf(stderr, "%.*s\n", str8_varg(title));
fprintf(stderr, "%.*s\n\n", str8_varg(message));
}
////////////////////////////////
@@ -0,0 +1,160 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal VoidProc *
r_ogl_os_load_procedure(char *name)
{
VoidProc *result = (VoidProc *)eglGetProcAddress(name);
return result;
}
internal void
r_ogl_os_init(CmdLine *cmdln)
{
//- rjf: set up state
{
Arena *arena = arena_alloc();
r_ogl_lnx_state = push_array(arena, R_OGL_LNX_State, 1);
r_ogl_lnx_state->arena = arena;
}
//- rjf: get EGL display
{
r_ogl_lnx_state->display = eglGetDisplay((EGLNativeDisplayType)os_lnx_gfx_state->display);
if(r_ogl_lnx_state->display == EGL_NO_DISPLAY)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Failed to get EGL display."));
os_abort(1);
}
}
//- rjf: initialize GL version
EGLint egl_version_major = 0;
EGLint egl_version_minor = 0;
if(!eglInitialize(r_ogl_lnx_state->display, &egl_version_major, &egl_version_minor))
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't initialize EGL display."));
os_abort(1);
}
if(egl_version_major < 1 || (egl_version_major == 1 && egl_version_minor < 5))
{
Temp scratch = scratch_begin(0, 0);
String8 message = push_str8f(scratch.arena, "Unsupported EGL version (%i.%i, need at least 1.5)", egl_version_major, egl_version_minor);
os_graphical_message(1, str8_lit("Fatal Error"), message);
os_abort(1);
scratch_end(scratch);
}
//- rjf: pick GL API
if(!eglBindAPI(EGL_OPENGL_API))
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't initialize EGL API to OpenGL."));
os_abort(1);
}
//- rjf: set up EGL config
{
EGLint options[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_CONFORMANT, EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE,
};
EGLint config_count = 0;
if(!eglChooseConfig(r_ogl_lnx_state->display, options, &r_ogl_lnx_state->config, 1, &config_count) || config_count != 1)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't choose EGL configuration."));
os_abort(1);
}
}
//- rjf: construct context
{
B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug"));
#if BUILD_DEBUG
debug_mode = 1;
#endif
EGLint options[] =
{
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 3,
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
debug_mode ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE,
EGL_NONE,
};
r_ogl_lnx_state->context = eglCreateContext(r_ogl_lnx_state->display, r_ogl_lnx_state->config, EGL_NO_CONTEXT, options);
if(r_ogl_lnx_state->context == EGL_NO_CONTEXT)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't create OpenGL context with EGL."));
os_abort(1);
}
}
eglMakeCurrent(r_ogl_lnx_state->display, 0, 0, r_ogl_lnx_state->context);
}
internal R_Handle
r_ogl_os_window_equip(OS_Handle window)
{
OS_LNX_Window *window_os = (OS_LNX_Window *)window.u64[0];
R_OGL_LNX_Window *w = r_ogl_lnx_state->free_window;
if(w != 0)
{
SLLStackPop(r_ogl_lnx_state->free_window);
}
else
{
w = push_array(r_ogl_lnx_state->arena, R_OGL_LNX_Window, 1);
}
{
EGLint options[] =
{
EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR,
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE,
};
w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, window_os->window, options);
if(w->surface == EGL_NO_SURFACE)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't create EGL surface."));
os_abort(1);
}
}
R_Handle result = {(U64)w};
return result;
}
internal void
r_ogl_os_window_unequip(OS_Handle os, R_Handle r)
{
R_OGL_LNX_Window *w = (R_OGL_LNX_Window *)r.u64[0];
{
}
SLLStackPush(r_ogl_lnx_state->free_window, w);
}
internal void
r_ogl_os_select_window(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0];
eglMakeCurrent(r_ogl_lnx_state->display, w_r->surface, w_r->surface, r_ogl_lnx_state->context);
}
internal void
r_ogl_os_window_swap(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0];
eglSwapBuffers(r_ogl_lnx_state->display, w_r->surface);
}
@@ -0,0 +1,35 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RENDER_OPENGL_LINUX_EGL_H
#define RENDER_OPENGL_LINUX_EGL_H
#define glTexImage3D glTexImage3D__static
#define glTexSubImage3D glTexSubImage3D__static
#define glActiveTexture glActiveTexture__static
#include <GL/gl.h>
#include <EGL/egl.h>
#undef glTexImage3D
#undef glTexSubImage3D
#undef glActiveTexture
typedef struct R_OGL_LNX_Window R_OGL_LNX_Window;
struct R_OGL_LNX_Window
{
R_OGL_LNX_Window *next;
EGLSurface *surface;
};
typedef struct R_OGL_LNX_State R_OGL_LNX_State;
struct R_OGL_LNX_State
{
Arena *arena;
EGLDisplay *display;
EGLConfig config;
EGLContext *context;
R_OGL_LNX_Window *free_window;
};
global R_OGL_LNX_State *r_ogl_lnx_state = 0;
#endif // RENDER_OPENGL_LINUX_EGL_H
@@ -0,0 +1,110 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal VoidProc *
r_ogl_os_load_procedure(char *name)
{
VoidProc *result = (VoidProc *)glXGetProcAddressARB((U8 *)name);
return result;
}
internal void
r_ogl_os_init(CmdLine *cmdln)
{
//- rjf: require GLX 1.3+
int glx_version_major = 0;
int glx_version_minor = 0;
if(!glXQueryVersion(os_lnx_gfx_state->display, &glx_version_major, &glx_version_minor) ||
(glx_version_major == 1 && glx_version_minor < 3) ||
glx_version_major < 1)
{
Temp scratch = scratch_begin(0, 0);
String8 message = push_str8f(scratch.arena, "Unsupported GLX version (%i.%i, need at least 1.3)", glx_version_major, glx_version_minor);
os_graphical_message(1, str8_lit("Fatal Error"), message);
os_abort(1);
scratch_end(scratch);
}
//- rjf: get frame buffer configs
local_persist int framebuffer_config_options[] =
{
GLX_X_RENDERABLE, 1,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, 1,
None
};
int framebuffer_configs_count = 0;
GLXFBConfig *framebuffer_configs = glXChooseFBConfig(os_lnx_gfx_state->display, DefaultScreen(os_lnx_gfx_state->display), framebuffer_config_options, &framebuffer_configs_count);
if(framebuffer_configs == 0)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Could not find a suitable framebuffer configuration."));
os_abort(1);
}
GLXFBConfig framebuffer_config = framebuffer_configs[0];
XFree(framebuffer_configs);
//- rjf: get visual info; create color map
XVisualInfo *visual_info = glXGetVisualFromFBConfig(os_lnx_gfx_state->display, framebuffer_config);
Colormap cmap = XCreateColormap(os_lnx_gfx_state->display, RootWindow(os_lnx_gfx_state->display, visual_info->screen), visual_info->visual, AllocNone);
//- rjf: construct set-window-attributes
XSetWindowAttributes set_window_attributes = {0};
set_window_attributes.background_pixmap = None;
set_window_attributes.border_pixel = 0;
set_window_attributes.event_mask = StructureNotifyMask;
//- rjf: construct context
{
B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug"));
#if BUILD_DEBUG
debug_mode = 1;
#endif
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((U8 *)"glXCreateContextAttribsARB");
int context_options[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_FLAGS_ARB, !!debug_mode*GLX_CONTEXT_DEBUG_BIT_ARB,
None
};
r_ogl_lnx_ctx = glXCreateContextAttribsARB(os_lnx_gfx_state->display, framebuffer_config, 0, 1, context_options);
}
glXMakeCurrent(os_lnx_gfx_state->display, RootWindow(os_lnx_gfx_state->display, visual_info->screen), r_ogl_lnx_ctx);
}
internal R_Handle
r_ogl_os_window_equip(OS_Handle window)
{
R_Handle result = {0};
return result;
}
internal void
r_ogl_os_window_unequip(OS_Handle os, R_Handle r)
{
}
internal void
r_ogl_os_select_window(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
glXMakeCurrent(os_lnx_gfx_state->display, w->window, r_ogl_lnx_ctx);
}
internal void
r_ogl_os_window_swap(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
glXSwapBuffers(os_lnx_gfx_state->display, w->window);
}
@@ -0,0 +1,25 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RENDER_OPENGL_LINUX_GLX_H
#define RENDER_OPENGL_LINUX_GLX_H
#define glTexImage3D glTexImage3D__static
#define glTexSubImage3D glTexSubImage3D__static
#define glActiveTexture glActiveTexture__static
#include <GL/gl.h>
#include <GL/glx.h>
#undef glTexImage3D
#undef glTexSubImage3D
#undef glActiveTexture
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
global GLXContext r_ogl_lnx_ctx = 0;
#endif // RENDER_OPENGL_LINUX_GLX_H
+8 -105
View File
@@ -1,110 +1,13 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal VoidProc *
r_ogl_os_load_procedure(char *name)
{
VoidProc *result = (VoidProc *)glXGetProcAddressARB((U8 *)name);
return result;
}
////////////////////////////////
//~ rjf: Backend Includes
internal void
r_ogl_os_init(CmdLine *cmdln)
{
//- rjf: require GLX 1.3+
int glx_version_major = 0;
int glx_version_minor = 0;
if(!glXQueryVersion(os_lnx_gfx_state->display, &glx_version_major, &glx_version_minor) ||
(glx_version_major == 1 && glx_version_minor < 3) ||
glx_version_major < 1)
{
Temp scratch = scratch_begin(0, 0);
String8 message = push_str8f(scratch.arena, "Unsupported GLX version (%i.%i, need at least 1.3)", glx_version_major, glx_version_minor);
os_graphical_message(1, str8_lit("Fatal Error"), message);
os_abort(1);
scratch_end(scratch);
}
//- rjf: get frame buffer configs
local_persist int framebuffer_config_options[] =
{
GLX_X_RENDERABLE, 1,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, 1,
None
};
int framebuffer_configs_count = 0;
GLXFBConfig *framebuffer_configs = glXChooseFBConfig(os_lnx_gfx_state->display, DefaultScreen(os_lnx_gfx_state->display), framebuffer_config_options, &framebuffer_configs_count);
if(framebuffer_configs == 0)
{
os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Could not find a suitable framebuffer configuration."));
os_abort(1);
}
GLXFBConfig framebuffer_config = framebuffer_configs[0];
XFree(framebuffer_configs);
//- rjf: get visual info; create color map
XVisualInfo *visual_info = glXGetVisualFromFBConfig(os_lnx_gfx_state->display, framebuffer_config);
Colormap cmap = XCreateColormap(os_lnx_gfx_state->display, RootWindow(os_lnx_gfx_state->display, visual_info->screen), visual_info->visual, AllocNone);
//- rjf: construct set-window-attributes
XSetWindowAttributes set_window_attributes = {0};
set_window_attributes.background_pixmap = None;
set_window_attributes.border_pixel = 0;
set_window_attributes.event_mask = StructureNotifyMask;
//- rjf: construct context
{
B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug"));
#if BUILD_DEBUG
debug_mode = 1;
#if R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_GLX
# include "glx/render_opengl_linux_glx.c"
#elif R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_EGL
# include "egl/render_opengl_linux_egl.c"
#else
# error Linux OpenGL backend not specified.
#endif
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((U8 *)"glXCreateContextAttribsARB");
int context_options[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_FLAGS_ARB, !!debug_mode*GLX_CONTEXT_DEBUG_BIT_ARB,
None
};
r_ogl_lnx_ctx = glXCreateContextAttribsARB(os_lnx_gfx_state->display, framebuffer_config, 0, 1, context_options);
}
glXMakeCurrent(os_lnx_gfx_state->display, RootWindow(os_lnx_gfx_state->display, visual_info->screen), r_ogl_lnx_ctx);
}
internal R_Handle
r_ogl_os_window_equip(OS_Handle window)
{
R_Handle result = {0};
return result;
}
internal void
r_ogl_os_window_unequip(OS_Handle os, R_Handle r)
{
}
internal void
r_ogl_os_select_window(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
glXMakeCurrent(os_lnx_gfx_state->display, w->window, r_ogl_lnx_ctx);
}
internal void
r_ogl_os_window_swap(OS_Handle os, R_Handle r)
{
OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0];
glXSwapBuffers(os_lnx_gfx_state->display, w->window);
}
+21 -15
View File
@@ -4,22 +4,28 @@
#ifndef RENDER_OPENGL_LINUX_H
#define RENDER_OPENGL_LINUX_H
#define glTexImage3D glTexImage3D__static
#define glTexSubImage3D glTexSubImage3D__static
#define glActiveTexture glActiveTexture__static
#include <GL/gl.h>
#include <GL/glx.h>
#undef glTexImage3D
#undef glTexSubImage3D
#undef glActiveTexture
////////////////////////////////
//~ rjf: Backend Constants
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
#define R_OPENGL_LINUX_BACKEND_GLX 0
#define R_OPENGL_LINUX_BACKEND_EGL 1
global GLXContext r_ogl_lnx_ctx = 0;
////////////////////////////////
//~ rjf: Decide On Backend
#if !defined(R_OPENGL_LINUX_BACKEND)
# define R_OPENGL_LINUX_BACKEND R_OPENGL_LINUX_BACKEND_GLX
#endif
////////////////////////////////
//~ rjf: Backend Includes
#if R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_GLX
# include "glx/render_opengl_linux_glx.h"
#elif R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_EGL
# include "egl/render_opengl_linux_egl.h"
#else
# error Linux OpenGL backend not specified.
#endif
#endif // RENDER_OPENGL_LINUX_H
+35 -35
View File
@@ -4,41 +4,6 @@
#ifndef RENDER_OPENGL_H
#define RENDER_OPENGL_H
////////////////////////////////
//~ rjf: OS Backend Includes
#if OS_WINDOWS
# include "render/opengl/win32/render_opengl_win32.h"
#elif OS_LINUX
# include "render/opengl/linux/render_opengl_linux.h"
#else
# error OS portion of OpenGL rendering backend not defined.
#endif
////////////////////////////////
//~ rjf: Shader Metadata Types
typedef struct R_OGL_Attribute R_OGL_Attribute;
struct R_OGL_Attribute
{
U64 index;
String8 name;
GLenum type;
U64 count;
};
typedef struct R_OGL_AttributeArray R_OGL_AttributeArray;
struct R_OGL_AttributeArray
{
R_OGL_Attribute *v;
U64 count;
};
////////////////////////////////
//~ rjf: Generated Code
#include "render/opengl/generated/render_opengl.meta.h"
////////////////////////////////
//~ rjf: Defines
@@ -107,6 +72,41 @@ typedef ptrdiff_t GLintptr;
#define GL_DEBUG_OUTPUT 0x92E0
////////////////////////////////
//~ rjf: OS Backend Includes
#if OS_WINDOWS
# include "render/opengl/win32/render_opengl_win32.h"
#elif OS_LINUX
# include "render/opengl/linux/render_opengl_linux.h"
#else
# error OS portion of OpenGL rendering backend not defined.
#endif
////////////////////////////////
//~ rjf: Shader Metadata Types
typedef struct R_OGL_Attribute R_OGL_Attribute;
struct R_OGL_Attribute
{
U64 index;
String8 name;
GLenum type;
U64 count;
};
typedef struct R_OGL_AttributeArray R_OGL_AttributeArray;
struct R_OGL_AttributeArray
{
R_OGL_Attribute *v;
U64 count;
};
////////////////////////////////
//~ rjf: Generated Code
#include "render/opengl/generated/render_opengl.meta.h"
////////////////////////////////
//~ rjf: OpenGL Procedure List