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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ppapi/native_client/tests/earth/earth.cc
===================================================================
--- ppapi/native_client/tests/earth/earth.cc (revision 0)
+++ ppapi/native_client/tests/earth/earth.cc (revision 0)
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// NaCl Earth demo
+// Ray trace planet Earth
+
+#include "native_client/tests/earth/earth.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define HAVE_THREADS 1
+#include "native_client/common/worker.h"
+
+// print/debug messages
+static void InfoPrintf(const char *fmt, ...) {
+ va_list argptr;
+ va_start (argptr, fmt);
+ vfprintf (stderr, fmt, argptr);
+ va_end (argptr);
+ fflush(stderr);
+}
+
+extern "C" void DebugPrintf(const char *fmt, ...) {
+ va_list argptr;
+ fprintf (stderr, "@@@ EARTH ");
+
+ va_start (argptr, fmt);
+ vfprintf (stderr, fmt, argptr);
+ va_end (argptr);
+ fflush(stderr);
+}
+
+// global properties
+const float kPI = M_PI;
+const float kOneOverPI = 1.0f / kPI;
+const float kOneOver2PI = 1.0f / (2.0f * kPI);
+const float kOneOver255 = 1.0f / 255.0f;
+const int kArcCosineTableSize = 4096;
+const float kMaxWindow = 4096;
+const int kEarthTextureWidth = 1024;
+const int kEarthTextureHeight = 512;
+const int kMaxFrames = 1000000;
+const int kRegionRatio = 8;
+int g_window_width = 512;
+int g_window_height = 512;
+int g_num_frames = 300;
+bool g_ask_sysconf = true;
+int g_num_threads = 4; // possibly overridden by sysconf()
+int g_num_regions = 4; // possibly overridden by sysconf()
+bool g_multi_threading = false; // can be overridden on cmd line
+
+int g_frame_checksum = 0; // used for nacl module testing
+
+// seed for rand_r() - we only call rand_r from main thread.
+static unsigned int g_seed = 0xC0DE533D;
+
+// random number helper
+inline unsigned char rand255() {
+ return static_cast<unsigned char>(rand_r(&g_seed) & 255);
+}
+
+// random number helper
+inline float frand() {
+ return (static_cast<float>(rand_r(&g_seed)) / static_cast<float>(RAND_MAX));
+}
+
+// build a packed color
+inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
+}
+
+// extraction routines
+inline float ExtractR(uint32_t c) {
+ return static_cast<float>(c & 0xFF) * kOneOver255;
+}
+
+inline float ExtractG(uint32_t c) {
+ return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255;
+}
+
+inline float ExtractB(uint32_t c) {
+ return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
+}
+
+
+// simple container for earth texture
+struct Texture {
+ int width, height;
+ unsigned int pixels[kEarthTextureWidth * kEarthTextureHeight];
+};
+
+
+// compile our texture straight in to avoid runtime filesystem
+Texture g_earth = {
+ kEarthTextureWidth, kEarthTextureHeight, {
+#include "native_client/tests/earth/earth_image.inc"
+ }
+};
+
+
+struct Surface {
+ int width, height, pitch;
+ uint32_t *pixels;
+ Surface(uint32_t *pix, int w, int h) {
+ width = w;
+ height = h;
+ pitch = w;
+ pixels = pix;
+ }
+};
+
+
+struct ArcCosine {
+ // slightly larger table so we can interpolate beyond table size
+ float table[kArcCosineTableSize + 2];
+ float TableLerp(float x);
+ ArcCosine();
+ ~ArcCosine() { ; }
+};
+
+
+ArcCosine::ArcCosine() {
+ // build a slightly larger table to allow for numeric imprecision
+ for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
+ float f = static_cast<float>(i) / kArcCosineTableSize;
+ f = f * 2.0f - 1.0f;
+ table[i] = acos(f);
+ }
+}
+
+
+// looks up acos(f) using a table and lerping between entries
+// (it is expected that input f is between -1 and 1)
+float ArcCosine::TableLerp(float f) {
+ float x = (f + 1.0f) * 0.5f;
+ x = x * kArcCosineTableSize;
+ int ix = static_cast<int>(x);
+ float fx = static_cast<float>(ix);
+ float dx = x - fx;
+ float af = table[ix];
+ float af2 = table[ix + 1];
+ float a = af + (af2 - af) * dx;
+ return a;
+}
+
+
+// takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
+inline unsigned int Clamp255(float x) {
+ if (x < 0.0f) {
+ x = 0.0f;
+ } else if (x > 1.0f) {
+ x = 1.0f;
+ }
+ return (unsigned int)(x * 255.0f);
+}
+
+
+// Planet class holds information and functionality needed to render
+// a ray-traced planet into an raw pixel surface
+class Planet {
+ float planet_radius_;
+ float planet_spin_;
+ float planet_x_, planet_y_, planet_z_;
+ float planet_pole_x_, planet_pole_y_, planet_pole_z_;
+ float planet_equator_x_, planet_equator_y_, planet_equator_z_;
+ float eye_x_, eye_y_, eye_z_;
+ float light_x_, light_y_, light_z_;
+ float diffuse_r_, diffuse_g_, diffuse_b_;
+ float ambient_r_, ambient_g_, ambient_b_;
+
+ // cached calculations
+ float planet_xyz_;
+ float planet_pole_x_equator_x_;
+ float planet_pole_x_equator_y_;
+ float planet_pole_x_equator_z_;
+ float planet_radius2_;
+ float planet_one_over_radius_;
+ float eye_xyz_;
+
+ // misc
+ Texture *tex_;
+ Surface surface_;
+ ArcCosine acos_;
+ int num_regions_;
+ WorkerThreadManager *workers_;
+ volatile bool exiting_;
+ bool rendering_;
+
+public:
+
+ // methods prefixed with 'w' are only called by worker threads!
+ // (unless MULTI_THREADING is false)
+ uint32_t* wGetAddr(int x, int y);
+ void wRenderPixelSpan(int x0, int x1, int y);
+ void wMakeRect(int r, int *x, int *y, int *w, int *h);
+ void wRenderRect(int x0, int y0, int x1, int y1);
+ void wWorkerThreadEntry();
+
+ // these methods are only called by the main thread
+ void CacheCalcs();
+ void SetPlanetXYZR(float x, float y, float z, float r);
+ void SetPlanetPole(float x, float y, float z);
+ void SetPlanetEquator(float x, float y, float z);
+ void SetPlanetSpin(float a);
+ void SetEyeXYZ(float x, float y, float z);
+ void SetLightXYZ(float x, float y, float z);
+ void SetAmbientRGB(float r, float g, float b);
+ void SetDiffuseRGB(float r, float g, float b);
+ void SetSurface(Surface surface);
+ bool CreateWorkerThreads(int num);
+ void UpdateSim();
+ void ParallelRender();
+ void ParallelRenderSync();
+ void SequentialRender();
+ void Render();
+ void Sync();
+ Planet(int numRegions, bool multithreading, Texture *tex);
+ ~Planet();
+};
+
+// Given a region r, derive a rectangle. Currently this function
+// slices the main output buffer into equal sized rows.
+// This function is used to convert a mutex guarded counter into
+// a rectangular region for a given worker thread to process.
+// This rectangle shouldn't overlap with work being done by other workers.
+// If multithreading, this function is only called by the worker threads.
+void Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
+ int dy = surface_.height / num_regions_;
+ *x = 0;
+ *w = surface_.width;
+ *y = r * dy;
+ *h = dy;
+}
+
+
+inline uint32_t* Planet::wGetAddr(int x, int y) {
+ assert(surface_.pixels);
+ return (surface_.pixels + y * surface_.pitch) + x;
+}
+
+
+union Convert {
+ float f;
+ int i;
+ Convert(int x) { i = x; }
+ Convert(float x) { f = x; }
+ const int asInt() { return i; }
+ const float asFloat() { return f; }
+};
+
+
+inline const int AsInteger(const float f) {
+ Convert u(f);
+ return u.asInt();
+}
+
+
+inline const float AsFloat(const int i) {
+ Convert u(i);
+ return u.asFloat();
+}
+
+
+const long int kOneAsInteger = AsInteger(1.0f);
+const float kScaleUp = float(0x00800000);
+const float kScaleDown = 1.0f / kScaleUp;
+
+
+inline float inline_quick_sqrt(float x) {
+ int i;
+ i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
+ return AsFloat(i);
+}
+
+
+inline float inline_sqrt(float x) {
+ float y;
+ y = inline_quick_sqrt(x);
+ y = (y * y + x) / (2.0f * y);
+ y = (y * y + x) / (2.0f * y);
+ return y;
+}
+
+
+// This is the meat of the ray tracer. Given a pixel span (x0, x1) on
+// scanline y, shoot rays into the scene and render what they hit. Use
+// scanline coherence to do a few optimizations
+void Planet::wRenderPixelSpan(int x0, int x1, int y) {
+ const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
+ float y0 = eye_y_;
+ float z0 = eye_z_;
+ float y1 = (static_cast<float>(y) / surface_.height) * 2.0f - 1.0f;
+ float z1 = 0.0f;
+ float dy = (y1 - y0);
+ float dz = (z1 - z0);
+ float dy_dy_dz_dz = dy * dy + dz * dz;
+ float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) +
+ 2.0f * dz * (z0 - planet_z_);
+ float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
+ float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
+ float oowidth = 1.0f / surface_.width;
+ uint32_t *pixels = this->wGetAddr(x0, y);
+ for (int x = x0; x <= x1; ++x) {
+ // scan normalized screen -1..1
+ float x1 = (static_cast<float>(x) * oowidth) * 2.0f - 1.0f;
+ // eye
+ float x0 = eye_x_;
+ // delta from screen to eye
+ float dx = (x1 - x0);
+ // build a, b, c
+ float a = dx * dx + dy_dy_dz_dz;
+ float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
+ float c = planet_xyz_eye_xyz +
+ -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
+ // calculate discriminant
+ float disc = b * b - 4.0f * a * c;
+
+ // did ray hit the sphere?
+ if (disc < 0.0f) {
+ *pixels = kColorBlack;
+ ++pixels;
+ continue;
+ }
+
+ // calc parametric t value
+ float t = (-b - inline_sqrt(disc)) / (2.0f * a);
+ float px = x0 + t * dx;
+ float py = y0 + t * dy;
+ float pz = z0 + t * dz;
+ float nx = (px - planet_x_) * planet_one_over_radius_;
+ float ny = (py - planet_y_) * planet_one_over_radius_;
+ float nz = (pz - planet_z_) * planet_one_over_radius_;
+
+ float Lx = (light_x_ - px);
+ float Ly = (light_y_ - py);
+ float Lz = (light_z_ - pz);
+ float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz);
+ Lx *= Lq;
+ Ly *= Lq;
+ Lz *= Lq;
+ float d = (Lx * nx + Ly * ny + Lz * nz);
+ float pr = (diffuse_r_ * d) + ambient_r_;
+ float pg = (diffuse_g_ * d) + ambient_g_;
+ float pb = (diffuse_b_ * d) + ambient_b_;
+ float ds = -(nx * planet_pole_x_ +
+ ny * planet_pole_y_ +
+ nz * planet_pole_z_);
+ float ang = acos_.TableLerp(ds);
+ float v = ang * kOneOverPI;
+ float dp = planet_equator_x_ * nx +
+ planet_equator_y_ * ny +
+ planet_equator_z_ * nz;
+ float w = dp / sin(ang);
+ if (w > 1.0f) w = 1.0f;
+ if (w < -1.0f) w = -1.0f;
+ float th = acos_.TableLerp(w) * kOneOver2PI;
+ float dps = planet_pole_x_equator_x_ * nx +
+ planet_pole_x_equator_y_ * ny +
+ planet_pole_x_equator_z_ * nz;
+ float u;
+ if (dps < 0.0f)
+ u = th;
+ else
+ u = 1.0f - th;
+
+ int tx = static_cast<int>(u * tex_->width);
+ int ty = static_cast<int>(v * tex_->height);
+ int offset = tx + ty * tex_->width;
+ uint32_t texel = tex_->pixels[offset];
+ float tr = ExtractR(texel);
+ float tg = ExtractG(texel);
+ float tb = ExtractB(texel);
+
+ unsigned int ir = Clamp255(pr * tr);
+ unsigned int ig = Clamp255(pg * tg);
+ unsigned int ib = Clamp255(pb * tb);
+ unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
+
+ *pixels = color;
+ ++pixels;
+ }
+}
+
+
+// Renders a rectangular area of the screen, scan line at a time
+void Planet::wRenderRect(int x, int y, int w, int h) {
+ for (int j = y; j < (y + h); ++j) {
+ this->wRenderPixelSpan(x, x + w - 1, j);
+ }
+}
+
+
+// Thread entry point Planet::wWorkerThread()
+// This is the main loop for the worker thread(s). It waits for work
+// by testing a semaphore, which will sleep this thread until work arrives.
+// It then grabs a mutex protected counter (which is also decremented)
+// and uses this value to determine which subregion this thread should be
+// processing. When rendering is finished the worker then pings the main
+// thread via PostDone() semaphore.
+// If multithreading, this function is only called by the worker threads.
+void Planet::wWorkerThreadEntry() {
+
+ // we're a 'detached' thread...
+ // (so we should automagically die when the main thread exits)
+ while (!exiting_) {
+ // wait for some work
+ workers_->WaitWork();
+
+ // if main thread is exiting, have worker exit too
+ if (exiting_) break;
+ // okay, grab region to work on from worker counter
+ int region = workers_->DecCounter();
+ if (region < 0) {
+ // This indicates we're not sync'ing properly
+ InfoPrintf("Region value went negative!\n");
+ exit(-1);
+ }
+ // convert region # into x0, y0, x1, y1 rectangle
+ int x, y, w, h;
+ this->wMakeRect(region, &x, &y, &w, &h);
+
+ // render this rectangle
+ this->wRenderRect(x, y, w, h);
+
+ // let main thread know we've finished a region
+ workers_->PostDone();
+ }
+}
+
+
+// Entry point for worker thread. (Can't really pass a member function to
+// pthread_create(), so we have to do this little round-about)
+// If multithreading, this function is only called by the worker threads.
+void* wWorkerThreadEntry(void *args) {
+ // unpack this pointer
+ Planet *pPlanet = reinterpret_cast<Planet*>(args);
+ pPlanet->wWorkerThreadEntry();
+ return NULL;
+}
+
+
+// Create worker threads and pass along our this pointer.
+// If workers_ is NULL, we're running in non-threaded mode.
+bool Planet::CreateWorkerThreads(int num) {
+ if (NULL != workers_) {
+ return workers_->CreateThreadPool(num, ::wWorkerThreadEntry, this);
+ } else {
+ return true;
+ }
+}
+
+
+// Run a simple sim to spin the planet. Update loop is run once per frame.
+// Called from the main thread only and only when the worker threads are idle.
+void Planet::UpdateSim() {
+ float m = planet_spin_ + 0.01f;
+ // keep in nice range
+ if (m > (kPI * 2.0f))
+ m = m - kPI * 2.0f;
+ SetPlanetSpin(m);
+}
+
+
+// This is the main thread's entry point to dispatch rendering of the planet.
+// First, it sets the region counter to its max value. This mutex guarded
+// counter is how worker threads determine which region of the diagram they
+// should be working on. Then it pings the PostWork semaphore multiple times
+// to wake up the sleeping worker threads.
+void Planet::ParallelRender() {
+
+ // At this point, all worker threads are idle and sleeping
+
+ // setup barrier counter before we wake workers
+ workers_->SetCounter(num_regions_);
+ rendering_ = true;
+
+ // wake up the workers
+ for (int i = 0; i < num_regions_; ++i) {
+ workers_->PostWork();
+ }
+ // At this point, all worker threads are awake and busy grabbing
+ // work assignments by reading and decrementing the counter.
+}
+
+
+// ParallelRenderSync will sleep a little by waiting for the workers to
+// finish. It does that by waiting on the WaitDone semaphore.
+void Planet::ParallelRenderSync() {
+
+ // Only wait if rendering is in progress.
+ if (rendering_) {
+ // wait for all work to be done
+ for (int i = 0; i < num_regions_; ++i) {
+ workers_->WaitDone();
+ }
+ // verify that our counter is where we expect it to be
+ int c = workers_->DecCounter();
+ if (-1 != c) {
+ InfoPrintf("We're not syncing correctly! (%d)\n", c);
+ exit(-1);
+ }
+ rendering_ = false;
+ }
+ // At this point, all worker threads are idle and sleeping again.
+ // The main thread is free to muck with shared data, such
+ // as updating the earth spin in the sim routine.
+}
+
+
+// Performs all rendering from the main thread.
+void Planet::SequentialRender() {
+ this->wRenderRect(0, 0, surface_.width, surface_.height);
+}
+
+
+// Renders the Planet diagram.
+// Picks either parallel or sequential rendering implementation.
+void Planet::Render() {
+ if (NULL == workers_) {
+ this->SequentialRender();
+ } else {
+ this->ParallelRender();
+ }
+}
+
+
+// Waits for a rendering to complete.
+void Planet::Sync() {
+ if (NULL != workers_) {
+ this->ParallelRenderSync();
+ }
+}
+
+
+// pre-calculations to make inner loops faster
+// these need to be recalculated when values change
+void Planet::CacheCalcs() {
+ planet_xyz_ = planet_x_ * planet_x_ +
+ planet_y_ * planet_y_ +
+ planet_z_ * planet_z_;
+ planet_radius2_ = planet_radius_ * planet_radius_;
+ planet_one_over_radius_ = 1.0f / planet_radius_;
+ eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
+ // spin vector from center->equator
+ planet_equator_x_ = cos(planet_spin_);
+ planet_equator_y_ = 0.0f;
+ planet_equator_z_ = sin(planet_spin_);
+ // cache cross product of pole & equator
+ planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
+ planet_pole_z_ * planet_equator_y_;
+ planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
+ planet_pole_x_ * planet_equator_z_;
+ planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
+ planet_pole_y_ * planet_equator_x_;
+}
+
+
+void Planet::SetPlanetXYZR(float x, float y, float z, float r) {
+ planet_x_ = x;
+ planet_y_ = y;
+ planet_z_ = z;
+ planet_radius_ = r;
+ CacheCalcs();
+}
+
+
+void Planet::SetEyeXYZ(float x, float y, float z) {
+ eye_x_ = x;
+ eye_y_ = y;
+ eye_z_ = z;
+ CacheCalcs();
+}
+
+
+void Planet::SetLightXYZ(float x, float y, float z) {
+ light_x_ = x;
+ light_y_ = y;
+ light_z_ = z;
+ CacheCalcs();
+}
+
+
+void Planet::SetAmbientRGB(float r, float g, float b) {
+ ambient_r_ = r;
+ ambient_g_ = g;
+ ambient_b_ = b;
+ CacheCalcs();
+}
+
+
+void Planet::SetDiffuseRGB(float r, float g, float b) {
+ diffuse_r_ = r;
+ diffuse_g_ = g;
+ diffuse_b_ = b;
+ CacheCalcs();
+}
+
+
+void Planet::SetPlanetPole(float x, float y, float z) {
+ planet_pole_x_ = x;
+ planet_pole_y_ = y;
+ planet_pole_z_ = z;
+ CacheCalcs();
+}
+
+
+void Planet::SetPlanetEquator(float x, float y, float z) {
+ // this is really over-ridden by spin at the momenent
+ planet_equator_x_ = x;
+ planet_equator_y_ = y;
+ planet_equator_z_ = z;
+ CacheCalcs();
+}
+
+
+void Planet::SetPlanetSpin(float a) {
+ planet_spin_ = a;
+ CacheCalcs();
+}
+
+
+void Planet::SetSurface(Surface surface) {
+ surface_ = surface;
+}
+
+
+// Setups and initializes planet data structures.
+// Seed planet, eye, and light
+Planet::Planet(int numRegions, bool multi, Texture *tex) :
+ planet_radius_(1.0f),
+ planet_spin_(0.0f),
+ planet_x_(0.0f),
+ planet_y_(0.0f),
+ planet_z_(0.0f),
+ planet_pole_x_(0.0f),
+ planet_pole_y_(0.0f),
+ planet_pole_z_(0.0f),
+ planet_equator_x_(0.0f),
+ planet_equator_y_(0.0f),
+ planet_equator_z_(0.0f),
+ eye_x_(0.0f),
+ eye_y_(0.0f),
+ eye_z_(0.0f),
+ light_x_(0.0f),
+ light_y_(0.0f),
+ light_z_(0.0f),
+ diffuse_r_(0.0f),
+ diffuse_g_(0.0f),
+ diffuse_b_(0.0f),
+ ambient_r_(0.0f),
+ ambient_g_(0.0f),
+ ambient_b_(0.0f),
+ planet_xyz_(0.0f),
+ planet_pole_x_equator_x_(0.0f),
+ planet_pole_x_equator_y_(0.0f),
+ planet_pole_x_equator_z_(0.0f),
+ planet_radius2_(0.0f),
+ planet_one_over_radius_(0.0f),
+ eye_xyz_(0.0f),
+ surface_(NULL, 0, 0) {
+ num_regions_ = numRegions;
+ workers_ = multi ? new WorkerThreadManager() : NULL;
+ tex_ = tex;
+ exiting_ = false;
+ rendering_ = false;
+
+ this->SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
+ this->SetEyeXYZ(0.0f, 0.0f, -14.0f);
+ this->SetLightXYZ(-8.0f, -4.0f, 2.0f);
+ this->SetAmbientRGB(0.4f, 0.4f, 0.4f);
+ this->SetDiffuseRGB(0.8f, 0.8f, 0.8f);
+ this->SetPlanetPole(0.0f, 1.0f, 0.0f);
+ this->SetPlanetEquator(1.0f, 0.0f, 0.0f);
+ this->SetPlanetSpin(kPI / 2.0f);
+}
+
+
+// Frees up planet resources.
+Planet::~Planet() {
+ if (workers_) {
+ exiting_ = true;
+ // wake up the worker threads from their slumber
+ workers_->PostWorkAll();
+ workers_->JoinAll();
+ delete workers_;
+ }
+}
+
+
+// Clamps input to the max we can realistically support.
+static int ClampThreads(int num) {
+ const int max = 128;
+ if (num > max) {
+ return max;
+ }
+ return num;
+}
+
+
+static void PrintCredits() {
+ static const char *credit =
+ "\n"
+ "Image Credit:\n"
+ "\n"
+ "NASA Goddard Space Flight Center Image by Reto Stöckli (land surface,\n"
+ "shallow water, clouds). Enhancements by Robert Simmon (ocean color,\n"
+ "compositing, 3D globes, animation).\n"
+ "Data and technical support: MODIS Land Group; MODIS Science Data,\n"
+ "Support Team; MODIS Atmosphere Group; MODIS Ocean Group\n"
+ "Additional data:\n"
+ "USGS EROS Data Center (topography); USGS Terrestrial Remote Sensing\n"
+ "Flagstaff Field Center (Antarctica); Defense Meteorological\n"
+ "Satellite Program (city lights).\n"
+ "\n";
+ InfoPrintf(credit);
+}
+
+// If user specifies options on cmd line, parse them
+// here and update global settings as needed.
+static void ParseCmdLineArgs(int argc, const char *argn[], const char *argv[]) {
+ // look for cmd line args
+ PrintCredits();
+ if (argc > 1) {
+ for (int i = 1; i < argc; ++i) {
+ if (argn[i] == strstr(argn[i], "numthreads")) {
+ int numthreads = atoi(argv[i]);
+ if (numthreads > 1) {
+ g_multi_threading = true;
+ g_num_threads = numthreads;
+ g_num_regions = numthreads * kRegionRatio;
+ InfoPrintf("Using %d threads\n", numthreads);
+ } else {
+ InfoPrintf("Could not parse numthreads=%s.\n", argv[i]);
+ }
+ } else if (argn[i] == strstr(argn[i], "usesysconf")) {
+ if (argv[i] == strstr(argv[i], "true")) {
+ g_multi_threading = true;
+ g_ask_sysconf = true;
+ } else if (argv[i] == strstr(argv[i], "false")) {
+ g_multi_threading = false;
+ } else {
+ InfoPrintf("Could not parse usesysconf=%s.\n", argv[i]);
+ }
+ } else if (argn[i] == strstr(argn[i], "xwidth")) {
+ int w = atoi(argv[i]);
+ if ((w > 0) && (w < kMaxWindow)) g_window_width = w;
+ } else if (argn[i] == strstr(argn[i], "xheight")) {
+ int h = atoi(argv[i]);
+ if ((h > 0) && (h < kMaxWindow)) g_window_height = h;
+ } else if (argn[i] == strstr(argn[i], "frames")) {
+ int f = atoi(argv[i]);
+ if ((f > 0) && (f < kMaxFrames)) g_num_frames = f;
+ } else if (argn[i] == strstr(argn[i], "id")) {
+ /* ignore id */
+ } else if (argn[i] == strstr(argn[i], "src")) {
+ /* ignore src */
+ } else if (argn[i] == strstr(argn[i], "style")) {
+ /* ignore style */
+ } else if (argn[i] == strstr(argn[i], "type")) {
+ /* ignore type */
+ } else {
+ if (argn[i] != strstr(argn[i], "help")) {
+ InfoPrintf("unknown option %s=%s\n", argn[i], argv[i]);
+ }
+ InfoPrintf("Earth Pepper Demo\n"
+ "usage: numthreads=\"n\" render using n threads.\n"
+ " usesysconf=true use sysconf to set thread count."
+ "\n"
+ " xwidth=\"w\" width of window.\n"
+ " xheight=\"h\" height of window.\n"
+ " framecount=\"n\" number of frames.\n"
+ " help show this screen.\n");
+ }
+ }
+ }
+
+ InfoPrintf("Multi-threading %s.\n",
+ g_multi_threading ? "enabled" : "disabled");
+
+ // see if the system can tell us # cpus
+ if ((g_ask_sysconf) && (g_multi_threading)) {
+ int ncpu = sysconf(_SC_NPROCESSORS_ONLN);
+ if (ncpu > 1) {
+ InfoPrintf("Using %d processors based on sysconf.\n", ncpu);
+ g_num_threads = ncpu;
+ g_num_regions = ncpu * kRegionRatio;
+ }
+ }
+
+ // clamp threads and regions
+ g_num_threads = ClampThreads(g_num_threads);
+ g_num_regions = ClampThreads(g_num_regions);
+}
+
+Planet *g_planet = NULL;
+
+// Parses cmd line options, initializes surface, runs the demo & shuts down.
+extern "C" void Earth_Init(int argc, const char *argn[], const char *argv[]) {
+ ParseCmdLineArgs(argc, argn, argv);
+ g_planet = new Planet(g_num_regions, g_multi_threading, &g_earth);
+ if (!g_planet->CreateWorkerThreads(g_num_threads)) {
+ DebugPrintf("Earth_Init: thread creation failed. g_num_threads: %d\n",
+ g_num_threads);
+ exit(-1);
+ }
+}
+
+extern "C" void Earth_Draw(uint32_t *image_data, int width, int height) {
+ g_planet->SetSurface(Surface(image_data, width, height));
+ g_planet->UpdateSim();
+ g_planet->Render();
+}
+
+extern "C" void Earth_Sync() {
+ g_planet->Sync();
+ g_planet->SetSurface(Surface(NULL, 0, 0));
+}
Property changes on: ppapi/native_client/tests/earth/earth.cc
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
« 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