/*! \file asyncrenderer.cpp
** \brief Template File
**
-** $Id: asyncrenderer.cpp,v 1.5 2005/01/12 07:03:42 darco Exp $
+** $Id$
**
** \legal
-** Copyright (c) 2002 Robert B. Quattlebaum Jr.
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**
-** This software and associated documentation
-** are CONFIDENTIAL and PROPRIETARY property of
-** the above-mentioned copyright holder.
+** This package is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License as
+** published by the Free Software Foundation; either version 2 of
+** the License, or (at your option) any later version.
**
-** You may not copy, print, publish, or in any
-** other way distribute this software without
-** a prior written agreement with
-** the copyright holder.
+** This package is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** General Public License for more details.
** \endlegal
*/
/* ========================================================================= */
#endif
#include "asyncrenderer.h"
+#include "app.h"
#include <glibmm/thread.h>
#include <glibmm/dispatcher.h>
{
public:
etl::handle<synfig::Target_Tile> warm_target;
-
+
struct tile_t
{
Surface surface;
}
};
std::list<tile_t> tile_queue;
+#ifndef SINGLE_THREADED
Glib::Mutex mutex;
-
+#endif // SINGLE_THREADED
+
#ifndef GLIB_DISPATCHER_BROKEN
Glib::Dispatcher tile_ready_signal;
#endif
Glib::Cond cond_tile_queue_empty;
bool alive_flag;
-
+
sigc::connection ready_connection;
-
+
public:
AsyncTarget_Tile(etl::handle<synfig::Target_Tile> warm_target):
warm_target(warm_target)
ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready));
#endif
}
-
+
~AsyncTarget_Tile()
{
ready_connection.disconnect();
}
void set_dead()
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
alive_flag=false;
}
-
+
virtual int total_tiles()const
{
return warm_target->total_tiles();
}
-
+
virtual int next_tile(int& x, int& y)
{
if(!alive_flag)
return 0;
-
+
return warm_target->next_tile(x,y);
}
return 0;
return warm_target->next_frame(time);
}
-
+
virtual bool start_frame(synfig::ProgressCallback *cb=0)
{
if(!alive_flag)
return false;
return warm_target->start_frame(cb);
}
-
+
virtual bool add_tile(const synfig::Surface &surface, int gx, int gy)
{
assert(surface);
if(!alive_flag)
return false;
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
tile_queue.push_back(tile_t(surface,gx,gy));
if(tile_queue.size()==1)
{
tile_ready_signal();
#endif
}
-
+
return alive_flag;
}
void tile_ready()
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
if(!alive_flag)
{
tile_queue.clear();
while(!tile_queue.empty() && alive_flag)
{
tile_t& tile(tile_queue.front());
-
+
alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
-
+
tile_queue.pop_front();
}
cond_tile_queue_empty.signal();
virtual void end_frame()
{
+#ifndef SINGLE_THREADED
while(alive_flag)
{
Glib::Mutex::Lock lock(mutex);
break;
}
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
if(!alive_flag)
return;
return warm_target->end_frame();
{
public:
etl::handle<synfig::Target_Scanline> warm_target;
-
+
int scanline_;
Surface surface;
+#ifndef SINGLE_THREADED
Glib::Mutex mutex;
-
+#endif // SINGLE_THREADED
+
#ifndef GLIB_DISPATCHER_BROKEN
Glib::Dispatcher frame_ready_signal;
#endif
#endif
surface.set_wh(warm_target->rend_desc().get_w(),warm_target->rend_desc().get_h());
}
-
+
~AsyncTarget_Scanline()
{
ready_connection.disconnect();
void set_dead()
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
alive_flag=false;
}
-
- virtual bool start_frame(synfig::ProgressCallback *cb=0)
- {
+
+ virtual bool start_frame(synfig::ProgressCallback */*cb*/=0)
+ {
return alive_flag;
}
-
+
virtual void end_frame()
{
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
if(!alive_flag)
return;
#endif
}
+#ifndef SINGLE_THREADED
while(alive_flag && !ready_next)
{
Glib::Mutex::Lock lock(mutex);
if(cond_frame_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
break;
}
+#endif // SINGLE_THREADED
}
-
+
virtual Color * start_scanline(int scanline)
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
return surface[scanline];
}
-
+
virtual bool end_scanline()
{
return alive_flag;
void frame_ready()
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
if(alive_flag)
alive_flag=warm_target->add_frame(&surface);
cond_frame_queue_empty.signal();
error(false),
success(false),
cb(cb)
+#ifdef SINGLE_THREADED
+ , updating(false)
+#endif // SINGLE_THREADED
{
render_thread=0;
if(etl::handle<synfig::Target_Tile>::cast_dynamic(target_))
etl::handle<AsyncTarget_Tile> wrap_target(
new AsyncTarget_Tile(etl::handle<synfig::Target_Tile>::cast_dynamic(target_))
);
-
+
signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Tile::set_dead));
-
+
target=wrap_target;
}
else if(etl::handle<synfig::Target_Scanline>::cast_dynamic(target_))
etl::handle<synfig::Target_Scanline>::cast_dynamic(target_)
)
);
-
+
signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Scanline::set_dead));
-
+
target=wrap_target;
}
}
{
if(target)
{
+#ifndef SINGLE_THREADED
Glib::Mutex::Lock lock(mutex);
+#endif // SINGLE_THREADED
done_connection.disconnect();
-
+
if(render_thread)
{
signal_stop_();
-
+
+#ifndef SINGLE_THREADED
#if REJOIN_ON_STOP
render_thread->join();
#endif
-
+#endif
+
// Make sure all the dispatch crap is cleared out
//Glib::MainContext::get_default()->iteration(false);
-
+
if(success)
signal_success_();
-
+
signal_finished_();
-
+
target=0;
render_thread=0;
}
);
}
+#ifdef SINGLE_THREADED
+void
+AsyncRenderer::rendering_progress()
+{
+ updating = true;
+ while(studio::App::events_pending()) studio::App::iteration(false);
+ updating = false;
+}
+#endif // SINGLE_THREADED
+
void
AsyncRenderer::start_()
{
#ifndef GLIB_DISPATCHER_BROKEN
done_connection=signal_done_.connect(mem_fun(*this,&AsyncRenderer::stop));
#endif
-
+
+#ifdef SINGLE_THREADED
+ target->signal_progress().connect(sigc::mem_fun(this,&AsyncRenderer::rendering_progress));
+ render_thread = (Glib::Thread*)1;
+ render_target();
+#else // SINGLE_THREADED
render_thread=Glib::Thread::create(
sigc::mem_fun(*this,&AsyncRenderer::render_target),
#if REJOIN_ON_STOP
#endif
);
assert(render_thread);
+#endif // SINGLE_THREADED
}
else
{
AsyncRenderer::render_target()
{
etl::handle<Target> target(AsyncRenderer::target);
-
+
if(target && target->render())
{
success=true;
#endif
}
+#ifndef SINGLE_THREADED
if(mutex.trylock())
+#endif // SINGLE_THREADED
{
#ifdef GLIB_DISPATCHER_BROKEN
done_connection=Glib::signal_timeout().connect(
#else
signal_done_.emit();
#endif
+#ifndef SINGLE_THREADED
mutex.unlock();
+#endif // SINGLE_THREADED
}
}