summaryrefslogtreecommitdiffstats
path: root/ppapi/native_client/tests/earth/earth.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/native_client/tests/earth/earth.cc')
-rw-r--r--ppapi/native_client/tests/earth/earth.cc830
1 files changed, 0 insertions, 830 deletions
diff --git a/ppapi/native_client/tests/earth/earth.cc b/ppapi/native_client/tests/earth/earth.cc
deleted file mode 100644
index 71854df..0000000
--- a/ppapi/native_client/tests/earth/earth.cc
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * Copyright (c) 2011 The Chromium 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));
-}