CNA-GAP-029: EasyGL GPU timers read 32-bit nanosecond results and cannot detect GL disjoint events
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
EasyGLGpuTimerRenderer reads GL_TIME_ELAPSED as a 32-bit value because meta-gl exposes only glGetQueryObjectuiv, not a 64-bit query-object read, and it never queries GL_GPU_DISJOINT_EXT, so results saturate near 4.29 s and only an all-ones result is rejected as undefined.
- Identifier
CNA-GAP-029- Category
- Functional gap
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- CNA::Graphics::GpuTimer and RenderPipeline pass timings (CNAEXT) on the EasyGL GL profiles
Expected behaviour
GL_EXT_disjoint_timer_query results are read as 64-bit values and believed only after GL_GPU_DISJOINT_EXT reports no disjoint event.
Actual behaviour at TARGET
EasyGLGpuTimerRenderer::IsResultAvailable and ElapsedNanoseconds in EasyGLRenderer.cpp read the result with glGetQueryObjectuiv into a 32-bit value and reject only the all-ones saturation value. A reading taken across a disjoint event that is not exactly 0xFFFFFFFF is reported as a duration, and a real pass longer than about 4.29 s saturates. The in-code comments say meta-gl exposes only a 32-bit result read and no general glGetIntegerv, so the disjoint state cannot be asked. The first is true (meta-gl declares only glGetQueryObjectuiv). The second is not: meta-gl declares glGetIntegerv(GetParameter, GLint*) as a plain pass-through, and this same file already casts a raw value into metagl::QueryTarget for GL_TIME_ELAPSED, so GL_GPU_DISJOINT_EXT could be read the same way. That query exists only on the OpenGL ES path (GL_EXT_disjoint_timer_query); desktop GL 3.3 timers come from ARB_timer_query and WebGL reports no timer support.
Source locations
modules/renderers/easygl/src/EasyGLRenderer.cpp— EasyGLGpuTimerRenderer::IsResultAvailable and ElapsedNanosecondsmodules/graphics-ext/src/GpuTimer.cpp— the CNAEXT GpuTimer consumer
Evidence
Checked by reading at 009d40f5 and meta-gl develop @ 20c8b2dc in the local checkout (no ui64v read and no disjoint token in include/); not executed. The limitation is imposed by the sibling API; the pass durations the engine layer measures are far below the saturation point.
Independent re-verification: Checked by reading at 009d40f5 and meta-gl develop @ 20c8b2dc in the local checkout (no glGetQueryObjectui64v, no disjoint token, but a typed glGetIntegerv that forwards any value); meta-gl is an unpinned sibling, so its state at the moment of any given build is not fixed by the CNA commit. Not executed. The pass durations the engine layer measures are far below the saturation point.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
GpuTimerTests.cpp and PassTimingTests.cpp cover the timer contract; nothing injects a disjoint event.
Regression test
Once meta-gl exposes glGetQueryObjectui64v and GL_GPU_DISJOINT_EXT: a test that a disjoint flag invalidates the sample.
Blast radius
GPU pass timings on the EasyGL family only; the first sample after a context change is the known disjoint case. Rendering is unaffected.
Workaround
Treat outlying samples, especially the first after a context change, as invalid.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Internals
- EasyGL renderer internals
- Deep dives
- EasyGL and MetaGL: the MetaGL surface
- Known issues
- Functional gap index