| Index: native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
|
| diff --git a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
|
| index bada6105c5cab2a52d5de67ddb3bcbb02fe39410..6080b0377bb850241c1953d3f9761a795025067e 100644
|
| --- a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
|
| +++ b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
|
| @@ -2,16 +2,20 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <math.h>
|
| +#include <pthread.h>
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
| -#include <cassert>
|
| -#include <cmath>
|
| -#include <cstring>
|
| +
|
| #include <string>
|
| -#include "ppapi/cpp/completion_callback.h"
|
| -#include "ppapi/cpp/var.h"
|
|
|
| -#include "pi_generator.h"
|
| +#include "ppapi/cpp/graphics_2d.h"
|
| +#include "ppapi/cpp/image_data.h"
|
| +#include "ppapi/cpp/instance.h"
|
| +#include "ppapi/cpp/rect.h"
|
| +#include "ppapi/cpp/size.h"
|
| +#include "ppapi/cpp/var.h"
|
| +#include "ppapi/utility/completion_callback_factory.h"
|
|
|
| namespace {
|
| const int kPthreadMutexSuccess = 0;
|
| @@ -23,16 +27,91 @@ const uint32_t kRedMask = 0xff0000;
|
| const uint32_t kBlueMask = 0xff;
|
| const uint32_t kRedShift = 16;
|
| const uint32_t kBlueShift = 0;
|
| +} // namespace
|
|
|
| -// This is called by the browser when the 2D context has been flushed to the
|
| -// browser window.
|
| -void FlushCallback(void* data, int32_t result) {
|
| - static_cast<pi_generator::PiGenerator*>(data)->set_flush_pending(false);
|
| -}
|
| +class PiGeneratorInstance : public pp::Instance {
|
| + public:
|
| + explicit PiGeneratorInstance(PP_Instance instance);
|
| + virtual ~PiGeneratorInstance();
|
|
|
| -} // namespace
|
| + // Start up the ComputePi() thread.
|
| + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
|
| +
|
| + // Update the graphics context to the new size, and regenerate |pixel_buffer_|
|
| + // to fit the new size as well.
|
| + virtual void DidChangeView(const pp::View& view);
|
| +
|
| + // Called by the browser to handle the postMessage() call in Javascript.
|
| + // The message in this case is expected to contain the string 'paint', and
|
| + // if so this invokes the Paint() function. If |var_message| is not a string
|
| + // type, or contains something other than 'paint', this method posts an
|
| + // invalid value for Pi (-1.0) back to the browser.
|
| + virtual void HandleMessage(const pp::Var& var_message);
|
| +
|
| + // Return a pointer to the pixels represented by |pixel_buffer_|. When this
|
| + // method returns, the underlying |pixel_buffer_| object is locked. This
|
| + // call must have a matching UnlockPixels() or various threading errors
|
| + // (e.g. deadlock) will occur.
|
| + uint32_t* LockPixels();
|
| + // Release the image lock acquired by LockPixels().
|
| + void UnlockPixels() const;
|
| +
|
| + // Flushes its contents of |pixel_buffer_| to the 2D graphics context. The
|
| + // ComputePi() thread fills in |pixel_buffer_| pixels as it computes Pi.
|
| + // This method is called by HandleMessage when a message containing 'paint'
|
| + // is received. Echos the current value of pi as computed by the Monte Carlo
|
| + // method by posting the value back to the browser.
|
| + void Paint();
|
| +
|
| + bool quit() const { return quit_; }
|
| +
|
| + // |pi_| is computed in the ComputePi() thread.
|
| + double pi() const { return pi_; }
|
| +
|
| + int width() const {
|
| + return pixel_buffer_ ? pixel_buffer_->size().width() : 0;
|
| + }
|
| + int height() const {
|
| + return pixel_buffer_ ? pixel_buffer_->size().height() : 0;
|
| + }
|
|
|
| -namespace pi_generator {
|
| + // Indicate whether a flush is pending. This can only be called from the
|
| + // main thread; it is not thread safe.
|
| + bool flush_pending() const { return flush_pending_; }
|
| + void set_flush_pending(bool flag) { flush_pending_ = flag; }
|
| +
|
| + private:
|
| + // Create and initialize the 2D context used for drawing.
|
| + void CreateContext(const pp::Size& size, float device_scale);
|
| + // Destroy the 2D drawing context.
|
| + void DestroyContext();
|
| + // Push the pixels to the browser, then attempt to flush the 2D context. If
|
| + // there is a pending flush on the 2D context, then update the pixels only
|
| + // and do not flush.
|
| + void FlushPixelBuffer();
|
| +
|
| + void FlushCallback(int32_t result);
|
| +
|
| + bool IsContextValid() const { return graphics_2d_context_ != NULL; }
|
| +
|
| + pp::CompletionCallbackFactory<PiGeneratorInstance> callback_factory_;
|
| + mutable pthread_mutex_t pixel_buffer_mutex_;
|
| + pp::Graphics2D* graphics_2d_context_;
|
| + pp::ImageData* pixel_buffer_;
|
| + bool flush_pending_;
|
| + bool quit_;
|
| + pthread_t compute_pi_thread_;
|
| + int thread_create_result_;
|
| + double pi_;
|
| + float device_scale_;
|
| +
|
| + // ComputePi() estimates Pi using Monte Carlo method and it is executed by a
|
| + // separate thread created in SetWindow(). ComputePi() puts kMaxPointCount
|
| + // points inside the square whose length of each side is 1.0, and calculates
|
| + // the ratio of the number of points put inside the inscribed quadrant divided
|
| + // by the total number of random points to get Pi/4.
|
| + static void* ComputePi(void* param);
|
| +};
|
|
|
| // A small helper RAII class that implements a scoped pthread_mutex lock.
|
| class ScopedMutexLock {
|
| @@ -55,7 +134,7 @@ class ScopedMutexLock {
|
| // A small helper RAII class used to acquire and release the pixel lock.
|
| class ScopedPixelLock {
|
| public:
|
| - explicit ScopedPixelLock(PiGenerator* image_owner)
|
| + explicit ScopedPixelLock(PiGeneratorInstance* image_owner)
|
| : image_owner_(image_owner), pixels_(image_owner->LockPixels()) {}
|
|
|
| ~ScopedPixelLock() {
|
| @@ -66,14 +145,13 @@ class ScopedPixelLock {
|
| uint32_t* pixels() const { return pixels_; }
|
|
|
| private:
|
| - PiGenerator* image_owner_; // Weak reference.
|
| - uint32_t* pixels_; // Weak reference.
|
| -
|
| - ScopedPixelLock(); // Not implemented, do not use.
|
| + PiGeneratorInstance* image_owner_; // Weak reference.
|
| + uint32_t* pixels_; // Weak reference.
|
| };
|
|
|
| -PiGenerator::PiGenerator(PP_Instance instance)
|
| +PiGeneratorInstance::PiGeneratorInstance(PP_Instance instance)
|
| : pp::Instance(instance),
|
| + callback_factory_(this),
|
| graphics_2d_context_(NULL),
|
| pixel_buffer_(NULL),
|
| flush_pending_(false),
|
| @@ -84,7 +162,7 @@ PiGenerator::PiGenerator(PP_Instance instance)
|
| pthread_mutex_init(&pixel_buffer_mutex_, NULL);
|
| }
|
|
|
| -PiGenerator::~PiGenerator() {
|
| +PiGeneratorInstance::~PiGeneratorInstance() {
|
| quit_ = true;
|
| if (thread_create_result_ == 0) {
|
| pthread_join(compute_pi_thread_, NULL);
|
| @@ -96,7 +174,7 @@ PiGenerator::~PiGenerator() {
|
| pthread_mutex_destroy(&pixel_buffer_mutex_);
|
| }
|
|
|
| -void PiGenerator::DidChangeView(const pp::View& view) {
|
| +void PiGeneratorInstance::DidChangeView(const pp::View& view) {
|
| pp::Size size = view.GetRect().size();
|
| float device_scale = view.GetDeviceScale();
|
| size.set_width(static_cast<int>(size.width() * device_scale));
|
| @@ -121,13 +199,15 @@ void PiGenerator::DidChangeView(const pp::View& view) {
|
| }
|
| }
|
|
|
| -bool PiGenerator::Init(uint32_t argc, const char* argn[], const char* argv[]) {
|
| +bool PiGeneratorInstance::Init(uint32_t argc,
|
| + const char* argn[],
|
| + const char* argv[]) {
|
| thread_create_result_ =
|
| pthread_create(&compute_pi_thread_, NULL, ComputePi, this);
|
| return thread_create_result_ == 0;
|
| }
|
|
|
| -uint32_t* PiGenerator::LockPixels() {
|
| +uint32_t* PiGeneratorInstance::LockPixels() {
|
| void* pixels = NULL;
|
| // Do not use a ScopedMutexLock here, since the lock needs to be held until
|
| // the matching UnlockPixels() call.
|
| @@ -139,7 +219,7 @@ uint32_t* PiGenerator::LockPixels() {
|
| return reinterpret_cast<uint32_t*>(pixels);
|
| }
|
|
|
| -void PiGenerator::HandleMessage(const pp::Var& var_message) {
|
| +void PiGeneratorInstance::HandleMessage(const pp::Var& var_message) {
|
| if (!var_message.is_string()) {
|
| PostMessage(pp::Var(kInvalidPiValue));
|
| }
|
| @@ -151,11 +231,11 @@ void PiGenerator::HandleMessage(const pp::Var& var_message) {
|
| }
|
| }
|
|
|
| -void PiGenerator::UnlockPixels() const {
|
| +void PiGeneratorInstance::UnlockPixels() const {
|
| pthread_mutex_unlock(&pixel_buffer_mutex_);
|
| }
|
|
|
| -void PiGenerator::Paint() {
|
| +void PiGeneratorInstance::Paint() {
|
| ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
| if (!scoped_mutex.is_valid()) {
|
| return;
|
| @@ -168,7 +248,8 @@ void PiGenerator::Paint() {
|
| PostMessage(pi_estimate);
|
| }
|
|
|
| -void PiGenerator::CreateContext(const pp::Size& size, float device_scale) {
|
| +void PiGeneratorInstance::CreateContext(const pp::Size& size,
|
| + float device_scale) {
|
| ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
| if (!scoped_mutex.is_valid()) {
|
| return;
|
| @@ -186,7 +267,7 @@ void PiGenerator::CreateContext(const pp::Size& size, float device_scale) {
|
| }
|
| }
|
|
|
| -void PiGenerator::DestroyContext() {
|
| +void PiGeneratorInstance::DestroyContext() {
|
| ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
| if (!scoped_mutex.is_valid()) {
|
| return;
|
| @@ -197,7 +278,7 @@ void PiGenerator::DestroyContext() {
|
| graphics_2d_context_ = NULL;
|
| }
|
|
|
| -void PiGenerator::FlushPixelBuffer() {
|
| +void PiGeneratorInstance::FlushPixelBuffer() {
|
| if (!IsContextValid())
|
| return;
|
| // Note that the pixel lock is held while the buffer is copied into the
|
| @@ -206,15 +287,22 @@ void PiGenerator::FlushPixelBuffer() {
|
| if (flush_pending())
|
| return;
|
| set_flush_pending(true);
|
| - graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
|
| + graphics_2d_context_->Flush(
|
| + callback_factory_.NewCallback(&PiGeneratorInstance::FlushCallback));
|
| }
|
|
|
| -void* PiGenerator::ComputePi(void* param) {
|
| +// This is called by the browser when the 2D context has been flushed to the
|
| +// browser window.
|
| +void PiGeneratorInstance::FlushCallback(int32_t result) {
|
| + set_flush_pending(false);
|
| +}
|
| +
|
| +void* PiGeneratorInstance::ComputePi(void* param) {
|
| int count = 0; // The number of points put inside the inscribed quadrant.
|
| unsigned int seed = 1;
|
| srand(seed);
|
|
|
| - PiGenerator* pi_generator = static_cast<PiGenerator*>(param);
|
| + PiGeneratorInstance* pi_generator = static_cast<PiGeneratorInstance*>(param);
|
| for (int i = 1; i <= kMaxPointCount && !pi_generator->quit(); ++i) {
|
| ScopedPixelLock scoped_pixel_lock(pi_generator);
|
| uint32_t* pixel_bits = scoped_pixel_lock.pixels();
|
| @@ -248,4 +336,16 @@ void* PiGenerator::ComputePi(void* param) {
|
| return 0;
|
| }
|
|
|
| -} // namespace pi_generator
|
| +class PiGeneratorModule : public pp::Module {
|
| + public:
|
| + PiGeneratorModule() : pp::Module() {}
|
| + virtual ~PiGeneratorModule() {}
|
| +
|
| + virtual pp::Instance* CreateInstance(PP_Instance instance) {
|
| + return new PiGeneratorInstance(instance);
|
| + }
|
| +};
|
| +
|
| +namespace pp {
|
| +Module* CreateModule() { return new PiGeneratorModule(); }
|
| +} // namespace pp
|
|
|