You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
LEGACY_GL_EMULATION: 4-component texture coordinates ignore q — no projective divide in generated samplers #27947
emcc 6.0.12; verified present on main (src/lib/libglemu.js, genTexUnitSampleExpr). Flags: -sLEGACY_GL_EMULATION.
Summary
Fixed-function OpenGL interpolates all four texture coordinates per fragment and samples at s/q, t/q. Supplying homogeneous coordinates — glTexCoord4f(s*q, t*q, 0, q) or glTexCoordPointer(4, ...) with q = 1/w — is the canonical GL 1.x technique for perspective-correct texturing, and real fixed-function games rely on it.
This is exactly equivalent to the current .xy when q == 1 — which is what the attribute's default w component yields for size-2/3 client arrays and glTexCoord2f — and correct otherwise, so it is safe to emit unconditionally. When a texture matrix is active the divide must use the post-matrix w (the expression above already does, since coord is the matrix-transformed vector). This is the patch we ship in production.
I imagine there should be a way to detect per-draw how many components the texture coordinates have, and then call texture2DProj() if 4, and texture2D() otherwise?
How complex would such runtime detection be?
If that is complex to implement, then happy to land code that does the unconditional texture2DProj(), with a note reminding // N.b. if projective texture sampling shows up as a performance bottleneck, consider optimizing via texture2D() when texture coordinates have at most three components. or something along those lines.
Runtime detection turned out to be modest, with one catch: the component count alone isn't enough. A texture matrix whose last row isn't (0,0,0,1) also makes q != 1 with 2-component coordinates. In #28063 each draw works out which units need q: a 4-component texcoord array, or a projective texture-matrix last row. That goes into the renderer key and is re-checked per draw, since a matrix change alone doesn't trigger a renderer lookup. Only those units use texture2DProj; everything else keeps texture2D. The test covers a matrix-only change between two draws and 4-component perspective coordinates. Both fail before the change and pass after it on Chrome/ANGLE Metal and SwiftShader. If you'd rather have the simpler unconditional texture2DProj with your performance note, it's a one-line change and I'm happy to switch.
Side finding, not fixed: fixed-function textureCube gets a .xy coordinate, which isn't valid GLSL.
Activity
juj commentedon Oct 14, 2026
I imagine there should be a way to detect per-draw how many components the texture coordinates have, and then call texture2DProj() if 4, and texture2D() otherwise?
How complex would such runtime detection be?
If that is complex to implement, then happy to land code that does the unconditional texture2DProj(), with a note reminding
// N.b. if projective texture sampling shows up as a performance bottleneck, consider optimizing via texture2D() when texture coordinates have at most three components.or something along those lines.TheTomBritton commentedon Oct 23, 2026
Runtime detection turned out to be modest, with one catch: the component count alone isn't enough. A texture matrix whose last row isn't (0,0,0,1) also makes q != 1 with 2-component coordinates. In #28063 each draw works out which units need q: a 4-component texcoord array, or a projective texture-matrix last row. That goes into the renderer key and is re-checked per draw, since a matrix change alone doesn't trigger a renderer lookup. Only those units use texture2DProj; everything else keeps texture2D. The test covers a matrix-only change between two draws and 4-component perspective coordinates. Both fail before the change and pass after it on Chrome/ANGLE Metal and SwiftShader. If you'd rather have the simpler unconditional texture2DProj with your performance note, it's a one-line change and I'm happy to switch.
Side finding, not fixed: fixed-function
textureCubegets a.xycoordinate, which isn't valid GLSL.