pyglet 3.0.dev6 migration#2865
Open
pvcraven wants to merge 12 commits into
Open
Conversation
Add feature specification and quality checklist for migrating Arcade from pyglet 3.0.dev3 directly to 3.0.dev6. Key decisions captured via clarification: - Arcade fully owns its own matrix UBO, independent of pyglet's ring-buffer/frame-resource lifecycle (fixes unbounded UBO growth). - Hard-cut to exactly pyglet==3.0.dev6; no dev4 checkpoint, no dual paths. - Full suite/stress/image-comparison runs are gated in a separate GPU-capable environment; local WSL runs a targeted subset only. - Reference-image deviations are investigated before any re-baselining.
…ev6 compatibility
…s independently of pyglet
…ce and add reference-image comparison tests
…ix window state leakage in stress tests
…ntext state, preventing leakage and ensuring accurate rendering comparisons
…valid CameraScissor, preventing GL_SCISSOR_TEST from being disabled
…ks, dropping pixel-tolerance comparison due to CI discrepancies
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrate Arcade's pinned pyglet dependency directly from
3.0.dev3to3.0.dev6(nodev4intermediate). This is a hard cutover: pygletdev5+ removedwindow._matricesand restructured how window view/projection/viewport are stored, which broke Arcade's rendering pipeline in three distinct ways. All three are fixedhere, verified empirically against the real pyglet dev6 source and a full local test run on native Windows.
Background
Between pyglet
dev4anddev5, pyglet:window._matrices(and its.ubo) entirely.default_camera(pyglet.window.camera.camera2d.Camera2D), backed by a per-frame ring-buffer UBO.A naive version bump crashes immediately (
AttributeError: 'Window' object has no attribute '_matrices'), and would go on to cause unbounded UBO growth once pastthat, because Arcade drives its own render loop and doesn't participate in pyglet's frame-resource lifecycle.
What changed
1. Arcade now owns its window-block UBO directly (
arcade/context.py)ArcadeContextallocates a single fixed-size (128-byte) buffer in__init__instead of reusingwindow._matrices.ubo.projection_matrix/view_matrixsetterswrite straight into this buffer. This buffer's identity never changes for the lifetime of the context — no ring buffer, no reallocation, so growth is impossible by
construction rather than by careful bookkeeping.
OpenGLArcadeContext/WebGLArcadeContext.bind_window_block()(arcade/gl/backends/{opengl,webgl}/context.py) now bind this buffer via the existingBuffer.bind_to_uniform_block()method instead of readingself._window_block.buffer.idfrom pyglet.2. Camera write-path fix (
arcade/camera/{orthographic,perspective,camera_2d}.py)Found via failing camera unit tests, not anticipated in the original migration plan:
OrthographicProjector.use(),PerspectiveProjector.use(), and Arcade's ownCamera2D.use()were writing matrices throughself._window.projection = .../self._window.view = ...— i.e. through pyglet's window properties, not Arcade's.Under
dev3this was harmless (both paths pointed at the same underlying buffer). Underdev6, pyglet's properties write into its own ring buffer — a completelydifferent buffer from the one Arcade now owns — so camera changes silently never reached the GPU. Fixed by routing all three through
ctx.projection_matrix/ctx.view_matrixinstead, matching the patternDefaultProjectoralready used.3.
DefaultProjectorpyglet-compatibility shim (arcade/camera/default.py)Found via the example/tutorial integration tests: pyglet's own batch-draw pipeline (used internally by
pyglet.text.Label.draw(), whicharcade.Textdelegates to)falls back to
window.default_camerawhen no explicit camera is given. Since Arcade'sWindow.default_cameraproperty override intercepts every access to thatname, pyglet's fallback gets Arcade's
DefaultProjectorinstead of its ownCamera2D, and calls methods on it that only a real pyglet camera implements — crashingwith
AttributeError.Rather than reimplementing pyglet's internal camera/view-hierarchy protocol (which would tightly couple Arcade to pyglet internals — exactly what this fix is trying to
avoid),
DefaultProjectorgained a minimal duck-typing shim:.view→ returnsself.begin()→ no-op (preserve whatever camera state Arcade already has bound).get_group_scissor_area()→ alwaysNone.projection/.view_matrix(get/set) → thin aliases over existing stateThis also fixes
window.projection/window.view(pyglet's base properties, which delegate toself.default_camera.projection/.view_matrix) for any testinfrastructure or downstream code that reads them directly.
New test infrastructure
tests/unit/rendering/— a reference-image comparison harness (scenes.py,image_compare.py,generate_baseline.py,test_dev6_reference_images.py) with 4checked-in baseline PNGs captured on
dev3before the pin change. No such harness existed before this PR.tests/integration/test_ubo_stress.py— 100-cycle window/draw/close andctx.reset()stress tests asserting zero"Growing UniformBufferObject"warnings and astable buffer identity.
Testing performed
dev3baselinespytest tests/) on native Windows: 1283 passed, 10 failed/1 error — confirmed byte-identical to running the exact same suite against the untoucheddev3install on the same machine. These pre-existing failures (Windows DPI-scaling assumptions in one test, shared-global-window test-order flakiness in a fewothers, an unrelated encoding bug in a docstring checker) are unrelated to pyglet version and out of scope for this PR.
.github/workflows/test.yml(Linux + xvfb CI) is untouched — verified viagit diff.Breaking changes
pyglet==3.0.dev6(was3.0.dev3); no dual code paths,dev3/dev4no longer supported.window._matricesno longer exists (removed by pyglet). Advanced users mixing raw pyglet camera/window code with Arcade should notewindow.default_camerais now pyglet's ownCamera2D, distinct fromarcade.Window.default_camera(Arcade'sDefaultProjector) — both exist simultaneously andserve different roles. See
CHANGELOG.md.ArcadeContextproperties,Window.default_camera,get_image()/get_pixel()) — verified by the fulltest suite.
Test plan (for reviewers)
uv sync --no-group docsresolves and installs cleanlyuv run pytest tests/unit/camera tests/unit/window -v— all passuv run pytest tests/unit/rendering -v— all 4 reference-image comparisons passuv run pytest tests/integration/test_ubo_stress.py -v— both stress tests passuv run pytest tests/integration/examples tests/integration/tutorials -v— noAttributeErrorfromdefault_camera