Blame synfig-core/src/synfig/context.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file context.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) 2008 Chris Moore
Carlos Lopez e83454
**	Copyright (c) 2012-2013 Carlos Lรณpez
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 "context.h"
bw 94d8a6
bw 94d8a6
#include "general.h"
bw 94d8a6
#include <synfig localization.h=""></synfig>
Carlos Lopez a09598
#include "layer.h"
Carlos Lopez a09598
#include "string.h"
Carlos Lopez a09598
#include "vector.h"
Carlos Lopez a09598
#include "color.h"
Carlos Lopez a09598
#include "valuenode.h"
068c13
#include "transformation.h"
Carlos Lopez a09598
bw 94d8a6
#include "layers/layer_pastecanvas.h"
bw 94d8a6
4472a9
#include "rendering/task.h"
4472a9
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
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
// #define SYNFIG_PROFILE_LAYERS
Carlos Lopez a09598
// #define SYNFIG_DEBUG_LAYERS
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez a09598
#include <etl clock=""></etl>
Carlos Lopez a09598
static int depth(0);
Carlos Lopez a09598
static std::map<string,float> time_table;</string,float>
Carlos Lopez a09598
static std::map<string,int> run_table;</string,int>
Carlos Lopez a09598
static etl::clock profile_timer;
Carlos Lopez a09598
static String curr_layer;
Carlos Lopez a09598
static void
Carlos Lopez a09598
_print_profile_report()
Carlos Lopez a09598
{
Carlos Lopez a09598
	synfig::info(">>>> Profile Report: (Times are in msecs)");
Carlos Lopez a09598
	std::map<string,float>::iterator iter;</string,float>
Carlos Lopez a09598
	float total_time(0);
Carlos Lopez a09598
	for(iter=time_table.begin();iter!=time_table.end();++iter)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		String layer(iter->first);
Carlos Lopez a09598
		float time(iter->second);
Carlos Lopez a09598
		int runs(run_table[layer]);
Carlos Lopez a09598
		total_time+=time;
Carlos Lopez a09598
		synfig::info(" Layer \"%s\",\tExecs: %03d, Avg Time: %05.1f, Total Time: %05.1f",layer.c_str(),runs,time/runs*1000,time*1000);
Carlos Lopez a09598
	}
Carlos Lopez a09598
	synfig::info("Total Time: %f seconds", total_time);
Carlos Lopez a09598
	synfig::info("<<<< End of Profile Report");
Carlos Lopez a09598
}
Carlos Lopez a09598
#endif	// SYNFIG_PROFILE_LAYERS
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
dd97a8
ac6c6c
void
26a291
IndependentContext::set_time(Time time, bool force)const
ac6c6c
{
ac6c6c
	IndependentContext context(*this);
dd97a8
	while(*context)
ac6c6c
	{
dd97a8
		if ( (*context)->active() &&
26a291
		    (force || !(*context)->get_time_mark().is_equal(time)) )
ac6c6c
			break;
ac6c6c
		++context;
ac6c6c
	}
dd97a8
	if (!*context) return;
ac6c6c
b98a79
	Layer::Handle layer(*context);
b98a79
	++context;
b98a79
	RWLock::WriterLock lock(layer->get_rw_lock());
b98a79
	layer->set_time(context, time);
ac6c6c
}
ac6c6c
ac6c6c
void
b98a79
IndependentContext::load_resources(Time time, bool /*force*/)const
c006c9
{
c006c9
	IndependentContext context(*this);
c006c9
	while(*context)
c006c9
	{
c006c9
		if ( (*context)->active() )
c006c9
			break;
c006c9
		++context;
c006c9
	}
c006c9
	if (!*context) return;
c006c9
b98a79
	Layer::Handle layer(*context);
b98a79
	++context;
b98a79
	//RWLock::WriterLock lock(layer->get_rw_lock());
b98a79
	layer->load_resources(context, time);
c006c9
}
c006c9
c006c9
void
dd97a8
IndependentContext::set_outline_grow(Real outline_grow)const
ac6c6c
{
dd97a8
	IndependentContext context(*this);
dd97a8
	while(*context)
ac6c6c
	{
dd97a8
		if ( (*context)->active()
dd97a8
		  && fabs((*context)->get_outline_grow_mark() - outline_grow) > 1e-8 )
ac6c6c
			break;
ac6c6c
		++context;
ac6c6c
	}
dd97a8
	if (!*context) return;
ac6c6c
dd97a8
	// Set up a writer lock
b98a79
	
b98a79
	Layer::Handle layer(*context);
b98a79
	++context;
b98a79
	RWLock::WriterLock lock(layer->get_rw_lock());
b98a79
	layer->set_outline_grow(context, outline_grow);
ac6c6c
}
ac6c6c
Carlos Lopez a09598
Color
Carlos Lopez a09598
Context::get_color(const Point &pos)const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Context context(*this);
Carlos Lopez a09598
Carlos Lopez a09598
	while(!context->empty())
Carlos Lopez a09598
	{
Carlos Lopez a09598
		// If this layer is active, then go
Carlos Lopez a09598
		// ahead and break out of the loop
2fe42f
		if(context.active() && context.in_z_range())
Carlos Lopez a09598
			break;
Carlos Lopez a09598
Carlos Lopez a09598
		// Otherwise, we want to keep searching
Carlos Lopez a09598
		// till we find either an active layer,
Carlos Lopez a09598
		// or the end of the layer list
Carlos Lopez a09598
		++context;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// If this layer isn't defined, return alpha
Carlos Lopez a09598
	if((context)->empty()) return Color::alpha();
Carlos Lopez a09598
Carlos Lopez a09598
	RWLock::ReaderLock lock((*context)->get_rw_lock());
Carlos Lopez a09598
c06d66
	return (*context)->get_color(context.get_next(), pos);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez 56fffe
CairoColor
Carlos Lopez 56fffe
Context::get_cairocolor(const Point &pos)const
Carlos Lopez 56fffe
{
Carlos Lopez 56fffe
	Context context(*this);
Carlos Lopez 56fffe
	
Carlos Lopez 56fffe
	while(!context->empty())
Carlos Lopez 56fffe
	{
Carlos Lopez 56fffe
		// If this layer is active, then go
Carlos Lopez 56fffe
		// ahead and break out of the loop
2fe42f
		if(context.active() && context.in_z_range())
Carlos Lopez 56fffe
			break;
Carlos Lopez 56fffe
		
Carlos Lopez 56fffe
		// Otherwise, we want to keep searching
Carlos Lopez 56fffe
		// till we find either an active layer,
Carlos Lopez 56fffe
		// or the end of the layer list
Carlos Lopez 56fffe
		++context;
Carlos Lopez 56fffe
	}
Carlos Lopez 56fffe
	
Carlos Lopez 56fffe
	// If this layer isn't defined, return alpha
Carlos Lopez 56fffe
	if((context)->empty()) return CairoColor::alpha();
Carlos Lopez 56fffe
	
Carlos Lopez 56fffe
	RWLock::ReaderLock lock((*context)->get_rw_lock());
Carlos Lopez 56fffe
	
c06d66
	return (*context)->get_cairocolor(context.get_next(), pos);
Carlos Lopez 56fffe
}
Carlos Lopez 56fffe
Carlos Lopez 56fffe
Carlos Lopez a09598
Rect
Carlos Lopez a09598
Context::get_full_bounding_rect()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Context context(*this);
Carlos Lopez a09598
Carlos Lopez a09598
	while(!context->empty())
Carlos Lopez a09598
	{
Carlos López ee08a5
		// If this layer is active and visible in z_depth range,
Carlos López ee08a5
		// then go ahead and break out of the loop
2fe42f
		if(context.active() && context.in_z_range())
Carlos Lopez a09598
			break;
Carlos Lopez a09598
Carlos Lopez a09598
		// Otherwise, we want to keep searching
Carlos Lopez a09598
		// till we find either an active layer,
Carlos Lopez a09598
		// or the end of the layer list
Carlos Lopez a09598
		++context;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// If this layer isn't defined, return zero-sized rectangle
Carlos Lopez a09598
	if(context->empty()) return Rect::zero();
Carlos Lopez a09598
c06d66
	return (*context)->get_full_bounding_rect(context.get_next());
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
/* Profiling will go like this:
Carlos Lopez a09598
	Profile start = +, stop = -
Carlos Lopez a09598
Carlos Lopez a09598
	+
Carlos Lopez a09598
	-
Carlos Lopez a09598
Carlos Lopez a09598
	time diff is recorded
Carlos Lopez a09598
Carlos Lopez a09598
	to get the independent times we need to break at the one inside and record etc...
Carlos Lopez a09598
	so it looks more like this:
Carlos Lopez a09598
Carlos Lopez a09598
	+
Carlos Lopez a09598
	  -
Carlos Lopez a09598
	  +
Carlos Lopez a09598
		-
Carlos Lopez a09598
		+
Carlos Lopez a09598
			...
Carlos Lopez a09598
		-
Carlos Lopez a09598
		+
Carlos Lopez a09598
	  -
Carlos Lopez a09598
	  +
Carlos Lopez a09598
	-
Carlos Lopez a09598
Carlos Lopez a09598
	at each minus we must record all the info for that which we are worried about...
Carlos Lopez a09598
	each layer can do work before or after the other work is done... so both values must be recorded...
Carlos Lopez a09598
*/
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
etl::handle<layer></layer>
Carlos Lopez a09598
Context::hit_check(const Point &pos)const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Context context(*this);
Carlos Lopez a09598
2fe42f
	while(!context->empty() && context.in_z_range())
Carlos Lopez a09598
	{
Carlos Lopez a09598
		// If this layer is active, then go
Carlos Lopez a09598
		// ahead and break out of the loop
668cc9
		if(context.active())
Carlos Lopez a09598
			break;
Carlos Lopez a09598
Carlos Lopez a09598
		// Otherwise, we want to keep searching
Carlos Lopez a09598
		// till we find either an active layer,
Carlos Lopez a09598
		// or the end of the layer list
Carlos Lopez a09598
		++context;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// If this layer isn't defined, return an empty handle
Carlos Lopez a09598
	if((context)->empty()) return 0;
Carlos Lopez a09598
c06d66
	return (*context)->hit_check(context.get_next(), pos);
Carlos Lopez a09598
}
Carlos Lopez 623fab
Carlos Lopez 623fab
Carlos Lopez 623fab
bool
Carlos Lopez 623fab
Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
Carlos Lopez 623fab
{
Carlos Lopez 623fab
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
	String layer_name(curr_layer);
Carlos Lopez 623fab
	//sum the pre-work done by layer above us... (curr_layer is layer above us...)
Carlos Lopez 623fab
	if(depth>0)
Carlos Lopez 623fab
	{
Carlos Lopez 623fab
		time_table[curr_layer]+=profile_timer();
Carlos Lopez 623fab
		//if(run_table.count(curr_layer))run_table[curr_layer]++;
Carlos Lopez 623fab
		//	else run_table[curr_layer]=1;
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
	
Carlos Lopez 623fab
	const Rect bbox(renddesc.get_rect());
068c13
	const Matrix &transfromation_matrix(renddesc.get_transformation_matrix());
Carlos Lopez 623fab
	// this is going to be set to true if this layer contributes
Carlos Lopez 623fab
	// nothing, but it's a straight blend with non-zero amount, and so
Carlos Lopez 623fab
	// it has an effect anyway
Carlos Lopez 623fab
	bool straight_and_empty = false;
Carlos Lopez 623fab
	etl::handle<layer_composite> composite;</layer_composite>
Carlos Lopez 623fab
	Context context(*this);
Carlos Lopez 623fab
	// Run all layers until context is empty
Carlos Lopez 623fab
	for(;!(context)->empty();++context)
Carlos Lopez 623fab
	{
Carlos Lopez 623fab
		// If we are not active then move on to next layer
668cc9
		if(!context.active())
Carlos Lopez 623fab
			continue;
068c13
		const Rect layer_bounds(Transformation::transform_bounds(transfromation_matrix, (*context)->get_bounding_rect()));
Carlos Lopez 623fab
		// Cast current layer to composite
Carlos Lopez 623fab
		composite = etl::handle<layer_composite>::cast_dynamic(*context);</layer_composite>
Carlos Lopez 623fab
		// If the box area is less than zero or the boxes do not
Carlos Lopez 623fab
		// intersect then move on to next layer, unless the layer is
Carlos Lopez 623fab
		// using a straight blend and has a non-zero amount, in which
Carlos Lopez 623fab
		// case it will still affect the result
Carlos Lopez 623fab
		if(layer_bounds.area() <= 0.0000000000001 || !(layer_bounds && bbox))
Carlos Lopez 623fab
		{
Carlos Lopez 623fab
			if (composite &&
Carlos Lopez 623fab
				Surface::value_type::is_straight(composite->get_blend_method()) &&
Carlos Lopez 623fab
				composite->get_amount() != 0.0f)
Carlos Lopez 623fab
			{
Carlos Lopez 623fab
				straight_and_empty = true;
Carlos Lopez 623fab
				break;
Carlos Lopez 623fab
			}
Carlos Lopez 623fab
			continue;
Carlos Lopez 623fab
		}
Carlos Lopez 623fab
		// If this layer has Straight as the blend method and amount
Carlos Lopez 623fab
		// is 1.0, and the layer doesn't depend on its context, then
Carlos Lopez 623fab
		// we don't want to render the context
Carlos Lopez 623fab
		if (composite &&
Carlos Lopez 623fab
			composite->get_blend_method() == Color::BLEND_STRAIGHT &&
Carlos Lopez 623fab
			composite->get_amount() == 1.0f &&
Carlos Lopez 623fab
			!composite->reads_context())
Carlos Lopez 623fab
		{
Carlos Lopez 623fab
			Layer::Handle layer = *context;
Carlos Lopez 623fab
			while (!context->empty()) context++; // skip the context
Carlos Lopez 623fab
			return layer->accelerated_render(context,surface,quality,renddesc, cb);
Carlos Lopez 623fab
		}
Carlos Lopez 623fab
		// Break out of the loop--we have found a good layer
Carlos Lopez 623fab
		break;
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
	// If this layer isn't defined, return alpha
Carlos Lopez 623fab
	if (context->empty() || (straight_and_empty && composite->get_amount() == 1.0f))
Carlos Lopez 623fab
	{
Carlos Lopez 623fab
#ifdef SYNFIG_DEBUG_LAYERS
Carlos Lopez 623fab
		synfig::info("Context::accelerated_render(): Hit end of list");
Carlos Lopez 623fab
#endif	// SYNFIG_DEBUG_LAYERS
Carlos Lopez 623fab
		// resize the surface to the given render description
Carlos Lopez 623fab
		surface->set_wh(renddesc.get_w(),renddesc.get_h());
Carlos Lopez 623fab
		// and clear the surface
Carlos Lopez 623fab
		surface->clear();
Carlos Lopez 623fab
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		profile_timer.reset();
Carlos Lopez 623fab
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		return true;
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
	
Carlos Lopez 623fab
#ifdef SYNFIG_DEBUG_LAYERS
Carlos Lopez 623fab
	synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
Carlos Lopez 623fab
#endif	// SYNFIG_DEBUG_LAYERS
Carlos Lopez 623fab
	
Carlos Lopez 623fab
	try {
Carlos Lopez 623fab
		// lock the context for reading
Carlos Lopez 623fab
		RWLock::ReaderLock lock((*context)->get_rw_lock());
Carlos Lopez 623fab
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		//go down one layer :P
Carlos Lopez 623fab
		depth++;
Carlos Lopez 623fab
		curr_layer=(*context)->get_name();	//make sure the layer inside is referring to the correct layer outside
Carlos Lopez 623fab
		profile_timer.reset(); 										// +
Carlos Lopez 623fab
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		bool ret;
Carlos Lopez 623fab
		// this layer doesn't draw anything onto the canvas we're
Carlos Lopez 623fab
		// rendering, but it uses straight blending, so we need to render
Carlos Lopez 623fab
		// the stuff under us and then blit transparent pixels over it
Carlos Lopez 623fab
		// using the appropriate 'amount'
Carlos Lopez 623fab
		if (straight_and_empty)
Carlos Lopez 623fab
		{
c06d66
			if ((ret = Context((context.get_next())).accelerated_render(surface,quality,renddesc,cb)))
Carlos Lopez 623fab
			{
Carlos Lopez 623fab
				Surface clearsurface;
Carlos Lopez 623fab
				clearsurface.set_wh(renddesc.get_w(),renddesc.get_h());
Carlos Lopez 623fab
				clearsurface.clear();
Carlos Lopez 623fab
				Surface::alpha_pen apen(surface->begin());
Carlos Lopez 623fab
				apen.set_alpha(composite->get_amount());
Carlos Lopez 623fab
				apen.set_blend_method(composite->get_blend_method());
Carlos Lopez 623fab
				
Carlos Lopez 623fab
				clearsurface.blit_to(apen);
Carlos Lopez 623fab
			}
Carlos Lopez 623fab
		}
Carlos Lopez 623fab
		else
c06d66
			ret = (*context)->accelerated_render(context.get_next(),surface,quality,renddesc, cb);
Carlos Lopez 623fab
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		//post work for the previous layer
Carlos Lopez 623fab
		time_table[curr_layer]+=profile_timer();							//-
Carlos Lopez 623fab
		if(run_table.count(curr_layer))run_table[curr_layer]++;
Carlos Lopez 623fab
		else run_table[curr_layer]=1;
Carlos Lopez 623fab
		depth--;
Carlos Lopez 623fab
		curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
Carlos Lopez 623fab
		//print out the table it we're done...
Carlos Lopez 623fab
		if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
Carlos Lopez 623fab
		profile_timer.reset();												//+
Carlos Lopez 623fab
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 623fab
		return ret;
Carlos Lopez 623fab
	}
0d77fe
	catch(std::bad_alloc&)
Carlos Lopez 623fab
	{
Carlos Lopez 623fab
		synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
Carlos Lopez 623fab
#ifdef _DEBUG
Carlos Lopez 623fab
		return false;
Carlos Lopez 623fab
#else  // _DEBUG
Carlos Lopez 623fab
		++context;
Carlos Lopez 623fab
		return context.accelerated_render(surface, quality, renddesc, cb);
Carlos Lopez 623fab
#endif	// _DEBUG
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
	catch(...)
Carlos Lopez 623fab
	{
Carlos Lopez 623fab
		synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
Carlos Lopez 623fab
		throw;
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
}
Carlos Lopez 623fab
Carlos Lopez 623fab
Carlos Lopez 623fab
bool
Carlos Lopez 413401
Context::accelerated_cairorender(cairo_t *cr,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
Carlos Lopez 413401
{
Carlos Lopez 413401
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
	String layer_name(curr_layer);
Carlos Lopez 413401
	//sum the pre-work done by layer above us... (curr_layer is layer above us...)
Carlos Lopez 413401
	if(depth>0)
Carlos Lopez 413401
	{
Carlos Lopez 413401
		time_table[curr_layer]+=profile_timer();
Carlos Lopez 413401
	}
Carlos Lopez 413401
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
	
Carlos Lopez 413401
	Context context(*this);
Carlos Lopez 413401
	// Run all layers until context is empty
Carlos Lopez 413401
	for(;!(context)->empty();++context)
Carlos Lopez 413401
	{
Carlos Lopez 413401
		// If we are not active then move on to next layer
668cc9
		if(!context.active())
Carlos Lopez 413401
			continue;
Carlos Lopez 1d2a64
		// Found one good layer
Carlos Lopez 413401
		break;
Carlos Lopez 413401
	}
Carlos Lopez 413401
	// If this layer isn't defined, return alpha
Carlos Lopez 1d2a64
	if (context->empty())
Carlos Lopez 413401
	{
Carlos Lopez 413401
#ifdef SYNFIG_DEBUG_LAYERS
Carlos Lopez 413401
		synfig::info("Context::accelerated_cairorender(): Hit end of list");
Carlos Lopez 413401
#endif	// SYNFIG_DEBUG_LAYERS
Carlos Lopez 413401
		// clear the surface
Carlos Lopez 413401
		cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
Carlos Lopez 413401
		cairo_paint(cr);
Carlos Lopez 413401
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		profile_timer.reset();
Carlos Lopez 413401
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		return true;
Carlos Lopez 413401
	}
Carlos Lopez 413401
	
Carlos Lopez 413401
#ifdef SYNFIG_DEBUG_LAYERS
Carlos Lopez 413401
	synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
Carlos Lopez 413401
#endif	// SYNFIG_DEBUG_LAYERS
Carlos Lopez 413401
	
Carlos Lopez 413401
	try {
Carlos Lopez 413401
		// lock the context for reading
Carlos Lopez 413401
		RWLock::ReaderLock lock((*context)->get_rw_lock());
Carlos Lopez 413401
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		//go down one layer :P
Carlos Lopez 413401
		depth++;
Carlos Lopez 413401
		curr_layer=(*context)->get_name();	//make sure the layer inside is referring to the correct layer outside
Carlos Lopez 413401
		profile_timer.reset(); 										// +
Carlos Lopez 413401
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		bool ret;
Carlos Lopez 413401
		// this layer doesn't draw anything onto the canvas we're
Carlos Lopez 413401
		// rendering, but it uses straight blending, so we need to render
Carlos Lopez 413401
		// the stuff under us and then blit transparent pixels over it
Carlos Lopez 413401
		// using the appropriate 'amount'
c06d66
		ret = (*context)->accelerated_cairorender(context.get_next(),cr,quality,renddesc, cb);
Carlos Lopez 413401
#ifdef SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		//post work for the previous layer
Carlos Lopez 413401
		time_table[curr_layer]+=profile_timer();							//-
Carlos Lopez 413401
		if(run_table.count(curr_layer))run_table[curr_layer]++;
Carlos Lopez 413401
		else run_table[curr_layer]=1;
Carlos Lopez 413401
		depth--;
Carlos Lopez 413401
		curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
Carlos Lopez 413401
		//print out the table it we're done...
Carlos Lopez 413401
		if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
Carlos Lopez 413401
		profile_timer.reset();												//+
Carlos Lopez 413401
#endif	// SYNFIG_PROFILE_LAYERS
Carlos Lopez 413401
		return ret;
Carlos Lopez 413401
	}
0d77fe
	catch(std::bad_alloc&)
Carlos Lopez 413401
	{
Carlos Lopez 413401
		synfig::error("Context::accelerated_cairorender(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
Carlos Lopez 413401
#ifdef _DEBUG
Carlos Lopez 413401
		return false;
Carlos Lopez 413401
#else  // _DEBUG
Carlos Lopez 413401
		++context;
Carlos Lopez 413401
		return context.accelerated_cairorender(cr, quality, renddesc, cb);
Carlos Lopez 413401
#endif	// _DEBUG
Carlos Lopez 413401
	}
Carlos Lopez 413401
	catch(...)
Carlos Lopez 413401
	{
Carlos Lopez 413401
		synfig::error("Context::accelerated_cairorender(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
Carlos Lopez 623fab
		throw;
Carlos Lopez 623fab
	}
Carlos Lopez 623fab
}
d04c89
d04c89
//!	Make rendering task using ContextParams
d04c89
rendering::Task::Handle
d04c89
Context::build_rendering_task() const
d04c89
{
4472a9
	Context context = *this;
4472a9
	while ( *context
d04c89
		 && ( !context.active()
d04c89
		   || ( !get_params().render_excluded_contexts
d04c89
			 && (*context)->get_exclude_from_rendering() )))
d04c89
		++context;
d04c89
d04c89
	// TODO: apply z_range and z_blur (now applies in Canvas::optimize_layers)
d04c89
4472a9
	return *context
d04c89
		 ? (*context)->build_rendering_task(context.get_next())
ce743b
		 : rendering::Task::Handle();
d04c89
}
d04c89