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

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file target_tile.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, 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
4590f7
#include <vector></vector>
4590f7
#include <algorithm></algorithm>
4590f7
4590f7
#include <etl clock=""></etl>
4590f7
Carlos Lopez a09598
#include "target_tile.h"
bw 94d8a6
4590f7
#include "general.h"
d3c8bd
#include "localization.h"
bw 94d8a6
Carlos Lopez a09598
#include "canvas.h"
Carlos Lopez a09598
#include "context.h"
bw 94d8a6
#include "render.h"
bw 94d8a6
#include "string.h"
bw 94d8a6
#include "surface.h"
Carlos Lopez a09598
d3c8bd
#include "debug/measure.h"
d3c8bd
4590f7
#include "rendering/renderer.h"
5e2754
#include "rendering/surface.h"
4590f7
#include "rendering/software/surfacesw.h"
5e2754
#include "rendering/common/task/tasktransformation.h"
874534
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;
371bd9
using namespace rendering;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
d3c8bd
Carlos Lopez a09598
const unsigned int	DEF_TILE_WIDTH = TILE_SIZE / 2;
9f38ba
const unsigned int	DEF_TILE_HEIGHT = TILE_SIZE / 2;
Carlos Lopez a09598
d3c8bd
#ifdef _DEBUG
d3c8bd
//#define DEBUG_MEASURE
Carlos Lopez a09598
#endif
Carlos Lopez a09598
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
Target_Tile::Target_Tile():
Carlos Lopez a09598
	threads_(2),
Carlos Lopez a09598
	tile_w_(DEF_TILE_WIDTH),
Carlos Lopez a09598
	tile_h_(DEF_TILE_HEIGHT),
Carlos Lopez a09598
	curr_tile_(0),
a4bbdd
	clipping_(true)
Carlos Lopez a09598
{
Carlos Lopez a09598
	curr_frame_=0;
371bd9
	if (const char *s = getenv("SYNFIG_TARGET_DEFAULT_ENGINE"))
371bd9
		set_engine(s);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
int
Carlos Lopez a09598
Target_Tile::next_frame(Time& time)
Carlos Lopez a09598
{
Carlos Lopez 4a0029
	return Target::next_frame(time);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
int
9f38ba
Target_Tile::next_tile(RectInt& rect)
Carlos Lopez a09598
{
Carlos Lopez a09598
	// Width of the image(in tiles)
Carlos Lopez a09598
	int tw(rend_desc().get_w()/tile_w_);
Carlos Lopez a09598
	int th(rend_desc().get_h()/tile_h_);
Carlos Lopez a09598
Carlos Lopez a09598
	// Add the last tiles (which will be clipped)
Carlos Lopez a09598
	if(rend_desc().get_w()%tile_w_!=0)tw++;
Carlos Lopez a09598
	if(rend_desc().get_h()%tile_h_!=0)th++;
Carlos Lopez a09598
9f38ba
	rect.minx = (curr_tile_%tw)*tile_w_;
9f38ba
	rect.miny = (curr_tile_/tw)*tile_h_;
9f38ba
	rect.maxx = rect.minx + tile_w_;
9f38ba
	rect.maxy = rect.miny + tile_h_;
Carlos Lopez a09598
Carlos Lopez a09598
	curr_tile_++;
Carlos Lopez a09598
	return (tw*th)-curr_tile_+1;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
a4bbdd
synfig::Target_Tile::call_renderer(
a4bbdd
	const etl::handle<rendering::surfaceresource> &surface,</rendering::surfaceresource>
a4bbdd
	Canvas &canvas,
a4bbdd
	const ContextParams &context_params,
a4bbdd
	const RendDesc &renddesc )
371bd9
{
d3c8bd
	#ifdef DEBUG_MEASURE
d3c8bd
	debug::Measure t("Target_Tile::call_renderer");
d3c8bd
	#endif
d3c8bd
5e2754
	surface->create(renddesc.get_w(), renddesc.get_h());
b006b4
	rendering::Task::Handle task;
371bd9
	{
b006b4
		#ifdef DEBUG_MEASURE
b006b4
		debug::Measure t("build rendering task");
b006b4
		#endif
a4bbdd
		task = canvas.build_rendering_task(context_params);
371bd9
	}
d3c8bd
b006b4
	if (task)
b006b4
	{
b006b4
		rendering::Renderer::Handle renderer = rendering::Renderer::get_renderer(get_engine());
b006b4
		if (!renderer)
b006b4
			throw "Renderer '" + get_engine() + "' not found";
371bd9
5e2754
		Vector p0 = renddesc.get_tl();
5e2754
		Vector p1 = renddesc.get_br();
5e2754
		if (p0[0] > p1[0] || p0[1] > p1[1]) {
093a8b
			Matrix m;
5e2754
			if (p0[0] > p1[0]) { m.m00 = -1.0; m.m20 = p0[0] + p1[0]; std::swap(p0[0], p1[0]); }
5e2754
			if (p0[1] > p1[1]) { m.m11 = -1.0; m.m21 = p0[1] + p1[1]; std::swap(p0[1], p1[1]); }
5e2754
			TaskTransformationAffine::Handle t = new TaskTransformationAffine();
5e2754
			t->transformation->matrix = m;
5e2754
			t->sub_task() = task;
5e2754
			task = t;
5e2754
		}
5e2754
5e2754
		task->target_surface = surface;
5e2754
		task->target_rect = RectInt( VectorInt(), surface->get_size() );
5e2754
		task->source_rect = Rect(p0, p1);
371bd9
b006b4
		rendering::Task::List list;
b006b4
		list.push_back(task);
d3c8bd
b006b4
		{
b006b4
			#ifdef DEBUG_MEASURE
b006b4
			debug::Measure t("run renderer");
b006b4
			#endif
b006b4
			renderer->run(list);
371bd9
		}
371bd9
	}
371bd9
	return true;
371bd9
}
371bd9
371bd9
bool
a4bbdd
synfig::Target_Tile::render_frame_(Canvas::Handle canvas, ContextParams context_params, ProgressCallback *cb)
Carlos Lopez a09598
{
Carlos Lopez a09598
	const RendDesc &rend_desc(desc);
Carlos Lopez a09598
a4bbdd
	etl::clock tile_timer;
a4bbdd
	tile_timer.reset();
Carlos Lopez a09598
a4bbdd
	// Gather tiles
a4bbdd
	std::vector<rectint> tiles;</rectint>
a4bbdd
	RectInt rect;
a4bbdd
	while(next_tile(rect)) {
a4bbdd
		if (clipping_)
a4bbdd
			if (rect.minx >= rend_desc.get_w() || rect.miny >= rend_desc.get_h())
a4bbdd
				continue;
a4bbdd
		tiles.push_back(rect);
Carlos Lopez a09598
	}
a4bbdd
a4bbdd
	// Render tiles
a4bbdd
	for(std::vector<rectint>::iterator i = tiles.begin(); i != tiles.end(); ++i)</rectint>
Carlos Lopez a09598
	{
a4bbdd
		// Progress callback
a4bbdd
		int index = i - tiles.begin();
a4bbdd
		int count = (int)tiles.size();
a4bbdd
		SuperCallback super(cb, (count-index)*1000, (count-index+1)*1000, count*1000);
a4bbdd
		if(!super.amount_complete(0,1000))
a4bbdd
			return false;
a4bbdd
a4bbdd
		// Render tile
Carlos Lopez a09598
		tile_timer.reset();
874534
a4bbdd
		rect = *i;
a4bbdd
		if (clipping_)
a4bbdd
			etl::set_intersect(rect, rect, RectInt(0, 0, rend_desc.get_w(), rend_desc.get_h()));
874534
a4bbdd
		if (!rect.valid())
a4bbdd
			continue;
874534
a4bbdd
		RendDesc tile_desc=rend_desc;
a4bbdd
		tile_desc.set_subwindow(rect.minx, rect.miny, rect.maxx - rect.minx, rect.maxy - rect.miny);
Carlos Lopez a09598
a4bbdd
		async_render_tile(canvas, context_params, rect, tile_desc, &super);
Carlos Lopez a09598
	}
4590f7
4590f7
	if (!wait_render_tiles(cb))
4590f7
		return false;
4590f7
9f38ba
	if(cb && !cb->amount_complete(10000,10000))
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
a4bbdd
synfig::Target_Tile::async_render_tile(
a4bbdd
	etl::handle<canvas> canvas,</canvas>
a4bbdd
	ContextParams context_params,
a4bbdd
	RectInt rect,
a4bbdd
	RendDesc tile_desc,
a4bbdd
	ProgressCallback *cb)
4590f7
{
5e2754
	SurfaceResource::Handle surface = new rendering::SurfaceResource();
4590f7
a4bbdd
	if (!call_renderer(surface, *canvas, context_params, tile_desc))
371bd9
	{
371bd9
		// For some reason, the accelerated renderer failed.
371bd9
		if(cb)cb->error(_("Accelerated Renderer Failure"));
371bd9
		return false;
4590f7
	}
4590f7
5e2754
	SurfaceResource::LockWrite<surfacesw> lock(surface);</surfacesw>
5e2754
5e2754
	if(!lock)
4590f7
	{
4590f7
		if(cb)cb->error(_("Bad surface"));
4590f7
		return false;
4590f7
	}
4590f7
5e2754
	synfig::Surface &s = lock->get_surface();
5e2754
	int cnt = s.get_w() * s.get_h();
5e2754
4590f7
	switch(get_alpha_mode())
4590f7
	{
4590f7
		case TARGET_ALPHA_MODE_FILL:
5e2754
			for(int i = 0; i < cnt; ++i)
5e2754
				s[0][i] = Color::blend(s[0][i], desc.get_bg_color(), 1.0f);
4590f7
			break;
4590f7
		case TARGET_ALPHA_MODE_EXTRACT:
5e2754
			for(int i = 0; i< cnt; ++i)
4590f7
			{
5e2754
				float a = s[0][i].get_a();
5e2754
				s[0][i] = Color(a,a,a,a);
4590f7
			}
4590f7
			break;
4590f7
		case TARGET_ALPHA_MODE_REDUCE:
5e2754
			for(int i = 0; i < cnt; ++i)
5e2754
				s[0][i].set_a(1.0f);
4590f7
			break;
4590f7
		default:
4590f7
			break;
4590f7
	}
4590f7
4590f7
	// Add the tile to the target
5e2754
	if (!add_tile(s, rect.minx, rect.miny))
4590f7
	{
Firas Hanife b4b6a7
		if(cb)cb->error(_("add_tile(): Unable to put surface on target"));
4590f7
		return false;
4590f7
	}
4590f7
4590f7
	signal_progress()();
4590f7
	return true;
4590f7
}
4590f7
4590f7
bool
4590f7
synfig::Target_Tile::wait_render_tiles(ProgressCallback* /* cb */)
4590f7
{
4590f7
	return true;
4590f7
}
4590f7
4590f7
4590f7
bool
Carlos Lopez a09598
synfig::Target_Tile::render(ProgressCallback *cb)
Carlos Lopez a09598
{
Carlos Lopez a09598
	SuperCallback super_cb;
Carlos Lopez a09598
	int
Carlos Lopez 4fdecc
		frames=0,
Carlos Lopez a09598
		total_frames,
Carlos Lopez a09598
		frame_start,
Carlos Lopez a09598
		frame_end;
Carlos Lopez a09598
	Time
Carlos Lopez 4fdecc
		t=0;
Carlos Lopez a09598
Carlos Lopez a09598
	assert(canvas);
Carlos Lopez a09598
	curr_frame_=0;
3b3e3e
	//init();
3b3e3e
	if (!init()) {
3b3e3e
		if (cb) cb->error(_("Target initialization failure"));
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	frame_start=desc.get_frame_start();
Carlos Lopez a09598
	frame_end=desc.get_frame_end();
Carlos Lopez a09598
c74593
	ContextParams context_params(desc.get_render_excluded_contexts());
c74593
Carlos Lopez a09598
	// Calculate the number of frames
Carlos Lopez 4fdecc
	total_frames=frame_end-frame_start+1;
Carlos Lopez 4fdecc
	if(total_frames<=0)total_frames=1;
Carlos Lopez a09598
Carlos Lopez a09598
	try {
Carlos Lopez a09598
Carlos Lopez 4fdecc
		if(total_frames>=1)
Carlos Lopez a09598
		{
Carlos Lopez ddc8e7
			do
Carlos Lopez ddc8e7
			{		
Carlos Lopez ddc8e7
				// Grab the time
Carlos Lopez ddc8e7
				frames=next_frame(t);
Carlos Lopez 4fdecc
Carlos Lopez ddc8e7
				curr_tile_=0;
Carlos Lopez a09598
Carlos Lopez ddc8e7
				// If we have a callback, and it returns
Carlos Lopez ddc8e7
				// false, go ahead and bail. (maybe a use cancel)
Carlos Lopez ddc8e7
				if(cb && !cb->amount_complete(total_frames-frames,total_frames))
Carlos Lopez ddc8e7
					return false;
Carlos Lopez a09598
Carlos Lopez ddc8e7
				if(!start_frame(cb))
Carlos Lopez ddc8e7
					return false;
Carlos Lopez a09598
Carlos Lopez ddc8e7
				// Set the time that we wish to render
a4bbdd
				canvas->set_time(t);
c3039f
				canvas->load_resources(t);
9cd69d
				canvas->set_outline_grow(desc.get_outline_grow());
a4bbdd
				if(!render_frame_(canvas, context_params, 0))
Carlos Lopez ddc8e7
					return false;
Carlos Lopez ddc8e7
				end_frame();
Carlos Lopez ddc8e7
			}while(frames);
Carlos Lopez ddc8e7
			//synfig::info("tilerenderer: i=%d, t=%s",i,t.get_string().c_str());
Carlos Lopez a09598
		}
Carlos Lopez a09598
		else
Carlos Lopez a09598
		{
Carlos Lopez a09598
			curr_tile_=0;
Carlos Lopez a09598
Carlos Lopez a09598
			if(!start_frame(cb))
Carlos Lopez a09598
				return false;
Carlos Lopez a09598
Carlos Lopez a09598
			// Set the time that we wish to render
a4bbdd
			canvas->set_time(t);
c3039f
			canvas->load_resources(t);
9cd69d
			canvas->set_outline_grow(desc.get_outline_grow());
Carlos Lopez a09598
Carlos Lopez a09598
			//synfig::info("2time_set_to %s",t.get_string().c_str());
a4bbdd
			if(!render_frame_(canvas, context_params, cb))
Carlos Lopez a09598
				return false;
Carlos Lopez a09598
			end_frame();
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
	}
b1afd8
	catch (const String& str)
Carlos Lopez a09598
	{
Firas Hanife b4b6a7
		if (cb) cb->error(_("Caught string: ")+str);
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
b1afd8
	catch (std::bad_alloc&)
Carlos Lopez a09598
	{
b1afd8
		if (cb) cb->error(_("Ran out of memory (Probably a bug)"));
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	catch(...)
Carlos Lopez a09598
	{
b1afd8
		if (cb) cb->error(_("Caught unknown error, rethrowing..."));
Carlos Lopez a09598
		throw;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}