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 ¶ms) const = 0; 210 apply(const RunParams & params)211 void apply(const RunParams ¶ms) 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 ¶ms, 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 ¶ms) 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