1 /* === S Y N F I G ========================================================= */
2 /*!	\file synfig/rendering/optimizer.h
3 **	\brief Optimizer Header
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	......... ... 2015 Ivan Mahonin
9 **
10 **	This package is free software; you can redistribute it and/or
11 **	modify it under the terms of the GNU General Public License as
12 **	published by the Free Software Foundation; either version 2 of
13 **	the License, or (at your option) any later version.
14 **
15 **	This package is distributed in the hope that it will be useful,
16 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **	General Public License for more details.
19 **	\endlegal
20 */
21 /* ========================================================================= */
22 
23 /* === S T A R T =========================================================== */
24 
25 #ifndef __SYNFIG_RENDERING_OPTIMIZER_H
26 #define __SYNFIG_RENDERING_OPTIMIZER_H
27 
28 #include "task.h"
29 
30 /* === M A C R O S ========================================================= */
31 
32 /* === T Y P E D E F S ===================================================== */
33 
34 /* === C L A S S E S & S T R U C T S ======================================= */
35 
36 namespace synfig
37 {
38 namespace rendering
39 {
40 
41 class Renderer;
42 
43 class Optimizer: public etl::shared_object
44 {
45 public:
46 	typedef etl::handle<Optimizer> Handle;
47 	typedef std::vector<Handle> List;
48 	typedef unsigned int Category;
49 	typedef unsigned int Mode;
50 
51 	enum CategoryId
52 	{
53 		CATEGORY_ID_COMMON,		     //! common optimizations of task-tree
54 		CATEGORY_ID_PRE_SPECIALIZE,  //! common optimizations, when transformations already applied
55 		CATEGORY_ID_SPECIALIZE,      //! renderer-specified optimizations of task-tree
56 		CATEGORY_ID_POST_SPECIALIZE, //! optimizations of task-tree, which required assigned surfaces
57 		CATEGORY_ID_CONVERT,	     //! OptimizerSurfaceConvert
58 		CATEGORY_ID_LINEAR,		     //! OptimizerLinear
59 		CATEGORY_ID_LIST		     //! optimizations of plain (linear) list of tasks
60 	};
61 
62 	enum
63 	{
64 		CATEGORY_ID_COUNT        = CATEGORY_ID_LIST + 1,
65 		CATEGORY_COMMON          = 1 << CATEGORY_ID_COMMON,          //! --
66 		CATEGORY_PRE_SPECIALIZE  = 1 << CATEGORY_ID_PRE_SPECIALIZE,  //! --
67 		CATEGORY_SPECIALIZE      = 1 << CATEGORY_ID_SPECIALIZE,      //! --
68 		CATEGORY_POST_SPECIALIZE = 1 << CATEGORY_ID_POST_SPECIALIZE, //! --
69 		CATEGORY_CONVERT         = 1 << CATEGORY_ID_CONVERT,         //! --
70 		CATEGORY_LINEAR          = 1 << CATEGORY_ID_LINEAR,          //! --
71 		CATEGORY_LIST            = 1 << CATEGORY_ID_LIST,            //! --
72 		CATEGORY_TREE            = CATEGORY_LINEAR - 1,              //! optimizations of task-tree
73 		CATEGORY_ALL             = (1 << CATEGORY_ID_COUNT) -1       //! all optimizations
74 	};
75 
76 	enum
77 	{
78 		MODE_NONE          = 0,	//! do nothing
79 		MODE_REPEAT_LAST   = 1, //! repeat optimization for current task
80 		MODE_REPEAT_PARENT = 3, //! repeat optimization for parent task (includes MODE_REPEAT_LAST)
81 		MODE_REPEAT_BRUNCH = 7, //! repeat optimization for each of parent tasks (includes MODE_REPEAT_PARENT and MODE_REPEAT_LAST)
82 								//! in sequence: current, parent, parent-of-parent, etc
83 		MODE_RECURSIVE     = 8,	//! uses with MODE_REPEAT_XXX, and tells what
84 		                        //! repeating should be done with recursive call of subtasks
85 	};
86 
87 	struct CategoryInfo
88 	{
89 		//! if set then run all optimizers for each task, else run each optimizer for all tasks
90 		//! true:  optimizer1(taskA), optimizer2(taskA), optimizer1(taskB), optimizer2(taskB)
91 		//! false: optimizer1(taskA), optimizer1(taskB), optimizer2(taskA), optimizer2(taskB)
92 		bool simultaneous_run;
CategoryInfoCategoryInfo93 		CategoryInfo(bool simultaneous_run): simultaneous_run(simultaneous_run) { }
94 	};
95 
96 	struct RunParams
97 	{
98 		//! current renderer
99 		const Renderer &renderer;
100 
101 		//! List of tasks for optimization,
102 		//! (see Optimizer::for_list)
103 		Task::List &list;
104 
105 		const Category depends_from;
106 
107 		//! Parent optimization params.
108 		//! Optimizer can read parent tasks via this field
109 		const RunParams * const parent;
110 
111 		const Task::Handle orig_task;
112 
113 		//! Task for optimization, optimizer may replace or remove (make null) it,
114 		//! (see Optimizer::for_task and Optimizer::for_root_task)
115 		mutable Task::Handle ref_task;
116 		//! Optimizer may mark dirty some set of categories, these categories should be reran
117 		mutable Category ref_affects_to;
118 		//! Optimizer may affect to optimization sequence.
119 		//! For example, initiate reoptimization of current task.
120 		//! (see Optimizater::MODE_XXX)
121 		mutable Mode ref_mode;
122 
123 		RunParams(
124 			const Renderer &renderer,
125 			Task::List &list,
126 			Category depends_from,
127 			const Task::Handle &task = Task::Handle(),
128 			const RunParams *parent = NULL
129 		):
rendererRunParams130 			renderer(renderer),
131 			list(list),
132 			depends_from(depends_from),
133 			parent(parent),
134 			orig_task(task),
135 			ref_task(task),
136 			ref_affects_to(),
137 			ref_mode()
138 		{ }
139 
RunParamsRunParams140 		RunParams(const RunParams &other):
141 			renderer(other.renderer),
142 			list(other.list),
143 			depends_from(other.depends_from),
144 			parent(other.parent),
145 			orig_task(other.orig_task),
146 			ref_task(other.ref_task),
147 			ref_affects_to(),
148 			ref_mode()
149 		{ }
150 
151 		//! Creates RunParams structure for sub-task
subRunParams152 		RunParams sub(const Task::Handle &task) const
153 			{ return RunParams(renderer, list, depends_from, task, this); }
154 
rootRunParams155 		const RunParams& root() const
156 			{ return parent ? parent->root() : *this; }
get_current_level_indexRunParams157 		int get_current_level_index() const
158 			{ return parent ? parent->get_current_level_index() + 1 : 0; }
get_parentRunParams159 		const RunParams* get_parent(int index) const
160 		{
161 			return index == 0 ? this
162 				 : index < 0 || !parent ? NULL
163 				 : parent->get_parent(index - 1);
164 		}
get_levelRunParams165 		const RunParams* get_level(int index) const
166 			{ return get_parent(get_current_level_index() - index); }
167 	};
168 
169 	static const CategoryInfo categories_info[CATEGORY_ID_COUNT];
170 
171 	//! Category of this optimizer,
172 	//! see enum Optimizer::CategoryId (CATEGORY_ID_XXX)
173 	CategoryId category_id;
174 	//! Determines the order of optimizers execution inside category
175 	Real order;
176 	//! Determines the order of optimizers execution inside category when order fields are equal
177 	long long index;
178 	//! Set of categories of optimizers which should be complete before run this optimizer,
179 	//! see Optimizer::CATEGORY_XXX enumerations
180 	Category depends_from;
181 	//! Set of categories of optimizers which should be processed again when this optimizer applied,
182 	//! see Optimizer::CATEGORY_XXX enumerations
183 	Category affects_to;
184 	//! Mode determines what shoud do optimization system when this optimizer applied,
185 	//! see Optimizer::MODE_XXXX enumerations
186 	Mode mode;
187 	//! Optimizer uses for list of tasks
188 	bool for_list;
189 	//! Optimizer uses for individual tasks
190 	bool for_task;
191 	//! Optimizer uses for individual tasks, but root nodes of the list only
192 	bool for_root_task;
193 	//! Optimizer runs for task after all of sub-tasks are processed
194 	bool deep_first;
195 
196 
Optimizer()197 	Optimizer(): category_id(), order(), index(), depends_from(), affects_to(), mode(), for_list(), for_task(), for_root_task(), deep_first() { }
198 	virtual ~Optimizer();
199 
less(const Handle & a,const Handle & b)200 	static bool less(const Handle &a, const Handle &b)
201 	{
202 		return !b ? false
203 			 : !a ? true
204 			 : a->order < b->order ? true
205 			 : b->order < a->order ? false
206 			 : a->index < b->index;
207 	}
208 
209 	virtual void run(const RunParams &params) const = 0;
210 
apply(const RunParams & params)211 	void apply(const RunParams &params) const
212 	{
213 		params.ref_affects_to |= affects_to;
214 		params.ref_mode |= mode;
215 	}
216 
apply(const RunParams & params,const Task::Handle & task)217 	void apply(const RunParams &params, const Task::Handle &task) const
218 	{
219 		apply(params);
220 		params.ref_task = task;
221 	}
222 
apply_clone(const RunParams & params)223 	void apply_clone(const RunParams &params) const
224 	{
225 		apply(params, params.ref_task->clone());
226 	}
227 
228 	template<typename T>
assign_surface(Task::Handle & task,int width,int height,const Vector & rect_lt,const Vector & rect_rb,const RectInt & target_rect)229 	static void assign_surface(
230 		Task::Handle &task,
231 		int width, int height,
232 		const Vector& rect_lt, const Vector& rect_rb,
233 		const RectInt &target_rect )
234 	{
235 		if (task && !task->target_surface)
236 		{
237 			task = task->clone();
238 			task->target_surface = new T();
239 			task->target_surface->is_temporary = true;
240 			task->target_surface->set_size(width, height);
241 			task->init_target_rect(target_rect, rect_lt, rect_rb);
242 			assert( task->check() );
243 			task->trunc_target_by_bounds();
244 		}
245 	}
246 
247 	template<typename T>
assign_surface(Task::Handle & task,const Task::Handle & parent)248 	static void assign_surface(Task::Handle &task, const Task::Handle &parent)
249 	{
250 		if (task && parent && parent->target_surface)
251 			assign_surface<T>(
252 				task,
253 				parent->get_target_rect().maxx - parent->get_target_rect().minx,
254 				parent->get_target_rect().maxy - parent->get_target_rect().miny,
255 				parent->get_source_rect_lt(),
256 				parent->get_source_rect_rb(),
257 				RectInt( 0, 0,
258 					parent->get_target_rect().maxx - parent->get_target_rect().minx,
259 					parent->get_target_rect().maxy - parent->get_target_rect().miny ));
260 	}
261 
262 	template<typename T>
assign_surfaces(const Task::Handle & parent)263 	static void assign_surfaces(const Task::Handle &parent)
264 	{
265 		if (parent && parent->target_surface)
266 		{
267 			for(Task::List::iterator i = parent->sub_tasks.begin(); i != parent->sub_tasks.end(); ++i)
268 				assign_surface<T>(*i, parent);
269 		}
270 	}
271 
272 	template<typename T, typename TT>
assign(const etl::handle<T> & dest,const etl::handle<TT> & src)273 	static void assign(const etl::handle<T> &dest, const etl::handle<TT> &src)
274 		{ *(TT*)dest.get() = *src; dest->trunc_target_by_bounds(); }
275 
276 	template<typename SurfaceType, typename T, typename TT>
assign_all(const etl::handle<T> & dest,const etl::handle<TT> & src)277 	static void assign_all(const etl::handle<T> &dest, const etl::handle<TT> &src)
278 		{ assign(dest, src); assign_surfaces<SurfaceType>(dest); }
279 
280 	template<typename T, typename TT>
init_and_assign(etl::handle<T> & dest,const etl::handle<TT> & src)281 	static void init_and_assign(etl::handle<T> &dest, const etl::handle<TT> &src)
282 		{ dest = new T(); assign(dest, src); }
283 
284 	template<typename SurfaceType, typename T, typename TT>
init_and_assign_all(etl::handle<T> & dest,const etl::handle<TT> & src)285 	static void init_and_assign_all(etl::handle<T> &dest, const etl::handle<TT> &src)
286 		{ dest = new T(); assign_all<SurfaceType>(dest, src); }
287 
288 	template<typename T, typename TT>
create_and_assign(const etl::handle<TT> & src)289 	static const etl::handle<T> create_and_assign(const etl::handle<TT> &src)
290 		{ const etl::handle<T> dest = new T(); assign(dest, src); return dest; }
291 
292 	template<typename SurfaceType, typename T, typename TT>
create_and_assign_all(const etl::handle<TT> & src)293 	static const etl::handle<T> create_and_assign_all(const etl::handle<TT> &src)
294 		{ const etl::handle<T> dest = new T(); assign_all<SurfaceType>(dest, src); return dest; }
295 };
296 
297 } /* end namespace rendering */
298 } /* end namespace synfig */
299 
300 /* -- E N D ----------------------------------------------------------------- */
301 
302 #endif
303