feat(3d): gl1 shim M3+M5 — display-list recorder, client arrays, VBO routing; 44/47 under parity floor

- display lists: literal command replay through the shim state machine
  (state leaks + between-list material changes get GL semantics for free);
  recorded glDrawArrays EAGERLY snapshots enabled client-memory arrays at
  compile time (the renderer frees them right after glEndList) and records
  buffer+offset for VBO-backed pointers
- client-array draws: shared AttribSource path packs client-memory arrays
  into one scratch-VBO upload and binds user VBOs with original offsets
  (GL_BYTE normals / GL_UNSIGNED_BYTE colors normalized per GL1)
- glDrawElements over user VBO/IBO passes indices through untouched
  (ELEMENT_ARRAY_BUFFER never touched by the shim)
- state mutators (enable/bindTexture/blendFunc/lineWidth/alphaFunc) shared
  between the __wrap interceptors and list replay

Parity: 44/47 under the 0.02 floor (was 20). Verified visually: mini-board
Tier-3 composite (mask translucency + stencil-punched TH holes), stencil
hole subtraction, alpha-tested seg-end discs, COMBINE const-alpha model
transparency, and post-machining reproducing the upstream countersink bug
(walls absent, matching the native golden). Remaining 3: camera-* trio
needing the M4 GLU quadrics (+5 small-geometry false-greens they share).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Istvan Matejcsok 2026-07-03 11:48:22 +02:00
commit 3fe4f6fb00
6 changed files with 565 additions and 87 deletions

View file

@ -209,6 +209,35 @@ bool* ffpCapSlot( GLenum cap );
// Marks the state blocks a cap flip invalidates.
void onCapChanged( GLenum cap );
// Immediate-execution state mutators shared by the __wrap_* interceptors and
// display-list replay (identical semantics, minus the recording check).
void stateEnable( GLenum cap, bool enable );
void stateBindTexture( GLenum target, GLuint texture );
void stateBlendFunc( GLenum sfactor, GLenum dfactor );
void stateLineWidth( GLfloat width );
void stateAlphaFunc( GLenum func, GLclampf ref );
// GL1 normalized-attribute rule: integer colors and normals are normalized,
// floats are not (positions/texcoords are float-only in this codebase).
bool attribNormalized( int arrayIndex, GLenum type );
// Effective byte stride of a client array (GL stride 0 = tightly packed).
GLsizei attribEffectiveStride( GLint size, GLenum type, GLsizei stride );
// One vertex attribute's data source for an array draw: either client memory
// to be uploaded (cpuData) or a byte offset into a user VBO (buffer/offset).
struct AttribSource
{
bool enabled = false;
GLint size = 4;
GLenum type = GL_FLOAT;
bool normalized = false;
GLsizei stride = 0; // effective byte stride, never 0
const void* cpuData = nullptr;
GLuint buffer = 0;
GLintptr offset = 0;
};
// --- matrix module (gl1_matrix.cpp) ---
void matrixLoadIdentity();
void matrixLoadf( const GLfloat* m );
@ -231,7 +260,10 @@ bool immActive();
// Uploads `count` interleaved ImmVertex records to the streaming VBO and draws
// them with the FFP program. `mode` must already be a WebGL2-legal primitive.
void drawImmVertices( GLenum mode, const ImmVertex* verts, GLsizei count );
// Routed glDrawArrays/glDrawElements over FFP client-array state (M3/M5).
// Non-indexed draw over explicit per-attribute sources (client arrays,
// display-list snapshots). Sources are pre-rebased: vertex 0 = first vertex.
void drawArraysWithSources( GLenum mode, GLsizei count, const AttribSource aSrc[CA_COUNT] );
// Routed glDrawArrays/glDrawElements over FFP client-array state.
void drawClientArrays( GLenum mode, GLint first, GLsizei count );
void drawClientElements( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices );