Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Side by Side Diff: ppapi/native_client/tests/earth/earth.cc

Issue 7920012: Add missing NaCl PPAPI test components to Chrome repo. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ppapi/native_client/tests/earth/earth.h ('k') | ppapi/native_client/tests/earth/earth_c.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 // NaCl Earth demo
8 // Ray trace planet Earth
9
10 #include "native_client/tests/earth/earth.h"
11
12 #include <assert.h>
13 #include <errno.h>
14 #include <math.h>
15 #include <pthread.h>
16 #include <semaphore.h>
17 #include <stdarg.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #define HAVE_THREADS 1
25 #include "native_client/common/worker.h"
26
27 // print/debug messages
28 static void InfoPrintf(const char *fmt, ...) {
29 va_list argptr;
30 va_start (argptr, fmt);
31 vfprintf (stderr, fmt, argptr);
32 va_end (argptr);
33 fflush(stderr);
34 }
35
36 extern "C" void DebugPrintf(const char *fmt, ...) {
37 va_list argptr;
38 fprintf (stderr, "@@@ EARTH ");
39
40 va_start (argptr, fmt);
41 vfprintf (stderr, fmt, argptr);
42 va_end (argptr);
43 fflush(stderr);
44 }
45
46 // global properties
47 const float kPI = M_PI;
48 const float kOneOverPI = 1.0f / kPI;
49 const float kOneOver2PI = 1.0f / (2.0f * kPI);
50 const float kOneOver255 = 1.0f / 255.0f;
51 const int kArcCosineTableSize = 4096;
52 const float kMaxWindow = 4096;
53 const int kEarthTextureWidth = 1024;
54 const int kEarthTextureHeight = 512;
55 const int kMaxFrames = 1000000;
56 const int kRegionRatio = 8;
57 int g_window_width = 512;
58 int g_window_height = 512;
59 int g_num_frames = 300;
60 bool g_ask_sysconf = true;
61 int g_num_threads = 4; // possibly overridden by sysconf()
62 int g_num_regions = 4; // possibly overridden by sysconf()
63 bool g_multi_threading = false; // can be overridden on cmd line
64
65 int g_frame_checksum = 0; // used for nacl module testing
66
67 // seed for rand_r() - we only call rand_r from main thread.
68 static unsigned int g_seed = 0xC0DE533D;
69
70 // random number helper
71 inline unsigned char rand255() {
72 return static_cast<unsigned char>(rand_r(&g_seed) & 255);
73 }
74
75 // random number helper
76 inline float frand() {
77 return (static_cast<float>(rand_r(&g_seed)) / static_cast<float>(RAND_MAX));
78 }
79
80 // build a packed color
81 inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
82 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
83 }
84
85 // extraction routines
86 inline float ExtractR(uint32_t c) {
87 return static_cast<float>(c & 0xFF) * kOneOver255;
88 }
89
90 inline float ExtractG(uint32_t c) {
91 return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255;
92 }
93
94 inline float ExtractB(uint32_t c) {
95 return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
96 }
97
98
99 // simple container for earth texture
100 struct Texture {
101 int width, height;
102 unsigned int pixels[kEarthTextureWidth * kEarthTextureHeight];
103 };
104
105
106 // compile our texture straight in to avoid runtime filesystem
107 Texture g_earth = {
108 kEarthTextureWidth, kEarthTextureHeight, {
109 #include "native_client/tests/earth/earth_image.inc"
110 }
111 };
112
113
114 struct Surface {
115 int width, height, pitch;
116 uint32_t *pixels;
117 Surface(uint32_t *pix, int w, int h) {
118 width = w;
119 height = h;
120 pitch = w;
121 pixels = pix;
122 }
123 };
124
125
126 struct ArcCosine {
127 // slightly larger table so we can interpolate beyond table size
128 float table[kArcCosineTableSize + 2];
129 float TableLerp(float x);
130 ArcCosine();
131 ~ArcCosine() { ; }
132 };
133
134
135 ArcCosine::ArcCosine() {
136 // build a slightly larger table to allow for numeric imprecision
137 for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
138 float f = static_cast<float>(i) / kArcCosineTableSize;
139 f = f * 2.0f - 1.0f;
140 table[i] = acos(f);
141 }
142 }
143
144
145 // looks up acos(f) using a table and lerping between entries
146 // (it is expected that input f is between -1 and 1)
147 float ArcCosine::TableLerp(float f) {
148 float x = (f + 1.0f) * 0.5f;
149 x = x * kArcCosineTableSize;
150 int ix = static_cast<int>(x);
151 float fx = static_cast<float>(ix);
152 float dx = x - fx;
153 float af = table[ix];
154 float af2 = table[ix + 1];
155 float a = af + (af2 - af) * dx;
156 return a;
157 }
158
159
160 // takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
161 inline unsigned int Clamp255(float x) {
162 if (x < 0.0f) {
163 x = 0.0f;
164 } else if (x > 1.0f) {
165 x = 1.0f;
166 }
167 return (unsigned int)(x * 255.0f);
168 }
169
170
171 // Planet class holds information and functionality needed to render
172 // a ray-traced planet into an raw pixel surface
173 class Planet {
174 float planet_radius_;
175 float planet_spin_;
176 float planet_x_, planet_y_, planet_z_;
177 float planet_pole_x_, planet_pole_y_, planet_pole_z_;
178 float planet_equator_x_, planet_equator_y_, planet_equator_z_;
179 float eye_x_, eye_y_, eye_z_;
180 float light_x_, light_y_, light_z_;
181 float diffuse_r_, diffuse_g_, diffuse_b_;
182 float ambient_r_, ambient_g_, ambient_b_;
183
184 // cached calculations
185 float planet_xyz_;
186 float planet_pole_x_equator_x_;
187 float planet_pole_x_equator_y_;
188 float planet_pole_x_equator_z_;
189 float planet_radius2_;
190 float planet_one_over_radius_;
191 float eye_xyz_;
192
193 // misc
194 Texture *tex_;
195 Surface surface_;
196 ArcCosine acos_;
197 int num_regions_;
198 WorkerThreadManager *workers_;
199 volatile bool exiting_;
200 bool rendering_;
201
202 public:
203
204 // methods prefixed with 'w' are only called by worker threads!
205 // (unless MULTI_THREADING is false)
206 uint32_t* wGetAddr(int x, int y);
207 void wRenderPixelSpan(int x0, int x1, int y);
208 void wMakeRect(int r, int *x, int *y, int *w, int *h);
209 void wRenderRect(int x0, int y0, int x1, int y1);
210 void wWorkerThreadEntry();
211
212 // these methods are only called by the main thread
213 void CacheCalcs();
214 void SetPlanetXYZR(float x, float y, float z, float r);
215 void SetPlanetPole(float x, float y, float z);
216 void SetPlanetEquator(float x, float y, float z);
217 void SetPlanetSpin(float a);
218 void SetEyeXYZ(float x, float y, float z);
219 void SetLightXYZ(float x, float y, float z);
220 void SetAmbientRGB(float r, float g, float b);
221 void SetDiffuseRGB(float r, float g, float b);
222 void SetSurface(Surface surface);
223 bool CreateWorkerThreads(int num);
224 void UpdateSim();
225 void ParallelRender();
226 void ParallelRenderSync();
227 void SequentialRender();
228 void Render();
229 void Sync();
230 Planet(int numRegions, bool multithreading, Texture *tex);
231 ~Planet();
232 };
233
234 // Given a region r, derive a rectangle. Currently this function
235 // slices the main output buffer into equal sized rows.
236 // This function is used to convert a mutex guarded counter into
237 // a rectangular region for a given worker thread to process.
238 // This rectangle shouldn't overlap with work being done by other workers.
239 // If multithreading, this function is only called by the worker threads.
240 void Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
241 int dy = surface_.height / num_regions_;
242 *x = 0;
243 *w = surface_.width;
244 *y = r * dy;
245 *h = dy;
246 }
247
248
249 inline uint32_t* Planet::wGetAddr(int x, int y) {
250 assert(surface_.pixels);
251 return (surface_.pixels + y * surface_.pitch) + x;
252 }
253
254
255 union Convert {
256 float f;
257 int i;
258 Convert(int x) { i = x; }
259 Convert(float x) { f = x; }
260 const int asInt() { return i; }
261 const float asFloat() { return f; }
262 };
263
264
265 inline const int AsInteger(const float f) {
266 Convert u(f);
267 return u.asInt();
268 }
269
270
271 inline const float AsFloat(const int i) {
272 Convert u(i);
273 return u.asFloat();
274 }
275
276
277 const long int kOneAsInteger = AsInteger(1.0f);
278 const float kScaleUp = float(0x00800000);
279 const float kScaleDown = 1.0f / kScaleUp;
280
281
282 inline float inline_quick_sqrt(float x) {
283 int i;
284 i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
285 return AsFloat(i);
286 }
287
288
289 inline float inline_sqrt(float x) {
290 float y;
291 y = inline_quick_sqrt(x);
292 y = (y * y + x) / (2.0f * y);
293 y = (y * y + x) / (2.0f * y);
294 return y;
295 }
296
297
298 // This is the meat of the ray tracer. Given a pixel span (x0, x1) on
299 // scanline y, shoot rays into the scene and render what they hit. Use
300 // scanline coherence to do a few optimizations
301 void Planet::wRenderPixelSpan(int x0, int x1, int y) {
302 const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
303 float y0 = eye_y_;
304 float z0 = eye_z_;
305 float y1 = (static_cast<float>(y) / surface_.height) * 2.0f - 1.0f;
306 float z1 = 0.0f;
307 float dy = (y1 - y0);
308 float dz = (z1 - z0);
309 float dy_dy_dz_dz = dy * dy + dz * dz;
310 float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) +
311 2.0f * dz * (z0 - planet_z_);
312 float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
313 float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
314 float oowidth = 1.0f / surface_.width;
315 uint32_t *pixels = this->wGetAddr(x0, y);
316 for (int x = x0; x <= x1; ++x) {
317 // scan normalized screen -1..1
318 float x1 = (static_cast<float>(x) * oowidth) * 2.0f - 1.0f;
319 // eye
320 float x0 = eye_x_;
321 // delta from screen to eye
322 float dx = (x1 - x0);
323 // build a, b, c
324 float a = dx * dx + dy_dy_dz_dz;
325 float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
326 float c = planet_xyz_eye_xyz +
327 -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
328 // calculate discriminant
329 float disc = b * b - 4.0f * a * c;
330
331 // did ray hit the sphere?
332 if (disc < 0.0f) {
333 *pixels = kColorBlack;
334 ++pixels;
335 continue;
336 }
337
338 // calc parametric t value
339 float t = (-b - inline_sqrt(disc)) / (2.0f * a);
340 float px = x0 + t * dx;
341 float py = y0 + t * dy;
342 float pz = z0 + t * dz;
343 float nx = (px - planet_x_) * planet_one_over_radius_;
344 float ny = (py - planet_y_) * planet_one_over_radius_;
345 float nz = (pz - planet_z_) * planet_one_over_radius_;
346
347 float Lx = (light_x_ - px);
348 float Ly = (light_y_ - py);
349 float Lz = (light_z_ - pz);
350 float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz);
351 Lx *= Lq;
352 Ly *= Lq;
353 Lz *= Lq;
354 float d = (Lx * nx + Ly * ny + Lz * nz);
355 float pr = (diffuse_r_ * d) + ambient_r_;
356 float pg = (diffuse_g_ * d) + ambient_g_;
357 float pb = (diffuse_b_ * d) + ambient_b_;
358 float ds = -(nx * planet_pole_x_ +
359 ny * planet_pole_y_ +
360 nz * planet_pole_z_);
361 float ang = acos_.TableLerp(ds);
362 float v = ang * kOneOverPI;
363 float dp = planet_equator_x_ * nx +
364 planet_equator_y_ * ny +
365 planet_equator_z_ * nz;
366 float w = dp / sin(ang);
367 if (w > 1.0f) w = 1.0f;
368 if (w < -1.0f) w = -1.0f;
369 float th = acos_.TableLerp(w) * kOneOver2PI;
370 float dps = planet_pole_x_equator_x_ * nx +
371 planet_pole_x_equator_y_ * ny +
372 planet_pole_x_equator_z_ * nz;
373 float u;
374 if (dps < 0.0f)
375 u = th;
376 else
377 u = 1.0f - th;
378
379 int tx = static_cast<int>(u * tex_->width);
380 int ty = static_cast<int>(v * tex_->height);
381 int offset = tx + ty * tex_->width;
382 uint32_t texel = tex_->pixels[offset];
383 float tr = ExtractR(texel);
384 float tg = ExtractG(texel);
385 float tb = ExtractB(texel);
386
387 unsigned int ir = Clamp255(pr * tr);
388 unsigned int ig = Clamp255(pg * tg);
389 unsigned int ib = Clamp255(pb * tb);
390 unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
391
392 *pixels = color;
393 ++pixels;
394 }
395 }
396
397
398 // Renders a rectangular area of the screen, scan line at a time
399 void Planet::wRenderRect(int x, int y, int w, int h) {
400 for (int j = y; j < (y + h); ++j) {
401 this->wRenderPixelSpan(x, x + w - 1, j);
402 }
403 }
404
405
406 // Thread entry point Planet::wWorkerThread()
407 // This is the main loop for the worker thread(s). It waits for work
408 // by testing a semaphore, which will sleep this thread until work arrives.
409 // It then grabs a mutex protected counter (which is also decremented)
410 // and uses this value to determine which subregion this thread should be
411 // processing. When rendering is finished the worker then pings the main
412 // thread via PostDone() semaphore.
413 // If multithreading, this function is only called by the worker threads.
414 void Planet::wWorkerThreadEntry() {
415
416 // we're a 'detached' thread...
417 // (so we should automagically die when the main thread exits)
418 while (!exiting_) {
419 // wait for some work
420 workers_->WaitWork();
421
422 // if main thread is exiting, have worker exit too
423 if (exiting_) break;
424 // okay, grab region to work on from worker counter
425 int region = workers_->DecCounter();
426 if (region < 0) {
427 // This indicates we're not sync'ing properly
428 InfoPrintf("Region value went negative!\n");
429 exit(-1);
430 }
431 // convert region # into x0, y0, x1, y1 rectangle
432 int x, y, w, h;
433 this->wMakeRect(region, &x, &y, &w, &h);
434
435 // render this rectangle
436 this->wRenderRect(x, y, w, h);
437
438 // let main thread know we've finished a region
439 workers_->PostDone();
440 }
441 }
442
443
444 // Entry point for worker thread. (Can't really pass a member function to
445 // pthread_create(), so we have to do this little round-about)
446 // If multithreading, this function is only called by the worker threads.
447 void* wWorkerThreadEntry(void *args) {
448 // unpack this pointer
449 Planet *pPlanet = reinterpret_cast<Planet*>(args);
450 pPlanet->wWorkerThreadEntry();
451 return NULL;
452 }
453
454
455 // Create worker threads and pass along our this pointer.
456 // If workers_ is NULL, we're running in non-threaded mode.
457 bool Planet::CreateWorkerThreads(int num) {
458 if (NULL != workers_) {
459 return workers_->CreateThreadPool(num, ::wWorkerThreadEntry, this);
460 } else {
461 return true;
462 }
463 }
464
465
466 // Run a simple sim to spin the planet. Update loop is run once per frame.
467 // Called from the main thread only and only when the worker threads are idle.
468 void Planet::UpdateSim() {
469 float m = planet_spin_ + 0.01f;
470 // keep in nice range
471 if (m > (kPI * 2.0f))
472 m = m - kPI * 2.0f;
473 SetPlanetSpin(m);
474 }
475
476
477 // This is the main thread's entry point to dispatch rendering of the planet.
478 // First, it sets the region counter to its max value. This mutex guarded
479 // counter is how worker threads determine which region of the diagram they
480 // should be working on. Then it pings the PostWork semaphore multiple times
481 // to wake up the sleeping worker threads.
482 void Planet::ParallelRender() {
483
484 // At this point, all worker threads are idle and sleeping
485
486 // setup barrier counter before we wake workers
487 workers_->SetCounter(num_regions_);
488 rendering_ = true;
489
490 // wake up the workers
491 for (int i = 0; i < num_regions_; ++i) {
492 workers_->PostWork();
493 }
494 // At this point, all worker threads are awake and busy grabbing
495 // work assignments by reading and decrementing the counter.
496 }
497
498
499 // ParallelRenderSync will sleep a little by waiting for the workers to
500 // finish. It does that by waiting on the WaitDone semaphore.
501 void Planet::ParallelRenderSync() {
502
503 // Only wait if rendering is in progress.
504 if (rendering_) {
505 // wait for all work to be done
506 for (int i = 0; i < num_regions_; ++i) {
507 workers_->WaitDone();
508 }
509 // verify that our counter is where we expect it to be
510 int c = workers_->DecCounter();
511 if (-1 != c) {
512 InfoPrintf("We're not syncing correctly! (%d)\n", c);
513 exit(-1);
514 }
515 rendering_ = false;
516 }
517 // At this point, all worker threads are idle and sleeping again.
518 // The main thread is free to muck with shared data, such
519 // as updating the earth spin in the sim routine.
520 }
521
522
523 // Performs all rendering from the main thread.
524 void Planet::SequentialRender() {
525 this->wRenderRect(0, 0, surface_.width, surface_.height);
526 }
527
528
529 // Renders the Planet diagram.
530 // Picks either parallel or sequential rendering implementation.
531 void Planet::Render() {
532 if (NULL == workers_) {
533 this->SequentialRender();
534 } else {
535 this->ParallelRender();
536 }
537 }
538
539
540 // Waits for a rendering to complete.
541 void Planet::Sync() {
542 if (NULL != workers_) {
543 this->ParallelRenderSync();
544 }
545 }
546
547
548 // pre-calculations to make inner loops faster
549 // these need to be recalculated when values change
550 void Planet::CacheCalcs() {
551 planet_xyz_ = planet_x_ * planet_x_ +
552 planet_y_ * planet_y_ +
553 planet_z_ * planet_z_;
554 planet_radius2_ = planet_radius_ * planet_radius_;
555 planet_one_over_radius_ = 1.0f / planet_radius_;
556 eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
557 // spin vector from center->equator
558 planet_equator_x_ = cos(planet_spin_);
559 planet_equator_y_ = 0.0f;
560 planet_equator_z_ = sin(planet_spin_);
561 // cache cross product of pole & equator
562 planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
563 planet_pole_z_ * planet_equator_y_;
564 planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
565 planet_pole_x_ * planet_equator_z_;
566 planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
567 planet_pole_y_ * planet_equator_x_;
568 }
569
570
571 void Planet::SetPlanetXYZR(float x, float y, float z, float r) {
572 planet_x_ = x;
573 planet_y_ = y;
574 planet_z_ = z;
575 planet_radius_ = r;
576 CacheCalcs();
577 }
578
579
580 void Planet::SetEyeXYZ(float x, float y, float z) {
581 eye_x_ = x;
582 eye_y_ = y;
583 eye_z_ = z;
584 CacheCalcs();
585 }
586
587
588 void Planet::SetLightXYZ(float x, float y, float z) {
589 light_x_ = x;
590 light_y_ = y;
591 light_z_ = z;
592 CacheCalcs();
593 }
594
595
596 void Planet::SetAmbientRGB(float r, float g, float b) {
597 ambient_r_ = r;
598 ambient_g_ = g;
599 ambient_b_ = b;
600 CacheCalcs();
601 }
602
603
604 void Planet::SetDiffuseRGB(float r, float g, float b) {
605 diffuse_r_ = r;
606 diffuse_g_ = g;
607 diffuse_b_ = b;
608 CacheCalcs();
609 }
610
611
612 void Planet::SetPlanetPole(float x, float y, float z) {
613 planet_pole_x_ = x;
614 planet_pole_y_ = y;
615 planet_pole_z_ = z;
616 CacheCalcs();
617 }
618
619
620 void Planet::SetPlanetEquator(float x, float y, float z) {
621 // this is really over-ridden by spin at the momenent
622 planet_equator_x_ = x;
623 planet_equator_y_ = y;
624 planet_equator_z_ = z;
625 CacheCalcs();
626 }
627
628
629 void Planet::SetPlanetSpin(float a) {
630 planet_spin_ = a;
631 CacheCalcs();
632 }
633
634
635 void Planet::SetSurface(Surface surface) {
636 surface_ = surface;
637 }
638
639
640 // Setups and initializes planet data structures.
641 // Seed planet, eye, and light
642 Planet::Planet(int numRegions, bool multi, Texture *tex) :
643 planet_radius_(1.0f),
644 planet_spin_(0.0f),
645 planet_x_(0.0f),
646 planet_y_(0.0f),
647 planet_z_(0.0f),
648 planet_pole_x_(0.0f),
649 planet_pole_y_(0.0f),
650 planet_pole_z_(0.0f),
651 planet_equator_x_(0.0f),
652 planet_equator_y_(0.0f),
653 planet_equator_z_(0.0f),
654 eye_x_(0.0f),
655 eye_y_(0.0f),
656 eye_z_(0.0f),
657 light_x_(0.0f),
658 light_y_(0.0f),
659 light_z_(0.0f),
660 diffuse_r_(0.0f),
661 diffuse_g_(0.0f),
662 diffuse_b_(0.0f),
663 ambient_r_(0.0f),
664 ambient_g_(0.0f),
665 ambient_b_(0.0f),
666 planet_xyz_(0.0f),
667 planet_pole_x_equator_x_(0.0f),
668 planet_pole_x_equator_y_(0.0f),
669 planet_pole_x_equator_z_(0.0f),
670 planet_radius2_(0.0f),
671 planet_one_over_radius_(0.0f),
672 eye_xyz_(0.0f),
673 surface_(NULL, 0, 0) {
674 num_regions_ = numRegions;
675 workers_ = multi ? new WorkerThreadManager() : NULL;
676 tex_ = tex;
677 exiting_ = false;
678 rendering_ = false;
679
680 this->SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
681 this->SetEyeXYZ(0.0f, 0.0f, -14.0f);
682 this->SetLightXYZ(-8.0f, -4.0f, 2.0f);
683 this->SetAmbientRGB(0.4f, 0.4f, 0.4f);
684 this->SetDiffuseRGB(0.8f, 0.8f, 0.8f);
685 this->SetPlanetPole(0.0f, 1.0f, 0.0f);
686 this->SetPlanetEquator(1.0f, 0.0f, 0.0f);
687 this->SetPlanetSpin(kPI / 2.0f);
688 }
689
690
691 // Frees up planet resources.
692 Planet::~Planet() {
693 if (workers_) {
694 exiting_ = true;
695 // wake up the worker threads from their slumber
696 workers_->PostWorkAll();
697 workers_->JoinAll();
698 delete workers_;
699 }
700 }
701
702
703 // Clamps input to the max we can realistically support.
704 static int ClampThreads(int num) {
705 const int max = 128;
706 if (num > max) {
707 return max;
708 }
709 return num;
710 }
711
712
713 static void PrintCredits() {
714 static const char *credit =
715 "\n"
716 "Image Credit:\n"
717 "\n"
718 "NASA Goddard Space Flight Center Image by Reto Stöckli (land surface,\n"
719 "shallow water, clouds). Enhancements by Robert Simmon (ocean color,\n"
720 "compositing, 3D globes, animation).\n"
721 "Data and technical support: MODIS Land Group; MODIS Science Data,\n"
722 "Support Team; MODIS Atmosphere Group; MODIS Ocean Group\n"
723 "Additional data:\n"
724 "USGS EROS Data Center (topography); USGS Terrestrial Remote Sensing\n"
725 "Flagstaff Field Center (Antarctica); Defense Meteorological\n"
726 "Satellite Program (city lights).\n"
727 "\n";
728 InfoPrintf(credit);
729 }
730
731 // If user specifies options on cmd line, parse them
732 // here and update global settings as needed.
733 static void ParseCmdLineArgs(int argc, const char *argn[], const char *argv[]) {
734 // look for cmd line args
735 PrintCredits();
736 if (argc > 1) {
737 for (int i = 1; i < argc; ++i) {
738 if (argn[i] == strstr(argn[i], "numthreads")) {
739 int numthreads = atoi(argv[i]);
740 if (numthreads > 1) {
741 g_multi_threading = true;
742 g_num_threads = numthreads;
743 g_num_regions = numthreads * kRegionRatio;
744 InfoPrintf("Using %d threads\n", numthreads);
745 } else {
746 InfoPrintf("Could not parse numthreads=%s.\n", argv[i]);
747 }
748 } else if (argn[i] == strstr(argn[i], "usesysconf")) {
749 if (argv[i] == strstr(argv[i], "true")) {
750 g_multi_threading = true;
751 g_ask_sysconf = true;
752 } else if (argv[i] == strstr(argv[i], "false")) {
753 g_multi_threading = false;
754 } else {
755 InfoPrintf("Could not parse usesysconf=%s.\n", argv[i]);
756 }
757 } else if (argn[i] == strstr(argn[i], "xwidth")) {
758 int w = atoi(argv[i]);
759 if ((w > 0) && (w < kMaxWindow)) g_window_width = w;
760 } else if (argn[i] == strstr(argn[i], "xheight")) {
761 int h = atoi(argv[i]);
762 if ((h > 0) && (h < kMaxWindow)) g_window_height = h;
763 } else if (argn[i] == strstr(argn[i], "frames")) {
764 int f = atoi(argv[i]);
765 if ((f > 0) && (f < kMaxFrames)) g_num_frames = f;
766 } else if (argn[i] == strstr(argn[i], "id")) {
767 /* ignore id */
768 } else if (argn[i] == strstr(argn[i], "src")) {
769 /* ignore src */
770 } else if (argn[i] == strstr(argn[i], "style")) {
771 /* ignore style */
772 } else if (argn[i] == strstr(argn[i], "type")) {
773 /* ignore type */
774 } else {
775 if (argn[i] != strstr(argn[i], "help")) {
776 InfoPrintf("unknown option %s=%s\n", argn[i], argv[i]);
777 }
778 InfoPrintf("Earth Pepper Demo\n"
779 "usage: numthreads=\"n\" render using n threads.\n"
780 " usesysconf=true use sysconf to set thread count."
781 "\n"
782 " xwidth=\"w\" width of window.\n"
783 " xheight=\"h\" height of window.\n"
784 " framecount=\"n\" number of frames.\n"
785 " help show this screen.\n");
786 }
787 }
788 }
789
790 InfoPrintf("Multi-threading %s.\n",
791 g_multi_threading ? "enabled" : "disabled");
792
793 // see if the system can tell us # cpus
794 if ((g_ask_sysconf) && (g_multi_threading)) {
795 int ncpu = sysconf(_SC_NPROCESSORS_ONLN);
796 if (ncpu > 1) {
797 InfoPrintf("Using %d processors based on sysconf.\n", ncpu);
798 g_num_threads = ncpu;
799 g_num_regions = ncpu * kRegionRatio;
800 }
801 }
802
803 // clamp threads and regions
804 g_num_threads = ClampThreads(g_num_threads);
805 g_num_regions = ClampThreads(g_num_regions);
806 }
807
808 Planet *g_planet = NULL;
809
810 // Parses cmd line options, initializes surface, runs the demo & shuts down.
811 extern "C" void Earth_Init(int argc, const char *argn[], const char *argv[]) {
812 ParseCmdLineArgs(argc, argn, argv);
813 g_planet = new Planet(g_num_regions, g_multi_threading, &g_earth);
814 if (!g_planet->CreateWorkerThreads(g_num_threads)) {
815 DebugPrintf("Earth_Init: thread creation failed. g_num_threads: %d\n",
816 g_num_threads);
817 exit(-1);
818 }
819 }
820
821 extern "C" void Earth_Draw(uint32_t *image_data, int width, int height) {
822 g_planet->SetSurface(Surface(image_data, width, height));
823 g_planet->UpdateSim();
824 g_planet->Render();
825 }
826
827 extern "C" void Earth_Sync() {
828 g_planet->Sync();
829 g_planet->SetSurface(Surface(NULL, 0, 0));
830 }
OLDNEW
« no previous file with comments | « ppapi/native_client/tests/earth/earth.h ('k') | ppapi/native_client/tests/earth/earth_c.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698