Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SurfacePlotVisual.set_data cause vertex shader to perform unnecessary build #2568

Open
Akalivivy opened this issue Jan 15, 2024 · 3 comments

Comments

@Akalivivy
Copy link

Akalivivy commented Jan 15, 2024

when I try to use scene.visuals.SurfacePlot.set_data with an app.Timer to get some animation effects,then I found that the CPU usage was very high.My core code like :

     # some init code in my class
     empty_data = np.zeros((13, 14))
     z = gaussian_filter(empty_data, (10, 10))
     self.plot = scene.visuals.SurfacePlot(z=empty_data)
     no_colors = np.ones((13, 14, 3))
     self.plot.set_data(z=empty_data, colors=no_colors)
     self.view.add(self.plot)
    # timer
     self.timer = app.Timer('auto', self.on_timer)
     self.timer.start(1/60)
    
    # the core update function
    def on_timer(self,event):
        print("on timer begin update")
        colors = np.zeros((13, 14, 3))
        shape = (13,14)  
        visualize_data = 3*np.random.rand(*shape)
        self.plot.set_data(z=visualize_data, colors=colors)
        print("on timer update have completed")


Then I traced the call process of the function from the source code,I found when the Superclass of SurfacePlotVisual,MeshVisual,calls the following code cause the vertex shader rebuild:
self.shared_program.vert['color_transform'] = self._build_color_transform(colors)
the line of mesh.py source code here:mesh.py

fun = Function(null_color_transform) (build_color_transform) in the function _build_color_transform create new Function object,when it call __setitem__ in the class Function function.py,the self.changed check process think both code_changed and value_changed,In the subsequent process, shared_program (shader) will be affected by the code_changed and believed that it need build(program.py),though the code for vertex shaders has not actually changed(the default text of null_color_transform:null_color_transform ).

So,it seems like once I use the SurfacePlotVisual.set_data, it cause vertex shader build.But I just hope to use set_data to replace the visual data during the loop process, but I cannot avoid rebuilding the shader.Could someone help me or had a similar experience?

@djhoese
Copy link
Member

djhoese commented Jan 16, 2024

I agree. I think you're correct. I think this visual has not been optimized for this color logic which is surprising. I think @brisvag or maybe @tlambert03 did some work on the ImageVisual (

if self._need_colortransform_update:
prg = view.view_program
self.shared_program.frag['color_transform'] = self._build_color_transform()
self._need_colortransform_update = False
prg['texture2D_LUT'] = self.cmap.texture_lut()
) to optimize when and how the color transform function is created and updated. I think the MeshVisual may need a similar update and extra care added to it.

I think the original intention of the code or the idea behind it was that if you change the data then the colors array will also change (I'm not sure this is always necessary either). Since colors is an input to the color transform creation it would make sense to assume that the color transform also always has to be updated. But you're right, when you look at it it clearly doesn't.

First, it would need to be updated so the function objects only get created once. I don't think there is a reason this shouldn't work. Next, it should be updated so if we already have a color transform but we are updating only the color limits, then just update the color limits. I think mocking this after the ImageVisual wouldn't be a terrible idea. This would mean something like a self._update_color_transform = True and maybe a self._update_color_limits = True. You can see in the ImageVisual that it even cheats and sets the color limits early if the color transform doesn't need to be updated:

def _update_colortransform_clim(self):
if self._need_colortransform_update:
# we are going to rebuild anyway so just do it later
return
try:
norm_clims = self._texture.clim_normalized
except RuntimeError:
return
else:
# shortcut so we don't have to rebuild the whole color transform
self.shared_program.frag['color_transform'][1]['clim'] = norm_clims

@brisvag
Copy link
Collaborator

brisvag commented Jan 16, 2024

Yup, agree with the above! I don't have the bandwidth now to do with this, but if anyone wants to open a PR with this I'd be happy to review.

@Akalivivy
Copy link
Author

@djhoese Thank you for your answer. In meshvisual, it is indeed necessary to use optimization logic similar to that already present in ImageVisual to avoid the repeated creation of function object。If I have time, I would be happy to try and contribute to the code.

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

No branches or pull requests

3 participants