Repository navigation
Conversation
`end_render_pass` bound the default framebuffer after every pass. Tile-based GPUs end a framebuffer's render pass whenever another one is bound: the driver submits the work so far, writes the tiles out to memory, and reads them back in when the framebuffer is next drawn to. macroquad begins and ends a pass for every batch it draws, so a frame drawn into a render target became one GPU render pass per batch. On a Pixel 6 (Mali-G78, OpenGL ES), a game that draws its frame into a 4× multisampled render target and then copies it to the screen ran at 23 to 40 fps, its render thread mostly submitting jobs from `glBindFramebuffer`. Without the rebind, it holds the display's 90 fps at 7 to 9 ms of CPU a frame. `begin_pass` binds the framebuffer it draws to, so passes draw where they did. Between passes, the bound framebuffer is now the last pass's rather than the default one, so code that reads the screen back with raw GL calls, such as macroquad's `grab_screen`, should bind the default framebuffer first. `commit_frame` binds it, so a frame still ends with it bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Why
end_render_passbinds the default framebuffer after every pass. On tile-based GPUs, binding another framebuffer ends the current one's render pass: the driver submits the work so far, writes the tiles out to memory, and reads them back in the next time that framebuffer is drawn to. macroquad begins and ends a pass for every batch, so a frame drawn into a render target becomes one GPU render pass per batch. This is the OpenGL side of what #641 did for Metal.On a Pixel 6 (Mali-G78, OpenGL ES), a macroquad game draws its frame into a 4× multisampled render target, then copies it to the screen. It ran at 26–37 fps, idle or moving, with every frame taking two refreshes. A CPU profile put its render thread in the driver's job submissions, called from
glBindFramebufferinend_render_pass. Drawing straight to the screen, which never switches framebuffers, ran at the display's 90 fps.Change
end_render_passleaves the pass's framebuffer bound.begin_passbinds the framebuffer it draws to, so every pass still draws where it did.commit_framebinds the default framebuffer, so a frame still ends with it bound.The Metal backend is unchanged.
Compatibility
Between passes, the bound framebuffer is now the last pass's rather than the default one. Drawing through miniquad doesn't notice. Raw GL calls made between passes that expect the screen do: reading the screen back with
glCopyTexImage2DorglReadPixelsafter a render-target pass reads that render target instead. To read the screen, callbegin_default_pass(PassAction::Nothing)andend_render_pass()first.In macroquad, that's
Texture2D::grab_screen, whichget_screen_dataand_ScreenTexturematerials use. not-fl3/macroquad#1071 binds the screen there first. It changes nothing with miniquad as released, so it can merge before this.Texture::read_pixelssaves and restores the binding, so it's unaffected.Verification
On the Pixel 6, with this change:
On macOS (OpenGL), the program from not-fl3/macroquad#1071 draws to the screen, then into a render target, then to the screen again, and reads both back. Both hold what was drawn to them, with and without this change.
The library and examples build, and
cargo checkpasses foraarch64-linux-androidandaarch64-apple-ios.🤖 Generated with Claude Code