1 /* === S I N F G =========================================================== */
2 /*! \file asyncrenderer.cpp
3 ** \brief Template File
5 ** $Id: asyncrenderer.cpp,v 1.5 2005/01/12 07:03:42 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include "asyncrenderer.h"
32 #include <glibmm/thread.h>
33 #include <glibmm/dispatcher.h>
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
43 #ifdef HAVE_SYS_WAIT_H
51 #include <sinfg/general.h>
56 /* === U S I N G =========================================================== */
60 using namespace sinfg;
61 using namespace studio;
63 #define BOREDOM_TIMEOUT 50
65 #define REJOIN_ON_STOP 1
67 // The Glib::Dispatcher class is broken as of Glibmm 2.4.5.
68 // Defining this macro enables the workaround.
69 #define GLIB_DISPATCHER_BROKEN 1
71 /* === C L A S S E S ======================================================= */
73 class AsyncTarget_Tile : public sinfg::Target_Tile
76 etl::handle<sinfg::Target_Tile> warm_target;
82 tile_t(const Surface& surface,int x, int y):
88 std::list<tile_t> tile_queue;
91 #ifndef GLIB_DISPATCHER_BROKEN
92 Glib::Dispatcher tile_ready_signal;
94 Glib::Cond cond_tile_queue_empty;
97 sigc::connection ready_connection;
100 AsyncTarget_Tile(etl::handle<sinfg::Target_Tile> warm_target):
101 warm_target(warm_target)
103 set_avoid_time_sync(warm_target->get_avoid_time_sync());
104 set_tile_w(warm_target->get_tile_w());
105 set_tile_h(warm_target->get_tile_h());
106 set_canvas(warm_target->get_canvas());
107 set_quality(warm_target->get_quality());
108 set_remove_alpha(warm_target->get_remove_alpha());
109 set_threads(warm_target->get_threads());
110 set_clipping(warm_target->get_clipping());
111 set_rend_desc(&warm_target->rend_desc());
113 #ifndef GLIB_DISPATCHER_BROKEN
114 ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready));
120 ready_connection.disconnect();
124 Glib::Mutex::Lock lock(mutex);
128 virtual int total_tiles()const
130 return warm_target->total_tiles();
133 virtual int next_tile(int& x, int& y)
138 return warm_target->next_tile(x,y);
141 virtual int next_frame(Time& time)
145 return warm_target->next_frame(time);
148 virtual bool start_frame(sinfg::ProgressCallback *cb=0)
152 return warm_target->start_frame(cb);
155 virtual bool add_tile(const sinfg::Surface &surface, int gx, int gy)
160 Glib::Mutex::Lock lock(mutex);
161 tile_queue.push_back(tile_t(surface,gx,gy));
162 if(tile_queue.size()==1)
164 #ifdef GLIB_DISPATCHER_BROKEN
165 ready_connection=Glib::signal_timeout().connect(
167 sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready),
182 Glib::Mutex::Lock lock(mutex);
186 cond_tile_queue_empty.signal();
189 while(!tile_queue.empty() && alive_flag)
191 tile_t& tile(tile_queue.front());
193 alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
195 tile_queue.pop_front();
197 cond_tile_queue_empty.signal();
200 virtual void end_frame()
204 Glib::Mutex::Lock lock(mutex);
205 if(!tile_queue.empty() && alive_flag)
207 if(cond_tile_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
213 Glib::Mutex::Lock lock(mutex);
216 return warm_target->end_frame();
222 class AsyncTarget_Scanline : public sinfg::Target_Scanline
225 etl::handle<sinfg::Target_Scanline> warm_target;
232 #ifndef GLIB_DISPATCHER_BROKEN
233 Glib::Dispatcher frame_ready_signal;
235 Glib::Cond cond_frame_queue_empty;
238 sigc::connection ready_connection;
242 AsyncTarget_Scanline(etl::handle<sinfg::Target_Scanline> warm_target):
243 warm_target(warm_target)
245 set_avoid_time_sync(warm_target->get_avoid_time_sync());
246 set_canvas(warm_target->get_canvas());
247 set_quality(warm_target->get_quality());
248 set_remove_alpha(warm_target->get_remove_alpha());
249 set_threads(warm_target->get_threads());
250 set_rend_desc(&warm_target->rend_desc());
252 #ifndef GLIB_DISPATCHER_BROKEN
253 ready_connection=frame_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready));
255 surface.set_wh(warm_target->rend_desc().get_w(),warm_target->rend_desc().get_h());
258 ~AsyncTarget_Scanline()
260 ready_connection.disconnect();
263 virtual int next_frame(Time& time)
267 return warm_target->next_frame(time);
273 Glib::Mutex::Lock lock(mutex);
277 virtual bool start_frame(sinfg::ProgressCallback *cb=0)
282 virtual void end_frame()
285 Glib::Mutex::Lock lock(mutex);
291 #ifdef GLIB_DISPATCHER_BROKEN
292 ready_connection=Glib::signal_timeout().connect(
294 sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready),
300 frame_ready_signal();
304 while(alive_flag && !ready_next)
306 Glib::Mutex::Lock lock(mutex);
307 if(cond_frame_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
313 virtual Color * start_scanline(int scanline)
315 Glib::Mutex::Lock lock(mutex);
317 return surface[scanline];
320 virtual bool end_scanline()
327 Glib::Mutex::Lock lock(mutex);
329 alive_flag=warm_target->add_frame(&surface);
330 cond_frame_queue_empty.signal();
335 /* === G L O B A L S ======================================================= */
337 /* === P R O C E D U R E S ================================================= */
339 /* === M E T H O D S ======================================================= */
341 AsyncRenderer::AsyncRenderer(etl::handle<sinfg::Target> target_,sinfg::ProgressCallback *cb):
347 if(etl::handle<sinfg::Target_Tile>::cast_dynamic(target_))
349 etl::handle<AsyncTarget_Tile> wrap_target(
350 new AsyncTarget_Tile(etl::handle<sinfg::Target_Tile>::cast_dynamic(target_))
353 signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Tile::set_dead));
357 else if(etl::handle<sinfg::Target_Scanline>::cast_dynamic(target_))
359 etl::handle<AsyncTarget_Scanline> wrap_target(
360 new AsyncTarget_Scanline(
361 etl::handle<sinfg::Target_Scanline>::cast_dynamic(target_)
365 signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Scanline::set_dead));
371 AsyncRenderer::~AsyncRenderer()
377 AsyncRenderer::stop()
381 Glib::Mutex::Lock lock(mutex);
382 done_connection.disconnect();
389 render_thread->join();
392 // Make sure all the dispatch crap is cleared out
393 //Glib::MainContext::get_default()->iteration(false);
407 AsyncRenderer::pause()
412 AsyncRenderer::resume()
417 AsyncRenderer::start()
419 done_connection=Glib::signal_timeout().connect(
421 mem_fun(*this,&AsyncRenderer::start_),
429 AsyncRenderer::start_()
431 error=false;success=false;
434 #ifndef GLIB_DISPATCHER_BROKEN
435 done_connection=signal_done_.connect(mem_fun(*this,&AsyncRenderer::stop));
438 render_thread=Glib::Thread::create(
439 sigc::mem_fun(*this,&AsyncRenderer::render_target),
446 assert(render_thread);
455 AsyncRenderer::render_target()
457 etl::handle<Target> target(AsyncRenderer::target);
459 if(target && target->render())
466 #ifndef REJOIN_ON_STOP
473 #ifdef GLIB_DISPATCHER_BROKEN
474 done_connection=Glib::signal_timeout().connect(
476 mem_fun(*this,&AsyncRenderer::stop),