Blame synfig-studio/src/gui/asyncrenderer.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file asyncrenderer.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007 Chris Moore
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#include "asyncrenderer.h"
Carlos Lopez a09598
#include "app.h"
Carlos Lopez a09598
#include <glibmm thread.h=""></glibmm>
Carlos Lopez a09598
#include <glibmm dispatcher.h=""></glibmm>
Carlos Lopez a09598
Carlos Lopez a09598
#include <synfig general.h=""></synfig>
4590f7
#include <synfig context.h=""></synfig>
Carlos Lopez a09598
#include <etl clock=""></etl>
Carlos Lopez a09598
abdbf2
#include <gui localization.h=""></gui>
BobSynfig 56dae1
#include <docks dock_info.h=""></docks>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === U S I N G =========================================================== */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
using namespace studio;
Carlos Lopez a09598
4590f7
#define BOREDOM_TIMEOUT		1
Carlos Lopez a09598
Carlos Lopez a09598
#define REJOIN_ON_STOP	1
Carlos Lopez a09598
Carlos Lopez a09598
// The Glib::Dispatcher class is broken as of Glibmm 2.4.5.
Carlos Lopez a09598
// Defining this macro enables the workaround.
Carlos Lopez a09598
#define GLIB_DISPATCHER_BROKEN 1
Carlos Lopez a09598
Carlos Lopez a09598
/* === C L A S S E S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
class AsyncTarget_Tile : public synfig::Target_Tile
Carlos Lopez a09598
{
Carlos Lopez a09598
public:
Carlos Lopez a09598
	etl::handle<synfig::target_tile> warm_target;</synfig::target_tile>
Carlos Lopez a09598
Carlos Lopez a09598
	struct tile_t
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Surface surface;
Carlos Lopez a09598
		int x,y;
Carlos Lopez a09598
		tile_t(const Surface& surface,int x, int y):
Carlos Lopez a09598
			surface(surface),
Carlos Lopez a09598
			x(x),y(y)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		}
Carlos Lopez a09598
	};
Carlos Lopez a09598
	std::list<tile_t> tile_queue;</tile_t>
4590f7
	std::list<glib::thread*> threads;</glib::thread*>
4590f7
	bool err;
Carlos Lopez a09598
	Glib::Mutex mutex;
Carlos Lopez a09598
Carlos Lopez a09598
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
	Glib::Dispatcher tile_ready_signal;
Carlos Lopez a09598
#endif
Carlos Lopez a09598
	Glib::Cond cond_tile_queue_empty;
Carlos Lopez a09598
	bool alive_flag;
Carlos Lopez a09598
Carlos Lopez a09598
	sigc::connection ready_connection;
Carlos Lopez a09598
Carlos Lopez a09598
public:
Carlos Lopez a09598
	AsyncTarget_Tile(etl::handle<synfig::target_tile> warm_target):</synfig::target_tile>
4590f7
		warm_target(warm_target), err(false)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		set_avoid_time_sync(warm_target->get_avoid_time_sync());
Carlos Lopez a09598
		set_tile_w(warm_target->get_tile_w());
Carlos Lopez a09598
		set_tile_h(warm_target->get_tile_h());
Carlos Lopez a09598
		set_canvas(warm_target->get_canvas());
Carlos Lopez a09598
		set_quality(warm_target->get_quality());
dc451c
		set_alpha_mode(warm_target->get_alpha_mode());
Carlos Lopez a09598
		set_threads(warm_target->get_threads());
Carlos Lopez a09598
		set_clipping(warm_target->get_clipping());
Carlos Lopez a09598
		set_rend_desc(&warm_target->rend_desc());
4590f7
		set_engine(warm_target->get_engine());
Carlos Lopez a09598
		alive_flag=true;
Carlos Lopez a09598
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready));
Carlos Lopez a09598
#endif
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	~AsyncTarget_Tile()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		ready_connection.disconnect();
Carlos Lopez a09598
	}
Carlos Lopez a09598
	void set_dead()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		alive_flag=false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
a4bbdd
	virtual bool async_render_tile(
a4bbdd
		etl::handle<canvas> canvas,</canvas>
a4bbdd
		ContextParams context_params,
a4bbdd
		RectInt rect,
a4bbdd
		RendDesc tile_desc,
3ca1e7
		ProgressCallback */*cb*/ )
4590f7
	{
4590f7
		if(!alive_flag)
4590f7
			return false;
4590f7
4590f7
		Glib::Thread *thread = Glib::Thread::create(
4590f7
			sigc::hide_return(
4590f7
				sigc::bind(
4590f7
					sigc::mem_fun(*this, &AsyncTarget_Tile::sync_render_tile),
a4bbdd
					canvas, context_params, rect, tile_desc, (synfig::ProgressCallback*)NULL )),
4590f7
				true
4590f7
			);
4590f7
		assert(thread);
4590f7
4590f7
		{
4590f7
			Glib::Mutex::Lock lock(mutex);
4590f7
			threads.push_back(thread);
4590f7
		}
4590f7
4590f7
		return true;
4590f7
	}
4590f7
a4bbdd
	bool sync_render_tile(
a4bbdd
		etl::handle<canvas> canvas,</canvas>
a4bbdd
		ContextParams context_params,
a4bbdd
		RectInt rect,
a4bbdd
		RendDesc tile_desc,
a4bbdd
		ProgressCallback *cb )
4590f7
	{
4590f7
		if(!alive_flag)
4590f7
			return false;
a4bbdd
		bool r = warm_target->async_render_tile(canvas, context_params, rect, tile_desc, cb);
4590f7
		if (!r) { Glib::Mutex::Lock lock(mutex); err = true; }
4590f7
		return r;
4590f7
	}
4590f7
4590f7
	virtual bool wait_render_tiles(ProgressCallback *cb=NULL)
4590f7
	{
4590f7
		if(!alive_flag)
4590f7
			return false;
4590f7
4590f7
		while(true)
4590f7
		{
4590f7
			Glib::Thread *thread;
4590f7
			{
4590f7
				Glib::Mutex::Lock lock(mutex);
4590f7
				if (threads.empty()) break;
4590f7
				thread = threads.front();
4590f7
				threads.pop_front();
4590f7
4590f7
			}
4590f7
			thread->join();
4590f7
		}
4590f7
4590f7
		{ Glib::Mutex::Lock lock(mutex); if (err) return false; }
4590f7
		return warm_target->wait_render_tiles(cb);
4590f7
	}
4590f7
9f38ba
	virtual int next_tile(RectInt& rect)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return 0;
Carlos Lopez a09598
9f38ba
		return warm_target->next_tile(rect);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual int next_frame(Time& time)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return 0;
Carlos Lopez a09598
		return warm_target->next_frame(time);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual bool start_frame(synfig::ProgressCallback *cb=0)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return false;
4590f7
		{ Glib::Mutex::Lock lock(mutex); err = false; }
Carlos Lopez a09598
		return warm_target->start_frame(cb);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual bool add_tile(const synfig::Surface &surface, int gx, int gy)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		assert(surface);
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return false;
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		tile_queue.push_back(tile_t(surface,gx,gy));
Carlos Lopez a09598
		if(tile_queue.size()==1)
Carlos Lopez a09598
		{
Carlos Lopez a09598
#ifdef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		ready_connection=Glib::signal_timeout().connect(
Carlos Lopez a09598
			sigc::bind_return(
Carlos Lopez a09598
				sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready),
Carlos Lopez a09598
				false
Carlos Lopez a09598
			)
Carlos Lopez a09598
			,0
Carlos Lopez a09598
		);
Carlos Lopez a09598
#else
Carlos Lopez a09598
		tile_ready_signal();
Carlos Lopez a09598
#endif
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		return alive_flag;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	void tile_ready()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			tile_queue.clear();
Carlos Lopez a09598
			cond_tile_queue_empty.signal();
Carlos Lopez a09598
			return;
Carlos Lopez a09598
		}
Carlos Lopez a09598
		while(!tile_queue.empty() && alive_flag)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			tile_t& tile(tile_queue.front());
Carlos Lopez a09598
Carlos Lopez a09598
			if (getenv("SYNFIG_SHOW_TILE_OUTLINES"))
Carlos Lopez a09598
			{
Carlos Lopez a09598
				Color red(1,0,0);
Carlos Lopez a09598
				tile.surface.fill(red, 0, 0, 1, tile.surface.get_h());
Carlos Lopez a09598
				tile.surface.fill(red, 0, 0, tile.surface.get_w(), 1);
Carlos Lopez a09598
			}
Carlos Lopez a09598
Carlos Lopez a09598
			alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
Carlos Lopez a09598
Carlos Lopez a09598
			tile_queue.pop_front();
Carlos Lopez a09598
		}
Carlos Lopez a09598
		cond_tile_queue_empty.signal();
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual void end_frame()
Carlos Lopez a09598
	{
a4bbdd
		while(alive_flag)
Carlos Lopez a09598
		{
a4bbdd
			Glib::Mutex::Lock lock(mutex);
a4bbdd
			Glib::TimeVal end_time;
Carlos Lopez 408d07
a4bbdd
			end_time.assign_current_time();
a4bbdd
			end_time.add_microseconds(BOREDOM_TIMEOUT);
Carlos Lopez 408d07
a4bbdd
			if(!tile_queue.empty() && alive_flag)
a4bbdd
			{
a4bbdd
				if(cond_tile_queue_empty.timed_wait(mutex,end_time))
Carlos Lopez a09598
					break;
Carlos Lopez a09598
			}
a4bbdd
			else
a4bbdd
				break;
Carlos Lopez a09598
		}
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return;
Carlos Lopez a09598
		return warm_target->end_frame();
Carlos Lopez a09598
	}
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez 0be21f
class AsyncTarget_Cairo_Tile : public synfig::Target_Cairo_Tile
Carlos Lopez 0be21f
{
Carlos Lopez 0be21f
public:
Carlos Lopez 0be21f
	etl::handle<synfig::target_cairo_tile> warm_target;</synfig::target_cairo_tile>
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	class tile_t
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
	public:
Carlos Lopez 0be21f
		cairo_surface_t* surface;
Carlos Lopez 0be21f
		int x,y;
Carlos Lopez 0be21f
		tile_t(): surface(NULL), x(0), y(0)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		tile_t(cairo_surface_t*& surface_,int x_, int y_)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
			if(surface_)
Carlos Lopez 0be21f
				surface=cairo_surface_reference(surface_);
Carlos Lopez 0be21f
			else
Carlos Lopez 0be21f
				surface=surface_;
Carlos Lopez 0be21f
			x=x_;
Carlos Lopez 0be21f
			y=y_;
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		tile_t(const tile_t &other):
Carlos Lopez 0be21f
		surface(cairo_surface_reference(other.surface)),
Carlos Lopez 0be21f
		x(other.x),
Carlos Lopez 0be21f
		y(other.y)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		~tile_t()
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
			if(surface)
Carlos Lopez 0be21f
				cairo_surface_destroy(surface);
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
	};
Carlos Lopez 0be21f
	std::list<tile_t> tile_queue;</tile_t>
Carlos Lopez 0be21f
	Glib::Mutex mutex;
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez 0be21f
	Glib::Dispatcher tile_ready_signal;
Carlos Lopez 0be21f
#endif
Carlos Lopez 0be21f
	Glib::Cond cond_tile_queue_empty;
Carlos Lopez 0be21f
	bool alive_flag;
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	sigc::connection ready_connection;
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
public:
Carlos Lopez 0be21f
	AsyncTarget_Cairo_Tile(etl::handle<synfig::target_cairo_tile> warm_target):</synfig::target_cairo_tile>
Carlos Lopez 0be21f
	warm_target(warm_target)
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		set_avoid_time_sync(warm_target->get_avoid_time_sync());
Carlos Lopez 0be21f
		set_tile_w(warm_target->get_tile_w());
Carlos Lopez 0be21f
		set_tile_h(warm_target->get_tile_h());
Carlos Lopez 0be21f
		set_canvas(warm_target->get_canvas());
Carlos Lopez 0be21f
		set_quality(warm_target->get_quality());
dc451c
		set_alpha_mode(warm_target->get_alpha_mode());
Carlos Lopez 0be21f
		set_threads(warm_target->get_threads());
Carlos Lopez 0be21f
		set_clipping(warm_target->get_clipping());
Carlos Lopez 0be21f
		set_rend_desc(&warm_target->rend_desc());
Carlos Lopez 0be21f
		alive_flag=true;
Carlos Lopez 0be21f
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez 0be21f
		ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Cairo_Tile::tile_ready));
Carlos Lopez 0be21f
#endif
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	~AsyncTarget_Cairo_Tile()
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		ready_connection.disconnect();
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	void set_dead()
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 0be21f
		alive_flag=false;
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	virtual int next_tile(int& x, int& y)
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
			return 0;
Carlos Lopez 0be21f
		
Carlos Lopez 0be21f
		return warm_target->next_tile(x,y);
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	virtual int next_frame(Time& time)
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
			return 0;
Carlos Lopez 0be21f
		return warm_target->next_frame(time);
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	virtual bool start_frame(synfig::ProgressCallback *cb=0)
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
			return false;
Carlos Lopez 0be21f
		return warm_target->start_frame(cb);
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 66f437
	virtual bool add_tile(cairo_surface_t* surface, int gx, int gy)
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		if(cairo_surface_status(surface))
Carlos Lopez 0be21f
			return false;
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
			return false;
Carlos Lopez 0be21f
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 0be21f
		tile_queue.push_back(tile_t(surface,gx,gy));
Carlos Lopez 0be21f
		if(tile_queue.size()==1)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
#ifdef GLIB_DISPATCHER_BROKEN
Carlos Lopez 0be21f
			ready_connection=Glib::signal_timeout().connect(
Carlos Lopez 0be21f
					sigc::bind_return(
Carlos Lopez 0be21f
							sigc::mem_fun(*this,&AsyncTarget_Cairo_Tile::tile_ready),
Carlos Lopez 0be21f
							false
Carlos Lopez 0be21f
							)
Carlos Lopez 0be21f
							,0
Carlos Lopez 0be21f
						);
Carlos Lopez 0be21f
#else
Carlos Lopez 0be21f
			tile_ready_signal();
Carlos Lopez 0be21f
#endif
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		//cairo_surface_destroy(surface);
Carlos Lopez 0be21f
		return alive_flag;
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	void tile_ready()
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
			tile_queue.clear();
Carlos Lopez 0be21f
			cond_tile_queue_empty.signal();
Carlos Lopez 0be21f
			return;
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		while(!tile_queue.empty() && alive_flag)
Carlos Lopez 0be21f
		{
Carlos Lopez 0be21f
			tile_t& tile(tile_queue.front());
Carlos Lopez 0be21f
			
Carlos Lopez 0be21f
//			if (getenv("SYNFIG_SHOW_TILE_OUTLINES"))
Carlos Lopez 0be21f
//			{
Carlos Lopez 0be21f
//				Color red(1,0,0);
Carlos Lopez 0be21f
//				tile.surface.fill(red, 0, 0, 1, tile.surface.get_h());
Carlos Lopez 0be21f
//				tile.surface.fill(red, 0, 0, tile.surface.get_w(), 1);
Carlos Lopez 0be21f
//			}
Carlos Lopez 0be21f
			
Carlos Lopez 0be21f
			alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
Carlos Lopez 0be21f
			
Carlos Lopez 0be21f
			tile_queue.pop_front();
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		cond_tile_queue_empty.signal();
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
	
Carlos Lopez 0be21f
	virtual void end_frame()
Carlos Lopez 0be21f
	{
a4bbdd
		while(alive_flag)
Carlos Lopez 0be21f
		{
a4bbdd
			Glib::Mutex::Lock lock(mutex);
a4bbdd
			Glib::TimeVal end_time;
a4bbdd
			
a4bbdd
			end_time.assign_current_time();
a4bbdd
			end_time.add_microseconds(BOREDOM_TIMEOUT);
a4bbdd
			
a4bbdd
			if(!tile_queue.empty() && alive_flag)
Carlos Lopez 0be21f
			{
a4bbdd
				if(cond_tile_queue_empty.timed_wait(mutex,end_time))
Carlos Lopez 0be21f
					break;
Carlos Lopez 0be21f
			}
a4bbdd
			else
a4bbdd
				break;
Carlos Lopez 0be21f
		}
Carlos Lopez 0be21f
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 0be21f
		if(!alive_flag)
Carlos Lopez 0be21f
			return;
Carlos Lopez 0be21f
		return warm_target->end_frame();
Carlos Lopez 0be21f
	}
Carlos Lopez 0be21f
};
Carlos Lopez 0be21f
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
class AsyncTarget_Scanline : public synfig::Target_Scanline
Carlos Lopez a09598
{
Carlos Lopez a09598
public:
Carlos Lopez a09598
	etl::handle<synfig::target_scanline> warm_target;</synfig::target_scanline>
Carlos Lopez a09598
Carlos Lopez a09598
	int scanline_;
Carlos Lopez a09598
	Surface surface;
Carlos Lopez a09598
Carlos Lopez a09598
	Glib::Mutex mutex;
Carlos Lopez a09598
Carlos Lopez a09598
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
	Glib::Dispatcher frame_ready_signal;
Carlos Lopez a09598
#endif
Carlos Lopez a09598
	Glib::Cond cond_frame_queue_empty;
Carlos Lopez a09598
	bool alive_flag;
Carlos Lopez a09598
	bool ready_next;
Carlos Lopez a09598
	sigc::connection ready_connection;
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
public:
Carlos Lopez a09598
	AsyncTarget_Scanline(etl::handle<synfig::target_scanline> warm_target):</synfig::target_scanline>
6320b8
		warm_target(warm_target),
6320b8
		scanline_(),
6320b8
		alive_flag(),
6320b8
		ready_next()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		set_avoid_time_sync(warm_target->get_avoid_time_sync());
Carlos Lopez a09598
		set_canvas(warm_target->get_canvas());
Carlos Lopez a09598
		set_quality(warm_target->get_quality());
dc451c
		set_alpha_mode(warm_target->get_alpha_mode());
Carlos Lopez a09598
		set_threads(warm_target->get_threads());
Carlos Lopez a09598
		set_rend_desc(&warm_target->rend_desc());
Carlos Lopez a09598
		alive_flag=true;
Carlos Lopez a09598
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		ready_connection=frame_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready));
Carlos Lopez a09598
#endif
Carlos Lopez a09598
		surface.set_wh(warm_target->rend_desc().get_w(),warm_target->rend_desc().get_h());
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	~AsyncTarget_Scanline()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		ready_connection.disconnect();
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual int next_frame(Time& time)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(!alive_flag)
Carlos Lopez a09598
			return 0;
Carlos Lopez a09598
		return warm_target->next_frame(time);
Carlos Lopez a09598
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	void set_dead()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		alive_flag=false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual bool start_frame(synfig::ProgressCallback */*cb*/=0)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		return alive_flag;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual void end_frame()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		{
Carlos Lopez a09598
			Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
Carlos Lopez a09598
			if(!alive_flag)
Carlos Lopez a09598
				return;
Carlos Lopez a09598
			ready_next=false;
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		ready_connection=Glib::signal_timeout().connect(
Carlos Lopez a09598
			sigc::bind_return(
Carlos Lopez a09598
				sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready),
Carlos Lopez a09598
				false
Carlos Lopez a09598
			)
Carlos Lopez a09598
			,0
Carlos Lopez a09598
		);
Carlos Lopez a09598
#else
Carlos Lopez a09598
			frame_ready_signal();
Carlos Lopez a09598
#endif
Carlos Lopez a09598
		}
Carlos Lopez a09598
a4bbdd
		Glib::TimeVal end_time;
Carlos Lopez e2c658
a4bbdd
		end_time.assign_current_time();
a4bbdd
		end_time.add_microseconds(BOREDOM_TIMEOUT);
Carlos Lopez 408d07
a4bbdd
		while(alive_flag && !ready_next)
a4bbdd
		{
a4bbdd
			Glib::Mutex::Lock lock(mutex);
a4bbdd
			if(cond_frame_queue_empty.timed_wait(mutex, end_time))
a4bbdd
				break;
Carlos Lopez 408d07
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
	virtual Color * start_scanline(int scanline)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
Carlos Lopez a09598
		return surface[scanline];
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	virtual bool end_scanline()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		return alive_flag;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	void frame_ready()
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		if(alive_flag)
Carlos Lopez a09598
			alive_flag=warm_target->add_frame(&surface);
a4bbdd
		cond_frame_queue_empty.signal();
Carlos Lopez a09598
		ready_next=true;
BobSynfig 56dae1
		
BobSynfig 56dae1
		int n_total_frames_to_render = warm_target->desc.get_frame_end()        //120
BobSynfig 56dae1
		                             - warm_target->desc.get_frame_start()      //0
BobSynfig 56dae1
		                             + 1;                                       //->121
BobSynfig 56dae1
		int current_rendered_frames_count = warm_target->curr_frame_
BobSynfig 56dae1
		                                  - warm_target->desc.get_frame_start();
BobSynfig 56dae1
		float r = (float) current_rendered_frames_count 
BobSynfig 56dae1
		        / (float) n_total_frames_to_render;
BobSynfig 56dae1
		App::dock_info_->set_render_progress(r);		
Carlos Lopez a09598
	}
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez 80f902
class AsyncTarget_Cairo : public synfig::Target_Cairo
Carlos Lopez 80f902
{
Carlos Lopez 80f902
public:
Carlos Lopez 80f902
	etl::handle<synfig::target_cairo> warm_target;</synfig::target_cairo>
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	cairo_surface_t* surface;
Carlos Lopez 80f902
	ProgressCallback *callback;
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	Glib::Mutex mutex;
Carlos Lopez 80f902
	
Carlos Lopez 80f902
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez 80f902
	Glib::Dispatcher frame_ready_signal;
Carlos Lopez 80f902
#endif
Carlos Lopez 80f902
	Glib::Cond cond_frame_queue_empty;
Carlos Lopez 80f902
	bool alive_flag;
Carlos Lopez 80f902
	bool ready_next;
Carlos Lopez 80f902
	sigc::connection ready_connection;
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	
Carlos Lopez 80f902
public:
Carlos Lopez 80f902
	AsyncTarget_Cairo(etl::handle<synfig::target_cairo> warm_target):</synfig::target_cairo>
6320b8
		warm_target(warm_target),
6320b8
		surface(),
6320b8
		callback(),
6320b8
		alive_flag(),
6320b8
		ready_next()
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		set_avoid_time_sync(warm_target->get_avoid_time_sync());
Carlos Lopez 80f902
		set_canvas(warm_target->get_canvas());
Carlos Lopez 80f902
		set_quality(warm_target->get_quality());
dc451c
		set_alpha_mode(warm_target->get_alpha_mode());
Carlos Lopez 80f902
		set_rend_desc(&warm_target->rend_desc());
Carlos Lopez 80f902
		alive_flag=true;
Carlos Lopez 80f902
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez 80f902
		ready_connection=frame_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Cairo::frame_ready));
Carlos Lopez 80f902
#endif
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	~AsyncTarget_Cairo()
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		ready_connection.disconnect();
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	virtual int next_frame(Time& time)
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 80f902
		if(!alive_flag)
Carlos Lopez 80f902
			return 0;
Carlos Lopez 80f902
		return warm_target->next_frame(time);
Carlos Lopez 80f902
		
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	void set_dead()
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 80f902
		alive_flag=false;
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
		
Carlos Lopez 80f902
	virtual bool put_surface(cairo_surface_t* s, ProgressCallback *cb)
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		{
Carlos Lopez 80f902
			Glib::Mutex::Lock lock(mutex);
Carlos Lopez 80f902
			surface=s;
Carlos Lopez 80f902
			callback=cb;
Carlos Lopez 80f902
			if(!alive_flag)
Carlos Lopez 80f902
				return false;
Carlos Lopez 80f902
			ready_next=false;
Carlos Lopez 80f902
			
Carlos Lopez 80f902
#ifdef GLIB_DISPATCHER_BROKEN
Carlos Lopez 80f902
			ready_connection=Glib::signal_timeout().connect(
Carlos Lopez 80f902
							sigc::bind_return(sigc::mem_fun(*this,&AsyncTarget_Cairo::frame_ready),false)
Carlos Lopez 80f902
											,0
Carlos Lopez 80f902
											);
Carlos Lopez 80f902
#else
Carlos Lopez 80f902
			frame_ready_signal();
Carlos Lopez 80f902
#endif
Carlos Lopez 80f902
		}
Carlos Lopez 80f902
		
a4bbdd
		Glib::TimeVal end_time;
a4bbdd
		
a4bbdd
		end_time.assign_current_time();
a4bbdd
		end_time.add_microseconds(BOREDOM_TIMEOUT);
a4bbdd
		
a4bbdd
		while(alive_flag && !ready_next)
Carlos Lopez 80f902
		{
a4bbdd
			Glib::Mutex::Lock lock(mutex);
a4bbdd
			if(cond_frame_queue_empty.timed_wait(mutex, end_time))
a4bbdd
				break;
Carlos Lopez 80f902
		}
Carlos Lopez 80f902
		return true;
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
	
Carlos Lopez 80f902
	void frame_ready()
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 80f902
		if(alive_flag)
Carlos Lopez 80f902
			alive_flag=warm_target->put_surface(surface, callback);
a4bbdd
		cond_frame_queue_empty.signal();
Carlos Lopez 80f902
		ready_next=true;
BobSynfig 56dae1
		
BobSynfig 56dae1
		int n_total_frames_to_render = warm_target->desc.get_frame_end()        //120
BobSynfig 56dae1
		                             - warm_target->desc.get_frame_start()      //0
BobSynfig 56dae1
		                             + 1;                                       //->121
BobSynfig 56dae1
		int current_rendered_frames_count = warm_target->curr_frame_
BobSynfig 56dae1
		                                  - warm_target->desc.get_frame_start();
BobSynfig 56dae1
		float r = (float) current_rendered_frames_count 
BobSynfig 56dae1
		        / (float) n_total_frames_to_render;
BobSynfig 56dae1
		App::dock_info_->set_render_progress(r);
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
Carlos Lopez 80f902
	virtual bool obtain_surface(cairo_surface_t*& s)
Carlos Lopez 80f902
	{
Carlos Lopez 80f902
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez 80f902
		if(!alive_flag)
Carlos Lopez 80f902
			return false;
Carlos Lopez 80f902
		return warm_target->obtain_surface(s);
Carlos Lopez 80f902
	}
Carlos Lopez 80f902
Carlos Lopez 80f902
};
Carlos Lopez 80f902
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
AsyncRenderer::AsyncRenderer(etl::handle<synfig::target> target_,synfig::ProgressCallback *cb):</synfig::target>
Carlos Lopez a09598
	error(false),
Carlos Lopez a09598
	success(false),
5d2885
	cb(cb),
a86ba5
	start_clock(0),
a86ba5
	finish_clock(0),
5d2885
	start_time(0, 0),
5d2885
	finish_time(0, 0)
Carlos Lopez a09598
{
Carlos Lopez a09598
	render_thread=0;
Carlos Lopez a09598
	if(etl::handle<synfig::target_tile>::cast_dynamic(target_))</synfig::target_tile>
Carlos Lopez a09598
	{
Carlos Lopez a09598
		etl::handle<asynctarget_tile> wrap_target(</asynctarget_tile>
Carlos Lopez a09598
			new AsyncTarget_Tile(etl::handle<synfig::target_tile>::cast_dynamic(target_))</synfig::target_tile>
Carlos Lopez a09598
		);
Carlos Lopez a09598
Carlos Lopez a09598
		signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Tile::set_dead));
Carlos Lopez a09598
Carlos Lopez a09598
		target=wrap_target;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else if(etl::handle<synfig::target_scanline>::cast_dynamic(target_))</synfig::target_scanline>
Carlos Lopez a09598
	{
Carlos Lopez a09598
		etl::handle<asynctarget_scanline> wrap_target(</asynctarget_scanline>
Carlos Lopez a09598
			new AsyncTarget_Scanline(
Carlos Lopez a09598
				etl::handle<synfig::target_scanline>::cast_dynamic(target_)</synfig::target_scanline>
Carlos Lopez a09598
			)
Carlos Lopez a09598
		);
Carlos Lopez a09598
Carlos Lopez a09598
		signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Scanline::set_dead));
Carlos Lopez a09598
Carlos Lopez a09598
		target=wrap_target;
Carlos Lopez a09598
	}
Carlos Lopez 0be21f
	else if(etl::handle<synfig::target_cairo_tile>::cast_dynamic(target_))</synfig::target_cairo_tile>
Carlos Lopez 0be21f
	{
Carlos Lopez 0be21f
		etl::handle<asynctarget_cairo_tile> wrap_target(</asynctarget_cairo_tile>
Carlos Lopez 0be21f
			new AsyncTarget_Cairo_Tile(
Carlos Lopez 0be21f
					etl::handle<synfig::target_cairo_tile>::cast_dynamic(target_)</synfig::target_cairo_tile>
Carlos Lopez 0be21f
			)
Carlos Lopez 0be21f
		);
Carlos Lopez 0be21f
		
Carlos Lopez 0be21f
		signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Cairo_Tile::set_dead));
Carlos Lopez 0be21f
		
Carlos Lopez 0be21f
		target=wrap_target;
Carlos Lopez 0be21f
	}
Carlos Lopez b17237
	else if(etl::handle<synfig::target_cairo>::cast_dynamic(target_))</synfig::target_cairo>
Carlos Lopez b17237
	{
Carlos Lopez b17237
		etl::handle<asynctarget_cairo> wrap_target(</asynctarget_cairo>
Carlos Lopez b17237
			new AsyncTarget_Cairo(
Carlos Lopez b17237
				etl::handle<synfig::target_cairo>::cast_dynamic(target_)</synfig::target_cairo>
Carlos Lopez b17237
			)
Carlos Lopez b17237
		);
Carlos Lopez b17237
		
Carlos Lopez b17237
		signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Cairo::set_dead));
Carlos Lopez b17237
		
Carlos Lopez b17237
		target=wrap_target;
Carlos Lopez b17237
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
AsyncRenderer::~AsyncRenderer()
Carlos Lopez a09598
{
Carlos Lopez a09598
	stop();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::stop()
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(target)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		Glib::Mutex::Lock lock(mutex);
Carlos Lopez a09598
		done_connection.disconnect();
Carlos Lopez a09598
Carlos Lopez a09598
		if(render_thread)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			signal_stop_();
Carlos Lopez a09598
Carlos Lopez a09598
#if REJOIN_ON_STOP
a4bbdd
			render_thread->join();
Carlos Lopez a09598
#endif
5d2885
			finish_time.assign_current_time();
a86ba5
			finish_clock = ::clock();
5d2885
Carlos Lopez a09598
Carlos Lopez a09598
			// Make sure all the dispatch crap is cleared out
Carlos Lopez a09598
			//Glib::MainContext::get_default()->iteration(false);
Carlos Lopez a09598
Carlos Lopez a09598
			if(success)
Carlos Lopez a09598
				signal_success_();
Carlos Lopez a09598
Carlos Lopez a09598
			target=0;
Carlos Lopez a09598
			render_thread=0;
48b78b
			
48b78b
			lock.release();
48b78b
			
48b78b
			signal_finished_();
Carlos Lopez a09598
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::pause()
Carlos Lopez a09598
{
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::resume()
Carlos Lopez a09598
{
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::start()
Carlos Lopez a09598
{
BobSynfig 56dae1
	App::dock_info_->set_render_progress(0.0);
5d2885
	start_time.assign_current_time();
5d2885
	finish_time = start_time;
a86ba5
	start_clock = ::clock();
a86ba5
	finish_clock = start_clock;
Carlos Lopez a09598
	done_connection=Glib::signal_timeout().connect(
Carlos Lopez a09598
		sigc::bind_return(
Carlos Lopez a09598
			mem_fun(*this,&AsyncRenderer::start_),
Carlos Lopez a09598
			false
Carlos Lopez a09598
		)
b17c40
		, 0
Carlos Lopez a09598
	);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::start_()
Carlos Lopez a09598
{
Carlos Lopez a09598
	error=false;success=false;
Carlos Lopez a09598
	if(target)
Carlos Lopez a09598
	{
Carlos Lopez a09598
#ifndef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		done_connection=signal_done_.connect(mem_fun(*this,&AsyncRenderer::stop));
Carlos Lopez a09598
#endif
a4bbdd
		render_thread=Glib::Thread::create(
a4bbdd
			sigc::mem_fun(*this,&AsyncRenderer::render_target),
Carlos Lopez a09598
#if REJOIN_ON_STOP
a4bbdd
			true
Carlos Lopez a09598
#else
a4bbdd
			false
Carlos Lopez a09598
#endif
a4bbdd
			);
a4bbdd
		assert(render_thread);
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
	{
Carlos Lopez a09598
		stop();
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
AsyncRenderer::render_target()
Carlos Lopez a09598
{
Carlos Lopez a09598
	etl::handle<target> target(AsyncRenderer::target);</target>
Carlos Lopez a09598
Carlos Lopez a09598
	if(target && target->render())
Carlos Lopez a09598
	{
Carlos Lopez a09598
		success=true;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
	{
Carlos Lopez a09598
		error=true;
Carlos Lopez a09598
#ifndef REJOIN_ON_STOP
Carlos Lopez a09598
		return;
Carlos Lopez a09598
#endif
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if(mutex.trylock())
Carlos Lopez a09598
	{
Carlos Lopez a09598
#ifdef GLIB_DISPATCHER_BROKEN
Carlos Lopez a09598
		done_connection=Glib::signal_timeout().connect(
Carlos Lopez a09598
			sigc::bind_return(
Carlos Lopez a09598
				mem_fun(*this,&AsyncRenderer::stop),
Carlos Lopez a09598
				false
Carlos Lopez a09598
			)
Carlos Lopez a09598
			,0
Carlos Lopez a09598
		);
Carlos Lopez a09598
#else
Carlos Lopez a09598
		signal_done_.emit();
Carlos Lopez a09598
#endif
Carlos Lopez a09598
		mutex.unlock();
Carlos Lopez a09598
	}
Carlos Lopez a09598
}