1 /*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 /*
18 The original source for this example is
19 Copyright (c) 1994-2008 John E. Stone
20 All rights reserved.
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions
24 are met:
25 1. Redistributions of source code must retain the above copyright
26 notice, this list of conditions and the following disclaimer.
27 2. Redistributions in binary form must reproduce the above copyright
28 notice, this list of conditions and the following disclaimer in the
29 documentation and/or other materials provided with the distribution.
30 3. The name of the author may not be used to endorse or promote products
31 derived from this software without specific prior written permission.
32
33 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 SUCH DAMAGE.
44 */
45
46 #include "machine.h"
47 #include "types.h"
48 #include "macros.h"
49 #include "vector.h"
50 #include "tgafile.h"
51 #include "trace.h"
52 #include "light.h"
53 #include "shade.h"
54 #include "camera.h"
55 #include "util.h"
56 #include "intersect.h"
57 #include "global.h"
58 #include "ui.h"
59 #include "tachyon_video.h"
60
61 // shared but read-only so could be private too
62 static thr_parms *all_parms;
63 static scenedef scene;
64 static int startx;
65 static int stopx;
66 static int starty;
67 static int stopy;
68 static flt jitterscale;
69 static int totaly;
70
71 #ifdef MARK_RENDERING_AREA
72
73 // rgb colors list for coloring image by each thread
74 static const float inner_alpha = 0.3;
75 static const float border_alpha = 0.5;
76 #define NUM_COLORS 24
77 static int colors[NUM_COLORS][3] = {
78 {255,110,0}, {220,254,0}, {102,254,0}, {0,21,254}, {97,0,254}, {254,30,0},
79 {20,41,8}, {144,238,38}, {184,214,139}, {28,95,20}, {139,173,148}, {188,228,183},
80 {145,47,56}, {204,147,193}, {45,202,143}, {204,171,143}, {143,160,204}, {220,173,3},
81 {1,152,231}, {79,235,237}, {52,193,72}, {67,136,151}, {78,87,179}, {143,255,9},
82 };
83
84 #include <atomic>
85 #include "tbb/enumerable_thread_specific.h"
86 // storage and counter for thread numbers in order of first task run
87 typedef tbb::enumerable_thread_specific< int > thread_id_t;
88 thread_id_t thread_ids (-1);
89 std::atomic<int> thread_number;
90
91 #endif
92
93 #include "tbb/parallel_for.h"
94 #include "tbb/spin_mutex.h"
95 #include "tbb/blocked_range2d.h"
96 #include "tbb/global_control.h"
97 #include "../../../common/utility/get_default_num_threads.h"
98
99 static tbb::spin_mutex MyMutex, MyMutex2;
100
render_one_pixel(int x,int y,unsigned int * local_mbox,unsigned int & serial,int startx,int stopx,int starty,int stopy,int * blend,float alpha)101 static color_t render_one_pixel (int x, int y, unsigned int *local_mbox, unsigned int &serial,
102 int startx, int stopx, int starty, int stopy
103 #ifdef MARK_RENDERING_AREA
104 , int *blend, float alpha
105 #endif
106 )
107 {
108 /* private vars moved inside loop */
109 ray primary, sample;
110 color col, avcol;
111 int R,G,B;
112 intersectstruct local_intersections;
113 int alias;
114 /* end private */
115
116 primary=camray(&scene, x, y);
117 primary.intstruct = &local_intersections;
118 primary.flags = RT_RAY_REGULAR;
119
120 serial++;
121 primary.serial = serial;
122 primary.mbox = local_mbox;
123 primary.maxdist = FHUGE;
124 primary.scene = &scene;
125 col=trace(&primary);
126
127 serial = primary.serial;
128
129 /* perform antialiasing if enabled.. */
130 if (scene.antialiasing > 0) {
131 for (alias=0; alias < scene.antialiasing; alias++) {
132
133 serial++; /* increment serial number */
134 sample=primary; /* copy the regular primary ray to start with */
135 sample.serial = serial;
136
137 {
138 tbb::spin_mutex::scoped_lock lock (MyMutex);
139 sample.d.x+=((rand() % 100) - 50) / jitterscale;
140 sample.d.y+=((rand() % 100) - 50) / jitterscale;
141 sample.d.z+=((rand() % 100) - 50) / jitterscale;
142 }
143
144 avcol=trace(&sample);
145
146 serial = sample.serial; /* update our overall serial # */
147
148 col.r += avcol.r;
149 col.g += avcol.g;
150 col.b += avcol.b;
151 }
152
153 col.r /= (scene.antialiasing + 1.0);
154 col.g /= (scene.antialiasing + 1.0);
155 col.b /= (scene.antialiasing + 1.0);
156 }
157
158 /* Handle overexposure and underexposure here... */
159 R=(int) (col.r*255);
160 if (R > 255) R = 255;
161 else if (R < 0) R = 0;
162
163 G=(int) (col.g*255);
164 if (G > 255) G = 255;
165 else if (G < 0) G = 0;
166
167 B=(int) (col.b*255);
168 if (B > 255) B = 255;
169 else if (B < 0) B = 0;
170
171 #ifdef MARK_RENDERING_AREA
172 R = int((1.0 - alpha) * R + alpha * blend[0]);
173 G = int((1.0 - alpha) * G + alpha * blend[1]);
174 B = int((1.0 - alpha) * B + alpha * blend[2]);
175 #endif
176
177 return video->get_color(R, G, B);
178 }
179
180 class parallel_task {
181 public:
operator ()(const tbb::blocked_range2d<int> & r) const182 void operator() (const tbb::blocked_range2d<int> &r) const
183 {
184 // task-local storage
185 unsigned int serial = 1;
186 unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
187 unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
188 memset(local_mbox,0,mboxsize);
189 #ifdef MARK_RENDERING_AREA
190 // compute thread number while first task run
191 thread_id_t::reference thread_id = thread_ids.local();
192 if (thread_id == -1) thread_id = thread_number++;
193 // choose thread color
194 int pos = thread_id % NUM_COLORS;
195 if(video->running) {
196 drawing_area drawing(r.cols().begin(), totaly-r.rows().end(), r.cols().end() - r.cols().begin(), r.rows().end()-r.rows().begin());
197 for (int i = 1, y = r.rows().begin(); y != r.rows().end(); ++y, i++) {
198 drawing.set_pos(0, drawing.size_y-i);
199 for (int x = r.cols().begin(); x != r.cols().end(); x++) {
200 int d = (y % 3 == 0) ? 2 : 1;
201 drawing.put_pixel(video->get_color(colors[pos][0]/d, colors[pos][1]/d, colors[pos][2]/d));
202 }
203 }
204 }
205 #endif
206 if(video->next_frame()) {
207 drawing_area drawing(r.cols().begin(), totaly-r.rows().end(), r.cols().end() - r.cols().begin(), r.rows().end()-r.rows().begin());
208 for (int i = 1, y = r.rows().begin(); y != r.rows().end(); ++y, i++) {
209 drawing.set_pos(0, drawing.size_y-i);
210 for (int x = r.cols().begin(); x != r.cols().end(); x++) {
211 #ifdef MARK_RENDERING_AREA
212 float alpha = y==r.rows().begin()||y==r.rows().end()-1||x==r.cols().begin()||x==r.cols().end()-1
213 ? border_alpha : inner_alpha;
214 color_t c = render_one_pixel (x, y, local_mbox, serial, startx, stopx, starty, stopy, colors[pos], alpha);
215 #else
216 color_t c = render_one_pixel (x, y, local_mbox, serial, startx, stopx, starty, stopy);
217 #endif
218 drawing.put_pixel(c);
219 }
220 }
221 }
222 }
223
parallel_task()224 parallel_task () {}
225 };
226
thread_trace(thr_parms * parms)227 void * thread_trace(thr_parms * parms)
228 {
229 #if !WIN8UI_EXAMPLE
230 int n, nthreads = utility::get_default_num_threads();
231 char *nthreads_str = getenv ("TBB_NUM_THREADS");
232 if (nthreads_str && (sscanf (nthreads_str, "%d", &n) > 0) && (n > 0)) nthreads = n;
233 tbb::global_control c(tbb::global_control::max_allowed_parallelism, nthreads);
234 #endif
235
236 // shared but read-only so could be private too
237 all_parms = parms;
238 scene = parms->scene;
239 startx = parms->startx;
240 stopx = parms->stopx;
241 starty = parms->starty;
242 stopy = parms->stopy;
243 jitterscale = 40.0*(scene.hres + scene.vres);
244 totaly = parms->scene.vres;
245 #ifdef MARK_RENDERING_AREA
246 thread_ids.clear();
247 #endif
248
249 int grain_size = 8;
250 //WIN8UI does not support getenv() function so using auto_partitioner unconditionally
251 #if !WIN8UI_EXAMPLE
252 int g;
253 char *grain_str = getenv ("TBB_GRAINSIZE");
254 if (grain_str && (sscanf (grain_str, "%d", &g) > 0) && (g > 0)) grain_size = g;
255 char *sched_str = getenv ("TBB_PARTITIONER");
256 static tbb::affinity_partitioner g_ap; // reused across calls to thread_trace
257 if ( sched_str && !strncmp(sched_str, "aff", 3) )
258 tbb::parallel_for (tbb::blocked_range2d<int> (starty, stopy, grain_size, startx, stopx, grain_size), parallel_task (), g_ap);
259 else if ( sched_str && !strncmp(sched_str, "simp", 4) )
260 tbb::parallel_for (tbb::blocked_range2d<int> (starty, stopy, grain_size, startx, stopx, grain_size), parallel_task (), tbb::simple_partitioner());
261 else
262 #endif
263 tbb::parallel_for (tbb::blocked_range2d<int> (starty, stopy, grain_size, startx, stopx, grain_size), parallel_task (), tbb::auto_partitioner());
264
265 return(NULL);
266 }
267