mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
nt_unixcall: glBlendFunc, glBlendFuncSeparate, glViewport, glTexParameteri and glUniform1f on the ring's fast path (E1)
The next GL calls in Noita's frame that still made an NT syscall each (GEX_NT_GL_STATS on the ejected page: 39, 8, 9, 12 and 14 a frame, about 0.4 ms of the main thread's frame with the stats' timing), all commands with no layer state. The provider writes them as the layer's hot_one does; tests/nt glfast checks each by a query (x86 with and without --cgen, x64), and gex-kernel's constants test covers the codes. The provider is C (gex-cgen/providers): no unit re-keys but the NT trampolines' (a few functions), whose key carries the providers it binds. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_d2453757b8a84fdbb4ee7c9e093141df
This commit is contained in:
1 parent
90291e6415
commit
430acec794
5 files changed
+78
-5
No files matched your search
@@ -58,6 +58,11 @@
|
||||
#define FN_glUniform1i 2524u
|
||||
#define FN_glUniform2f 2542u
|
||||
#define FN_glUseProgram 2645u
|
||||
#define FN_glBlendFunc 16u
|
||||
#define FN_glBlendFuncSeparate 463u
|
||||
#define FN_glViewport 344u
|
||||
#define FN_glTexParameteri 313u
|
||||
#define FN_glUniform1f 2520u
|
||||
#define FN_glEnableClientState 82u
|
||||
#define FN_glDisableClientState 73u
|
||||
#define OP_ENABLE 19u
|
||||
@@ -65,12 +70,17 @@
|
||||
#define OP_USE_PROGRAM 55u
|
||||
#define OP_UNIFORM_1I 64u
|
||||
#define OP_UNIFORM_2F 66u
|
||||
#define OP_VIEWPORT 18u
|
||||
#define OP_BLEND_FUNC 21u
|
||||
#define OP_BLEND_FUNC_SEPARATE 37u
|
||||
#define OP_UNIFORM_1F 65u
|
||||
#define OP_TEX_PARAMETER_I 100u
|
||||
#define OP_BIND_TEXTURE 98u
|
||||
#define OP_ACTIVE_TEXTURE 99u
|
||||
#define OP_ENABLE_CLIENT_STATE 185u
|
||||
#define OP_DISABLE_CLIENT_STATE 186u
|
||||
|
||||
/* Append one command of `n` argument words (1 to 3) taken from the params
|
||||
/* Append one command of `n` argument words (1 to 4) taken from the params
|
||||
* struct (after its TEB pointer). 1 when it is in the ring. */
|
||||
GEX_INLINE int gl_put(uint32_t op, uint32_t params, uint32_t n) {
|
||||
uint32_t ring = __atomic_load_n(GA(GL_FAST_RING), __ATOMIC_ACQUIRE);
|
||||
@@ -134,6 +144,14 @@ static GEX_PROVIDER(p_unix_call) {
|
||||
case FN_glBindTexture: op = OP_BIND_TEXTURE, n = 2; break;
|
||||
case FN_glUniform1i: op = OP_UNIFORM_1I, n = 2; break;
|
||||
case FN_glUniform2f: op = OP_UNIFORM_2F, n = 3; break;
|
||||
/* The next most frequent in Noita's frame after the seven above
|
||||
* (GEX_NT_GL_STATS: 39, 8, 9, 12 and 14 a frame), all commands
|
||||
* with no layer state, as the layer's `hot_one` writes them. */
|
||||
case FN_glBlendFunc: op = OP_BLEND_FUNC, n = 2; break;
|
||||
case FN_glBlendFuncSeparate: op = OP_BLEND_FUNC_SEPARATE, n = 4; break;
|
||||
case FN_glViewport: op = OP_VIEWPORT, n = 4; break;
|
||||
case FN_glTexParameteri: op = OP_TEX_PARAMETER_I, n = 3; break;
|
||||
case FN_glUniform1f: op = OP_UNIFORM_1F, n = 2; break;
|
||||
case FN_glEnableClientState:
|
||||
case FN_glDisableClientState:
|
||||
if (params >= 0x10000u && client_state(params, code == FN_glEnableClientState)) {
|
||||
|
||||
@@ -1470,6 +1470,11 @@ enum Hot {
|
||||
BindTexture,
|
||||
Uniform1i,
|
||||
Uniform2f,
|
||||
BlendFunc,
|
||||
BlendFuncSeparate,
|
||||
Viewport,
|
||||
TexParameteri,
|
||||
Uniform1f,
|
||||
}
|
||||
|
||||
fn hot(code: u32) -> Option<Hot> {
|
||||
@@ -1485,6 +1490,11 @@ fn hot(code: u32) -> Option<Hot> {
|
||||
"glBindTexture" => Some(Hot::BindTexture),
|
||||
"glUniform1i" => Some(Hot::Uniform1i),
|
||||
"glUniform2f" => Some(Hot::Uniform2f),
|
||||
"glBlendFunc" => Some(Hot::BlendFunc),
|
||||
"glBlendFuncSeparate" => Some(Hot::BlendFuncSeparate),
|
||||
"glViewport" => Some(Hot::Viewport),
|
||||
"glTexParameteri" => Some(Hot::TexParameteri),
|
||||
"glUniform1f" => Some(Hot::Uniform1f),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
@@ -1501,6 +1511,13 @@ fn hot_one(c: &mut Call<'_>, h: Hot, p: &Params) -> R<()> {
|
||||
Hot::BindTexture => cmd(c, op::BIND_TEXTURE, &[p.u32(c, 1)?, p.u32(c, 2)?], &[]),
|
||||
Hot::Uniform1i => cmd(c, op::UNIFORM_1I, &[p.u32(c, 1)?, p.u32(c, 2)?], &[]),
|
||||
Hot::Uniform2f => cmd(c, op::UNIFORM_2F, &[p.u32(c, 1)?, p.u32(c, 2)?, p.u32(c, 3)?], &[]),
|
||||
Hot::BlendFunc => cmd(c, op::BLEND_FUNC, &[p.u32(c, 1)?, p.u32(c, 2)?], &[]),
|
||||
Hot::BlendFuncSeparate => {
|
||||
cmd(c, op::BLEND_FUNC_SEPARATE, &[p.u32(c, 1)?, p.u32(c, 2)?, p.u32(c, 3)?, p.u32(c, 4)?], &[])
|
||||
}
|
||||
Hot::Viewport => cmd(c, op::VIEWPORT, &[p.u32(c, 1)?, p.u32(c, 2)?, p.u32(c, 3)?, p.u32(c, 4)?], &[]),
|
||||
Hot::TexParameteri => cmd(c, op::TEX_PARAMETER_I, &[p.u32(c, 1)?, p.u32(c, 2)?, p.u32(c, 3)?], &[]),
|
||||
Hot::Uniform1f => cmd(c, op::UNIFORM_1F, &[p.u32(c, 1)?, p.u32(c, 2)?], &[]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2569,6 +2586,11 @@ mod tests {
|
||||
("FN_glBindTexture", "OP_BIND_TEXTURE", "glBindTexture", op::BIND_TEXTURE),
|
||||
("FN_glUniform1i", "OP_UNIFORM_1I", "glUniform1i", op::UNIFORM_1I),
|
||||
("FN_glUniform2f", "OP_UNIFORM_2F", "glUniform2f", op::UNIFORM_2F),
|
||||
("FN_glBlendFunc", "OP_BLEND_FUNC", "glBlendFunc", op::BLEND_FUNC),
|
||||
("FN_glBlendFuncSeparate", "OP_BLEND_FUNC_SEPARATE", "glBlendFuncSeparate", op::BLEND_FUNC_SEPARATE),
|
||||
("FN_glViewport", "OP_VIEWPORT", "glViewport", op::VIEWPORT),
|
||||
("FN_glTexParameteri", "OP_TEX_PARAMETER_I", "glTexParameteri", op::TEX_PARAMETER_I),
|
||||
("FN_glUniform1f", "OP_UNIFORM_1F", "glUniform1f", op::UNIFORM_1F),
|
||||
] {
|
||||
let code = def(f) as usize;
|
||||
assert_eq!(table::FUNCS[code].0, name, "{f}");
|
||||
@@ -2577,7 +2599,7 @@ mod tests {
|
||||
assert!(hot(code as u32).is_some(), "{name} is not a hot call here");
|
||||
}
|
||||
// i386 params: the TEB pointer, then 4-byte fields.
|
||||
for sig in ["pi", "pii", "piff"] {
|
||||
for sig in ["pi", "pii", "piff", "piiii", "pf", "pif"] {
|
||||
let offs = layout(sig, Abi::P32);
|
||||
for (i, o) in offs[..sig.len()].iter().enumerate() {
|
||||
assert_eq!(*o, 4 * i as u64, "{sig}");
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+36
-3
@@ -1,7 +1,8 @@
|
||||
/* The GL calls the unix-call dispatcher's provider writes into the command
|
||||
* ring itself (gex-cgen/providers/nt_unixcall.c): glEnable, glDisable,
|
||||
* glActiveTexture, glUseProgram, glBindTexture, glUniform1i, glUniform2f,
|
||||
* glEnableClientState, glDisableClientState (which also leave the arrays'
|
||||
* glBlendFunc, glBlendFuncSeparate, glViewport, glTexParameteri,
|
||||
* glUniform1f, glEnableClientState, glDisableClientState (which also leave the arrays'
|
||||
* flags where the layer reads them before a draw: client-memory arrays are
|
||||
* uploaded only when the layer sees them enabled).
|
||||
* Each is checked by a query (which the NT layer answers after a submit),
|
||||
@@ -33,6 +34,8 @@ PROC(void, glUseProgram, (GLuint))
|
||||
PROC(GLint, glGetUniformLocation, (GLuint, const char *))
|
||||
PROC(void, glUniform1i, (GLint, GLint))
|
||||
PROC(void, glUniform2f, (GLint, float, float))
|
||||
PROC(void, glUniform1f, (GLint, float))
|
||||
PROC(void, glBlendFuncSeparate, (GLenum, GLenum, GLenum, GLenum))
|
||||
PROC(void, glGetUniformfv, (GLuint, GLint, float *))
|
||||
PROC(void, glGetUniformiv, (GLuint, GLint, GLint *))
|
||||
PROC(void, glClientActiveTexture, (GLenum))
|
||||
@@ -68,7 +71,7 @@ int main(void) {
|
||||
|
||||
LOAD(glActiveTexture); LOAD(glCreateShader); LOAD(glShaderSource); LOAD(glCompileShader);
|
||||
LOAD(glCreateProgram); LOAD(glAttachShader); LOAD(glLinkProgram); LOAD(glUseProgram);
|
||||
LOAD(glGetUniformLocation); LOAD(glUniform1i); LOAD(glUniform2f); LOAD(glGetUniformfv); LOAD(glGetUniformiv);
|
||||
LOAD(glGetUniformLocation); LOAD(glUniform1i); LOAD(glUniform2f); LOAD(glUniform1f); LOAD(glBlendFuncSeparate); LOAD(glGetUniformfv); LOAD(glGetUniformiv);
|
||||
LOAD(glClientActiveTexture);
|
||||
CHECK("GL 2.0 entry points", pglActiveTexture && pglUseProgram && pglUniform2f);
|
||||
if (!pglActiveTexture || !pglUseProgram || !pglUniform2f) return 1;
|
||||
@@ -80,7 +83,7 @@ int main(void) {
|
||||
pglActiveTexture(GL_TEXTURE0);
|
||||
|
||||
const char *vs = "#version 110\nvoid main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }";
|
||||
const char *fs = "#version 110\nuniform vec2 off; uniform int k; void main() { gl_FragColor = vec4(off, float(k), 1.0); }";
|
||||
const char *fs = "#version 110\nuniform vec2 off; uniform int k; uniform float a; void main() { gl_FragColor = vec4(off, float(k), a); }";
|
||||
GLuint v = pglCreateShader(0x8B31), fr = pglCreateShader(0x8B30), prog = pglCreateProgram();
|
||||
pglShaderSource(v, 1, &vs, 0);
|
||||
pglShaderSource(fr, 1, &fs, 0);
|
||||
@@ -104,6 +107,36 @@ int main(void) {
|
||||
pglGetUniformiv(prog, s, &iv);
|
||||
CHECK("glUniform2f", fv[0] == 0.25f && fv[1] == -1.5f);
|
||||
CHECK("glUniform1i", iv == 5);
|
||||
if (pglUniform1f) {
|
||||
GLint a = pglGetUniformLocation(prog, "a");
|
||||
float av = 0;
|
||||
pglUniform1f(a, 0.75f);
|
||||
pglGetUniformfv(prog, a, &av);
|
||||
CHECK("glUniform1f", av == 0.75f);
|
||||
}
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLint bs = 0, bd = 0;
|
||||
glGetIntegerv(GL_BLEND_SRC, &bs);
|
||||
glGetIntegerv(GL_BLEND_DST, &bd);
|
||||
CHECK("glBlendFunc", bs == GL_SRC_ALPHA && bd == GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (pglBlendFuncSeparate) {
|
||||
GLint v4[4] = {0, 0, 0, 0};
|
||||
pglBlendFuncSeparate(GL_ONE, GL_ZERO, GL_DST_ALPHA, GL_ONE);
|
||||
glGetIntegerv(0x80C9, &v4[0]); /* GL_BLEND_SRC_RGB */
|
||||
glGetIntegerv(0x80C8, &v4[1]); /* GL_BLEND_DST_RGB */
|
||||
glGetIntegerv(0x80CB, &v4[2]); /* GL_BLEND_SRC_ALPHA */
|
||||
glGetIntegerv(0x80CA, &v4[3]); /* GL_BLEND_DST_ALPHA */
|
||||
CHECK("glBlendFuncSeparate", v4[0] == GL_ONE && v4[1] == GL_ZERO && v4[2] == GL_DST_ALPHA && v4[3] == GL_ONE);
|
||||
}
|
||||
glViewport(3, 5, 40, 30);
|
||||
GLint vp[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
CHECK("glViewport", vp[0] == 3 && vp[1] == 5 && vp[2] == 40 && vp[3] == 30);
|
||||
glBindTexture(GL_TEXTURE_2D, tex[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
GLint mf = 0;
|
||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &mf);
|
||||
CHECK("glTexParameteri", mf == GL_NEAREST);
|
||||
|
||||
/* Two million fast calls (some 26 MB of commands: the ring fills and is
|
||||
* submitted three times), with layer-encoded calls among them, ending in
|
||||
|
||||
Reference in new issue
Block a user