wxGLCanvas always displaying previous render on Windows 10

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
rjinman
In need of some credit
In need of some credit
Posts: 6
Joined: Wed Mar 13, 2019 5:08 pm

wxGLCanvas always displaying previous render on Windows 10

Post by rjinman » Thu Mar 14, 2019 3:29 pm

I've studied the pyramid sample, which doesn't exhibit the problem, so it's likely I'm doing something wrong, but I can't for the life of me see what I'm doing differently.

I'm making a fractal renderer, so I'm not rendering in a loop, like in a game; I'm rendering only when I want to redraw the fractal. The problem is that on Windows, I always see the last render, not the latest one. For example, if I click and drag on the canvas, so as to zoom in, nothing happens. Then I do something that forces a repaint, and only then do I see the render.

When I want a render to occur, I call refresh().

Code: Select all

void Canvas::refresh() {
  Refresh(false);
  Update();
}

void Canvas::onPaint(wxPaintEvent&) {
  wxPaintDC dc(this);
  render(dc);
}

void Canvas::render(wxDC&) {
  if (!IsShownOnScreen()) {
    return;
  }

  SetCurrent(*m_context);

  if (!m_renderer.isInitialised()) {
    auto sz = GetSize();
    m_renderer.initialise(sz.x, sz.y);

    PostSizeEvent();
  }

  m_renderer.clear(255, 255, 255);

  if (m_disabled) {
    m_renderer.finish();
    SwapBuffers();

    return;
  }

  // Disgusting hack to force out stale render on Windows
#ifdef WIN32
  m_renderer.drawMandelbrot(m_mouseDown || m_disableRender);

  if (!m_disableRender) {
    m_disableRender = true;
    CallAfter([this]() { refresh(); });
  }
  else {
    m_disableRender = false;
  }
#else
  m_renderer.drawMandelbrot(m_mouseDown);
#endif

  if (m_mouseDown) {
    int x = m_selectionRect.x;
    int y = m_selectionRect.y;
    int w = m_selectionRect.width;
    int h = m_selectionRect.height;

    m_renderer.drawSelectionRect(x, y, w, h);
  }

  m_renderer.finish();
  SwapBuffers();

  measureFrameRate();
  m_onRender();
}
As you can see I'm hacking it at the moment by forcing a repaint after every render. The bool passed to drawMandelbrot determines whether to recompute the fractal or just draw the last one from a texture (false to recompute).

User avatar
doublemax
Moderator
Moderator
Posts: 13147
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGLCanvas always displaying previous render on Windows 10

Post by doublemax » Thu Mar 14, 2019 4:05 pm

For example, if I click and drag on the canvas, so as to zoom in, nothing happens.
If you do something that changes the view, you have to call Refresh() yourself. The system can't know that it changed and send a paint event.

E.g in the pyramid sample you see calls to Refresh() in the OnSize() event handler and the mouse event handler.
Use the source, Luke!

rjinman
In need of some credit
In need of some credit
Posts: 6
Joined: Wed Mar 13, 2019 5:08 pm

Re: wxGLCanvas always displaying previous render on Windows 10

Post by rjinman » Thu Mar 14, 2019 4:11 pm

Hi, yes, I do do that. Here is the relevant part of the code.

Code: Select all

void Canvas::onLeftMouseBtnDown(wxMouseEvent& e) {
  e.Skip();

  SetFocus();
  SetCurrent(*m_context);

  m_mouseDown = true;
  m_selectionRect = wxRect(e.GetPosition(), wxSize(0, 0));
}

void Canvas::onLeftMouseBtnUp(wxMouseEvent& e) {
  e.Skip();

  m_mouseDown = false;

  if (selectionSizeAboveThreshold(m_selectionRect.GetSize())) {
    int x0 = m_selectionRect.x;
    int y0 = m_selectionRect.y;
    int x1 = x0 + m_selectionRect.width;
    int y1 = y0 + m_selectionRect.height;

    m_renderer.screenSpaceZoom(x0, y0, x1, y1);
  }

  m_renderer.drawSelectionRect(0, 0, 0, 0);
  refresh();
}

void Canvas::onMouseMove(wxMouseEvent& e) {
  e.Skip();

  if (m_mouseDown) {
    wxPoint p = wxGetMousePosition() - GetScreenPosition();
    wxPoint sz_p = p - m_selectionRect.GetTopLeft();
    wxSize sz(sz_p.x, sz_p.y);

    wxSize winSz = GetClientSize();
    float aspect = static_cast<float>(winSz.x) / static_cast<float>(winSz.y);
    sz.y = sz.x / aspect;

    m_selectionRect.SetSize(sz);

    refresh();
  }
}
So on mouse up, I'm calling refresh, which I can confirm triggers a paint event and a render, but I don't see the render.

User avatar
doublemax
Moderator
Moderator
Posts: 13147
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGLCanvas always displaying previous render on Windows 10

Post by doublemax » Thu Mar 14, 2019 4:35 pm

This combination - render works if you force a refresh, render does not work during mouse down, but event handler gets called - should not be possible.

Are you sure the error is not in the m_renderer.drawMandelbrot(m_mouseDown) call, when m_mouseDown is true?

If that's not it, i'm out of ideas.
Use the source, Luke!

rjinman
In need of some credit
In need of some credit
Posts: 6
Joined: Wed Mar 13, 2019 5:08 pm

Re: wxGLCanvas always displaying previous render on Windows 10

Post by rjinman » Tue Mar 19, 2019 1:47 pm

I've simplified the code in an attempt to isolate the problem. You can see the code in the screenshot. As before, it's always displaying the last result.

Image

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 3062
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxGLCanvas always displaying previous render on Windows 10

Post by ONEEYEMAN » Tue Mar 19, 2019 2:35 pm

Hi,
It is better to put the code directly here in the <code></code> tags.
And it is better to do as minimal compilable example, so that anybody can grab it, compile it and test it.

Thank you.

Post Reply