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");
83 /* === P R O C E D U R E S ================================================= */
85 /* === M E T H O D S ======================================================= */
88 Context::get_color(const Point &pos)const
90 Context context(*this);
92 while(!context->empty())
94 // If this layer is active, then go
95 // ahead and break out of the loop
96 if((*context)->active())
99 // Otherwise, we want to keep searching
100 // till we find either an active layer,
101 // or the end of the layer list
105 // If this layer isn't defined, return alpha
106 if((context)->empty()) return Color::alpha();
108 RWLock::ReaderLock lock((*context)->get_rw_lock());
110 return (*context)->get_color(context+1, pos);
114 Context::get_full_bounding_rect()const
116 Context context(*this);
118 while(!context->empty())
120 // If this layer is active, then go
121 // ahead and break out of the loop
122 if((*context)->active())
125 // Otherwise, we want to keep searching
126 // till we find either an active layer,
127 // or the end of the layer list
131 // If this layer isn't defined, return zero-sized rectangle
132 if(context->empty()) return Rect::zero();
134 return (*context)->get_full_bounding_rect(context+1);
138 /* Profiling will go like this:
139 Profile start = +, stop = -
144 time diff is recorded
146 to get the independent times we need to break at the one inside and record etc...
147 so it looks more like this:
161 at each minus we must record all the info for that which we are worried about...
162 each layer can do work before or after the other work is done... so both values must be recorded...
166 Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
168 #ifdef SYNFIG_PROFILE_LAYERS
169 String layer_name(curr_layer);
171 //sum the pre-work done by layer above us... (curr_layer is layer above us...)
174 time_table[curr_layer]+=profile_timer();
175 //if(run_table.count(curr_layer))run_table[curr_layer]++;
176 // else run_table[curr_layer]=1;
180 const Rect bbox(renddesc.get_rect());
182 Context context(*this);
183 for(;!(context)->empty();++context)
185 // If we are not active
186 // then move on to next layer
187 if(!(*context)->active())
190 const Rect layer_bounds((*context)->get_bounding_rect());
192 // If the box area is less than zero
193 // then move on to next layer
194 if(layer_bounds.area()<=0.0000000000001)
197 // If the boxes do not intersect
198 // then move on to next layer
199 if(!(layer_bounds && bbox))
202 // Break out of the loop--we have found a good layer
206 // If this layer isn't defined, return alpha
207 if((context)->empty())
209 #ifdef SYNFIG_DEBUG_LAYERS
210 synfig::info("Context::accelerated_render(): Hit end of list");
212 surface->set_wh(renddesc.get_w(),renddesc.get_h());
214 #ifdef SYNFIG_PROFILE_LAYERS
215 profile_timer.reset();
220 #ifdef SYNFIG_DEBUG_LAYERS
221 synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
225 RWLock::ReaderLock lock((*context)->get_rw_lock());
227 #ifdef SYNFIG_PROFILE_LAYERS
229 //go down one layer :P
231 curr_layer=(*context)->get_name(); //make sure the layer inside is referring to the correct layer outside
232 profile_timer.reset(); // +
233 bool ret((*context)->accelerated_render(context+1,surface,quality,renddesc, cb));
235 //post work for the previous layer
236 time_table[curr_layer]+=profile_timer(); //-
237 if(run_table.count(curr_layer))run_table[curr_layer]++;
238 else run_table[curr_layer]=1;
241 curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
243 //print out the table it we're done...
244 if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
245 profile_timer.reset(); //+
248 return (*context)->accelerated_render(context+1,surface,quality,renddesc, cb);
252 catch(std::bad_alloc)
254 synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
259 return context.accelerated_render(surface, quality, renddesc, cb);
264 synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
270 Context::set_time(Time time)const
272 Context context(*this);
273 while(!(context)->empty())
275 // If this layer is active, then go
276 // ahead and break out of the loop
277 if((*context)->active() && !(*context)->dirty_time_.is_equal(time))
280 // Otherwise, we want to keep searching
281 // till we find either an active layer,
282 // or the end of the layer list
286 // If this layer isn't defined, just return
287 if((context)->empty()) return;
289 // Set up a writer lock
290 RWLock::WriterLock lock((*context)->get_rw_lock());
292 //synfig::info("%s: dirty_time=%f",(*context)->get_name().c_str(),(float)(*context)->dirty_time_);
293 //synfig::info("%s: time=%f",(*context)->get_name().c_str(),(float)time);
296 Layer::ParamList params;
297 Layer::DynamicParamList::const_iterator iter;
299 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
300 params[iter->first]=(*iter->second)(time);
302 (*context)->set_param_list(params);
304 (*context)->set_time(context+1,time);
305 (*context)->dirty_time_=time;
311 Context::set_time(Time time,const Vector &/*pos*/)const
315 Context context(*this);
316 while(!(context)->empty())
318 // If this layer is active, then go
319 // ahead and break out of the loop
320 if((*context)->active())
323 // Otherwise, we want to keep searching
324 // till we find either an active layer,
325 // or the end of the layer list
329 // If this layer isn't defined, just return
330 if((context)->empty()) return;
334 Layer::ParamList params;
335 Layer::DynamicParamList::const_iterator iter;
337 for(iter=(*context)->dynamic_param_list().begin();iter!=(*context)->dynamic_param_list().end();iter++)
338 params[iter->first]=(*iter->second)(time);
340 (*context)->set_param_list(params);
342 (*context)->set_time(context+1,time,pos);
348 Context::hit_check(const Point &pos)const
350 Context context(*this);
352 while(!context->empty())
354 // If this layer is active, then go
355 // ahead and break out of the loop
356 if((*context)->active())
359 // Otherwise, we want to keep searching
360 // till we find either an active layer,
361 // or the end of the layer list
365 // If this layer isn't defined, return an empty handle
366 if((context)->empty()) return 0;
368 return (*context)->hit_check(context+1, pos);