-/* === S I N F G =========================================================== */
+/* === S Y N F I G ========================================================= */
/*! \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>
#include <signal.h>
#endif
-#include <sinfg/general.h>
+#include <synfig/general.h>
#include <ETL/clock>
#endif
using namespace std;
using namespace etl;
-using namespace sinfg;
+using namespace synfig;
using namespace studio;
#define BOREDOM_TIMEOUT 50
/* === C L A S S E S ======================================================= */
-class AsyncTarget_Tile : public sinfg::Target_Tile
+class AsyncTarget_Tile : public synfig::Target_Tile
{
public:
- etl::handle<sinfg::Target_Tile> warm_target;
-
+ etl::handle<synfig::Target_Tile> warm_target;
+
struct tile_t
{
Surface surface;
};
std::list<tile_t> tile_queue;
Glib::Mutex mutex;
-
+
#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<sinfg::Target_Tile> warm_target):
+ AsyncTarget_Tile(etl::handle<synfig::Target_Tile> warm_target):
warm_target(warm_target)
{
set_avoid_time_sync(warm_target->get_avoid_time_sync());
ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready));
#endif
}
-
+
~AsyncTarget_Tile()
{
ready_connection.disconnect();
Glib::Mutex::Lock lock(mutex);
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(sinfg::ProgressCallback *cb=0)
+
+ virtual bool start_frame(synfig::ProgressCallback *cb=0)
{
if(!alive_flag)
return false;
return warm_target->start_frame(cb);
}
-
- virtual bool add_tile(const sinfg::Surface &surface, int gx, int gy)
+
+ virtual bool add_tile(const synfig::Surface &surface, int gx, int gy)
{
assert(surface);
if(!alive_flag)
tile_ready_signal();
#endif
}
-
+
return alive_flag;
}
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()
{
- while(alive_flag)
+ if (!single_threaded())
{
- Glib::Mutex::Lock lock(mutex);
- if(!tile_queue.empty() && alive_flag)
+ while(alive_flag)
{
- if(cond_tile_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
+ Glib::Mutex::Lock lock(mutex);
+ if(!tile_queue.empty() && alive_flag)
+ {
+ if(cond_tile_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
+ break;
+ }
+ else
break;
}
- else
- break;
}
Glib::Mutex::Lock lock(mutex);
if(!alive_flag)
-class AsyncTarget_Scanline : public sinfg::Target_Scanline
+class AsyncTarget_Scanline : public synfig::Target_Scanline
{
public:
- etl::handle<sinfg::Target_Scanline> warm_target;
-
+ etl::handle<synfig::Target_Scanline> warm_target;
+
int scanline_;
Surface surface;
Glib::Mutex mutex;
-
+
#ifndef GLIB_DISPATCHER_BROKEN
Glib::Dispatcher frame_ready_signal;
#endif
public:
- AsyncTarget_Scanline(etl::handle<sinfg::Target_Scanline> warm_target):
+ AsyncTarget_Scanline(etl::handle<synfig::Target_Scanline> warm_target):
warm_target(warm_target)
{
set_avoid_time_sync(warm_target->get_avoid_time_sync());
#endif
surface.set_wh(warm_target->rend_desc().get_w(),warm_target->rend_desc().get_h());
}
-
+
~AsyncTarget_Scanline()
{
ready_connection.disconnect();
Glib::Mutex::Lock lock(mutex);
alive_flag=false;
}
-
- virtual bool start_frame(sinfg::ProgressCallback *cb=0)
- {
+
+ virtual bool start_frame(synfig::ProgressCallback */*cb*/=0)
+ {
return alive_flag;
}
-
+
virtual void end_frame()
{
{
#else
frame_ready_signal();
#endif
- }
-
- while(alive_flag && !ready_next)
- {
- Glib::Mutex::Lock lock(mutex);
- if(cond_frame_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
- break;
}
+
+ if (single_threaded())
+ signal_progress()();
+ else
+ while(alive_flag && !ready_next)
+ {
+ Glib::Mutex::Lock lock(mutex);
+ if(cond_frame_queue_empty.timed_wait(mutex,Glib::TimeVal(0,BOREDOM_TIMEOUT)))
+ break;
+ }
}
-
+
virtual Color * start_scanline(int scanline)
{
Glib::Mutex::Lock lock(mutex);
return surface[scanline];
}
-
+
virtual bool end_scanline()
{
return alive_flag;
Glib::Mutex::Lock lock(mutex);
if(alive_flag)
alive_flag=warm_target->add_frame(&surface);
- cond_frame_queue_empty.signal();
+ if (!single_threaded()) cond_frame_queue_empty.signal();
ready_next=true;
}
};
/* === M E T H O D S ======================================================= */
-AsyncRenderer::AsyncRenderer(etl::handle<sinfg::Target> target_,sinfg::ProgressCallback *cb):
+AsyncRenderer::AsyncRenderer(etl::handle<synfig::Target> target_,synfig::ProgressCallback *cb):
error(false),
success(false),
- cb(cb)
+ cb(cb),
+ updating(false)
{
render_thread=0;
- if(etl::handle<sinfg::Target_Tile>::cast_dynamic(target_))
+ if(etl::handle<synfig::Target_Tile>::cast_dynamic(target_))
{
etl::handle<AsyncTarget_Tile> wrap_target(
- new AsyncTarget_Tile(etl::handle<sinfg::Target_Tile>::cast_dynamic(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<sinfg::Target_Scanline>::cast_dynamic(target_))
+ else if(etl::handle<synfig::Target_Scanline>::cast_dynamic(target_))
{
etl::handle<AsyncTarget_Scanline> wrap_target(
new AsyncTarget_Scanline(
- etl::handle<sinfg::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;
}
}
{
Glib::Mutex::Lock lock(mutex);
done_connection.disconnect();
-
+
if(render_thread)
{
signal_stop_();
-
+
#if REJOIN_ON_STOP
- render_thread->join();
+ if (!single_threaded()) render_thread->join();
#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;
}
}
void
+AsyncRenderer::rendering_progress()
+{
+ updating = true;
+ while(studio::App::events_pending()) studio::App::iteration(false);
+ updating = false;
+}
+
+void
AsyncRenderer::start_()
{
error=false;success=false;
#ifndef GLIB_DISPATCHER_BROKEN
done_connection=signal_done_.connect(mem_fun(*this,&AsyncRenderer::stop));
#endif
-
- render_thread=Glib::Thread::create(
- sigc::mem_fun(*this,&AsyncRenderer::render_target),
+
+ if (single_threaded())
+ {
+ synfig::info("%s:%d rendering in the same thread", __FILE__, __LINE__);
+ target->signal_progress().connect(sigc::mem_fun(this,&AsyncRenderer::rendering_progress));
+ render_thread = (Glib::Thread*)1;
+ render_target();
+ }
+ else
+ {
+ render_thread=Glib::Thread::create(
+ sigc::mem_fun(*this,&AsyncRenderer::render_target),
#if REJOIN_ON_STOP
- true
+ true
#else
- false
+ false
#endif
- );
- assert(render_thread);
+ );
+ assert(render_thread);
+ }
}
else
{
AsyncRenderer::render_target()
{
etl::handle<Target> target(AsyncRenderer::target);
-
+
if(target && target->render())
{
success=true;