1 /* === S Y N F I G ========================================================= */
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
39 #include "valuenode.h"
43 /* === U S I N G =========================================================== */
47 using namespace synfig;
49 /* === M A C R O S ========================================================= */
51 // #define SYNFIG_PROFILE_LAYERS
52 // #define SYNFIG_DEBUG_LAYERS
54 /* === G L O B A L S ======================================================= */
56 #ifdef SYNFIG_PROFILE_LAYERS
59 static std::map<String,float> time_table;
60 static std::map<String,int> run_table;
61 static etl::clock profile_timer;
62 static String curr_layer;
64 _print_profile_report()
66 synfig::info(">>>> Profile Report: (Times are in msecs)");
67 std::map<String,float>::iterator iter;
69 for(iter=time_table.begin();iter!=time_table.end();++iter)
71 String layer(iter->first);
72 float time(iter->second);
73 int runs(run_table[layer]);
75 synfig::info(" Layer \"%s\",\tExecs: %03d, Avg Time: %05.1f, Total Time: %05.1f",layer.c_str(),runs,time/runs*1000,time*1000);
77 synfig::info("Total Time: %f seconds", total_time);
78 synfig::info("<<<< End of Profile Report");
80 #endif // SYNFIG_PROFILE_LAYERS
82 /* === P R O C E D U R E S ================================================= */
84 /* === M E T H O D S ======================================================= */
87 Context::get_color(const Point &pos)const
89 Context context(*this);
91 while(!context->empty())
93 // If this layer is active, then go
94 // ahead and break out of the loop
95 if((*context)->active())
98 // Otherwise, we want to keep searching
99 // till we find either an active layer,
100 // or the end of the layer list
104 // If this layer isn't defined, return alpha
105 if((context)->empty()) return Color::alpha();
107 RWLock::ReaderLock lock((*context)->get_rw_lock());
109 return (*context)->get_color(context+1, pos);
113 Context::get_full_bounding_rect()const
115 Context context(*this);
117 while(!context->empty())
119 // If this layer is active, then go
120 // ahead and break out of the loop
121 if((*context)->active())
124 // Otherwise, we want to keep searching
125 // till we find either an active layer,
126 // or the end of the layer list
130 // If this layer isn't defined, return zero-sized rectangle
131 if(context->empty()) return Rect::zero();
133 return (*context)->get_full_bounding_rect(context+1);
137 /* Profiling will go like this:
138 Profile start = +, stop = -
143 time diff is recorded
145 to get the independent times we need to break at the one inside and record etc...
146 so it looks more like this:
160 at each minus we must record all the info for that which we are worried about...
161 each layer can do work before or after the other work is done... so both values must be recorded...
165 Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
167 #ifdef SYNFIG_PROFILE_LAYERS
168 String layer_name(curr_layer);
170 //sum the pre-work done by layer above us... (curr_layer is layer above us...)
173 time_table[curr_layer]+=profile_timer();
174 //if(run_table.count(curr_layer))run_table[curr_layer]++;
175 // else run_table[curr_layer]=1;
177 #endif // SYNFIG_PROFILE_LAYERS
179 const Rect bbox(renddesc.get_rect());
181 Context context(*this);
182 for(;!(context)->empty();++context)
184 // If we are not active
185 // then move on to next layer
186 if(!(*context)->active())
189 const Rect layer_bounds((*context)->get_bounding_rect());
191 // If the box area is less than zero
192 // then move on to next layer
193 if(layer_bounds.area()<=0.0000000000001)
196 // If the boxes do not intersect
197 // then move on to next layer
198 if(!(layer_bounds && bbox))
201 // Break out of the loop--we have found a good layer
205 // If this layer isn't defined, return alpha
206 if((context)->empty())
208 #ifdef SYNFIG_DEBUG_LAYERS
209 synfig::info("Context::accelerated_render(): Hit end of list");
210 #endif // SYNFIG_DEBUG_LAYERS
211 surface->set_wh(renddesc.get_w(),renddesc.get_h());
213 #ifdef SYNFIG_PROFILE_LAYERS
214 profile_timer.reset();
215 #endif // SYNFIG_PROFILE_LAYERS
219 #ifdef SYNFIG_DEBUG_LAYERS
220 synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
221 #endif // SYNFIG_DEBUG_LAYERS
224 RWLock::ReaderLock lock((*context)->get_rw_lock());
226 #ifdef SYNFIG_PROFILE_LAYERS
227 //go down one layer :P
229 curr_layer=(*context)->get_name(); //make sure the layer inside is referring to the correct layer outside
230 profile_timer.reset(); // +
231 bool ret((*context)->accelerated_render(context+1,surface,quality,renddesc, cb));
233 //post work for the previous layer
234 time_table[curr_layer]+=profile_timer(); //-
235 if(run_table.count(curr_layer))run_table[curr_layer]++;
236 else run_table[curr_layer]=1;
239 curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
241 //print out the table it we're done...
242 if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
243 profile_timer.reset(); //+
245 #else // SYNFIG_PROFILE_LAYERS
246 return (*context)->accelerated_render(context+1,surface,quality,renddesc, cb);
247 #endif // SYNFIG_PROFILE_LAYERS
250 catch(std::bad_alloc)
252 synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
257 return context.accelerated_render(surface, quality, renddesc, cb);
262 synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
268 Context::set_time(Time time)const
270 Context context(*this);
271 while(!(context)->empty())
273 // If this layer is active, then go
274 // ahead and break out of the loop
275 if((*context)->active() && !(*context)->dirty_time_.is_equal(time))
278 // Otherwise, we want to keep searching
279 // till we find either an active layer,
280 // or the end of the layer list
284 // If this layer isn't defined, just return
285 if((context)->empty()) return;
287 // Set up a writer lock
288 RWLock::WriterLock lock((*context)->get_rw_lock());
290 //synfig::info("%s: dirty_time=%f",(*context)->get_name().c_str(),(float)(*context)->dirty_time_);
291 //synfig::info("%s: time=%f",(*context)->get_name().c_str(),(float)time);
294 Layer::ParamList params;
295 Layer::DynamicParamList::const_iterator iter;
297 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
298 params[iter->first]=(*iter->second)(time);
300 (*context)->set_param_list(params);
302 (*context)->set_time(context+1,time);
303 (*context)->dirty_time_=time;
309 Context::set_time(Time time,const Vector &/*pos*/)const
313 Context context(*this);
314 while(!(context)->empty())
316 // If this layer is active, then go
317 // ahead and break out of the loop
318 if((*context)->active())
321 // Otherwise, we want to keep searching
322 // till we find either an active layer,
323 // or the end of the layer list
327 // If this layer isn't defined, just return
328 if((context)->empty()) return;
332 Layer::ParamList params;
333 Layer::DynamicParamList::const_iterator iter;
335 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
336 params[iter->first]=(*iter->second)(time);
338 (*context)->set_param_list(params);
340 (*context)->set_time(context+1,time,pos);
346 Context::hit_check(const Point &pos)const
348 Context context(*this);
350 while(!context->empty())
352 // If this layer is active, then go
353 // ahead and break out of the loop
354 if((*context)->active())
357 // Otherwise, we want to keep searching
358 // till we find either an active layer,
359 // or the end of the layer list
363 // If this layer isn't defined, return an empty handle
364 if((context)->empty()) return 0;
366 return (*context)->hit_check(context+1, pos);