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