Skip to content

fix(gl): derive the GL index type from sizeof(ofIndexType) in indexed draws - #8526

Open
smeyfroi wants to merge 1 commit into
openframeworks:masterfrom
smeyfroi:fix/gl-index-type-16bit-ofindextype
Open

fix(gl): derive the GL index type from sizeof(ofIndexType) in indexed draws#8526
smeyfroi wants to merge 1 commit into
openframeworks:masterfrom
smeyfroi:fix/gl-index-type-16bit-ofindextype

Conversation

@smeyfroi

@smeyfroi smeyfroi commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

On current macOS nightlies (verified against of_v20260730, macOS 26 / Apple silicon), every indexed VBO draw silently reads the index buffer with the wrong GL type, and instanced indexed draws (ofVbo::drawElementsInstanced) render garbage triangles or nothing at all, varying non-deterministically between launches and even between relinks of the same code.

Cause

ofIndexType is typedef TESSindex ofIndexType (ofConstants.h), and the tess2 header shipped since apothecary #552 picks its width with #if defined(TARGET_OS_IPHONE) || …. Apple's TargetConditionals.h defines every TARGET_OS_* macro on every Apple platform — as 1 or 0 — so on macOS TARGET_OS_IPHONE is defined as 0, the defined() test is true, and TESSindex/ofIndexType becomes unsigned short. (Apothecary #558 later noticed Apple builds landing in the 16-bit branch, but guarded only the __arm__-family defines, which aren't defined on Apple arm64 — the actual trigger survived.)

Meanwhile the desktop branches of drawElements / drawElementsInstanced in both renderers hardcode GL_UNSIGNED_INT. ofVbo uploads sizeof(ofIndexType) × count bytes, so the draw reads 2× past the uploaded index buffer: the first indices are misparsed short-pairs (out of range of the mesh), the rest are whatever follows in GPU memory — out-of-range vertex fetches that render as giant garbage triangles or degenerate/invisible ones depending on heap layout. No GL error is raised.

Fix

Derive the GL index type from the compiled index width at the five desktop call sites:

sizeof(ofIndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT

The ternary constant-folds, so there is no runtime cost, and the sites remain correct whatever width tess2 ends up giving ofIndexType. The GLES branches are untouched: every GLES platform lands in tess2's 16-bit branch, so their hardcoded GL_UNSIGNED_SHORT already matches.

A companion apothecary PR fixes the root-cause condition in tess2.patch itself: openframeworks/apothecary#561. Both fixes stand alone; this one keeps the renderers honest under either header, and the apothecary one also restores the full 32-bit index range for large meshes on macOS.

Verification

  • Reproduced on macOS 26 / Apple silicon with an instanced line renderer: 16-bit uploads (12-byte index buffer for a 6-index quad, confirmed via GL_BUFFER_SIZE) drawn with GL_UNSIGNED_INT produce garbage or missing geometry, flipping between relinks.
  • With this patch, disassembly of both Release build systems (Xcode and makefile) shows the draw sites passing GL_UNSIGNED_SHORT (0x1403), matching the uploads; the renderer output is correct and stable across relinks.
  • The pre-CRITICAL FIX: ios touch positions are in the wrong place when in landscape #552 tree (of_v20251123, 32-bit ofIndexType) is unaffected by the patch: the ternary folds to GL_UNSIGNED_INT there.

… draws

ofIndexType is tess2's TESSindex, and tesselator.h picks unsigned short
whenever TARGET_OS_IPHONE is defined() — TargetConditionals.h defines it
(as 0) on every Apple platform, so macOS builds get 16-bit indices when
any Apple header precedes tesselator.h. The desktop branches of
drawElements / drawElementsInstanced in both renderers hardcode
GL_UNSIGNED_INT, so ofVbo uploads sizeof(ofIndexType)-sized indices and
the draw reads twice as many bytes: out-of-range vertex fetches that
render as garbage triangles or nothing at all, varying with GPU heap
layout (non-deterministic across relinks and runs).

Derive the type from sizeof(ofIndexType) at the five desktop call sites
(the ES branches already match: every GLES platform lands in tess2's
16-bit branch). The ternary constant-folds; no runtime cost.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant