bugGNU Octave - Bugs: bug #44781, Qt (but not FLTK) figure draws...

 
 

bug #44781: Qt (but not FLTK) figure draws empty axes before doing the actual plot

Submitted by:  Dan Sebald <sebald>
Submitted on:  Wed 08 Apr 2015 06:52:57 PM UTC  
 
Category:  Plotting with OpenGL Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Confirmed Assigned to:  None
Originator Name:  Open/Closed:  Open
Release:  dev Operating System:  Any

Add a New Comment (Rich Markup)
   

You are not logged in

Please log in, so followups can be emailed to you.

 

( Jump to the original submission)

Fri 23 Dec 2016 10:40:42 PM UTC, comment #7: 

This issue seems to be still present in Octave 4.2.0.

The description in comment #0 is still fully valid for what I observe with Octave 4.2.0 today.

Hartmut <hardy>
Fri 10 Apr 2015 12:02:26 AM UTC, comment #6: 

The drawing canvas is implemented by class GLCanvas. This class inherits from QGLWidget. It overrides QGLWidget::paintGL, which is the entry point for the entire drawing process. This method is called internally by Qt, from the Qt event loop, after QGLWidget has taken care of creating, initializing and making current a valid OpenGL context corresponding to the QGLWidget.

In other words, the OpenGL commands are not executed in the octave thread. There are executed in the Qt event loop thread.

Michael Goffioul <goffioul>
Thu 09 Apr 2015 01:52:18 AM UTC, comment #5: 

Hmm, I can't duplicate that here, but OpenGL is very driver dependent.  My system ends up using the X11 software implementation, which is kind of slow, so may not behave exactly the same as others.

I see the OpenGL code for drawing objects in libinterp/corefcn/gl-render.cc.  I don't quite understand how the canvas is accessed.  Is there something to the OpenGL context and its initialization that directs which window/viewport it should act on?  Brainstorming, one thing I'm wondering about is that these OpenGL commands appear to be executed in the Octave thread while the Qt canvas is instantiated in the main GUI thread. (As you pointed out.)  If so, perhaps there needs to be a mutex keeping the GUI from acting on the Qt window while Octave core via OpenGL is drawing in the canvas.  Has that sort of thing been worked out?

On the other hand, there would still be a window in which the GUI thread could act on the window if the semaphore is taken, empty axes are drawn, the semaphore freed, [GUI comes in], the semaphore taken again, the long draw done, the semaphore freed again.  The Octave thread would have to not let go of the semaphore.

Dan Sebald <sebald>
Thu 09 Apr 2015 12:32:33 AM UTC, comment #4: 

I am able to reproduce the update during long draw. The fact that the various functions involved also use auto-locking may interfere for you. But basically, I can easily reproduce it as follows:
- "figure" to create the figure
- "plot(1:10000000)" to create the first plot
- "clf" to reset the figure
- move the figure window partially under the octave GUI (e.g. half of it is only visible)
- "plot(1:10000000)", then after hitting <Enter> quickly uses Alt-Tab to bring the figure window to foreground; I can then see the default axes for about 0.5 second before the plot is updated

There used to be call to asyncUpdate, but jwe removed it recently to fix another bug. But in any case, this is not related to this issue and asyncUpdate was not used for that purpose.

The redraw events in this issue are generated by X11 when the window is exposed (note: resizing the window was probably not a good suggestion, a simple expose is better).

The code responsible to draw the figure is in libinterp/corefcn/gl-render.cc

Michael Goffioul <goffioul>
Wed 08 Apr 2015 10:30:24 PM UTC, comment #3: 

I understand the timing/asynchronous issue, however some trial and error doesn't agree with the update during long draws.  That is, I've run plot([1:5000000]) several times, changing window size while the draw is taking place and don't see any sort of refresh until the whole plot is complete.  Granted, the plot will have the wrong size because of the slow draw, and then refresh again very slowly.  It could be that both constructing the plot and repainting it are very slow.

Is this signal/slot the one that controls this?

  connect (this, SIGNAL (asyncUpdate (void)),
           this, SLOT (updateContainer (void)));

It looks like asyncUpdate isn't emitted anywhere anymore.  No harm of course, just extraneous.

Could someone point to where the core code is issuing the primitives to draw on the Qt canvas?  The code in the libgui/graphics is easily searchable, but the core isn't so searchable.

Dan Sebald <sebald>
Wed 08 Apr 2015 08:46:26 PM UTC, comment #2: 

I think it's more due to the fact that Qt and octave lives in different thread. When octave creates a figure (e.g. "gcf"), the figure object is created immediately (synchronously IIRC) in Qt. Once the figure object is created, octave starts populating it (axes, line...). This can take some time, and during that time the Qt event loop is running, so it's possible the Qt window receives an expose event, while octave hasn't added the line object.

In other words, a typical "plot" does the following:

% create the figure
figure(...)
% create the axes
axes(...)
% create the line
line(...)

Between, the axes and the line creation, especially if the line creation takes some time, the Qt event loop can process an expose event for the created figure window, hence drawing the figure with a default axes object.

This does not occur when the figure is created separately, because by the time octave executes the plot command (which then only consist of the axes and line creation), Qt has most likely already processed the expose event of the figure window; as the figure didn't have any axes object, it's been drawn empty. And no further expose event is going to be generated between the axes and line creation, in normal situation. In theory, if the line creation is long enough, you could still get the same issue if you manage to force a redraw/expose of the figure window (e.g. resizing it, overlapping it with another window and bringing it to foreground again...).

Michael Goffioul <goffioul>
Wed 08 Apr 2015 08:10:47 PM UTC, comment #1: 

Confirmed.  I bet in the Qt case there is an internal call to refresh the figure after the axis is first drawn and a second time after the points have been plotted.  The code in _init_fltk_.cc does a pretty job of calling the FLTK event loop parsimoniously.

Rik <rik5>
Project Administrator
Wed 08 Apr 2015 06:52:57 PM UTC, original submission:  

When a fresh figure is created via "plot", Qt graphics toolkit will first draw an empty axes before doing the actual plot.  This creates a sort of flashing effect sometimes.

Launch Octave GUI and create a slow plot with many points such as:

plot(1:1000000)

Notice how there are empty axes with extent (0:1) x (0:1) while the large draw is waiting to complete.  This does not happen in FLTK graphics toolkit.

If the figure is first created, neither does the empty axes appear.  Try

figure
plot(1:1000000)

With "figure" there is a new window, but completely blank.  With the "plot" the window remains blank until the (0:1000000) x (0:1000000) axes appear.

Dan Sebald <sebald>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by hardy (Posted a comment)
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by sebald (Submitted the item)
  •  

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only project members can vote.

     

     

     

    Follows 1 latest change.

    Date Changed by Updated Field Previous Value => Replaced by
    2015-04-08 rik5 StatusNone => Confirmed

    Back to the top


    Powered by Savane 3.5