1 /**************************************************************************/
2 /*  Copyright 2012 Tim Day                                                */
3 /*                                                                        */
4 /*  This file is part of Evolvotron                                       */
5 /*                                                                        */
6 /*  Evolvotron is free software: you can redistribute it and/or modify    */
7 /*  it under the terms of the GNU General Public License as published by  */
8 /*  the Free Software Foundation, either version 3 of the License, or     */
9 /*  (at your option) any later version.                                   */
10 /*                                                                        */
11 /*  Evolvotron is distributed in the hope that it will be useful,         */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
14 /*  GNU General Public License for more details.                          */
15 /*                                                                        */
16 /*  You should have received a copy of the GNU General Public License     */
17 /*  along with Evolvotron.  If not, see <http://www.gnu.org/licenses/>.   */
18 /**************************************************************************/
19 
20 /*! \file
21   \brief Implementation of class MutatableImageComputer.
22 */
23 
24 #include "mutatable_image_computer.h"
25 
26 #include "mutatable_image.h"
27 #include "mutatable_image_computer_farm.h"
28 #include "mutatable_image_computer_task.h"
29 
30 #include "platform_specific.h"
31 
MutatableImageComputer(MutatableImageComputerFarm * frm,int niceness)32 MutatableImageComputer::MutatableImageComputer(MutatableImageComputerFarm* frm,int niceness)
33   :_farm(frm)
34   ,_niceness(niceness)
35   ,_r01(23)  // Seed pretty unimportant; only used for sample jitter
36 {
37   start();
38 }
39 
~MutatableImageComputer()40 MutatableImageComputer::~MutatableImageComputer()
41 {
42   std::clog << "Deleting a computer...\n";
43 
44   kill();
45   wait();
46 
47   _task.reset();
48 
49   std::clog << "...deleted a computer\n";
50 }
51 
52 /*! Compute threads run this method until killed (probably by the destructor being invoked by the original spawning thread.
53  */
run()54 void MutatableImageComputer::run()
55 {
56   std::clog << "Thread starting\n";
57 
58   // Lower compute thread priority slightly; computing yet more stuff
59   // is less important than displaying the results we've got so far.
60   add_thread_niceness(_niceness);
61 
62   // Run until something sets the kill flag
63   while(!communications().kill())
64     {
65       // If we don't have a task try and get one.  This will block or return null.
66       if (task()==0)
67 	{
68 	  _task=farm()->pop_todo(*this);
69 	}
70 
71       if (task())
72 	{
73 	  // Careful, we could be given an already aborted task
74 	  if (!task()->aborted())
75 	    {
76 	      while (!communications().kill_or_abort_or_defer() && !task()->completed())
77 		{
78 		  XYZ accumulated_colour=task()->image_function()->get_rgb
79 		    (
80 		     task()->fragment_origin().width()+task()->current_col(),
81 		     task()->fragment_origin().height()+task()->current_row(),
82 		     task()->current_frame(),
83 		     task()->whole_image_size().width(),
84 		     task()->whole_image_size().height(),
85 		     task()->frames(),
86 		     (task()->jittered_samples() ? &_r01 : 0),
87 		     task()->multisample_grid()
88 		     );
89 
90 		  const uint col0=lrint(accumulated_colour.x());
91 		  const uint col1=lrint(accumulated_colour.y());
92 		  const uint col2=lrint(accumulated_colour.z());
93 
94 		  task()->images()[task()->current_frame()].setPixel(task()->current_col(),task()->current_row(),((col0<<16)|(col1<<8)|(col2)));
95 
96 		  task()->pixel_advance();
97 		}
98 	    }
99 
100 	  // Maybe should capture copies of the flags for use here
101 	  if (!communications().kill())
102 	    {
103 	      if (communications().defer() && !communications().abort())
104 		{
105 		  farm()->push_todo(task());
106 		  communications().defer(false);
107 		  _task.reset();
108 		}
109 	      else
110 		{
111 		  if (communications().abort())
112 		    {
113 		      task()->abort();
114 		    }
115 
116 		  communications().defer(false);
117 		  communications().abort(false);
118 
119 		  farm()->push_done(task());
120 		  _task.reset();
121 		}
122 	    }
123 	}
124     }
125   std::clog << "Thread shutting down\n";
126 }
127 
defer_if_less_important_than(uint pri)128 bool MutatableImageComputer::defer_if_less_important_than(uint pri)
129 {
130   const boost::shared_ptr<const MutatableImageComputerTask> task_tmp=_task;
131   if (task_tmp && task_tmp->priority()>pri)
132     {
133       communications().defer(true);
134       return true;
135     }
136   else
137     {
138       return false;
139     }
140 }
141 
abort()142 void MutatableImageComputer::abort()
143 {
144   communications().abort(true);
145 }
146 
abort_for(const MutatableImageDisplay * disp)147 void MutatableImageComputer::abort_for(const MutatableImageDisplay* disp)
148 {
149   if (task()!=0 && task()->display()==disp)
150     {
151       communications().abort(true);
152     }
153 }
154 
kill()155 void MutatableImageComputer::kill()
156 {
157   communications().kill(true);
158 }
159 
killed() const160 bool MutatableImageComputer::killed() const
161 {
162   return communications().kill();
163 }
164