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