Interaction between Handle Management and Handle Rendering
Handle Rendering -> Handle Management
As seen in the previous part, every DrawableObject has a pointer on the sciPointObj it displays. Since the rendering is totally based on the handle, the Rendering part almost always access to the Handle Management part. It normally uses the functions located in SetProperty.h and GetProperty.h but may also access the object directly.
Handle Management -> Handle Rendering
This interface is less straightforward since Handle Management is in C code and Handle Rendering is in C++. There are 4 gateways to access Handle Rendering part from the Handle Management one. All the functions located in the gateways have a sciPointObj as argument.
This file contains functions to retrieve properties from the Handle Rendering Part. For now there are three kinds of properties:
- Graphic window properties.
- Coordinates change.
- Axes ticks.
This is the counter part of GetProperty.h for setting the properties.
This files contains function which will request an interaction with the user, such as the zoom or the rotation.
This is the most important one since it contains functions used to force a handle display. Here is little list of the useful functions:
This function already existed in Scilab 4. The Scilab 5 behavior is similar, however it requests a display of the whole graphic window. Actually, it calls hasChanged on the object and force a display of the graphic window. Consequently all the graphic objects will be quickly drawn using show expect the drawn one.
Normally actions on the graphics from Scilab only modify one handle. In this case the code should be like this 1. modify the handle 2. call sciDrawObj on it. However in some cases some other handles are modified such as the parent subwindow. In this case this function must be called on the modified handles to ensure that the next display will call there draw function.
Specify that a handle has been moved and request a display of the graphic window.
Similar to forceRedraw, to be used only if several handles are moved in the same time.
Although the creation of DrawableObjects is automatic, its destruction still needed to be performed when the handle is destroyed.
This function is deprecated. This function should be used in combination with some pixel drawing mode (such as "xor" or "nor"). Normally, for each display the graphic canvas is cleared and then the whole graphic hierarchy is displayed on it. With this function, the canvas in not cleared and only one handle and its children are drawn above the canvas.
This function is similar to sciDrawSigleObj and is also deprecated. It allows to draw not one but several objects above the canvas.
Force all the handles located inside the same graphic canvas as the handle to be drawn during the next display. Should be called with caution, but needed for example when the colormap changes.
Force a draw on all the object located inside the same canvas as the handle.
Synchronization between the two parts
The to parts runs on two different threads. The handle management part is managed by Scilab and runs on the Scilab thread. The handle rendering is managed by JOGL and runs on the OpenGL thread (actually the AWT event dispatch thread). Since the two parts needs to access the graphic hiereachy, we need to use some synchronization to avoid simultaneous access to the data.
There are 3 kinds of actions which can be performed on the graphic hierarchy: reading, writing and display.
Access to the data only to retrieve some values (such as getting a property). Reading action can be performed even if there are others reading or display actions being carried out since they do not modify the hirerachy. However, if some writing actions are in execution, the access will wait until the writing is finished.
Access to the data in order to modify or create new values (such as modifying a property). Writing actions can only be performed if their are no other actions being carried out.
Access to the data in order to display them. This action is similar to the reading one, excepting the fact that there can be only one display action which cen be executed at a time. This limitation has been created in order to avoid simultaneous display calls send from JOGL. However, the JOGL architecture prevent simultaneous draw, and this action could probably been removed.
The synchronization is used on each Figure independantly to avoid locking to much data each time. However, there are some actions which need to lock the whole graphic hierachy. For example adding or removing a new figure will modify the figure table and then will impact the whole graphic.
Actually, there are two layers of synchronizer. There is a global synchronizer which protect the whole graphic data and one for each graphic figure. The global synchrnonizer grants access to the data only if it grant access and all the local synchronizer grant access. The local synchronizers also check the global one before granting access.
This mechasim runs quite successfully in Scilab. However, their are some limitations when modifying properties related to the Java UI, such as the figure_size property. Generally, modifying such properties will need a redraw of the figure from Java. Consequently, while in writing action, a display of the canvas is requested and then a display action. Since a display action can only be perfomred if there are no other display and writing actions pending it will wait the end of the current writing action. However, the writing action would only finish when the property is actually modified and then the display ends. So there is a deadlock here. for now, to avoid the deadlock, the syncronisation is disable when Java propeties are set.
The graphic synchronization was created before the integration of a thread library in Scilab. Since rendering is now build upon JOGL and then Java and thanks to the use og Giws it was easy to create a wrapping around Java threading capabilities. Actually, jnis directly provide monitors able to create mutual exclusions code. The wait and notify routines are wrapped using jnis. Consequenlty, all the basics routines are provided by Java.
Synchronization in the use
All the routines can be found in the GraphicSynchrinizerInterface.h file.
- createGraphicSynchronizer / destroyGraphicSynchronizer
These two functions create or destroy the global synchronizer. The first one is nor really needed since the global synchronizer is a singleton. There are no equivalent for local synchrnonizer, they are created and destroyed with figures.
- startGraphicDataWriting / endGraphicDataWriting
Use the global synchronizer to protect some code which will modify the graphic data.
- startGraphicDataDisplaying / endGraphicDataDisplaying
Same but for code which will display the data.
- startGraphicDataReading / endGraphicDataReading
Same but for code which will only read the data.
- startFigureDataWriting(figure) / endFigureDataWriting(figure)
Same as startGraphicDataWriting / endGraphicDataWriting but only protects a single figure and its children.
- startFigureDataDisplaying(figure) / endFigureDataDisplaying(figure)
Same as startGraphicDataDisplaying / endGraphicDataDisplaying but only protects a single figure and its children.
- startFigureDataReading(figure) / endFigureDataReading(figure)
Same as startGraphicDataReading / endGraphicDataReading but only protects a single figure and its children.
For convienience, it is accepatable to imbricate start***Data*** / end***Data*** structures. If such imbrication is reached by the same thread, the highest protection will apply. For example if having startFigureDataReading; startFigureDataWriting ... endFigureDataWriting; endFigureDataReading will protect the data as if they were between startFigureDataWriting and endFigureDataWriting. An other example, having startFigureDataReading; startGraphicDataDisplaying ... startGraphicDataDisplaying ; endFigureDataReading will protect the data as if they were between startGraphicDataDisplaying and startGraphicDataDisplaying.
This behaviour as been added to be able to call protected functions (such as getCurrentFigure) within already protected code and avoiding creating a deadlock in this case. For now the only protected function is getCurrentFigure.
- disableFigureSynchronization(figure) / enableFigureSynchronization(figure)
As describe above, its is sometime needed to disable graphic synchrnonization. This two functions enable or disable both global synchronization and local synchrnonization for a figure.