Bug when creating multiple render windows with VTK and WSLink

I believe there is a bug regarding the the way the IDs for render windows are SET and then being GET.

When I set a new VIEW (Render Window) using:
self.getApplication().GetObjectIdMap().SetActiveObject( "1", my_render_window)

I am using the function on the C++ side:
vtkTypeUInt32 vtkObjectIdMap::SetActiveObject(const char* objectType, vtkObject* obj)

which like the signature says it allows for a const char* type, meaning that it does not have to be a integer. And this is the way the example is showed using “VIEW” as the id.

But then if one wants to create more than 1 render window using for example something like uuid to generate ids for the views it stops working because the GET is wrong in multiple places (imo).

First place that it’s broken:

def getView(self, vid):
        """
        Returns the view for a given view ID, if vid is None then return the
        current active view.
        :param vid: The view ID
        :type vid: str
        """
        v = self.mapIdToObject(vid)

        if not v:
            # Use active view is none provided.
            v = self.getApplication().GetObjectIdMap().GetActiveObject("VIEW")
        if not v:
            raise Exception("no view provided: %s" % vid)

        return v

as one can see the v is mapped by using mapIdToObject which then casts the id to an int to pass it to ...getVTKObject(id) which is not the same way it’s being saved in the first place:
SetActiveObject should imply a GetActiveObject and not GetVTKObject .

def mapIdToObject(self, id):
        """
        Maps global-id for a vtkObject to the vtkObject instance. May return None if the
        id is not valid.
        """
        id = int(id)
        if id <= 0:
            return None
        return self.getApplication().GetObjectIdMap().GetVTKObject(id)

This is the first place that it’s not right because it allows the creation of multiple windows with a string id but then on the get side casts the ids to integers and uses a different function to get the views.

But then if one for example changes mapIdObject to GetActiveObject instead another problem follows when asking for view updates.

In many places of the vtkWebPublishImageDelivery protocol there is a call to request the VTK Global Id like so:

@exportRpc("viewport.image.push")
def imagePush(self, options):
    sView = self.getView(options["view"])
    realViewId = str(self.getGlobalId(sView))
    # Make sure an image is pushed
    self.getApplication().InvalidateCache(sView)
    self.pushRender(realViewId)

This asks the pushRender function to push the realViewId and then “ignores” the id that was set earlier creating a mismatch if the ids are not integers and created sequentially.

I am hoping I am not seeing this correctly and that there is a nicer way to create multiple render windows but this is as far as my investigation as reached.

Any answers to this?

From a quick browse of what you are saying, you may have found a bug. Would you mind submitting a PR that fix it ?

fyi @Sebastien_Jourdain

It is not a bug, just a bad usage from your side.

Active objects can only be “VIEW”, “SOURCE”, “REPRESENTATION” and what ever else category you see fit. The concept of active is that you can only have one object at a time in a given category.

So by default we use ID=“-1” for a view which perform the lookup of the actual ID of the registered active view. (That way you don’t need to know the id before hand).

If you don’t want to be limited with the number of view, you just need to provide all the view ids correctly and obviously not relying on any “Active” part of the API.

HTH

Hi Sebastien, so if I want multiple views being streamed at the same time how do I set their ids?

The thing is I could use getGlobalId to set the correct ID for a view but then if I create views:
1 - 2 - 3 - 4
and I delete view 2, when I call render it will complain about missing view 2

Well, you need to remove the view 2 from the ones you want to render. The JS side should make that call when the component get unmounted.

I was using the server VTK to handle views calling freeObject on the server end. Do I need to call the protocol “viewport.image.push.enabled” or “removeRenderObserver” or something like that?
Not sure how to do state management to handle this cleanly.

The protocol keep track of view usage on the client side, so if the protocol still think that a view should be rendered but get destroyed on the side, when an update comes, it will try to render it.

We could probably auto detect that issue at the protocol level, but that was not implemented in that fashion.

You can see that logic here.

Would you also use the frontend api to add actors to views and change properties on those actors?
I manage all of those in the python side, I still use rpc calls but I use my custom ones.
As you said to manage the creation and deletion from the frontend, would you use that viewId to then manage things on the server or is there a simpler solution?
Thank you btw for your time in replying, it’s helping a lot.

Yes using RPC for that make sense and indeed providing the viewId would help the python to lookup the actual renderWindow.

I still don’t fully understand how do I attach a render_window in the server to a client viewStream.

Will I still have 2 different IDs? On for the viewStream and another for the server RenderWindow?

const session = client.getConnection().getSession();
const imageStream = vtkImageStream.newInstance();
imageStream.connect(session);
const viewStream = imageStream.createViewStream(viewId);

Do I need an imageStream for every viewStream or one per session?

Here I am creating the viewStream with an ID created by a library. But then how do I attach my server render window to it?

Should I create the render window first, call getGlobalID(render_window) and then use that to create the viewStream?

You only need 1 imageStream per session, but you will create 1 viewStream per vtkRenderWindow.

Yes, you do need to get the id from getGlobalID(render_window) to create its corresponding viewStream.

1 Like