[wxruby-users] Drawing thread not getting enough time from scheduler?
Jay McGavren
jay at mcgavren.com
Thu Jan 10 11:14:50 EST 2008
Alex Fenton wrote:
> Jay McGavren wrote:
> > It did speed things up a bit, but it still runs many
> times faster (55
> > seconds vs. 5 seconds) if I join the animation thread.
> >
> ...
> > Any idea how I can get the thread scheduler to devote a
> bit more time
> > to animation, without completely freezing the GUI?
> Just had a chance to try your code. For me on OS X it
> doesn't work at all if thread.join is called, but runs
> pretty smoothly (about 8s total) otherwise. At some level
> you'll also be caught by the granularity of Ruby's thread
> time slices (10ms IIRC), and garbage collection, which is
> taking up to 9ms tracking wxRuby objects alone in your
> example.
OK, so avoid excessive object creation... Oh, yes, and I forgot
(again) to mention I'm on Windows, as are my main target users.
Interesting that the thread handling seems to be so much better on
OSX.
> I see a couple of further potential optimisations in your
> code which improve smoothness for me:
>
> * Take the calls to surface.pen= and surface.pen.cap= out
> of the 30.times loop.
> * See whether the drawing could be more efficiently done
> with a single draw_polygon (which acccepts an Array of
> Wx::Points)
It only happens to look like a polygon - my actual game needs to draw
individual lines (in varying colors and line widths). But that's OK,
because your below suggestion allowed me to draw everything at decent
speed...
> Another untested possibility to improve perceived
> smoothness might be to drive the animation from a
> Wx::Timer. Have it run at regular intervals, calling
> window.refresh to invalidate the window, then copy from the
> bitmap inside an evt_paint handler.
This was the key. It's drawing 300 lines in under 33 milliseconds
now, even on my laptop. The close button and window dragging respond
immediately.
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|
update_window(window, buffer)
end
#Initialize drawing loop counter.
@i = 0
#Animate periodically.
timer_id = Wx::ID_HIGHEST + 1
t = Wx::Timer.new(self, timer_id)
evt_timer(timer_id) {animate(window, buffer)}
t.start(33)
end
def animate(window, buffer)
green_pen = Wx::Pen.new(Wx::Colour.new(128, 255, 128), 3)
black_pen = Wx::Pen.new(Wx::Colour.new(0, 0, 0), 0)
buffer.draw do |surface|
#Clear screen.
surface.pen = black_pen
surface.brush = Wx::BLACK_BRUSH
surface.draw_rectangle(0, 0, 300, 300)
#Draw lines.
surface.pen = green_pen
surface.pen.cap = Wx::CAP_ROUND
300.times do |j|
x = @i + j
surface.draw_line(x, 0, x+100, 100)
end
end
#Update screen.
update_window(window, buffer)
@i += 1
@i = 0 if @i > 300
end
def update_window(window, buffer)
window.paint do |dc|
#Copy the buffer to the viewable window.
dc.draw_bitmap(buffer, 0, 0, false)
end
end
end
app = MyApp.new
app.main_loop
Now to see if I can get similar results from the game itself. Thanks
to everyone for the assistance!
-Jay McGavren
http://jay.mcgavren.com/zyps
More information about the wxruby-users
mailing list