Fix osmand build

This commit is contained in:
Victor Shcherb 2012-06-05 09:30:57 +02:00
parent 025274008f
commit 37ba9dcca0
8 changed files with 393 additions and 178 deletions

View file

@ -1,6 +1,7 @@
ifeq ($(ARCH),)
ifndef $(ARCH)
ARCH := x86
endif
############################################
############# NACL ### TARGET
ifeq ($(TARGET),nacl)
@ -26,10 +27,10 @@ CC:=$(TC_PATH)/bin/i686-nacl-gcc
STATICLIB_EXT := a
DYNAMICLIB_EXT := nexe
LIBRARY_PREFIX := lib
LDFLAGS := -lppapi
LDFLAGS := -lppapi_cpp -lppapi
GLOBAL_INCLUDES=-I../zlib/zlib_library -I$(TC_PATH)/i686-nacl/usr/include
RT_NOT_SUPPORTED :=
ZLIB_BUILD :=
RT_NOT_SUPPORTED := defined
ZLIB_BUILD := defined
ifeq ($(ARCH),x86)
CFLAGS += -m32
@ -83,7 +84,9 @@ RANLIB := i586-mingw32msvc-ranlib
WINDRES := i586-mingw32msvc-windres
AR := i586-mingw32msvc-ar
GLOBAL_INCLUDES := -I../pthread/pthreads_library -I../zlib/zlib_library
RT_NOT_SUPPORTED := 1
RT_NOT_SUPPORTED := defined
ZLIB_BUILD := defined
PTHREAD_BUILD := defined
COMMONFLAGS := -D_Windows -DXMD_H -DHAVE_BOOLEAN -DRT_NOT_SUPPORTED
CPP_FLAGS := $(COMMONFLAGS)
CFLAGS := -D_JNI_IMPLEMENTATION $(COMMONFLAGS)

View file

@ -11,6 +11,8 @@ LOCAL_MODULE := osmand_neon
LOCAL_ARM_NEON := true
endif
LOCAL_SRC_FILES += src/java_wrap.cpp
LOCAL_CFLAGS := \
-DGOOGLE_PROTOBUF_NO_RTTI \
-DANDROID_BUILD \

View file

@ -1 +1,2 @@
*.nexe
osmand-*.nexe

View file

@ -69,11 +69,19 @@
appendToEventLog('abort');
}
// When the NaCl module has loaded indicate success.
var piGenerator = null;
var paintInterval = null;
// Start up the paint timer when the NaCl module has loaded.
function moduleDidLoad() {
loadProgressModule = document.getElementById('load_progress');
appendToEventLog('load');
updateStatus('SUCCESS');
piGenerator = document.getElementById('load_progress');
paintInterval = setInterval('load_progress.postMessage("paint")', 50);
}
function pageDidUnload() {
clearInterval(paintInterval);
}
// Handler that gets called when the NaCl module loading has completed.
@ -94,7 +102,8 @@
// Handle a message coming from the NaCl module.
function handleMessage(message_event) {
alert(message_event.data);
// alert(message_event.data);
//document.form.pi.value = message_event.data;
}
// Set the global status message. Updates the 'status_field' element with
@ -195,7 +204,7 @@
-->
<embed name="nacl_module"
id="load_progress"
width=0 height=0
width=500 height=500
src="osmand.nmf"
type="application/x-nacl" />

View file

@ -1,182 +1,266 @@
/* Copyright (c) 2012 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.
*/
// Copyright (c) 2012 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.
/** @file hello_world.c
* This example demonstrates loading, running and scripting a very simple
* NaCl module.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <cmath>
#include <cstring>
#include <string>
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/var.h"
#include <ppapi/cpp/module.h>
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"
#include "osmand_nacl.h"
static PPB_Messaging* ppb_messaging_interface = NULL;
static PPB_Var* ppb_var_interface = NULL;
namespace {
const int kPthreadMutexSuccess = 0;
const char* const kPaintMethodId = "paint";
const double kInvalidPiValue = -1.0;
const int kMaxPointCount = 1000000000; // The total number of points to draw.
const uint32_t kOpaqueColorMask = 0xff000000; // Opaque pixels.
const uint32_t kRedMask = 0xff0000;
const uint32_t kBlueMask = 0xff;
const uint32_t kRedShift = 16;
const uint32_t kBlueShift = 0;
// 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<osmand::PiGenerator*>(data)->set_flush_pending(false);
}
} // namespace
/**
* Creates new string PP_Var from C string. The resulting object will be a
* refcounted string object. It will be AddRef()ed for the caller. When the
* caller is done with it, it should be Release()d.
* @param[in] str C string to be converted to PP_Var
* @return PP_Var containing string.
*/
static struct PP_Var CStrToVar(const char* str) {
if (ppb_var_interface != NULL) {
return ppb_var_interface->VarFromUtf8(str, strlen(str));
namespace osmand {
// A small helper RAII class that implementes a scoped pthread_mutex lock.
class ScopedMutexLock {
public:
explicit ScopedMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) {
if (pthread_mutex_lock(mutex_) != kPthreadMutexSuccess) {
mutex_ = NULL;
}
}
return PP_MakeUndefined();
}
/**
* Called when the NaCl module is instantiated on the web page. The identifier
* of the new instance will be passed in as the first argument (this value is
* generated by the browser and is an opaque handle). This is called for each
* instantiation of the NaCl module, which is each time the <embed> tag for
* this module is encountered.
*
* If this function reports a failure (by returning @a PP_FALSE), the NaCl
* module will be deleted and DidDestroy will be called.
* @param[in] instance The identifier of the new instance representing this
* NaCl module.
* @param[in] argc The number of arguments contained in @a argn and @a argv.
* @param[in] argn An array of argument names. These argument names are
* supplied in the <embed> tag, for example:
* <embed id="nacl_module" dimensions="2">
* will produce two arguments, one named "id" and one named "dimensions".
* @param[in] argv An array of argument values. These are the values of the
* arguments listed in the <embed> tag. In the above example, there will
* be two elements in this array, "nacl_module" and "2". The indices of
* these values match the indices of the corresponding names in @a argn.
* @return @a PP_TRUE on success.
*/
static PP_Bool Instance_DidCreate(PP_Instance instance,
uint32_t argc,
const char* argn[],
const char* argv[]) {
ppb_messaging_interface->PostMessage(instance,
CStrToVar("Osmand application"));
return PP_TRUE;
}
/**
* Called when the NaCl module is destroyed. This will always be called,
* even if DidCreate returned failure. This routine should deallocate any data
* associated with the instance.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
*/
static void Instance_DidDestroy(PP_Instance instance) {
}
/**
* Called when the position, the size, or the clip rect of the element in the
* browser that corresponds to this NaCl module has changed.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] position The location on the page of this NaCl module. This is
* relative to the top left corner of the viewport, which changes as the
* page is scrolled.
* @param[in] clip The visible region of the NaCl module. This is relative to
* the top left of the plugin's coordinate system (not the page). If the
* plugin is invisible, @a clip will be (0, 0, 0, 0).
*/
static void Instance_DidChangeView(PP_Instance instance,
PP_Resource view_resource) {
}
/**
* Notification that the given NaCl module has gained or lost focus.
* Having focus means that keyboard events will be sent to the NaCl module
* represented by @a instance. A NaCl module's default condition is that it
* will not have focus.
*
* Note: clicks on NaCl modules will give focus only if you handle the
* click event. You signal if you handled it by returning @a true from
* HandleInputEvent. Otherwise the browser will bubble the event and give
* focus to the element on the page that actually did end up consuming it.
* If you're not getting focus, check to make sure you're returning true from
* the mouse click in HandleInputEvent.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] has_focus Indicates whether this NaCl module gained or lost
* event focus.
*/
static void Instance_DidChangeFocus(PP_Instance instance,
PP_Bool has_focus) {
}
/**
* Handler that gets called after a full-frame module is instantiated based on
* registered MIME types. This function is not called on NaCl modules. This
* function is essentially a place-holder for the required function pointer in
* the PPP_Instance structure.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
* @return PP_FALSE.
*/
static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
PP_Resource url_loader) {
/* NaCl modules do not need to handle the document load function. */
return PP_FALSE;
}
/**
* Entry points for the module.
* Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var.
* @param[in] a_module_id module ID
* @param[in] get_browser pointer to PPB_GetInterface
* @return PP_OK on success, any other value on failure.
*/
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
PPB_GetInterface get_browser) {
ppb_messaging_interface =
(PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
return PP_OK;
}
/**
* Returns an interface pointer for the interface of the given name, or NULL
* if the interface is not supported.
* @param[in] interface_name name of the interface
* @return pointer to the interface
*/
PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
static PPP_Instance instance_interface = {
&Instance_DidCreate,
&Instance_DidDestroy,
&Instance_DidChangeView,
&Instance_DidChangeFocus,
&Instance_HandleDocumentLoad,
};
return &instance_interface;
~ScopedMutexLock() {
if (mutex_)
pthread_mutex_unlock(mutex_);
}
return NULL;
bool is_valid() const {
return mutex_ != NULL;
}
private:
pthread_mutex_t* mutex_; // Weak reference.
};
// A small helper RAII class used to acquire and release the pixel lock.
class ScopedPixelLock {
public:
explicit ScopedPixelLock(PiGenerator* image_owner)
: image_owner_(image_owner), pixels_(image_owner->LockPixels()) {}
~ScopedPixelLock() {
pixels_ = NULL;
image_owner_->UnlockPixels();
}
uint32_t* pixels() const {
return pixels_;
}
private:
PiGenerator* image_owner_; // Weak reference.
uint32_t* pixels_; // Weak reference.
ScopedPixelLock(); // Not implemented, do not use.
};
PiGenerator::PiGenerator(PP_Instance instance)
: pp::Instance(instance),
graphics_2d_context_(NULL),
pixel_buffer_(NULL),
flush_pending_(false),
quit_(false),
compute_pi_thread_(0),
pi_(0.0) {
pthread_mutex_init(&pixel_buffer_mutex_, NULL);
}
PiGenerator::~PiGenerator() {
quit_ = true;
if (compute_pi_thread_) {
pthread_join(compute_pi_thread_, NULL);
}
DestroyContext();
// The ComputePi() thread should be gone by now, so there is no need to
// acquire the mutex for |pixel_buffer_|.
delete pixel_buffer_;
pthread_mutex_destroy(&pixel_buffer_mutex_);
}
void PiGenerator::DidChangeView(const pp::Rect& position,
const pp::Rect& clip) {
if (position.size().width() == width() &&
position.size().height() == height())
return; // Size didn't change, no need to update anything.
// Create a new device context with the new size.
DestroyContext();
CreateContext(position.size());
// Delete the old pixel buffer and create a new one.
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
delete pixel_buffer_;
pixel_buffer_ = NULL;
if (graphics_2d_context_ != NULL) {
pixel_buffer_ = new pp::ImageData(this,
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
graphics_2d_context_->size(),
false);
}
}
bool PiGenerator::Init(uint32_t argc, const char* argn[], const char* argv[]) {
pthread_create(&compute_pi_thread_, NULL, ComputePi, this);
return true;
}
uint32_t* PiGenerator::LockPixels() {
void* pixels = NULL;
// Do not use a ScopedMutexLock here, since the lock needs to be held until
// the matching UnlockPixels() call.
if (pthread_mutex_lock(&pixel_buffer_mutex_) == kPthreadMutexSuccess) {
if (pixel_buffer_ != NULL && !pixel_buffer_->is_null()) {
pixels = pixel_buffer_->data();
}
}
return reinterpret_cast<uint32_t*>(pixels);
}
void PiGenerator::HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string()) {
PostMessage(pp::Var(kInvalidPiValue));
}
std::string message = var_message.AsString();
if (message == kPaintMethodId) {
Paint();
} else {
PostMessage(pp::Var(kInvalidPiValue));
}
}
void PiGenerator::UnlockPixels() const {
pthread_mutex_unlock(&pixel_buffer_mutex_);
}
void PiGenerator::Paint() {
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
if (!scoped_mutex.is_valid()) {
return;
}
FlushPixelBuffer();
// Post the current estimate of Pi back to the browser.
pp::Var pi_estimate(pi());
// Paint() is called on the main thread, so no need for CallOnMainThread()
// here. It's OK to just post the message.
PostMessage(pi_estimate);
}
void PiGenerator::CreateContext(const pp::Size& size) {
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
if (!scoped_mutex.is_valid()) {
return;
}
if (IsContextValid())
return;
graphics_2d_context_ = new pp::Graphics2D(this, size, false);
if (!BindGraphics(*graphics_2d_context_)) {
printf("Couldn't bind the device context\n");
}
}
void PiGenerator::DestroyContext() {
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
if (!scoped_mutex.is_valid()) {
return;
}
if (!IsContextValid())
return;
delete graphics_2d_context_;
graphics_2d_context_ = NULL;
}
void PiGenerator::FlushPixelBuffer() {
if (!IsContextValid())
return;
// Note that the pixel lock is held while the buffer is copied into the
// device context and then flushed.
graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point());
if (flush_pending())
return;
set_flush_pending(true);
graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
}
void* PiGenerator::ComputePi(void* param) {
int count = 0; // The number of points put inside the inscribed quadrant.
unsigned int seed = 1;
PiGenerator* pi_generator = static_cast<PiGenerator*>(param);
srand(seed);
for (int i = 1; i <= kMaxPointCount && !pi_generator->quit(); ++i) {
ScopedPixelLock scoped_pixel_lock(pi_generator);
uint32_t* pixel_bits = scoped_pixel_lock.pixels();
if (pixel_bits == NULL) {
// Note that if the pixel buffer never gets initialized, this won't ever
// paint anything. Which is probably the right thing to do. Also, this
// clause means that the image will not get the very first few Pi dots,
// since it's possible that this thread starts before the pixel buffer is
// initialized.
continue;
}
double x = static_cast<double>(rand_r(&seed)) / RAND_MAX;
double y = static_cast<double>(rand_r(&seed)) / RAND_MAX;
double distance = sqrt(x * x + y * y);
int px = x * pi_generator->width();
int py = (1.0 - y) * pi_generator->height();
uint32_t color = pixel_bits[pi_generator->width() * py + px];
if (distance < 1.0) {
// Set color to blue.
++count;
pi_generator->pi_ = 4.0 * count / i;
color += 4 << kBlueShift;
color &= kBlueMask;
} else {
// Set color to red.
color += 4 << kRedShift;
color &= kRedMask;
}
pixel_bits[pi_generator->width() * py + px] = color | kOpaqueColorMask;
}
return 0;
}
/**
* Called before the plugin module is unloaded.
*/
PP_EXPORT void PPP_ShutdownModule() {
// The Module class. The browser calls the CreateInstance() method to create
// an instance of your NaCl module on the web page. The browser creates a new
// instance for each <embed> tag with type="application/x-nacl".
class OsmandModule : public pp::Module {
public:
OsmandModule() : pp::Module() {}
virtual ~OsmandModule() {}
// Create and return a PiGeneratorInstance object.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new PiGenerator(instance);
}
};
} // namespace osmand
// Factory function called by the browser when the module is first loaded.
// The browser keeps a singleton of this module. It calls the
// CreateInstance() method on the object you return to make instances. There
// is one instance per <embed> tag on the page. This is the main binding
// point for your NaCl module with the browser.
namespace pp {
Module* CreateModule() {
return new osmand::OsmandModule();
}
} // namespace pp

View file

@ -0,0 +1,116 @@
// Copyright (c) 2012 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.
#ifndef OSMAND_NACL_H_
#define OSMAND_NACL_H_
#include <pthread.h>
#include <map>
#include <vector>
#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"
namespace osmand {
// The Instance class. One of these exists for each instance of your NaCl
// module on the web page. The browser will ask the Module object to create
// a new Instance for each occurrence of the <embed> tag that has these
// attributes:
// type="application/x-nacl"
// nacl="pi_generator.nmf"
class PiGenerator : public pp::Instance {
public:
explicit PiGenerator(PP_Instance instance);
virtual ~PiGenerator();
// 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::Rect& position, const pp::Rect& clip);
// 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;
}
// 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);
// 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();
bool IsContextValid() const {
return graphics_2d_context_ != NULL;
}
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_;
double pi_;
// 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);
};
} // namespace osmand
#endif // OSMAND_NACL_H