source: synfigstudio/trunk/fuentes/src/gui/asyncrenderer.cpp @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 17.7 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file asyncrenderer.cpp
3**      \brief Template File
4**
5**      $Id$
6**
7**      \legal
8**      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9**      Copyright (c) 2007 Chris Moore
10**
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.
15**
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.
20**      \endlegal
21*/
22/* ========================================================================= */
23
24/* === H E A D E R S ======================================================= */
25
26#ifdef USING_PCH
27#       include "pch.h"
28#else
29#ifdef HAVE_CONFIG_H
30#       include <config.h>
31#endif
32
33#include "asyncrenderer.h"
34#include "app.h"
35#include <glibmm/thread.h>
36#include <glibmm/dispatcher.h>
37
38#ifdef HAVE_UNISTD_H
39#include <unistd.h>
40#endif
41
42#ifdef HAVE_SYS_TYPES_H
43#include <sys/types.h>
44#endif
45
46#ifdef HAVE_SYS_WAIT_H
47#include <sys/wait.h>
48#endif
49
50#ifdef HAVE_SIGNAL_H
51#include <signal.h>
52#endif
53
54#include <synfig/general.h>
55#include <ETL/clock>
56
57#include "general.h"
58
59#endif
60
61/* === U S I N G =========================================================== */
62
63using namespace std;
64using namespace etl;
65using namespace synfig;
66using namespace studio;
67
68#define BOREDOM_TIMEOUT         50
69
70#define REJOIN_ON_STOP  1
71
72// The Glib::Dispatcher class is broken as of Glibmm 2.4.5.
73// Defining this macro enables the workaround.
74#define GLIB_DISPATCHER_BROKEN 1
75
76/* === C L A S S E S ======================================================= */
77
78class AsyncTarget_Tile : public synfig::Target_Tile
79{
80public:
81        etl::handle<synfig::Target_Tile> warm_target;
82
83        struct tile_t
84        {
85                Surface surface;
86                int x,y;
87                tile_t(const Surface& surface,int x, int y):
88                        surface(surface),
89                        x(x),y(y)
90                {
91                }
92        };
93        std::list<tile_t> tile_queue;
94        Glib::Mutex mutex;
95
96#ifndef GLIB_DISPATCHER_BROKEN
97        Glib::Dispatcher tile_ready_signal;
98#endif
99        Glib::Cond cond_tile_queue_empty;
100        bool alive_flag;
101
102        sigc::connection ready_connection;
103
104public:
105        AsyncTarget_Tile(etl::handle<synfig::Target_Tile> warm_target):
106                warm_target(warm_target)
107        {
108                set_avoid_time_sync(warm_target->get_avoid_time_sync());
109                set_tile_w(warm_target->get_tile_w());
110                set_tile_h(warm_target->get_tile_h());
111                set_canvas(warm_target->get_canvas());
112                set_quality(warm_target->get_quality());
113                set_alpha_mode(warm_target->get_alpha_mode());
114                set_threads(warm_target->get_threads());
115                set_clipping(warm_target->get_clipping());
116                set_rend_desc(&warm_target->rend_desc());
117                alive_flag=true;
118#ifndef GLIB_DISPATCHER_BROKEN
119                ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready));
120#endif
121        }
122
123        ~AsyncTarget_Tile()
124        {
125                ready_connection.disconnect();
126        }
127        void set_dead()
128        {
129                Glib::Mutex::Lock lock(mutex);
130                alive_flag=false;
131        }
132
133        virtual int total_tiles()const
134        {
135                return warm_target->total_tiles();
136        }
137
138        virtual int next_tile(int& x, int& y)
139        {
140                if(!alive_flag)
141                        return 0;
142
143                return warm_target->next_tile(x,y);
144        }
145
146        virtual int next_frame(Time& time)
147        {
148                if(!alive_flag)
149                        return 0;
150                return warm_target->next_frame(time);
151        }
152
153        virtual bool start_frame(synfig::ProgressCallback *cb=0)
154        {
155                if(!alive_flag)
156                        return false;
157                return warm_target->start_frame(cb);
158        }
159
160        virtual bool add_tile(const synfig::Surface &surface, int gx, int gy)
161        {
162                assert(surface);
163                if(!alive_flag)
164                        return false;
165                Glib::Mutex::Lock lock(mutex);
166                tile_queue.push_back(tile_t(surface,gx,gy));
167                if(tile_queue.size()==1)
168                {
169#ifdef GLIB_DISPATCHER_BROKEN
170                ready_connection=Glib::signal_timeout().connect(
171                        sigc::bind_return(
172                                sigc::mem_fun(*this,&AsyncTarget_Tile::tile_ready),
173                                false
174                        )
175                        ,0
176                );
177#else
178                tile_ready_signal();
179#endif
180                }
181
182                return alive_flag;
183        }
184
185        void tile_ready()
186        {
187                Glib::Mutex::Lock lock(mutex);
188                if(!alive_flag)
189                {
190                        tile_queue.clear();
191                        cond_tile_queue_empty.signal();
192                        return;
193                }
194                while(!tile_queue.empty() && alive_flag)
195                {
196                        tile_t& tile(tile_queue.front());
197
198                        if (getenv("SYNFIG_SHOW_TILE_OUTLINES"))
199                        {
200                                Color red(1,0,0);
201                                tile.surface.fill(red, 0, 0, 1, tile.surface.get_h());
202                                tile.surface.fill(red, 0, 0, tile.surface.get_w(), 1);
203                        }
204
205                        alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
206
207                        tile_queue.pop_front();
208                }
209                cond_tile_queue_empty.signal();
210        }
211
212        virtual void end_frame()
213        {
214#ifdef SINGLE_THREADED
215                if (!single_threaded())
216                {
217#endif
218                        while(alive_flag)
219                        {
220                                Glib::Mutex::Lock lock(mutex);
221                                Glib::TimeVal end_time;
222
223                                end_time.assign_current_time();
224                                end_time.add_microseconds(BOREDOM_TIMEOUT);
225
226                                if(!tile_queue.empty() && alive_flag)
227                                {
228                                        if(cond_tile_queue_empty.timed_wait(mutex,end_time))
229                                                break;
230                                }
231                                else
232                                        break;
233                        }
234#ifdef SINGLE_THREADED
235                }
236#endif
237                Glib::Mutex::Lock lock(mutex);
238                if(!alive_flag)
239                        return;
240                return warm_target->end_frame();
241        }
242};
243
244class AsyncTarget_Cairo_Tile : public synfig::Target_Cairo_Tile
245{
246public:
247        etl::handle<synfig::Target_Cairo_Tile> warm_target;
248       
249        class tile_t
250        {
251        public:
252                cairo_surface_t* surface;
253                int x,y;
254                tile_t(): surface(NULL), x(0), y(0)
255                {
256                }
257                tile_t(cairo_surface_t*& surface_,int x_, int y_)
258                {
259                        if(surface_)
260                                surface=cairo_surface_reference(surface_);
261                        else
262                                surface=surface_;
263                        x=x_;
264                        y=y_;
265                }
266                tile_t(const tile_t &other):
267                surface(cairo_surface_reference(other.surface)),
268                x(other.x),
269                y(other.y)
270                {
271                }
272                ~tile_t()
273                {
274                        if(surface)
275                                cairo_surface_destroy(surface);
276                }
277        };
278        std::list<tile_t> tile_queue;
279        Glib::Mutex mutex;
280       
281#ifndef GLIB_DISPATCHER_BROKEN
282        Glib::Dispatcher tile_ready_signal;
283#endif
284        Glib::Cond cond_tile_queue_empty;
285        bool alive_flag;
286       
287        sigc::connection ready_connection;
288       
289public:
290        AsyncTarget_Cairo_Tile(etl::handle<synfig::Target_Cairo_Tile> warm_target):
291        warm_target(warm_target)
292        {
293                set_avoid_time_sync(warm_target->get_avoid_time_sync());
294                set_tile_w(warm_target->get_tile_w());
295                set_tile_h(warm_target->get_tile_h());
296                set_canvas(warm_target->get_canvas());
297                set_quality(warm_target->get_quality());
298                set_alpha_mode(warm_target->get_alpha_mode());
299                set_threads(warm_target->get_threads());
300                set_clipping(warm_target->get_clipping());
301                set_rend_desc(&warm_target->rend_desc());
302                alive_flag=true;
303#ifndef GLIB_DISPATCHER_BROKEN
304                ready_connection=tile_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Cairo_Tile::tile_ready));
305#endif
306        }
307       
308        ~AsyncTarget_Cairo_Tile()
309        {
310                ready_connection.disconnect();
311        }
312        void set_dead()
313        {
314                Glib::Mutex::Lock lock(mutex);
315                alive_flag=false;
316        }
317       
318        virtual int total_tiles()const
319        {
320                return warm_target->total_tiles();
321        }
322       
323        virtual int next_tile(int& x, int& y)
324        {
325                if(!alive_flag)
326                        return 0;
327               
328                return warm_target->next_tile(x,y);
329        }
330       
331        virtual int next_frame(Time& time)
332        {
333                if(!alive_flag)
334                        return 0;
335                return warm_target->next_frame(time);
336        }
337       
338        virtual bool start_frame(synfig::ProgressCallback *cb=0)
339        {
340                if(!alive_flag)
341                        return false;
342                return warm_target->start_frame(cb);
343        }
344       
345        virtual bool add_tile(cairo_surface_t* surface, int gx, int gy)
346        {
347                if(cairo_surface_status(surface))
348                        return false;
349                if(!alive_flag)
350                        return false;
351                Glib::Mutex::Lock lock(mutex);
352                tile_queue.push_back(tile_t(surface,gx,gy));
353                if(tile_queue.size()==1)
354                {
355#ifdef GLIB_DISPATCHER_BROKEN
356                        ready_connection=Glib::signal_timeout().connect(
357                                        sigc::bind_return(
358                                                        sigc::mem_fun(*this,&AsyncTarget_Cairo_Tile::tile_ready),
359                                                        false
360                                                        )
361                                                        ,0
362                                                );
363#else
364                        tile_ready_signal();
365#endif
366                }
367                //cairo_surface_destroy(surface);
368                return alive_flag;
369        }
370       
371        void tile_ready()
372        {
373                Glib::Mutex::Lock lock(mutex);
374                if(!alive_flag)
375                {
376                        tile_queue.clear();
377                        cond_tile_queue_empty.signal();
378                        return;
379                }
380                while(!tile_queue.empty() && alive_flag)
381                {
382                        tile_t& tile(tile_queue.front());
383                       
384//                      if (getenv("SYNFIG_SHOW_TILE_OUTLINES"))
385//                      {
386//                              Color red(1,0,0);
387//                              tile.surface.fill(red, 0, 0, 1, tile.surface.get_h());
388//                              tile.surface.fill(red, 0, 0, tile.surface.get_w(), 1);
389//                      }
390                       
391                        alive_flag=warm_target->add_tile(tile.surface,tile.x,tile.y);
392                       
393                        tile_queue.pop_front();
394                }
395                cond_tile_queue_empty.signal();
396        }
397       
398        virtual void end_frame()
399        {
400#ifdef SINGLE_THREADED
401                if (!single_threaded())
402                {
403#endif
404                        while(alive_flag)
405                        {
406                                Glib::Mutex::Lock lock(mutex);
407                                Glib::TimeVal end_time;
408                               
409                                end_time.assign_current_time();
410                                end_time.add_microseconds(BOREDOM_TIMEOUT);
411                               
412                                if(!tile_queue.empty() && alive_flag)
413                                {
414                                        if(cond_tile_queue_empty.timed_wait(mutex,end_time))
415                                                break;
416                                }
417                                else
418                                        break;
419                        }
420#ifdef SINGLE_THREADED
421                }
422#endif
423                Glib::Mutex::Lock lock(mutex);
424                if(!alive_flag)
425                        return;
426                return warm_target->end_frame();
427        }
428};
429
430
431
432class AsyncTarget_Scanline : public synfig::Target_Scanline
433{
434public:
435        etl::handle<synfig::Target_Scanline> warm_target;
436
437        int scanline_;
438        Surface surface;
439
440        Glib::Mutex mutex;
441
442#ifndef GLIB_DISPATCHER_BROKEN
443        Glib::Dispatcher frame_ready_signal;
444#endif
445        Glib::Cond cond_frame_queue_empty;
446        bool alive_flag;
447        bool ready_next;
448        sigc::connection ready_connection;
449
450
451public:
452        AsyncTarget_Scanline(etl::handle<synfig::Target_Scanline> warm_target):
453                warm_target(warm_target),
454                scanline_(),
455                alive_flag(),
456                ready_next()
457        {
458                set_avoid_time_sync(warm_target->get_avoid_time_sync());
459                set_canvas(warm_target->get_canvas());
460                set_quality(warm_target->get_quality());
461                set_alpha_mode(warm_target->get_alpha_mode());
462                set_threads(warm_target->get_threads());
463                set_rend_desc(&warm_target->rend_desc());
464                alive_flag=true;
465#ifndef GLIB_DISPATCHER_BROKEN
466                ready_connection=frame_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready));
467#endif
468                surface.set_wh(warm_target->rend_desc().get_w(),warm_target->rend_desc().get_h());
469        }
470
471        ~AsyncTarget_Scanline()
472        {
473                ready_connection.disconnect();
474        }
475
476        virtual int next_frame(Time& time)
477        {
478                if(!alive_flag)
479                        return 0;
480                return warm_target->next_frame(time);
481
482        }
483
484        void set_dead()
485        {
486                Glib::Mutex::Lock lock(mutex);
487                alive_flag=false;
488        }
489
490        virtual bool start_frame(synfig::ProgressCallback */*cb*/=0)
491        {
492                return alive_flag;
493        }
494
495        virtual void end_frame()
496        {
497                {
498                        Glib::Mutex::Lock lock(mutex);
499
500                        if(!alive_flag)
501                                return;
502                        ready_next=false;
503
504#ifdef GLIB_DISPATCHER_BROKEN
505                ready_connection=Glib::signal_timeout().connect(
506                        sigc::bind_return(
507                                sigc::mem_fun(*this,&AsyncTarget_Scanline::frame_ready),
508                                false
509                        )
510                        ,0
511                );
512#else
513                        frame_ready_signal();
514#endif
515                }
516
517#ifdef SINGLE_THREADED
518                if (single_threaded())
519                        signal_progress()();
520                else
521#endif
522                {
523
524                        Glib::TimeVal end_time;
525
526                        end_time.assign_current_time();
527                        end_time.add_microseconds(BOREDOM_TIMEOUT);
528
529                        while(alive_flag && !ready_next)
530                        {
531                                Glib::Mutex::Lock lock(mutex);
532                                if(cond_frame_queue_empty.timed_wait(mutex, end_time))
533                                        break;
534                        }
535                }
536        }
537
538
539        virtual Color * start_scanline(int scanline)
540        {
541                Glib::Mutex::Lock lock(mutex);
542
543                return surface[scanline];
544        }
545
546        virtual bool end_scanline()
547        {
548                return alive_flag;
549        }
550
551        void frame_ready()
552        {
553                Glib::Mutex::Lock lock(mutex);
554                if(alive_flag)
555                        alive_flag=warm_target->add_frame(&surface);
556#ifdef SINGLE_THREADED
557                if (!single_threaded())
558#endif
559                        cond_frame_queue_empty.signal();
560                ready_next=true;
561        }
562};
563
564class AsyncTarget_Cairo : public synfig::Target_Cairo
565{
566public:
567        etl::handle<synfig::Target_Cairo> warm_target;
568       
569        cairo_surface_t* surface;
570        ProgressCallback *callback;
571       
572        Glib::Mutex mutex;
573       
574#ifndef GLIB_DISPATCHER_BROKEN
575        Glib::Dispatcher frame_ready_signal;
576#endif
577        Glib::Cond cond_frame_queue_empty;
578        bool alive_flag;
579        bool ready_next;
580        sigc::connection ready_connection;
581       
582       
583public:
584        AsyncTarget_Cairo(etl::handle<synfig::Target_Cairo> warm_target):
585                warm_target(warm_target),
586                surface(),
587                callback(),
588                alive_flag(),
589                ready_next()
590        {
591                set_avoid_time_sync(warm_target->get_avoid_time_sync());
592                set_canvas(warm_target->get_canvas());
593                set_quality(warm_target->get_quality());
594                set_alpha_mode(warm_target->get_alpha_mode());
595                set_rend_desc(&warm_target->rend_desc());
596                alive_flag=true;
597#ifndef GLIB_DISPATCHER_BROKEN
598                ready_connection=frame_ready_signal.connect(sigc::mem_fun(*this,&AsyncTarget_Cairo::frame_ready));
599#endif
600        }
601       
602        ~AsyncTarget_Cairo()
603        {
604                ready_connection.disconnect();
605        }
606       
607        virtual int next_frame(Time& time)
608        {
609                Glib::Mutex::Lock lock(mutex);
610                if(!alive_flag)
611                        return 0;
612                return warm_target->next_frame(time);
613               
614        }
615       
616        void set_dead()
617        {
618                Glib::Mutex::Lock lock(mutex);
619                alive_flag=false;
620        }
621               
622        virtual bool put_surface(cairo_surface_t* s, ProgressCallback *cb)
623        {
624                {
625                        Glib::Mutex::Lock lock(mutex);
626                        surface=s;
627                        callback=cb;
628                        if(!alive_flag)
629                                return false;
630                        ready_next=false;
631                       
632#ifdef GLIB_DISPATCHER_BROKEN
633                        ready_connection=Glib::signal_timeout().connect(
634                                                        sigc::bind_return(sigc::mem_fun(*this,&AsyncTarget_Cairo::frame_ready),false)
635                                                                                        ,0
636                                                                                        );
637#else
638                        frame_ready_signal();
639#endif
640                }
641               
642#ifdef SINGLE_THREADED
643                if (single_threaded())
644                        signal_progress()();
645                else
646#endif
647                {
648                       
649                        Glib::TimeVal end_time;
650                       
651                        end_time.assign_current_time();
652                        end_time.add_microseconds(BOREDOM_TIMEOUT);
653                       
654                        while(alive_flag && !ready_next)
655                        {
656                                Glib::Mutex::Lock lock(mutex);
657                                if(cond_frame_queue_empty.timed_wait(mutex, end_time))
658                                        break;
659                        }
660                }
661                return true;
662        }
663       
664        void frame_ready()
665        {
666                Glib::Mutex::Lock lock(mutex);
667                if(alive_flag)
668                        alive_flag=warm_target->put_surface(surface, callback);
669#ifdef SINGLE_THREADED
670                if (!single_threaded())
671#endif
672                        cond_frame_queue_empty.signal();
673                ready_next=true;
674        }
675
676        virtual bool obtain_surface(cairo_surface_t*& s)
677        {
678                Glib::Mutex::Lock lock(mutex);
679                if(!alive_flag)
680                        return false;
681                return warm_target->obtain_surface(s);
682        }
683
684};
685
686
687/* === G L O B A L S ======================================================= */
688
689/* === P R O C E D U R E S ================================================= */
690
691/* === M E T H O D S ======================================================= */
692
693AsyncRenderer::AsyncRenderer(etl::handle<synfig::Target> target_,synfig::ProgressCallback *cb):
694        error(false),
695        success(false),
696        cb(cb),
697#ifdef SINGLE_THREADED
698        updating(false),
699#endif
700        start_time(0, 0),
701        finish_time(0, 0)
702{
703        render_thread=0;
704        if(etl::handle<synfig::Target_Tile>::cast_dynamic(target_))
705        {
706                etl::handle<AsyncTarget_Tile> wrap_target(
707                        new AsyncTarget_Tile(etl::handle<synfig::Target_Tile>::cast_dynamic(target_))
708                );
709
710                signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Tile::set_dead));
711
712                target=wrap_target;
713        }
714        else if(etl::handle<synfig::Target_Scanline>::cast_dynamic(target_))
715        {
716                etl::handle<AsyncTarget_Scanline> wrap_target(
717                        new AsyncTarget_Scanline(
718                                etl::handle<synfig::Target_Scanline>::cast_dynamic(target_)
719                        )
720                );
721
722                signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Scanline::set_dead));
723
724                target=wrap_target;
725        }
726        else if(etl::handle<synfig::Target_Cairo_Tile>::cast_dynamic(target_))
727        {
728                etl::handle<AsyncTarget_Cairo_Tile> wrap_target(
729                        new AsyncTarget_Cairo_Tile(
730                                        etl::handle<synfig::Target_Cairo_Tile>::cast_dynamic(target_)
731                        )
732                );
733               
734                signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Cairo_Tile::set_dead));
735               
736                target=wrap_target;
737        }
738
739        else if(etl::handle<synfig::Target_Cairo>::cast_dynamic(target_))
740        {
741                etl::handle<AsyncTarget_Cairo> wrap_target(
742                        new AsyncTarget_Cairo(
743                                etl::handle<synfig::Target_Cairo>::cast_dynamic(target_)
744                        )
745                );
746               
747                signal_stop_.connect(sigc::mem_fun(*wrap_target,&AsyncTarget_Cairo::set_dead));
748               
749                target=wrap_target;
750        }
751
752}
753
754AsyncRenderer::~AsyncRenderer()
755{
756        stop();
757}
758
759void
760AsyncRenderer::stop()
761{
762        if(target)
763        {
764                Glib::Mutex::Lock lock(mutex);
765                done_connection.disconnect();
766
767                if(render_thread)
768                {
769                        signal_stop_();
770
771#if REJOIN_ON_STOP
772#ifdef SINGLE_THREADED
773                        if (!single_threaded())
774#endif
775                                render_thread->join();
776#endif
777                        finish_time.assign_current_time();
778
779
780                        // Make sure all the dispatch crap is cleared out
781                        //Glib::MainContext::get_default()->iteration(false);
782
783                        if(success)
784                                signal_success_();
785
786                        target=0;
787                        render_thread=0;
788                       
789                        lock.release();
790                       
791                        signal_finished_();
792                }
793        }
794}
795
796void
797AsyncRenderer::pause()
798{
799}
800
801void
802AsyncRenderer::resume()
803{
804}
805
806void
807AsyncRenderer::start()
808{
809        start_time.assign_current_time();
810        finish_time = start_time;
811        done_connection=Glib::signal_timeout().connect(
812                sigc::bind_return(
813                        mem_fun(*this,&AsyncRenderer::start_),
814                        false
815                )
816                , 0
817        );
818}
819
820#ifdef SINGLE_THREADED
821void
822AsyncRenderer::rendering_progress()
823{
824        updating = true;
825        while(studio::App::events_pending()) studio::App::iteration(false);
826        updating = false;
827}
828#endif
829
830void
831AsyncRenderer::start_()
832{
833        error=false;success=false;
834        if(target)
835        {
836#ifndef GLIB_DISPATCHER_BROKEN
837                done_connection=signal_done_.connect(mem_fun(*this,&AsyncRenderer::stop));
838#endif
839
840#ifdef SINGLE_THREADED
841                if (single_threaded())
842                {
843                        //synfig::info("%s:%d rendering in the same thread", __FILE__, __LINE__);
844                        target->signal_progress().connect(sigc::mem_fun(this,&AsyncRenderer::rendering_progress));
845                        render_thread = (Glib::Thread*)1;
846                        render_target();
847                }
848                else
849#endif
850                {
851                        render_thread=Glib::Thread::create(
852                                sigc::mem_fun(*this,&AsyncRenderer::render_target),
853#if REJOIN_ON_STOP
854                                true
855#else
856                                false
857#endif
858                                );
859                        assert(render_thread);
860                }
861        }
862        else
863        {
864                stop();
865        }
866}
867
868void
869AsyncRenderer::render_target()
870{
871        etl::handle<Target> target(AsyncRenderer::target);
872
873        if(target && target->render())
874        {
875                success=true;
876        }
877        else
878        {
879                error=true;
880#ifndef REJOIN_ON_STOP
881                return;
882#endif
883        }
884
885        if(mutex.trylock())
886        {
887#ifdef GLIB_DISPATCHER_BROKEN
888                done_connection=Glib::signal_timeout().connect(
889                        sigc::bind_return(
890                                mem_fun(*this,&AsyncRenderer::stop),
891                                false
892                        )
893                        ,0
894                );
895#else
896                signal_done_.emit();
897#endif
898                mutex.unlock();
899        }
900}
Note: See TracBrowser for help on using the repository browser.