Ruby Forum wxRuby > Tearing in my buffered animation test script...

Posted by Jay McGavren (Guest)
on 01.12.2007 05:29
(Received via mailing list)
OK, I have a basic blit demo working (thanks to Alex Fenton for his
reply, which I finally saw).

However, there's a great deal of "tearing" on the screen - flickering
grey lines in the black background.  It looks like the blit isn't
always complete when the screen refreshes.

Can anyone look at this and tell me what I might be doing wrong?  Any
help would be most appreciated!

-Jay McGavren
http://jay.mcgavren.com/zyps


require 'rubygems'
require 'wx'

class MyApp < Wx::App

  def on_init

    #Containing frame.
    frame = Wx::Frame.new(nil, :size => [300, 300])
    frame.show

    #Offscreen drawing buffer.
    buffer = Wx::Bitmap.new(300, 300)

    #Displays drawing.
    window = Wx::Window.new(frame, :size => [300, 300])
    window.evt_paint do |event|
      window.paint do |dc|
        #Copy the buffer to the viewable window.
        buffer.draw do |buffer_dc|
          dc.blit(0, 0, 300, 300, buffer_dc, 0, 0)
        end
      end
    end

    #Animate.
    (1..40).each do |i|
      #Clear screen.
      buffer.draw do |surface|
        surface.pen = Wx::Pen.new(Wx::Colour.new(0, 0, 0), 0)
        surface.brush = Wx::BLACK_BRUSH
        surface.draw_rectangle(0, 0, 300, 300)
      end
      #Draw line.
      buffer.draw do |surface|
        surface.pen = Wx::Pen.new(
          Wx::Colour.new(128, 255, 128),
          3
        )
        surface.pen.cap = Wx::CAP_ROUND
        surface.draw_line(i, 0, i+100, 100)
      end
      #Update screen.
      window.refresh
      window.update
      sleep 0.1
    end

  end

end

app = MyApp.new
app.main_loop
Posted by Mario Steele (Guest)
on 01.12.2007 14:30
(Received via mailing list)
On 11/30/07, Jay McGavren <jay@mcgavren.com> wrote:
>
> -Jay McGavren
> http://jay.mcgavren.com/zyps
> <snip>


Hey Jay,

I've actually looked over the demo, and tested it out on my computer.
According to what I see here, there should be no problems with it.  And 
I've
tested it on Linux, and I have no flickering, or tears in it.  I would
suggest, for the final "blit" operation, that instead of waiting for a 
Paint
Event, you switch to using DC#draw_bitmap()  instead of using DC#blit()
This will take a lot of the computation off of wxRuby, which it must do 
to
ensure that everything is within bounds, and there is not a programmer 
error
(Which is often raised by a Message box error, or a segfault). 
Especially
considering that your drawing the entire buffer that you have offscreen.

Two other things.
1.) If your doing the actual painting when evt_paint() is called, then 
you
do not need to create a ClientDC  (Which is what window.paint does)
2.) You can skip evt_paint() and window.refresh/window.update all 
together,
and just call window.paint, to paint to the window, when your finished 
with
the painting on the Buffer.

Just a couple of suggestions for ya, which should take care of the 
flicker
and tearing.

Mario Steele
Posted by Mario Steele (Guest)
on 01.12.2007 14:55
(Received via mailing list)
On 12/1/07, Mario Steele <mario@ruby-im.net> wrote:

>
> Mario Steele
>


Just a quick follow up.  What I meant to say, was that you need to use 
one,
or the other, as your basically creating two DC's within a single event,
which would be causing the flicker.  So, you need to either create a 
Thread
to draw it, or you need to take out the paint and draw within the
evt_paint() proc.  Sorry if that didn't make sense earlier. ;-)
Posted by Paul w Florczykowski (sagge)
on 19.03.2008 20:59
Hi Jay!

I have tested your application, and indeed there is great deal of 
flicker as expected. You are not making any particular errors in your 
code; the problem occurs because the drawing, or more precisely, the 
copying of graphics (blit) is not synchronized with the vertical sync 
signal your screen receives from your graphics card. (I'm speaking in 
terms of analog signal CRT, but actually this applies to any kind of 
digital screen as well, as far the application is concerned)

The usual way to deal with this is:

1. Draw all the graphics onto an backbuffer (any surface that does not 
appear on the screen yet)

2. Await the V-blank (the vertical sync signal)

3. Copy the contents of this backbuffer onto the screen (the 
frontbuffer), or simply swap the buffers if your API supports it

4. repeat from 1

What you are currently doing is similar but lacks the point (2). wxRuby 
aims to support this on a lower level (i think). There is a method 
called "paint_buffered" (in stead of "paint") that provides a 
BufferedDC-object instead of ClientDC or DC. Drawing to the BufferedDC 
is then not supposed to be visible first after: 1. the actual drawing 
you are making on it is finally completed ie. the block provided to 
"buffered_paint" finishes, and 2. the V-blank occurs.

Sadly enough, this feature does not seem to be working properly with 
wxruby 1.9.5. I have currently similar problem - have not yet decided 
whether to devise another method to signal V-blank to Ruby, or to accept 
the moderate flicker in my application.

Best regards,

Paul W Florczykowski
Posted by Alex Fenton (Guest)
on 28.03.2008 01:17
(Received via mailing list)
Hi Paul

Paul w Florczykowski wrote:
> 1. Draw all the graphics onto an backbuffer (any surface that does not 
> appear on the screen yet)
>
> 2. Await the V-blank (the vertical sync signal)
>
> 3. Copy the contents of this backbuffer onto the screen (the 
> frontbuffer), or simply swap the buffers if your API supports it
>
> 4. repeat from 1
>   
I didn't know about (2), thanks for this info on buffering.
> whether to devise another method to signal V-blank to Ruby, or to accept 
> the moderate flicker in my application.
>   
wxRuby 1.9.5 'paint_buffered' method does what you describe, lacking
point (2). It doesn't do anything more low-level. It's implemented in
pure Ruby,

http://wxruby.rubyforge.org/svn/trunk/wxruby2/lib/wx/classes/window.rb

but it's a straight conversion of the C++ code that wxWidgets uses to
provide BufferedDC:

http://svn.wxwidgets.org/viewvc/wx/wxWidgets/tags/WX_2_8_7/include/wx/dcbuffer.h?revision=52270&view=markup

If you find any advice on how we can improve this by synchronising with
the V-blank please post this, as this is beyond my expertise.

thanks
alex