gex-gl: the compatibility profile, generated from the Khronos registry

tools/gen_gl_compat.py gives every OpenGL command in gl.xml (GL 1.0-4.6
with what core removed, and every extension) a wire plan derived from the
registry's own parameter metadata -- types, `len`, `class` -- unless it
cannot be carried safely (callbacks, pointers to pointers, lengths left to
prose; 2520 planned, 465 left out, listed by --report). A plan is one
token per parameter: scalars, input and output arrays with their counts
(fixed, a parameter times N, pname-sized from one shared table, strings,
unpack pixel transfers that may be unpack-buffer offsets, glBitmap,
glCallLists), and vertex/index/indirect pointers as buffer offsets.
Opcodes are 8192 plus the command's index in the registry's sorted list,
so adding a policy never renumbers one. Protocol 13.

Generated from it:
- guest/gl/gl-compat-generated.inc: the Linux guest's entry points for
  every planned command gexgl.c and the 4.4 transport do not define, each
  one call to gexgen_call (gexgl.c), which interprets its plan;
- web/mesa/gl-compat-generated-{decoders,cases}.inc: the host decoder, a
  function per command (gcc takes thousands of cases in one switch very
  badly), shared by the browser's Mesa decoder and the native host;
- guest/gl/gl-pname-counts.h, guest/gl/gexgl-plan.h: what both ends size
  arrays with;
- crates/gex-gl/src/compat_plans.rs: the table, tested for well-formedness.

The native host now runs every generated command: crates/gex-gl/native
builds the same C++ cases (and the 4.4 transport's, which the native host
never decoded) against the host's GL through eglGetProcAddress, plus the
hand-written opcodes host.rs lacked, copied from the Mesa decoder
(native/hand-cases.inc); host.rs hands it whatever it does not know. The
host's context is released after each batch, so a guest may submit from
any thread (wined3d's command-stream thread and its main one).

The guest's extension list grows with its exports (+135 claimable).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FYuLCHiLKSdV6EMSoZB8cZ
This commit is contained in:
velzieandClaude Opus 5.5 committed 2026-10-02 19:25:53 -04:00
1 parent 7df2573645
commit fd5b970fb4
25 files changed
+49422 -12

No files matched your search

Generated
+3
View File
@@ -490,6 +490,9 @@ version = "0.0.1"
[[package]]
name = "gex-gl"
version = "0.0.1"
dependencies = [
"cc",
]
[[package]]
name = "gex-gpu"
+5
View File
@@ -14,6 +14,11 @@ host = []
[dependencies]
# The native host's decoder for the generated commands is C++ shared with the
# browser's (native/gexgl-native.cpp), built here when `host` is on.
[build-dependencies]
cc = "1.4"
# The host half links against the host's own GL. There is nothing to build on
# a target that has none, and the guest half is C, so this is the only side
# that needs a library at all.
+71
View File
@@ -0,0 +1,71 @@
//! Builds native/gexgl-native.cpp, the native host's decoder for the
//! generated GL commands (the same cases the browser's Mesa decoder runs),
//! when the `host` feature is on and the target has a host GL.
fn main() {
println!("cargo:rerun-if-changed=native/gexgl-native.cpp");
println!("cargo:rerun-if-changed=native/hand-cases.inc");
println!("cargo:rerun-if-changed=src/proto.rs");
for f in [
"../../web/mesa/gl44-generated-cases.inc",
"../../web/mesa/gl-compat-generated-cases.inc",
"../../web/mesa/gexgl-compat-host.h",
"../../guest/gl/gexgl-plan.h",
"../../guest/gl/gexgl-pixel.h",
"../../guest/gl/gl-pname-counts.h",
] {
println!("cargo:rerun-if-changed={f}");
}
let host = std::env::var_os("CARGO_FEATURE_HOST").is_some();
let wasm = std::env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("wasm32");
if !host || wasm {
return;
}
// The 4.4 cases call some GL functions directly, which the browser's
// Mesa links statically; here every one goes through the proc table
// (native/gexgl-native.cpp's GEX_GL_CALL), as the native host links only
// EGL and GLES.
let cases = std::fs::read_to_string("../../web/mesa/gl44-generated-cases.inc").unwrap_or_default()
+ &std::fs::read_to_string("native/hand-cases.inc").unwrap_or_default();
let mut direct = std::collections::BTreeSet::new();
let b = cases.as_bytes();
for (i, _) in cases.match_indices("gl") {
let starts = i == 0 || !(b[i - 1].is_ascii_alphanumeric() || b[i - 1] == b'_');
if !starts || !b.get(i + 2).is_some_and(|c| c.is_ascii_uppercase()) {
continue;
}
let end = i + cases[i..].find(|c: char| !(c.is_ascii_alphanumeric() || c == '_')).unwrap_or(0);
if b.get(end) == Some(&b'(') {
direct.insert(&cases[i..end]);
}
}
let out = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
let header: String =
direct.iter().map(|f| format!("#define {f}(...) GEX_GL_CALL({f}, __VA_ARGS__)\n")).collect();
std::fs::write(out.join("gexgl-direct-calls.h"), header).unwrap();
// The hand-written opcodes' names, from proto.rs, for hand-cases.inc.
let proto = std::fs::read_to_string("src/proto.rs").unwrap();
let ops = &proto[proto.find("pub mod op {").unwrap()..];
let ops = &ops[..ops.find("\n}").unwrap()];
let mut names = String::new();
for line in ops.lines() {
let line = line.trim();
if let Some(rest) = line.strip_prefix("pub const ") {
if let Some((name, value)) = rest.split_once(": u32 = ") {
let value = value.split(';').next().unwrap_or("0").trim();
names += &format!(" {name} = {value},\n");
}
}
}
std::fs::write(out.join("gexgl-hand-ops.h"), names).unwrap();
cc::Build::new()
.cpp(true)
.include(&out)
.std("c++17")
.file("native/gexgl-native.cpp")
.flag_if_supported("-Wno-unused-function")
.flag_if_supported("-Wno-unused-variable")
.flag_if_supported("-Wno-unused-parameter")
.opt_level(2)
.compile("gexgl_native");
}
+268
View File
@@ -0,0 +1,268 @@
/* The native host's decoder for the generated commands: the GL 4.4
* transport (web/mesa/gl44-generated-cases.inc) and the registry's
* compatibility-profile commands (web/mesa/gl-compat-generated-cases.inc),
* the same cases the browser's Mesa decoder runs, here against the host's
* GL. crates/gex-gl/src/host.rs hands this any opcode its own decoder does
* not know (gexgl_native_one).
*
* Object names: the native host runs the guest's buffer, texture and other
* names as they are (a desktop compatibility context and GLES both accept
* names they never generated), so those tables are the identity; programs
* and shaders are named by the host's GL, and host.rs tells this side about
* each (gexgl_native_name). Program pipelines are generated by these cases
* themselves and kept here. */
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <EGL/egl.h>
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "../../../guest/gl/gexgl-pixel.h"
namespace {
void* gexgen_proc(const char* name, const char* alias);
/* Each call site looks its function up once. */
#define GEX_GL_CALL(function, ...) \
([]() { \
static const auto p__ = reinterpret_cast<decltype(&function)>(gexgen_proc(#function, nullptr)); \
return p__; \
}())(__VA_ARGS__)
void* gexgen_proc(const char* name, const char* alias) {
void* f = reinterpret_cast<void*>(eglGetProcAddress(name));
if (!f && alias) f = reinterpret_cast<void*>(eglGetProcAddress(alias));
return f;
}
void gexgen_missing(const char* name) {
static std::unordered_set<std::string> said;
if (said.insert(name).second) fprintf(stderr, "gex-gl: the host's GL has no %s; the call does nothing\n", name);
}
gexgl_pixel_store pack_store = gexgl_default_pixel_store();
gexgl_pixel_store unpack_store = gexgl_default_pixel_store();
struct Reader {
const uint8_t* p;
const uint8_t* end;
bool ok = true;
uint32_t u32() {
if (end - p < 4) { ok = false; return 0; }
uint32_t v; std::memcpy(&v, p, 4); p += 4; return v;
}
int32_t i32() { return static_cast<int32_t>(u32()); }
uint64_t u64() {
const uint64_t low = u32();
const uint64_t high = u32();
return low | (high << 32);
}
int64_t i64() { return static_cast<int64_t>(u64()); }
float f32() { uint32_t u = u32(); float f; std::memcpy(&f, &u, 4); return f; }
double f64() { uint64_t u = u64(); double f; std::memcpy(&f, &u, 8); return f; }
const uint8_t* blob(uint32_t& n) {
n = u32();
if (!ok || static_cast<size_t>(end - p) < n) { ok = false; n = 0; return nullptr; }
const uint32_t padded = n <= UINT32_MAX - 3u ? (n + 3u) & ~3u : 0;
if (padded < n || static_cast<size_t>(end - p) < padded) {
ok = false; n = 0; return nullptr;
}
const uint8_t* out = p; p += padded;
return out;
}
std::string string() {
uint32_t n; const uint8_t* s = blob(n);
return s ? std::string(reinterpret_cast<const char*>(s), n) : std::string();
}
};
} // namespace
#include "../../../web/mesa/gexgl-compat-host.h"
namespace {
std::vector<uint8_t> reply;
void put_u32(uint32_t v) {
const size_t at = reply.size(); reply.resize(at + 4); std::memcpy(reply.data() + at, &v, 4);
}
void put_u64(uint64_t v) {
put_u32(static_cast<uint32_t>(v));
put_u32(static_cast<uint32_t>(v >> 32));
}
void put_blob(const void* p, uint32_t n) {
const size_t padded = (static_cast<size_t>(n) + 3u) & ~size_t{3};
put_u32(n); const size_t at = reply.size(); reply.resize(at + padded, 0);
if (p && n) std::memcpy(reply.data() + at, p, n);
}
/* Names: the guest's, unless a command that has the host generate them
* (samplers, vertex arrays, queries, transform feedbacks, program pipelines;
* programs and shaders, which host.rs reports) mapped them to the host's. */
std::unordered_map<uint32_t, GLuint> buffers, textures, framebuffers, renderbuffers, queries, samplers,
vertex_arrays, transform_feedbacks, shaders, programs, program_pipelines;
const GLuint default_vao = 0;
GLint current_clear_stencil = 0;
std::vector<GLenum> current_draw_buffers;
GLuint lookup(const std::unordered_map<uint32_t, GLuint>& map, uint32_t name) {
if (!name) return 0;
auto it = map.find(name);
return it == map.end() ? name : it->second;
}
GLuint lookup_program_or_shader(uint32_t name) {
auto p = programs.find(name);
if (p != programs.end()) return p->second;
return lookup(shaders, name);
}
uint32_t external_name(const std::unordered_map<uint32_t, GLuint>& map, GLuint name) {
if (!name) return 0;
for (const auto& [external, internal] : map)
if (internal == name) return external;
return name;
}
template <typename Fn>
bool gexgl_negative_count(GLsizei n, Fn call) {
if (n >= 0) return false;
call(n, static_cast<GLuint*>(nullptr));
return true;
}
#define GEXGEN_NAME(kind, name) lookup(kind, name)
size_t integer_query_components(GLenum pname) {
switch (pname) {
case GL_VIEWPORT:
case GL_SCISSOR_BOX:
case GL_COLOR_WRITEMASK:
case GL_COLOR_CLEAR_VALUE:
case GL_BLEND_COLOR:
return 4;
case GL_DEPTH_RANGE:
case GL_MAX_VIEWPORT_DIMS:
case GL_ALIASED_POINT_SIZE_RANGE:
case GL_ALIASED_LINE_WIDTH_RANGE:
case GL_POINT_SIZE_RANGE:
case GL_SMOOTH_LINE_WIDTH_RANGE:
case GL_VIEWPORT_BOUNDS_RANGE:
case GL_POLYGON_MODE:
return 2;
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
return 3;
case GL_COMPRESSED_TEXTURE_FORMATS: {
GLint count = 0;
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &count);
return static_cast<size_t>(std::clamp(count, 0, 4096));
}
case GL_PROGRAM_BINARY_FORMATS: {
GLint count = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &count);
return static_cast<size_t>(std::clamp(count, 0, 4096));
}
case GL_SHADER_BINARY_FORMATS: {
GLint count = 0;
glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &count);
return static_cast<size_t>(std::clamp(count, 0, 4096));
}
default:
return 1;
}
}
uint32_t gexgl_state_query_components(GLenum pname) {
return static_cast<uint32_t>(integer_query_components(pname));
}
uint32_t uniform_components(GLuint program, GLint location) {
GLint count = 0, max_name = 0;
GEX_GL_CALL(glGetProgramiv, program, GL_ACTIVE_UNIFORMS, &count);
GEX_GL_CALL(glGetProgramiv, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name);
std::vector<char> name(std::max(max_name, 1));
GLenum type = 0;
for (GLint i = 0; i < count; ++i) {
GLsizei length = 0; GLint size = 0; GLenum candidate = 0;
GEX_GL_CALL(glGetActiveUniform, program, i, (GLsizei)name.size(), &length, &size, &candidate, name.data());
if (GEX_GL_CALL(glGetUniformLocation, program, name.data()) == location) { type = candidate; break; }
}
switch (type) {
case GL_FLOAT_VEC2: case GL_INT_VEC2: case GL_UNSIGNED_INT_VEC2: case GL_BOOL_VEC2:
case GL_DOUBLE_VEC2: return 2;
case GL_FLOAT_VEC3: case GL_INT_VEC3: case GL_UNSIGNED_INT_VEC3: case GL_BOOL_VEC3:
case GL_DOUBLE_VEC3: return 3;
case GL_FLOAT_VEC4: case GL_INT_VEC4: case GL_UNSIGNED_INT_VEC4: case GL_BOOL_VEC4:
case GL_DOUBLE_VEC4: return 4;
case GL_FLOAT_MAT2: case GL_DOUBLE_MAT2: return 4;
case GL_FLOAT_MAT3: case GL_DOUBLE_MAT3: return 9;
case GL_FLOAT_MAT4: case GL_DOUBLE_MAT4: return 16;
case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT3x2:
case GL_DOUBLE_MAT2x3: case GL_DOUBLE_MAT3x2: return 6;
case GL_FLOAT_MAT2x4: case GL_FLOAT_MAT4x2:
case GL_DOUBLE_MAT2x4: case GL_DOUBLE_MAT4x2: return 8;
case GL_FLOAT_MAT3x4: case GL_FLOAT_MAT4x3:
case GL_DOUBLE_MAT3x4: case GL_DOUBLE_MAT4x3: return 12;
default: return 1;
}
}
/* The direct calls the 4.4 cases make, through the proc table like the rest
* (generated by build.rs): the native host links only EGL and GLES, not a
* desktop GL library. */
#include "gexgl-direct-calls.h"
#include "../../../web/mesa/gl-compat-generated-decoders.inc"
/* The hand-written opcodes, by name (crates/gex-gl/src/proto.rs). */
enum Op : uint32_t {
#include "gexgl-hand-ops.h"
};
bool one(uint32_t op, Reader& a) {
switch (op) {
#include "hand-cases.inc"
#include "../../../web/mesa/gl44-generated-cases.inc"
#include "../../../web/mesa/gl-compat-generated-cases.inc"
default:
return false;
}
return a.ok;
}
} // namespace
/* Run one generated command. 1 if it ran (its reply, possibly empty, at
* *reply_out), 0 if the opcode is not one of them, -1 if it was malformed. */
extern "C" int gexgl_native_one(uint32_t op, const uint8_t* body, size_t len,
const uint8_t** reply_out, size_t* reply_len) {
reply.clear();
Reader a{body, body + len};
const bool ok = one(op, a);
const bool known = ok || !a.ok || op >= 1024;
*reply_out = reply.data();
*reply_len = reply.size();
if (!known) return 0;
if (!ok) return a.ok ? 0 : -1;
return 1;
}
/* A glPixelStorei host.rs ran, which pixel-sized cases here read. */
extern "C" void gexgl_native_pixel_store(uint32_t pname, int32_t param) {
(void)gexgl_set_pixel_store(&pack_store, &unpack_store, pname, param);
}
/* A shader (kind 0) or program (kind 1) host.rs created (host != 0) or
* deleted (host == 0). */
extern "C" void gexgl_native_name(uint32_t kind, uint32_t guest, uint32_t host) {
auto& map = kind == 0 ? shaders : programs;
if (host) map[guest] = host;
else map.erase(guest);
}
+316
View File
@@ -0,0 +1,316 @@
/* The hand-written wire commands crates/gex-gl/src/host.rs does not decode
* itself, for the native host: copied from the browser's decoder
* (web/mesa/gexgl-mesa.cpp's `one`) by the list of opcodes host.rs lacks, so
* a Linux guest's and opengl32's batches run the same on both hosts. Keep
* them in step with that file. Included by gexgl-native.cpp, inside its
* switch. */
case DEPTH_MASK: glDepthMask(a.u32()); break;
case HINT: { GLenum target=a.u32(), mode=a.u32(); glHint(target,mode); break; }
case COLOR_MASK: { GLboolean r=a.u32(), g=a.u32(), b=a.u32(), alpha=a.u32(); glColorMask(r,g,b,alpha); break; }
case BLEND_EQUATION: glBlendEquation(a.u32()); break;
case BLEND_COLOR: { GLfloat r=a.f32(), g=a.f32(), b=a.f32(), alpha=a.f32(); glBlendColor(r,g,b,alpha); break; }
case BLEND_EQUATION_SEPARATE: { GLenum rgb=a.u32(), alpha=a.u32(); glBlendEquationSeparate(rgb,alpha); break; }
case CLEAR_BUFFER_FV: {
GLenum b=a.u32(); GLint d=a.i32(); GLfloat v[4]; for(float& x:v)x=a.f32();
glClearBufferfv(b,d,v);
break;
}
case CLEAR_BUFFER_IV: {
GLenum b=a.u32(); GLint d=a.i32(); GLint v[4]; for(int& x:v)x=a.i32();
glClearBufferiv(b,d,v);
break;
}
case CLEAR_BUFFER_UIV: {
GLenum b=a.u32(); GLint d=a.i32(); GLuint v[4]; for(unsigned& x:v)x=a.u32();
glClearBufferuiv(b,d,v);
break;
}
case CLEAR_BUFFER_FI: {
GLenum b=a.u32(); GLint d=a.i32(); GLfloat depth=a.f32(); GLint stencil=a.i32();
glClearBufferfi(b,d,depth,stencil);
break;
}
case STENCIL_FUNC: { GLenum func=a.u32(); GLint ref=a.i32(); GLuint mask=a.u32(); glStencilFunc(func,ref,mask); break; }
case STENCIL_FUNC_SEPARATE: { GLenum face=a.u32(), func=a.u32(); GLint ref=a.i32(); GLuint mask=a.u32(); glStencilFuncSeparate(face,func,ref,mask); break; }
case STENCIL_MASK: glStencilMask(a.u32()); break;
case STENCIL_MASK_SEPARATE: { GLenum face=a.u32(); GLuint mask=a.u32(); glStencilMaskSeparate(face,mask); break; }
case STENCIL_OP: { GLenum fail=a.u32(), zfail=a.u32(), zpass=a.u32(); glStencilOp(fail,zfail,zpass); break; }
case STENCIL_OP_SEPARATE: { GLenum face=a.u32(), fail=a.u32(), zfail=a.u32(), zpass=a.u32(); glStencilOpSeparate(face,fail,zfail,zpass); break; }
case POLYGON_OFFSET: { GLfloat factor=a.f32(), units=a.f32(); glPolygonOffset(factor,units); break; }
case LINE_WIDTH: glLineWidth(a.f32()); break;
case CLEAR_STENCIL: current_clear_stencil=a.i32(); glClearStencil(current_clear_stencil); break;
case DEPTH_RANGE: { GLfloat near_value=a.f32(), far_value=a.f32(); glDepthRangef(near_value,far_value); break; }
case GEN_QUERIES: {
GLsizei n = a.i32();
if (n < 0) { glGenQueries(n, nullptr); break; }
std::vector<GLuint> ids(static_cast<size_t>(n)); glGenQueries(n, ids.data());
for (GLsizei i = 0; i < n; ++i) queries[a.u32()] = ids[static_cast<size_t>(i)];
break;
}
case DELETE_QUERIES: {
GLsizei n = a.i32();
if (n < 0) { glDeleteQueries(n, nullptr); break; }
std::vector<GLuint> ids; ids.reserve(static_cast<size_t>(n));
for (GLsizei i = 0; i < n; ++i) { uint32_t g=a.u32(); ids.push_back(lookup(queries,g)); queries.erase(g); }
glDeleteQueries(n, ids.data()); break;
}
case IS_QUERY: put_u32(glIsQuery(lookup(queries, a.u32()))); break;
case GEN_TRANSFORM_FEEDBACKS: {
GLsizei n = a.i32();
if (n < 0) { glGenTransformFeedbacks(n, nullptr); break; }
std::vector<GLuint> ids(static_cast<size_t>(n)); glGenTransformFeedbacks(n, ids.data());
for (GLsizei i = 0; i < n; ++i) transform_feedbacks[a.u32()] = ids[static_cast<size_t>(i)];
break;
}
case DELETE_TRANSFORM_FEEDBACKS: {
GLsizei n = a.i32();
if (n < 0) { glDeleteTransformFeedbacks(n, nullptr); break; }
std::vector<GLuint> ids; ids.reserve(static_cast<size_t>(n));
for (GLsizei i = 0; i < n; ++i) { uint32_t g=a.u32(); ids.push_back(lookup(transform_feedbacks,g)); transform_feedbacks.erase(g); }
glDeleteTransformFeedbacks(n, ids.data()); break;
}
case BIND_TRANSFORM_FEEDBACK: {
GLenum target=a.u32(); GLuint id=lookup(transform_feedbacks,a.u32());
glBindTransformFeedback(target,id); break;
}
case IS_TRANSFORM_FEEDBACK: put_u32(glIsTransformFeedback(lookup(transform_feedbacks,a.u32()))); break;
case PAUSE_TRANSFORM_FEEDBACK: glPauseTransformFeedback(); break;
case RESUME_TRANSFORM_FEEDBACK: glResumeTransformFeedback(); break;
case BIND_BUFFER_BASE: {
GLenum target = a.u32(); GLuint index = a.u32();
glBindBufferBase(target, index, lookup(buffers, a.u32())); break;
}
case GEN_SAMPLERS: {
GLsizei n = a.i32();
if (gexgl_negative_count(n, [](GLsizei c, GLuint *p) { glGenSamplers(c, p); })) break;
std::vector<GLuint> ids(n); glGenSamplers(n, ids.data());
for (uint32_t i = 0; i < n; ++i) samplers[a.u32()] = ids[i]; break;
}
case DELETE_SAMPLERS: {
uint32_t n = a.u32(); std::vector<GLuint> ids; ids.reserve(n);
for (uint32_t i = 0; i < n; ++i) { uint32_t g=a.u32(); ids.push_back(lookup(samplers,g)); samplers.erase(g); }
glDeleteSamplers(n, ids.data()); break;
}
case BIND_SAMPLER: { GLuint unit=a.u32(); glBindSampler(unit, lookup(samplers,a.u32())); break; }
case SAMPLER_PARAMETER_I: {
GLuint sampler = lookup(samplers, a.u32()); GLenum pname = a.u32();
GLint values[4]{}; const size_t count = pname == GL_TEXTURE_BORDER_COLOR ? 4u : 1u;
for (size_t i = 0; i < count; ++i) values[i] = a.i32();
if (count == 4) glSamplerParameteriv(sampler, pname, values);
else glSamplerParameteri(sampler, pname, values[0]);
break;
}
case SAMPLER_PARAMETER_F: {
GLuint sampler = lookup(samplers, a.u32()); GLenum pname = a.u32();
GLfloat values[4]{}; const size_t count = pname == GL_TEXTURE_BORDER_COLOR ? 4u : 1u;
for (size_t i = 0; i < count; ++i) values[i] = a.f32();
if (count == 4) glSamplerParameterfv(sampler, pname, values);
else glSamplerParameterf(sampler, pname, values[0]);
break;
}
case DETACH_SHADER: { GLuint p = lookup(programs, a.u32()); glDetachShader(p, lookup(shaders, a.u32())); break; }
case GET_UNIFORM_BLOCK_INDEX: { GLuint p = lookup(programs, a.u32()); std::string n = a.string(); put_u32(glGetUniformBlockIndex(p, n.c_str())); break; }
case UNIFORM_BLOCK_BINDING: { GLuint p = lookup(programs, a.u32()); GLuint i = a.u32(); glUniformBlockBinding(p, i, a.u32()); break; }
case GET_ATTACHED_SHADERS: {
uint32_t gp = a.u32(), max_count = a.u32(); GLuint p = lookup(programs, gp);
std::vector<GLuint> ids(max_count); GLsizei count = 0;
glGetAttachedShaders(p, max_count, &count, ids.data());
put_u32(count);
for (GLsizei i = 0; i < count; ++i) {
uint32_t guest = 0;
for (const auto &entry : shaders) if (entry.second == ids[i]) { guest = entry.first; break; }
put_u32(guest);
}
break;
}
case UNIFORM_2I: { GLint l=a.i32(), x=a.i32(), y=a.i32(); glUniform2i(l,x,y); break; }
case UNIFORM_3I: { GLint l=a.i32(), x=a.i32(), y=a.i32(), z=a.i32(); glUniform3i(l,x,y,z); break; }
case UNIFORM_4I: { GLint l=a.i32(), x=a.i32(), y=a.i32(), z=a.i32(), w=a.i32(); glUniform4i(l,x,y,z,w); break; }
case GET_ACTIVE_UNIFORM:
case GET_ACTIVE_ATTRIB:
case GET_TRANSFORM_FEEDBACK_VARYING: {
GLuint program = lookup(programs, a.u32()); GLuint index = a.u32();
GLenum length_query = op == GET_ACTIVE_UNIFORM
? GL_ACTIVE_UNIFORM_MAX_LENGTH
: op == GET_ACTIVE_ATTRIB
? GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
: GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH;
GLint max_len = 0;
glGetProgramiv(program, length_query, &max_len);
std::vector<char> name(std::max(max_len, 1)); GLsizei length = 0; GLint size = 0; GLenum type = 0;
if (op == GET_ACTIVE_UNIFORM) glGetActiveUniform(program, index, name.size(), &length, &size, &type, name.data());
else if (op == GET_ACTIVE_ATTRIB) glGetActiveAttrib(program, index, name.size(), &length, &size, &type, name.data());
else glGetTransformFeedbackVarying(program, index, name.size(), &length, &size, &type, name.data());
put_u32(size); put_u32(type); put_blob(name.data(), length); break;
}
case GET_ACTIVE_UNIFORM_NAME:
case GET_ACTIVE_UNIFORM_BLOCK_NAME: {
GLuint program = lookup(programs, a.u32()); GLuint index = a.u32();
GLint max_len = 0;
glGetProgramiv(program,
op == GET_ACTIVE_UNIFORM_NAME
? GL_ACTIVE_UNIFORM_MAX_LENGTH
: GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
&max_len);
std::vector<char> name(std::max(max_len, 1));
GLsizei length = 0;
if (op == GET_ACTIVE_UNIFORM_NAME)
glGetActiveUniformName(program, index, name.size(), &length, name.data());
else
glGetActiveUniformBlockName(program, index, name.size(), &length, name.data());
put_blob(name.data(), length); break;
}
case GET_ACTIVE_UNIFORM_BLOCKIV: {
GLuint program = lookup(programs, a.u32());
GLuint index = a.u32();
GLenum pname = a.u32();
/* Only one query returns more than a single integer, and its length is
* itself a query. */
GLint count = 1;
if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
glGetActiveUniformBlockiv(program, index,
GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &count);
std::vector<GLint> params(std::max(count, 1), 0);
glGetActiveUniformBlockiv(program, index, pname, params.data());
put_blob(params.data(), std::max(count, 0) * sizeof(GLint)); break;
}
case GET_ACTIVE_UNIFORMSIV: {
GLuint program = lookup(programs, a.u32());
GLenum pname = a.u32();
uint32_t bytes = 0;
const uint8_t* raw = a.blob(bytes);
const GLsizei count = (GLsizei)(bytes / sizeof(GLuint));
std::vector<GLuint> indices(count);
if (count) memcpy(indices.data(), raw, (size_t)count * sizeof(GLuint));
std::vector<GLint> params(std::max(count, 1), 0);
glGetActiveUniformsiv(program, count, indices.data(), pname, params.data());
put_blob(params.data(), (size_t)count * sizeof(GLint)); break;
}
case GET_UNIFORM_INDICES: {
GLuint program = lookup(programs, a.u32());
const GLsizei count = (GLsizei)a.u32();
uint32_t bytes = 0;
const uint8_t* raw = a.blob(bytes);
/* One blob of NUL-terminated names; walk it rather than trusting a
* separate length array the guest would have had to build. */
std::vector<const GLchar*> names;
const char* at = reinterpret_cast<const char*>(raw);
const char* end = at + bytes;
for (GLsizei i = 0; i < count && at < end; ++i) {
names.push_back(at);
at += strnlen(at, (size_t)(end - at)) + 1;
}
std::vector<GLuint> indices(std::max<size_t>(names.size(), 1),
GL_INVALID_INDEX);
if (!names.empty())
glGetUniformIndices(program, (GLsizei)names.size(), names.data(),
indices.data());
put_blob(indices.data(), names.size() * sizeof(GLuint)); break;
}
case GET_SHADER_SOURCE: {
GLuint shader = lookup(shaders, a.u32());
GLint max_len = 0;
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &max_len);
std::vector<char> source(std::max(max_len, 1));
GLsizei length = 0;
glGetShaderSource(shader, source.size(), &length, source.data());
put_blob(source.data(), length); break;
}
#define GEX_UNIFORM_VECTOR(OP, FN, TYPE) case OP: { GLint l=a.i32(); GLsizei n=a.i32(); uint32_t bytes; const uint8_t*p=a.blob(bytes); FN(l,n,reinterpret_cast<const TYPE*>(p)); break; }
GEX_UNIFORM_VECTOR(UNIFORM_1IV, glUniform1iv, GLint)
GEX_UNIFORM_VECTOR(UNIFORM_1FV, glUniform1fv, GLfloat)
GEX_UNIFORM_VECTOR(UNIFORM_2FV, glUniform2fv, GLfloat)
GEX_UNIFORM_VECTOR(UNIFORM_3FV, glUniform3fv, GLfloat)
GEX_UNIFORM_VECTOR(UNIFORM_4FV, glUniform4fv, GLfloat)
GEX_UNIFORM_VECTOR(UNIFORM_2IV, glUniform2iv, GLint)
GEX_UNIFORM_VECTOR(UNIFORM_3IV, glUniform3iv, GLint)
GEX_UNIFORM_VECTOR(UNIFORM_4IV, glUniform4iv, GLint)
#undef GEX_UNIFORM_VECTOR
case UNIFORM_MATRIX2FV: {GLint l=a.i32();GLsizei n=a.i32();GLboolean t=a.u32();uint32_t bytes;const uint8_t*p=a.blob(bytes);glUniformMatrix2fv(l,n,t,reinterpret_cast<const GLfloat*>(p));break;}
case UNIFORM_MATRIX3FV: {GLint l=a.i32();GLsizei n=a.i32();GLboolean t=a.u32();uint32_t bytes;const uint8_t*p=a.blob(bytes);glUniformMatrix3fv(l,n,t,reinterpret_cast<const GLfloat*>(p));break;}
case VERTEX_ATTRIB_I_POINTER: {
GLuint i = a.u32(); GLint size = a.i32(); GLenum type = a.u32();
GLsizei stride = a.i32(); uintptr_t off = a.u32();
glVertexAttribIPointer(i, size, type, stride, reinterpret_cast<void*>(off)); break;
}
case VERTEX_ATTRIB_DIVISOR: { GLuint index=a.u32(), divisor=a.u32();
glVertexAttribDivisor(index,divisor); break; }
case VERTEX_ATTRIB_4F: { GLuint index=a.u32(); GLfloat x=a.f32(), y=a.f32(), z=a.f32(), w=a.f32(); glVertexAttrib4f(index,x,y,z,w); break; }
case VERTEX_ATTRIB_I4I: { GLuint index=a.u32(); GLint x=a.i32(), y=a.i32(), z=a.i32(), w=a.i32(); glVertexAttribI4i(index,x,y,z,w); break; }
case GEN_VERTEX_ARRAYS: {
GLsizei n = a.i32();
if (gexgl_negative_count(n, [](GLsizei c, GLuint *p) { glGenVertexArrays(c, p); })) break;
std::vector<GLuint> ids(n); glGenVertexArrays(n, ids.data());
for(uint32_t i=0;i<n;++i) vertex_arrays[a.u32()]=ids[i]; break;
}
case DELETE_VERTEX_ARRAYS: {
uint32_t n=a.u32(); std::vector<GLuint> ids; ids.reserve(n);
for(uint32_t i=0;i<n;++i){uint32_t g=a.u32();ids.push_back(lookup(vertex_arrays,g));vertex_arrays.erase(g);} glDeleteVertexArrays(n,ids.data());break;
}
case BIND_VERTEX_ARRAY: { uint32_t g=a.u32(); glBindVertexArray(g ? lookup(vertex_arrays,g) : default_vao); break; }
case TEX_PARAMETER_F: { GLenum target=a.u32(), pname=a.u32(); GLfloat value=a.f32(); glTexParameterf(target,pname,value); break; }
case TEX_PARAMETER_FV: {
GLenum target=a.u32(), pname=a.u32(); GLfloat value[4]{};
const size_t count = (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_SWIZZLE_RGBA) ? 4 : 1;
for (size_t i = 0; i < count; ++i) value[i]=a.f32();
glTexParameterfv(target,pname,value);
break;
}
case TEX_PARAMETER_IV: {
GLenum target=a.u32(), pname=a.u32(); GLint value[4]{};
const size_t count = (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_SWIZZLE_RGBA) ? 4 : 1;
for (size_t i = 0; i < count; ++i) value[i]=a.i32();
glTexParameteriv(target,pname,value);
break;
}
case DRAW_BUFFERS: {
GLsizei n = a.i32(); current_draw_buffers.resize(std::max(n, 0));
for (GLsizei i = 0; i < n; ++i) current_draw_buffers[i] = a.u32();
glDrawBuffers(n, current_draw_buffers.data()); break;
}
case DRAW_ARRAYS_INSTANCED: { GLenum mode=a.u32(); GLint first=a.i32(); GLsizei count=a.i32(), instances=a.i32(); glDrawArraysInstanced(mode,first,count,instances); break; }
case DRAW_ELEMENTS_INSTANCED: {
GLenum mode=a.u32(); GLsizei n=a.i32(); GLenum type=a.u32(); uintptr_t off=a.u32(); GLsizei instances=a.i32();
glDrawElementsInstanced(mode,n,type,reinterpret_cast<void*>(off),instances); break;
}
case BLIT_FRAMEBUFFER: {
GLint sx0=a.i32(),sy0=a.i32(),sx1=a.i32(),sy1=a.i32();
GLint dx0=a.i32(),dy0=a.i32(),dx1=a.i32(),dy1=a.i32();
GLbitfield mask=a.u32(); GLenum filter=a.u32();
glBlitFramebuffer(sx0,sy0,sx1,sy1,dx0,dy0,dx1,dy1,mask,filter); break;
}
case GENERATE_MIPMAP: glGenerateMipmap(a.u32()); break;
case TEX_STORAGE_2D: { GLenum target=a.u32(); GLsizei levels=a.i32(); GLenum format=a.u32(); GLsizei w=a.i32(), h=a.i32(); glTexStorage2D(target,levels,format,w,h); break; }
case TEX_STORAGE_3D: { GLenum target=a.u32(); GLsizei levels=a.i32(); GLenum format=a.u32(); GLsizei w=a.i32(), h=a.i32(), d=a.i32(); glTexStorage3D(target,levels,format,w,h,d); break; }
case TEX_IMAGE_3D: {
GLenum t=a.u32();GLint l=a.i32(),in=a.i32();GLsizei w=a.i32(),h=a.i32(),d=a.i32();
GLint border=a.i32();GLenum f=a.u32(),ty=a.u32();bool pbo=a.u32()!=0;
uintptr_t pointer=static_cast<uintptr_t>(a.u64());uint32_t n;const uint8_t* bytes=a.blob(n);
gexgl_pixel_layout layout{};
const bool valid=gexgl_compute_pixel_layout(f,ty,w,h,d,&unpack_store,&layout);
if ((pbo && n != 0) || (!pbo && pointer && (!valid || layout.end != n))) {
a.ok=false;break;
}
const void* data=pbo?reinterpret_cast<const void*>(pointer):(pointer?bytes:nullptr);
glTexImage3D(t,l,in,w,h,d,border,f,ty,data);break;
}
case FRAMEBUFFER_TEXTURE_LAYER: {GLenum t=a.u32(),att=a.u32();GLuint tex=lookup(textures,a.u32());GLint level=a.i32(),layer=a.i32();glFramebufferTextureLayer(t,att,tex,level,layer);break;}
case GET_STRING_I: {
GLenum name = a.u32(); GLuint index = a.u32();
const char* s = reinterpret_cast<const char*>(glGetStringi(name, index));
put_blob(s, s ? std::strlen(s) : 0);
break;
}
case GET_UNIFORM_FV:
case GET_UNIFORM_IV: {
GLuint program=lookup_program_or_shader(a.u32()); GLint location=a.i32();
uint32_t components=uniform_components(program,location);
if (op == GET_UNIFORM_FV) {
GLfloat values[16] = {}; glGetUniformfv(program,location,values);
put_blob(values,components*sizeof(values[0]));
} else {
GLint values[16] = {}; glGetUniformiv(program,location,values);
put_blob(values,components*sizeof(values[0]));
}
break;
}
File diff suppressed because it is too large. Load diff
+41 -3
View File
@@ -751,10 +751,23 @@ impl Gl {
/// Run one batch. Returns the reply and, if the stream was malformed,
/// where and why.
pub fn run(&mut self, batch: &[u8]) -> (Reply, u32, u32) {
let mut reply = Reply::default();
if self.make_current().is_err() {
return (reply, error::NO_CONTEXT, 0);
return (Reply::default(), error::NO_CONTEXT, 0);
}
let r = self.run_current(batch);
// Released after every batch: a guest may submit from any of its
// threads (wined3d's command stream thread and the main one), and a
// context still current on one thread cannot be made current on
// another. Batches are already serialized by the device.
unsafe {
eglMakeCurrent(self.display, std::ptr::null_mut(), std::ptr::null_mut(), std::ptr::null_mut());
}
self.current_on = None;
r
}
fn run_current(&mut self, batch: &[u8]) -> (Reply, u32, u32) {
let mut reply = Reply::default();
let mut commands = Commands::new(batch);
let mut index = 0u32;
loop {
@@ -939,6 +952,7 @@ impl Gl {
if let (Some(p), Some(v)) = (a.u32(), a.i32()) {
glPixelStorei(p, v);
set_pixel_store(&mut self.pack_store, &mut self.unpack_store, p, v);
native::gexgl_native_pixel_store(p, v);
}
}
@@ -1007,6 +1021,7 @@ impl Gl {
};
let real = glCreateShader(ty);
self.names.shaders.insert(name, real);
native::gexgl_native_name(0, name, real);
}
op::SHADER_SOURCE => {
let (Some(name), Some(src)) = (a.u32(), a.blob()) else {
@@ -1027,6 +1042,7 @@ impl Gl {
op::DELETE_SHADER => {
if let Some(n) = a.u32() {
if let Some(real) = self.names.shaders.remove(&n) {
native::gexgl_native_name(0, n, 0);
glDeleteShader(real);
}
}
@@ -1035,6 +1051,7 @@ impl Gl {
if let Some(name) = a.u32() {
let real = glCreateProgram();
self.names.programs.insert(name, real);
native::gexgl_native_name(1, name, real);
}
}
op::ATTACH_SHADER => {
@@ -1069,6 +1086,7 @@ impl Gl {
op::DELETE_PROGRAM => {
if let Some(n) = a.u32() {
if let Some(real) = self.names.programs.remove(&n) {
native::gexgl_native_name(1, n, 0);
glDeleteProgram(real);
}
}
@@ -1555,13 +1573,33 @@ impl Gl {
_ => return false,
}
}
_ => return false,
// The generated commands (GL 4.4 and the registry's
// compatibility profile) are decoded by the C++ shared with
// the browser's host.
_ => {
let (mut out, mut len) = (std::ptr::null(), 0usize);
if native::gexgl_native_one(opcode, body.as_ptr(), body.len(), &mut out, &mut len) != 1 {
return false;
}
if len > 0 {
reply.bytes.extend_from_slice(std::slice::from_raw_parts(out, len));
}
}
}
}
true
}
}
/// native/gexgl-native.cpp (built by build.rs).
mod native {
extern "C" {
pub fn gexgl_native_one(op: u32, body: *const u8, len: usize, reply: *mut *const u8, reply_len: *mut usize) -> i32;
pub fn gexgl_native_pixel_store(pname: u32, param: i32);
pub fn gexgl_native_name(kind: u32, guest: u32, host: u32);
}
}
/// Read a [`Header`] out of the front of a shared buffer.
pub fn read_header(bytes: &[u8]) -> Option<Header> {
if bytes.len() < Header::SIZE {
+1
View File
@@ -3,6 +3,7 @@
//! See [`proto`] for why the split is at the API rather than at a virtual
//! GPU, and [`host`] for what runs the commands.
pub mod compat_plans;
pub mod proto;
pub mod trace;
+3 -1
View File
@@ -17,7 +17,9 @@
pub const MAGIC: u32 = 0x4758_4547;
/// Version of the command ABI. A guest and host must agree before any opcode
/// is decoded; generated opcode policy changes require incrementing this.
pub const PROTOCOL_VERSION: u32 = 12;
/// 13: the registry's compatibility-profile commands (tools/gen_gl_compat.py,
/// opcodes from [`crate::compat_plans::COMPAT_BASE`]).
pub const PROTOCOL_VERSION: u32 = 13;
/// The fixed header at the start of the shared buffer. `repr(C)` for the C
/// guest half; every field 32 bits, 32 bytes total.
+50
View File
@@ -0,0 +1,50 @@
//! The generated compatibility-profile plans (tools/gen_gl_compat.py) are
//! well-formed: every opcode is its own and past the hand-written and GL 4.4
//! ones, every token is one the encoders and decoders know, and every count
//! names a parameter the command has.
use gex_gl::compat_plans::{COMPAT_BASE, PLANS};
use std::collections::HashSet;
#[test]
fn plans_are_well_formed() {
assert!(PLANS.len() > 2000, "the registry's commands are planned");
let mut opcodes = HashSet::new();
for (name, opcode, plan) in PLANS {
assert!(*opcode >= COMPAT_BASE, "{name}: opcode {opcode}");
assert!(opcodes.insert(*opcode), "{name}: opcode {opcode} twice");
let toks: Vec<&str> = plan.split(' ').collect();
assert!(matches!(toks[0], "v" | "w" | "f" | "q"), "{name}: return {}", toks[0]);
let params = toks.len() - 1;
for t in &toks[1..] {
match t.as_bytes()[0] {
b'w' | b'f' | b'q' | b'P' => assert_eq!(t.len(), 1, "{name}: {t}"),
b'i' | b'j' | b'o' => {
let (size, spec) = t[1..].split_once(':').unwrap_or_else(|| panic!("{name}: {t}"));
assert!(matches!(size, "1" | "2" | "4" | "8"), "{name}: element size {size}");
let kind = spec.as_bytes()[0];
assert!(b"npezLsSXBTU".contains(&kind), "{name}: count {spec}");
for arg in spec[1..].split([',', '*']).filter(|a| !a.is_empty() && *a != "_") {
let v: usize = arg.parse().unwrap_or_else(|_| panic!("{name}: {spec}"));
// A multiplier, an element count, or a parameter.
if kind != b'n' && !spec.contains(&format!("*{arg}")) {
assert!(v < params, "{name}: {spec} names parameter {v} of {params}");
}
}
}
_ => panic!("{name}: token {t}"),
}
}
}
}
#[test]
fn fixed_function_commands_are_planned() {
// What a GL 1.1 renderer (GoldSrc's) and wined3d's fixed-function
// pipeline call that no hand-written command covers.
for want in ["glOrtho", "glTexCoord2f", "glFogfv", "glClipPlane", "glMultiTexCoord2f", "glGetTexEnvfv", "glDrawPixels", "glBitmap"] {
assert!(PLANS.iter().any(|(n, _, _)| *n == want), "{want} has no plan");
}
let fog = PLANS.iter().find(|(n, _, _)| *n == "glFogfv").unwrap();
assert_eq!(fog.2, "v w i4:e0", "glFogfv: a pname-sized float vector");
}
+3
View File
@@ -28,6 +28,9 @@ fi
# This deliberately fails closed if a pointer-shaped command has no explicit
# wire policy in tools/gen_gl44_transport.py.
python3 "$ROOT/tools/gen_gl44_transport.py"
# And every other registry command with a wire plan: the guest's entry
# points, opengl32's plans and the hosts' decoder (tools/gen_gl_compat.py).
python3 "$ROOT/tools/gen_gl_compat.py"
# The opcodes come from the Rust side, so the two cannot drift.
python3 - "$ROOT" "$HERE" <<'PYEOF'
+86
View File
@@ -0,0 +1,86 @@
/* Wire plans (tools/gen_gl_compat.py): what both ends of a generated
* command agree on. A plan is a return token then one token per parameter;
* this parses them and sizes their arrays, for the guest's interpreter
* (gexgl.c) and the host decoders (web/mesa/gexgl-compat-host.h), so the
* size an encoder sends is the one a decoder checks. C and C++. */
#ifndef GEXGL_PLAN_H
#define GEXGL_PLAN_H
#include <stddef.h>
#include <stdint.h>
#include "gexgl-pixel.h"
#include "gl-pname-counts.h"
#define GEXGEN_MAX_PARAMS 24
/* No single array is larger than this on the wire. */
#define GEXGEN_MAX_BYTES ((size_t)1 << 28)
struct gexgen_tok {
char kind; /* w f q: scalars; i j: input arrays; o: output */
unsigned size; /* element bytes, for arrays */
char spec; /* n p e z L s S X B T */
int arg[5]; /* parameter indices (-1 absent) or N / multiplier */
};
/* A non-negative element count from a signed parameter, times `mult`,
* saturating at what the wire can carry. */
static inline size_t gexgen_count(long long value, long long mult) {
if (value <= 0 || mult <= 0) return 0;
if ((unsigned long long)value > GEXGEN_MAX_BYTES / (unsigned long long)mult) return GEXGEN_MAX_BYTES;
return (size_t)(value * mult);
}
/* glCallLists' element types. */
static inline size_t gexgen_type_bytes(unsigned type) {
switch (type) {
case 0x1400: case 0x1401: return 1; /* BYTE, UNSIGNED_BYTE */
case 0x1402: case 0x1403: case 0x1407: return 2; /* SHORT, UNSIGNED_SHORT, 2_BYTES */
case 0x1408: return 3; /* 3_BYTES */
case 0x1404: case 0x1405: case 0x1406: case 0x1409: return 4; /* INT, UNSIGNED_INT, FLOAT, 4_BYTES */
default: return 0;
}
}
/* A glBitmap's bytes under the unpack store: rows of (row length or width)
* bits, each padded to the alignment, after the skipped rows and pixels. */
static inline size_t gexgen_bitmap_bytes_store(long long width, long long height,
const struct gexgl_pixel_store *s) {
if (width <= 0 || height <= 0 || width > 1 << 20 || height > 1 << 20) return 0;
size_t px = s->row_length ? s->row_length : (size_t)width;
size_t row = (px + 7) / 8, a = s->alignment ? s->alignment : 1;
row = (row + a - 1) / a * a;
return (s->skip_rows + (size_t)height) * row + (s->skip_pixels + 7) / 8;
}
/* Parse one token at `p` into `t`; returns past it, or NULL at the end. */
static inline const char *gexgen_parse(const char *p, struct gexgen_tok *t) {
while (*p == ' ') p++;
if (!*p) return NULL;
t->kind = *p++;
t->size = 0;
t->spec = 0;
for (int i = 0; i < 5; i++) t->arg[i] = -1;
if (t->kind == 'i' || t->kind == 'j' || t->kind == 'o') {
while (*p >= '0' && *p <= '9') t->size = t->size * 10 + (unsigned)(*p++ - '0');
if (*p == ':') p++;
t->spec = *p++;
int n = 0;
while (*p && *p != ' ' && n < 5) {
if (*p == '_') { p++; n++; }
else if (*p >= '0' && *p <= '9') {
int v = 0;
while (*p >= '0' && *p <= '9') v = v * 10 + (*p++ - '0');
t->arg[n++] = v;
} else if (*p != ',' && *p != '*') {
p++;
}
if (*p == ',' || *p == '*') p++;
}
/* p<i> without a multiplier multiplies by one. */
if (t->spec == 'p' && t->arg[1] < 0) t->arg[1] = 1;
}
return p;
}
#endif
+105 -1
View File
@@ -55,6 +55,7 @@
#include "gexgl.h"
#include "gexgl-pixel.h"
#include "gexgl-plan.h"
/* ---------------------------------------------------------------- the ring */
@@ -1277,7 +1278,6 @@ void glClientActiveTexture(unsigned unit) {
client_active_texture = unit >= 0x84C0u ? unit - 0x84C0u : 0;
CMD1(GEXGL_CLIENT_ACTIVE_TEXTURE, unit);
}
void glClientActiveTextureARB(unsigned unit) { glClientActiveTexture(unit); }
/* glLockArraysEXT/glUnlockArraysEXT are a promise the arrays will not
change between them; the uploads above already copy at every draw. */
void glLockArraysEXT(int first, int count) { (void)first; (void)count; }
@@ -2129,6 +2129,110 @@ void glGetSynciv(void *sync, unsigned pname, int buf_size, int *length, int *val
as the hand-written pointer/object-aware commands above. */
#include "gl44-generated.inc"
/* ------------------------------------------- the registry's other commands */
/* Every other registry command with a wire plan (tools/gen_gl_compat.py,
guest/gl/gexgl-plan.h) is one call to this, its arguments as 64-bit words
(floats and doubles as their bits, pointers as addresses): the plan says
how each goes on the wire and how many elements an array holds. A command
with a return value or outputs waits for the reply. */
static uint64_t gexgen_dbits(double d) {
uint64_t v;
memcpy(&v, &d, 8);
return v;
}
static size_t gexgen_elements(const struct gexgen_tok *t, const uint64_t *v) {
const void *ptr = (const void *)(uintptr_t)0;
switch (t->spec) {
case 'n': return (size_t)t->arg[0];
case 'p': return gexgen_count((int32_t)v[t->arg[0]], t->arg[1]);
case 'e': return gexgl_pname_count((unsigned)v[t->arg[0]]);
case 'z': return gexgen_count((long long)v[t->arg[0]], 1);
case 'L': return gexgen_count((int32_t)v[t->arg[0]], (long long)gexgen_type_bytes((unsigned)v[t->arg[1]]));
case 'T': return 128;
case 'U': return 16; /* a uniform: the host says how many, at most a 4x4 matrix */
case 'B': return gexgen_bitmap_bytes_store((int32_t)v[t->arg[0]], (int32_t)v[t->arg[1]], &unpack_store);
case 'X': {
struct gexgl_pixel_layout layout;
const int w = (int32_t)v[t->arg[2]];
const int h = t->arg[3] >= 0 ? (int32_t)v[t->arg[3]] : 1;
const int d = t->arg[4] >= 0 ? (int32_t)v[t->arg[4]] : -1;
return gexgl_compute_pixel_layout((uint32_t)v[t->arg[0]], (uint32_t)v[t->arg[1]], w, h, d,
&unpack_store, &layout) ? layout.end : 0;
}
default: (void)ptr; return 0;
}
}
static uint64_t gexgen_call(uint32_t opcode, const char *plan, const uint64_t *v) {
struct gexgen_tok toks[GEXGEN_MAX_PARAMS + 1];
toks[0].kind = 'v';
size_t bytes[GEXGEN_MAX_PARAMS];
int mode[GEXGEN_MAX_PARAMS]; /* inputs: 0 null, 1 data, 2 unpack offset */
int n = 0, outputs = 0;
const char *p = gexgen_parse(plan, &toks[0]);
const char ret = toks[0].kind;
while (p && n < GEXGEN_MAX_PARAMS && (p = gexgen_parse(p, &toks[n + 1]))) n++;
size_t words = 0;
for (int i = 0; i < n; i++) {
const struct gexgen_tok *t = &toks[i + 1];
const void *ptr = (const void *)(uintptr_t)v[i];
switch (t->kind) {
case 'w': case 'f': words += 1; break;
case 'q': words += 2; break;
case 'o': outputs++; break;
default:
if (t->kind == 'j' && bound_buffer(0x88ECu)) { /* GL_PIXEL_UNPACK_BUFFER */
mode[i] = 2; words += 3; break;
}
if (!ptr) { mode[i] = 0; words += 1; break; }
if (t->spec == 's') bytes[i] = strlen((const char *)ptr);
else if (t->spec == 'S') {
const int len = (int32_t)v[t->arg[0]];
bytes[i] = len < 0 ? strlen((const char *)ptr) : (size_t)len;
} else bytes[i] = gexgen_elements(t, v) * t->size;
if (bytes[i] > GEXGEN_MAX_BYTES) bytes[i] = 0;
mode[i] = 1;
words += 2 + (bytes[i] + 3) / 4;
}
}
uint32_t *a = begin(opcode, words, 0);
if (!a) return 0;
for (int i = 0; i < n; i++) {
const struct gexgen_tok *t = &toks[i + 1];
switch (t->kind) {
case 'w': case 'f': *a++ = (uint32_t)v[i]; break;
case 'q': *a++ = (uint32_t)v[i]; *a++ = (uint32_t)(v[i] >> 32); break;
case 'o': break;
default:
*a++ = (uint32_t)mode[i];
if (mode[i] == 2) { *a++ = (uint32_t)v[i]; *a++ = (uint32_t)(v[i] >> 32); }
else if (mode[i] == 1) {
put_blob(a, (const void *)(uintptr_t)v[i], bytes[i]);
a += 1 + (bytes[i] + 3) / 4;
}
}
}
if (ret == 'v' && !outputs) return 0;
flush();
uint64_t r = 0;
if (ret == 'w' || ret == 'f') r = reply_u32();
else if (ret == 'q') { r = reply_u32(); r |= (uint64_t)reply_u32() << 32; }
for (int i = 0; i < n; i++) {
const struct gexgen_tok *t = &toks[i + 1];
if (t->kind != 'o') continue;
uint32_t len = 0;
const uint8_t *src = reply_blob(&len);
const size_t want = gexgen_elements(t, v) * t->size;
void *dst = (void *)(uintptr_t)v[i];
if (dst && src && (len == want || (t->spec == 'U' && len <= want))) memcpy(dst, src, len);
}
return r;
}
#include "gl-compat-generated.inc"
/* --------------------------------------------------------------------- EGL */
/* EGL here is bookkeeping and nothing else. There is one display, one config
+1 -3
View File
@@ -183,7 +183,6 @@
#define GEXGL_END_LIST 182
#define GEXGL_CALL_LIST 183
#define GEXGL_DELETE_LISTS 184
/* Protocol 11: client arrays and fixed-function matrices (proto.rs). */
#define GEXGL_ENABLE_CLIENT_STATE 185
#define GEXGL_DISABLE_CLIENT_STATE 186
#define GEXGL_VERTEX_POINTER 187
@@ -197,7 +196,6 @@
#define GEXGL_COLOR4F 195
#define GEXGL_TEX_ENVI 196
#define GEXGL_ALPHA_FUNC 197
/* Protocol 12: the attribute stack (proto.rs). */
#define GEXGL_PUSH_ATTRIB 198
#define GEXGL_POP_ATTRIB 199
@@ -208,7 +206,7 @@
#define GEXGL_CLIENT_API_DESKTOP 1
#define GEXGL_MAGIC 0x47584547u
#define GEXGL_PROTOCOL_VERSION 12u
#define GEXGL_PROTOCOL_VERSION 13u
#define GEXGL_SUBMIT 0xc0086701u
#define GEXGL_SURFACE 0x40106703u
+144 -1
View File
@@ -4,7 +4,7 @@
* a different name. An extension requires the suffixed spelling even
* when the function has been core, unsuffixed, for twenty years, and
* an extension whose entry points are missing cannot honestly be
* claimed -- so here are the 451 of them whose target this
* claimed -- so here are the 594 of them whose target this
* library already exports. Included last, where every target is
* declared, and typed from the target so the two cannot disagree.
*/
@@ -18,11 +18,13 @@ extern __typeof(glBindAttribLocation) glBindAttribLocationARB __attribute__((ali
extern __typeof(glBindBuffer) glBindBufferARB __attribute__((alias("glBindBuffer")));
extern __typeof(glBindBufferBase) glBindBufferBaseEXT __attribute__((alias("glBindBufferBase")));
extern __typeof(glBindBufferBase) glBindBufferBaseNV __attribute__((alias("glBindBufferBase")));
extern __typeof(glBindBufferOffsetEXT) glBindBufferOffsetNV __attribute__((alias("glBindBufferOffsetEXT")));
extern __typeof(glBindBufferRange) glBindBufferRangeEXT __attribute__((alias("glBindBufferRange")));
extern __typeof(glBindBufferRange) glBindBufferRangeNV __attribute__((alias("glBindBufferRange")));
extern __typeof(glBindFragDataLocation) glBindFragDataLocationEXT __attribute__((alias("glBindFragDataLocation")));
extern __typeof(glBindFragDataLocationIndexed) glBindFragDataLocationIndexedEXT __attribute__((alias("glBindFragDataLocationIndexed")));
extern __typeof(glBindFramebuffer) glBindFramebufferEXT __attribute__((alias("glBindFramebuffer")));
extern __typeof(glBindProgramARB) glBindProgramNV __attribute__((alias("glBindProgramARB")));
extern __typeof(glBindRenderbuffer) glBindRenderbufferEXT __attribute__((alias("glBindRenderbuffer")));
extern __typeof(glBindTexture) glBindTextureEXT __attribute__((alias("glBindTexture")));
extern __typeof(glBindVertexArray) glBindVertexArrayOES __attribute__((alias("glBindVertexArray")));
@@ -57,10 +59,17 @@ extern __typeof(glClampColor) glClampColorARB __attribute__((alias("glClampColor
extern __typeof(glClearDepthf) glClearDepthfOES __attribute__((alias("glClearDepthf")));
extern __typeof(glClearTexImage) glClearTexImageEXT __attribute__((alias("glClearTexImage")));
extern __typeof(glClearTexSubImage) glClearTexSubImageEXT __attribute__((alias("glClearTexSubImage")));
extern __typeof(glClientActiveTexture) glClientActiveTextureARB __attribute__((alias("glClientActiveTexture")));
extern __typeof(glClientWaitSync) glClientWaitSyncAPPLE __attribute__((alias("glClientWaitSync")));
extern __typeof(glClipControl) glClipControlEXT __attribute__((alias("glClipControl")));
extern __typeof(glColorMaski) glColorMaskIndexedEXT __attribute__((alias("glColorMaski")));
extern __typeof(glColorMaski) glColorMaskiEXT __attribute__((alias("glColorMaski")));
extern __typeof(glColorMaski) glColorMaskiOES __attribute__((alias("glColorMaski")));
extern __typeof(glColorSubTable) glColorSubTableEXT __attribute__((alias("glColorSubTable")));
extern __typeof(glColorTable) glColorTableEXT __attribute__((alias("glColorTable")));
extern __typeof(glColorTableParameterfv) glColorTableParameterfvSGI __attribute__((alias("glColorTableParameterfv")));
extern __typeof(glColorTableParameteriv) glColorTableParameterivSGI __attribute__((alias("glColorTableParameteriv")));
extern __typeof(glColorTable) glColorTableSGI __attribute__((alias("glColorTable")));
extern __typeof(glCompileShader) glCompileShaderARB __attribute__((alias("glCompileShader")));
extern __typeof(glCompressedTexImage1D) glCompressedTexImage1DARB __attribute__((alias("glCompressedTexImage1D")));
extern __typeof(glCompressedTexImage2D) glCompressedTexImage2DARB __attribute__((alias("glCompressedTexImage2D")));
@@ -68,7 +77,17 @@ extern __typeof(glCompressedTexImage3D) glCompressedTexImage3DARB __attribute__(
extern __typeof(glCompressedTexSubImage1D) glCompressedTexSubImage1DARB __attribute__((alias("glCompressedTexSubImage1D")));
extern __typeof(glCompressedTexSubImage2D) glCompressedTexSubImage2DARB __attribute__((alias("glCompressedTexSubImage2D")));
extern __typeof(glCompressedTexSubImage3D) glCompressedTexSubImage3DARB __attribute__((alias("glCompressedTexSubImage3D")));
extern __typeof(glConvolutionFilter1D) glConvolutionFilter1DEXT __attribute__((alias("glConvolutionFilter1D")));
extern __typeof(glConvolutionFilter2D) glConvolutionFilter2DEXT __attribute__((alias("glConvolutionFilter2D")));
extern __typeof(glConvolutionParameterf) glConvolutionParameterfEXT __attribute__((alias("glConvolutionParameterf")));
extern __typeof(glConvolutionParameterfv) glConvolutionParameterfvEXT __attribute__((alias("glConvolutionParameterfv")));
extern __typeof(glConvolutionParameteri) glConvolutionParameteriEXT __attribute__((alias("glConvolutionParameteri")));
extern __typeof(glConvolutionParameteriv) glConvolutionParameterivEXT __attribute__((alias("glConvolutionParameteriv")));
extern __typeof(glCopyBufferSubData) glCopyBufferSubDataNV __attribute__((alias("glCopyBufferSubData")));
extern __typeof(glCopyColorSubTable) glCopyColorSubTableEXT __attribute__((alias("glCopyColorSubTable")));
extern __typeof(glCopyColorTable) glCopyColorTableSGI __attribute__((alias("glCopyColorTable")));
extern __typeof(glCopyConvolutionFilter1D) glCopyConvolutionFilter1DEXT __attribute__((alias("glCopyConvolutionFilter1D")));
extern __typeof(glCopyConvolutionFilter2D) glCopyConvolutionFilter2DEXT __attribute__((alias("glCopyConvolutionFilter2D")));
extern __typeof(glCopyImageSubData) glCopyImageSubDataEXT __attribute__((alias("glCopyImageSubData")));
extern __typeof(glCopyImageSubData) glCopyImageSubDataOES __attribute__((alias("glCopyImageSubData")));
extern __typeof(glCopyTexImage1D) glCopyTexImage1DEXT __attribute__((alias("glCopyTexImage1D")));
@@ -78,6 +97,10 @@ extern __typeof(glCopyTexSubImage2D) glCopyTexSubImage2DEXT __attribute__((alias
extern __typeof(glCopyTexSubImage3D) glCopyTexSubImage3DEXT __attribute__((alias("glCopyTexSubImage3D")));
extern __typeof(glCreateProgram) glCreateProgramObjectARB __attribute__((alias("glCreateProgram")));
extern __typeof(glCreateShader) glCreateShaderObjectARB __attribute__((alias("glCreateShader")));
extern __typeof(glDebugMessageControl) glDebugMessageControlARB __attribute__((alias("glDebugMessageControl")));
extern __typeof(glDebugMessageControl) glDebugMessageControlKHR __attribute__((alias("glDebugMessageControl")));
extern __typeof(glDebugMessageInsert) glDebugMessageInsertARB __attribute__((alias("glDebugMessageInsert")));
extern __typeof(glDebugMessageInsert) glDebugMessageInsertKHR __attribute__((alias("glDebugMessageInsert")));
extern __typeof(glDeleteBuffers) glDeleteBuffersARB __attribute__((alias("glDeleteBuffers")));
extern __typeof(glDeleteFramebuffers) glDeleteFramebuffersEXT __attribute__((alias("glDeleteFramebuffers")));
extern __typeof(glDeleteQueries) glDeleteQueriesARB __attribute__((alias("glDeleteQueries")));
@@ -131,12 +154,17 @@ extern __typeof(glEndTransformFeedback) glEndTransformFeedbackNV __attribute__((
extern __typeof(glFenceSync) glFenceSyncAPPLE __attribute__((alias("glFenceSync")));
extern __typeof(glFlushMappedBufferRange) glFlushMappedBufferRangeAPPLE __attribute__((alias("glFlushMappedBufferRange")));
extern __typeof(glFlushMappedBufferRange) glFlushMappedBufferRangeEXT __attribute__((alias("glFlushMappedBufferRange")));
extern __typeof(glFogCoordd) glFogCoorddEXT __attribute__((alias("glFogCoordd")));
extern __typeof(glFogCoorddv) glFogCoorddvEXT __attribute__((alias("glFogCoorddv")));
extern __typeof(glFogCoordf) glFogCoordfEXT __attribute__((alias("glFogCoordf")));
extern __typeof(glFogCoordfv) glFogCoordfvEXT __attribute__((alias("glFogCoordfv")));
extern __typeof(glFramebufferRenderbuffer) glFramebufferRenderbufferEXT __attribute__((alias("glFramebufferRenderbuffer")));
extern __typeof(glFramebufferTexture1D) glFramebufferTexture1DEXT __attribute__((alias("glFramebufferTexture1D")));
extern __typeof(glFramebufferTexture2D) glFramebufferTexture2DEXT __attribute__((alias("glFramebufferTexture2D")));
extern __typeof(glFramebufferTexture3D) glFramebufferTexture3DEXT __attribute__((alias("glFramebufferTexture3D")));
extern __typeof(glFramebufferTexture) glFramebufferTextureARB __attribute__((alias("glFramebufferTexture")));
extern __typeof(glFramebufferTexture) glFramebufferTextureEXT __attribute__((alias("glFramebufferTexture")));
extern __typeof(glFramebufferTextureFaceARB) glFramebufferTextureFaceEXT __attribute__((alias("glFramebufferTextureFaceARB")));
extern __typeof(glFramebufferTextureLayer) glFramebufferTextureLayerARB __attribute__((alias("glFramebufferTextureLayer")));
extern __typeof(glFramebufferTextureLayer) glFramebufferTextureLayerEXT __attribute__((alias("glFramebufferTextureLayer")));
extern __typeof(glFramebufferTexture) glFramebufferTextureOES __attribute__((alias("glFramebufferTexture")));
@@ -156,7 +184,11 @@ extern __typeof(glGetBufferParameteriv) glGetBufferParameterivARB __attribute__(
extern __typeof(glGetBufferPointerv) glGetBufferPointervARB __attribute__((alias("glGetBufferPointerv")));
extern __typeof(glGetBufferPointerv) glGetBufferPointervOES __attribute__((alias("glGetBufferPointerv")));
extern __typeof(glGetBufferSubData) glGetBufferSubDataARB __attribute__((alias("glGetBufferSubData")));
extern __typeof(glGetColorTableParameterfv) glGetColorTableParameterfvEXT __attribute__((alias("glGetColorTableParameterfv")));
extern __typeof(glGetColorTableParameteriv) glGetColorTableParameterivEXT __attribute__((alias("glGetColorTableParameteriv")));
extern __typeof(glGetCompressedTexImage) glGetCompressedTexImageARB __attribute__((alias("glGetCompressedTexImage")));
extern __typeof(glGetDebugMessageLog) glGetDebugMessageLogARB __attribute__((alias("glGetDebugMessageLog")));
extern __typeof(glGetDebugMessageLog) glGetDebugMessageLogKHR __attribute__((alias("glGetDebugMessageLog")));
extern __typeof(glGetDoublei_v) glGetDoubleIndexedvEXT __attribute__((alias("glGetDoublei_v")));
extern __typeof(glGetDoublei_v) glGetDoublei_vEXT __attribute__((alias("glGetDoublei_v")));
extern __typeof(glGetFloati_v) glGetFloatIndexedvEXT __attribute__((alias("glGetFloati_v")));
@@ -172,6 +204,8 @@ extern __typeof(glGetInteger64v) glGetInteger64vAPPLE __attribute__((alias("glGe
extern __typeof(glGetInteger64v) glGetInteger64vEXT __attribute__((alias("glGetInteger64v")));
extern __typeof(glGetIntegeri_v) glGetIntegerIndexedvEXT __attribute__((alias("glGetIntegeri_v")));
extern __typeof(glGetMultisamplefv) glGetMultisamplefvNV __attribute__((alias("glGetMultisamplefv")));
extern __typeof(glGetObjectLabel) glGetObjectLabelKHR __attribute__((alias("glGetObjectLabel")));
extern __typeof(glGetProgramBinary) glGetProgramBinaryOES __attribute__((alias("glGetProgramBinary")));
extern __typeof(glGetQueryObjecti64v) glGetQueryObjecti64vEXT __attribute__((alias("glGetQueryObjecti64v")));
extern __typeof(glGetQueryObjectiv) glGetQueryObjectivARB __attribute__((alias("glGetQueryObjectiv")));
extern __typeof(glGetQueryObjectiv) glGetQueryObjectivEXT __attribute__((alias("glGetQueryObjectiv")));
@@ -189,6 +223,8 @@ extern __typeof(glGetTexParameterIiv) glGetTexParameterIivEXT __attribute__((ali
extern __typeof(glGetTexParameterIiv) glGetTexParameterIivOES __attribute__((alias("glGetTexParameterIiv")));
extern __typeof(glGetTexParameterIuiv) glGetTexParameterIuivEXT __attribute__((alias("glGetTexParameterIuiv")));
extern __typeof(glGetTexParameterIuiv) glGetTexParameterIuivOES __attribute__((alias("glGetTexParameterIuiv")));
extern __typeof(glGetTextureHandleARB) glGetTextureHandleIMG __attribute__((alias("glGetTextureHandleARB")));
extern __typeof(glGetTextureSamplerHandleARB) glGetTextureSamplerHandleIMG __attribute__((alias("glGetTextureSamplerHandleARB")));
extern __typeof(glGetTransformFeedbackVarying) glGetTransformFeedbackVaryingEXT __attribute__((alias("glGetTransformFeedbackVarying")));
extern __typeof(glGetUniformLocation) glGetUniformLocationARB __attribute__((alias("glGetUniformLocation")));
extern __typeof(glGetUniformfv) glGetUniformfvARB __attribute__((alias("glGetUniformfv")));
@@ -205,12 +241,14 @@ extern __typeof(glGetVertexAttribfv) glGetVertexAttribfvARB __attribute__((alias
extern __typeof(glGetVertexAttribfv) glGetVertexAttribfvNV __attribute__((alias("glGetVertexAttribfv")));
extern __typeof(glGetVertexAttribiv) glGetVertexAttribivARB __attribute__((alias("glGetVertexAttribiv")));
extern __typeof(glGetVertexAttribiv) glGetVertexAttribivNV __attribute__((alias("glGetVertexAttribiv")));
extern __typeof(glHistogram) glHistogramEXT __attribute__((alias("glHistogram")));
extern __typeof(glIsBuffer) glIsBufferARB __attribute__((alias("glIsBuffer")));
extern __typeof(glIsEnabledi) glIsEnabledIndexedEXT __attribute__((alias("glIsEnabledi")));
extern __typeof(glIsEnabledi) glIsEnablediEXT __attribute__((alias("glIsEnabledi")));
extern __typeof(glIsEnabledi) glIsEnablediNV __attribute__((alias("glIsEnabledi")));
extern __typeof(glIsEnabledi) glIsEnablediOES __attribute__((alias("glIsEnabledi")));
extern __typeof(glIsFramebuffer) glIsFramebufferEXT __attribute__((alias("glIsFramebuffer")));
extern __typeof(glIsProgramARB) glIsProgramNV __attribute__((alias("glIsProgramARB")));
extern __typeof(glIsQuery) glIsQueryARB __attribute__((alias("glIsQuery")));
extern __typeof(glIsRenderbuffer) glIsRenderbufferEXT __attribute__((alias("glIsRenderbuffer")));
extern __typeof(glIsSync) glIsSyncAPPLE __attribute__((alias("glIsSync")));
@@ -218,12 +256,18 @@ extern __typeof(glIsTransformFeedback) glIsTransformFeedbackNV __attribute__((al
extern __typeof(glIsVertexArray) glIsVertexArrayAPPLE __attribute__((alias("glIsVertexArray")));
extern __typeof(glIsVertexArray) glIsVertexArrayOES __attribute__((alias("glIsVertexArray")));
extern __typeof(glLinkProgram) glLinkProgramARB __attribute__((alias("glLinkProgram")));
extern __typeof(glLoadTransposeMatrixd) glLoadTransposeMatrixdARB __attribute__((alias("glLoadTransposeMatrixd")));
extern __typeof(glLoadTransposeMatrixf) glLoadTransposeMatrixfARB __attribute__((alias("glLoadTransposeMatrixf")));
extern __typeof(glMapBuffer) glMapBufferARB __attribute__((alias("glMapBuffer")));
extern __typeof(glMapBuffer) glMapBufferOES __attribute__((alias("glMapBuffer")));
extern __typeof(glMapBufferRange) glMapBufferRangeEXT __attribute__((alias("glMapBufferRange")));
extern __typeof(glMaxShaderCompilerThreadsKHR) glMaxShaderCompilerThreadsARB __attribute__((alias("glMaxShaderCompilerThreadsKHR")));
extern __typeof(glMemoryBarrier) glMemoryBarrierEXT __attribute__((alias("glMemoryBarrier")));
extern __typeof(glMinSampleShading) glMinSampleShadingARB __attribute__((alias("glMinSampleShading")));
extern __typeof(glMinSampleShading) glMinSampleShadingOES __attribute__((alias("glMinSampleShading")));
extern __typeof(glMinmax) glMinmaxEXT __attribute__((alias("glMinmax")));
extern __typeof(glMultTransposeMatrixd) glMultTransposeMatrixdARB __attribute__((alias("glMultTransposeMatrixd")));
extern __typeof(glMultTransposeMatrixf) glMultTransposeMatrixfARB __attribute__((alias("glMultTransposeMatrixf")));
extern __typeof(glMultiDrawArrays) glMultiDrawArraysEXT __attribute__((alias("glMultiDrawArrays")));
extern __typeof(glMultiDrawArraysIndirect) glMultiDrawArraysIndirectAMD __attribute__((alias("glMultiDrawArraysIndirect")));
extern __typeof(glMultiDrawArraysIndirect) glMultiDrawArraysIndirectEXT __attribute__((alias("glMultiDrawArraysIndirect")));
@@ -231,6 +275,41 @@ extern __typeof(glMultiDrawElementsBaseVertex) glMultiDrawElementsBaseVertexEXT
extern __typeof(glMultiDrawElements) glMultiDrawElementsEXT __attribute__((alias("glMultiDrawElements")));
extern __typeof(glMultiDrawElementsIndirect) glMultiDrawElementsIndirectAMD __attribute__((alias("glMultiDrawElementsIndirect")));
extern __typeof(glMultiDrawElementsIndirect) glMultiDrawElementsIndirectEXT __attribute__((alias("glMultiDrawElementsIndirect")));
extern __typeof(glMultiTexCoord1d) glMultiTexCoord1dARB __attribute__((alias("glMultiTexCoord1d")));
extern __typeof(glMultiTexCoord1dv) glMultiTexCoord1dvARB __attribute__((alias("glMultiTexCoord1dv")));
extern __typeof(glMultiTexCoord1f) glMultiTexCoord1fARB __attribute__((alias("glMultiTexCoord1f")));
extern __typeof(glMultiTexCoord1fv) glMultiTexCoord1fvARB __attribute__((alias("glMultiTexCoord1fv")));
extern __typeof(glMultiTexCoord1i) glMultiTexCoord1iARB __attribute__((alias("glMultiTexCoord1i")));
extern __typeof(glMultiTexCoord1iv) glMultiTexCoord1ivARB __attribute__((alias("glMultiTexCoord1iv")));
extern __typeof(glMultiTexCoord1s) glMultiTexCoord1sARB __attribute__((alias("glMultiTexCoord1s")));
extern __typeof(glMultiTexCoord1sv) glMultiTexCoord1svARB __attribute__((alias("glMultiTexCoord1sv")));
extern __typeof(glMultiTexCoord2d) glMultiTexCoord2dARB __attribute__((alias("glMultiTexCoord2d")));
extern __typeof(glMultiTexCoord2dv) glMultiTexCoord2dvARB __attribute__((alias("glMultiTexCoord2dv")));
extern __typeof(glMultiTexCoord2f) glMultiTexCoord2fARB __attribute__((alias("glMultiTexCoord2f")));
extern __typeof(glMultiTexCoord2fv) glMultiTexCoord2fvARB __attribute__((alias("glMultiTexCoord2fv")));
extern __typeof(glMultiTexCoord2i) glMultiTexCoord2iARB __attribute__((alias("glMultiTexCoord2i")));
extern __typeof(glMultiTexCoord2iv) glMultiTexCoord2ivARB __attribute__((alias("glMultiTexCoord2iv")));
extern __typeof(glMultiTexCoord2s) glMultiTexCoord2sARB __attribute__((alias("glMultiTexCoord2s")));
extern __typeof(glMultiTexCoord2sv) glMultiTexCoord2svARB __attribute__((alias("glMultiTexCoord2sv")));
extern __typeof(glMultiTexCoord3d) glMultiTexCoord3dARB __attribute__((alias("glMultiTexCoord3d")));
extern __typeof(glMultiTexCoord3dv) glMultiTexCoord3dvARB __attribute__((alias("glMultiTexCoord3dv")));
extern __typeof(glMultiTexCoord3f) glMultiTexCoord3fARB __attribute__((alias("glMultiTexCoord3f")));
extern __typeof(glMultiTexCoord3fv) glMultiTexCoord3fvARB __attribute__((alias("glMultiTexCoord3fv")));
extern __typeof(glMultiTexCoord3i) glMultiTexCoord3iARB __attribute__((alias("glMultiTexCoord3i")));
extern __typeof(glMultiTexCoord3iv) glMultiTexCoord3ivARB __attribute__((alias("glMultiTexCoord3iv")));
extern __typeof(glMultiTexCoord3s) glMultiTexCoord3sARB __attribute__((alias("glMultiTexCoord3s")));
extern __typeof(glMultiTexCoord3sv) glMultiTexCoord3svARB __attribute__((alias("glMultiTexCoord3sv")));
extern __typeof(glMultiTexCoord4d) glMultiTexCoord4dARB __attribute__((alias("glMultiTexCoord4d")));
extern __typeof(glMultiTexCoord4dv) glMultiTexCoord4dvARB __attribute__((alias("glMultiTexCoord4dv")));
extern __typeof(glMultiTexCoord4f) glMultiTexCoord4fARB __attribute__((alias("glMultiTexCoord4f")));
extern __typeof(glMultiTexCoord4fv) glMultiTexCoord4fvARB __attribute__((alias("glMultiTexCoord4fv")));
extern __typeof(glMultiTexCoord4i) glMultiTexCoord4iARB __attribute__((alias("glMultiTexCoord4i")));
extern __typeof(glMultiTexCoord4iv) glMultiTexCoord4ivARB __attribute__((alias("glMultiTexCoord4iv")));
extern __typeof(glMultiTexCoord4s) glMultiTexCoord4sARB __attribute__((alias("glMultiTexCoord4s")));
extern __typeof(glMultiTexCoord4sv) glMultiTexCoord4svARB __attribute__((alias("glMultiTexCoord4sv")));
extern __typeof(glNamedBufferStorage) glNamedBufferStorageEXT __attribute__((alias("glNamedBufferStorage")));
extern __typeof(glNamedBufferSubData) glNamedBufferSubDataEXT __attribute__((alias("glNamedBufferSubData")));
extern __typeof(glObjectLabel) glObjectLabelKHR __attribute__((alias("glObjectLabel")));
extern __typeof(glPatchParameteri) glPatchParameteriEXT __attribute__((alias("glPatchParameteri")));
extern __typeof(glPatchParameteri) glPatchParameteriOES __attribute__((alias("glPatchParameteri")));
extern __typeof(glPauseTransformFeedback) glPauseTransformFeedbackNV __attribute__((alias("glPauseTransformFeedback")));
@@ -243,7 +322,9 @@ extern __typeof(glPointParameterfv) glPointParameterfvSGIS __attribute__((alias(
extern __typeof(glPointParameteri) glPointParameteriNV __attribute__((alias("glPointParameteri")));
extern __typeof(glPointParameteriv) glPointParameterivNV __attribute__((alias("glPointParameteriv")));
extern __typeof(glPolygonMode) glPolygonModeNV __attribute__((alias("glPolygonMode")));
extern __typeof(glPolygonOffsetClamp) glPolygonOffsetClampEXT __attribute__((alias("glPolygonOffsetClamp")));
extern __typeof(glPopDebugGroup) glPopDebugGroupKHR __attribute__((alias("glPopDebugGroup")));
extern __typeof(glProgramBinary) glProgramBinaryOES __attribute__((alias("glProgramBinary")));
extern __typeof(glProgramParameteri) glProgramParameteriARB __attribute__((alias("glProgramParameteri")));
extern __typeof(glProgramParameteri) glProgramParameteriEXT __attribute__((alias("glProgramParameteri")));
extern __typeof(glProgramUniform1f) glProgramUniform1fEXT __attribute__((alias("glProgramUniform1f")));
@@ -270,6 +351,8 @@ extern __typeof(glProgramUniform4i) glProgramUniform4iEXT __attribute__((alias("
extern __typeof(glProgramUniform4iv) glProgramUniform4ivEXT __attribute__((alias("glProgramUniform4iv")));
extern __typeof(glProgramUniform4ui) glProgramUniform4uiEXT __attribute__((alias("glProgramUniform4ui")));
extern __typeof(glProgramUniform4uiv) glProgramUniform4uivEXT __attribute__((alias("glProgramUniform4uiv")));
extern __typeof(glProgramUniformHandleui64ARB) glProgramUniformHandleui64IMG __attribute__((alias("glProgramUniformHandleui64ARB")));
extern __typeof(glProgramUniformHandleui64vARB) glProgramUniformHandleui64vIMG __attribute__((alias("glProgramUniformHandleui64vARB")));
extern __typeof(glProgramUniformMatrix2fv) glProgramUniformMatrix2fvEXT __attribute__((alias("glProgramUniformMatrix2fv")));
extern __typeof(glProgramUniformMatrix2x3fv) glProgramUniformMatrix2x3fvEXT __attribute__((alias("glProgramUniformMatrix2x3fv")));
extern __typeof(glProgramUniformMatrix2x4fv) glProgramUniformMatrix2x4fvEXT __attribute__((alias("glProgramUniformMatrix2x4fv")));
@@ -280,12 +363,20 @@ extern __typeof(glProgramUniformMatrix4fv) glProgramUniformMatrix4fvEXT __attrib
extern __typeof(glProgramUniformMatrix4x2fv) glProgramUniformMatrix4x2fvEXT __attribute__((alias("glProgramUniformMatrix4x2fv")));
extern __typeof(glProgramUniformMatrix4x3fv) glProgramUniformMatrix4x3fvEXT __attribute__((alias("glProgramUniformMatrix4x3fv")));
extern __typeof(glProvokingVertex) glProvokingVertexEXT __attribute__((alias("glProvokingVertex")));
extern __typeof(glPushDebugGroup) glPushDebugGroupKHR __attribute__((alias("glPushDebugGroup")));
extern __typeof(glQueryCounter) glQueryCounterEXT __attribute__((alias("glQueryCounter")));
extern __typeof(glReadnPixels) glReadnPixelsARB __attribute__((alias("glReadnPixels")));
extern __typeof(glReadnPixels) glReadnPixelsEXT __attribute__((alias("glReadnPixels")));
extern __typeof(glReadnPixels) glReadnPixelsKHR __attribute__((alias("glReadnPixels")));
extern __typeof(glRenderbufferStorage) glRenderbufferStorageEXT __attribute__((alias("glRenderbufferStorage")));
extern __typeof(glRenderbufferStorageMultisample) glRenderbufferStorageMultisampleEXT __attribute__((alias("glRenderbufferStorageMultisample")));
extern __typeof(glRenderbufferStorageMultisample) glRenderbufferStorageMultisampleNV __attribute__((alias("glRenderbufferStorageMultisample")));
extern __typeof(glResetHistogram) glResetHistogramEXT __attribute__((alias("glResetHistogram")));
extern __typeof(glResetMinmax) glResetMinmaxEXT __attribute__((alias("glResetMinmax")));
extern __typeof(glResumeTransformFeedback) glResumeTransformFeedbackNV __attribute__((alias("glResumeTransformFeedback")));
extern __typeof(glSampleCoverage) glSampleCoverageARB __attribute__((alias("glSampleCoverage")));
extern __typeof(glSampleMaskEXT) glSampleMaskSGIS __attribute__((alias("glSampleMaskEXT")));
extern __typeof(glSamplePatternEXT) glSamplePatternSGIS __attribute__((alias("glSamplePatternEXT")));
extern __typeof(glSamplerParameterIiv) glSamplerParameterIivEXT __attribute__((alias("glSamplerParameterIiv")));
extern __typeof(glSamplerParameterIiv) glSamplerParameterIivOES __attribute__((alias("glSamplerParameterIiv")));
extern __typeof(glSamplerParameterIuiv) glSamplerParameterIuivEXT __attribute__((alias("glSamplerParameterIuiv")));
@@ -296,7 +387,24 @@ extern __typeof(glScissorIndexed) glScissorIndexedNV __attribute__((alias("glSci
extern __typeof(glScissorIndexed) glScissorIndexedOES __attribute__((alias("glScissorIndexed")));
extern __typeof(glScissorIndexedv) glScissorIndexedvNV __attribute__((alias("glScissorIndexedv")));
extern __typeof(glScissorIndexedv) glScissorIndexedvOES __attribute__((alias("glScissorIndexedv")));
extern __typeof(glSecondaryColor3b) glSecondaryColor3bEXT __attribute__((alias("glSecondaryColor3b")));
extern __typeof(glSecondaryColor3bv) glSecondaryColor3bvEXT __attribute__((alias("glSecondaryColor3bv")));
extern __typeof(glSecondaryColor3d) glSecondaryColor3dEXT __attribute__((alias("glSecondaryColor3d")));
extern __typeof(glSecondaryColor3dv) glSecondaryColor3dvEXT __attribute__((alias("glSecondaryColor3dv")));
extern __typeof(glSecondaryColor3f) glSecondaryColor3fEXT __attribute__((alias("glSecondaryColor3f")));
extern __typeof(glSecondaryColor3fv) glSecondaryColor3fvEXT __attribute__((alias("glSecondaryColor3fv")));
extern __typeof(glSecondaryColor3i) glSecondaryColor3iEXT __attribute__((alias("glSecondaryColor3i")));
extern __typeof(glSecondaryColor3iv) glSecondaryColor3ivEXT __attribute__((alias("glSecondaryColor3iv")));
extern __typeof(glSecondaryColor3s) glSecondaryColor3sEXT __attribute__((alias("glSecondaryColor3s")));
extern __typeof(glSecondaryColor3sv) glSecondaryColor3svEXT __attribute__((alias("glSecondaryColor3sv")));
extern __typeof(glSecondaryColor3ub) glSecondaryColor3ubEXT __attribute__((alias("glSecondaryColor3ub")));
extern __typeof(glSecondaryColor3ubv) glSecondaryColor3ubvEXT __attribute__((alias("glSecondaryColor3ubv")));
extern __typeof(glSecondaryColor3ui) glSecondaryColor3uiEXT __attribute__((alias("glSecondaryColor3ui")));
extern __typeof(glSecondaryColor3uiv) glSecondaryColor3uivEXT __attribute__((alias("glSecondaryColor3uiv")));
extern __typeof(glSecondaryColor3us) glSecondaryColor3usEXT __attribute__((alias("glSecondaryColor3us")));
extern __typeof(glSecondaryColor3usv) glSecondaryColor3usvEXT __attribute__((alias("glSecondaryColor3usv")));
extern __typeof(glShaderSource) glShaderSourceARB __attribute__((alias("glShaderSource")));
extern __typeof(glSpecializeShader) glSpecializeShaderARB __attribute__((alias("glSpecializeShader")));
extern __typeof(glStencilOpSeparate) glStencilOpSeparateATI __attribute__((alias("glStencilOpSeparate")));
extern __typeof(glTexBuffer) glTexBufferARB __attribute__((alias("glTexBuffer")));
extern __typeof(glTexBuffer) glTexBufferEXT __attribute__((alias("glTexBuffer")));
@@ -304,6 +412,7 @@ extern __typeof(glTexBuffer) glTexBufferOES __attribute__((alias("glTexBuffer"))
extern __typeof(glTexBufferRange) glTexBufferRangeEXT __attribute__((alias("glTexBufferRange")));
extern __typeof(glTexBufferRange) glTexBufferRangeOES __attribute__((alias("glTexBufferRange")));
extern __typeof(glTexImage3D) glTexImage3DEXT __attribute__((alias("glTexImage3D")));
extern __typeof(glTexPageCommitmentARB) glTexPageCommitmentEXT __attribute__((alias("glTexPageCommitmentARB")));
extern __typeof(glTexParameterIiv) glTexParameterIivEXT __attribute__((alias("glTexParameterIiv")));
extern __typeof(glTexParameterIiv) glTexParameterIivOES __attribute__((alias("glTexParameterIiv")));
extern __typeof(glTexParameterIuiv) glTexParameterIuivEXT __attribute__((alias("glTexParameterIuiv")));
@@ -342,6 +451,8 @@ extern __typeof(glUniform4i) glUniform4iARB __attribute__((alias("glUniform4i"))
extern __typeof(glUniform4iv) glUniform4ivARB __attribute__((alias("glUniform4iv")));
extern __typeof(glUniform4ui) glUniform4uiEXT __attribute__((alias("glUniform4ui")));
extern __typeof(glUniform4uiv) glUniform4uivEXT __attribute__((alias("glUniform4uiv")));
extern __typeof(glUniformHandleui64ARB) glUniformHandleui64IMG __attribute__((alias("glUniformHandleui64ARB")));
extern __typeof(glUniformHandleui64vARB) glUniformHandleui64vIMG __attribute__((alias("glUniformHandleui64vARB")));
extern __typeof(glUniformMatrix2fv) glUniformMatrix2fvARB __attribute__((alias("glUniformMatrix2fv")));
extern __typeof(glUniformMatrix2x3fv) glUniformMatrix2x3fvNV __attribute__((alias("glUniformMatrix2x3fv")));
extern __typeof(glUniformMatrix2x4fv) glUniformMatrix2x4fvNV __attribute__((alias("glUniformMatrix2x4fv")));
@@ -459,3 +570,35 @@ extern __typeof(glViewportIndexedf) glViewportIndexedfOES __attribute__((alias("
extern __typeof(glViewportIndexedfv) glViewportIndexedfvNV __attribute__((alias("glViewportIndexedfv")));
extern __typeof(glViewportIndexedfv) glViewportIndexedfvOES __attribute__((alias("glViewportIndexedfv")));
extern __typeof(glWaitSync) glWaitSyncAPPLE __attribute__((alias("glWaitSync")));
extern __typeof(glWindowPos2d) glWindowPos2dARB __attribute__((alias("glWindowPos2d")));
extern __typeof(glWindowPos2d) glWindowPos2dMESA __attribute__((alias("glWindowPos2d")));
extern __typeof(glWindowPos2dv) glWindowPos2dvARB __attribute__((alias("glWindowPos2dv")));
extern __typeof(glWindowPos2dv) glWindowPos2dvMESA __attribute__((alias("glWindowPos2dv")));
extern __typeof(glWindowPos2f) glWindowPos2fARB __attribute__((alias("glWindowPos2f")));
extern __typeof(glWindowPos2f) glWindowPos2fMESA __attribute__((alias("glWindowPos2f")));
extern __typeof(glWindowPos2fv) glWindowPos2fvARB __attribute__((alias("glWindowPos2fv")));
extern __typeof(glWindowPos2fv) glWindowPos2fvMESA __attribute__((alias("glWindowPos2fv")));
extern __typeof(glWindowPos2i) glWindowPos2iARB __attribute__((alias("glWindowPos2i")));
extern __typeof(glWindowPos2i) glWindowPos2iMESA __attribute__((alias("glWindowPos2i")));
extern __typeof(glWindowPos2iv) glWindowPos2ivARB __attribute__((alias("glWindowPos2iv")));
extern __typeof(glWindowPos2iv) glWindowPos2ivMESA __attribute__((alias("glWindowPos2iv")));
extern __typeof(glWindowPos2s) glWindowPos2sARB __attribute__((alias("glWindowPos2s")));
extern __typeof(glWindowPos2s) glWindowPos2sMESA __attribute__((alias("glWindowPos2s")));
extern __typeof(glWindowPos2sv) glWindowPos2svARB __attribute__((alias("glWindowPos2sv")));
extern __typeof(glWindowPos2sv) glWindowPos2svMESA __attribute__((alias("glWindowPos2sv")));
extern __typeof(glWindowPos3d) glWindowPos3dARB __attribute__((alias("glWindowPos3d")));
extern __typeof(glWindowPos3d) glWindowPos3dMESA __attribute__((alias("glWindowPos3d")));
extern __typeof(glWindowPos3dv) glWindowPos3dvARB __attribute__((alias("glWindowPos3dv")));
extern __typeof(glWindowPos3dv) glWindowPos3dvMESA __attribute__((alias("glWindowPos3dv")));
extern __typeof(glWindowPos3f) glWindowPos3fARB __attribute__((alias("glWindowPos3f")));
extern __typeof(glWindowPos3f) glWindowPos3fMESA __attribute__((alias("glWindowPos3f")));
extern __typeof(glWindowPos3fv) glWindowPos3fvARB __attribute__((alias("glWindowPos3fv")));
extern __typeof(glWindowPos3fv) glWindowPos3fvMESA __attribute__((alias("glWindowPos3fv")));
extern __typeof(glWindowPos3i) glWindowPos3iARB __attribute__((alias("glWindowPos3i")));
extern __typeof(glWindowPos3i) glWindowPos3iMESA __attribute__((alias("glWindowPos3i")));
extern __typeof(glWindowPos3iv) glWindowPos3ivARB __attribute__((alias("glWindowPos3iv")));
extern __typeof(glWindowPos3iv) glWindowPos3ivMESA __attribute__((alias("glWindowPos3iv")));
extern __typeof(glWindowPos3s) glWindowPos3sARB __attribute__((alias("glWindowPos3s")));
extern __typeof(glWindowPos3s) glWindowPos3sMESA __attribute__((alias("glWindowPos3s")));
extern __typeof(glWindowPos3sv) glWindowPos3svARB __attribute__((alias("glWindowPos3sv")));
extern __typeof(glWindowPos3sv) glWindowPos3svMESA __attribute__((alias("glWindowPos3sv")));
File diff suppressed because it is too large. Load diff
+134 -1
View File
@@ -2,13 +2,14 @@
*
* Extensions the guest may repeat from the host: every command the
* Khronos registry says they require is exported by this library.
* 581 claimable, 279 withheld for missing entry
* 714 claimable, 146 withheld for missing entry
* points, out of the registry's whole extension set. A host
* extension absent from this table is not advertised to the guest,
* which is why adding a driver capability can need a rebuild here.
*/
static const char *const gexgl_claimable_extensions[] = {
"GL_3DFX_multisample",
"GL_3DFX_tbuffer",
"GL_3DFX_texture_compression_FXT1",
"GL_AMD_blend_minmax_factor",
"GL_AMD_compressed_3DC_texture",
@@ -16,13 +17,18 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_AMD_conservative_depth",
"GL_AMD_depth_clamp_separate",
"GL_AMD_draw_buffers_blend",
"GL_AMD_framebuffer_multisample_advanced",
"GL_AMD_gcn_shader",
"GL_AMD_gpu_shader_half_float",
"GL_AMD_gpu_shader_int16",
"GL_AMD_gpu_shader_int64",
"GL_AMD_interleaved_elements",
"GL_AMD_multi_draw_indirect",
"GL_AMD_occlusion_query_event",
"GL_AMD_pinned_memory",
"GL_AMD_program_binary_Z400",
"GL_AMD_query_buffer_object",
"GL_AMD_sample_positions",
"GL_AMD_seamless_cubemap_per_texture",
"GL_AMD_shader_atomic_counter_ops",
"GL_AMD_shader_ballot",
@@ -31,11 +37,14 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_AMD_shader_image_load_store_lod",
"GL_AMD_shader_stencil_export",
"GL_AMD_shader_trinary_minmax",
"GL_AMD_sparse_texture",
"GL_AMD_stencil_operation_extended",
"GL_AMD_texture_gather_bias_lod",
"GL_AMD_texture_texture4",
"GL_AMD_transform_feedback3_lines_triangles",
"GL_AMD_transform_feedback4",
"GL_AMD_vertex_shader_layer",
"GL_AMD_vertex_shader_tessellator",
"GL_AMD_vertex_shader_viewport_index",
"GL_ANDROID_extension_pack_es31a",
"GL_ANGLE_depth_texture",
@@ -50,6 +59,8 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_APPLE_clip_distance",
"GL_APPLE_color_buffer_packed_float",
"GL_APPLE_float_pixels",
"GL_APPLE_flush_buffer_range",
"GL_APPLE_object_purgeable",
"GL_APPLE_rgb_422",
"GL_APPLE_row_bytes",
"GL_APPLE_specular_vector",
@@ -59,7 +70,10 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_APPLE_texture_max_level",
"GL_APPLE_texture_packed_float",
"GL_APPLE_transform_hint",
"GL_APPLE_vertex_array_object",
"GL_APPLE_vertex_array_range",
"GL_APPLE_ycbcr_422",
"GL_ARB_ES3_1_compatibility",
"GL_ARB_ES3_compatibility",
"GL_ARB_arrays_of_arrays",
"GL_ARB_base_instance",
@@ -67,10 +81,12 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_buffer_storage",
"GL_ARB_clear_buffer_object",
"GL_ARB_clear_texture",
"GL_ARB_clip_control",
"GL_ARB_color_buffer_float",
"GL_ARB_compatibility",
"GL_ARB_compressed_texture_pixel_storage",
"GL_ARB_compute_shader",
"GL_ARB_compute_variable_group_size",
"GL_ARB_conditional_render_inverted",
"GL_ARB_conservative_depth",
"GL_ARB_copy_buffer",
@@ -96,6 +112,10 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_framebuffer_no_attachments",
"GL_ARB_framebuffer_object",
"GL_ARB_framebuffer_sRGB",
"GL_ARB_geometry_shader4",
"GL_ARB_get_program_binary",
"GL_ARB_get_texture_sub_image",
"GL_ARB_gl_spirv",
"GL_ARB_gpu_shader5",
"GL_ARB_gpu_shader_fp64",
"GL_ARB_half_float_pixel",
@@ -104,17 +124,21 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_instanced_arrays",
"GL_ARB_internalformat_query",
"GL_ARB_internalformat_query2",
"GL_ARB_invalidate_subdata",
"GL_ARB_map_buffer_alignment",
"GL_ARB_map_buffer_range",
"GL_ARB_multi_bind",
"GL_ARB_multi_draw_indirect",
"GL_ARB_multisample",
"GL_ARB_multitexture",
"GL_ARB_occlusion_query",
"GL_ARB_occlusion_query2",
"GL_ARB_parallel_shader_compile",
"GL_ARB_pipeline_statistics_query",
"GL_ARB_pixel_buffer_object",
"GL_ARB_point_parameters",
"GL_ARB_point_sprite",
"GL_ARB_polygon_offset_clamp",
"GL_ARB_post_depth_coverage",
"GL_ARB_program_interface_query",
"GL_ARB_provoking_vertex",
@@ -137,6 +161,7 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_shader_precision",
"GL_ARB_shader_stencil_export",
"GL_ARB_shader_storage_buffer_object",
"GL_ARB_shader_subroutine",
"GL_ARB_shader_texture_image_samples",
"GL_ARB_shader_texture_lod",
"GL_ARB_shader_viewport_layer_array",
@@ -145,12 +170,15 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_shading_language_packing",
"GL_ARB_shadow",
"GL_ARB_shadow_ambient",
"GL_ARB_sparse_buffer",
"GL_ARB_sparse_texture",
"GL_ARB_sparse_texture2",
"GL_ARB_sparse_texture_clamp",
"GL_ARB_spirv_extensions",
"GL_ARB_stencil_texturing",
"GL_ARB_sync",
"GL_ARB_tessellation_shader",
"GL_ARB_texture_barrier",
"GL_ARB_texture_border_clamp",
"GL_ARB_texture_buffer_object",
"GL_ARB_texture_buffer_object_rgb32",
@@ -187,6 +215,7 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_transform_feedback3",
"GL_ARB_transform_feedback_instanced",
"GL_ARB_transform_feedback_overflow_query",
"GL_ARB_transpose_matrix",
"GL_ARB_uniform_buffer_object",
"GL_ARB_vertex_array_bgra",
"GL_ARB_vertex_array_object",
@@ -196,6 +225,7 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARB_vertex_shader",
"GL_ARB_vertex_type_10f_11f_11f_rev",
"GL_ARB_vertex_type_2_10_10_10_rev",
"GL_ARB_window_pos",
"GL_ARM_mali_program_binary",
"GL_ARM_mali_shader_binary",
"GL_ARM_rgba8",
@@ -203,12 +233,18 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_ARM_shader_framebuffer_fetch_depth_stencil",
"GL_ARM_texture_unnormalized_coordinates",
"GL_ATI_draw_buffers",
"GL_ATI_envmap_bumpmap",
"GL_ATI_meminfo",
"GL_ATI_pixel_format_float",
"GL_ATI_pn_triangles",
"GL_ATI_separate_stencil",
"GL_ATI_text_fragment_shader",
"GL_ATI_texture_env_combine3",
"GL_ATI_texture_float",
"GL_ATI_texture_mirror_once",
"GL_ATI_vertex_array_object",
"GL_ATI_vertex_attrib_array_object",
"GL_ATI_vertex_streams",
"GL_DMP_program_binary",
"GL_DMP_shader_binary",
"GL_EXT_422_pixels",
@@ -227,14 +263,21 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_blend_subtract",
"GL_EXT_buffer_storage",
"GL_EXT_clear_texture",
"GL_EXT_clip_control",
"GL_EXT_clip_cull_distance",
"GL_EXT_clip_volume_hint",
"GL_EXT_cmyka",
"GL_EXT_color_buffer_float",
"GL_EXT_color_buffer_half_float",
"GL_EXT_color_subtable",
"GL_EXT_compiled_vertex_array",
"GL_EXT_conservative_depth",
"GL_EXT_copy_image",
"GL_EXT_copy_texture",
"GL_EXT_cull_vertex",
"GL_EXT_debug_label",
"GL_EXT_debug_marker",
"GL_EXT_depth_bounds_test",
"GL_EXT_depth_clamp",
"GL_EXT_draw_buffers",
"GL_EXT_draw_buffers2",
@@ -244,7 +287,9 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_draw_range_elements",
"GL_EXT_draw_transform_feedback",
"GL_EXT_float_blend",
"GL_EXT_fragment_shading_rate",
"GL_EXT_framebuffer_blit",
"GL_EXT_framebuffer_blit_layers",
"GL_EXT_framebuffer_multisample",
"GL_EXT_framebuffer_multisample_blit_scaled",
"GL_EXT_framebuffer_object",
@@ -252,15 +297,22 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_geometry_point_size",
"GL_EXT_geometry_shader",
"GL_EXT_geometry_shader4",
"GL_EXT_gpu_program_parameters",
"GL_EXT_gpu_shader4",
"GL_EXT_gpu_shader5",
"GL_EXT_index_array_formats",
"GL_EXT_index_func",
"GL_EXT_index_material",
"GL_EXT_index_texture",
"GL_EXT_instanced_arrays",
"GL_EXT_light_texture",
"GL_EXT_map_buffer_range",
"GL_EXT_memory_object_fd",
"GL_EXT_mesh_shader",
"GL_EXT_misc_attribute",
"GL_EXT_multi_draw_arrays",
"GL_EXT_multi_draw_indirect",
"GL_EXT_multisample",
"GL_EXT_multisampled_compatibility",
"GL_EXT_multisampled_render_to_texture2",
"GL_EXT_multiview_tessellation_geometry_shader",
@@ -270,22 +322,29 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_packed_float",
"GL_EXT_packed_pixels",
"GL_EXT_pixel_buffer_object",
"GL_EXT_pixel_transform",
"GL_EXT_pixel_transform_color_table",
"GL_EXT_point_parameters",
"GL_EXT_polygon_offset",
"GL_EXT_polygon_offset_clamp",
"GL_EXT_post_depth_coverage",
"GL_EXT_protected_textures",
"GL_EXT_provoking_vertex",
"GL_EXT_pvrtc_sRGB",
"GL_EXT_raster_multisample",
"GL_EXT_read_format_bgra",
"GL_EXT_render_snorm",
"GL_EXT_rescale_normal",
"GL_EXT_sRGB",
"GL_EXT_sRGB_write_control",
"GL_EXT_semaphore_fd",
"GL_EXT_separate_depth_stencil",
"GL_EXT_separate_specular_color",
"GL_EXT_shader_framebuffer_fetch",
"GL_EXT_shader_framebuffer_fetch_non_coherent",
"GL_EXT_shader_group_vote",
"GL_EXT_shader_image_load_formatted",
"GL_EXT_shader_image_load_store",
"GL_EXT_shader_implicit_conversions",
"GL_EXT_shader_integer_mix",
"GL_EXT_shader_io_blocks",
@@ -297,7 +356,10 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_shadow_funcs",
"GL_EXT_shadow_samplers",
"GL_EXT_shared_texture_palette",
"GL_EXT_sparse_texture",
"GL_EXT_sparse_texture2",
"GL_EXT_stencil_clear_tag",
"GL_EXT_stencil_two_side",
"GL_EXT_stencil_wrap",
"GL_EXT_subtexture",
"GL_EXT_tessellation_point_size",
@@ -324,10 +386,12 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_texture_filter_minmax",
"GL_EXT_texture_format_BGRA8888",
"GL_EXT_texture_format_sRGB_override",
"GL_EXT_texture_integer",
"GL_EXT_texture_lod_bias",
"GL_EXT_texture_mirror_clamp",
"GL_EXT_texture_mirror_clamp_to_edge",
"GL_EXT_texture_norm16",
"GL_EXT_texture_perturb_normal",
"GL_EXT_texture_query_lod",
"GL_EXT_texture_rg",
"GL_EXT_texture_sRGB",
@@ -337,22 +401,30 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_EXT_texture_shadow_lod",
"GL_EXT_texture_shared_exponent",
"GL_EXT_texture_snorm",
"GL_EXT_texture_storage",
"GL_EXT_texture_swizzle",
"GL_EXT_texture_type_2_10_10_10_REV",
"GL_EXT_texture_view",
"GL_EXT_timer_query",
"GL_EXT_transform_feedback",
"GL_EXT_unpack_subimage",
"GL_EXT_vertex_array_bgra",
"GL_EXT_vertex_attrib_64bit",
"GL_EXT_win32_keyed_mutex",
"GL_FJ_shader_binary_GCCSO",
"GL_GREMEDY_frame_terminator",
"GL_GREMEDY_string_marker",
"GL_HP_convolution_border_modes",
"GL_HP_image_transform",
"GL_HP_occlusion_test",
"GL_HP_texture_lighting",
"GL_HUAWEI_program_binary",
"GL_HUAWEI_shader_binary",
"GL_IBM_cull_vertex",
"GL_IBM_rasterpos_clip",
"GL_IBM_static_data",
"GL_IBM_texture_mirrored_repeat",
"GL_IMG_bindless_texture",
"GL_IMG_program_binary",
"GL_IMG_read_format",
"GL_IMG_shader_binary",
@@ -366,9 +438,11 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_INTEL_blackhole_render",
"GL_INTEL_conservative_rasterization",
"GL_INTEL_fragment_shader_ordering",
"GL_INTEL_framebuffer_CMAA",
"GL_KHR_blend_equation_advanced_coherent",
"GL_KHR_context_flush_control",
"GL_KHR_no_error",
"GL_KHR_parallel_shader_compile",
"GL_KHR_robust_buffer_access_behavior",
"GL_KHR_shader_subgroup",
"GL_KHR_texture_compression_astc_hdr",
@@ -377,35 +451,51 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_MESAX_texture_stack",
"GL_MESA_bgra",
"GL_MESA_framebuffer_flip_x",
"GL_MESA_framebuffer_flip_y",
"GL_MESA_framebuffer_swap_xy",
"GL_MESA_pack_invert",
"GL_MESA_program_binary_formats",
"GL_MESA_resize_buffers",
"GL_MESA_sampler_objects",
"GL_MESA_shader_integer_functions",
"GL_MESA_texture_const_bandwidth",
"GL_MESA_tile_raster_order",
"GL_MESA_window_pos",
"GL_MESA_ycbcr_texture",
"GL_NVX_blend_equation_advanced_multi_draw_buffers",
"GL_NVX_conditional_render",
"GL_NVX_gpu_memory_info",
"GL_NV_alpha_to_coverage_dither_control",
"GL_NV_bindless_texture",
"GL_NV_blend_equation_advanced_coherent",
"GL_NV_blend_minmax_factor",
"GL_NV_blend_square",
"GL_NV_clip_space_w_scaling",
"GL_NV_compute_program5",
"GL_NV_compute_shader_derivatives",
"GL_NV_conditional_render",
"GL_NV_conservative_raster",
"GL_NV_conservative_raster_dilate",
"GL_NV_conservative_raster_pre_snap",
"GL_NV_conservative_raster_pre_snap_triangles",
"GL_NV_conservative_raster_underestimation",
"GL_NV_copy_buffer",
"GL_NV_copy_depth_to_color",
"GL_NV_copy_image",
"GL_NV_deep_texture3D",
"GL_NV_depth_buffer_float",
"GL_NV_depth_clamp",
"GL_NV_depth_nonlinear",
"GL_NV_draw_instanced",
"GL_NV_draw_texture",
"GL_NV_explicit_attrib_location",
"GL_NV_explicit_multisample",
"GL_NV_fbo_color_attachments",
"GL_NV_fill_rectangle",
"GL_NV_float_buffer",
"GL_NV_fog_distance",
"GL_NV_fragment_coverage_to_color",
"GL_NV_fragment_program",
"GL_NV_fragment_program2",
"GL_NV_fragment_program4",
"GL_NV_fragment_program_option",
@@ -413,28 +503,43 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_NV_fragment_shader_interlock",
"GL_NV_framebuffer_blit",
"GL_NV_framebuffer_multisample",
"GL_NV_framebuffer_multisample_coverage",
"GL_NV_generate_mipmap_sRGB",
"GL_NV_geometry_program4",
"GL_NV_geometry_shader4",
"GL_NV_geometry_shader_passthrough",
"GL_NV_gpu_program4",
"GL_NV_gpu_program5_mem_extended",
"GL_NV_gpu_shader5",
"GL_NV_half_float",
"GL_NV_image_formats",
"GL_NV_instanced_arrays",
"GL_NV_internalformat_sample_query",
"GL_NV_light_max_exponent",
"GL_NV_memory_object_sparse",
"GL_NV_mesh_shader",
"GL_NV_multisample_coverage",
"GL_NV_multisample_filter_hint",
"GL_NV_non_square_matrices",
"GL_NV_pack_subimage",
"GL_NV_packed_depth_stencil",
"GL_NV_parameter_buffer_object",
"GL_NV_parameter_buffer_object2",
"GL_NV_path_rendering_shared_edge",
"GL_NV_pixel_buffer_object",
"GL_NV_pixel_data_range",
"GL_NV_point_sprite",
"GL_NV_polygon_mode",
"GL_NV_present_video",
"GL_NV_primitive_restart",
"GL_NV_primitive_shading_rate",
"GL_NV_query_resource",
"GL_NV_read_buffer_front",
"GL_NV_read_depth",
"GL_NV_read_depth_stencil",
"GL_NV_read_stencil",
"GL_NV_register_combiners",
"GL_NV_register_combiners2",
"GL_NV_representative_fragment_test",
"GL_NV_robustness_video_memory_purge",
"GL_NV_sRGB_formats",
@@ -457,27 +562,33 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_NV_tessellation_program5",
"GL_NV_texgen_emboss",
"GL_NV_texgen_reflection",
"GL_NV_texture_barrier",
"GL_NV_texture_border_clamp",
"GL_NV_texture_compression_s3tc_update",
"GL_NV_texture_compression_vtc",
"GL_NV_texture_env_combine4",
"GL_NV_texture_expand_normal",
"GL_NV_texture_multisample",
"GL_NV_texture_npot_2D_mipmap",
"GL_NV_texture_rectangle",
"GL_NV_texture_rectangle_compressed",
"GL_NV_texture_shader",
"GL_NV_texture_shader2",
"GL_NV_texture_shader3",
"GL_NV_transform_feedback2",
"GL_NV_uniform_buffer_std430_layout",
"GL_NV_uniform_buffer_unified_memory",
"GL_NV_vertex_array_range2",
"GL_NV_vertex_attrib_integer_64bit",
"GL_NV_vertex_program1_1",
"GL_NV_vertex_program2",
"GL_NV_vertex_program2_option",
"GL_NV_vertex_program3",
"GL_NV_vertex_program4",
"GL_NV_viewport_array2",
"GL_NV_viewport_swizzle",
"GL_OES_EGL_image_external_essl3",
"GL_OES_byte_coordinates",
"GL_OES_compressed_ETC1_RGB8_sub_texture",
"GL_OES_compressed_ETC1_RGB8_texture",
"GL_OES_compressed_paletted_texture",
@@ -493,11 +604,13 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_OES_fragment_precision_high",
"GL_OES_geometry_point_size",
"GL_OES_geometry_shader",
"GL_OES_get_program_binary",
"GL_OES_gpu_shader5",
"GL_OES_mapbuffer",
"GL_OES_matrix_get",
"GL_OES_packed_depth_stencil",
"GL_OES_point_sprite",
"GL_OES_query_matrix",
"GL_OES_read_format",
"GL_OES_required_internalformat",
"GL_OES_rgb8_rgba8",
@@ -506,6 +619,7 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_OES_shader_image_atomic",
"GL_OES_shader_io_blocks",
"GL_OES_shader_multisample_interpolation",
"GL_OES_single_precision",
"GL_OES_standard_derivatives",
"GL_OES_stencil1",
"GL_OES_stencil4",
@@ -534,7 +648,9 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_OML_interlace",
"GL_OML_resample",
"GL_OML_subsample",
"GL_OVR_multiview",
"GL_OVR_multiview2",
"GL_PGI_misc_hints",
"GL_PGI_vertex_hints",
"GL_QCOM_YUV_texture_gather",
"GL_QCOM_binning_control",
@@ -550,9 +666,12 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_REND_screen_coordinates",
"GL_S3_s3tc",
"GL_SGIS_generate_mipmap",
"GL_SGIS_multisample",
"GL_SGIS_pixel_texture",
"GL_SGIS_point_line_texgen",
"GL_SGIS_point_parameters",
"GL_SGIS_texture_border_clamp",
"GL_SGIS_texture_color_mask",
"GL_SGIS_texture_edge_clamp",
"GL_SGIS_texture_lod",
"GL_SGIS_texture_select",
@@ -564,15 +683,25 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_SGIX_convolution_accuracy",
"GL_SGIX_depth_pass_instrument",
"GL_SGIX_depth_texture",
"GL_SGIX_flush_raster",
"GL_SGIX_fog_offset",
"GL_SGIX_fragment_lighting",
"GL_SGIX_framezoom",
"GL_SGIX_igloo_interface",
"GL_SGIX_instruments",
"GL_SGIX_interlace",
"GL_SGIX_ir_instrument1",
"GL_SGIX_list_priority",
"GL_SGIX_pixel_texture",
"GL_SGIX_pixel_tiles",
"GL_SGIX_reference_plane",
"GL_SGIX_resample",
"GL_SGIX_scalebias_hint",
"GL_SGIX_shadow",
"GL_SGIX_shadow_ambient",
"GL_SGIX_sprite",
"GL_SGIX_subsample",
"GL_SGIX_tag_sample_buffer",
"GL_SGIX_texture_add_env",
"GL_SGIX_texture_coordinate_clamp",
"GL_SGIX_texture_lod_bias",
@@ -584,8 +713,12 @@ static const char *const gexgl_claimable_extensions[] = {
"GL_SGIX_ycrcba",
"GL_SGI_color_matrix",
"GL_SGI_texture_color_table",
"GL_SUNX_constant_data",
"GL_SUN_convolution_border_modes",
"GL_SUN_global_alpha",
"GL_SUN_mesh_array",
"GL_SUN_slice_accum",
"GL_SUN_vertex",
"GL_VIV_shader_binary",
"GL_WIN_phong_shading",
"GL_WIN_specular_fog",
+77
View File
@@ -0,0 +1,77 @@
/* Generated by tools/gen_gl_compat.py; do not edit.
*
* How many values a pname-sized parameter vector holds (COMPSIZE(pname)
* in the registry): the guest encoders, opengl32's and every host
* decoder size those vectors with this one table. */
#ifndef GEXGL_PNAME_COUNTS_H
#define GEXGL_PNAME_COUNTS_H
static inline unsigned gexgl_pname_count(unsigned pname) {
switch (pname) {
case 0x0B00u: return 4u;
case 0x0B02u: return 3u;
case 0x0B03u: return 4u;
case 0x0B04u: return 4u;
case 0x0B06u: return 4u;
case 0x0B07u: return 4u;
case 0x0B12u: return 2u;
case 0x0B22u: return 2u;
case 0x0B40u: return 2u;
case 0x0B53u: return 4u;
case 0x0B66u: return 4u;
case 0x0B70u: return 2u;
case 0x0B80u: return 4u;
case 0x0BA2u: return 4u;
case 0x0BA6u: return 16u;
case 0x0BA7u: return 16u;
case 0x0BA8u: return 16u;
case 0x0C10u: return 4u;
case 0x0C22u: return 4u;
case 0x0C23u: return 4u;
case 0x0D3Au: return 2u;
case 0x0DD0u: return 2u;
case 0x0DD2u: return 4u;
case 0x0DD3u: return 2u;
case 0x1004u: return 4u;
case 0x1200u: return 4u;
case 0x1201u: return 4u;
case 0x1202u: return 4u;
case 0x1203u: return 4u;
case 0x1204u: return 3u;
case 0x1600u: return 4u;
case 0x1602u: return 4u;
case 0x1603u: return 3u;
case 0x1800u: return 4u;
case 0x2201u: return 4u;
case 0x2501u: return 4u;
case 0x2502u: return 4u;
case 0x8005u: return 4u;
case 0x8014u: return 4u;
case 0x8015u: return 4u;
case 0x80B1u: return 16u;
case 0x80D1u: return 4u;
case 0x80D6u: return 4u;
case 0x80D7u: return 4u;
case 0x8129u: return 3u;
case 0x8154u: return 4u;
case 0x8171u: return 4u;
case 0x825Du: return 2u;
case 0x8459u: return 4u;
case 0x846Du: return 2u;
case 0x846Eu: return 2u;
case 0x84E3u: return 16u;
case 0x84E4u: return 16u;
case 0x84E5u: return 16u;
case 0x84E6u: return 16u;
case 0x852Au: return 4u;
case 0x852Bu: return 4u;
case 0x8626u: return 4u;
case 0x8891u: return 4u;
case 0x8E46u: return 4u;
case 0x91BEu: return 3u;
case 0x91BFu: return 3u;
default: return 1u;
}
}
#endif
+3 -1
View File
@@ -156,7 +156,9 @@ impl GlDevice {
}
// No GL is reported in the header, not as a failed ioctl, so the
// guest falls back as it would for a driver that refused to load.
Err(_) => {
Err(e) => {
static SAID: std::sync::Once = std::sync::Once::new();
SAID.call_once(|| eprintln!("gex-gl: no host GL context: {e}"));
write_status(m, ring, error::NO_CONTEXT, 0, 0)?;
return Ok(0);
}
+762
View File
@@ -0,0 +1,762 @@
#!/usr/bin/env python3
"""Generate gex-gl's compatibility-profile transport from the Khronos registry.
tools/gen_gl_compat.py [--check]
Every OpenGL command in third_party/opengl-registry/xml/gl.xml -- GL 1.0
through 4.6 including what the core profile removed, and every extension
command -- gets a wire *plan* derived from the registry's own parameter
metadata (types, `len`, `class`), unless something about it cannot be
carried safely (a callback, a pointer to pointers, a length the registry
leaves to prose); those are listed in the generated files with the reason.
The plan is a short string, one token per parameter, that both encoders
interpret and the host decoders are generated from:
v | w | f | q the return: none, a 32-bit word, a float, 64 bits
w a 32-bit scalar parameter: one word
q a 64-bit scalar (doubles, 64-bit integers, and
GLintptr/GLsizeiptr, sign-extended): two words
i<size>:<count> an input array of <size>-byte elements
j<size>:<count> the same, pixel data: an offset into the bound
unpack buffer when there is one
o<size>:<count> an output array (comes back in the reply)
and a count is
n<N> N elements p<i>[*<M>] parameter i, times M
e<i> pname-sized (gl-pname-counts.h) on parameter i
s a NUL-terminated string S<i> a string of length
parameter i (<0: NUL)
z<i> parameter i bytes L<i>,<j> parameter i elements
of GL type parameter j
X<f>,<t>,<w>,<h>,<d> an unpack pixel transfer (format, type, width,
height, depth; `_` for absent): from the unpack buffer when
one is bound
B<w>,<h> a glBitmap bitmap T glPolygonStipple's
32x32 bits
On the wire a command is its scalars in order, each input array as a tag
word (0 null, 1 a blob follows: length then bytes padded to four, 2 an
offset into the bound unpack buffer: two words) and nothing for outputs;
the reply is the return value then each output as a blob. Opcodes are
COMPAT_BASE plus the command's index in the registry's sorted command list,
so a policy change never renumbers one.
Outputs:
guest/gl/gl-compat-generated.inc the Linux guest's entry points
guest/gl/gl-pname-counts.h the pname-sized counts (C, both ends)
crates/gex-kernel/src/nt/opengl/generated.rs opengl32's plans (NT)
crates/gex-gl/src/compat_plans.rs the opcode table, for the hosts' tests
web/mesa/gl-compat-generated-cases.inc the host decoder (C++; the
browser's Mesa and the native host)
"""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
import xml.etree.ElementTree as ET
ROOT = pathlib.Path(__file__).resolve().parents[1]
REGISTRY = ROOT / "third_party/opengl-registry/xml/gl.xml"
COMPAT_BASE = 8192
# Scalar types: (wire token, guest C type, host C type, element bytes).
SCALARS = {
"GLenum": ("w", "unsigned", "GLenum", 4),
"GLuint": ("w", "unsigned", "GLuint", 4),
"GLbitfield": ("w", "unsigned", "GLbitfield", 4),
"GLint": ("w", "int", "GLint", 4),
"GLsizei": ("w", "int", "GLsizei", 4),
"GLfixed": ("w", "int", "GLint", 4),
"GLclampx": ("w", "int", "GLint", 4),
"GLhandleARB": ("w", "unsigned", "GLuint", 4),
"GLshort": ("w", "short", "GLshort", 2),
"GLushort": ("w", "unsigned short", "GLushort", 2),
"GLhalfNV": ("w", "unsigned short", "GLushort", 2),
"GLbyte": ("w", "signed char", "GLbyte", 1),
"GLubyte": ("w", "unsigned char", "GLubyte", 1),
"GLboolean": ("w", "unsigned char", "GLboolean", 1),
"GLchar": ("w", "char", "GLchar", 1),
"GLcharARB": ("w", "char", "GLchar", 1),
"GLfloat": ("f", "float", "GLfloat", 4),
"GLclampf": ("f", "float", "GLfloat", 4),
"GLdouble": ("q", "double", "GLdouble", 8),
"GLclampd": ("q", "double", "GLdouble", 8),
"GLint64": ("q", "long long", "GLint64", 8),
"GLint64EXT": ("q", "long long", "GLint64", 8),
"GLuint64": ("q", "unsigned long long", "GLuint64", 8),
"GLuint64EXT": ("q", "unsigned long long", "GLuint64", 8),
"GLintptr": ("q", "long", "ptrdiff_t", None),
"GLsizeiptr": ("q", "long", "ptrdiff_t", None),
"GLintptrARB": ("q", "long", "ptrdiff_t", None),
"GLsizeiptrARB": ("q", "long", "ptrdiff_t", None),
}
# Array element types (pointer-sized integers are not carried in arrays).
ELEMENTS = {k: v for k, v in SCALARS.items() if v[3]}
ELEMENTS["void"] = ("w", "void", "void", 1)
# The object kinds a host maps from the guest's names (`class` in gl.xml).
CLASSES = {
"buffer": "buffers", "texture": "textures", "framebuffer": "framebuffers",
"renderbuffer": "renderbuffers", "query": "queries", "sampler": "samplers",
"vertex array": "vertex_arrays", "transform feedback": "transform_feedbacks",
"program pipeline": "program_pipelines", "program": "programs", "shader": "shaders",
"display list": None,
}
# Parameter vectors whose length a pname decides (`COMPSIZE(pname)`): the
# multi-valued ones; everything else is one value. Shared by every end, so
# what an encoder sends is what a decoder expects.
PNAME_COUNTS = {
16: ["GL_MODELVIEW_MATRIX", "GL_PROJECTION_MATRIX", "GL_TEXTURE_MATRIX", "GL_COLOR_MATRIX",
"GL_TRANSPOSE_MODELVIEW_MATRIX", "GL_TRANSPOSE_PROJECTION_MATRIX",
"GL_TRANSPOSE_TEXTURE_MATRIX", "GL_TRANSPOSE_COLOR_MATRIX"],
4: ["GL_CURRENT_COLOR", "GL_CURRENT_TEXTURE_COORDS", "GL_CURRENT_RASTER_POSITION",
"GL_CURRENT_RASTER_COLOR", "GL_CURRENT_RASTER_TEXTURE_COORDS", "GL_CURRENT_SECONDARY_COLOR",
"GL_FOG_COLOR", "GL_LIGHT_MODEL_AMBIENT", "GL_ACCUM_CLEAR_VALUE", "GL_COLOR_CLEAR_VALUE",
"GL_COLOR_WRITEMASK", "GL_BLEND_COLOR", "GL_VIEWPORT", "GL_SCISSOR_BOX",
"GL_MAP2_GRID_DOMAIN", "GL_TEXTURE_ENV_COLOR", "GL_TEXTURE_BORDER_COLOR",
"GL_TEXTURE_SWIZZLE_RGBA", "GL_AMBIENT", "GL_DIFFUSE", "GL_SPECULAR", "GL_EMISSION",
"GL_POSITION", "GL_AMBIENT_AND_DIFFUSE", "GL_OBJECT_PLANE", "GL_EYE_PLANE",
"GL_CONVOLUTION_BORDER_COLOR", "GL_CONVOLUTION_FILTER_SCALE", "GL_CONVOLUTION_FILTER_BIAS",
"GL_COLOR_TABLE_SCALE", "GL_COLOR_TABLE_BIAS", "GL_CURRENT_VERTEX_ATTRIB",
"GL_CONSTANT_COLOR0_NV", "GL_CONSTANT_COLOR1_NV", "GL_TEXTURE_CLIPMAP_CENTER_SGIX",
"GL_POST_CONVOLUTION_COLOR_TABLE", "GL_DEPTH_BOUNDS_EXT", "GL_COLOR"],
3: ["GL_CURRENT_NORMAL", "GL_SPOT_DIRECTION", "GL_COLOR_INDEXES", "GL_POINT_DISTANCE_ATTENUATION",
"GL_MAX_COMPUTE_WORK_GROUP_COUNT", "GL_MAX_COMPUTE_WORK_GROUP_SIZE"],
2: ["GL_DEPTH_RANGE", "GL_MAX_VIEWPORT_DIMS", "GL_POINT_SIZE_RANGE", "GL_LINE_WIDTH_RANGE",
"GL_ALIASED_POINT_SIZE_RANGE", "GL_ALIASED_LINE_WIDTH_RANGE", "GL_POLYGON_MODE",
"GL_MAP1_GRID_DOMAIN", "GL_MAP2_GRID_SEGMENTS", "GL_VIEWPORT_BOUNDS_RANGE",
"GL_DEPTH_BOUNDS_EXT"],
}
# Commands left to the hand-written halves on every end even where a plan
# would fit, because the encoder keeps state about them or a host must
# allocate on their behalf: names a host maps, client arrays and their
# pointers, mapping a buffer, the pixel store, strings handed back.
HAND = {
"glBindBuffer", "glPixelStorei", "glPixelStoref", "glGetError", "glGetString", "glGetStringi",
"glFinish", "glFlush", "glGetIntegerv", "glGetPointerv", "glGenLists", "glNewList", "glEndList",
"glFenceSync", "glDeleteSync", "glClientWaitSync", "glWaitSync", "glIsSync", "glGetSynciv",
"glDebugMessageCallback", "glDebugMessageCallbackARB", "glDebugMessageCallbackAMD",
"glReadPixels", "glGetTexImage", "glArrayElement", "glInterleavedArrays",
"glEnableClientState", "glDisableClientState", "glClientActiveTexture",
"glEnableVertexAttribArray", "glDisableVertexAttribArray",
"glEnableClientStateiEXT", "glDisableClientStateiEXT", "glEnableClientStateIndexedEXT",
"glDisableClientStateIndexedEXT", "glBindVertexArray", "glLockArraysEXT", "glUnlockArraysEXT",
"glCreateShader", "glCreateProgram", "glCreateShaderProgramv", "glCreateShaderProgramEXT",
"glCreateShaderObjectARB", "glCreateProgramObjectARB", "glDeleteObjectARB",
"glShaderSource", "glShaderSourceARB", "glGetShaderSource", "glGetShaderSourceARB",
}
# Commands whose untyped input is pixel data: an unpack buffer offset when
# one is bound.
PIXEL_COMMAND = re.compile(r"(Tex|Texture|MultiTex)(Sub)?Image|CompressedTex|CompressedMultiTex|"
r"DrawPixels|ColorTable|ColorSubTable|ConvolutionFilter|SeparableFilter")
HAND_PREFIXES = ("glDelete", "glCreate", "glMapBuffer", "glMapNamedBuffer", "glUnmap", "glFlushMapped",
"glGetBufferPointer", "glGetNamedBufferPointer")
# glGen<objects>: the encoders choose the names.
GEN_OBJECTS = re.compile(r"^glGen(?!erate)[A-Z]\w*")
def text(e):
return "".join(e.itertext())
class Param:
def __init__(self, e):
self.name = e.find("name").text
decl = re.sub(r"\s+", " ", text(e)).strip()
self.decl = decl
pt = e.find("ptype")
self.base = pt.text if pt is not None else ("void" if "void" in decl else decl.rsplit(" ", 1)[0])
before = decl[: decl.rfind(self.name)]
self.ptr = before.count("*")
self.const = bool(re.search(r"\bconst\b", before))
self.len = e.get("len")
self.cls = e.get("class")
class Command:
def __init__(self, e):
proto = e.find("proto")
self.name = proto.find("name").text
ret = re.sub(r"\s+", " ", text(proto)).strip()
self.ret = ret[: ret.rfind(self.name)].strip()
self.params = [Param(p) for p in e.findall("param")]
a = e.find("alias")
self.alias = a.get("name") if a is not None else None
def load():
root = ET.parse(REGISTRY).getroot()
commands = {}
for e in root.find("commands"):
c = Command(e)
commands[c.name] = c
# The suffixed spellings guest/gl serves as the core command although the
# registry does not mark them aliases (tools/gen_gl_extensions.py).
sys.path.insert(0, str(ROOT / "tools"))
from gen_gl_extensions import CURATED_ALIASES
for name, target in CURATED_ALIASES.items():
commands[name].alias = target
enums = {}
for group in root.findall("enums"):
for e in group.findall("enum"):
if e.get("api") in (None, "gl"):
enums.setdefault(e.get("name"), int(e.get("value"), 0))
wanted = set()
for f in root.findall("feature"):
if f.get("api") == "gl":
for req in f.findall("require"):
wanted |= {c.get("name") for c in req.findall("command")}
for ext in root.find("extensions"):
sup = (ext.get("supported") or "").split("|")
if not {"gl", "glcore"} & set(sup):
continue
for req in ext.findall("require"):
if req.get("api") in (None, "gl"):
wanted |= {c.get("name") for c in req.findall("command")}
return commands, enums, wanted
class Skip(Exception):
pass
def count_spec(cmd, p, index_of):
"""The count token for pointer parameter p, or Skip."""
L = p.len
names = [q.name for q in cmd.params]
scalars = {q.name for q in cmd.params if q.ptr == 0}
if p.base in ("GLchar", "GLcharARB") and p.const:
if L is None or L in ("COMPSIZE(name)", "COMPSIZE()"):
return "s"
m = re.fullmatch(r"COMPSIZE\((\w+),(\w+)\)", L)
if m and m.group(2) in scalars and m.group(1) == p.name:
return f"S{index_of[m.group(2)]}"
if L in scalars:
return f"S{index_of[L]}"
raise Skip(f"string length {L}")
if L is None:
raise Skip(f"{p.name} has no length")
if L.isdigit():
if int(L) == 0:
raise Skip("zero-length array")
return f"n{L}"
m = re.fullmatch(r"(\w+)\s*\*\s*(\d+)", L)
if m and m.group(1) in scalars:
return f"p{index_of[m.group(1)]}*{m.group(2)}"
if L in scalars:
if p.base == "void":
return f"z{index_of[L]}"
return f"p{index_of[L]}"
m = re.fullmatch(r"COMPSIZE\(([\w,]*)\)", L)
if not m:
raise Skip(f"length {L}")
args = [a for a in m.group(1).split(",") if a]
if args and args[-1] in ("pname",) and args[-1] in scalars and (len(args) == 1 or cmd.name.startswith(("glGetTexLevelParameter",))):
return f"e{index_of[args[-1]]}"
if len(args) == 1 and args[0] == "pname" and "pname" in scalars:
return f"e{index_of['pname']}"
if p.const and p.base == "void" and args and args[0] == "format" and args[1:2] == ["type"] and 3 <= len(args) <= 5:
idx = [index_of[a] if a in index_of else "_" for a in args[2:]]
while len(idx) < 3:
idx.append("_")
return "X%d,%d,%s" % (index_of["format"], index_of["type"], ",".join(str(i) for i in idx))
if args == ["width", "height"] and p.base == "GLubyte" and cmd.name == "glBitmap":
return f"B{index_of['width']},{index_of['height']}"
if args == [] and cmd.name == "glPolygonStipple":
return "T"
if len(args) == 2 and p.const and args[1] == "type" and args[0] in scalars and p.name == "lists":
return f"L{index_of[args[0]]},{index_of['type']}"
if len(args) == 1 and args[0] in scalars and p.base == "void" and args[0] == "size":
return f"z{index_of['size']}"
# Indexed state (glGetIntegeri_v): sized as that state is.
if args == ["target"] and not p.const and re.search(r"i_v|Indexedv", cmd.name):
return f"e{index_of['target']}"
# glClearBuffer*v: four for GL_COLOR, one for depth or stencil.
if args == ["buffer"] and "buffer" in scalars:
return f"e{index_of['buffer']}"
# One value per uniform.
if args == ["uniformCount", "pname"] and "uniformCount" in scalars:
return f"p{index_of['uniformCount']}"
# A uniform's value: as many as its type holds, which the host knows.
if len(args) == 2 and args[1] == "location" and not p.const and args[0] in scalars:
return f"U{index_of[args[0]]},{index_of['location']}"
raise Skip(f"length {L}")
def offset_pointer(cmd, p):
"""A vertex, index or indirect pointer: an offset into a bound buffer, or
client memory the encoder uploads to one first. Never carried as data."""
if p.base != "void" or not p.const or p.ptr != 1:
return False
if p.name == "indirect":
return True
if p.name == "pointer" and re.search(r"Pointer", cmd.name):
return p.len is None or p.len.startswith("COMPSIZE(")
if p.name == "indices" and re.match(r"glDraw(Range)?Elements", cmd.name):
return True
return False
# Commands whose pointers are buffer offsets (offset_pointer): planned for
# the hosts, which take the offset; the encoders keep the client-memory case
# by hand and call these by opcode.
POINTER_COMMANDS = re.compile(r"^gl((Vertex|Color|TexCoord|Normal|SecondaryColor|FogCoord|EdgeFlag|Index)Pointer"
r"|VertexAttrib[IL]?Pointer|Draw(Range)?Elements\w*|Draw(Arrays|Elements)Indirect"
r"|MultiDraw(Arrays|Elements)Indirect)(ARB|EXT)?$")
def plan_of(cmd):
"""(plan, reason): the wire plan, or None and why not."""
try:
pointer_command = bool(POINTER_COMMANDS.match(cmd.name))
if not pointer_command and (cmd.name in HAND or cmd.name.startswith(HAND_PREFIXES) or GEN_OBJECTS.match(cmd.name)):
raise Skip("hand-written")
ret = cmd.ret.replace("const", "").strip()
if ret == "void":
r = "v"
elif ret in SCALARS and "*" not in ret:
r = SCALARS[ret][0]
if r == "q" and SCALARS[ret][3] is None:
raise Skip("pointer-sized return")
else:
raise Skip(f"returns {cmd.ret}")
index_of = {q.name: i for i, q in enumerate(cmd.params)}
toks = []
for p in cmd.params:
if p.ptr == 0:
if p.base not in SCALARS:
raise Skip(f"{p.name} is a {p.base}")
if p.cls and p.cls not in CLASSES:
raise Skip(f"{p.name} is a {p.cls}")
toks.append(SCALARS[p.base][0])
continue
if p.ptr != 1:
raise Skip(f"{p.name} is a pointer to pointers")
if p.base not in ELEMENTS:
raise Skip(f"{p.name} points to {p.base}")
if p.cls:
raise Skip(f"{p.name} is an array of {p.cls} names")
if offset_pointer(cmd, p):
toks.append("P")
continue
spec = count_spec(cmd, p, index_of)
size = ELEMENTS[p.base][3]
if not p.const:
if spec[0] in "XBTLsSz" and not (spec[0] == "z"):
raise Skip(f"output {p.name} sized {spec}")
if p.base == "void" and spec[0] != "z":
raise Skip(f"untyped output {p.name}")
toks.append(f"o{size}:{spec}")
else:
if spec[0] in "XBTLsSz":
size = 1
# Pixel data may be an offset into the bound unpack buffer.
pbo = spec[0] in "XBT" or (p.base == "void" and PIXEL_COMMAND.search(cmd.name))
toks.append(f"{'j' if pbo else 'i'}{size}:{spec}")
if "P" in toks and not pointer_command:
raise Skip("an offset pointer in a command the encoders do not track")
return r + " " + " ".join(toks) if toks else r, None
except Skip as e:
return None, str(e)
def guest_type(p):
if p.ptr:
base = ELEMENTS.get(p.base, ("", "void"))[1] if p.base in ELEMENTS else "void"
return ("const " if p.const else "") + base + " *"
return SCALARS[p.base][1]
def host_type(p):
if p.ptr:
base = ELEMENTS[p.base][2]
return ("const " if p.const else "") + base + "*"
return SCALARS[p.base][2]
def guest_ret(cmd):
r = cmd.ret.replace("const", "").strip()
return "void" if r == "void" else SCALARS[r][1]
def host_ret(cmd):
r = cmd.ret.replace("const", "").strip()
return "void" if r == "void" else SCALARS[r][2]
def guest_value(p):
"""The parameter as the uint64 the guest interpreter takes."""
n = p.name + "_"
if p.ptr:
return f"(uint64_t)(uintptr_t){n}"
t = SCALARS[p.base]
if t[0] == "f":
return f"(uint64_t)as_bits({n})"
if p.base in ("GLdouble", "GLclampd"):
return f"gexgen_dbits({n})"
if t[0] == "q":
return f"(uint64_t)(int64_t){n}" if t[1] in ("long", "long long") else f"(uint64_t){n}"
if t[1] in ("int", "short", "signed char", "char"):
return f"(uint64_t)(uint32_t)(int32_t){n}"
return f"(uint64_t)(uint32_t){n}"
def defined_in(path):
"""C function definitions in a source file (to leave hand-written ones be)."""
src = path.read_text() if path.exists() else ""
names = set(re.findall(r"^[A-Za-z_][\w \*]*?\b(gl[A-Z]\w*)\s*\([^;{]*\)\s*\{", src, re.M))
names |= set(re.findall(r"__typeof\(\w+\)\s+(gl[A-Z]\w*)", src))
return names
def emit_guest(cmds, plans, opcodes):
hand = set()
for f in ("gexgl.c", "gl44-generated.inc", "gexgl-glx.inc"):
hand |= defined_in(ROOT / "guest/gl" / f)
out = ["/* Generated by tools/gen_gl_compat.py from the Khronos registry; do not edit.",
" *",
" * The Linux guest's compatibility-profile entry points: every registry",
" * command with a wire plan that gexgl.c and gl44-generated.inc do not",
" * define, each a call to gexgen_call (gexgl.c) with its plan. Aliases",
" * of exported commands come from gl-aliases-generated.inc. */", ""]
n = 0
for name in sorted(plans):
c = cmds[name]
if name in hand or " P" in plans[name]:
continue
# An alias of a command that will be exported is left to the alias
# file, which spells it as that command.
if c.alias and (c.alias in hand or c.alias in plans):
continue
params = ", ".join(f"{guest_type(p)} {p.name}_" for p in c.params) or "void"
vals = ", ".join(guest_value(p) for p in c.params)
rt = guest_ret(c)
body = f"uint64_t args__[{max(len(c.params), 1)}] = {{{vals or '0'}}};\n "
call = f"gexgen_call({opcodes[name]}u, \"{plans[name]}\", args__)"
r = plans[name].split(" ")[0]
if rt == "void":
body += call + ";"
elif r == "f":
body += f"uint32_t ret__ = (uint32_t){call}; float f__; memcpy(&f__, &ret__, 4); return f__;"
else:
body += f"return ({rt}){call};"
out.append(f"{rt} {name}({params}) {{\n {body}\n}}")
n += 1
out.insert(6, f"/* {n} entry points. */")
return "\n".join(out) + "\n"
def emit_pname_counts(enums):
lines = ["/* Generated by tools/gen_gl_compat.py; do not edit.",
" *",
" * How many values a pname-sized parameter vector holds (COMPSIZE(pname)",
" * in the registry): the guest encoders, opengl32's and every host",
" * decoder size those vectors with this one table. */",
"#ifndef GEXGL_PNAME_COUNTS_H", "#define GEXGL_PNAME_COUNTS_H", "",
"static inline unsigned gexgl_pname_count(unsigned pname) {", " switch (pname) {"]
seen = {}
for count in sorted(PNAME_COUNTS, reverse=True):
for e in PNAME_COUNTS[count]:
v = enums.get(e)
if v is None or v in seen:
continue
seen[v] = count
for v, count in sorted(seen.items()):
lines.append(f" case 0x{v:04X}u: return {count}u;")
lines += [" default: return 1u;", " }", "}", "", "#endif", ""]
rust = ["/// What `gexgl_pname_count` says (guest/gl/gl-pname-counts.h).",
"pub fn pname_count(pname: u32) -> u32 {", " match pname {"]
for v, count in sorted(seen.items()):
rust.append(f" 0x{v:04X} => {count},")
rust += [" _ => 1,", " }", "}"]
return "\n".join(lines), "\n".join(rust)
def nt_table():
"""opengl32's unix calls and their params signatures (table.rs)."""
src = (ROOT / "crates/gex-kernel/src/nt/opengl/table.rs").read_text()
return dict(re.findall(r'\("(\w+)", "(\w*)"\)', src))
# Commands opengl32 does not serve that do not keep the version it reports
# down (a call still fails loudly by name): evaluators, pixel maps, feedback
# and selection, which nothing this serves draws with.
NT_TOLERATED = {
"glMap1d", "glMap1f", "glMap2d", "glMap2f", "glGetMapdv", "glGetMapfv", "glGetMapiv",
"glMapGrid1d", "glMapGrid1f", "glMapGrid2d", "glMapGrid2f",
"glGetPixelMapfv", "glGetPixelMapuiv", "glGetPixelMapusv", "glGetPolygonStipple",
"glFeedbackBuffer", "glSelectBuffer", "glInterleavedArrays", "glArrayElement", "glEdgeFlagPointer",
"glIndexPointer", "glGetPointerv", "glAreTexturesResident", "glPrioritizeTextures",
"glMultiDrawElements", "glGetVertexAttribPointerv", "glGetShaderSource", "glGetAttachedShaders",
"glTransformFeedbackVaryings", "glGetUniformIndices", "glGetActiveUniformBlockiv",
"glMultiDrawElementsBaseVertex",
}
# Extensions opengl32 does not claim even with every command served: what it
# serves differs from what they promise (a persistent mapping is a copy here,
# not coherent memory).
NT_UNCLAIMABLE = {"GL_ARB_buffer_storage", "GL_EXT_buffer_storage"}
# The newest version whose promise includes nothing in NT_UNCLAIMABLE.
NT_VERSION_LIMIT = (4, 3)
def emit_nt(cmds, plans, opcodes, pname_rust):
funcs = nt_table()
hand = set(re.findall(r'"(gl\w+)"\s*(?:\||=>)', (ROOT / "crates/gex-kernel/src/nt/opengl/mod.rs").read_text()))
rows, aliases, skipped, pointer_rows = [], [], [], []
served = set(hand)
for name in sorted(funcs):
if not name.startswith("gl"):
continue
c = cmds.get(name)
if c is None:
continue
if name not in plans:
if name not in hand and c.alias and (c.alias in plans or c.alias in hand):
# Same parameters under another name: served as that command.
if [p.base for p in c.params] == [p.base for p in cmds[c.alias].params]:
aliases.append((name, c.alias))
served.add(name)
continue
sig = funcs[name]
want = 1 + len(c.params) + (0 if plans[name][0] == "v" else 1)
if len(sig) != want or (sig and sig[0] != "p"):
skipped.append(f"{name} (params struct {sig!r})")
continue
if " P" in plans[name]:
pointer_rows.append((name, opcodes[name], plans[name]))
continue
rows.append((name, opcodes[name], plans[name]))
served.add(name)
# What opengl32 can honestly report: the newest version, and the
# extensions, whose every command it serves.
root = ET.parse(REGISTRY).getroot()
required, version = set(), (1, 0)
for f in root.findall("feature"):
if f.get("api") != "gl":
continue
for r in f.findall("require"):
required |= {x.get("name") for x in r.findall("command")}
number = tuple(int(x) for x in f.get("number").split("."))
if number > NT_VERSION_LIMIT or required - served - NT_TOLERATED:
break
version = number
claimable = []
for e in root.find("extensions"):
if not {"gl", "glcore"} & set((e.get("supported") or "").split("|")):
continue
need = {x.get("name") for r in e.findall("require") if r.get("api") in (None, "gl")
for x in r.findall("command")}
if e.get("name") not in NT_UNCLAIMABLE and not need - served:
claimable.append(e.get("name"))
out = ["// Generated by tools/gen_gl_compat.py from the Khronos registry and",
"// table.rs; do not edit.", "",
"/// opengl32 calls with a wire plan (`tools/gen_gl_compat.py`), by name:",
"/// the opcode and the plan, which `super::planned` interprets.",
"pub const PLANS: &[(&str, u32, &str)] = &["]
out += [f' ("{n}", {o}, "{p}"),' for n, o, p in rows]
out += ["];", "",
"/// The pointer commands (vertex, index and indirect pointers as buffer",
"/// offsets), which `super` sends itself once client memory is uploaded.",
"pub const POINTER_PLANS: &[(&str, u32, &str)] = &["]
out += [f' ("{n}", {o}, "{p}"),' for n, o, p in pointer_rows]
out += ["];", "", "/// opengl32 calls that are another command under another name.",
"pub const ALIASES: &[(&str, &str)] = &["]
out += [f' ("{a}", "{b}"),' for a, b in aliases]
out += ["];", "",
"/// The newest GL version every command of which opengl32 serves (or",
"/// tolerates missing: `NT_TOLERATED` in the generator).",
f"pub const MAX_VERSION: (i32, i32) = {version};",
"/// The registry extensions every command of which it serves.",
"pub const CLAIMABLE: &[&str] = &["]
out += [f' "{e}",' for e in sorted(claimable)]
out += ["];", "", pname_rust, ""]
return "\n".join(out)
def host_case(c, opcode, plan):
toks = plan.split(" ")
r, ptoks = toks[0], toks[1:]
L = [f"/* {c.name} */", f"template <typename R> static bool gexgen_{opcode}(R& a) {{"]
args = []
post = []
check = []
names = [p.name + "_" for p in c.params]
for i, (p, t) in enumerate(zip(c.params, ptoks)):
n = names[i]
if t == "P":
L.append(f" const void* {n} = reinterpret_cast<const void*>(static_cast<uintptr_t>(a.u64()));")
args.append(n)
continue
if t in ("w", "f", "q"):
ht = host_type(p)
rd = {"w": "a.u32()", "f": "a.f32()", "q": "a.u64()"}[t]
if p.base in ("GLdouble", "GLclampd"):
rd = "a.f64()"
elif t == "q":
rd = "a.i64()" if ht in ("GLint64", "ptrdiff_t") else "a.u64()"
elif t == "w" and ht in ("GLint", "GLsizei", "GLshort", "GLbyte"):
rd = "a.i32()"
if p.cls and CLASSES.get(p.cls):
L.append(f" const {ht} {n} = ({ht})GEXGEN_NAME({CLASSES[p.cls]}, {rd});")
else:
L.append(f" const {ht} {n} = ({ht}){rd};")
args.append(n)
continue
kind, rest = t[0], t[1:]
pbo = kind == "j"
kind = "i" if pbo else kind
size, spec = rest.split(":", 1)
size = int(size)
et = ELEMENTS[p.base][2]
if spec[0] == "n":
count = spec[1:]
elif spec[0] == "p":
m = re.fullmatch(r"p(\d+)(?:\*(\d+))?", spec)
count = f"gexgen_count({names[int(m.group(1))]}, {m.group(2) or 1})"
elif spec[0] == "e":
count = f"gexgl_pname_count((unsigned){names[int(spec[1:])]})"
elif spec[0] == "z":
count = f"gexgen_count({names[int(spec[1:])]}, 1)"
elif spec[0] == "U":
pi, li = spec[1:].split(",")
count = f"uniform_components({names[int(pi)]}, {names[int(li)]})"
else:
count = None
if kind == "o":
check.append(f" const size_t {n}count = {count};")
check.append(f" std::vector<uint64_t> {n}store(gexgen_words({n}count < 16 ? 16 : {n}count, {size}), 0);")
check.append(f" {et}* {n} = reinterpret_cast<{et}*>({n}store.data());")
post.append(f" put_blob({n}, (uint32_t)({n}count * {size}));")
args.append(n)
continue
L.append(f" gexgen_raw {n}raw; std::vector<uint64_t> {n}store;")
L.append(f" if (!gexgen_take(a, {n}raw, {'true' if pbo else 'false'})) return false;")
if spec[0] in "sS":
check.append(f" const char* {n}s = nullptr;")
check.append(f" if (!gexgen_check_string({n}raw, {n}store, &{n}s)) {{ a.ok = false; return false; }}")
check.append(f" const {et}* {n} = reinterpret_cast<const {et}*>({n}s);")
args.append(n)
continue
check.append(f" const void* {n}v = nullptr;")
if spec[0] == "X":
f_, t_, w_, h_, d_ = spec[1:].split(",")
dim = lambda x, dflt: names[int(x)] if x != "_" else dflt
test = (f"gexgen_check_pixels({n}raw, {n}store, &{n}v, {names[int(f_)]}, {names[int(t_)]}, "
f"{dim(w_, '1')}, {dim(h_, '1')}, {dim(d_, '-1')})")
else:
if spec[0] == "B":
w_, h_ = spec[1:].split(",")
bytes_ = f"gexgen_bitmap_bytes({names[int(w_)]}, {names[int(h_)]})"
elif spec[0] == "T":
bytes_ = "128"
elif spec[0] == "L":
ni, ti = spec[1:].split(",")
bytes_ = f"gexgen_count({names[int(ni)]}, (long long)gexgen_type_bytes({names[int(ti)]}))"
else:
bytes_ = f"{count} * {size}"
test = f"gexgen_check({n}raw, {n}store, &{n}v, {bytes_})"
check.append(f" if (!{test}) {{ a.ok = false; return false; }}")
check.append(f" const {et}* {n} = reinterpret_cast<const {et}*>({n}v);")
args.append(n)
L.append(" if (!a.ok) return false;")
L += check
ftype = f"{host_ret(c)} (*)({', '.join(host_type(p) for p in c.params)})"
alias = f'"{c.alias}"' if c.alias else "nullptr"
L.append(f" using F__ = {ftype};")
L.append(f" static F__ f__ = reinterpret_cast<F__>(gexgen_proc(\"{c.name}\", {alias}));")
call = f"f__({', '.join(args)})"
missing = "put_u32(0); " if r in ("w", "f") else "put_u64(0); " if r == "q" else ""
L.append(f" if (!f__) {{ gexgen_missing(\"{c.name}\"); {missing}" +
"".join(f"put_blob(nullptr, 0); " for t in ptoks if t[0] == "o") + "return true; }")
if r == "v":
L.append(f" {call};")
elif r == "f":
L.append(f" const float ret__ = {call}; uint32_t bits__; memcpy(&bits__, &ret__, 4); put_u32(bits__);")
elif r == "q":
L.append(f" put_u64((uint64_t){call});")
else:
L.append(f" put_u32((uint32_t){call});")
L += post
L.append(" return true;")
L.append("}")
return "\n".join(L)
def emit_host(cmds, plans, opcodes):
"""The decoders (a function per command, which a compiler takes far
better than one switch of thousands of cases) and the cases."""
out = ["/* Generated by tools/gen_gl_compat.py from the Khronos registry; do not edit.",
" *",
" * The host half of every planned command: decode, map the guest's object",
" * names (GEXGEN_NAME), call the host's GL through gexgen_proc, reply;",
" * false for a malformed command. The includer defines the Reader,",
" * put_u32/put_u64/put_blob, GEXGEN_NAME, uniform_components,",
" * gexgen_proc/gexgen_missing, and includes web/mesa/gexgl-compat-host.h;",
" * the cases (gl-compat-generated-cases.inc) go in its switch. */"]
cases = ["/* Generated by tools/gen_gl_compat.py; do not edit. The decoders are",
" * gl-compat-generated-decoders.inc. */"]
for name in sorted(plans):
out.append(host_case(cmds[name], opcodes[name], plans[name]))
cases.append(f"case {opcodes[name]}: if (!gexgen_{opcodes[name]}(a)) return false; break;")
return "\n".join(out) + "\n", "\n".join(cases) + "\n"
def emit_rust_table(plans, opcodes):
out = ["// Generated by tools/gen_gl_compat.py; do not edit.", "",
"/// The first opcode of the generated compatibility-profile commands.",
f"pub const COMPAT_BASE: u32 = {COMPAT_BASE};",
"/// Every planned command: name, opcode and plan.",
"pub const PLANS: &[(&str, u32, &str)] = &["]
out += [f' ("{n}", {opcodes[n]}, "{plans[n]}"),' for n in sorted(plans)]
out += ["];", ""]
return "\n".join(out)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true", help="fail if a checked-in output differs")
ap.add_argument("--report", action="store_true", help="list the commands left out, and why")
args = ap.parse_args()
cmds, enums, wanted = load()
allnames = sorted(cmds)
opcodes = {n: COMPAT_BASE + allnames.index(n) for n in allnames}
plans, skipped = {}, {}
for n in sorted(wanted):
p, why = plan_of(cmds[n])
if p is None:
skipped[n] = why
else:
plans[n] = p
pname_c, pname_rust = emit_pname_counts(enums)
host_decoders, host_cases = emit_host(cmds, plans, opcodes)
outputs = {
ROOT / "guest/gl/gl-compat-generated.inc": emit_guest(cmds, plans, opcodes),
ROOT / "guest/gl/gl-pname-counts.h": pname_c,
ROOT / "crates/gex-kernel/src/nt/opengl/generated.rs": emit_nt(cmds, plans, opcodes, pname_rust),
ROOT / "crates/gex-gl/src/compat_plans.rs": emit_rust_table(plans, opcodes),
ROOT / "web/mesa/gl-compat-generated-decoders.inc": host_decoders,
ROOT / "web/mesa/gl-compat-generated-cases.inc": host_cases,
}
if args.report:
for n, why in sorted(skipped.items()):
print(f"{n}: {why}")
print(f"{len(plans)} planned, {len(skipped)} left out", file=sys.stderr)
if args.check:
stale = [str(p.relative_to(ROOT)) for p, v in outputs.items() if not p.is_file() or p.read_text() != v]
if stale:
ap.error("stale generated files: " + ", ".join(stale))
return 0
for p, v in outputs.items():
p.write_text(v)
return 0
if __name__ == "__main__":
sys.exit(main())
+86
View File
@@ -0,0 +1,86 @@
/* The host side of the generated compatibility-profile commands
* (tools/gen_gl_compat.py, gl-compat-generated-cases.inc): reading a plan's
* input arrays off the wire and checking them against the size the plan
* gives, which is computed here exactly as the guest computed it
* (guest/gl/gexgl-plan.h). Shared by the browser's Mesa decoder
* (gexgl-mesa.cpp) and the native host's (crates/gex-gl/native).
*
* The includer provides, before this header: a `Reader` with u32/u64/blob
* and `ok`; `unpack_store`, the unpack pixel store its pixel commands
* track; and, before the cases, put_u32/put_u64/put_blob, GEXGEN_NAME(kind,
* name), `void* gexgen_proc(const char* name, const char* alias)` and
* `void gexgen_missing(const char* name)`. */
#ifndef GEXGL_COMPAT_HOST_H
#define GEXGL_COMPAT_HOST_H
#include <cstdint>
#include <cstring>
#include <limits>
#include <vector>
#include "../../guest/gl/gexgl-plan.h"
/* 64-bit words enough for `count` elements of `size` bytes. */
static inline size_t gexgen_words(size_t count, size_t size) {
if (count > GEXGEN_MAX_BYTES / (size ? size : 1)) count = GEXGEN_MAX_BYTES / (size ? size : 1);
return (count * size + 7) / 8 + 1;
}
/* An input array as it came off the wire: read in parameter order, checked
* once every parameter (its count among them) has been read. */
struct gexgen_raw {
uint32_t tag = 0; /* 0 NULL, 1 bytes, 2 an unpack buffer offset */
const uint8_t* p = nullptr;
uint32_t n = 0;
uint64_t offset = 0;
};
template <typename R>
static bool gexgen_take(R& a, gexgen_raw& r, bool unpack) {
r.tag = a.u32();
if (!a.ok) return false;
if (r.tag == 1) r.p = a.blob(r.n);
else if (r.tag == 2 && unpack) r.offset = a.u64();
else if (r.tag != 0) a.ok = false;
return a.ok;
}
/* Bytes, which must be exactly `bytes` long: copied to 8-byte-aligned
* storage, zero-padded to at least 64 bytes (a pname-sized vector GL may read
* more of than the shared table says). An unpack offset is passed as the
* pointer GL takes for one. */
static inline bool gexgen_check(const gexgen_raw& r, std::vector<uint64_t>& store, const void** out, size_t bytes) {
*out = nullptr;
if (r.tag == 0) return true;
if (r.tag == 2) { *out = reinterpret_cast<const void*>(static_cast<uintptr_t>(r.offset)); return true; }
if (r.n != bytes) return false;
store.assign((r.n + 7) / 8 < 8 ? 8 : (r.n + 7) / 8, 0);
if (r.n) memcpy(store.data(), r.p, r.n);
*out = store.data();
return true;
}
/* An unpack pixel transfer, sized by this end's unpack store. */
static inline bool gexgen_check_pixels(const gexgen_raw& r, std::vector<uint64_t>& store, const void** out,
uint32_t format, uint32_t type, int w, int h, int d) {
struct gexgl_pixel_layout layout;
const size_t bytes = gexgl_compute_pixel_layout(format, type, w, h, d, &unpack_store, &layout) ? layout.end : 0;
return gexgen_check(r, store, out, bytes);
}
static inline size_t gexgen_bitmap_bytes(long long w, long long h) {
return gexgen_bitmap_bytes_store(w, h, &unpack_store);
}
/* A string: any length, NUL-terminated here. */
static inline bool gexgen_check_string(const gexgen_raw& r, std::vector<uint64_t>& store, const char** out) {
*out = nullptr;
if (r.tag == 0) return true;
if (r.tag != 1) return false;
store.assign(r.n / 8 + 1, 0);
if (r.n) memcpy(store.data(), r.p, r.n);
*out = reinterpret_cast<const char*>(store.data());
return true;
}
#endif
+17
View File
@@ -481,6 +481,7 @@ static bool gexgl_negative_count(GLsizei n, Fn call)
gexgl_pixel_store pack_store = gexgl_default_pixel_store();
gexgl_pixel_store unpack_store = gexgl_default_pixel_store();
#include "gexgl-compat-host.h"
int get_frontend_param(struct pipe_frontend_screen* fscreen,
enum st_manager_param param) {
@@ -1591,6 +1592,21 @@ uint32_t uniform_components(GLuint program, GLint location) {
}
}
/* For the generated compatibility-profile cases (gexgl-compat-host.h). */
#define GEXGEN_NAME(kind, name) lookup(kind, name)
void* gexgen_proc(const char* name, const char* alias) {
void* f = reinterpret_cast<void*>(_mesa_glapi_get_proc_address(name));
if (!f && alias) f = reinterpret_cast<void*>(_mesa_glapi_get_proc_address(alias));
return f;
}
void gexgen_missing(const char* name) {
static std::unordered_set<std::string> said;
if (said.insert(name).second)
fprintf(stderr, "gexgl: Mesa has no %s; the call does nothing\n", name);
}
#include "gl-compat-generated-decoders.inc"
bool one(uint32_t op, Reader& a) {
switch (op) {
case CONTEXT_CREATE: {
@@ -2497,6 +2513,7 @@ bool one(uint32_t op, Reader& a) {
case PUSH_ATTRIB: glPushAttrib(a.u32()); break;
case POP_ATTRIB: glPopAttrib(); break;
#include "gl44-generated-cases.inc"
#include "gl-compat-generated-cases.inc"
default:
/* Named, once. A command the host does not know aborts the whole
* batch -- the guest discards every queued byte, including the
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -198,7 +198,7 @@ export const op = {
};
export const MAGIC = 0x47584547;
export const PROTOCOL_VERSION = 12;
export const PROTOCOL_VERSION = 13;
export const HEADER_BYTES = 32;
export const error = {