Skip to content

Commit

Permalink
Allow selecting custom OpenGL profile and version.
Browse files Browse the repository at this point in the history
  • Loading branch information
skullernet committed Aug 21, 2024
1 parent 1959593 commit f820dee
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 29 deletions.
16 changes: 16 additions & 0 deletions doc/client.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,22 @@ gl_texturebits::
(should be typically 0, 8, 16 or 32). Default value is 0 (choose the best
internal format automatically).

gl_debug::
Create debug OpenGL context, if supported by OpenGL implementation.
This option may hurt performance and is intended for developers only.
Default value is 0.

gl_profile::
Specifies custom profile and version of OpenGL context to create. Default
value is empty string, which means to create highest version compatibility
profile context. Can be set to "gl" to create OpenGL core profile context,
or "es" to create OpenGL ES context. May be followed by desired minimum
OpenGL version number. For example, "gl4.6" or "es3.0". Not all OpenGL
implementations support this.

NOTE: Using OpenGL compatibility profile is recommended. Some features may not
work in more restricted profiles, or performance may be suboptimal.

gl_screenshot_format::
Specifies image format ‘screenshot’ command uses. Possible values are
"png", "jpg" and "tga". Default value is "jpg".
Expand Down
9 changes: 9 additions & 0 deletions inc/refresh/refresh.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,21 @@ typedef struct {
particle_t *particles;
} refdef_t;

enum {
QGL_PROFILE_NONE,
QGL_PROFILE_CORE,
QGL_PROFILE_ES,
};

typedef struct {
uint8_t colorbits;
uint8_t depthbits;
uint8_t stencilbits;
uint8_t multisamples;
bool debug;
uint8_t profile;
uint8_t major_ver;
uint8_t minor_ver;
} r_opengl_config_t;

typedef enum {
Expand Down
23 changes: 23 additions & 0 deletions src/refresh/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,29 @@ r_opengl_config_t R_GetGLConfig(void)
if (cfg.multisamples < 2)
cfg.multisamples = 0;

const char *s = Cvar_Get("gl_profile", "", CVAR_REFRESH)->string;

if (!Q_stricmpn(s, "gl", 2))
cfg.profile = QGL_PROFILE_CORE;
else if (!Q_stricmpn(s, "es", 2))
cfg.profile = QGL_PROFILE_ES;

if (cfg.profile) {
int major = 0, minor = 0;

sscanf(s + 2, "%d.%d", &major, &minor);
if (major >= 1 && minor >= 0) {
cfg.major_ver = major;
cfg.minor_ver = minor;
} else if (cfg.profile == QGL_PROFILE_CORE) {
cfg.major_ver = 3;
cfg.minor_ver = 2;
} else if (cfg.profile == QGL_PROFILE_ES) {
cfg.major_ver = 3;
cfg.minor_ver = 0;
}
}

return cfg;
}

Expand Down
15 changes: 8 additions & 7 deletions src/unix/video/sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,16 @@ static void set_gl_attributes(void)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, cfg.multisamples);
}
if (cfg.debug) {

if (cfg.debug)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}

#if USE_GLES
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
#endif
if (cfg.profile) {
if (cfg.profile == QGL_PROFILE_ES)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, cfg.major_ver);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, cfg.minor_ver);
}
}

static void *get_proc_addr(const char *sym)
Expand Down
41 changes: 31 additions & 10 deletions src/unix/video/x11.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,19 @@ static struct {
} x11;

enum {
QGLX_ARB_create_context = BIT(0),
QGLX_ARB_multisample = BIT(1),
QGLX_EXT_swap_control = BIT(2),
QGLX_EXT_swap_control_tear = BIT(3),
QGLX_ARB_create_context = BIT(0),
QGLX_ARB_multisample = BIT(1),
QGLX_EXT_create_context_es_profile = BIT(2),
QGLX_EXT_swap_control = BIT(3),
QGLX_EXT_swap_control_tear = BIT(4),
};

static unsigned glx_parse_extension_string(const char *s)
{
static const char *const extnames[] = {
"GLX_ARB_create_context",
"GLX_ARB_multisample",
"GLX_EXT_create_context_es_profile",
"GLX_EXT_swap_control",
"GLX_EXT_swap_control_tear",
NULL
Expand Down Expand Up @@ -379,20 +381,39 @@ static bool init(void)
XFree(list);
}

if (cfg.debug) {
if (cfg.profile == QGL_PROFILE_ES && !(x11.extensions & QGLX_EXT_create_context_es_profile)) {
Com_WPrintf("GLX_EXT_create_context_es_profile not found\n");
cfg.profile = QGL_PROFILE_NONE;
}

if (cfg.debug || cfg.profile) {
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = NULL;

if (x11.extensions & QGLX_ARB_create_context)
glXCreateContextAttribsARB = get_proc_addr("glXCreateContextAttribsARB");

if (glXCreateContextAttribsARB) {
int ctx_attr[] = {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
None
};
int ctx_attr[9];
int i = 0;

if (cfg.profile) {
ctx_attr[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
ctx_attr[i++] = cfg.major_ver;
ctx_attr[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
ctx_attr[i++] = cfg.minor_ver;
}
if (cfg.profile == QGL_PROFILE_ES) {
ctx_attr[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
ctx_attr[i++] = GLX_CONTEXT_ES_PROFILE_BIT_EXT;
}
if (cfg.debug) {
ctx_attr[i++] = GLX_CONTEXT_FLAGS_ARB;
ctx_attr[i++] = GLX_CONTEXT_DEBUG_BIT_ARB;
}
ctx_attr[i] = None;

if (!(x11.ctx = glXCreateContextAttribsARB(x11.dpy, fbc, NULL, True, ctx_attr)))
Com_EPrintf("Failed to create debug GL context\n");
Com_EPrintf("Failed to create GL context with attributes\n");
} else {
Com_WPrintf("GLX_ARB_create_context not found\n");
}
Expand Down
47 changes: 35 additions & 12 deletions src/windows/wgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ static struct {
static cvar_t *gl_allow_software;

enum {
QWGL_ARB_create_context = BIT(0),
QWGL_ARB_multisample = BIT(1),
QWGL_ARB_pixel_format = BIT(2),
QWGL_EXT_swap_control = BIT(3),
QWGL_EXT_swap_control_tear = BIT(4),
QWGL_ARB_create_context = BIT(0),
QWGL_ARB_multisample = BIT(1),
QWGL_ARB_pixel_format = BIT(2),
QWGL_EXT_create_context_es_profile = BIT(3),
QWGL_EXT_swap_control = BIT(4),
QWGL_EXT_swap_control_tear = BIT(5),
};

static unsigned wgl_parse_extension_string(const char *s)
Expand All @@ -46,6 +47,7 @@ static unsigned wgl_parse_extension_string(const char *s)
"WGL_ARB_create_context",
"WGL_ARB_multisample",
"WGL_ARB_pixel_format",
"WGL_EXT_create_context_es_profile",
"WGL_EXT_swap_control",
"WGL_EXT_swap_control_tear",
NULL
Expand Down Expand Up @@ -152,11 +154,26 @@ static int wgl_setup_gl(r_opengl_config_t cfg)
}

// startup the OpenGL subsystem by creating a context and making it current
if (wgl.CreateContextAttribsARB && cfg.debug) {
int attr[] = {
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
0
};
if (wgl.CreateContextAttribsARB && (cfg.debug || cfg.profile)) {
int attr[9];
int i = 0;

if (cfg.profile) {
attr[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attr[i++] = cfg.major_ver;
attr[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
attr[i++] = cfg.minor_ver;
}
if (cfg.profile == QGL_PROFILE_ES) {
attr[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attr[i++] = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
}
if (cfg.debug) {
attr[i++] = WGL_CONTEXT_FLAGS_ARB;
attr[i++] = WGL_CONTEXT_DEBUG_BIT_ARB;
}
attr[i] = 0;

if (!(wgl.context = wgl.CreateContextAttribsARB(win.dc, NULL, attr))) {
print_error("wglCreateContextAttribsARB");
goto soft;
Expand Down Expand Up @@ -282,7 +299,7 @@ static bool wgl_init(void)
cfg = R_GetGLConfig();

// check for extensions by creating a fake window
if (cfg.multisamples || cfg.debug)
if (cfg.multisamples || cfg.debug || cfg.profile)
fake_extensions = get_fake_window_extensions();

if (cfg.multisamples) {
Expand All @@ -297,9 +314,15 @@ static bool wgl_init(void)
}
}

if (cfg.debug && !wgl.CreateContextAttribsARB) {
if ((cfg.debug || cfg.profile) && !wgl.CreateContextAttribsARB) {
Com_WPrintf("WGL_ARB_create_context not found\n");
cfg.debug = false;
cfg.profile = QGL_PROFILE_NONE;
}

if (cfg.profile == QGL_PROFILE_ES && !(fake_extensions & QWGL_EXT_create_context_es_profile)) {
Com_WPrintf("WGL_EXT_create_context_es_profile not found\n");
cfg.profile = QGL_PROFILE_NONE;
}

// create window, choose PFD, setup OpenGL context
Expand Down

0 comments on commit f820dee

Please sign in to comment.