1 /* === S Y N F I G ========================================================= */
2 /*! \file target_tile.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include "target_tile.h"
44 /* === U S I N G =========================================================== */
48 using namespace synfig;
50 /* === M A C R O S ========================================================= */
51 const unsigned int DEF_TILE_WIDTH = TILE_SIZE / 2;
52 const unsigned int DEF_TILE_HEIGHT= TILE_SIZE / 2;
54 // note that if this isn't defined then the rendering is incorrect for
55 // the straight blend method since the optimize_layers() function in
56 // canvas.cpp which makes the straight blend method work correctly
57 // isn't called. ie. leave this defined. to see the problem, draw a
58 // small circle over a solid background. set circle to amount 0.99
59 // and blend method 'straight'. the background should vanish but doesn't
60 #define SYNFIG_OPTIMIZE_LAYER_TREE
63 // #define SYNFIG_DISPLAY_EFFICIENCY
66 /* === G L O B A L S ======================================================= */
68 /* === P R O C E D U R E S ================================================= */
70 /* === M E T H O D S ======================================================= */
72 Target_Tile::Target_Tile():
74 tile_w_(DEF_TILE_WIDTH),
75 tile_h_(DEF_TILE_HEIGHT),
83 Target_Tile::next_frame(Time& time)
93 // If the description's end frame is equal to
94 // the start frame, then it is assumed that we
95 // are rendering only one frame. Correct it.
96 if(desc.get_frame_end()==desc.get_frame_start())
97 desc.set_frame_end(desc.get_frame_start()+1);
99 frame_start=desc.get_frame_start();
100 frame_end=desc.get_frame_end();
101 time_start=desc.get_time_start();
102 time_end=desc.get_time_end();
104 // Calculate the number of frames
105 total_frames=frame_end-frame_start;
106 if(total_frames<=0)total_frames=1;
108 //RendDesc rend_desc=desc;
109 //rend_desc.set_gamma(1);
111 // int total_tiles(total_tiles());
112 time=(time_end-time_start)*curr_frame_/total_frames+time_start;
115 /* synfig::info("curr_frame_: %d",curr_frame_);
116 synfig::info("total_frames: %d",total_frames);
117 synfig::info("time_end: %s",time_end.get_string().c_str());
118 synfig::info("time_start: %s",time_start.get_string().c_str());
120 // synfig::info("time: %s",time.get_string().c_str());
122 return total_frames- curr_frame_+1;
126 Target_Tile::next_tile(int& x, int& y)
128 // Width of the image(in tiles)
129 int tw(rend_desc().get_w()/tile_w_);
130 int th(rend_desc().get_h()/tile_h_);
132 // Add the last tiles (which will be clipped)
133 if(rend_desc().get_w()%tile_w_!=0)tw++;
134 if(rend_desc().get_h()%tile_h_!=0)th++;
136 x=(curr_tile_%tw)*tile_h_;
137 y=(curr_tile_/tw)*tile_w_;
140 return (tw*th)-curr_tile_+1;
144 synfig::Target_Tile::render_frame_(Context context,ProgressCallback *cb)
146 if(tile_w_<=0||tile_h_<=0)
148 if(cb)cb->error(_("Bad Tile Size"));
151 const RendDesc &rend_desc(desc);
152 #define total_tiles total_tiles()
154 etl::clock total_time;
155 etl::clock::value_type work_time(0);
156 etl::clock::value_type find_tile_time(0);
157 etl::clock::value_type add_tile_time(0);
160 // If the quality is set to zero, then we
161 // use the parametric scanline-renderer.
169 etl::clock tile_timer;
171 while((i=next_tile(x,y)))
173 find_tile_time+=tile_timer();
174 SuperCallback super(cb,(total_tiles-i+1)*1000,(total_tiles-i+2)*1000,total_tiles*1000);
175 if(!super.amount_complete(0,1000))
177 //if(cb && !cb->amount_complete(total_tiles-i,total_tiles))
180 // Perform clipping on the tile
183 w=x+tile_w_<rend_desc.get_w()?tile_w_:rend_desc.get_w()-x;
184 h=y+tile_h_<rend_desc.get_h()?tile_h_:rend_desc.get_h()-y;
185 if(w<=0||h<=0)continue;
194 tile_desc.set_subwindow(x,y,w,h);
195 if(!parametric_render(context, surface, tile_desc,&super))
197 // For some reason, the parametric renderer failed.
198 if(cb)cb->error(_("Parametric Renderer Failure"));
205 if(cb)cb->error(_("Bad surface"));
208 if(get_remove_alpha())
209 for(int i=0;i<surface.get_w()*surface.get_h();i++)
210 surface[0][i]=Color::blend(surface[0][i],desc.get_bg_color(),1.0f);
212 // Add the tile to the target
213 if(!add_tile(surface,x,y))
215 if(cb)cb->error(_("add_tile():Unable to put surface on target"));
222 else // If quality is set otherwise, then we use the accelerated renderer
229 etl::clock tile_timer;
231 while((i=next_tile(x,y)))
233 find_tile_time+=tile_timer();
234 SuperCallback super(cb,(total_tiles-i)*1000,(total_tiles-i+1)*1000,total_tiles*1000);
235 if(!super.amount_complete(0,1000))
237 // if(cb && !cb->amount_complete(total_tiles-i,total_tiles))
239 // Perform clipping on the tile
242 w=x+tile_w_<rend_desc.get_w()?tile_w_:rend_desc.get_w()-x;
243 h=y+tile_h_<rend_desc.get_h()?tile_h_:rend_desc.get_h()-y;
244 if(w<=0||h<=0)continue;
253 tile_desc.set_subwindow(x,y,w,h);
258 if(!context.accelerated_render(&surface,get_quality(),tile_desc,&super))
260 // For some reason, the accelerated renderer failed.
261 if(cb)cb->error(_("Accelerated Renderer Failure"));
269 if(cb)cb->error(_("Bad surface"));
272 if(get_remove_alpha())
273 for(int i=0;i<surface.get_w()*surface.get_h();i++)
274 surface[0][i]=Color::blend(surface[0][i],desc.get_bg_color(),1.0f);
278 // Add the tile to the target
279 if(!add_tile(surface,x,y))
281 if(cb)cb->error(_("add_tile():Unable to put surface on target"));
284 add_tile_time+=timer();
290 if(cb && !cb->amount_complete(total_tiles,total_tiles))
293 #ifdef SYNFIG_DISPLAY_EFFICIENCY
294 synfig::info(">>>>>> Render Time: %fsec, Find Tile Time: %fsec, Add Tile Time: %fsec, Total Time: %fsec",work_time,find_tile_time,add_tile_time,total_time());
295 synfig::info(">>>>>> FRAME EFFICIENCY: %f%%",(100.0f*work_time/total_time()));
302 synfig::Target_Tile::render(ProgressCallback *cb)
304 SuperCallback super_cb;
319 if(cb) cb->error(_("Target initialization failure"));
324 // If the description's end frame is equal to
325 // the start frame, then it is assumed that we
326 // are rendering only one frame. Correct it.
327 if(desc.get_frame_end()==desc.get_frame_start())
328 desc.set_frame_end(desc.get_frame_start()+1);
330 frame_start=desc.get_frame_start();
331 frame_end=desc.get_frame_end();
332 time_start=desc.get_time_start();
333 time_end=desc.get_time_end();
335 // Calculate the number of frames
336 total_frames=frame_end-frame_start;
344 //synfig::info("1time_set_to %s",t.get_string().c_str());
352 // If we have a callback, and it returns
353 // false, go ahead and bail. (maybe a use cancel)
354 if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
360 // Set the time that we wish to render
361 //if(!get_avoid_time_sync() || canvas->get_time()!=t)
366 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
367 Canvas::Handle op_canvas;
368 if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
370 op_canvas = Canvas::create();
371 op_canvas->set_file_name(canvas->get_file_name());
372 optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
373 context=op_canvas->get_context();
376 context=canvas->get_context();
378 context=canvas->get_context();
382 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
384 Canvas::Handle op_canvas(Canvas::create());
385 op_canvas->set_file_name(canvas->get_file_name());
386 // Set the time that we wish to render
388 optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
389 context=op_canvas->get_context();
392 // Set the time that we wish to render
394 context=canvas->get_context();
398 if(!render_frame_(context,0))
401 }while((i=next_frame(t)));
402 //synfig::info("tilerenderer: i=%d, t=%s",i,t.get_string().c_str());
411 // Set the time that we wish to render
412 // if(!get_avoid_time_sync() || canvas->get_time()!=t)
415 //synfig::info("2time_set_to %s",t.get_string().c_str());
419 #ifdef SYNFIG_OPTIMIZE_LAYER_TREE
420 Canvas::Handle op_canvas;
421 if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
423 op_canvas = Canvas::create();
424 op_canvas->set_file_name(canvas->get_file_name());
425 optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
426 context=op_canvas->get_context();
429 context=canvas->get_context();
431 context=canvas->get_context();
434 if(!render_frame_(context, cb))
442 if(cb)cb->error(_("Caught string :")+str);
445 catch(std::bad_alloc)
447 if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
452 if(cb)cb->error(_("Caught unknown error, rethrowing..."));