mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
gex-gl: the native host makes a compatibility context when a guest asks for core
Since6230d6f4(10-06) the native host honours a core-profile request, and a core profile refuses to bind a buffer, texture or vertex array name glGen* did not return -- but the guest library names its own objects, as the wire protocol lets it. Every glBindBuffer of a core client failed with INVALID_OPERATION: tests/gl-map-buffer.sh read zeros (0 of 3 on gooner, with any gexc and any guest library from 10-04 on), and native Muck, a GL 4.x core client, drew nothing. E3 (bcc93e30) is not involved (it is the NT opengl32 layer; this is the Linux guest path). The host now asks for a compatibility context of the requested version, falling back to core only where there is none, and the guest library answers GL_CONTEXT_PROFILE_MASK with the profile the client asked for. tests/gl-map-buffer.sh 3/3, tests/gl-state-query-cache.sh 10/10, tests/games/glx-context.sh 0 failures (3.2 core reports mask 1). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_d2453757b8a84fdbb4ee7c9e093141df
This commit is contained in:
1 parent
b755fb7adb
commit
c39706baac
2 files changed
+35
-13
No files matched your search
+25
-12
@@ -779,18 +779,31 @@ impl Gl {
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
return Err("no desktop OpenGL EGL config".into());
|
||||
}
|
||||
// Core only when asked for, from 3.2 (where profiles begin).
|
||||
let core = !compat && (major > 3 || (major == 3 && minor >= 2));
|
||||
let mut ctx_attrs = vec![
|
||||
EGL_CONTEXT_OPENGL_PROFILE_MASK,
|
||||
if core { EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT } else { EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT },
|
||||
];
|
||||
if major > 3 || (major == 3 && minor > 0) {
|
||||
ctx_attrs.extend_from_slice(&[EGL_CONTEXT_MAJOR_VERSION, major as EGLint]);
|
||||
ctx_attrs.extend_from_slice(&[EGL_CONTEXT_MINOR_VERSION, minor as EGLint]);
|
||||
// A compatibility context even when the guest asks for core, and
|
||||
// core only where the host has no compatibility context of that
|
||||
// version. The guest names its own objects (the wire protocol lets
|
||||
// it), and a core profile refuses to bind a buffer, texture or
|
||||
// vertex array name glGen* did not return: every glBindBuffer of
|
||||
// Muck's (a GL 4.x core client) failed with INVALID_OPERATION,
|
||||
// and nothing drew. A compatibility profile is a superset of core
|
||||
// for what a core client calls; the guest library answers
|
||||
// GL_CONTEXT_PROFILE_MASK with what the client asked for.
|
||||
let attrs_for = |core: bool| {
|
||||
let mut a = vec![
|
||||
EGL_CONTEXT_OPENGL_PROFILE_MASK,
|
||||
if core { EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT } else { EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT },
|
||||
];
|
||||
if major > 3 || (major == 3 && minor > 0) {
|
||||
a.extend_from_slice(&[EGL_CONTEXT_MAJOR_VERSION, major as EGLint]);
|
||||
a.extend_from_slice(&[EGL_CONTEXT_MINOR_VERSION, minor as EGLint]);
|
||||
}
|
||||
a.push(EGL_NONE);
|
||||
a
|
||||
};
|
||||
let mut context = eglCreateContext(self.display, config, std::ptr::null_mut(), attrs_for(false).as_ptr());
|
||||
if context.is_null() && (major > 3 || (major == 3 && minor >= 2)) {
|
||||
context = eglCreateContext(self.display, config, std::ptr::null_mut(), attrs_for(true).as_ptr());
|
||||
}
|
||||
ctx_attrs.push(EGL_NONE);
|
||||
let context = eglCreateContext(self.display, config, std::ptr::null_mut(), ctx_attrs.as_ptr());
|
||||
if context.is_null() {
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
return Err(format!("no desktop OpenGL context: {:#x}", eglGetError()));
|
||||
@@ -815,7 +828,7 @@ impl Gl {
|
||||
self.unpack_store = PixelStore::default();
|
||||
self.current_on = Some(std::thread::current().id());
|
||||
self.compat = Compat::load();
|
||||
self.desktop = Some((major, minor, !core));
|
||||
self.desktop = Some((major, minor, compat || !(major > 3 || (major == 3 && minor >= 2))));
|
||||
self.vendor = gl_string(0x1F00);
|
||||
self.renderer = gl_string(0x1F01);
|
||||
self.version = gl_string(0x1F02);
|
||||
|
||||
+10
-1
@@ -2117,6 +2117,8 @@ static void host_gl_version(int *major, int *minor) {
|
||||
}
|
||||
|
||||
static size_t gexgl_state_query_components(unsigned pname);
|
||||
/* Defined with the EGL context state below: what the client asked for. */
|
||||
static int egl_context_major, egl_context_minor, egl_context_profile;
|
||||
|
||||
void glGetIntegerv(unsigned pname, int *out) {
|
||||
if (pname == 0x821Bu || pname == 0x821Cu) { /* GL_MAJOR/MINOR_VERSION */
|
||||
@@ -2139,12 +2141,19 @@ void glGetIntegerv(unsigned pname, int *out) {
|
||||
when it is one (GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, 2), and a
|
||||
desktop context of 3.2 or later otherwise is core (1). ES has no
|
||||
profiles. This answered core for every desktop context. */
|
||||
/* What the client asked for, when it asked for core: the native
|
||||
host gives it a compatibility context regardless (crates/gex-gl
|
||||
become_desktop: a core one refuses the guest's own object names),
|
||||
and its version string would say so. */
|
||||
int mask = 0;
|
||||
if (egl_api == 0x30A2u) {
|
||||
const char *v = (const char *)glGetString(0x1F02u);
|
||||
int major = 0, minor = 0;
|
||||
host_gl_version(&major, &minor);
|
||||
if (v && strstr(v, "Compatibility")) mask = 2;
|
||||
const int asked_core = egl_context_profile == 0 &&
|
||||
(egl_context_major > 3 || (egl_context_major == 3 && egl_context_minor >= 2));
|
||||
if (asked_core) mask = 1;
|
||||
else if (v && strstr(v, "Compatibility")) mask = 2;
|
||||
else if (major > 3 || (major == 3 && minor >= 2)) mask = 1;
|
||||
}
|
||||
if (out) out[0] = mask;
|
||||
|
||||
Reference in new issue
Block a user