← 返回首页
auto-replace buffers by kushalkolar · Pull Request #974 · fastplotlib/fastplotlib · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

auto-replace buffers#974

Merged
kushalkolar merged 45 commits into
ndwidgetfrom
replaceable-buffers
Feb 4, 2026
Merged

auto-replace buffers#974
kushalkolar merged 45 commits into
ndwidgetfrom
replaceable-buffers

Conversation

kushalkolar commented Jan 13, 2026
edited
Loading

Copy link
Copy Markdown
Member

closes #869

Replace buffers when the user sets all the data with a new array that has a different number of positions (vertices) pr a different set of dimensions (images) than the existing buffer. Example, user sets all line or scatter data, line.data = <bigger or smaller array>.

Implemented in all BufferManager subclasses, and the image TextureArrays

  • VertexPositions
  • VertexColors
  • VertexRotations
  • VertexPointSizes
  • VertexMarkers
  • MeshIndices, gets it automatically from parent class VertexPositions
  • images and volumes - create an entirely new TextureArray if setting all the data with a new image that has different dims
  • removes isolated_buffer, OOC rendering is the better way to handle very large data
  • add color_mode property for positions graphics, will do marker_mode, size_mode, edge_color_mode in a future PR for scatters.
  • test deferencing
  • test garbage collection

Slicing and setting data, i.e. graphic.data[<slice>] = <array> is unchanged. New buffers are created only when the entire data is set with new data that needs a bigger or smaller buffer.

Copy link
Copy Markdown
Member Author

OK I got the basics down for lines. One caveat is that now there's no check to make sure that the buffer sizes match for data and colors for example.

Consider this:

lg = subplot.add_line(np.random.rand(100)) lg.data = np.random.rand(200)

Now the last 100 line points are just black since they're not defined. A user has to explicitly set the colors of the new vertices that extend beyond the previously defined buffer.

lg.colors = ["w"] * 200

Or they can use a uniform color for things like this.

kushalkolar commented Jan 13, 2026
edited
Loading

Copy link
Copy Markdown
Member Author

ok for images I think easiest way is to create new world objects 🤔

EDIT: Yup this will be fine, I was initially worried that we'd have to re-add event handlers if we create a new world object, but I don't think that's necessary since ImageGraphic and ImageVolumeGraphic use a pygfx.Group as the world object, so we can just clear the group and add new image tiles.

EDIT again: Just tested with image click events, if an event handler is added to the graphic then when new tiles are created the graphic is still responsive to those events because it's the pygfx.Group that is handling the events and not the individual image tiles.

kushalkolar marked this pull request as ready for review January 13, 2026 07:27
kushalkolar requested a review from clewis7 as a code owner January 13, 2026 07:27

Copy link
Copy Markdown
Member Author

@clewis7 would like to get your review before I do the gc tests

github-actions Bot commented Jan 13, 2026
edited
Loading

Copy link
Copy Markdown

📚 Docs preview built and uploaded! https://www.fastplotlib.org/ver/replaceable-buffers

Copy link
Copy Markdown
Member Author

I think we should make uniforms the default for all graphics 🤔.

Also good time to start a "performance tips" section of the docs. Replacing the buffer has a huge performance hit so you don't want do it all the time.

kushalkolar commented Jan 13, 2026
edited
Loading

Copy link
Copy Markdown
Member Author

I found a memory leak, if old_buffer._wgpu_object.destroy() is not called then it lingers on in GPU VRAM even if the Binding object no longer exists.

Posted on pygfx: pygfx/pygfx#1264

For now I implemented manually destroying the GPUBuffer when it's replaced.

kushalkolar commented Jan 14, 2026
edited
Loading

Copy link
Copy Markdown
Member Author

@clewis7 what do you think about:

For lines, default is:
uniform_colors = True

For scatters, default is:
uniform_colors = False

I think independent scatter colors is a more common usecase than lines. We can auto-determine it in the future based on the colors and cmap arg but I'll do that in the future.

EDIT: But then the API is inconsistent between lines and scatters :/

clewis7 commented Jan 14, 2026

Copy link
Copy Markdown
Member

OK I got the basics down for lines. One caveat is that now there's no check to make sure that the buffer sizes match for data and colors for example.

Consider this:

lg = subplot.add_line(np.random.rand(100)) lg.data = np.random.rand(200)

Now the last 100 line points are just black since they're not defined. A user has to explicitly set the colors of the new vertices that extend beyond the previously defined buffer.

lg.colors = ["w"] * 200

Or they can use a uniform color for things like this.

I think this behavior is confusing. Perhaps it is better to just by default take the current color scheme and extend it to the new or fewer points.

clewis7 commented Jan 14, 2026

Copy link
Copy Markdown
Member

@clewis7 what do you think about:

For lines, default is: uniform_colors = True

For scatters, default is: uniform_colors = False

I think independent scatter colors is a more common usecase than lines. We can auto-determine it in the future based on the colors and cmap arg but I'll do that in the future.

EDIT: But then the API is inconsistent between lines and scatters :/

Hmmm, I do agree that scatters are more likley to have individual colors. How much a performance reduction is it if you make the lines also have uniform_buffer=True as the default??

kushalkolar mentioned this pull request Jan 30, 2026
21 tasks

Copy link
Copy Markdown
Member Author

Maybe we can do an auto mode 🤔
And have it change dynamically too when the colors feature is modified.

Copy link
Copy Markdown
Member Author

Got "auto" color mode working for lines and scatter, and can switch between vertex and uniform modes and the corresponding buffers are auto created and the previous one removed. Need to test that garbage collection works when switching from vertex -> uniform.

I think I'm going to just implement this for colors for now. Will do scatter-specific markers, edge colors, and sizes later since I think expanding the data buffers isn't going to be too common. And when the user does expand the data buffer, they should also be aware that they should set the scatter point markers and other properties for the new points anyways. I'll work on on tests, testing this properly, make sure garbage collection works and then we merge because I need this for #971 . Dynamic display_windows require auto-replaceable buffers.

12 hidden items Load more…

kushalkolar commented Feb 4, 2026
edited
Loading

Copy link
Copy Markdown
Member Author

OK so there's an issue with scatters (even with the "simple" mode that doesn't use markers or edge_colors) where I get a wgpu bind group error 😭 . The resource has been destroyed, so this manual destroying can cause issues. Will post to pygfx and figure out.

EDIT: ok seems like the dereferencing is clearing GPU VRAM, I guess it does it eventually, not sure what's up with pygfx/pygfx#1264 (comment)

Line and images seem to work, kept this running for 20 mins and it's still going.

image-replace-2026-02-03_20.04.24.mp4 line-replace-2026-02-03_20.04.53.mp4

Also watching nvidia-smi to see that there's no VRAM leak, after 20 mins no memory leak, goes up and back down as expected 😄

nvidia-smi-2026-02-03_20.27.19.mp4

Copy link
Copy Markdown
Member Author

I think I might be able to get rid of the bindgroup issues with scatter by destroying the old buffer after we set the new buffer, instead of right now where it destroys first and then sets the new buffer.

kushalkolar commented Feb 4, 2026
edited
Loading

Copy link
Copy Markdown
Member Author

ok interesting, without wgpu_obj.destroy(), seems like it's working for this example, but not the testing UI I made to check buffer gc 🤷‍♂️

no_destroy-2026-02-03_21.29.02.mp4

Copy link
Copy Markdown
Member Author

I think tests should pass now! 😄

@clewis7 I'm guessing you won't be able to review today so I will merge this into #971 , let me know if you have any objections XD . You can review it later as part of #971

clewis7 commented Feb 4, 2026

Copy link
Copy Markdown
Member

I think tests should pass now! 😄

@clewis7 I'm guessing you won't be able to review today so I will merge this into #971 , let me know if you have any objections XD . You can review it later as part of #971

No objections, can review later :D

kushalkolar changed the base branch from main to ndwidget February 4, 2026 16:55
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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a new buffer if necessary when setting an existing Graphic

2 participants

Footer

© 2026 GitHub, Inc.