Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
build_cmd: bin\build.bat /DWIN32_OPENGL
- suffix: x64-linux
os: ubuntu-latest
build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && ./bin/build-linux.sh
build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libegl-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && ./bin/build-linux.sh
- suffix: x64-mac
os: macos-15-intel
build_cmd: ./bin/build-mac.sh
Expand Down
2 changes: 1 addition & 1 deletion code/bin/4ed_build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, cha

# define GCC_LIBS_COMMON \
"-lX11 -lpthread -lm -lrt " \
"-lGL -ldl -lXfixes -lfreetype -lfontconfig"
"-lEGL -lGL -ldl -lXfixes -lfreetype -lfontconfig"

# define GCC_LIBS_X64 GCC_LIBS_COMMON
# define GCC_LIBS_X86 GCC_LIBS_COMMON
Expand Down
214 changes: 94 additions & 120 deletions code/platform_linux/linux_4ed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
//#include <fontconfig/fontconfig.h>
#define internal static

#include <GL/glx.h>
#include <GL/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#ifdef INSO_DEBUG
#define LINUX_FN_DEBUG(fmt, ...) do { \
Expand Down Expand Up @@ -159,6 +159,11 @@ struct Linux_Vars {
Thread_Context tctx;
Arena frame_arena;

EGLDisplay egl_display;
EGLSurface egl_surface;
EGLContext egl_context;
EGLConfig egl_config;

Display* dpy;
Window win;

Expand Down Expand Up @@ -622,123 +627,99 @@ font_make_face(Arena* arena, Face_Description* description, f32 scale_factor) {
////////////////////////////

internal b32
glx_init(void) {
int glx_maj, glx_min;

if(!glXQueryVersion(linuxvars.dpy, &glx_maj, &glx_min)) {
return false;
egl_init(void) {
linuxvars.egl_display = eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, linuxvars.dpy, 0);
if(linuxvars.egl_display)
{
int egl_maj, egl_min;
if(eglInitialize(linuxvars.egl_display, &egl_maj, &egl_min) &&
((egl_maj > 1) || ((egl_maj == 1) && (egl_min >= 5))))
{
return eglBindAPI(EGL_OPENGL_API);
}
}

return glx_maj > 1 || (glx_maj == 1 && glx_min >= 3);
return false;
}

internal b32
glx_get_config(GLXFBConfig* fb_config, XVisualInfo* vi) {

static const int attrs[] = {
GLX_X_RENDERABLE , True,
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 , True,
None
};

int conf_count = 0;
GLXFBConfig* conf_list = glXChooseFBConfig(linuxvars.dpy, DefaultScreen(linuxvars.dpy), attrs, &conf_count);
if(!conf_count || conf_count <= 0) {
return false;
}

*fb_config = *conf_list;
XFree(conf_list);

XVisualInfo* xvi = glXGetVisualFromFBConfig(linuxvars.dpy, *fb_config);
if(!xvi) {
return false;
}

*vi = *xvi;
XFree(xvi);

return true;
}

internal b32 glx_ctx_error;

internal int
glx_error_handler(Display* dpy, XErrorEvent* ev){
glx_ctx_error = true;
return 0;
}

typedef GLXContext (glXCreateContextAttribsARB_Function)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef void (glXSwapIntervalEXT_Function) (Display *dpy, GLXDrawable drawable, int interval);
typedef int (glXSwapIntervalMESA_Function) (unsigned int interval);
typedef int (glXGetSwapIntervalMESA_Function) (void);
typedef int (glXSwapIntervalSGI_Function) (int interval);

internal b32
glx_create_context(GLXFBConfig fb_config){
const char *glx_exts = glXQueryExtensionsString(linuxvars.dpy, DefaultScreen(linuxvars.dpy));

glXCreateContextAttribsARB_Function *glXCreateContextAttribsARB = 0;
glXSwapIntervalEXT_Function *glXSwapIntervalEXT = 0;
glXSwapIntervalMESA_Function *glXSwapIntervalMESA = 0;
glXGetSwapIntervalMESA_Function *glXGetSwapIntervalMESA = 0;
glXSwapIntervalSGI_Function *glXSwapIntervalSGI = 0;
egl_create_context(void){
Scratch_Block scratch(&linuxvars.tctx);

#define GLXLOAD(f) f = (f##_Function*) glXGetProcAddressARB((const GLubyte*) #f);
GLXLOAD(glXCreateContextAttribsARB);
EGLint config_attributes[] =
{
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_CONFORMANT, EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,

EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,

EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,

EGL_NONE,
};

GLXContext ctx = NULL;
int (*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(&glx_error_handler);
EGLAttrib surface_attributes[] =
{
// TODO(maria): decide if we want an sRGB capable surface;
//EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB,
EGL_NONE,
};

if (glXCreateContextAttribsARB == NULL){
//LOG("glXCreateContextAttribsARB() not found, using old-style GLX context\n" );
ctx = glXCreateNewContext(linuxvars.dpy, fb_config, GLX_RGBA_TYPE, 0, True);
} else {
static const int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
EGLint context_attributes[] =
{
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 2,
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
#if GL_DEBUG_MODE
GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB,
EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE,
#endif
None
};

ctx = glXCreateContextAttribsARB(linuxvars.dpy, fb_config, 0, True, context_attribs);
}

XSync(linuxvars.dpy, False);
if(glx_ctx_error || !ctx) {
return false;
}

XSync(linuxvars.dpy, False);
XSetErrorHandler(old_handler);

//b32 direct = glXIsDirect(linuxvars.dpy, ctx);

//LOG("Making context current\n");
glXMakeCurrent(linuxvars.dpy, linuxvars.win, ctx);

//glx_enable_vsync();
EGL_NONE,
};

// NOTE(allen): Load gl functions
#define GL_FUNC(f,R,P) GLXLOAD(f)
EGLint config_count = 0;
if(eglChooseConfig(linuxvars.egl_display, config_attributes, 0, 0, &config_count) &&
(config_count > 0))
{
EGLConfig *configs = push_array(scratch, EGLConfig, config_count);
if(eglChooseConfig(linuxvars.egl_display, config_attributes, configs, config_count, &config_count) &&
(config_count > 0))
{
for(i32 config_index = 0;
config_index < config_count;
++config_index)
{
EGLConfig test_config = configs[config_index];
EGLSurface test_surface = eglCreatePlatformWindowSurface(linuxvars.egl_display, test_config, &linuxvars.win, surface_attributes);
if(test_surface)
{
linuxvars.egl_config = test_config;
linuxvars.egl_surface = test_surface;
break;
}
}

if(linuxvars.egl_surface)
{
linuxvars.egl_context = eglCreateContext(linuxvars.egl_display, linuxvars.egl_config, EGL_NO_CONTEXT, context_attributes);
if(linuxvars.egl_context && eglMakeCurrent(linuxvars.egl_display, linuxvars.egl_surface, linuxvars.egl_surface, linuxvars.egl_context))
{
// NOTE(allen): Load gl functions
#define GL_FUNC(f,R,P) f = (f##_Function*)eglGetProcAddress(#f);
#include "opengl/4ed_opengl_funcs.h"
#undef GL_FUNC
return true;
}
}
}
}

#undef GLXLOAD

return true;
return false;
}

////////////////////////////
Expand Down Expand Up @@ -771,14 +752,8 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {

#undef LOAD_ATOM

if (!glx_init()){
system_error_box("Your XServer's GLX version is too old. GLX 1.3+ is required.");
}

GLXFBConfig fb_config;
XVisualInfo vi;
if (!glx_get_config(&fb_config, &vi)){
system_error_box("Could not get a matching GLX FBConfig. Check your OpenGL drivers are installed correctly.");
if (!egl_init()){
system_error_box("Your EGL version is too old. EGL 1.5+ is required.");
}

// TODO: window size
Expand All @@ -795,10 +770,9 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
swa.backing_store = WhenMapped;
swa.event_mask = StructureNotifyMask;
swa.bit_gravity = NorthWestGravity;
swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi.screen), vi.visual, AllocNone);

u32 CWflags = CWBackingStore|CWBitGravity|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask;
linuxvars.win = XCreateWindow(dpy, RootWindow(dpy, vi.screen), 0, 0, w, h, 0, vi.depth, InputOutput, vi.visual, CWflags, &swa);
u32 CWflags = CWBackingStore|CWBitGravity|CWBackPixel|CWBorderPixel|CWEventMask;
linuxvars.win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, w, h, 0, CopyFromParent, InputOutput, CopyFromParent, CWflags, &swa);

if (!linuxvars.win){
system_error_box("XCreateWindow failed. Make sure your display is set up correctly.");
Expand Down Expand Up @@ -855,8 +829,8 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
// NOTE(inso): make the window visible
XMapWindow(linuxvars.dpy, linuxvars.win);

if(!glx_create_context(fb_config)) {
system_error_box("Unable to create GLX context.");
if(!egl_create_context()) {
system_error_box("Unable to create EGL context.");
}

XRaiseWindow(linuxvars.dpy, linuxvars.win);
Expand Down Expand Up @@ -2019,7 +1993,7 @@ main(int argc, char **argv){
}

gl_render(&render_target);
glXSwapBuffers(linuxvars.dpy, linuxvars.win);
eglSwapBuffers(linuxvars.egl_display, linuxvars.egl_surface);

// TODO(allen): don't let the screen size change until HERE after the render

Expand Down