Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / native_client_sdk / src / examples / demo / voronoi / voronoi.cc
blob99cf566ec0cf3fa6c5f4aac0bbf2ac1c97c99c44
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <assert.h>
6 #include <math.h>
7 #include <ppapi/c/ppb_input_event.h>
8 #include <ppapi/cpp/input_event.h>
9 #include <ppapi/cpp/var.h>
10 #include <ppapi/cpp/var_array.h>
11 #include <ppapi/cpp/var_array_buffer.h>
12 #include <ppapi/cpp/var_dictionary.h>
13 #include <pthread.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <unistd.h>
20 #include <algorithm>
21 #include <string>
23 #include "ppapi_simple/ps.h"
24 #include "ppapi_simple/ps_context_2d.h"
25 #include "ppapi_simple/ps_event.h"
26 #include "ppapi_simple/ps_interface.h"
27 #include "ppapi_simple/ps_main.h"
28 #include "sdk_util/thread_pool.h"
30 using namespace sdk_util; // For sdk_util::ThreadPool
32 // Global properties used to setup Voronoi demo.
33 namespace {
34 const int kMinRectSize = 4;
35 const int kStartRecurseSize = 32; // must be power-of-two
36 const float kHugeZ = 1.0e38f;
37 const float kPI = M_PI;
38 const float kTwoPI = kPI * 2.0f;
39 const int kFramesToBenchmark = 100;
40 const unsigned int kRandomStartSeed = 0xC0DE533D;
41 const int kMaxPointCount = 1024;
42 const int kStartPointCount = 48;
43 const int kDefaultNumRegions = 256;
45 unsigned int g_rand_state = kRandomStartSeed;
47 // random number helper
48 inline unsigned char rand255() {
49 return static_cast<unsigned char>(rand_r(&g_rand_state) & 255);
52 // random number helper
53 inline float frand() {
54 return (static_cast<float>(rand_r(&g_rand_state)) /
55 static_cast<float>(RAND_MAX));
58 // reset random seed
59 inline void rand_reset(unsigned int seed) {
60 g_rand_state = seed;
63 #ifndef NDEBUG
64 // returns true if input is power of two.
65 // only used in assertions.
66 inline bool is_pow2(int x) {
67 return (x & (x - 1)) == 0;
69 #endif
71 inline double getseconds() {
72 const double usec_to_sec = 0.000001;
73 timeval tv;
74 if (0 == gettimeofday(&tv, NULL))
75 return tv.tv_sec + tv.tv_usec * usec_to_sec;
76 return 0.0;
79 // BGRA helper function, for constructing a pixel for a BGRA buffer.
80 inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
81 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
83 } // namespace
85 // Vec2, simple 2D vector
86 struct Vec2 {
87 float x, y;
88 Vec2() {}
89 Vec2(float px, float py) {
90 x = px;
91 y = py;
93 void Set(float px, float py) {
94 x = px;
95 y = py;
99 // The main object that runs Voronoi simulation.
100 class Voronoi {
101 public:
102 Voronoi();
103 virtual ~Voronoi();
104 // Runs a tick of the simulations, update 2D output.
105 void Update();
106 // Handle event from user, or message from JS.
107 void HandleEvent(PSEvent* ps_event);
109 private:
110 // Methods prefixed with 'w' are run on worker threads.
111 uint32_t* wGetAddr(int x, int y);
112 int wCell(float x, float y);
113 inline void wFillSpan(uint32_t *pixels, uint32_t color, int width);
114 void wRenderTile(int x, int y, int w, int h);
115 void wProcessTile(int x, int y, int w, int h);
116 void wSubdivide(int x, int y, int w, int h);
117 void wMakeRect(int region, int *x, int *y, int *w, int *h);
118 bool wTestRect(int *m, int x, int y, int w, int h);
119 void wFillRect(int x, int y, int w, int h, uint32_t color);
120 void wRenderRect(int x0, int y0, int x1, int y1);
121 void wRenderRegion(int region);
122 static void wRenderRegionEntry(int region, void *thiz);
124 // These methods are only called by the main thread.
125 void Reset();
126 void UpdateSim();
127 void RenderDot(float x, float y, uint32_t color1, uint32_t color2);
128 void SuperimposePositions();
129 void Render();
130 void Draw();
131 void StartBenchmark();
132 void EndBenchmark();
133 // Helper to post small update messages to JS.
134 void PostUpdateMessage(const char* message_name, double value);
136 PSContext2D_t* ps_context_;
137 Vec2 positions_[kMaxPointCount];
138 Vec2 screen_positions_[kMaxPointCount];
139 Vec2 velocities_[kMaxPointCount];
140 uint32_t colors_[kMaxPointCount];
141 float ang_;
142 const int num_regions_;
143 int num_threads_;
144 int point_count_;
145 bool draw_points_;
146 bool draw_interiors_;
147 ThreadPool* workers_;
148 int benchmark_frame_counter_;
149 bool benchmarking_;
150 double benchmark_start_time_;
151 double benchmark_end_time_;
155 void Voronoi::Reset() {
156 rand_reset(kRandomStartSeed);
157 ang_ = 0.0f;
158 for (int i = 0; i < kMaxPointCount; i++) {
159 // random initial start position
160 const float x = frand();
161 const float y = frand();
162 positions_[i].Set(x, y);
163 // random directional velocity ( -1..1, -1..1 )
164 const float speed = 0.0005f;
165 const float u = (frand() * 2.0f - 1.0f) * speed;
166 const float v = (frand() * 2.0f - 1.0f) * speed;
167 velocities_[i].Set(u, v);
168 // 'unique' color (well... unique enough for our purposes)
169 colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255);
173 Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0),
174 point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true),
175 benchmark_frame_counter_(0), benchmarking_(false) {
176 Reset();
177 // By default, render from the dispatch thread.
178 workers_ = new ThreadPool(num_threads_);
179 PSEventSetFilter(PSE_ALL);
180 ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
183 Voronoi::~Voronoi() {
184 delete workers_;
185 PSContext2DFree(ps_context_);
188 inline uint32_t* Voronoi::wGetAddr(int x, int y) {
189 return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
192 // This is the core of the Voronoi calculation. At a given point on the
193 // screen, iterate through all voronoi positions and render them as 3D cones.
194 // We're looking for the voronoi cell that generates the closest z value.
195 // (not really cones - since it is all relative, we avoid doing the
196 // expensive sqrt and test against z*z instead)
197 // If multithreading, this function is only called by the worker threads.
198 int Voronoi::wCell(float x, float y) {
199 int closest_cell = 0;
200 float zz = kHugeZ;
201 Vec2* pos = screen_positions_;
202 for (int i = 0; i < point_count_; ++i) {
203 // measured 5.18 cycles per iteration on a core2
204 float dx = x - pos[i].x;
205 float dy = y - pos[i].y;
206 float dd = (dx * dx + dy * dy);
207 if (dd < zz) {
208 zz = dd;
209 closest_cell = i;
212 return closest_cell;
215 // Given a region r, derive a non-overlapping rectangle for a thread to
216 // work on.
217 // If multithreading, this function is only called by the worker threads.
218 void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) {
219 const int parts = 16;
220 assert(parts * parts == num_regions_);
221 *w = ps_context_->width / parts;
222 *h = ps_context_->height / parts;
223 *x = *w * (r % parts);
224 *y = *h * ((r / parts) % parts);
227 // Test 4 corners of a rectangle to see if they all belong to the same
228 // voronoi cell. Each test is expensive so bail asap. Returns true
229 // if all 4 corners match.
230 // If multithreading, this function is only called by the worker threads.
231 bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) {
232 // each test is expensive, so exit ASAP
233 const int m0 = wCell(x, y);
234 const int m1 = wCell(x + w - 1, y);
235 if (m0 != m1) return false;
236 const int m2 = wCell(x, y + h - 1);
237 if (m0 != m2) return false;
238 const int m3 = wCell(x + w - 1, y + h - 1);
239 if (m0 != m3) return false;
240 // all 4 corners belong to the same cell
241 *m = m0;
242 return true;
245 // Quickly fill a span of pixels with a solid color. Assumes
246 // span width is divisible by 4.
247 // If multithreading, this function is only called by the worker threads.
248 inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
249 if (!draw_interiors_) {
250 const uint32_t gray = MakeBGRA(128, 128, 128, 255);
251 color = gray;
253 for (int i = 0; i < width; i += 4) {
254 *pixels++ = color;
255 *pixels++ = color;
256 *pixels++ = color;
257 *pixels++ = color;
261 // Quickly fill a rectangle with a solid color. Assumes
262 // the width w parameter is evenly divisible by 4.
263 // If multithreading, this function is only called by the worker threads.
264 void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
265 const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
266 uint32_t* pixels = wGetAddr(x, y);
267 for (int j = 0; j < h; j++) {
268 wFillSpan(pixels, color, w);
269 pixels += stride_in_pixels;
273 // When recursive subdivision reaches a certain minimum without finding a
274 // rectangle that has four matching corners belonging to the same voronoi
275 // cell, this function will break the retangular 'tile' into smaller scanlines
276 // and look for opportunities to quick fill at the scanline level. If the
277 // scanline can't be quick filled, it will slow down even further and compute
278 // voronoi membership per pixel.
279 void Voronoi::wRenderTile(int x, int y, int w, int h) {
280 // rip through a tile
281 const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
282 uint32_t* pixels = wGetAddr(x, y);
283 for (int j = 0; j < h; j++) {
284 // get start and end cell values
285 int ms = wCell(x + 0, y + j);
286 int me = wCell(x + w - 1, y + j);
287 // if the end points are the same, quick fill the span
288 if (ms == me) {
289 wFillSpan(pixels, colors_[ms], w);
290 } else {
291 // else compute each pixel in the span... this is the slow part!
292 uint32_t* p = pixels;
293 *p++ = colors_[ms];
294 for (int i = 1; i < (w - 1); i++) {
295 int m = wCell(x + i, y + j);
296 *p++ = colors_[m];
298 *p++ = colors_[me];
300 pixels += stride_in_pixels;
304 // Take a rectangular region and do one of -
305 // If all four corners below to the same voronoi cell, stop recursion and
306 // quick fill the rectangle.
307 // If the minimum rectangle size has been reached, break out of recursion
308 // and process the rectangle. This small rectangle is called a tile.
309 // Otherwise, keep recursively subdividing the rectangle into 4 equally
310 // sized smaller rectangles.
311 // Note: at the moment, these will always be squares, not rectangles.
312 // If multithreading, this function is only called by the worker threads.
313 void Voronoi::wSubdivide(int x, int y, int w, int h) {
314 int m;
315 // if all 4 corners are equal, quick fill interior
316 if (wTestRect(&m, x, y, w, h)) {
317 wFillRect(x, y, w, h, colors_[m]);
318 } else {
319 // did we reach the minimum rectangle size?
320 if ((w <= kMinRectSize) || (h <= kMinRectSize)) {
321 wRenderTile(x, y, w, h);
322 } else {
323 // else recurse into smaller rectangles
324 const int half_w = w / 2;
325 const int half_h = h / 2;
326 wSubdivide(x, y, half_w, half_h);
327 wSubdivide(x + half_w, y, half_w, half_h);
328 wSubdivide(x, y + half_h, half_w, half_h);
329 wSubdivide(x + half_w, y + half_h, half_w, half_h);
334 // This function cuts up the rectangle into power of 2 sized squares. It
335 // assumes the input rectangle w & h are evenly divisible by
336 // kStartRecurseSize.
337 // If multithreading, this function is only called by the worker threads.
338 void Voronoi::wRenderRect(int x, int y, int w, int h) {
339 for (int iy = y; iy < (y + h); iy += kStartRecurseSize) {
340 for (int ix = x; ix < (x + w); ix += kStartRecurseSize) {
341 wSubdivide(ix, iy, kStartRecurseSize, kStartRecurseSize);
346 // If multithreading, this function is only called by the worker threads.
347 void Voronoi::wRenderRegion(int region) {
348 // convert region # into x0, y0, x1, y1 rectangle
349 int x, y, w, h;
350 wMakeRect(region, &x, &y, &w, &h);
351 // render this rectangle
352 wRenderRect(x, y, w, h);
355 // Entry point for worker thread. Can't pass a member function around, so we
356 // have to do this little round-about.
357 void Voronoi::wRenderRegionEntry(int region, void* thiz) {
358 static_cast<Voronoi*>(thiz)->wRenderRegion(region);
361 // Function Voronoi::UpdateSim()
362 // Run a simple sim to move the voronoi positions. This update loop
363 // is run once per frame. Called from the main thread only, and only
364 // when the worker threads are idle.
365 void Voronoi::UpdateSim() {
366 ang_ += 0.002f;
367 if (ang_ > kTwoPI) {
368 ang_ = ang_ - kTwoPI;
370 float z = cosf(ang_) * 3.0f;
371 // push the points around on the screen for animation
372 for (int j = 0; j < kMaxPointCount; j++) {
373 positions_[j].x += (velocities_[j].x) * z;
374 positions_[j].y += (velocities_[j].y) * z;
375 screen_positions_[j].x = positions_[j].x * ps_context_->width;
376 screen_positions_[j].y = positions_[j].y * ps_context_->height;
380 // Renders a small diamond shaped dot at x, y clipped against the window
381 void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
382 const int ix = static_cast<int>(x);
383 const int iy = static_cast<int>(y);
384 const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
385 // clip it against window
386 if (ix < 1) return;
387 if (ix >= (ps_context_->width - 1)) return;
388 if (iy < 1) return;
389 if (iy >= (ps_context_->height - 1)) return;
390 uint32_t* pixel = wGetAddr(ix, iy);
391 // render dot as a small diamond
392 *pixel = color1;
393 *(pixel - 1) = color2;
394 *(pixel + 1) = color2;
395 *(pixel - stride_in_pixels) = color2;
396 *(pixel + stride_in_pixels) = color2;
399 // Superimposes dots on the positions.
400 void Voronoi::SuperimposePositions() {
401 const uint32_t white = MakeBGRA(255, 255, 255, 255);
402 const uint32_t gray = MakeBGRA(192, 192, 192, 255);
403 for (int i = 0; i < point_count_; i++) {
404 RenderDot(
405 screen_positions_[i].x, screen_positions_[i].y, white, gray);
409 // Renders the Voronoi diagram, dispatching the work to multiple threads.
410 void Voronoi::Render() {
411 workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
412 if (draw_points_)
413 SuperimposePositions();
416 void Voronoi::StartBenchmark() {
417 Reset();
418 printf("Benchmark started...\n");
419 benchmark_frame_counter_ = kFramesToBenchmark;
420 benchmarking_ = true;
421 benchmark_start_time_ = getseconds();
424 void Voronoi::EndBenchmark() {
425 benchmark_end_time_ = getseconds();
426 printf("Benchmark ended... time: %2.5f\n",
427 benchmark_end_time_ - benchmark_start_time_);
428 benchmarking_ = false;
429 benchmark_frame_counter_ = 0;
430 double result = benchmark_end_time_ - benchmark_start_time_;
431 PostUpdateMessage("benchmark_result", result);
434 // Handle input events from the user and messages from JS.
435 void Voronoi::HandleEvent(PSEvent* ps_event) {
436 // Give the 2D context a chance to process the event.
437 if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
438 return;
439 if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
440 // Convert Pepper Simple event to a PPAPI C++ event
441 pp::InputEvent event(ps_event->as_resource);
442 switch (event.GetType()) {
443 case PP_INPUTEVENT_TYPE_KEYDOWN: {
444 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
445 uint32_t key_code = key.GetKeyCode();
446 if (key_code == 84) // 't' key
447 if (!benchmarking_)
448 StartBenchmark();
449 break;
451 case PP_INPUTEVENT_TYPE_TOUCHSTART:
452 case PP_INPUTEVENT_TYPE_TOUCHMOVE: {
453 pp::TouchInputEvent touches = pp::TouchInputEvent(event);
454 uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
455 // Touch points 0..n directly set position of points 0..n in
456 // Voronoi diagram.
457 for (uint32_t i = 0; i < count; i++) {
458 pp::TouchPoint touch =
459 touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, i);
460 pp::FloatPoint point = touch.position();
461 positions_[i].Set(point.x() / ps_context_->width,
462 point.y() / ps_context_->height);
464 break;
466 default:
467 break;
469 } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
470 // Convert Pepper Simple message to PPAPI C++ var
471 pp::Var var(ps_event->as_var);
472 if (var.is_dictionary()) {
473 pp::VarDictionary dictionary(var);
474 std::string message = dictionary.Get("message").AsString();
475 if (message == "run_benchmark" && !benchmarking_)
476 StartBenchmark();
477 else if (message == "draw_points")
478 draw_points_ = dictionary.Get("value").AsBool();
479 else if (message == "draw_interiors")
480 draw_interiors_ = dictionary.Get("value").AsBool();
481 else if (message == "set_points") {
482 int num_points = dictionary.Get("value").AsInt();
483 point_count_ = std::min(kMaxPointCount, std::max(0, num_points));
484 } else if (message == "set_threads") {
485 int thread_count = dictionary.Get("value").AsInt();
486 delete workers_;
487 workers_ = new ThreadPool(thread_count);
493 // PostUpdateMessage() helper function for sendimg small messages to JS.
494 void Voronoi::PostUpdateMessage(const char* message_name, double value) {
495 pp::VarDictionary message;
496 message.Set("message", message_name);
497 message.Set("value", value);
498 PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
501 void Voronoi::Update() {
502 PSContext2DGetBuffer(ps_context_);
503 if (NULL == ps_context_->data)
504 return;
505 assert(is_pow2(ps_context_->width));
506 assert(is_pow2(ps_context_->height));
508 // When benchmarking is running, don't update display via
509 // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
510 // the benchmark results.
511 do {
512 UpdateSim();
513 Render();
514 if (!benchmarking_) break;
515 --benchmark_frame_counter_;
516 } while (benchmark_frame_counter_ > 0);
517 if (benchmarking_)
518 EndBenchmark();
520 PSContext2DSwapBuffer(ps_context_);
523 // Starting point for the module. We do not use main since it would
524 // collide with main in libppapi_cpp.
525 int example_main(int argc, char* argv[]) {
526 Voronoi voronoi;
527 while (true) {
528 PSEvent* ps_event;
529 // Consume all available events.
530 while ((ps_event = PSEventTryAcquire()) != NULL) {
531 voronoi.HandleEvent(ps_event);
532 PSEventRelease(ps_event);
534 // Do simulation, render and present.
535 voronoi.Update();
538 return 0;
541 // Register the function to call once the Instance Object is initialized.
542 // see: pappi_simple/ps_main.h
543 PPAPI_SIMPLE_REGISTER_MAIN(example_main);