summaryrefslogtreecommitdiff
path: root/native_client_sdk
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-10-31 11:16:26 +0000
committerTorne (Richard Coles) <torne@google.com>2013-10-31 11:16:26 +0000
commit1e9bf3e0803691d0a228da41fc608347b6db4340 (patch)
treeab2e5565f71b4219b3da406e19f16fe306704ef5 /native_client_sdk
parentf10b58d5bc6ae3e74076fc4ccca14cbc57ef805c (diff)
downloadchromium_org-1e9bf3e0803691d0a228da41fc608347b6db4340.tar.gz
Merge from Chromium at DEPS revision 232015
This commit was generated by merge_to_master.py. Change-Id: If86767ad396b9e2e1a4c1e9df1427daea29703ef
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-xnative_client_sdk/src/build_tools/build_app.py44
-rw-r--r--native_client_sdk/src/build_tools/build_paths.py2
-rwxr-xr-xnative_client_sdk/src/build_tools/build_sdk.py35
-rw-r--r--native_client_sdk/src/build_tools/generate_make.py1
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list3
-rw-r--r--native_client_sdk/src/doc/devguide/coding/3D-graphics.rst506
-rw-r--r--native_client_sdk/src/doc/devguide/coding/FileIO.rst2
-rw-r--r--native_client_sdk/src/doc/devguide/coding/audio.rst382
-rw-r--r--native_client_sdk/src/doc/devguide/coding/nacl_io.rst225
-rw-r--r--native_client_sdk/src/doc/devguide/devcycle/building.rst46
-rw-r--r--native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst2
-rw-r--r--native_client_sdk/src/doc/devguide/devcycle/running.rst220
-rw-r--r--native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst13
-rw-r--r--native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst496
-rw-r--r--native_client_sdk/src/doc/faq.rst83
-rw-r--r--native_client_sdk/src/doc/images/3d-graphics-render-loop.pngbin20414 -> 21468 bytes
-rw-r--r--native_client_sdk/src/doc/images/icon128.pngbin0 -> 10729 bytes
-rw-r--r--native_client_sdk/src/doc/images/icon16.pngbin0 -> 609 bytes
-rw-r--r--native_client_sdk/src/doc/images/nacl_io1.png (renamed from native_client_sdk/src/doc/images/naclmounts1.png)bin5395 -> 5395 bytes
-rw-r--r--native_client_sdk/src/doc/images/pepper-audio-api.pngbin10268 -> 23444 bytes
-rw-r--r--native_client_sdk/src/doc/images/pepper-audio-buffer.pngbin7790 -> 19761 bytes
-rw-r--r--native_client_sdk/src/doc/index.rst3
-rw-r--r--native_client_sdk/src/doc/nacl-and-pnacl.rst3
-rw-r--r--native_client_sdk/src/doc/overview.rst2
-rw-r--r--native_client_sdk/src/doc/publications-and-presentations.rst43
-rw-r--r--native_client_sdk/src/doc/reference/nacl-manifest-format.rst23
-rw-r--r--native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst9
-rw-r--r--native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst222
-rw-r--r--native_client_sdk/src/doc/sdk/examples.rst3
-rw-r--r--native_client_sdk/src/examples/api/file_io/example.js2
-rw-r--r--native_client_sdk/src/examples/demo/drive/example.dsc9
-rw-r--r--native_client_sdk/src/examples/demo/drive/example.js4
-rw-r--r--native_client_sdk/src/examples/demo/nacl_io/example.js2
-rw-r--r--native_client_sdk/src/examples/tutorial/debugging/example.js2
-rw-r--r--native_client_sdk/src/gonacl_appengine/README66
-rw-r--r--native_client_sdk/src/gonacl_appengine/app.yaml3
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/Makefile255
-rwxr-xr-xnative_client_sdk/src/gonacl_appengine/src/bullet/build.sh29
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/earth/.gitignore1
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/life/Makefile30
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/life/life.c317
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/lua/.gitignore1
-rwxr-xr-xnative_client_sdk/src/gonacl_appengine/src/lua/build.sh74
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile30
-rw-r--r--native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc499
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html4
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js2
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js50
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js6
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js194
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html39
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html30
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js8
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js197
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js233
-rw-r--r--native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html80
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/poll.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/sys/poll.h (renamed from native_client_sdk/src/libraries/nacl_io/poll.h)9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc34
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc40
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc79
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_socket.h2
-rw-r--r--native_client_sdk/src/resources/manifest.json.template7
-rw-r--r--native_client_sdk/src/resources/screenshot_earth_1280.pngbin0 -> 311210 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_gles_1280.pngbin60899 -> 0 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_graphics2d_1280.pngbin0 -> 79160 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_graphics3d_1280.pngbin0 -> 91711 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_life_1280.pngbin0 -> 125249 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_pi_1280.pngbin100971 -> 0 bytes
-rw-r--r--native_client_sdk/src/resources/screenshot_voronoi_1280.pngbin0 -> 79834 bytes
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc79
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc33
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc5
-rw-r--r--native_client_sdk/src/tools/nacl_llvm.mk11
-rwxr-xr-xnative_client_sdk/src/tools/sel_ldr.py2
77 files changed, 4517 insertions, 341 deletions
diff --git a/native_client_sdk/src/build_tools/build_app.py b/native_client_sdk/src/build_tools/build_app.py
index cf16f881a1..577fd97ba5 100755
--- a/native_client_sdk/src/build_tools/build_app.py
+++ b/native_client_sdk/src/build_tools/build_app.py
@@ -31,8 +31,13 @@ def RemoveBuildCruft(outdir):
for f in files:
path = os.path.join(root, f)
ext = os.path.splitext(path)[1]
+ # Remove unwanted files from the package. Also remove manifest.json files
+ # (which we usually want). These ones are the manifests of the invidual
+ # examples, though, which CWS complains about. The master manifest.json
+ # is generated after we call RemoveBuildCruft.
if (ext in ('.d', '.o') or
f == 'dir.stamp' or
+ f == 'manifest.json' or
re.search(r'_unstripped_.*?\.nexe', f)):
buildbot_common.RemoveFile(path)
@@ -73,7 +78,13 @@ def GetStrip(pepperdir, platform, arch, toolchain):
def main(args):
parser = optparse.OptionParser()
- _, args = parser.parse_args(args[1:])
+ parser.add_option('-c', '--channel',
+ help='Channel to display in the name of the package.')
+ options, args = parser.parse_args(args[1:])
+
+ if options.channel:
+ if options.channel not in ('Dev', 'Beta'):
+ parser.error('Unknown channel: %s' % options.channel)
toolchains = ['newlib', 'glibc']
@@ -120,18 +131,6 @@ def main(args):
all_permissions.append({'socket': all_socket_permissions})
pretty_permissions = json.dumps(all_permissions, sort_keys=True, indent=4)
- template_dict = {
- 'name': 'Native Client SDK',
- 'description':
- 'Native Client SDK examples, showing API use and key concepts.',
- 'key': False, # manifests with "key" are rejected when uploading to CWS.
- 'permissions': pretty_permissions,
- 'version': build_version.ChromeVersionNoTrunk()
- }
- easy_template.RunTemplateFile(
- os.path.join(sdk_resources_dir, 'manifest.json.template'),
- os.path.join(app_examples_dir, 'manifest.json'),
- template_dict)
for filename in ['background.js', 'icon128.png']:
buildbot_common.CopyFile(os.path.join(sdk_resources_dir, filename),
os.path.join(app_examples_dir, filename))
@@ -144,6 +143,25 @@ def main(args):
RemoveBuildCruft(app_dir)
StripNexes(app_dir, platform, pepperdir)
+ # Add manifest.json after RemoveBuildCruft... that function removes the
+ # manifest.json files for the individual examples.
+ name = 'Native Client SDK'
+ if options.channel:
+ name += ' (%s)' % options.channel
+ template_dict = {
+ 'name': name,
+ 'channel': options.channel,
+ 'description':
+ 'Native Client SDK examples, showing API use and key concepts.',
+ 'key': False, # manifests with "key" are rejected when uploading to CWS.
+ 'permissions': pretty_permissions,
+ 'version': build_version.ChromeVersionNoTrunk()
+ }
+ easy_template.RunTemplateFile(
+ os.path.join(sdk_resources_dir, 'manifest.json.template'),
+ os.path.join(app_examples_dir, 'manifest.json'),
+ template_dict)
+
app_zip = os.path.join(app_dir, 'examples.zip')
os.chdir(app_examples_dir)
oshelpers.Zip([app_zip, '-r', '*'])
diff --git a/native_client_sdk/src/build_tools/build_paths.py b/native_client_sdk/src/build_tools/build_paths.py
index 941f91b2f4..9f1801ff0e 100644
--- a/native_client_sdk/src/build_tools/build_paths.py
+++ b/native_client_sdk/src/build_tools/build_paths.py
@@ -16,5 +16,7 @@ NACL_DIR = os.path.join(SRC_DIR, 'native_client')
OUT_DIR = os.path.join(SRC_DIR, 'out')
PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi')
NACLPORTS_DIR = os.path.join(OUT_DIR, 'naclports')
+GONACL_APPENGINE_DIR = os.path.join(SDK_SRC_DIR, 'gonacl_appengine')
+GONACL_APPENGINE_SRC_DIR = os.path.join(GONACL_APPENGINE_DIR, 'src')
GSTORE = 'https://commondatastorage.googleapis.com/nativeclient-mirror/nacl/'
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index 6db06d4a82..49d1cbe309 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -42,7 +42,7 @@ import parse_dsc
import verify_filelist
from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR
-from build_paths import NACLPORTS_DIR, GSTORE
+from build_paths import NACLPORTS_DIR, GSTORE, GONACL_APPENGINE_SRC_DIR
# Add SDK make tools scripts to the python path.
sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
@@ -426,9 +426,7 @@ def GypNinjaInstall(pepperdir, toolchains):
['minidump_stackwalk', 'minidump_stackwalk']
]
- if platform != 'mac':
- # Mac doesn't build 64-bit binaries.
- tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
+ tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
if platform == 'linux':
tools_files.append(['nacl_helper_bootstrap',
@@ -479,16 +477,15 @@ def GypNinjaBuild_NaCl(rel_out_dir):
platform = getos.GetPlatform()
if platform == 'win':
NinjaBuild('sel_ldr64', out_dir)
- elif platform == 'linux':
+ else:
out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64')
GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64)
# We only need sel_ldr from the 64-bit out directory.
# sel_ldr needs to be renamed, so we'll call it sel_ldr64.
- files_to_copy = [
- ('sel_ldr', 'sel_ldr64'),
- ('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'),
- ]
+ files_to_copy = [('sel_ldr', 'sel_ldr64')]
+ if platform == 'linux':
+ files_to_copy.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'))
for src, dst in files_to_copy:
buildbot_common.CopyFile(
@@ -861,6 +858,15 @@ def BuildStepTarNaClPorts(pepper_ver, tarfile):
buildbot_common.Run(cmd, cwd=NACL_DIR)
+def BuildStepBuildAppEngine(pepperdir, chrome_revision):
+ """Build the projects found in src/gonacl_appengine/src"""
+ buildbot_common.BuildStep('Build GoNaCl AppEngine Projects')
+ cmd = ['make', 'upload', 'REVISION=%s' % chrome_revision]
+ env = dict(os.environ)
+ env['NACL_SDK_ROOT'] = pepperdir
+ buildbot_common.Run(cmd, env=env, cwd=GONACL_APPENGINE_SRC_DIR)
+
+
def main(args):
parser = optparse.OptionParser()
parser.add_option('--tar', help='Force the tar step.',
@@ -874,14 +880,15 @@ def main(args):
dest='release', default=None)
parser.add_option('--build-ports',
help='Build naclport bundle.', action='store_true')
+ parser.add_option('--build-app-engine',
+ help='Build AppEngine demos.', action='store_true')
parser.add_option('--experimental',
help='build experimental examples and libraries', action='store_true',
dest='build_experimental')
parser.add_option('--skip-toolchain', help='Skip toolchain untar',
action='store_true')
- parser.add_option('--mac_sdk',
- help='Set the mac_sdk (e.g. 10.6) to use when building with ninja.',
- dest='mac_sdk')
+ parser.add_option('--mac-sdk',
+ help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.')
global options
options, args = parser.parse_args(args[1:])
@@ -890,6 +897,7 @@ def main(args):
if buildbot_common.IsSDKBuilder():
options.archive = True
options.build_ports = True
+ options.build_app_engine = True
options.tar = True
toolchains = ['newlib', 'glibc', 'arm', 'pnacl', 'host']
@@ -948,6 +956,9 @@ def main(args):
if options.tar:
BuildStepTarNaClPorts(pepper_ver, ports_tarfile)
+ if options.build_app_engine and getos.GetPlatform() == 'linux':
+ BuildStepBuildAppEngine(pepperdir, chrome_revision)
+
# Archive on non-trybots.
if options.archive:
BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision,
diff --git a/native_client_sdk/src/build_tools/generate_make.py b/native_client_sdk/src/build_tools/generate_make.py
index 2963d0bf03..f694ac9cf3 100644
--- a/native_client_sdk/src/build_tools/generate_make.py
+++ b/native_client_sdk/src/build_tools/generate_make.py
@@ -157,6 +157,7 @@ def GenerateManifest(srcroot, dstroot, desc):
'name': desc['TITLE'],
'description': '%s Example' % desc['TITLE'],
'key': True,
+ 'channel': None,
'permissions': pretty_permissions,
'version': build_version.ChromeVersionNoTrunk()
}
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 5c8c7656dc..73cd38a4f1 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -85,6 +85,7 @@ include/ppapi_simple/*
include/sdk_util/*
[win]include/win/*
include/win/poll.h
+include/win/sys/poll.h
[linux]lib/${PLATFORM}_host/Debug/libgmock.a
[linux]lib/${PLATFORM}_host/Debug/libgtest.a
[linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
@@ -427,4 +428,4 @@ tools/quote.py
tools/run.py
tools/sel_ldr.py
tools/sel_ldr_x86_32${EXE_EXT}
-[linux,win]tools/sel_ldr_x86_64${EXE_EXT}
+tools/sel_ldr_x86_64${EXE_EXT}
diff --git a/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst b/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
index 5c432e0f71..7ca1513eab 100644
--- a/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
+++ b/native_client_sdk/src/doc/devguide/coding/3D-graphics.rst
@@ -4,5 +4,509 @@
3D Graphics
###########
-foo
+Native Client applications use the `OpenGL ES 2.0
+<http://en.wikipedia.org/wiki/OpenGL_ES>`_ API for 3D rendering. This document
+describes how to call the OpenGL ES 2.0 interface in a Native Client module and
+how to build an efficient rendering loop. It also explains how to validate GPU
+drivers and test for specific GPU capabilities, and provides tips to help ensure
+your rendering code runs efficiently.
+.. Note::
+ :class: note
+
+ **Note**: 3D drawing and OpenGL are complex topics. This document deals only
+ with issues directly related to programming in the Native Client
+ environment. To learn more about OpenGL ES 2.0 itself, see the `OpenGL ES 2.0
+ Programming Guide <http://opengles-book.com/>`_.
+
+Validating the client graphics platform
+=======================================
+
+Native Client is a software technology that lets you code an application once
+and run it on multiple platforms without worrying about the implementation
+details on every possible target platform. It's difficult to provide the same
+support at the hardware level. Graphics hardware comes from many different
+manufacturers and is controlled by drivers of varying quality. A particular GPU
+driver may not support every OpenGL ES 2.0 feature, and some drivers are known
+to have vulnerabilities that can be exploited.
+
+Even if the GPU driver is safe to use, your program should perform a validation
+check before you launch your application to ensure that the driver supports all
+the features you need.
+
+Vetting the driver in JavaScript
+--------------------------------
+
+At startup, the application should perform a few additional tests that can be
+implemented in JavaScript on its hosting web page. The script that performs
+these tests should be included before the module's ``embed`` tag, and ideally
+the ``embed`` tag should appear on the hosting page only if these tests succeed.
+
+The first thing to check is whether you can create a graphics context. If you
+can, use the context to confirm the existence of any required OpenGL ES 2.0
+extensions. You may want to refer to the `extension registry
+<http://www.khronos.org/registry/webgl/extensions/>`_ and include `vendor
+prefixes <https://developer.mozilla.org/en-US/docs/WebGL/Using_Extensions>`_
+when checking for extensions.
+
+Vetting the driver in Native Client
+-----------------------------------
+
+Create a context
+^^^^^^^^^^^^^^^^
+
+Once you've passed the JavaScript validation tests, it's safe to add a Native
+Client embed tag to the hosting web page and load the module. As part of the
+module initialization code, you must create a graphics context for the app by
+either creating a C++ ``Graphics3D`` object or calling ``PPB_Graphics3D`` API
+function ``Create``. Don't assume this will always succeed; you still might have
+problems creating the context. If you are in development mode and can't create
+the context, try creating a simpler version to see if you're asking for an
+unsupported feature or exceeding a driver resource limit. Your production code
+should always check that the context was created and fail gracefully if that's
+not the case.
+
+Check for extensions and capabilities
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Not every GPU supports every extension or has the same amount of texture units,
+vertex attributes, etc. On startup, call ``glGetString(GLEXTENSIONS)`` and check
+for the extensions and the features you need. For example:
+
+* If you are using non power-of-2 texture with mipmaps, make sure
+ ``GL_OES_texture_npot`` exists.
+
+* If you are using floating point textures, make sure ``GL_OES_texture_float``
+ exists.
+
+* If you are using DXT1, DXT3, or DXT5 textures, make sure the corresponding
+ extensions ``EXT_texture_compression_dxt1``,
+ ``GL_CHROMIUM_texture_compression_dxt3``, and
+ ``GL_CHROMIUM_texture_compression_dxt5`` exist.
+
+Check for system capabilites with ``glGetIntegerv`` and adjust shader programs
+as well as texture and vertex data accordingly:
+
+* If you are using textures in vertex shaders, make sure
+ ``glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, ...)`` and
+ ``glGetIntegerv(GL_MAX_TEXTURE_SIZE, ...)`` return values greater than 0.
+
+* If you are using more than 8 textures in a single shader, make sure
+ ``glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)`` returns a value greater
+ than or equal to the number of simultaneous textures you need.
+
+Vetting the driver in the Chrome Web Store
+------------------------------------------
+
+If you choose to place your application in the `Chrome Web
+Store <https://developers.google.com/chrome/web-store/docs/>`_, its Web Store
+`manifest file <http://code.google.com/chrome/extensions/manifest.html>`_ can
+include the ``webgl`` feature in the requirements parameter. It looks like this:
+
+.. naclcode::
+
+ "requirements": {
+ "3D": {
+ "features": ["webgl"]
+ }
+ }
+
+While WebGL is technically a JavaScript API, specifying the ``webgl`` feature
+also works for OpenGL ES 2.0 because both interfaces use the same driver.
+
+This manifest item is not required, but if you include it, the Chrome Web Store
+will prevent a user from installing the application if the browser is running on
+a machine that does not support OpenGL ES 2.0 or that is using a known
+blacklisted GPU driver that could invite an attack.
+
+If the Web Store determines that the user's driver is deficient, the app won't
+appear on the store's tile display. However, it will appear in store search
+results or if the user links to it directly, in which case the user could still
+download it. But the manifest requirements will be checked when the user reaches
+the install page, and if there is a problem, the browser will display the
+message "This application is not supported on this computer. Installation has
+been disabled."
+
+The manifest-based check applies only to downloads directly from the Chrome Web
+Store. It is not performed when an application is loaded via `inline
+installation
+<https://developers.google.com/chrome/web-store/docs/inline_installation>`_.
+
+What to do when there are problems
+----------------------------------
+
+Using the vetting procedure described above, you should be able to detect the
+most common problems before your application runs. If there are problems, your
+code should describe the issue as clearly as possible. That's easy if there is a
+missing feature. Failure to create a graphics context is tougher to diagnose. At
+the very least, you can suggest that the user try to update the driver. You
+might want to linke to the Chrome page that describes `how to do updates
+<http://support.google.com/chrome/bin/answer.py?hl=en&answer=1202946>`_.
+
+If a user can't update the driver, or their problem persists, be sure to gather
+information about their graphics environment. Ask for the contents of the Chrome
+``about:gpu`` page.
+
+Document unreliable drivers
+---------------------------
+
+It can be helpful to include information about known dubious drivers in your
+user documentation. This might help identify if a rogue driver is the cause of a
+problem. There are many sources of GPU driver blacklists. Two such lists can be
+found at the `Chromium project
+<http://src.chromium.org/viewvc/chrome/trunk/deps/gpu/software_rendering_list/software_rendering_list.json>`_
+and `Khronos <http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists>`_. You
+can use these lists to include information in your documentation that warns
+users about dangerous drivers.
+
+Test your defenses
+------------------
+
+You can test your driver validation code by running Chrome with the following
+flags (all at once) and watching how your application responds:
+
+* ``--disable-webgl``
+* ``--disable-pepper-3d``
+* ``--disable-gl-multisampling``
+* ``--disable-accelerated-compositing``
+* ``--disable-accelerated-2d-canvas``
+
+Calling OpenGL ES 2.0 commands
+==============================
+
+There are three ways to write OpenGL ES 2.0 calls in Native Client.
+
+Use "pure" OpenGL ES 2.0 function calls
+---------------------------------------
+
+You can make OpenGL ES 2.0 calls through a Pepper extension library. The SDK
+example ``examples/api/graphics_3d`` works this way. In the file
+``graphics_3d.cc``, the key initialization steps are as follows:
+
+* Add these includes at the top of the file:
+
+ .. naclcode::
+
+ #include <GLES2/gl2.h>
+ #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
+
+* Define the function ``InitGL``. The exact specification of ``attrib_list``
+ will be application specific.
+
+ .. naclcode::
+
+ bool InitGL(int32_t new_width, int32_t new_height) {
+ if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
+ fprintf(stderr, "Unable to initialize GL PPAPI!\n");
+ return false;
+ }
+
+ const int32_t attrib_list[] = {
+ PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
+ PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
+ PP_GRAPHICS3DATTRIB_WIDTH, new_width,
+ PP_GRAPHICS3DATTRIB_HEIGHT, new_height,
+ PP_GRAPHICS3DATTRIB_NONE
+ };
+
+ context_ = pp::Graphics3D(this, attrib_list);
+ if (!BindGraphics(context_)) {
+ fprintf(stderr, "Unable to bind 3d context!\n");
+ context_ = pp::Graphics3D();
+ glSetCurrentContextPPAPI(0);
+ return false;
+ }
+
+ glSetCurrentContextPPAPI(context_.pp_resource());
+ return true;
+ }
+
+* Include logic in ``Instance::DidChangeView`` to call ``InitGL`` whenever
+ necessary: upon application launch (when the graphics context is NULL) and
+ whenever the module's View changes size.
+
+Use Regal
+---------
+
+If you are porting an OpenGL ES 2.0 application, or are comfortable writing in
+OpenGL ES 2.0, you should stick with the Pepper APIs or pure OpenGL ES 2.0 calls
+described above. If you are porting an application that uses features not in
+OpenGL ES 2.0, consider using Regal. Regal is an open source library that
+supports many versions of OpenGL. Regal recently added support for Native
+Client. Regal forwards most OpenGL calls directly to the underlying graphics
+library, but it can also emulate other calls that are not included (when
+hardware support exists). See `libregal
+<http://www.altdevblogaday.com/2012/09/04/bringing-regal-opengl-to-native-client/>`_
+for more info.
+
+Use the Pepper API
+------------------
+
+Your code can call the Pepper `PPB_OpenGLES2
+<https://developers.google.com/native-client/pepperc/struct_p_p_b___open_g_l_e_s2>`_
+API directly, as with any Pepper interface. When you write in this way, each
+invocation of an OpenGL ES 2.0 function must begin with a reference to the
+Pepper interface, and the first argument is the graphics context. To invoke the
+function ``glCompileShader``, your code might look like:
+
+.. naclcode::
+
+ ppb_g3d_interface->CompileShader(graphicsContext, shader);
+
+This approach specifically targets the Pepper APIs. Each call corresponds to a
+OpenGL ES 2.0 function, but the syntax is unique to Native Client, so the source
+file is not portable.
+
+Implementing a rendering loop
+=============================
+
+Graphics applications require a continuous frame render-and-redraw cycle that
+runs at a high frequency. To achieve the best frame rate, is important to
+understand how the OpenGL ES 2.0 code in a Native Client module interacts with
+Chrome.
+
+The Chrome and Native Client processes
+--------------------------------------
+
+Chrome is a multi-process browser. Each Chrome tab is a separate process that is
+running an application with its own main thread (we'll call it the Chrome main
+thread). When an application launches a Native Client module, the module runs in
+a new, separate sandboxed process. The module's process has its own main thread
+(the Native Client thread). The Chrome and Native Client processes communicate
+with each other using Pepper API calls on their main threads.
+
+When the Chrome main thread calls the Native Client thread (keyboard and mouse
+callbacks, for example), the Chrome main thread will block. This means that
+lengthy operations on the Native Client thread can steal cycles from Chrome, and
+performing blocking operations on the Native Client thread can bring your app to
+a standstill.
+
+Native Client uses callback functions to synchronize the main threads of the two
+processes. Only certain Pepper functions use callbacks; `SwapBuffers
+<https://developers.google.com/native-client/pepperc/struct_p_p_b___graphics3_d__1__0#a293c6941c0da084267ffba3954793497>`_
+is one.
+
+``SwapBuffers`` and its callback function
+-----------------------------------------
+
+``SwapBuffers`` is non-blocking; it is called from the Native Client thread and
+returns immediately. When ``SwapBuffers`` is called, it runs asynchronously on
+the Chrome main thread. It switches the graphics data buffers, handles any
+needed compositing operations, and redraws the screen. When the screen update is
+complete, the callback function that was included as one of ``SwapBuffer``'s
+arguments will be called from the Chrome thread and executed on the Native
+Client thread.
+
+To create a rendering loop, your Native Client module should include a function
+that does the rendering work and then executes ``SwapBuffers``, passing itself
+as the ``SwapBuffer`` callback. If your rendering code is efficient and runs
+quickly, this scheme will achieve the highest frame rate possible. The
+documentation for ``SwapBuffers`` explains why this is optimal: because the
+callback is executed only when the plugin's current state is actually on the
+screen, this function provides a way to rate-limit animations. By waiting until
+the image is on the screen before painting the next frame, you can ensure you're
+not generating updates faster than the screen can be updated.
+
+The following diagram illustrates the interaction between the Chrome and Native
+Client processes. The application-specific rendering code runs in the function
+called ``Draw`` on the Native Client thread. Blue down-arrows are blocking calls
+from the main thread to Native Client, green up-arrows are non-blocking
+``SwapBuffers`` calls from Native Client to the main thread. All OpenGL ES 2.0
+calls are made from ``Draw`` in the Native Client thread.
+
+.. image:: /images/3d-graphics-render-loop.png
+
+SDK example ``graphics_3d``
+---------------------------
+
+The SDK example ``graphics_3d`` uses the function ``MainLoop`` (in
+``hello_world.cc``) to create a rendering loop as described above. ``MainLoop``
+calls ``Render`` to do the rendering work, and then invokes ``SwapBuffers``,
+passing itself as the callback.
+
+.. naclcode::
+
+ void MainLoop(void* foo, int bar) {
+ if (g_LoadCnt == 3) {
+ InitProgram();
+ g_LoadCnt++;
+ }
+ if (g_LoadCnt > 3) {
+ Render();
+ PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
+ ppb_g3d_interface->SwapBuffers(g_context, cc);
+ } else {
+ PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
+ ppb_core_interface->CallOnMainThread(0, cc, 0);
+ }
+ }
+
+Managing the OpenGL ES 2.0 pipeline
+===================================
+
+OpenGL ES 2.0 commands do not run in the Chrome or Native Client processes. They
+are passed into a FIFO queue in shared memory which is best understood as a `GPU
+command buffer
+<http://www.chromium.org/developers/design-documents/gpu-command-buffer>`_. The
+command buffer is shared by a dedicated GPU process. By using a separate GPU
+process, Chrome implements another layer of runtime security, vetting all OpenGL
+ES 2.0 commands and their arguments before they are sent on to the
+GPU. Buffering commands through the FIFO also speeds up your code, since each
+OpenGL ES 2.0 call in your Native Client thread returns immediately, while the
+processing may be delayed as the GPU works down the commands queued up in the
+FIFO.
+
+Before the screen is updated, all the intervening OpenGL ES 2.0 commands must be
+processed by the GPU. Programmers often try to ensure this by using the
+``glFlush`` and ``glFinish`` commands in their rendering code. In the case of
+Native Client this is usually unnecessary. The ``SwapBuffers`` command does an
+implicit flush, and the Chrome team is continually tweaking the GPU code to
+consume the OpenGL ES 2.0 FIFO as fast as possible.
+
+Sometimes a 3D application can write to the FIFO in a way that's difficult to
+handle. The command pipeline may fill up and your code will have to wait for the
+GPU to flush the FIFO. If this is the case, you may be able to add ``glFlush``
+calls to speed up the flow of the OpenGL ES 2.0 command FIFO. Before you start
+to add your own flushes, first try to determine if pipeline saturation is really
+the problem by monitoring the rendering time per frame and looking for irregular
+spikes that do not consistently fall on the same OpenGL ES 2.0 call. If you're
+convinced the pipeline needs to be accelerated, insert ``glFlush`` calls in your
+code before starting blocks of processing that do not generate OpenGL ES 2.0
+commands. For example, issue a flush before you begin any multithreaded particle
+work, so that the command buffer will be clear when you start doing OpenGL ES
+2.0 calls again. Determining where and how often to call ``glFlush`` can be
+tricky, you will need to experiment to find the sweet spot.
+
+Rendering and inactive tabs
+===========================
+
+Users will often switch between tabs in a multi-tab browser. A well-behaved
+application that's performing 3D rendering should pause any real-time processing
+and yield cycles to other processes when its tab becomes inactive.
+
+In Chrome, an inactive tab will continue to execute timed functions (such as
+``setInterval`` and ``setTimeout``) but the timer interval will be automatically
+overridden and limited to not less than one second while the tab is inactive. In
+addition, any callback associated with a ``SwapBuffers`` call will not be sent
+until the tab is active again. You may receive asynchronous callbacks from
+functions other than ``SwapBuffers`` while a tab is inactive. Depending on the
+design of your application, you might choose to handle them as they arrive, or
+to queue them in a buffer and process them when the tab becomes active.
+
+The time that passes while a tab is inactive can be considerable. If your main
+thread pulse is based on the ``SwapBuffers`` callback, your app won't update
+while a tab is inactive. A Native Client module should be able to detect and
+respond to the state of the tab in which it's running. For example, when a tab
+becomes inactive, you can set an atomic flag in the Native Client thread that
+will skip the 3D rendering and ``SwapBuffers`` calls and continue to call the
+main thread every 30 msec or so. This provides time to update features that
+should still run in the background, like audio. It may also be helpful to call
+``sched_yield`` or ``usleep`` on any worker threads to release resources and
+cede cycles to the OS.
+
+Handling tab activation from the main thread
+--------------------------------------------
+
+You can detect and respond to the activation or deactivation of a tab with
+JavaScript on your hosting page. Add an EventListener for ``visibilitychange``
+that sends a message to the Native Client module, as in this example:
+
+.. naclcode::
+
+ document.addEventListener('visibilitychange', function(){
+ if (document.hidden) {
+ // PostMessage to your Native Client module
+ document.nacl_module.postMessage('INACTIVE');
+ } else {
+ // PostMessage to your Native Client module
+ document.nacl_module.postMessage('ACTIVE');
+ }
+
+ }, false);
+
+Handling tab activation from the Native Client thread
+-----------------------------------------------------
+
+You can also detect and respond to the activation or deactivation of a tab
+directly from your Native Client module by including code in the function
+``pp::Instance::DidChangeView``, which is called whenever a change in the
+module's view occurs. The code can call ``ppb::View::IsPageVisible`` to
+determine if the page is visible or not. The most common cause of invisible
+pages is that the page is in a background tab.
+
+Tips and best practices
+=======================
+
+Here are some suggestions for writing safe code and getting the maximum
+performance with the Pepper 3D API.
+
+Do's
+----
+
+* **Make sure to enable attrib 0.** OpenGL requires that you enable attrib 0,
+ but OpenGL ES 2.0 does not. For example, you can define a vertex shader with 2
+ attributes, numbered like this:
+
+ .. naclcode::
+
+ glBindAttribLocation(program, "positions", 1);
+ glBindAttribLocation(program, "normals", 2);
+
+ In this case the shader is not using attrib 0 and Chrome may have to perform
+ some additional work if it is emulating OpenGL ES 2.0 on top of OpenGL. It's
+ always more efficient to enable attrib 0, even if you do not use it.
+
+* **Check how shaders compile.** Shaders can compile differently on different
+ systems, which can result in ``glGetAttrib*`` functions returning different
+ results. Be sure that the vertex attribute indices match the corresponding
+ name each time you recompile a shader.
+
+* **Update indices sparingly.** For security reasons, all indices must be
+ validated. If you change indices, Native Client will validate them
+ again. Structure your code so indices are not updated often.
+
+* **Use a smaller plugin and let CSS scale it.** If you're running into fillrate
+ issues, it may be beneficial to perform scaling via CSS. The size your plugin
+ renders is determined by the width and height attributes of the ``<embed>``
+ element for the module. The actual size displayed on the web page is
+ controlled by the CSS styles applied to the element.
+
+* **Avoid matrix-to-matrix conversions.** With some versions of Mac OS, there is
+ a driver problem when compiling shaders. If you get compiler errors for matrix
+ transforms, avoid matrix-to-matrix conversions. For instance, upres a vec3 to
+ a vec4 before transforming it by a mat4, rather than converting the mat4 to a
+ mat3.
+
+Don'ts
+------
+
+* **Don't use client side buffers.** OpenGL ES 2.0 can use client side data with
+ ``glVertexAttribPointer`` and ``glDrawElements``, but this is really slow. Try
+ to avoid client side buffers. Use Vertex Buffer Objects (VBOs) instead.
+
+* **Don't mix vertex data and index data.** By default, Pepper 3D binds buffers
+ to a single point. You could create a buffer and bind it to both
+ ``GL_ARRAY_BUFFER`` and ``GL_ELEMENT_ARRAY_BUFFER``, but that would be
+ expensive overhead and it is not recommended.
+
+* **Don't call ``glGet*`` or ``glCheck*`` during rendering.** This is normal
+ advice for OpenGL programs, but is particularly important for 3D on
+ Chrome. Calls to any OpenGL ES 2.0 function whose name begins with these
+ strings blocks the Native Client thread. This includes ``glGetError``; avoid
+ calling it in release builds.
+
+* **Don't use fixed point (``GL_FIXED``) vertex attributes.** Fixed point
+ attributes are not supported in OpenGL ES 2.0, so emulating them in OpenGL ES
+ 2.0 is slow. By default, ``GL_FIXED`` support is turned off in the Pepper 3D
+ API.
+
+* **Don't read data from the GPU.** Don't call ``glReadPixels``, as it is slow.
+
+* **Don't update a small portion of a large buffer.** In the current OpenGL ES
+ 2.0 implementation when you update a portion of a buffer (with
+ ``glSubBufferData`` for example) the entire buffer must be reprocessed. To
+ avoid this problem, keep static and dynamic data in different buffers.
+
+* **Don't call ``glDisable(GL_TEXTURE_2D)``.** This is an OpenGL ES 2.0
+ error. Each time it is called, an error messages will appear in Chrome's
+ ``about:gpu`` tab.
diff --git a/native_client_sdk/src/doc/devguide/coding/FileIO.rst b/native_client_sdk/src/doc/devguide/coding/FileIO.rst
index ed0867e987..6e3a4a5f20 100644
--- a/native_client_sdk/src/doc/devguide/coding/FileIO.rst
+++ b/native_client_sdk/src/doc/devguide/coding/FileIO.rst
@@ -6,4 +6,6 @@ File I/O
foo
+.. _quota_management:
+
.. _enabling_file_access:
diff --git a/native_client_sdk/src/doc/devguide/coding/audio.rst b/native_client_sdk/src/doc/devguide/coding/audio.rst
index f1696e543d..6c76e9a113 100644
--- a/native_client_sdk/src/doc/devguide/coding/audio.rst
+++ b/native_client_sdk/src/doc/devguide/coding/audio.rst
@@ -4,5 +4,385 @@
Audio
#####
-fooooooooooooooooooooo
+.. contents::
+ :local:
+ :backlinks: none
+ :depth: 2
+This chapter describes how to use the Pepper audio API to play an audio
+stream. The Pepper audio API provides a low-level means of playing a stream of
+audio samples generated by a Native Client module. The API generally works as
+follows: A Native Client module creates an audio resource that represents an
+audio stream, and tells the browser to start or stop playing the audio
+resource. The browser calls a function in the Native Client module to fill a
+buffer with audio samples every time it needs data to play from the audio
+stream.
+
+The code examples in this chapter describe a simple Native Client module that
+generates audio samples using a sine wave with a frequency of 440 Hz. The module
+starts playing the audio samples as soon as it is loaded into the browser. For a
+slightly more sophisticated example, see the ``audio`` example (source code in
+the SDK directory ``examples/api/audio``), which lets users specify a frequency
+for the sine wave and click buttons to start and stop audio playback.
+
+Reference information
+=====================
+
+For reference information related to the Pepper audio API, see the following
+documentation:
+
+* `pp::AudioConfig class
+ <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio_config>`_
+
+* `pp::Audio class
+ <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio>`_
+
+* `audio_config.h
+ <https://developers.google.com/native-client/peppercpp/audio__config_8h>`_
+
+* `audio.h <https://developers.google.com/native-client/peppercpp/audio_8h>`_
+
+* `PP_AudioSampleRate
+ <https://developers.google.com/native-client/pepperc/group___enums.html#gaee750c350655f2fb0fe04c04029e0ff8>`_
+
+About the Pepper audio API
+==========================
+
+The Pepper audio API lets Native Client modules play audio streams in a
+browser. To play an audio stream, a module generates audio samples and writes
+them into a buffer. The browser reads the audio samples from the buffer and
+plays them using an audio device on the client computer.
+
+.. image:: /images/pepper-audio-buffer.png
+
+This mechanism is simple but low-level. If you want to play plain sound files in
+a web application, you may want to consider higher-level alternatives such as
+using the HTML ``<audio>`` tag, JavaScript, or the new `Web Audio API
+<http://chromium.googlecode.com/svn/trunk/samples/audio/index.html>`_.
+
+The Pepper audio API is a good option for playing audio data if you want to do
+audio processing in your web application. You might use the audio API, for
+example, if you want to apply audio effects to sounds, synthesize your own
+sounds, or do any other type of CPU-intensive processing of audio
+samples. Another likely use case is gaming applications: you might use a gaming
+library to process audio data, and then simply use the audio API to output the
+processed data.
+
+The Pepper audio API is straightforward to use:
+
+#. Your module creates an audio configuration resource and an audio resource.
+
+#. Your module implements a callback function that fills an audio buffer with
+ data.
+
+#. Your module invokes the StartPlayback and StopPlayback methods of the audio
+ resource (e.g., when certain events occur).
+
+#. The browser invokes your callback function whenever it needs audio data to
+ play. Your callback function can generate the audio data in a number of
+ ways---e.g., it can generate new data, or it can copy pre-mixed data into the
+ audio buffer.
+
+This basic interaction is illustrated below, and described in detail in the
+sections that follow.
+
+.. image:: /images/pepper-audio-api.png
+
+Digital audio concepts
+======================
+
+Before you use the Pepper audio API, it's helpful to understand a few concepts
+that are fundamental to how digital audio is recorded and played back:
+
+sample rate
+ the number of times an input sound source is sampled per second;
+ correspondingly, the number of samples that are played back per second
+
+bit depth
+ the number of bits used to represent a sample
+
+channels
+ the number of input sources recorded in each sampling interval;
+ correspondingly, the number of outputs that are played back simultaneously
+ (typically using different speakers)
+
+The higher the sample rate and bit depth used to record a sound wave, the more
+accurately the sound wave can be reproduced, since it will have been sampled
+more frequently and stored using a higher level of quantization. Common sampling
+rates include 44,100 Hz (44,100 samples/second, the sample rate used on CDs),
+and 48,000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common
+bit depth is 16 bits per sample, and a common number of channels is 2 (left and
+right channels for stereo sound).
+
+.. _pepper_audio_configurations:
+
+The Pepper audio API currently lets Native Client modules play audio streams
+with the following configurations:
+
+* **sample rate**: 44,100 Hz or 48,000 Hz
+* **bit depth**: 16
+* **channels**: 2 (stereo)
+
+Setting up the module
+=====================
+
+The code examples below describe a simple Native Client module that generates
+audio samples using a sine wave with a frequency of 440 Hz. The module starts
+playing the audio samples as soon as it is loaded into the browser.
+
+The Native Client module is set up by implementing subclasses of the
+``pp::Module`` and ``pp::Instance`` classes, as normal.
+
+.. naclcode::
+
+ class SineSynthInstance : public pp::Instance {
+ public:
+ explicit SineSynthInstance(PP_Instance instance);
+ virtual ~SineSynthInstance() {}
+
+ // Called by the browser once the NaCl module is loaded and ready to
+ // initialize. Creates a Pepper audio context and initializes it. Returns
+ // true on success. Returning false causes the NaCl module to be deleted
+ // and no other functions to be called.
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+
+ private:
+ // Function called by the browser when it needs more audio samples.
+ static void SineWaveCallback(void* samples,
+ uint32_t buffer_size,
+ void* data);
+
+ // Audio resource.
+ pp::Audio audio_;
+
+ ...
+
+ };
+
+ class SineSynthModule : public pp::Module {
+ public:
+ SineSynthModule() : pp::Module() {}
+ ~SineSynthModule() {}
+
+ // Create and return a SineSynthInstance object.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new SineSynthInstance(instance);
+ }
+ };
+
+Creating an audio configuration resource
+========================================
+
+Resources
+---------
+
+Before the module can play an audio stream, it must create two resources: an
+audio configuration resource and an audio resource. Resources are handles to
+objects that the browser provides to module instances. An audio resource is an
+object that represents the state of an audio stream, including whether the
+stream is paused or being played back, and which callback function to invoke
+when the samples in the stream's buffer run out. An audio configuration resource
+is an object that stores configuration data for an audio resource, including the
+sampling frequency of the audio samples, and the number of samples that the
+callback function must provide when the browser invokes it.
+
+Sample frame count
+------------------
+
+Prior to creating an audio configuration resource, the module should call
+``RecommendSampleFrameCount`` to obtain a *sample frame count* from the
+browser. The sample frame count is the number of samples that the callback
+function must provide per channel each time the browser invokes the callback
+function. For example, if the sample frame count is 4096 for a stereo audio
+stream, the callback function must provide a 8192 samples (4096 for the left
+channel and 4096 for the right channel).
+
+The module can request a specific sample frame count, but the browser may return
+a different sample frame count depending on the capabilities of the client
+device. At present, ``RecommendSampleFrameCount`` simply bound-checks the
+requested sample frame count (see ``include/ppapi/c/ppb_audio_config.h`` for the
+minimum and maximum sample frame counts, currently 64 and 32768). In the future,
+``RecommendSampleFrameCount`` may perform a more sophisticated calculation,
+particularly if there is an intrinsic buffer size for the client device.
+
+Selecting a sample frame count for an audio stream involves a tradeoff between
+latency and CPU usage. If you want your module to have short audio latency so
+that it can rapidly change what's playing in the audio stream, you should
+request a small sample frame count. That could be useful in gaming applications,
+for example, where sounds have to change frequently in response to game
+action. However, a small sample frame count results in higher CPU usage, since
+the browser must invoke the callback function frequently to refill the audio
+buffer. Conversely, a large sample frame count results in higher latency but
+lower CPU usage. You should request a large sample frame count if your module
+will play long, uninterrupted audio segments.
+
+Supported audio configurations
+------------------------------
+
+After the module obtains a sample frame count, it can create an audio
+configuration resource. Currently the Pepper audio API supports audio streams
+with the configuration settings shown :ref:`above<pepper_audio_configurations>`.
+C++ modules can create a configuration resource by instantiating a
+``pp::AudioConfig`` object. Check ``audio_config.h`` for the latest
+configurations that are supported.
+
+.. naclcode::
+
+ bool SineSynthInstance::Init(uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+
+ // Ask the browser/device for an appropriate sample frame count size.
+ sample_frame_count_ =
+ pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
+ kSampleFrameCount);
+
+ // Create an audio configuration resource.
+ pp::AudioConfig audio_config = pp::AudioConfig(this,
+ PP_AUDIOSAMPLERATE_44100,
+ sample_frame_count_);
+
+ // Create an audio resource.
+ audio_ = pp::Audio(this,
+ audio_config,
+ SineWaveCallback,
+ this);
+
+ // Start playback when the module instance is initialized.
+ return audio_.StartPlayback();
+ }
+
+Creating an audio resource
+==========================
+
+Once the module has created an audio configuration resource, it can create an
+audio resource. To do so, it instantiates a ``pp::Audio`` object, passing in a
+pointer to the module instance, the audio configuration resource, a callback
+function, and a pointer to user data (data that is used in the callback
+function). See the example above.
+
+Implementing a callback function
+================================
+
+The browser calls the callback function associated with an audio resource every
+time it needs more samples to play. The callback function can generate new
+samples (e.g., by applying sound effects), or copy pre-mixed samples into the
+audio buffer. The example below generates new samples by computing values of a
+sine wave.
+
+The last parameter passed to the callback function is generic user data that the
+function can use in processing samples. In the example below, the user data is a
+pointer to the module instance, which includes member variables
+``sample_frame_count_`` (the sample frame count obtained from the browser) and
+``theta_`` (the last angle that was used to compute a sine value in the previous
+callback; this lets the function generate a smooth sine wave by starting at that
+angle plus a small delta).
+
+.. naclcode::
+
+ class SineSynthInstance : public pp::Instance {
+ public:
+ ...
+
+ private:
+ static void SineWaveCallback(void* samples,
+ uint32_t buffer_size,
+ void* data) {
+
+ // The user data in this example is a pointer to the module instance.
+ SineSynthInstance* sine_synth_instance =
+ reinterpret_cast<SineSynthInstance*>(data);
+
+ // Delta by which to increase theta_ for each sample.
+ const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100;
+ // Amount by which to scale up the computed sine value.
+ const int16_t max_int16 = std::numeric_limits<int16_t>::max();
+
+ int16_t* buff = reinterpret_cast<int16_t*>(samples);
+
+ // Make sure we can't write outside the buffer.
+ assert(buffer_size >= (sizeof(*buff) * kChannels *
+ sine_synth_instance->sample_frame_count_));
+
+ for (size_t sample_i = 0;
+ sample_i < sine_synth_instance->sample_frame_count_;
+ ++sample_i, sine_synth_instance->theta_ += delta) {
+
+ // Keep theta_ from going beyond 2*Pi.
+ if (sine_synth_instance->theta_ > kTwoPi) {
+ sine_synth_instance->theta_ -= kTwoPi;
+ }
+
+ // Compute the sine value for the current theta_, scale it up,
+ // and write it into the buffer once for each channel.
+ double sin_value(std::sin(sine_synth_instance->theta_));
+ int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
+ for (size_t channel = 0; channel < kChannels; ++channel) {
+ *buff++ = scaled_value;
+ }
+ }
+ }
+
+ ...
+ };
+
+Application threads and real-time requirements
+----------------------------------------------
+
+The callback function runs in a background application thread. This allows audio
+processing to continue even when the application is busy doing something
+else. If the main application thread and the callback thread access the same
+data, you may be tempted to use a lock to control access to that data. You
+should avoid the use of locks in the callback thread, however, as attempting to
+acquire a lock may cause the thread to get swapped out, resulting in audio
+dropouts.
+
+In general, you must program the callback thread carefully, as the Pepper audio
+API is a very low level API that needs to meet hard real-time requirements. If
+the callback thread spends too much time processing, it can easily miss the
+real-time deadline, resulting in audio dropouts. One way the callback thread can
+miss the deadline is by taking too much time doing computation. Another way the
+callback thread can miss the deadline is by executing a function call that swaps
+out the callback thread. Unfortunately, such function calls include just about
+all C Run-Time (CRT) library calls and Pepper API calls. The callback thread
+should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical
+sections, and so forth; any such calls could attempt to take a lock and swap out
+the callback thread, which would be disastrous for audio playback. Similarly,
+the callback thread should avoid Pepper API calls. Audio dropouts due to thread
+swapping can be very rare and very hard to track down and debug---it's best to
+avoid making system/Pepper calls in the first place. In short, the audio
+(callback) thread should use "lock-free" techniques and avoid making CRT library
+calls.
+
+One other issue to be aware of is that the ``StartPlayback`` function (discussed
+below) is an asynchronous RPC; i.e., it does not block. That means that the
+callback function may not be called immediately after the call to
+``StartPlayback``. If it's important to synchronize the callback thread with
+another thread so that the audio stream starts playing simultaneously with
+another action in your application, you must handle such synchronization
+manually.
+
+Starting and stopping playback
+==============================
+
+To start and stop audio playback, the module simply reacts to JavaScript
+messages.
+
+.. naclcode::
+
+ const char* const kPlaySoundId = "playSound";
+ const char* const kStopSoundId = "stopSound";
+
+ void SineSynthInstance::HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_string()) {
+ return;
+ }
+ std::string message = var_message.AsString();
+ if (message == kPlaySoundId) {
+ audio_.StartPlayback();
+ } else if (message == kStopSoundId) {
+ audio_.StopPlayback();
+ } else if (...) {
+ ...
+ }
+ }
diff --git a/native_client_sdk/src/doc/devguide/coding/nacl_io.rst b/native_client_sdk/src/doc/devguide/coding/nacl_io.rst
new file mode 100644
index 0000000000..6cee0f7525
--- /dev/null
+++ b/native_client_sdk/src/doc/devguide/coding/nacl_io.rst
@@ -0,0 +1,225 @@
+###################
+The nacl_io Library
+###################
+
+.. contents::
+ :local:
+ :backlinks: none
+ :depth: 2
+
+Introduction
+============
+
+``nacl_io`` is a utility library that provides implementations of standard
+C APIs such as POSIX I/O (``stdio.h``) and BSD sockets (``sys/socket.h``).
+Its primary function is to allow code that uses these standard APIs to be
+compiled and used in a Native Client module. The library is included as part
+of Native Client SDK and is implemented in on top of Pepper API.
+
+Since Native Client modules cannot access the host machine's file system
+directly, nacl_io provides several alternative filesystem types which
+can be used by the application. For example, the Chrome browser supports the
+`HTML5 File System API
+<http://www.html5rocks.com/en/tutorials/file/filesystem/>`_ which provides
+access to a protected area of the local file system. This filesystem can
+be accessed by an HTML page using JavaScript commands, and also by a Native
+Client module using the Pepper :doc:`File IO API <FileIO>`. With nacl_io
+a Native Client application can mount an HTML5 filesystem and access it via
+standard POSIX I/O function such as ``fopen``, ``fseek``, ``fread``,
+``fwrite``, and ``fclose``, or their low level UNIX counterparts ``open``,
+``lseek``, ``read``, ``write`` and ``close``.
+
+As well as the HTML5 file system, nacl_io provides several other file system
+types which are described in the table below:
+
+=========== ==================================================================
+File System Description
+=========== ==================================================================
+memfs An in-memory file system
+html5fs An HTML5 local file system, which can be persistent or temporary
+http Maps files on a remote webserver into the local filesystem.
+dev A file system containing special files (e.g.: ``/dev/null``)
+=========== ==================================================================
+
+Using nacl_io
+=============
+
+Using nacl_io is mostly just a matter of using the standard POSIX C library
+functions. However, there are some steps required to initialize the library
+and setup the filesystem mounts. In general the following steps will be needed
+to use nacl_io in a NaCl application:
+
+#. Link the application with the nacl_io library (``-lnacl_io``)
+#. Initialize nacl_io at startup using the ``nacl_io_init_ppapi`` or
+ ``nacl_io_init`` functions.
+#. Mount any desired filesystems using the ``mount`` function. The arguments
+ to ``mount`` for the different filesystem types are detailed in
+ ``include/nacl_io/nacl_io.h``.
+#. If you are going to mount an HTML5 file system, be sure to allocate space
+ for it. You can either set the ``unlimitedStorage`` permission in the app's
+ Web Store manifest file, or call the HTML5 QuotaManagement API. These
+ options are explained in the :ref:`File IO documentation <quota_management>`.
+#. Make sure that file and socket API calls are all made from the background
+ thread. This is because the main Pepper thread does not support the blocking
+ behavior needed by the POSIX I/O operations.
+
+The nacl_io demo
+================
+
+Building and running the demo
+-----------------------------
+
+The demo application launches a Native Client module that mounts three file
+systems and displays a set of controls that let you work with them:
+
+.. image:: /images/nacl_io1.png
+
+Follow these steps to build and run the demo:
+
+* Open a terminal in the demo directory::
+
+ $ cd $NACL_SDK_ROOT/examples/demo/nacl_io
+
+* run the demo::
+
+ $ make run
+
+Once the demo is running, try these operations:
+
+#. select the fopen command (when you select a command the fields in the line
+ below will change according to the command)
+#. type in the filename ``/persistent/test``
+#. check the write checkbox and press the fopen button
+#. select the fwrite command and select the file ``/persistent/test`` in the
+ menu that appears below on the left
+#. enter some data and press the fwrite button
+#. select the fclose command, be sure the file ``/persistent/test`` is selected
+ in the menu, and press the fclose button
+#. select the fopen command
+#. type in the filename ``/persistent/test``
+#. check the fread checkbox and press the fopen button
+#. select the fread command, be sure the file /persistent/test is selected in
+ the menu, enter a byte count, and press the fread button
+
+A look at the code
+------------------
+
+The demo is written C and comprises three files.
+
+nacl_io_demo.c
+^^^^^^^^^^^^^^
+
+This is the demo's main file. The code here creates and initializes the Native
+Client module instance. The Pepper function ``Instance_DidCreate`` initializes
+nacl_io and mounts an HTML5 filesystem at ``/persistent``.
+
+.. naclcode::
+
+ static PP_Bool Instance_DidCreate(PP_Instance instance,
+ uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+ g_instance = instance;
+ nacl_io_init_ppapi(instance, get_browser_interface);
+ mount(
+ "", /* source */
+ "/persistent", /* target */
+ "html5fs", /* filesystemtype */
+ 0, /* mountflags */
+ "type=PERSISTENT,expected_size=1048576"); /* data specific to the html5fs type */
+
+ pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
+ InitializeMessageQueue();
+
+ return PP_TRUE;
+ }
+
+Space is allocated to the ``/persistent`` file system after the module is
+initialized. This is accomplished by the ``domContentLoaded`` function in
+the file ``example.js``. This script is included in the module's html page (see
+``examples/demo/index.html``):
+
+.. naclcode::
+
+ function domContentLoaded(name, tc, config, width, height) {
+ navigator.webkitPersistentStorage.requestQuota(window.PERSISTENT, 1024 * 1024,
+ function(bytes) {
+ common.updateStatus(
+ 'Allocated ' + bytes + ' bytes of persistant storage.');
+ common.createNaClModule(name, tc, config, width, height);
+ common.attachDefaultListeners();
+ },
+ function(e) { alert('Failed to allocate space') });
+ }
+
+The ``Instance_DidCreate`` function also creates a worker thread that receives
+messages sent from the html page and performs the specified file system
+operations. The logic for the worker thread is encoded in the other two files,
+described below.
+
+queue.c
+^^^^^^^
+
+This file implements a circular queue that is used to receive messages from the
+browser UI to the Native Client module. The file system commands in the
+enqueued messages are executed on the worker thread. This keeps blocking calls
+(like fread) off the main Native Client thread, which is a good thing. The
+queue is initialized in nacl_io_demo.c ``Instance_DidCreate``.
+
+handlers.c
+^^^^^^^^^^
+
+This file implements the stdio calls associated with the commands sent from the
+browser. There is a separate ``Handle*`` function for each command: fopen,
+fclose, fseek, fread, fwrite. The handlers are called from the
+``HandleMessage`` function in nacl_io_demo.c, which runs in the worker
+thread managing the message queue. The code for the ``fwrite`` handler appears
+below. Notice that it does not contain any PPAPI calls and looks like
+"ordinary" C code.
+
+
+.. naclcode::
+
+ int HandleFwrite(int num_params, char** params, char** output) {
+ FILE* file;
+ const char* file_index_string;
+ const char* data;
+ size_t data_len;
+ size_t bytes_written;
+
+ if (num_params != 2) {
+ *output = PrintfToNewString("Error: fwrite takes 2 parameters.");
+ return 1;
+ }
+
+ file_index_string = params[0];
+ file = GetFileFromIndexString(file_index_string, NULL);
+ data = params[1];
+ data_len = strlen(data);
+
+ if (!file) {
+ *output = PrintfToNewString("Error: Unknown file handle %s.",
+ file_index_string);
+ return 2;
+ }
+
+ bytes_written = fwrite(data, 1, data_len, file);
+
+ *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string,
+ bytes_written);
+ return 0;
+ }
+
+Reference information
+=====================
+
+The example discussed here is included in the SDK in the directory
+``examples/demo/nacl_io``.
+
+The nacl_io library is included in the SDK toolchain and is not a part of the
+Pepper API. For reference information related to the nacl_io interface see
+its header file in the SDK directory, located at
+``include/nacl_io/nacl_io.h``.
+
+For more about the HTML5 file system read the `specification
+<http://dev.w3.org/2009/dap/file-system/pub/FileSystem/>`_.
diff --git a/native_client_sdk/src/doc/devguide/devcycle/building.rst b/native_client_sdk/src/doc/devguide/devcycle/building.rst
index d1a6b04eba..8d5ab3d2a4 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/building.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/building.rst
@@ -62,13 +62,14 @@ See :doc:`Dynamic Linking & Loading with glibc <dynamic-loading>`
for information about these libraries, including factors to help you
decide which to use.
+.. _building_cpp_libraries:
C++ libraries
-------------
The PNaCl SDK can use either
`libstdc++ <http://gcc.gnu.org/libstdc++>`_ (the current default)
-or LLVM's `libc++ <http://libcxx.llvm.org/>`_ (preliminary support).
+or LLVM's `libc++ <http://libcxx.llvm.org/>`_ (experimental support).
The ``-stdlib=[libstdc++|libc++]`` command line argument can be used
to choose which standard library to use.
@@ -78,7 +79,8 @@ The GCC-based Native Client SDK only has support for
C++11 library support is only complete in libc++ but other non-library
language features should work regardless of which standard library is
used. The ``-std=[c++98|c++11]`` command line argument can be used to
-indicate which C++ language standard to use.
+indicate which C++ language standard to use (or ``-std=gnu++11`` with
+non-standard extensions).
SDK toolchains
--------------
@@ -94,7 +96,7 @@ toolchains are located in directories named
* *<architecture>* is your target architecture (x86 or arm)
* *<library>* is the C library you are compiling with (newlib or glibc)
-The compilers, linkers, and other tools are located in the ``bin/``
+The compilers, linkers, and other tools are located in the ``bin/``
subdirectory in each toolchain. For example, the tools in the Windows SDK
for PNaCl has a C++ compiler in ``toolchain/win_pnacl/bin/pnacl-clang++``.
As another example, the GCC-based C++ compiler that targets the x86 and uses the
@@ -154,6 +156,8 @@ architecture-specific .nexe (e.g., for debugging purposes).
Each tool's name is preceded by the prefix "pnacl-". Some of the useful
tools include:
+pnacl-abicheck
+ Check that the **pexe** follows the PNaCl ABI rules.
pnacl-ar
Creates archives (e.g., static libraries)
pnacl-clang
@@ -618,5 +622,37 @@ Here is one way to find the appropriate library for a given symbol:
<NACL_SDK_ROOT>/toolchain/<platform>_pnacl/bin/pnacl-nm -o \
toolchain/<platform>_pnacl/usr/lib/*.a | grep <MySymbolName>
-.. TODO(jvoung): Add some notes about debugging GNU-extensions not
-.. supported by PNaCl ABI stabilization passes, like computed gotos?
+
+PNaCl ABI Verification errors
+-----------------------------
+
+PNaCl has restrictions on what is supported in bitcode. There is a bitcode
+ABI verifier which checks that the application conforms to the ABI restrictions,
+before it is translated and run in the browser. However, it is best to
+avoid runtime errors for users, so the verifier also runs on the developer's
+machine at link time.
+
+For example, the following program which uses 128-bit integers
+would compile with NaCl GCC for the x86-64 target. However, it is not
+portable and would not compile with NaCl GCC for the i686 target.
+With PNaCl, it would fail to pass the ABI verifier:
+
+.. naclcode::
+
+ typedef unsigned int uint128_t __attribute__((mode(TI)));
+
+ uint128_t foo(uint128_t x) {
+ return x;
+ }
+
+With PNaCl you would get the following error at link time:
+
+.. naclcode::
+
+ Function foo has disallowed type: i128 (i128)
+ LLVM ERROR: PNaCl ABI verification failed
+
+When faced with a PNaCl ABI verification error, check the list of features
+that are :ref:`not supported by PNaCl <when-to-use-nacl>`.
+If the problem you face is not listed as restricted,
+:ref:`let us know <help>`!
diff --git a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
index a0f8255b54..00b76bb3a5 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
@@ -317,6 +317,8 @@ example, the shared objects are put into the subdirectories ``lib32`` and
``lib64``. These directories are used to collect all the shared libraries
needed by the application, as discussed below.
+.. _dynamic_loading_manifest:
+
Generating a Native Client manifest file for a dynamically linked application
=============================================================================
diff --git a/native_client_sdk/src/doc/devguide/devcycle/running.rst b/native_client_sdk/src/doc/devguide/devcycle/running.rst
index 17d8ad5e49..3b3273a08a 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/running.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/running.rst
@@ -4,7 +4,7 @@
Running
#######
-.. contents:: Table Of Contents
+.. contents::
:local:
:backlinks: none
:depth: 2
@@ -15,6 +15,27 @@ Introduction
This document describes how to run Native Client applications during
development.
+The workflow for PNaCl applications is straightfoward and will only be discussed
+briefly. For NaCl applications distributed through the web-store, there is a
+number of options and these will be discussed more in-depth.
+
+Portable Native Client (PNaCl) applications
+===========================================
+
+Running PNaCl applications from the open web is enabled in Chrome version 31 and
+above; therefore, no special provisions are required to run and test such
+applications locally. An application that uses a PNaCl module can be tested
+similarly to any other web application that only consists of HTML, CSS and
+JavaScript.
+
+To better simulate a production environment, it's recommended to start a local
+web server to serve the application's files. The NaCl SDK comes with a simple
+local server built in, and the process of using it to run PNaCl applications is
+described in :ref:`the tutorial <tutorial_step_2>`.
+
+Native Client applications and the Chrome Web Store
+===================================================
+
Before reading about how to run Native Client applications, it's important to
understand a little bit about how Native Client applications are distributed.
As explained in :doc:`Distributing Your Application <../distributing>`, Native
@@ -43,42 +64,67 @@ below. Each technique has certain requirements (NaCl flag, web server, and/or
CWS metadata); these are explained in the :ref:`Requirements <requirements>`
section below.
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| Technique | Requires NaCl flag | Requires web server | Requires CWS metadata | Description |
-+===========+======================+=====================+=======================+=============+
-| 1 | local server | | | |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 2 | packaged application | | | |
-| | loaded as an | | | |
-| | unpacked extension | | | |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 3 | hosted application | | | |
-| | loaded as an unpacked| | | |
-| | extension | | | |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-| 4 | Chrome Web Store | | | |
-| | application with | | | |
-| | trusted testers | | | |
-+-----------+----------------------+---------------------+-----------------------+-------------+
-
-Which of the above techniques you use to run your application during
-development is largely a matter of personal preference (i.e., would you rather
-start a local server or create CWS metadata?). As a general rule, once you have
-an idea of how you plan to distribute your application, you should use the
-corresponding technique during development (technique # 2 for packaged
-applications and extensions; technique # 3 for hosted applications). Choosing a
-distribution option depends on a number of factors such as application size,
-application start-up time, hosting costs, offline functionality, etc. (see
-:doc:`Distributing Your Application <../distributing>` for details), but you
-don't need to make a decision about how to distribute your application at the
-outset.
+.. list-table::
+ :header-rows: 1
+
+ * - #
+ - Technique
+ - Requires NaCl flag
+ - Requires Web Server
+ - Requires CWS Metadata
+ - Description
+ * - 1
+ - Local server
+ - |CHK|
+ - |CHK|
+ -
+ - Run a local server and simply point your browser to your application on
+ the server.
+ * - 2
+ - Packaged application loaded as an unpacked extension
+ -
+ -
+ - |CHK|
+ - Load your packaged application into Chrome as an unpacked extension and
+ run it without a server. An unpacked extension is simply an application
+ whose source and metadata files are located in a plain (unzipped) folder
+ on your development machine. The CWS manifest file (explained below) must
+ specify a ``local_path`` field.
+ * - 3
+ - Hosted application loaded as an unpacked extension
+ -
+ - |CHK|
+ - |CHK|
+ - Load your hosted application into Chrome as an unpacked extension and run
+ it from a server (which can be a local server). The CWS manifest file
+ must specify a ``web_url`` field.
+ * - 4
+ - CWS application with untrusted testers
+ -
+ -
+ - |CHK|
+ - This is the standard technique for distributing a packaged or hosted
+ application in the CWS, but you can limit the application to a few
+ trusted testers. This technique requires a server if your application is
+ a hosted application.
+
+.. |CHK| image:: /images/check-red.png
+
+Which of the above techniques you use to run your application during development
+is largely a matter of personal preference (i.e., would you rather start a local
+server or create CWS metadata?). As a general rule, once you have an idea of how
+you plan to distribute your application, you should use the corresponding
+technique during development. Choosing a distribution option depends on a number
+of factors such as application size, application start-up time, hosting costs,
+offline functionality, etc. (see :doc:`Distributing Your Application
+<../distributing>` for details), but you don't need to make a decision about how
+to distribute your application at the outset.
The next two sections of this document describe a couple of prerequisites for
-running applications during development (using the correct version of Chrome
-and turning off the Chrome cache), and explain the three requirements listed in
-the table above (NaCl flag, web server, and CWS metadata). The subsequent
-sections of the document provide instructions for how to use each of the four
-techniques.
+running applications during development, and explain the three requirements
+listed in the table above (NaCl flag, web server, and CWS metadata). The
+subsequent sections of the document provide instructions for how to use each of
+the four techniques.
Prerequisites
=============
@@ -91,28 +137,17 @@ correct version of Chrome. Each version of Chrome supports a corresponding
version of the Pepper API. You (and your users) must use a version of Chrome
that is equal to or higher than the version of the Pepper API that your
application uses. For example, if you compiled your application using the
-``pepper_28`` bundle, your application uses the Pepper 28 API, and you must run
-the application in Chrome 28 or higher. To check which version of Chrome you're
-using, type ``about:chrome`` or ``about:version`` in the Chrome address bar
-(the latter address shows additional information such as the Chrome command
-line and profile path).
-
-If your application requires a minimum version of Chrome, you are encouraged to
-include code in the application to check that the user's browser is compatible
-with the application. For sample code that checks the user's browser version,
-refer to the ``load_progress`` example in the Native Client SDK.
+``pepper_31`` bundle, your application uses the Pepper 31 API, and you must run
+the application in Chrome 31 or higher. To check which version of Chrome you're
+using, type ``about:version`` in the Chrome address bar.
Chrome Cache
------------
-Chrome caches resources aggressively. You should disable Chrome's cache
-whenever you are developing a Native Client application in order to make sure
-Chrome loads new versions of your application. To disable the cache:
-
-#. Open Chrome's developer tools by clicking the menu icon |menu-icon| and
- choosing **Tools > Developer tools**.
-#. Click the gear icon in the bottom right corner of the Chrome window.
-#. Under the "General" settings, check the box next to "Disable cache".
+Chrome caches resources aggressively. You should disable Chrome's cache whenever
+you are developing a Native Client application in order to make sure Chrome
+loads new versions of your application. Follow the instructions :ref:`in the
+tutorial <tutorial_step_3>`.
.. _requirements:
@@ -136,9 +171,9 @@ Client flag in Chrome as follows:
#. If the link below "Native Client" says "Enable":
* Click the "Enable" link.
- * Scroll down to the bottom of the page and click the "Relaunch Now" button.
- **Native Client will not be enabled until you relaunch your browser**. All
- browser windows will restart when you relaunch Chrome.
+ * Click the "Relaunch Now" button in the bottom of the screen. **Native
+ Client will not be enabled until you relaunch your browser**. All browser
+ windows will restart when you relaunch Chrome.
If you enable the Native Client flag and still can't run applications from
outside the Chrome Web Store, you may need to enable the Native Client plugin:
@@ -149,7 +184,6 @@ outside the Chrome Web Store, you may need to enable the Native Client plugin:
the Native Client plugin. You do not need to relaunch Chrome after enabling
the Native Client plugin.
-
.. _web_server:
Web server
@@ -158,27 +192,22 @@ Web server
For security reasons, Native Client applications must come from a server (you
can't simply drag HTML files into your browser). The Native Client SDK comes
with a lightweight Python web server that you can run to serve your application
-locally. The server is included in the ``examples`` directory in the SDK
-bundles (e.g., ``pepper_28/examples``). Here is how to run the server:
-
-* Windows::
+locally. The server can be invoked from a Makefile. Here is how to run the
+server:
- cd examples
- httpd.cmd
+.. naclcode::
+ :prettyprint: 0
-* Mac, Linux::
+ $ cd examples
+ $ make serve
- cd examples
- python httpd.py
+By default, the server listens for requests on port 5103. You can use the server
+to run most applications under the ``examples`` directory where you started the
+server. For example, to run the ``flock`` example in the SDK, start the server
+and point your browser to http://localhost:5103/demo/flock/.
-By default, the server listens for requests on port 5103. To use a different
-port, simply specify a different port number, e.g.: ``python httpd.py 5104``.
-
-You can use the server to run any application under the ``examples`` directory
-where you started the server. For example, to run the
-``hello_world_interactive`` example in the SDK, start the server as described
-above and point your browser to
-http://localhost:5103/hello_world_interactive/hello_world.html.
+Some of the applications need special flags to Chrome, and must be run with the
+``make run`` command. See :ref:`running_the_sdk_examples` for more details.
.. _metadata:
@@ -186,17 +215,19 @@ Chrome Web Store metadata
~~~~~~~~~~~~~~~~~~~~~~~~~
Applications published in the Chrome Web Store must be accompanied by CWS
-metadata—specifically, a Chrome Web Store manifest file named
+metadata; specifically, a Chrome Web Store manifest file named
``manifest.json``, and at least one icon.
-Below is an example of a CWS manifest file for a **hosted application**::
+Below is an example of a CWS manifest file for a **hosted application**:
+
+.. naclcode::
{
"name": "My NaCl App",
"description": "Simple game implemented using Native Client",
"version": "0.1",
"icons": {
- "128": "nacl_icon_128.jpg"
+ "128": "icon128.png"
},
"app": {
"urls": [
@@ -210,15 +241,17 @@ Below is an example of a CWS manifest file for a **hosted application**::
For a **packaged application**, you can omit the urls field, and replace the
-``web_url`` field with a ``local_path`` field, as shown below::
+``web_url`` field with a ``local_path`` field, as shown below:
+
+.. naclcode::
{
"name": "My NaCl App",
"description": "Simple game implemented using Native Client",
"version": "0.1",
"icons": {
- "16": "nacl_icon_16.jpg",
- "128": "nacl_icon_128.jpg"
+ "16": "icon16.png",
+ "128": "icon128.png"
},
"app": {
"launch": {
@@ -230,11 +263,18 @@ For a **packaged application**, you can omit the urls field, and replace the
You must put the ``manifest.json`` file in the same directory as your
application's main HTML page.
-If you don't have icons for your application, you can use the following icons
-as placeholders: nacl_icon_16.jpg and nacl_icon_128.jpg. Put the icons in the
-same directory as the CWS manifest file.
+If you don't have icons for your application, you can use the following icons as
+placeholders:
+
+|ICON16|
-For more information about CWS manifest files and application icons, see:
+|ICON128|
+
+.. |ICON16| image:: /images/icon16.png
+.. |ICON128| image:: /images/icon128.png
+
+Put the icons in the same directory as the CWS manifest file. For more
+information about CWS manifest files and application icons, see:
* `Chrome Web Store Tutorial: Getting Started
<https://developers.google.com/chrome/web-store/docs/get_started_simple>`_
@@ -249,7 +289,7 @@ To run your application from a local server:
* Enable the :ref:`Native Client flag <flag>` in Chrome.
* Start a :ref:`local web server <web_server>`.
* Put your application under the examples directory in the SDK bundle you are
- using (e.g., in the directory ``pepper_28/examples/my_app``).
+ using (e.g., in the directory ``pepper_31/examples/my_app``).
* Access your application on the local server by typing the location of its
HTML file in Chrome, e.g.:
``http://localhost:5103/my_app/my_app_main_page.html``.
@@ -259,7 +299,7 @@ To run your application from a local server:
**Note:** You don't have to use a local web server---you can use another
server if you already have one running. You must still enable the Native
- Client flag in order to run your application from your server.
+ Client flag in order to run your application from the server.
Technique 2: Packaged application loaded as an unpacked extension
=================================================================
@@ -297,10 +337,11 @@ application into Chrome (including troubleshooting information), see the
`Chrome Web Store Tutorial: Getting Started
<https://developers.google.com/chrome/web-store/docs/get_started_simple>`_.
+See also :ref:`run_sdk_examples_as_packaged`.
+
Technique 3: Hosted application loaded as an unpacked extension
===============================================================
-
For development purposes, Chrome lets you load a hosted application as an
unpacked extension. To load and run your hosted application as an unpacked
extension:
@@ -315,7 +356,7 @@ extension:
* If you're using the local server included with the Native Client SDK,
simply put your application under the ``examples`` directory in the SDK
bundle you are using (e.g., in the directory
- ``pepper_28/examples/my_app``).
+ ``pepper_31/examples/my_app``).
#. Create a Chrome Web Store manifest file and one or more icons for your
application.
@@ -360,7 +401,8 @@ is how to do so:
your application, as described above under :ref:`Chrome Web Store metadata
<metadata>`. Note that packaged applications must have at least two icons
(a 16x16 icon and a 128x128 icon).
- * You also need to create the following additional assets before you can publish your application:
+ * You also need to create the following additional assets before you can
+ publish your application:
* a screenshot (size must be 640x400 or 1280x800)
* a promotional image called a "small tile" (size must be 440x280)
diff --git a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
index 3570f1c941..ccb87a9900 100644
--- a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
+++ b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part1.rst
@@ -1,8 +1,8 @@
.. _tutorial:
-#############################
-C++ Tutorial: Getting Started
-#############################
+######################################
+C++ Tutorial: Getting Started (Part 1)
+######################################
.. contents::
:local:
@@ -44,8 +44,9 @@ analogous to client/server communication on the web, where the client posts a
message to the server and returns immediately. The Native Client messaging
system is part of the Pepper API, and is described in detail in
:doc:`Developer's Guide: Messaging System </devguide/coding/message-system>`.
-
-TODO: would it be better to compare to web-worker communication?
+It is also similar to the way `web workers
+<http://en.wikipedia.org/wiki/Web_worker>`_ interact with the main document in
+JavaScript.
Step 1: Download and install the Native Client SDK
==================================================
@@ -143,6 +144,8 @@ The stub code is intentionally very minimal. The C++ code does not do anything
except correctly initialize itself. The JavaScript code waits for the Native
Client module to load and changes the status text on the web page accordingly.
+.. _tutorial_step_5:
+
Step 5: Compile the Native Client module and run the stub application
=====================================================================
diff --git a/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst
new file mode 100644
index 0000000000..91c9377700
--- /dev/null
+++ b/native_client_sdk/src/doc/devguide/tutorial/tutorial-part2.rst
@@ -0,0 +1,496 @@
+.. _tutorial2:
+
+######################################
+C++ Tutorial: Getting Started (Part 2)
+######################################
+
+.. contents::
+ :local:
+ :backlinks: none
+ :depth: 2
+
+Overview
+========
+
+This tutorial shows how to convert the finished PNaCl web application from
+:doc:`Part 1 <tutorial-part1>` to use the Native Client SDK build system and
+common JavaScript files. It also demonstrates some techniques to make your
+web application `Content Security Policy (CSP)-compliant
+<http://developer.chrome.com/apps/contentSecurityPolicy.html>`, which is
+necessary for `Chrome Apps
+<https://developer.chrome.com/apps/about_apps.html>`_.
+
+Using the Native Client SDK build system makes it easy to build with all of the
+SDK toolchains, and switch between the Debug and Release configurations. It
+also simplifies the makefiles for your project, as we'll see in the next
+section. Finally, it adds some useful commands for :ref:`running
+<running_the_sdk_examples>` and :ref:`debugging <debugging_the_sdk_examples>`
+your application.
+
+The finished code for this example can be found in the
+``pepper_$(VERSION)/getting_started/part2`` directory in the Native Client SDK
+download.
+
+Using the Native Client SDK build system
+========================================
+
+This section describes how to use the SDK build system. To do so, we'll make
+changes in the makefile. Because the makefile in part1 and part2 are so
+different, it is easier to start from scratch. Here is the contents of the new
+makefile. The following sections will describe it in more detail.
+
+Simplifying the Makefile
+------------------------
+
+The makefile from part1 only supports one toolchain (PNaCl) and one
+configuration (Release). It also only supports one source file. It's relatively
+simple, but if we want to add support for multiple toolchains, configurations,
+source files, or build steps, it would grow increasingly complex. The SDK build
+system uses a set of variables and macros to make this possible, without
+significantly increasing the complexity of the makefile.
+
+Here is the new makefile, supporting three toolchains (PNaCl, Newlib NaCl,
+Glibc NaCl) and two configurations (Debug, Release).
+
+.. naclcode::
+
+ VALID_TOOLCHAINS := pnacl newlib glibc
+
+ NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
+ include $(NACL_SDK_ROOT)/tools/common.mk
+
+ TARGET = part2
+ LIBS = ppapi_cpp ppapi
+
+ CFLAGS = -Wall
+ SOURCES = hello_tutorial.cc
+
+ # Build rules generated by macros from common.mk:
+
+ $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ ifeq ($(CONFIG),Release)
+ $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+ $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+ else
+ $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+ endif
+
+ $(eval $(call NMF_RULE,$(TARGET),))
+
+Choosing valid toolchains, and including common.mk
+--------------------------------------------------
+
+The makefile begins by specifying the toolchains that are valid for this
+project. The Native Client SDK build system supports multi-toolchain projects
+for its examples and libraries, but generally you will choose one toolchain
+when you begin your project and never change it. Please see the
+:ref:`Toolchains section of the Native Client overview <toolchains>` for more
+information.
+
+For this example, we support the ``pnacl``, ``newlib`` and ``glibc`` toolchains.
+
+.. naclcode::
+
+ VALID_TOOLCHAINS := pnacl newlib glibc
+
+Next, as a convenience, we specify where to find ``NACL_SDK_ROOT``. Because
+this example is located in ``pepper_$(VERSION)/getting_started/part2``, the
+root of the SDK is two directories up.
+
+.. naclcode::
+
+ NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
+
+.. Note::
+ :class: note
+
+ In your own projects, you can use the absolute path to your installed SDK
+ here. You can also override this default by setting the ``NACL_SDK_ROOT``
+ environment variable. See :ref:`Step 5 of Part 1 of this tutorial
+ <tutorial_step_5>` for more details.
+
+Next, we include the file ``tools/common.mk``. This file provides the
+functionality for the Native Client SDK build system, including new build rules
+to compile and link a project, which we'll use below.
+
+.. naclcode::
+
+ include $(NACL_SDK_ROOT)/tools/common.mk
+
+Configuring your project
+------------------------
+
+After including ``tools/common.mk``, we configure the project by specifying its
+name, the sources and libraries it uses:
+
+.. naclcode::
+
+ TARGET = part2
+ LIBS = ppapi_cpp ppapi
+
+ CFLAGS = -Wall
+ SOURCES = hello_tutorial.cc
+
+These variable names are not required and not used by the SDK build system;
+they are only used in the rules described below. By convention, all SDK
+makefiles use the following variables:
+
+TARGET
+ The name of the project to build. This variable determines the name of the
+ library or executable that will be generated. In the above example, we call
+ the target ``part2``, which will generate an executable called
+ ``part2.pexe`` for PNaCl. For NaCl toolchains, the executable's file name
+ will be given a suffix for its architecture. For example, the ARM executable
+ is called ``part2_arm.nexe``.
+
+LIBS
+ A list of libraries that this executable needs to link against. The library
+ search path is already set up to only look in the directory for the current
+ toolchain and architecture. In this example, we link against ``ppapi_cpp``
+ and ``ppapi``. ``ppapi_cpp`` is needed to use the `Pepper C++ interface
+ <https://developers.google.com/native-client/peppercpp/>`_. ``ppapi`` is
+ needed for communicating with the browser.
+
+CFLAGS
+ A list of extra flags to pass to the compiler. In this example, we pass
+ ``-Wall``, which turns on all warnings.
+
+LDFLAGS
+ A list of additional flags to pass to the linker. This example does not need
+ any special linker flags, so this variable is omitted.
+
+SOURCES
+ A list of C or C++ sources to compile, separated by spaces. If you have a
+ long list of sources, it may be easier to read if you put each file on its
+ own line, and use ``\`` as a line-continuation character. Here's an example:
+
+.. naclcode::
+
+ SOURCES = foo.cc \
+ bar.cc \
+ baz.cc \
+ quux.cc
+
+Build macros
+------------
+
+For many projects, the following build macros do not need to be changed; they
+will use the variables we've defined above.
+
+.. naclcode::
+
+ $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ ifeq ($(CONFIG),Release)
+ $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+ $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+ else
+ $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+ endif
+
+ $(eval $(call NMF_RULE,$(TARGET),))
+
+The first line defines rules to compile each source in ``SOURCES``, using the
+flags in ``CFLAGS``:
+
+.. naclcode::
+
+ $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+The next six lines define rules to link the object files into one or more
+executables. When ``TOOLCHAIN`` is ``pnacl``, there is only one executable
+generated: in the example above, ``part2.pexe``. When using a NaCl toolchain,
+there will be three executables generated, one for each architecture: in the
+example above, ``part2_arm.nexe``, ``part2_x86_32.nexe`` and
+``part2_x86_64.nexe``.
+
+When ``CONFIG`` is ``Release``, each executable is also stripped to remove
+debug information and reduce the file size:
+
+.. naclcode::
+
+ ifeq ($(CONFIG),Release)
+ $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+ $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+ else
+ $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+ endif
+
+Finally, the NMF rule generates a NaCl manifest file (``.nmf``) that references
+each executable generated in the previous step:
+
+.. naclcode::
+
+ $(eval $(call NMF_RULE,$(TARGET),))
+
+Making index.html work for Chrome Apps
+======================================
+
+This section describes the changes necessary to make the HTML and JavaScript
+in part1 CSP-compliant. This is required if you want to build a `Chrome App
+<https://developer.chrome.com/apps/about_apps.html>`_, but is not necessary
+if you want to use PNaCl on the open web.
+
+CSP rules
+---------
+
+`Chrome Apps CSP
+<http://developer.chrome.com/apps/contentSecurityPolicy.html#what>`_
+restricts you from doing the following:
+
+* You can’t use inline scripting in your Chrome App pages. The restriction
+ bans both ``<script>`` blocks and event handlers (``<button onclick="...">``).
+* You can’t reference any external resources in any of your app files (except
+ for video and audio resources). You can’t embed external resources in an
+ iframe.
+* You can’t use string-to-JavaScript methods like ``eval()`` and ``new
+ Function()``.
+
+Making index.html CSP-compliant
+-------------------------------
+
+To make our application CSP-compliant, we have to remove inline scripting. As
+described above, we can't use inline ``<script>`` blocks or event handlers. This
+is easy to do---we'll just reference some new files from our script tag, and
+remove all of our inlined scripts:
+
+.. naclcode::
+
+ <head>
+ ...
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+ </head>
+
+``common.js`` has shared code used by all SDK examples, and is described
+later in this document. ``example.js`` is a script that has code specific to
+this example.
+
+We also need to remove the inline event handler on the body tag:
+
+.. naclcode::
+
+ <body onload="pageDidLoad()">
+ ...
+
+This logic is now handled by ``common.js``.
+
+Making index.html support different toolchains and configurations
+-----------------------------------------------------------------
+
+Finally, there are a few changes to ``index.html`` that are not necessary for
+CSP-compliance, but help make the SDK examples more generic.
+
+First, we add some `data attributes
+<https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes>`_
+to the body element to specify the name, supported toolchains, supported
+configurations, and path to the ``.nmf`` file:
+
+.. naclcode::
+
+ <body data-name="part2"
+ data-tools="newlib glibc pnacl"
+ data-configs="Debug Release"
+ data-path="{tc}/{config}">
+ ...
+
+``common.js`` will read these data attributes to allow you to load the same
+example with different toolchains by changing the URL's `query string
+<http://en.wikipedia.org/wiki/Query_string>`_. For example, you can load the
+glibc Debug version of this example by navigating to
+``index.html?tc=glibc&config=Debug``.
+
+Next, we remove the ``embed`` element that is described in HTML. This will be
+automatically added for us by ``common.js``, based on the current
+toolchain/configuration combination:
+
+.. naclcode::
+
+ <!--
+ Just as in part1, the <embed> element will be wrapped inside the <div>
+ element with the id "listener". In part1, the embed was specified in HTML,
+ here the common.js module creates a new <embed> element and adds it to the
+ <div> for us.
+ -->
+ <div id="listener"></div>
+
+Sharing common code with common.js
+==================================
+
+``common.js`` contains JavaScript code that each example uses to create a
+NaCl module, handle messages from that module and other common tasks like
+displaying the module load status and logging messages. Explaining all of
+``common.js`` is outside the scope of this document, but please look at the
+documentation in that file for more information.
+
+Loading the page and creating the module
+----------------------------------------
+
+Since we've added ``<script>`` tags for ``common.js`` and ``example.js`` to the
+``head`` element, they will be loaded and executed before the rest of the
+document has been parsed. As a result, we have to wait for the page to finish
+loading before we try to create the embed element and add it to the page.
+
+We can do that by calling ``addEventListener`` and listening for the
+``DOMContentLoaded`` event:
+
+.. naclcode::
+
+ // Listen for the DOM content to be loaded. This event is fired when parsing of
+ // the page's document has finished.
+ document.addEventListener('DOMContentLoaded', function() {
+ ...
+ });
+
+Inside this function, we parse the URL query string, and compare that to the
+data attributes:
+
+.. naclcode::
+
+ // From https://developer.mozilla.org/en-US/docs/DOM/window.location
+ var searchVars = {};
+ if (window.location.search.length > 1) {
+ var pairs = window.location.search.substr(1).split('&');
+ for (var key_ix = 0; key_ix < pairs.length; key_ix++) {
+ var keyValue = pairs[key_ix].split('=');
+ searchVars[unescape(keyValue[0])] =
+ keyValue.length > 1 ? unescape(keyValue[1]) : '';
+ }
+ }
+
+ ...
+
+ var toolchains = body.dataset.tools.split(' ');
+ var configs = body.dataset.configs.split(' ');
+
+ ...
+
+ var tc = toolchains.indexOf(searchVars.tc) !== -1 ?
+ searchVars.tc : toolchains[0];
+
+ // If the config value is included in the search vars, use that.
+ // Otherwise default to Release if it is valid, or the first value if
+ // Release is not valid.
+ if (configs.indexOf(searchVars.config) !== -1)
+ var config = searchVars.config;
+ else if (configs.indexOf('Release') !== -1)
+ var config = 'Release';
+ else
+ var config = configs[0];
+
+Then ``domContentLoaded`` is called, which performs some checks to see if the
+browser supports Native Client, then creates the NaCl module.
+
+.. naclcode::
+
+ function domContentLoaded(name, tool, path, width, height, attrs) {
+ updateStatus('Page loaded.');
+ if (!browserSupportsNaCl(tool)) {
+ updateStatus(
+ 'Browser does not support NaCl (' + tool + '), or NaCl is disabled');
+ } else if (common.naclModule == null) {
+ updateStatus('Creating embed: ' + tool);
+
+ // We use a non-zero sized embed to give Chrome space to place the bad
+ // plug-in graphic, if there is a problem.
+ width = typeof width !== 'undefined' ? width : 200;
+ height = typeof height !== 'undefined' ? height : 200;
+ attachDefaultListeners();
+ createNaClModule(name, tool, path, width, height, attrs);
+ } else {
+ // It's possible that the Native Client module onload event fired
+ // before the page's onload event. In this case, the status message
+ // will reflect 'SUCCESS', but won't be displayed. This call will
+ // display the current message.
+ updateStatus('Waiting.');
+ }
+ }
+
+``attachDefaultListeners`` is added before the creation of the module, to make
+sure that no messages are lost. Note that ``window.attachListeners`` is also
+called; this is the way that ``common.js`` allows each example to configure
+itself differently. If an example defines the ``attachListeners`` function, it
+will be called by ``common.js``.
+
+.. naclcode::
+
+ function attachDefaultListeners() {
+ var listenerDiv = document.getElementById('listener');
+ listenerDiv.addEventListener('load', moduleDidLoad, true);
+ listenerDiv.addEventListener('message', handleMessage, true);
+ listenerDiv.addEventListener('crash', handleCrash, true);
+ if (typeof window.attachListeners !== 'undefined') {
+ window.attachListeners();
+ }
+ }
+
+Finally, ``createNaClModule`` actually creates the ``embed``, and appends it as
+a child of the element with id ``listener``:
+
+.. naclcode::
+
+ function createNaClModule(name, tool, path, width, height, attrs) {
+ var moduleEl = document.createElement('embed');
+ moduleEl.setAttribute('name', 'nacl_module');
+ moduleEl.setAttribute('id', 'nacl_module');
+ moduleEl.setAttribute('width', width);
+ moduleEl.setAttribute('height', height);
+ moduleEl.setAttribute('path', path);
+ moduleEl.setAttribute('src', path + '/' + name + '.nmf');
+
+ ...
+
+ var mimetype = mimeTypeForTool(tool);
+ moduleEl.setAttribute('type', mimetype);
+
+ var listenerDiv = document.getElementById('listener');
+ listenerDiv.appendChild(moduleEl);
+ ...
+ }
+
+When the module finishes loading, it will dispatch a ``load`` event, and the
+event listener function that was registered above (``moduleDidLoad``) will be
+called. Note that ``common.js`` allows each example to define a
+``window.moduleDidLoad`` function, that will be called here as well.
+
+.. naclcode::
+
+ function moduleDidLoad() {
+ common.naclModule = document.getElementById('nacl_module');
+ updateStatus('RUNNING');
+
+ if (typeof window.moduleDidLoad !== 'undefined') {
+ window.moduleDidLoad();
+ }
+ }
+
+Example-specific behavior with example.js
+=========================================
+
+As described in the previous section, ``common.js`` will call certain functions
+during the module loading process. This example only needs to respond to two:
+``moduleDidLoad`` and ``handleMessage``.
+
+.. naclcode::
+
+ // This function is called by common.js when the NaCl module is
+ // loaded.
+ function moduleDidLoad() {
+ // Once we load, hide the plugin. In this example, we don't display anything
+ // in the plugin, so it is fine to hide it.
+ common.hideModule();
+
+ // After the NaCl module has loaded, common.naclModule is a reference to the
+ // NaCl module's <embed> element.
+ //
+ // postMessage sends a message to it.
+ common.naclModule.postMessage('hello');
+ }
+
+ // This function is called by common.js when a message is received from the
+ // NaCl module.
+ function handleMessage(message) {
+ var logEl = document.getElementById('log');
+ logEl.textContent += message.data;
+ }
diff --git a/native_client_sdk/src/doc/faq.rst b/native_client_sdk/src/doc/faq.rst
index 021c475d1e..6ac764dc15 100644
--- a/native_client_sdk/src/doc/faq.rst
+++ b/native_client_sdk/src/doc/faq.rst
@@ -63,7 +63,11 @@ Portable Native client further enhances the above:
gains support for new processors and fully uses their capabilities.
.. TODO Expand on the PNaCl performance section in another document, and
-.. link to it here.
+.. link to it here. How does one profile PNaCl code? What are common
+.. causes of slowness? How can code be made faster? What's the best way
+.. to use Pepper's asynchronous APIs? What do I need to know about
+.. threads and inter-thread communications? Can I use SIMD or other
+.. processor-specific instructions? What aboutt he GPU?
For more details, refer to the :doc:`history behind and comparison of
NaCl and PNaCl <nacl-and-pnacl>`.
@@ -91,29 +95,40 @@ When should I use Portable Native Client?
See :doc:`NaCl and PNaCl <nacl-and-pnacl>`. In short: PNaCl works on the
open web whereas NaCl only works on the Chrome Web Store.
-How fast does code run in Native Client?
-----------------------------------------
+How fast does code run in Portable Native Client?
+-------------------------------------------------
-Fast! Benchmarks on x86-32 measured an average performance overhead of
-less than 5% compared to native C/C++ on applications such as Quake,
-bzip2, and Google Earth. For details of those benchmarks, see `Native
-Client: A Sandbox for Portable, Untrusted x86 Code
-<https://src.chromium.org/viewvc/native_client/data/docs_tarball/nacl/googleclient/native_client/documentation/nacl_paper.pdf>`_
-(PDF).
+Fast! The SPEC2k benchmarks (C, C++ and floating-point benchmarks) give
+the following overhead for optimized PNaCl compared to regular optimized
+LLVM:
-Benchmarks on x86-64 and ARM measured an average performance overhead of
-less than 5% on ARM and 7% on x86-64; however, benchmark performance was
-bimodal for x86-64, so different use cases are likely to achieve either
-significantly better or significantly worse performance than that
-average. For details, see `Adapting Software Fault Isolation to
-Contemporary CPU Architectures
-<https://nativeclient.googlecode.com/svn/data/site/NaCl_SFI.pdf>`_ (PDF).
++--------+-----+
+| x86-32 | 15% |
++--------+-----+
+| x86-64 | 20% |
++--------+-----+
+| ARM | 10% |
++--------+-----+
-.. TODO Update performance numbers.
+Note that benchmark performance is sometimes bimodal, so different use
+cases are likely to achieve better or worse performance than the above
+averages. For example floating-point heavy code usually exhibits much
+lower overheads whereas very branch-heavy code often performs worse.
+
+For details, see:
+
+* `Adapting Software Fault Isolation to Contemporary CPU Architectures
+ <https://nativeclient.googlecode.com/svn/data/site/NaCl_SFI.pdf>`_
+ (PDF).
+* `Native Client: A Sandbox for Portable, Untrusted x86 Code
+ <https://src.chromium.org/viewvc/native_client/data/docs_tarball/nacl/googleclient/native_client/documentation/nacl_paper.pdf>`_
+ (PDF).
If your code isn't performing as close to native speed as you'd expect,
:doc:`let us know <help>`!
+.. TODO Link to the non-existent performance page! (see above todo).
+
Why use Portable Native Client instead of *<technology X>*?
-----------------------------------------------------------
@@ -151,11 +166,8 @@ develop on ChromeOS with `Crouton
self-hosting a full development environment on Portable Native Client.
Any editor+shell combination should work as well as IDEs like Eclipse,
-Visual Studio with the `Native Client Add-In
-<https://developers.google.com/native-client/dev/devguide/devcycle/vs-addin>`_
-on Windows, or Xcode on Mac OSX.
-
-.. TODO: update link to Visual Studio when ReST-ified.
+Visual Studio with the :doc:`Native Client Add-In
+<devguide/devcycle/vs-addin>` on Windows, or Xcode on Mac OSX.
I'm not familiar with native development tools, can I still use the Native Client SDK?
--------------------------------------------------------------------------------------
@@ -184,10 +196,8 @@ to consider Native Client for standardization.
We consistenly try to document our design and implementation and hope to
standardize Portable Native Client when it gains more traction. A good
-example is our `PNaCl bitcode reference manual
-<http://www.chromium.org/nativeclient/pnacl/bitcode-abi>`_.
-
-.. TODO Update the above bitcode-abi link to a :doc: once 3693 is fixed.
+example is our :doc:`PNaCl bitcode reference manual
+<reference/pnacl-bitcode-abi>`.
What are the supported instruction set architectures?
-----------------------------------------------------
@@ -210,6 +220,8 @@ portability to JavaScript and can adapt to new instruction set
architectures without requiring recompilation. The web is better when
it's platform-independent, and we'd like it to stay that way.
+.. _other_languages:
+
Do I have to use C or C++? I'd really like to use another language.
-------------------------------------------------------------------
@@ -274,12 +286,8 @@ Yes. Native Client supports `OpenGL ES 2.0
To alert the user regarding their hardware platform's 3D feature set
-before loading a large NaCl application, see `Vetting the driver in
-Javascript
-<https://developers.google.com/native-client/devguide/coding/3D-graphics>`_.
-
-.. TODO Update link to point to the right place in the document once
-.. it's ReST-ified.
+before loading a large NaCl application, see :doc:`Vetting the driver in
+Javascript <devguide/coding/3D-graphics>`.
Some GL extensions are exposed to Native Client applications, see the
`GL ES 2 file
@@ -301,13 +309,13 @@ barriers, atomic read/modify/write, compare-and-exchange, etc...), thus
allowing your Native Client application to utilize several CPU cores.
Note that this allows you to modify datastructures concurrently without
needing to copy them, which is often a limitation of shared-nothing
-systems.
+systems. For more information see :ref:`memory model and atomics
+<memory_model_and_atomics>` and :ref:`threading
+<language_support_threading>`.
Native Client doesn't support HTML5 Web Workers directly but can
interact with JavaScript code which does.
-.. TODO Add link to relevant documentation, once written.
-
Coming Soon
===========
@@ -387,13 +395,10 @@ Google has taken several steps to ensure that Native Client's security
works, including:
* Open source, peer-reviewed papers describing the design.
-* A `security contest
- <https://developers.google.com/native-client/community/security-contest/>`_.
+* A :doc:`security contest <community/security-contest/index>`.
* Multiple internal and external security reviews.
* The ongoing vigilance of our engineering and developer community.
-.. TODO: Fix security contest link once ReST-ified.
-
Google is committed to making Native Client safer than JavaScript and
other popular browser technologies. If you have suggestions for security
improvements, let the team know, by way of the `native-client-discuss
diff --git a/native_client_sdk/src/doc/images/3d-graphics-render-loop.png b/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
index 66e1121c37..3d2aac5e48 100644
--- a/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
+++ b/native_client_sdk/src/doc/images/3d-graphics-render-loop.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/icon128.png b/native_client_sdk/src/doc/images/icon128.png
new file mode 100644
index 0000000000..a10c52a5de
--- /dev/null
+++ b/native_client_sdk/src/doc/images/icon128.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/icon16.png b/native_client_sdk/src/doc/images/icon16.png
new file mode 100644
index 0000000000..0a8d70cb23
--- /dev/null
+++ b/native_client_sdk/src/doc/images/icon16.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/naclmounts1.png b/native_client_sdk/src/doc/images/nacl_io1.png
index 78d1867234..78d1867234 100644
--- a/native_client_sdk/src/doc/images/naclmounts1.png
+++ b/native_client_sdk/src/doc/images/nacl_io1.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/pepper-audio-api.png b/native_client_sdk/src/doc/images/pepper-audio-api.png
index c3fd2369a7..cbce867f63 100644
--- a/native_client_sdk/src/doc/images/pepper-audio-api.png
+++ b/native_client_sdk/src/doc/images/pepper-audio-api.png
Binary files differ
diff --git a/native_client_sdk/src/doc/images/pepper-audio-buffer.png b/native_client_sdk/src/doc/images/pepper-audio-buffer.png
index 10654f7bc1..d7a55be4d3 100644
--- a/native_client_sdk/src/doc/images/pepper-audio-buffer.png
+++ b/native_client_sdk/src/doc/images/pepper-audio-buffer.png
Binary files differ
diff --git a/native_client_sdk/src/doc/index.rst b/native_client_sdk/src/doc/index.rst
index 2d33727a04..194a00bda8 100644
--- a/native_client_sdk/src/doc/index.rst
+++ b/native_client_sdk/src/doc/index.rst
@@ -19,6 +19,7 @@ Contents:
devguide/index.rst
devguide/tutorial/index.rst
devguide/tutorial/tutorial-part1.rst
+ devguide/tutorial/tutorial-part2.rst
devguide/devcycle/index.rst
devguide/devcycle/building.rst
devguide/devcycle/running.rst
@@ -31,6 +32,7 @@ Contents:
devguide/coding/application-structure.rst
devguide/coding/native-client-modules.rst
devguide/coding/FileIO.rst
+ devguide/coding/nacl_io.rst
devguide/coding/message-system.rst
devguide/coding/progress-events.rst
devguide/coding/url-loading.rst
@@ -46,6 +48,7 @@ Contents:
peppercpp/index.rst
reference/index.rst
reference/pnacl-bitcode-abi.rst
+ reference/pnacl-c-cpp-language-support.rst
reference/nacl-manifest-format.rst
publications-and-presentations.rst
faq.rst
diff --git a/native_client_sdk/src/doc/nacl-and-pnacl.rst b/native_client_sdk/src/doc/nacl-and-pnacl.rst
index 82cde79699..caa8352b64 100644
--- a/native_client_sdk/src/doc/nacl-and-pnacl.rst
+++ b/native_client_sdk/src/doc/nacl-and-pnacl.rst
@@ -115,3 +115,6 @@ non-portable NaCl:
``newlib``). Dynamic linking and ``glibc`` are not yet supported.
Work is under way to enable dynamic linking in future versions of PNaCl.
* In the initial release, PNaCl does not support C++ exception handling.
+* In the initial release, PNaCl does not support vector types and SIMD.
+* In the initial release, PNaCl does not support some GNU extensions like
+ taking the address of a label for computed gotos, or nested functions.
diff --git a/native_client_sdk/src/doc/overview.rst b/native_client_sdk/src/doc/overview.rst
index 3a5efed8ed..e8ad2d743e 100644
--- a/native_client_sdk/src/doc/overview.rst
+++ b/native_client_sdk/src/doc/overview.rst
@@ -181,6 +181,8 @@ Chrome Web Store.
For more details on the difference between NaCl and PNaCl, see
:doc:`NaCl and PNaCl <nacl-and-pnacl>`.
+.. _toolchains:
+
Toolchains
----------
diff --git a/native_client_sdk/src/doc/publications-and-presentations.rst b/native_client_sdk/src/doc/publications-and-presentations.rst
index 5d27f0c371..ccf5dc7fd4 100644
--- a/native_client_sdk/src/doc/publications-and-presentations.rst
+++ b/native_client_sdk/src/doc/publications-and-presentations.rst
@@ -155,46 +155,3 @@ to Linux and Macintosh in lieu of native ports. They describe the
porting process on their blog.
`Read more <http://carbongames.com/2012/01/Native-Client>`__
-
-Porting XaoS
-^^^^^^^^^^^^
-
-Google engineers ported `XaoS <http://xaos.sourceforge.net/english.php>`_, an
-interactive graphical exploration tool for fractals, to Native Client. Many of
-the porting problems they encountered are quite common, and the techniques
-described here should help with similar porting efforts. Some of the background
-information might also benefit those who are writing new Native Client
-applications.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/xaos>`__
-
-.. TODO Fix link once it is ReST-ified.
-
-Porting MAME
-^^^^^^^^^^^^
-
-Multiple Arcade Machine Emulator (`MAME <http://mamedev.org>`_) is an
-emulator for a large number of classic arcade games. Google engineers
-ported it to Native Client. This article discusses the overall porting
-strategy, dealing with ``newlib`` incompatibilities, and handling
-binaries that are built and run as part of the build process.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/MAME>`__
-
-.. TODO Fix link once it is ReST-ified.
-
-How to Port SDL Games
-^^^^^^^^^^^^^^^^^^^^^
-
-`Simple Directmedia Layer <http://www.libsdl.org>`_ (SDL) is a popular
-library that many games and applications use to access sound and video
-capabilities on end-user machines. Native Client bindings for SDL are
-available on naclports, making it possible to port SDL-based games to
-Native Client. This article by Google engineers describes how to
-complete such a port, focusing on writing the glue code for fusing your
-game with the Pepper APIs.
-
-`Read more
-<https://developers.google.com/native-client/community/porting/SDLgames>`__
diff --git a/native_client_sdk/src/doc/reference/nacl-manifest-format.rst b/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
index a218a6956c..a61cf5556c 100644
--- a/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
+++ b/native_client_sdk/src/doc/reference/nacl-manifest-format.rst
@@ -180,20 +180,15 @@ with the NaCl port of glibc, the main program is specified in the
}
-Dynamic libraries that the dynamic program depends upon and links in
-at program startup must be listed in the ``files`` dictionary.
-Library files that are loaded after startup using ``dlopen()`` should either
-be listed in the ``files`` dictionary, or should be made accessible
-by the ``nacl_io`` library. The ``nacl_io`` library provides various
-file system *mounts* such as HTTP-based file systems and memory-based
-file systems. The Native Client SDK includes helpful tools for
-determining library dependencies and generating NaCl manifest files
-for programs that that use dynamic linking. See
-`Generating a Native Client manifest file for a dynamically linked application
-<https://developers.google.com/native-client/devguide/devcycle/dynamic-loading#manifest>`_.
-
-.. TODO(jvoung) update the link when glibc document is linkable.
-
+Dynamic libraries that the dynamic program depends upon and links in at program
+startup must be listed in the ``files`` dictionary. Library files that are
+loaded after startup using ``dlopen()`` should either be listed in the ``files``
+dictionary, or should be made accessible by the ``nacl_io`` library. The
+``nacl_io`` library provides various file system *mounts* such as HTTP-based
+file systems and memory-based file systems. The Native Client SDK includes
+helpful tools for determining library dependencies and generating NaCl manifest
+files for programs that that use dynamic linking. See
+:ref:`dynamic_loading_manifest`.
Semantics
=========
diff --git a/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst b/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
index b4cf4e817e..0aa9a9929b 100644
--- a/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
+++ b/native_client_sdk/src/doc/reference/pnacl-bitcode-abi.rst
@@ -77,13 +77,12 @@ Global Variables
Restrictions on global variables:
-* PNaCl bitcode does not support LLVM IR TLS models.
+* PNaCl bitcode does not support LLVM IR TLS models. See
+ :ref:`language_support_threading` for more details.
* Restrictions on :ref:`linkage types <bitcode_linkagetypes>`.
* The ``addrspace``, ``section``, ``unnamed_addr`` and
``externally_initialized`` attributes are not supported.
-.. TODO: link to developer's guide to explain TLS in more detail
-
Every global variable must have an initializer. Each initializer must be
either a *SimpleElement* or a *CompoundElement*, defined as follows.
@@ -162,9 +161,7 @@ Volatile Memory Accesses
PNaCl bitcode does not support volatile memory accesses. The
``volatile`` attribute on loads and stores is not supported. See the
-`PNaCl Developer's Guide <PNaClDeveloperGuide.html>`_ for more details.
-
-.. TODO: link to developers guide once it's ported
+:doc:`pnacl-c-cpp-language-support` for more details.
Memory Model for Concurrent Operations
--------------------------------------
diff --git a/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst b/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst
new file mode 100644
index 0000000000..bcbce53add
--- /dev/null
+++ b/native_client_sdk/src/doc/reference/pnacl-c-cpp-language-support.rst
@@ -0,0 +1,222 @@
+============================
+PNaCl C/C++ Language Support
+============================
+
+.. contents::
+ :local:
+ :backlinks: none
+ :depth: 3
+
+Source language support
+=======================
+
+The currently supported languages are C and C++. The PNaCl toolchain is
+based on Clang 3.3, which fully supports C++11 and most of C11. A
+detailed status of the language support is available `here
+<http://clang.llvm.org/cxx_status.html>`_.
+
+For information on using languages other than C/C++, see the :ref:`FAQ
+section on other languages <other_languages>`.
+
+As for the standard libraries, the PNaCl toolchain is currently based on
+``libstdc++`` version 4.6.1, and the ``newlib`` standard C library
+(version is available through the macro ``NEWLIB_VERSION``).
+Experimental ``libc++`` support is also included; see
+:ref:`building_cpp_libraries` for more details.
+
+Preprocessor definitions
+------------------------
+
+When compiling C/C++ code, the PNaCl toolchain defines the ``__pnacl__``
+macro. In addition, ``__native_client__`` is defined for compatibility
+with other NaCl toolchains.
+
+.. _memory_model_and_atomics:
+
+Memory Model and Atomics
+========================
+
+Memory Model for Concurrent Operations
+--------------------------------------
+
+The memory model offered by PNaCl relies on the same coding guidelines
+as the C11/C++11 one: concurrent accesses must always occur through
+atomic primitives (offered by `atomic intrinsics
+<PNaClLangRef.html#atomicintrinsics>`_), and these accesses must always
+occur with the same size for the same memory location. Visibility of
+stores is provided on a happens-before basis that relates memory
+locations to each other as the C11/C++11 standards do.
+
+Non-atomic memory accesses may be reordered, separated, elided or fused
+according to C and C++'s memory model before the pexe is created as well
+as after its creation.
+
+As in C11/C++11 some atomic accesses may be implemented with locks on
+certain platforms. The ``ATOMIC_*_LOCK_FREE`` macros will always be
+``1``, signifying that all types are sometimes lock-free. The
+``is_lock_free`` methods and ``atomic_is_lock_free`` will return the
+current platform's implementation at translation time. These macros,
+methods and functions are in the C11 header ``<stdatomic.h>`` and the
+C++11 header ``<atomic>``.
+
+The PNaCl toolchain supports concurrent memory accesses through legacy
+GCC-style ``__sync_*`` builtins, as well as through C11/C++11 atomic
+primitives. ``volatile`` memory accesses can also be used, though these
+are discouraged. See `Volatile Memory Accesses`_.
+
+PNaCl supports concurrency and parallelism with some restrictions:
+
+* Threading is explicitly supported and has no restrictions over what
+ prevalent implementations offer. See `Threading`_.
+
+* ``volatile`` and atomic operations are address-free (operations on the
+ same memory location via two different addresses work atomically), as
+ intended by the C11/C++11 standards. This is critical in supporting
+ synchronous "external modifications" such as mapping underlying memory
+ at multiple locations.
+
+* Inter-process communication through shared memory is currently not
+ supported. See `Future Directions`_.
+
+* Signal handling isn't supported, PNaCl therefore promotes all
+ primitives to cross-thread (instead of single-thread). This may change
+ at a later date. Note that using atomic operations which aren't
+ lock-free may lead to deadlocks when handling asynchronous
+ signals. See `Future Directions`_.
+
+* Direct interaction with device memory isn't supported, and there is no
+ intent to support it. The embedding sandbox's runtime can offer APIs
+ to indirectly access devices.
+
+Setting up the above mechanisms requires assistance from the embedding
+sandbox's runtime (e.g. NaCl's Pepper APIs), but using them once setup
+can be done through regular C/C++ code.
+
+Atomic Memory Ordering Constraints
+----------------------------------
+
+Atomics follow the same ordering constraints as in regular C11/C++11,
+but all accesses are promoted to sequential consistency (the strongest
+memory ordering) at pexe creation time. We plan to support more of the
+C11/C++11 memory orderings in the future.
+
+Some additional restrictions, following the C11/C++11 standards:
+
+- Atomic accesses must at least be naturally aligned.
+- Some accesses may not actually be atomic on certain platforms,
+ requiring an implementation that uses global locks.
+- An atomic memory location must always be accessed with atomic
+ primitives, and these primitives must always be of the same bit size
+ for that location.
+- Not all memory orderings are valid for all atomic operations.
+
+Volatile Memory Accesses
+------------------------
+
+The C11/C++11 standards mandate that ``volatile`` accesses execute in
+program order (but are not fences, so other memory operations can
+reorder around them), are not necessarily atomic, and can’t be
+elided. They can be separated into smaller width accesses.
+
+Before any optimizations occur, the PNaCl toolchain transforms
+``volatile`` loads and stores into sequentially consistent ``volatile``
+atomic loads and stores, and applies regular compiler optimizations
+along the above guidelines. This orders ``volatiles`` according to the
+atomic rules, and means that fences (including ``__sync_synchronize``)
+act in a better-defined manner. Regular memory accesses still do not
+have ordering guarantees with ``volatile`` and atomic accesses, though
+the internal representation of ``__sync_synchronize`` attempts to
+prevent reordering of memory accesses to objects which may escape.
+
+Relaxed ordering could be used instead, but for the first release it is
+more conservative to apply sequential consistency. Future releases may
+change what happens at compile-time, but already-released pexes will
+continue using sequential consistency.
+
+The PNaCl toolchain also requires that ``volatile`` accesses be at least
+naturally aligned, and tries to guarantee this alignment.
+
+The above guarantees ease the support of legacy (i.e. non-C11/C++11)
+code, and combined with builtin fences these programs can do meaningful
+cross-thread communication without changing code. They also better
+reflect the original code's intent and guarantee better portability.
+
+.. _language_support_threading:
+
+Threading
+=========
+
+Threading is explicitly supported through C11/C++11's threading
+libraries as well as POSIX threads.
+
+Communication between threads should use atomic primitives as described
+in `Memory Model and Atomics`_.
+
+``setjmp`` and ``longjmp``
+==========================
+
+PNaCl and NaCl support ``setjmp`` and ``longjmp`` without any
+restrictions beyond C's.
+
+Inline Assembly
+===============
+
+Inline assembly isn't supported by PNaCl because it isn't portable. The
+one current exception is the common compiler barrier idiom
+``asm("":::"memory")``, which gets transformed to a sequentially
+consistent memory barrier (equivalent to ``__sync_synchronize()``). In
+PNaCl this barrier is only guaranteed to order ``volatile`` and atomic
+memory accesses, though in practice the implementation attempts to also
+prevent reordering of memory accesses to objects which may escape.
+
+NaCl supports a fairly wide subset of inline assembly through GCC's
+inline assembly syntax, with the restriction that the sandboxing model
+for the target architecture has to be respected.
+
+Future Directions
+=================
+
+SIMD
+----
+
+PNaCl currently doesn't support SIMD. We plan to add SIMD support in the
+very near future.
+
+NaCl supports SIMD.
+
+Inter-Process Communication
+---------------------------
+
+Inter-process communication through shared memory is currently not
+supported by PNaCl/NaCl. When implemented, it may be limited to
+operations which are lock-free on the current platform (``is_lock_free``
+methods). It will rely on the address-free properly discussed in `Memory
+Model for Concurrent Operations`_.
+
+Signal Handling
+---------------
+
+Signal handling from user code currently isn't supported by PNaCl. When
+supported, the impact of ``volatile`` and atomics for same-thread signal
+handling will need to be carefully detailed.
+
+NaCl supports signal handling.
+
+Exception Handling
+------------------
+
+PNaCl currently doesn't support exception handling. It supports the
+usual ``-fno-exceptions`` flag, and by default it transforms all
+``throw`` statements into ``abort``. We plan to add exception-handling
+support in the very near future, and zero-cost exception handling soon
+thereafter.
+
+NaCl supports exception handling.
+
+Computed ``goto``
+-----------------
+
+PNaCl currently doesn't support computed ``goto``, a non-standard
+extension to C used by some interpreters.
+
+NaCl supports computed ``goto``.
diff --git a/native_client_sdk/src/doc/sdk/examples.rst b/native_client_sdk/src/doc/sdk/examples.rst
index 73c6a33fe5..22404d4add 100644
--- a/native_client_sdk/src/doc/sdk/examples.rst
+++ b/native_client_sdk/src/doc/sdk/examples.rst
@@ -159,6 +159,8 @@ For details on how to use ``make``, see the `GNU 'make' Manual
use the SDK toolchain itself, see :doc:`Building Native Client Modules
<../devguide/devcycle/building>`.
+.. _running_the_sdk_examples:
+
Run the SDK examples
--------------------
@@ -202,6 +204,7 @@ You can run via a different toolchain or configuration by using the
$ make run TOOLCHAIN=pnacl CONFIG=Debug
+.. _run_sdk_examples_as_packaged:
Run the SDK examples as packaged apps
-------------------------------------
diff --git a/native_client_sdk/src/examples/api/file_io/example.js b/native_client_sdk/src/examples/api/file_io/example.js
index 3fdc741197..6143fd567c 100644
--- a/native_client_sdk/src/examples/api/file_io/example.js
+++ b/native_client_sdk/src/examples/api/file_io/example.js
@@ -12,8 +12,8 @@ function domContentLoaded(name, tc, config, width, height) {
function(bytes) {
common.updateStatus(
'Allocated ' + bytes + ' bytes of persistant storage.');
- common.createNaClModule(name, tc, config, width, height);
common.attachDefaultListeners();
+ common.createNaClModule(name, tc, config, width, height);
},
function(e) { alert('Failed to allocate space') });
}
diff --git a/native_client_sdk/src/examples/demo/drive/example.dsc b/native_client_sdk/src/examples/demo/drive/example.dsc
index 8efe7443fc..2f83aa1d37 100644
--- a/native_client_sdk/src/examples/demo/drive/example.dsc
+++ b/native_client_sdk/src/examples/demo/drive/example.dsc
@@ -8,13 +8,6 @@
'LIBS': ['jsoncpp', 'ppapi_cpp', 'ppapi', 'pthread']
}
],
- 'PRE': """
-#
-# We use the chrome.experimental.identity API, which requires the
-# --enable-experimental-expension-apis flag.
-#
-CHROME_ARGS += --enable-experimental-extension-apis
-""",
'DATA': [
'example.js',
],
@@ -23,7 +16,7 @@ CHROME_ARGS += --enable-experimental-extension-apis
'TITLE': 'Google Drive',
'GROUP': 'Demo',
'PERMISSIONS': [
- 'experimental',
+ 'identity',
'https://www.googleapis.com/*/drive/*',
'https://*.googleusercontent.com/*'
]
diff --git a/native_client_sdk/src/examples/demo/drive/example.js b/native_client_sdk/src/examples/demo/drive/example.js
index ce4279be23..ae6326f48d 100644
--- a/native_client_sdk/src/examples/demo/drive/example.js
+++ b/native_client_sdk/src/examples/demo/drive/example.js
@@ -7,7 +7,7 @@
var authToken = '';
function getAuthToken(interactive) {
- chrome.experimental.identity.getAuthToken(
+ chrome.identity.getAuthToken(
{'interactive': interactive}, onGetAuthToken);
}
@@ -38,7 +38,7 @@ function moduleDidLoad() {
// Make sure this example is running as a packaged app. If not, display a
// warning.
- if (!chrome.experimental) {
+ if (!chrome.identity) {
common.updateStatus('Error: must be run as a packged app.');
return;
}
diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.js b/native_client_sdk/src/examples/demo/nacl_io/example.js
index 6de6afbbb2..0ccaf7da7e 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/example.js
+++ b/native_client_sdk/src/examples/demo/nacl_io/example.js
@@ -12,8 +12,8 @@ function domContentLoaded(name, tc, config, width, height) {
function(bytes) {
common.updateStatus(
'Allocated ' + bytes + ' bytes of persistant storage.');
- common.createNaClModule(name, tc, config, width, height);
common.attachDefaultListeners();
+ common.createNaClModule(name, tc, config, width, height);
},
function(e) { alert('Failed to allocate space') });
}
diff --git a/native_client_sdk/src/examples/tutorial/debugging/example.js b/native_client_sdk/src/examples/tutorial/debugging/example.js
index 7542844b42..3016eb7216 100644
--- a/native_client_sdk/src/examples/tutorial/debugging/example.js
+++ b/native_client_sdk/src/examples/tutorial/debugging/example.js
@@ -6,8 +6,8 @@ var lastModuleError = '';
var crashed = false;
function domContentLoaded(name, tc, config, width, height) {
- common.createNaClModule(name, tc, config, width, height);
common.attachDefaultListeners();
+ common.createNaClModule(name, tc, config, width, height);
updateStatus('Page Loaded');
}
diff --git a/native_client_sdk/src/gonacl_appengine/README b/native_client_sdk/src/gonacl_appengine/README
index ab51466d2e..22db5579d1 100644
--- a/native_client_sdk/src/gonacl_appengine/README
+++ b/native_client_sdk/src/gonacl_appengine/README
@@ -1,25 +1,65 @@
+GoNaCl App Engine
+=================
+
This is a new App Engine Python 2.7 application for http://gonacl.com
At this time it presents the existing functionality of redirecting
to http://developers.google.com/native-client/
-Also, there are PNaCl demos added at /static/pnacl-demo-<name>/index.html
+Also, there are PNaCl demos added at ``/static/pnacl-demo-<name>/index.html``
+
+
+To Run Locally
+--------------
+
+1. Download the App Engine SDK (https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python)
+
+2. Run ``<path/to/app/engine>/dev_appserver.py app.yaml``
-To upload, run this from the root directory of the AppEngine SDK:
+3. Navigate in your browser to http://localhost:8080/static/
-$ ./appcfg.py update <path-to-this-dir>
+
+To Update App Engine (HTML/JS)
+------------------------------
+
+To upload, run this from the root directory of the App Engine SDK::
+
+ $ ./appcfg.py update <path-to-this-dir>
It probably makes sense to bump the application version in app.yaml for each
-upload, as it lets us use AppEngine's versioning. The newly uploaded version can
-be tried before actually being activated, by going to the "Versions" section on
-the AppEngine dashboard. Note that the newly uploaded version only becomes
-active when it's set as the "default" version in the dashboard.
+upload, as it lets us use App Engine's versioning. The newly uploaded version
+can be tried before actually being activated, by going to the "Versions"
+section on the App Engine dashboard. Note that the newly uploaded version only
+becomes active when it's set as the "default" version in the dashboard.
+
+
+To Update the Binary files (.pexe/.nmf)
+---------------------------------------
+
+The build outputs are automatically uploaded to Google Cloud Storage
+(``commondatastorage.googleapis.com``) by the linux SDK builder
+(linux-sdk-multi).
+To publish a new version:
+
+1. Make and land your change to the demo, found in ``src/<demo-name>``.
+
+2. Wait for the linux SDK builder to build and upload your change. You can see
+ what's available by using gsutil::
+
+ $ gsutil ls gs://gonacl/demos/continuous
+
+ gs://gonacl/demos/continuous/229855/
+ gs://gonacl/demos/continuous/229860/
+ ...
+
+3. Update the URLs to use this new revision in each demo's JavaScript files:
+
+ * For ``earth``, this is found in ``/static/pnacl-demo-earth/example.js``, in
+ the ``getDataURL`` function.
-Included demos:
+ * For ``bullet``, this is found in ``/static/pnacl-demo-bullet/main.js``, in
+ the ``pageDidLoad`` function.
-* static/pnacl-demo-earth: the modified Earth demo.
-* static/pnacl-demo-bullet: a demo of bullet physics, using NaCl acceleration
- modules.
+4. Land a CL with these changes.
-Only the source files (HTML and JS) are kept in source control. The pexe and
-images should be copied over from an SDK build when uploading to AppEngine.
+5. Update App Engine, using the instructions above.
diff --git a/native_client_sdk/src/gonacl_appengine/app.yaml b/native_client_sdk/src/gonacl_appengine/app.yaml
index 60a8fa1442..6dbc6f0ffc 100644
--- a/native_client_sdk/src/gonacl_appengine/app.yaml
+++ b/native_client_sdk/src/gonacl_appengine/app.yaml
@@ -22,3 +22,6 @@ handlers:
- url: /.*
script: gonacl.application
+
+skip_files:
+- src/.*
diff --git a/native_client_sdk/src/gonacl_appengine/src/Makefile b/native_client_sdk/src/gonacl_appengine/src/Makefile
new file mode 100644
index 0000000000..aef5995d1c
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/Makefile
@@ -0,0 +1,255 @@
+# Copyright (c) 2013 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.
+
+#
+# This script allows you to build, upload, and publish demo binaries that will
+# go on Google Cloud Storage (commondatastorage).
+#
+# NOTE: you normally should not upload examples. This will be done
+# automatically by the buildbots.
+#
+# Building
+# --------
+#
+# * Build all examples.
+#
+# $ make
+#
+# * Build a specific example.
+#
+# $ make bullet
+#
+# Uploading
+# ---------
+#
+# * Build and upload all examples.
+#
+# $ make upload REVISION=1234
+#
+# * Build and upload a single example
+#
+# $ make upload-bullet REVISION=1234
+#
+# Publishing
+# ----------
+#
+# * Publish binaries for all examples.
+#
+# $ make publish REVISION=1234
+#
+# * Publish binaries for one example.
+#
+# $ make publish-bullet REVISION=1234
+#
+
+ifeq (,$(NACL_SDK_ROOT))
+ $(error NACL_SDK_ROOT is not defined)
+endif
+
+# Define default build target
+all:
+
+#
+# All projects built by this Makefile
+#
+PROJECTS = earth voronoi life bullet lua
+
+GS_URL_CONTINUOUS = gs://gonacl/demos/continuous
+GS_URL_PUBLISH = gs://gonacl/demos/publish
+
+#
+# Each project must define the following variables. All paths should be
+# absolute paths.
+#
+# foo_SRCS: src files for this project
+# foo_TGTS: generated files for this project
+# foo_EXTRA_UPLOADS: additional files to upload for this project (optional)
+#
+# And a recipe to build TGTS from SRCS:
+# $(foo_TGTS): $(foo_SRCS)
+# ...
+#
+
+#
+# Earth
+#
+earth_SRC_DIR = earth
+earth_TGT_DIR = earth/pnacl/Release
+earth_JPG_DIR = ../../examples/demo/earth
+earth_SRCS = $(earth_SRC_DIR)/earth.cc \
+ $(earth_SRC_DIR)/Makefile
+earth_TGTS = $(earth_TGT_DIR)/earth.pexe \
+ $(earth_TGT_DIR)/earth.nmf
+earth_JPGS = $(earth_JPG_DIR)/earth.jpg \
+ $(earth_JPG_DIR)/earthnight.jpg
+earth_EXTRA_UPLOADS = $(earth_JPGS)
+
+$(earth_TGTS): $(earth_SRCS)
+ $(MAKE) -C earth TOOLCHAIN=pnacl CONFIG=Release
+
+
+#
+# Bullet
+#
+bullet_SRC_DIR = bullet
+bullet_TGT_DIR = bullet/out
+bullet_SRCS = $(bullet_SRC_DIR)/build.sh \
+ $(bullet_SRC_DIR)/Makefile
+bullet_TGTS = $(bullet_TGT_DIR)/NaClAMBullet.pexe \
+ $(bullet_TGT_DIR)/NaClAMBullet.nmf
+
+$(bullet_TGTS): $(bullet_SRCS)
+ bullet/build.sh
+
+#
+# Lua
+#
+lua_SRC_DIR = lua
+lua_TGT_DIR = lua/out/naclports/src/out/publish/lua/pnacl
+lua_SRCS = $(lua_SRC_DIR)/build.sh
+lua_TGTS = $(lua_TGT_DIR)/lua.pexe \
+ $(lua_TGT_DIR)/luadata.tar \
+ $(lua_TGT_DIR)/lua.nmf \
+ $(lua_TGT_DIR)/hterm.concat.js
+
+$(lua_TGTS): $(lua_SRCS)
+ lua/build.sh
+
+#
+# Voronoi
+#
+voronoi_SRC_DIR = voronoi
+voronoi_TGT_DIR = voronoi/pnacl/Release
+voronoi_SRCS = $(voronoi_SRC_DIR)/voronoi.cc \
+ $(voronoi_SRC_DIR)/Makefile
+voronoi_TGTS = $(voronoi_TGT_DIR)/voronoi.pexe \
+ $(voronoi_TGT_DIR)/voronoi.nmf
+
+$(voronoi_TGTS): $(voronoi_SRCS)
+ $(MAKE) -C voronoi TOOLCHAIN=pnacl CONFIG=Release
+
+#
+# Life
+#
+life_SRC_DIR = life
+life_TGT_DIR = life/pnacl/Release
+life_SRCS = $(life_SRC_DIR)/life.c \
+ $(life_SRC_DIR)/Makefile
+life_TGTS = $(life_TGT_DIR)/life.pexe \
+ $(life_TGT_DIR)/life.nmf
+
+$(life_TGTS): $(life_SRCS)
+ $(MAKE) -C life TOOLCHAIN=pnacl CONFIG=Release
+
+###############################################################################
+
+SHELL = /bin/bash
+
+OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
+GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
+WHICH := $(OSHELPERS) which
+
+# Try the location of gsutil on the bots first...
+BOT_GSUTIL = /b/build/scripts/slave/gsutil
+ifneq (,$(wildcard $(BOT_GSUTIL)))
+ GSUTIL = $(BOT_GSUTIL)
+else
+ GSUTIL = $(shell $(WHICH) gsutil)
+ ifeq (,$(wildcard $(GSUTIL)))
+ $(error Unable to find gstuil)
+ endif
+endif
+
+#
+# Define some variables for the given project.
+#
+# FOO_UPLOADS:
+# All files to upload for this project.
+# FOO_CONTINUOUS_DIR:
+# URL of the continuous build directory for this
+# project and revision.
+# FOO_CONTINUOUS_UPLOADS:
+# URLs of all files that will be uploaded for this
+# project and revision.
+# FOO_PUBLISH_DIR:
+# URL of the publish directory for this project and revision.
+#
+# $1 = NAME (e.g. earth)
+#
+define PROJECT
+ $(1)_UPLOADS = $$($(1)_TGTS) $$($(1)_EXTRA_UPLOADS)
+ $(1)_CONTINUOUS_DIR = $(GS_URL_CONTINUOUS)/$(REVISION)/$(1)
+ $(1)_CONTINUOUS_UPLOADS = $$(addprefix $$($(1)_CONTINUOUS_DIR)/,$$(notdir $$($(1)_UPLOADS)))
+ $(1)_PUBLISH_DIR = $(GS_URL_PUBLISH)/$(REVISION)/$(1)
+
+ all: $$($(1)_TGTS)
+
+ .PHONY: $(1)
+ $(1): $$($(1)_TGTS)
+endef
+
+
+#
+# Define rules to upload the project files to the continuous builder directory
+# on CDS.
+#
+# $1 = NAME (e.g. earth)
+#
+define UPLOAD_RULE
+.PHONY: upload-$(1)
+upload-$(1): revision-check
+ @echo "Uploading $$(notdir $$($(1)_UPLOADS)) to $$($(1)_CONTINUOUS_DIR)"
+ @$(GSUTIL) cp -q -a public-read $$($(1)_UPLOADS) $$($(1)_CONTINUOUS_DIR)
+
+upload: upload-$(1)
+endef
+
+#
+# Define rules to copy the project files from the continuous builder
+# directory to the publish directory.
+#
+# $1 = NAME (e.g. earth)
+#
+define PUBLISH_RULE
+.PHONY: publish-$(1)
+publish-$(1): revision-check
+ @echo "Testing that files to publish '$(1)' exist on CDS..."
+ @$(GSUTIL) ls $$($(1)_CONTINUOUS_UPLOADS)
+ @echo OK.
+ @echo "About to publish revision $(REVISION) of '$(1)'..."
+ @read -p "Continue? " -n 1 -r && \
+ echo && \
+ if [[ ! $$$${REPLY} =~ ^[Yy]$$$$ ]]; then \
+ exit 1; \
+ fi;
+ @echo "Publishing..."
+ @$(GSUTIL) cp -p -q $$($(1)_CONTINUOUS_UPLOADS) $$($(1)_PUBLISH_DIR)/
+ @echo "Done."
+
+publish: publish-$(1)
+endef
+
+
+###############################################################################
+# RULES
+
+.PHONY: all
+all:
+
+$(foreach project,$(PROJECTS),$(eval $(call PROJECT,$(project))))
+
+.PHONY: revision-check
+revision-check:
+ifeq (,$(REVISION))
+ $(error Unknown revision number. Run with REVSION=<...>)
+endif
+
+.PHONY: upload
+upload: all
+
+.PHONY: publish
+publish:
+
+$(foreach project,$(PROJECTS),$(eval $(call UPLOAD_RULE,$(project))))
+$(foreach project,$(PROJECTS),$(eval $(call PUBLISH_RULE,$(project))))
diff --git a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
index a327933390..5ac21851ef 100755
--- a/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
+++ b/native_client_sdk/src/gonacl_appengine/src/bullet/build.sh
@@ -6,6 +6,17 @@
set -o nounset
set -o errexit
+SCRIPT_DIR="$(cd $(dirname $0) && pwd)"
+cd ${SCRIPT_DIR}
+
+OUT_DIR=out
+NACLPORTS_URL=https://chromium.googlesource.com/external/naclports
+NACLPORTS_SHA=0096083c0fa71c014f6218bb14d7e1742d9a6b0c
+NACLPORTS_DIR=${OUT_DIR}/naclports
+NACLAM_URL=https://github.com/johnmccutchan/NaClAMBase
+NACLAM_DIR=${OUT_DIR}/NaClAMBase
+NACLAM_SHA=0eb4647a3f99c6e66156959edc6c55d4a913468a
+
if [ -z "${NACL_SDK_ROOT:-}" ]; then
echo "-------------------------------------------------------------------"
echo "NACL_SDK_ROOT is unset."
@@ -31,13 +42,18 @@ LogExecute() {
Clone() {
local url=$1
local dir=$2
+ local sha=$3
if [ ! -d $dir ]; then
LogExecute git clone $url $dir
else
pushd $dir
- LogExecute git pull origin master
+ LogExecute git fetch origin
popd
fi
+
+ pushd $dir
+ LogExecute git checkout $sha
+ popd
}
readonly OS_NAME=$(uname -s)
@@ -49,13 +65,8 @@ else
OS_JOBS=1
fi
-NACLPORTS_URL=https://chromium.googlesource.com/external/naclports
-NACLPORTS_DIR=naclports
-NACLAM_URL=https://github.com/johnmccutchan/NaClAMBase
-NACLAM_DIR=NaClAMBase
-
Banner Cloning naclports
-Clone ${NACLPORTS_URL} ${NACLPORTS_DIR}
+Clone ${NACLPORTS_URL} ${NACLPORTS_DIR} ${NACLPORTS_SHA}
Banner Building bullet
pushd ${NACLPORTS_DIR}
@@ -63,7 +74,7 @@ make NACL_ARCH=pnacl bullet
popd
Banner Cloning NaClAMBase
-Clone ${NACLAM_URL} ${NACLAM_DIR}
+Clone ${NACLAM_URL} ${NACLAM_DIR} ${NACLAM_SHA}
Banner Building NaClAM
LogExecute cp Makefile ${NACLAM_DIR}
@@ -71,6 +82,6 @@ pushd ${NACLAM_DIR}
LogExecute make -j${OS_JOBS}
popd
-LogExecute cp ${NACLAM_DIR}/pnacl/Release/NaClAMBullet.{pexe,nmf} .
+LogExecute cp ${NACLAM_DIR}/pnacl/Release/NaClAMBullet.{pexe,nmf} ${OUT_DIR}
Banner Done!
diff --git a/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore b/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore
new file mode 100644
index 0000000000..b370218a84
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/earth/.gitignore
@@ -0,0 +1 @@
+pnacl
diff --git a/native_client_sdk/src/gonacl_appengine/src/life/Makefile b/native_client_sdk/src/gonacl_appengine/src/life/Makefile
new file mode 100644
index 0000000000..e016af6c83
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/life/Makefile
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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.
+
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
+
+VALID_TOOLCHAINS := newlib glibc pnacl
+
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)
+include $(NACL_SDK_ROOT)/tools/common.mk
+
+TARGET = life
+LIBS = $(DEPS) ppapi_simple nacl_io sdk_util ppapi_cpp ppapi pthread
+
+CFLAGS = -Wall
+SOURCES = life.c
+
+# Build rules generated by macros from common.mk:
+
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ifeq ($(CONFIG),Release)
+$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+else
+$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+endif
+
+$(eval $(call NMF_RULE,$(TARGET),))
diff --git a/native_client_sdk/src/gonacl_appengine/src/life/life.c b/native_client_sdk/src/gonacl_appengine/src/life/life.c
new file mode 100644
index 0000000000..4dbf57fe12
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/life/life.c
@@ -0,0 +1,317 @@
+/* Copyright (c) 2013 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.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_view.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_main.h"
+
+PPB_Core* g_pCore;
+PPB_Graphics2D* g_pGraphics2D;
+PPB_ImageData* g_pImageData;
+PPB_Instance* g_pInstance;
+PPB_View* g_pView;
+PPB_InputEvent* g_pInputEvent;
+PPB_KeyboardInputEvent* g_pKeyboardInput;
+PPB_MouseInputEvent* g_pMouseInput;
+PPB_TouchInputEvent* g_pTouchInput;
+
+struct {
+ PP_Resource ctx;
+ struct PP_Size size;
+ int bound;
+ uint8_t* cell_in;
+ uint8_t* cell_out;
+} g_Context;
+
+
+const unsigned int kInitialRandSeed = 0xC0DE533D;
+
+/* BGRA helper macro, for constructing a pixel for a BGRA buffer. */
+#define MakeBGRA(b, g, r, a) \
+ (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+
+/*
+ * Given a count of cells in a 3x3 grid where cells are worth 1 except for
+ * the center which is worth 9, this is a color representation of how
+ * "alive" that cell is making for a more interesting representation than
+ * a binary alive or dead.
+ */
+const uint32_t kNeighborColors[] = {
+ MakeBGRA(0x00, 0x00, 0x00, 0xff),
+ MakeBGRA(0x00, 0x40, 0x00, 0xff),
+ MakeBGRA(0x00, 0x60, 0x00, 0xff),
+ MakeBGRA(0x00, 0x80, 0x00, 0xff),
+ MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+ MakeBGRA(0x00, 0x00, 0x00, 0xff),
+ MakeBGRA(0x00, 0x40, 0x00, 0xff),
+ MakeBGRA(0x00, 0x60, 0x00, 0xff),
+ MakeBGRA(0x00, 0x80, 0x00, 0xff),
+ MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+};
+
+/*
+ * These represent the new health value of a cell based on its neighboring
+ * values. The health is binary: either alive or dead.
+ */
+const uint8_t kIsAlive[] = {
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, /* Values if the center cell is dead. */
+ 0, 0, 1, 1, 0, 0, 0, 0, 0 /* Values if the center cell is alive. */
+};
+
+void UpdateContext(uint32_t width, uint32_t height) {
+ if (width != g_Context.size.width || height != g_Context.size.height) {
+ size_t size = width * height;
+ size_t index;
+
+ free(g_Context.cell_in);
+ free(g_Context.cell_out);
+
+ /* Create a new context */
+ g_Context.cell_in = (uint8_t*) malloc(size);
+ g_Context.cell_out = (uint8_t*) malloc(size);
+
+ memset(g_Context.cell_out, 0, size);
+ for (index = 0; index < size; index++) {
+ g_Context.cell_in[index] = rand() & 1;
+ }
+ }
+
+ /* Recreate the graphics context on a view change */
+ g_pCore->ReleaseResource(g_Context.ctx);
+ g_Context.size.width = width;
+ g_Context.size.height = height;
+ g_Context.ctx =
+ g_pGraphics2D->Create(PSGetInstanceId(), &g_Context.size, PP_TRUE);
+ g_Context.bound =
+ g_pInstance->BindGraphics(PSGetInstanceId(), g_Context.ctx);
+}
+
+void DrawCell(int32_t x, int32_t y) {
+ int32_t width = g_Context.size.width;
+ int32_t height = g_Context.size.height;
+
+ if (!g_Context.cell_in) return;
+
+ if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+ g_Context.cell_in[x - 1 + y * width] = 1;
+ g_Context.cell_in[x + 1 + y * width] = 1;
+ g_Context.cell_in[x + (y - 1) * width] = 1;
+ g_Context.cell_in[x + (y + 1) * width] = 1;
+ }
+}
+
+void ProcessTouchEvent(PSEvent* event) {
+ uint32_t count = g_pTouchInput->GetTouchCount(event->as_resource,
+ PP_TOUCHLIST_TYPE_TOUCHES);
+ uint32_t i, j;
+ for (i = 0; i < count; i++) {
+ struct PP_TouchPoint touch = g_pTouchInput->GetTouchByIndex(
+ event->as_resource, PP_TOUCHLIST_TYPE_TOUCHES, i);
+ int radius = (int)touch.radius.x;
+ int x = (int)touch.position.x;
+ int y = (int)touch.position.y;
+ /* num = 1/100th the area of touch point */
+ int num = (int)(M_PI * radius * radius / 100.0f);
+ for (j = 0; j < num; j++) {
+ int dx = rand() % (radius * 2) - radius;
+ int dy = rand() % (radius * 2) - radius;
+ /* only plot random cells within the touch area */
+ if (dx * dx + dy * dy <= radius * radius)
+ DrawCell(x + dx, y + dy);
+ }
+ }
+}
+
+void ProcessEvent(PSEvent* event) {
+ switch(event->type) {
+ /* If the view updates, build a new Graphics 2D Context */
+ case PSE_INSTANCE_DIDCHANGEVIEW: {
+ struct PP_Rect rect;
+
+ g_pView->GetRect(event->as_resource, &rect);
+ UpdateContext(rect.size.width, rect.size.height);
+ break;
+ }
+
+ case PSE_INSTANCE_HANDLEINPUT: {
+ PP_InputEvent_Type type = g_pInputEvent->GetType(event->as_resource);
+ PP_InputEvent_Modifier modifiers =
+ g_pInputEvent->GetModifiers(event->as_resource);
+
+ switch(type) {
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
+ struct PP_Point location =
+ g_pMouseInput->GetPosition(event->as_resource);
+ /* If the button is down, draw */
+ if (modifiers & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
+ DrawCell(location.x, location.y);
+ }
+ break;
+ }
+
+ case PP_INPUTEVENT_TYPE_TOUCHSTART:
+ case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+ ProcessTouchEvent(event);
+ break;
+
+ default:
+ break;
+ }
+ /* case PSE_INSTANCE_HANDLEINPUT */
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+void Stir(uint32_t width, uint32_t height) {
+ int i;
+ if (g_Context.cell_in == NULL || g_Context.cell_out == NULL)
+ return;
+
+ for (i = 0; i < width; ++i) {
+ g_Context.cell_in[i] = rand() & 1;
+ g_Context.cell_in[i + (height - 1) * width] = rand() & 1;
+ }
+ for (i = 0; i < height; ++i) {
+ g_Context.cell_in[i * width] = rand() & 1;
+ g_Context.cell_in[i * width + (width - 1)] = rand() & 1;
+ }
+}
+
+void Render() {
+ struct PP_Size* psize = &g_Context.size;
+ PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL;
+
+ /*
+ * Create a buffer to draw into. Since we are waiting until the next flush
+ * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h.
+ */
+ PP_Resource image =
+ g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE);
+ uint8_t* pixels = g_pImageData->Map(image);
+
+ struct PP_ImageDataDesc desc;
+ uint8_t* cell_temp;
+ uint32_t x, y;
+
+ /* If we somehow have not allocated these pointers yet, skip this frame. */
+ if (!g_Context.cell_in || !g_Context.cell_out) return;
+
+ /* Get the stride. */
+ g_pImageData->Describe(image, &desc);
+
+ /* Stir up the edges to prevent the simulation from reaching steady state. */
+ Stir(desc.size.width, desc.size.height);
+
+ /* Do neighbor summation; apply rules, output pixel color. */
+ for (y = 1; y < desc.size.height - 1; ++y) {
+ uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1;
+ uint8_t *src1 = src0 + desc.size.width;
+ uint8_t *src2 = src1 + desc.size.width;
+ int count;
+ uint32_t color;
+ uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1;
+ uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride);
+
+ for (x = 1; x < (desc.size.width - 1); ++x) {
+ /* Build sum, weight center by 9x. */
+ count = src0[-1] + src0[0] + src0[1] +
+ src1[-1] + src1[0] * 9 + src1[1] +
+ src2[-1] + src2[0] + src2[1];
+ color = kNeighborColors[count];
+
+ *pixel_line++ = color;
+ *dst++ = kIsAlive[count];
+ ++src0;
+ ++src1;
+ ++src2;
+ }
+ }
+
+ cell_temp = g_Context.cell_in;
+ g_Context.cell_in = g_Context.cell_out;
+ g_Context.cell_out = cell_temp;
+
+ /* Unmap the range, we no longer need it. */
+ g_pImageData->Unmap(image);
+
+ /* Replace the contexts, and block until it's on the screen. */
+ g_pGraphics2D->ReplaceContents(g_Context.ctx, image);
+ g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete());
+
+ /* Release the image data, we no longer need it. */
+ g_pCore->ReleaseResource(image);
+}
+
+/*
+ * Starting point for the module. We do not use main since it would
+ * collide with main in libppapi_cpp.
+ */
+int example_main(int argc, char *argv[]) {
+ fprintf(stdout,"Started main.\n");
+ g_pCore = (PPB_Core*)PSGetInterface(PPB_CORE_INTERFACE);
+ g_pGraphics2D = (PPB_Graphics2D*)PSGetInterface(PPB_GRAPHICS_2D_INTERFACE);
+ g_pInstance = (PPB_Instance*)PSGetInterface(PPB_INSTANCE_INTERFACE);
+ g_pImageData = (PPB_ImageData*)PSGetInterface(PPB_IMAGEDATA_INTERFACE);
+ g_pView = (PPB_View*)PSGetInterface(PPB_VIEW_INTERFACE);
+
+ g_pInputEvent =
+ (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE);
+ g_pKeyboardInput = (PPB_KeyboardInputEvent*)
+ PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE);
+ g_pMouseInput =
+ (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE);
+ g_pTouchInput =
+ (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE);
+
+ PSEventSetFilter(PSE_ALL);
+ while (1) {
+ /* Process all waiting events without blocking */
+ PSEvent* event;
+ while ((event = PSEventTryAcquire()) != NULL) {
+ ProcessEvent(event);
+ PSEventRelease(event);
+ }
+
+ /* Render a frame, blocking until complete. */
+ if (g_Context.bound) {
+ Render();
+ }
+ }
+ return 0;
+}
+
+/*
+ * Register the function to call once the Instance Object is initialized.
+ * see: pappi_simple/ps_main.h
+ */
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore b/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore
new file mode 100644
index 0000000000..1fcb1529f8
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/lua/.gitignore
@@ -0,0 +1 @@
+out
diff --git a/native_client_sdk/src/gonacl_appengine/src/lua/build.sh b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh
new file mode 100755
index 0000000000..3891fa9f5b
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/lua/build.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# 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.
+
+set -o nounset
+set -o errexit
+set -o xtrace
+
+SCRIPT_DIR="$(cd $(dirname $0) && pwd)"
+cd ${SCRIPT_DIR}
+
+OUT_DIR=out
+NACLPORTS_URL=http://naclports.googlecode.com/svn/trunk/src
+NACLPORTS_REV=939
+NACLPORTS_DIR=${OUT_DIR}/naclports
+
+if [ -z "${NACL_SDK_ROOT:-}" ]; then
+ echo "-------------------------------------------------------------------"
+ echo "NACL_SDK_ROOT is unset."
+ echo "This environment variable needs to be pointed at some version of"
+ echo "the Native Client SDK (the directory containing toolchain/)."
+ echo "NOTE: set this to an absolute path."
+ echo "-------------------------------------------------------------------"
+ exit -1
+fi
+
+Banner() {
+ echo "######################################################################"
+ echo $*
+ echo "######################################################################"
+}
+
+# echo a command to stdout and then execute it.
+LogExecute() {
+ echo $*
+ $*
+}
+
+Clone() {
+ local url=$1
+ local dir=$2
+ local sha=$3
+ if [ ! -d $dir ]; then
+ LogExecute git clone $url $dir
+ else
+ pushd $dir
+ LogExecute git fetch origin
+ popd
+ fi
+
+ pushd $dir
+ LogExecute git checkout $sha
+ popd
+}
+
+Banner Cloning naclports
+if [ ! -d ${NACLPORTS_DIR} ]; then
+ mkdir -p ${NACLPORTS_DIR}
+ pushd ${NACLPORTS_DIR}
+ gclient config --name=src ${NACLPORTS_URL}
+ popd
+fi
+
+pushd ${NACLPORTS_DIR}
+gclient sync -r ${NACLPORTS_REV}
+popd
+
+Banner Building lua
+pushd ${NACLPORTS_DIR}/src
+make NACL_ARCH=pnacl lua_ppapi
+popd
+
+Banner Done!
diff --git a/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile b/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile
new file mode 100644
index 0000000000..089bf9062e
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/voronoi/Makefile
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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.
+
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
+
+VALID_TOOLCHAINS := newlib glibc pnacl
+
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)
+include $(NACL_SDK_ROOT)/tools/common.mk
+
+TARGET = voronoi
+LIBS = $(DEPS) ppapi_simple nacl_io sdk_util ppapi_cpp ppapi pthread
+
+CFLAGS = -Wall
+SOURCES = voronoi.cc
+
+# Build rules generated by macros from common.mk:
+
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+
+ifeq ($(CONFIG),Release)
+$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
+else
+$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
+endif
+
+$(eval $(call NMF_RULE,$(TARGET),))
diff --git a/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc b/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc
new file mode 100644
index 0000000000..1e30047285
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/src/voronoi/voronoi.cc
@@ -0,0 +1,499 @@
+// Copyright (c) 2013 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.
+
+#include <assert.h>
+#include <math.h>
+#include <ppapi/c/ppb_input_event.h>
+#include <ppapi/cpp/input_event.h>
+#include <ppapi/cpp/var.h>
+#include <ppapi/cpp/var_array.h>
+#include <ppapi/cpp/var_array_buffer.h>
+#include <ppapi/cpp/var_dictionary.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_main.h"
+#include "sdk_util/thread_pool.h"
+
+using namespace sdk_util; // For sdk_util::ThreadPool
+
+// Global properties used to setup Voronoi demo.
+namespace {
+const int kMinRectSize = 4;
+const int kStartRecurseSize = 32; // must be power-of-two
+const float kHugeZ = 1.0e38f;
+const float kPI = M_PI;
+const float kTwoPI = kPI * 2.0f;
+const unsigned int kRandomStartSeed = 0xC0DE533D;
+const int kMaxPointCount = 1024;
+const int kStartPointCount = 48;
+const int kDefaultNumRegions = 256;
+
+unsigned int g_rand_state = kRandomStartSeed;
+
+// random number helper
+inline unsigned char rand255() {
+ return static_cast<unsigned char>(rand_r(&g_rand_state) & 255);
+}
+
+// random number helper
+inline float frand() {
+ return (static_cast<float>(rand_r(&g_rand_state)) /
+ static_cast<float>(RAND_MAX));
+}
+
+// reset random seed
+inline void rand_reset(unsigned int seed) {
+ g_rand_state = seed;
+}
+
+inline uint32_t next_pow2(uint32_t x) {
+ // Via Hacker's Delight, section 3.2 "Rounding Up/Down to the Next Power of 2"
+ --x;
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return x + 1;
+}
+
+// BGRA helper function, for constructing a pixel for a BGRA buffer.
+inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
+ return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
+}
+} // namespace
+
+// Vec2, simple 2D vector
+struct Vec2 {
+ float x, y;
+ Vec2() {}
+ Vec2(float px, float py) {
+ x = px;
+ y = py;
+ }
+ void Set(float px, float py) {
+ x = px;
+ y = py;
+ }
+};
+
+// The main object that runs Voronoi simulation.
+class Voronoi {
+ public:
+ Voronoi();
+ virtual ~Voronoi();
+ // Runs a tick of the simulations, update 2D output.
+ void Update();
+ // Handle event from user, or message from JS.
+ void HandleEvent(PSEvent* ps_event);
+
+ private:
+ // Methods prefixed with 'w' are run on worker threads.
+ uint32_t* wGetAddr(int x, int y);
+ int wCell(float x, float y);
+ inline void wFillSpan(uint32_t *pixels, uint32_t color, int width);
+ void wRenderTile(int x, int y, int w, int h);
+ void wProcessTile(int x, int y, int w, int h);
+ void wSubdivide(int x, int y, int w, int h);
+ void wMakeRect(int region, int *x, int *y, int *w, int *h);
+ bool wTestRect(int *m, int x, int y, int w, int h);
+ void wFillRect(int x, int y, int w, int h, uint32_t color);
+ void wRenderRect(int x0, int y0, int x1, int y1);
+ void wRenderRegion(int region);
+ static void wRenderRegionEntry(int region, void *thiz);
+
+ // These methods are only called by the main thread.
+ void Reset();
+ void UpdateSim();
+ void RenderDot(float x, float y, uint32_t color1, uint32_t color2);
+ void SuperimposePositions();
+ void Render();
+ void Draw();
+ // Helper to post small update messages to JS.
+ void PostUpdateMessage(const char* message_name, double value);
+
+ PSContext2D_t* ps_context_;
+ Vec2 positions_[kMaxPointCount];
+ Vec2 screen_positions_[kMaxPointCount];
+ Vec2 velocities_[kMaxPointCount];
+ uint32_t colors_[kMaxPointCount];
+ float ang_;
+ const int num_regions_;
+ int num_threads_;
+ int point_count_;
+ bool draw_points_;
+ bool draw_interiors_;
+ ThreadPool* workers_;
+};
+
+
+void Voronoi::Reset() {
+ rand_reset(kRandomStartSeed);
+ ang_ = 0.0f;
+ for (int i = 0; i < kMaxPointCount; i++) {
+ // random initial start position
+ const float x = frand();
+ const float y = frand();
+ positions_[i].Set(x, y);
+ // random directional velocity ( -1..1, -1..1 )
+ const float speed = 0.0005f;
+ const float u = (frand() * 2.0f - 1.0f) * speed;
+ const float v = (frand() * 2.0f - 1.0f) * speed;
+ velocities_[i].Set(u, v);
+ // 'unique' color (well... unique enough for our purposes)
+ colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255);
+ }
+}
+
+Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0),
+ point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true) {
+ Reset();
+ // By default, render from the dispatch thread.
+ workers_ = new ThreadPool(num_threads_);
+ PSEventSetFilter(PSE_ALL);
+ ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
+}
+
+Voronoi::~Voronoi() {
+ delete workers_;
+ PSContext2DFree(ps_context_);
+}
+
+inline uint32_t* Voronoi::wGetAddr(int x, int y) {
+ return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
+}
+
+// This is the core of the Voronoi calculation. At a given point on the
+// screen, iterate through all voronoi positions and render them as 3D cones.
+// We're looking for the voronoi cell that generates the closest z value.
+// (not really cones - since it is all relative, we avoid doing the
+// expensive sqrt and test against z*z instead)
+// If multithreading, this function is only called by the worker threads.
+int Voronoi::wCell(float x, float y) {
+ int closest_cell = 0;
+ float zz = kHugeZ;
+ Vec2* pos = screen_positions_;
+ for (int i = 0; i < point_count_; ++i) {
+ // measured 5.18 cycles per iteration on a core2
+ float dx = x - pos[i].x;
+ float dy = y - pos[i].y;
+ float dd = (dx * dx + dy * dy);
+ if (dd < zz) {
+ zz = dd;
+ closest_cell = i;
+ }
+ }
+ return closest_cell;
+}
+
+// Given a region r, derive a non-overlapping rectangle for a thread to
+// work on.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) {
+ const int parts = 16;
+ assert(parts * parts == num_regions_);
+ // Round up to the nearest power of two so we can divide by parts cleanly. We
+ // could round up to the nearest 16 pixels, but it runs much faster when
+ // subdividing power-of-two squares.
+ //
+ // Many of these squares are outside of the canvas, but they will be
+ // trivially culled by wRenderRect.
+ *w = static_cast<int>(next_pow2(ps_context_->width)) / parts;
+ *h = static_cast<int>(next_pow2(ps_context_->height)) / parts;
+ *x = *w * (r % parts);
+ *y = *h * ((r / parts) % parts);
+}
+
+// Test 4 corners of a rectangle to see if they all belong to the same
+// voronoi cell. Each test is expensive so bail asap. Returns true
+// if all 4 corners match.
+// If multithreading, this function is only called by the worker threads.
+bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) {
+ // each test is expensive, so exit ASAP
+ const int m0 = wCell(x, y);
+ const int m1 = wCell(x + w - 1, y);
+ if (m0 != m1) return false;
+ const int m2 = wCell(x, y + h - 1);
+ if (m0 != m2) return false;
+ const int m3 = wCell(x + w - 1, y + h - 1);
+ if (m0 != m3) return false;
+ // all 4 corners belong to the same cell
+ *m = m0;
+ return true;
+}
+
+// Quickly fill a span of pixels with a solid color.
+// If multithreading, this function is only called by the worker threads.
+inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
+ if (!draw_interiors_) {
+ const uint32_t gray = MakeBGRA(128, 128, 128, 255);
+ color = gray;
+ }
+
+ for (int i = 0; i < width; ++i)
+ *pixels++ = color;
+}
+
+// Quickly fill a rectangle with a solid color.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+ uint32_t* pixels = wGetAddr(x, y);
+ for (int j = 0; j < h; j++) {
+ wFillSpan(pixels, color, w);
+ pixels += stride_in_pixels;
+ }
+}
+
+// When recursive subdivision reaches a certain minimum without finding a
+// rectangle that has four matching corners belonging to the same voronoi
+// cell, this function will break the retangular 'tile' into smaller scanlines
+// and look for opportunities to quick fill at the scanline level. If the
+// scanline can't be quick filled, it will slow down even further and compute
+// voronoi membership per pixel.
+void Voronoi::wRenderTile(int x, int y, int w, int h) {
+ // rip through a tile
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+ uint32_t* pixels = wGetAddr(x, y);
+ for (int j = 0; j < h; j++) {
+ // get start and end cell values
+ int ms = wCell(x + 0, y + j);
+ int me = wCell(x + w - 1, y + j);
+ // if the end points are the same, quick fill the span
+ if (ms == me) {
+ wFillSpan(pixels, colors_[ms], w);
+ } else {
+ // else compute each pixel in the span... this is the slow part!
+ uint32_t* p = pixels;
+ *p++ = colors_[ms];
+ for (int i = 1; i < (w - 1); i++) {
+ int m = wCell(x + i, y + j);
+ *p++ = colors_[m];
+ }
+ *p++ = colors_[me];
+ }
+ pixels += stride_in_pixels;
+ }
+}
+
+// Take a rectangular region and do one of -
+// If all four corners below to the same voronoi cell, stop recursion and
+// quick fill the rectangle.
+// If the minimum rectangle size has been reached, break out of recursion
+// and process the rectangle. This small rectangle is called a tile.
+// Otherwise, keep recursively subdividing the rectangle into 4 equally
+// sized smaller rectangles.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wSubdivide(int x, int y, int w, int h) {
+ int m;
+ // if all 4 corners are equal, quick fill interior
+ if (wTestRect(&m, x, y, w, h)) {
+ wFillRect(x, y, w, h, colors_[m]);
+ } else {
+ // did we reach the minimum rectangle size?
+ if ((w <= kMinRectSize) || (h <= kMinRectSize)) {
+ wRenderTile(x, y, w, h);
+ } else {
+ // else recurse into smaller rectangles
+ const int half_w = w / 2;
+ const int half_h = h / 2;
+ wSubdivide(x, y, half_w, half_h);
+ wSubdivide(x + half_w, y, w - half_w, half_h);
+ wSubdivide(x, y + half_h, half_w, h - half_h);
+ wSubdivide(x + half_w, y + half_h, w - half_w, h - half_h);
+ }
+ }
+}
+
+// This function cuts up the rectangle into squares (preferably power-of-two).
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wRenderRect(int x, int y, int w, int h) {
+ for (int iy = y; iy < (y + h); iy += kStartRecurseSize) {
+ for (int ix = x; ix < (x + w); ix += kStartRecurseSize) {
+ int iw = kStartRecurseSize;
+ int ih = kStartRecurseSize;
+ // Clamp width + height.
+ if (ix + iw > ps_context_->width)
+ iw = ps_context_->width - ix;
+ if (iy + ih > ps_context_->height)
+ ih = ps_context_->height - iy;
+ if (iw <= 0 || ih <= 0)
+ continue;
+
+ wSubdivide(ix, iy, iw, ih);
+ }
+ }
+}
+
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wRenderRegion(int region) {
+ // convert region # into x0, y0, x1, y1 rectangle
+ int x, y, w, h;
+ wMakeRect(region, &x, &y, &w, &h);
+ // render this rectangle
+ wRenderRect(x, y, w, h);
+}
+
+// Entry point for worker thread. Can't pass a member function around, so we
+// have to do this little round-about.
+void Voronoi::wRenderRegionEntry(int region, void* thiz) {
+ static_cast<Voronoi*>(thiz)->wRenderRegion(region);
+}
+
+// Function Voronoi::UpdateSim()
+// Run a simple sim to move the voronoi positions. This update loop
+// is run once per frame. Called from the main thread only, and only
+// when the worker threads are idle.
+void Voronoi::UpdateSim() {
+ ang_ += 0.002f;
+ if (ang_ > kTwoPI) {
+ ang_ = ang_ - kTwoPI;
+ }
+ float z = cosf(ang_) * 3.0f;
+ // push the points around on the screen for animation
+ for (int j = 0; j < kMaxPointCount; j++) {
+ positions_[j].x += (velocities_[j].x) * z;
+ positions_[j].y += (velocities_[j].y) * z;
+ screen_positions_[j].x = positions_[j].x * ps_context_->width;
+ screen_positions_[j].y = positions_[j].y * ps_context_->height;
+ }
+}
+
+// Renders a small diamond shaped dot at x, y clipped against the window
+void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
+ const int ix = static_cast<int>(x);
+ const int iy = static_cast<int>(y);
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+ // clip it against window
+ if (ix < 1) return;
+ if (ix >= (ps_context_->width - 1)) return;
+ if (iy < 1) return;
+ if (iy >= (ps_context_->height - 1)) return;
+ uint32_t* pixel = wGetAddr(ix, iy);
+ // render dot as a small diamond
+ *pixel = color1;
+ *(pixel - 1) = color2;
+ *(pixel + 1) = color2;
+ *(pixel - stride_in_pixels) = color2;
+ *(pixel + stride_in_pixels) = color2;
+}
+
+// Superimposes dots on the positions.
+void Voronoi::SuperimposePositions() {
+ const uint32_t white = MakeBGRA(255, 255, 255, 255);
+ const uint32_t gray = MakeBGRA(192, 192, 192, 255);
+ for (int i = 0; i < point_count_; i++) {
+ RenderDot(
+ screen_positions_[i].x, screen_positions_[i].y, white, gray);
+ }
+}
+
+// Renders the Voronoi diagram, dispatching the work to multiple threads.
+void Voronoi::Render() {
+ workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
+ if (draw_points_)
+ SuperimposePositions();
+}
+
+// Handle input events from the user and messages from JS.
+void Voronoi::HandleEvent(PSEvent* ps_event) {
+ // Give the 2D context a chance to process the event.
+ if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
+ return;
+ if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
+ // Convert Pepper Simple event to a PPAPI C++ event
+ pp::InputEvent event(ps_event->as_resource);
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_TOUCHSTART:
+ case PP_INPUTEVENT_TYPE_TOUCHMOVE: {
+ pp::TouchInputEvent touches = pp::TouchInputEvent(event);
+ uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
+ // Touch points 0..n directly set position of points 0..n in
+ // Voronoi diagram.
+ for (uint32_t i = 0; i < count; i++) {
+ pp::TouchPoint touch =
+ touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, i);
+ pp::FloatPoint point = touch.position();
+ positions_[i].Set(point.x() / ps_context_->width,
+ point.y() / ps_context_->height);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
+ // Convert Pepper Simple message to PPAPI C++ var
+ pp::Var var(ps_event->as_var);
+ if (var.is_dictionary()) {
+ pp::VarDictionary dictionary(var);
+ std::string message = dictionary.Get("message").AsString();
+ if (message == "draw_points")
+ draw_points_ = dictionary.Get("value").AsBool();
+ else if (message == "draw_interiors")
+ draw_interiors_ = dictionary.Get("value").AsBool();
+ else if (message == "set_points") {
+ int num_points = dictionary.Get("value").AsInt();
+ point_count_ = std::min(kMaxPointCount, std::max(0, num_points));
+ } else if (message == "set_threads") {
+ int thread_count = dictionary.Get("value").AsInt();
+ delete workers_;
+ workers_ = new ThreadPool(thread_count);
+ }
+ }
+ }
+}
+
+// PostUpdateMessage() helper function for sendimg small messages to JS.
+void Voronoi::PostUpdateMessage(const char* message_name, double value) {
+ pp::VarDictionary message;
+ message.Set("message", message_name);
+ message.Set("value", value);
+ PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
+}
+
+void Voronoi::Update() {
+ PSContext2DGetBuffer(ps_context_);
+ if (NULL == ps_context_->data)
+ return;
+
+ UpdateSim();
+ Render();
+
+ PSContext2DSwapBuffer(ps_context_);
+}
+
+// Starting point for the module. We do not use main since it would
+// collide with main in libppapi_cpp.
+int example_main(int argc, char* argv[]) {
+ Voronoi voronoi;
+ while (true) {
+ PSEvent* ps_event;
+ // Consume all available events.
+ while ((ps_event = PSEventTryAcquire()) != NULL) {
+ voronoi.HandleEvent(ps_event);
+ PSEventRelease(ps_event);
+ }
+ // Do simulation, render and present.
+ voronoi.Update();
+ }
+
+ return 0;
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
index 3ab6eab3ee..7af7346808 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/index.html
@@ -61,8 +61,8 @@ found in the LICENSE file.
<button id="reload">Reload Scene</button>
</div>
<ul>
- <li>Hold "h" to pick up an object</li>
- <li>Click and drag to rotate the camera</li>
+ <li>Click and drag an object to move it</li>
+ <li>Click and drag elsewhere to rotate the camera</li>
<li>Use the mousewheel to zoom in/out</li>
</ul>
<p class="small">
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
index b84c2acfc7..be091e26fc 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/main.js
@@ -75,7 +75,7 @@ function pageDidLoad() {
embed.setAttribute('width', '0');
embed.setAttribute('height', '0');
embed.setAttribute('type', 'application/x-pnacl');
- embed.setAttribute('src', 'http://commondatastorage.googleapis.com/gonacl/pnacl-demo-bullet/NaClAMBullet.portable.nmf');
+ embed.setAttribute('src', 'http://commondatastorage.googleapis.com/gonacl/demos/publish/229855/bullet/NaClAMBullet.nmf');
embedWrap.appendChild(embed);
}
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
index 6740155dfa..27ae546e52 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-bullet/scene.js
@@ -194,8 +194,6 @@ function init() {
rendererContainer.appendChild(renderer.domElement);
- controls = new THREE.OrbitControls (camera, rendererContainer);
-
var idFuncHash = {
jenga10: loadJenga10,
jenga20: loadJenga20,
@@ -213,9 +211,13 @@ function init() {
$('reload').addEventListener('click', reloadScene, false);
- renderer.domElement.addEventListener('mousemove', onDocumentMouseMove, false );
- window.addEventListener('keydown', onDocumentKeyDown, false);
- window.addEventListener('keyup', onDocumentKeyUp, false);
+ rendererContainer.addEventListener('mousedown', onMouseDown, false);
+ rendererContainer.addEventListener('mouseup', onMouseUp, false);
+ renderer.domElement.addEventListener('mousemove', onMouseMove, false);
+
+ // Add the OrbitControls after our own listeners -- that way we can prevent
+ // the camera rotation when dragging an object.
+ controls = new THREE.OrbitControls(camera, rendererContainer);
window.setInterval(pollForRendererResize, 10);
}
@@ -234,35 +236,35 @@ function pollForRendererResize() {
lastRendererHeight = h;
}
-function onDocumentKeyDown(event) {
- if (event.keyCode == 72 || event.keyCode == 104) {
- if (SELECTED != undefined) {
- return;
- }
- hold = true;
- var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
- projector.unprojectVector( vector, camera );
- var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
- var intersects = ray.intersectObjects( objects );
- if (intersects.length > 0) {
- if (intersects[0].object != plane) {
- SELECTED = intersects[0].object;
- //console.log(SELECTED.objectTableIndex);
- NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
- }
+function onMouseDown(event) {
+ var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
+ projector.unprojectVector( vector, camera );
+ var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
+ var intersects = ray.intersectObjects( objects );
+ if (intersects.length > 0) {
+ if (intersects[0].object != plane) {
+ hold = true;
+ SELECTED = intersects[0].object;
+ //console.log(SELECTED.objectTableIndex);
+ NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
+ // stopImmediatePropagation() will prevent other event listeners on the
+ // same element from firing -- in this case, the OrbitControls camera
+ // rotation.
+ event.stopImmediatePropagation();
}
}
}
-function onDocumentKeyUp(event) {
- if (event.keyCode == 72 || event.keyCode == 104) {
+function onMouseUp(event) {
+ if (hold) {
hold = false;
SELECTED = undefined;
NaClAMBulletDropObject();
+ event.stopImmediatePropagation();
}
}
-function onDocumentMouseMove( event ) {
+function onMouseMove( event ) {
event.preventDefault();
var rendererContainer = $('rendererContainer');
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
index fac8405faa..53e9e6d996 100644
--- a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-earth/example.js
@@ -42,9 +42,9 @@ function browserSupportsPNaCl() {
* @return {string}
*/
function getDataURL(name) {
- var baseUrl =
- 'http://commondatastorage.googleapis.com/gonacl/pnacl-earth-demo/';
- return baseUrl + name;
+ var revision = 229855;
+ var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+ return baseUrl + revision + '/earth/' + name;
}
/**
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js
new file mode 100644
index 0000000000..276aaed05e
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/example.js
@@ -0,0 +1,194 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+var naclModule = null;
+
+/**
+ * A helper function to abbreviate getElementById.
+ *
+ * @param {string} elementId The id to get.
+ * @return {Element}
+ */
+function $(elementId) {
+ return document.getElementById(elementId);
+}
+
+/**
+ * MIME type for PNaCl
+ *
+ * @return {string} MIME type
+ */
+function PNaClmimeType() {
+ return 'application/x-pnacl';
+}
+
+/**
+ * Check if the browser supports PNaCl.
+ *
+ * @return {bool}
+ */
+function browserSupportsPNaCl() {
+ var mimetype = PNaClmimeType();
+ return navigator.mimeTypes[mimetype] !== undefined;
+}
+
+/**
+ * Get the URL for Google Cloud Storage.
+ *
+ * @param {string} name The relative path to the file.
+ * @return {string}
+ */
+function getDataURL(name) {
+ var revision = 231029;
+ var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+ return baseUrl + revision + '/life/' + name;
+}
+
+/**
+ * Create the Native Client <embed> element as a child of the DOM element
+ * named "listener".
+ *
+ * @param {string} name The name of the example.
+ * @param {number} width The width to create the plugin.
+ * @param {number} height The height to create the plugin.
+ * @param {Object} attrs Dictionary of attributes to set on the module.
+ */
+function createNaClModule(name, width, height, attrs) {
+ var moduleEl = document.createElement('embed');
+ moduleEl.setAttribute('name', 'nacl_module');
+ moduleEl.setAttribute('id', 'nacl_module');
+ moduleEl.setAttribute('width', width);
+ moduleEl.setAttribute('height', height);
+ moduleEl.setAttribute('path', '');
+ moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
+ moduleEl.setAttribute('type', PNaClmimeType());
+
+ // Add any optional arguments
+ if (attrs) {
+ for (var key in attrs) {
+ moduleEl.setAttribute(key, attrs[key]);
+ }
+ }
+
+ // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+ // and a 'message' event listener attached. This wrapping method is used
+ // instead of attaching the event listeners directly to the <EMBED> element
+ // to ensure that the listeners are active before the NaCl module 'load'
+ // event fires.
+ var listenerDiv = $('listener');
+ listenerDiv.appendChild(moduleEl);
+}
+
+/**
+ * Add the default event listeners to the element with id "listener".
+ */
+function attachDefaultListeners() {
+ var listenerDiv = $('listener');
+ listenerDiv.addEventListener('load', moduleDidLoad, true);
+ listenerDiv.addEventListener('error', moduleLoadError, true);
+ listenerDiv.addEventListener('progress', moduleLoadProgress, true);
+ listenerDiv.addEventListener('crash', handleCrash, true);
+}
+
+/**
+ * Called when the Browser can not communicate with the Module
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ *
+ * @param {Object} event
+ */
+function handleCrash(event) {
+ if (naclModule.exitStatus == -1) {
+ updateStatus('CRASHED');
+ } else {
+ updateStatus('EXITED [' + naclModule.exitStatus + ']');
+ }
+}
+
+/**
+ * Called when the NaCl module is loaded.
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ */
+function moduleDidLoad() {
+ var bar = $('progress');
+ bar.value = 100;
+ bar.max = 100;
+ naclModule = $('nacl_module');
+ hideStatus();
+ setThreadCount();
+}
+
+/**
+ * Hide the status field and progress bar.
+ */
+function hideStatus() {
+ $('statusField').style.display = 'none';
+ $('progress').style.display = 'none';
+}
+
+/**
+ * Called when the plugin fails to load.
+ *
+ * @param {Object} event
+ */
+function moduleLoadError(event) {
+ updateStatus('Load failed.');
+}
+
+/**
+ * Called when the plugin reports progress events.
+ *
+ * @param {Object} event
+ */
+function moduleLoadProgress(event) {
+ $('progress').style.display = 'block';
+
+ var loadPercent = 0.0;
+ var bar = $('progress');
+ bar.max = 100;
+ if (event.lengthComputable && event.total > 0) {
+ loadPercent = event.loaded / event.total * 100.0;
+ } else {
+ // The total length is not yet known.
+ loadPercent = -1.0;
+ }
+ bar.value = loadPercent;
+}
+
+/**
+ * If the element with id 'statusField' exists, then set its HTML to the status
+ * message as well.
+ *
+ * @param {string} opt_message The message to set.
+ */
+function updateStatus(opt_message) {
+ var statusField = $('statusField');
+ if (statusField) {
+ statusField.style.display = 'block';
+ statusField.textContent = opt_message;
+ }
+}
+
+/**
+ * Listen for the DOM content to be loaded. This event is fired when parsing of
+ * the page's document has finished.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ updateStatus('Loading...');
+ if (!browserSupportsPNaCl()) {
+ updateStatus('Browser does not support PNaCl or PNaCl is disabled');
+ } else if (naclModule == null) {
+ createNaClModule('life', 512, 512);
+ attachDefaultListeners();
+ } else {
+ // It's possible that the Native Client module onload event fired
+ // before the page's onload event. In this case, the status message
+ // will reflect 'SUCCESS', but won't be displayed. This call will
+ // display the current message.
+ updateStatus('Waiting.');
+ }
+});
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html
new file mode 100644
index 0000000000..1b02777d40
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-life/index.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright (c) 2013 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.
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Life</title>
+ <script type="text/javascript" src="example.js"></script>
+ <link href="/static/common.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+ <div class="absolute-fill">
+ <div class="flex-container">
+ <div class="main absolute-fill-parent">
+ <div class="absolute-fill">
+ <div class="flex-container flex-column flex-justify-center">
+ <div id="message">
+ <div id="statusField"></div>
+ <progress id="progress"></progress>
+ </div>
+ </div>
+ </div>
+ <div id="listener" class="absolute-fill"></div>
+ </div>
+ <div class="sidebar">
+ <h1>Life</h1>
+ <p>
+ This demo renders <a
+ href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway's
+ Game of Life</a>.
+ </p>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html
new file mode 100644
index 0000000000..c0371d25bc
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/index.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Lua</title>
+ <script type="text/javascript" src="http://commondatastorage.googleapis.com/gonacl/demos/publish/231022/lua/hterm.concat.js"></script>
+ <script type="text/javascript" src="naclterm.js"></script>
+ <script type="text/javascript" src="lua.js"></script>
+
+ <style type="text/css">
+ body {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ }
+
+ #terminal {
+ display: block;
+ position: static;
+ width: 100%;
+ height: 100%;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="terminal"></div>
+ </body>
+</html>
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js
new file mode 100644
index 0000000000..18b84275d9
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/lua.js
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+NaClTerm.prefix = 'lua'
+NaClTerm.nmf = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/231022/lua/lua.nmf'
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js
new file mode 100644
index 0000000000..d272a0bdc9
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-lua/naclterm.js
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+'use strict';
+
+lib.rtdep('lib.f',
+ 'hterm');
+
+// CSP means that we can't kick off the initialization from the html file,
+// so we do it like this instead.
+window.onload = function() {
+ lib.init(function() {
+ NaClTerm.init();
+ });
+};
+
+/**
+ * The hterm-powered terminal command.
+ *
+ * This class defines a command that can be run in an hterm.Terminal instance.
+ *
+ * @param {Object} argv The argument object passed in from the Terminal.
+ */
+function NaClTerm(argv) {
+ this.argv_ = argv;
+ this.io = null;
+};
+
+var embed;
+
+/**
+ * Static initialier called from index.html.
+ *
+ * This constructs a new Terminal instance and instructs it to run the NaClTerm
+ * command.
+ */
+NaClTerm.init = function() {
+ var profileName = lib.f.parseQuery(document.location.search)['profile'];
+ var terminal = new hterm.Terminal(profileName);
+ terminal.decorate(document.querySelector('#terminal'));
+
+ // Useful for console debugging.
+ window.term_ = terminal;
+
+ // We don't properly support the hterm bell sound, so we need to disable it.
+ terminal.prefs_.definePreference('audible-bell-sound', '');
+
+ terminal.setAutoCarriageReturn(true);
+ terminal.setCursorPosition(0, 0);
+ terminal.setCursorVisible(true);
+ terminal.runCommandClass(NaClTerm, document.location.hash.substr(1));
+
+ return true;
+};
+
+/**
+ * Handle messages sent to us from NaCl.
+ *
+ * @private
+ */
+NaClTerm.prototype.handleMessage_ = function(e) {
+ if (e.data.indexOf(NaClTerm.prefix) != 0) return;
+ var msg = e.data.substring(NaClTerm.prefix.length);
+ if (!this.loaded) {
+ this.bufferedOutput += msg;
+ } else {
+ term_.io.print(msg);
+ }
+}
+
+/**
+ * Handle load error event from NaCl.
+ */
+NaClTerm.prototype.handleLoadAbort_ = function(e) {
+ term_.io.print("Load aborted.\n");
+}
+
+/**
+ * Handle load abort event from NaCl.
+ */
+NaClTerm.prototype.handleLoadError_ = function(e) {
+ term_.io.print(embed.lastError + '\n');
+}
+
+/**
+ * Handle load end event from NaCl.
+ */
+NaClTerm.prototype.handleLoad_ = function(e) {
+ if (typeof(this.lastUrl) != 'undefined')
+ term_.io.print("\n");
+ term_.io.print("Loaded.\n");
+
+ // Now that have completed loading and displaying
+ // loading messages we output any messages from the
+ // NaCl module that were buffered up unto this point
+ this.loaded = true;
+ term_.io.print(this.bufferedOutput);
+ this.bufferedOutput = ''
+}
+
+/**
+ * Handle load progress event from NaCl.
+ */
+NaClTerm.prototype.handleProgress_ = function(e) {
+ var url = e.url.substring(e.url.lastIndexOf('/') + 1);
+ if (this.lastUrl != url) {
+ if (url != '') {
+ if (this.lastUrl)
+ term_.io.print("\n");
+ term_.io.print("Loading " + url + " .");
+ }
+ } else {
+ term_.io.print(".");
+ }
+ if (url)
+ this.lastUrl = url;
+}
+
+/**
+ * Handle crash event from NaCl.
+ */
+NaClTerm.prototype.handleCrash_ = function(e) {
+ if (embed.exitStatus == -1) {
+ term_.io.print("Program crashed (exit status -1)\n")
+ } else {
+ term_.io.print("Program exited (status=" + embed.exitStatus + ")\n");
+ }
+}
+
+
+NaClTerm.prototype.onTerminalResize_ = function() {
+ var width = term_.io.terminal_.screenSize.width;
+ var height = term_.io.terminal_.screenSize.height;
+ embed.postMessage({'tty_resize': [ width, height ]});
+}
+
+NaClTerm.prototype.onVTKeystroke_ = function(str) {
+ var message = {};
+ message[NaClTerm.prefix] = str;
+ embed.postMessage(message);
+}
+
+/*
+ * This is invoked by the terminal as a result of terminal.runCommandClass().
+ */
+NaClTerm.prototype.run = function() {
+ this.io = this.argv_.io.push();
+ this.bufferedOutput = '';
+ this.loaded = false;
+
+ embed = document.createElement('object');
+ embed.width = 0;
+ embed.height = 0;
+ embed.data = NaClTerm.nmf;
+ embed.type = 'application/x-pnacl';
+ embed.addEventListener('message', this.handleMessage_.bind(this));
+ embed.addEventListener('progress', this.handleProgress_.bind(this));
+ embed.addEventListener('load', this.handleLoad_.bind(this));
+ embed.addEventListener('error', this.handleLoadError_.bind(this));
+ embed.addEventListener('abort', this.handleLoadAbort_.bind(this));
+ embed.addEventListener('crash', this.handleCrash_.bind(this));
+
+ function addParam(name, value) {
+ var param = document.createElement('param');
+ param.name = name;
+ param.value = value;
+ embed.appendChild(param);
+ }
+
+ addParam('ps_tty_prefix', NaClTerm.prefix);
+ addParam('ps_tty_resize', 'tty_resize');
+ addParam('ps_stdin', '/dev/tty');
+ addParam('ps_stdout', '/dev/tty');
+ addParam('ps_stderr', '/dev/tty');
+ addParam('ps_verbosity', '2');
+ addParam('TERM', 'xterm-256color');
+
+ var args = lib.f.parseQuery(document.location.search);
+ var argn = 1;
+ while (true) {
+ var argname = 'arg' + argn;
+ var arg = args[argname];
+ if (typeof(arg) === 'undefined')
+ break;
+ addParam(argname, arg);
+ argn = argn + 1;
+ }
+
+ term_.io.print("Loading NaCl module.\n")
+ document.body.appendChild(embed);
+
+ this.io.onVTKeystroke = this.onVTKeystroke_.bind(this);
+ this.io.onTerminalResize = this.onTerminalResize_.bind(this);
+};
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js
new file mode 100644
index 0000000000..ff8357184d
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/example.js
@@ -0,0 +1,233 @@
+// Copyright (c) 2013 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.
+
+'use strict';
+
+var naclModule = null;
+
+/**
+ * A helper function to abbreviate getElementById.
+ *
+ * @param {string} elementId The id to get.
+ * @return {Element}
+ */
+function $(elementId) {
+ return document.getElementById(elementId);
+}
+
+/**
+ * MIME type for PNaCl
+ *
+ * @return {string} MIME type
+ */
+function PNaClmimeType() {
+ return 'application/x-pnacl';
+}
+
+/**
+ * Check if the browser supports PNaCl.
+ *
+ * @return {bool}
+ */
+function browserSupportsPNaCl() {
+ var mimetype = PNaClmimeType();
+ return navigator.mimeTypes[mimetype] !== undefined;
+}
+
+/**
+ * Get the URL for Google Cloud Storage.
+ *
+ * @param {string} name The relative path to the file.
+ * @return {string}
+ */
+function getDataURL(name) {
+ var revision = 231029;
+ var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
+ return baseUrl + revision + '/voronoi/' + name;
+}
+
+/**
+ * Create the Native Client <embed> element as a child of the DOM element
+ * named "listener".
+ *
+ * @param {string} name The name of the example.
+ * @param {number} width The width to create the plugin.
+ * @param {number} height The height to create the plugin.
+ * @param {Object} attrs Dictionary of attributes to set on the module.
+ */
+function createNaClModule(name, width, height, attrs) {
+ var moduleEl = document.createElement('embed');
+ moduleEl.setAttribute('name', 'nacl_module');
+ moduleEl.setAttribute('id', 'nacl_module');
+ moduleEl.setAttribute('width', width);
+ moduleEl.setAttribute('height', height);
+ moduleEl.setAttribute('path', '');
+ moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
+ moduleEl.setAttribute('type', PNaClmimeType());
+
+ // Add any optional arguments
+ if (attrs) {
+ for (var key in attrs) {
+ moduleEl.setAttribute(key, attrs[key]);
+ }
+ }
+
+ // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+ // and a 'message' event listener attached. This wrapping method is used
+ // instead of attaching the event listeners directly to the <EMBED> element
+ // to ensure that the listeners are active before the NaCl module 'load'
+ // event fires.
+ var listenerDiv = $('listener');
+ listenerDiv.appendChild(moduleEl);
+}
+
+/**
+ * Add the default event listeners to the element with id "listener".
+ */
+function attachDefaultListeners() {
+ var listenerDiv = $('listener');
+ listenerDiv.addEventListener('load', moduleDidLoad, true);
+ listenerDiv.addEventListener('error', moduleLoadError, true);
+ listenerDiv.addEventListener('progress', moduleLoadProgress, true);
+ listenerDiv.addEventListener('crash', handleCrash, true);
+ attachListeners();
+}
+
+/**
+ * Called when the Browser can not communicate with the Module
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ *
+ * @param {Object} event
+ */
+function handleCrash(event) {
+ if (naclModule.exitStatus == -1) {
+ updateStatus('CRASHED');
+ } else {
+ updateStatus('EXITED [' + naclModule.exitStatus + ']');
+ }
+}
+
+/**
+ * Called when the NaCl module is loaded.
+ *
+ * This event listener is registered in attachDefaultListeners above.
+ */
+function moduleDidLoad() {
+ var bar = $('progress');
+ bar.value = 100;
+ bar.max = 100;
+ naclModule = $('nacl_module');
+ hideStatus();
+ setThreadCount();
+}
+
+/**
+ * Hide the status field and progress bar.
+ */
+function hideStatus() {
+ $('statusField').style.display = 'none';
+ $('progress').style.display = 'none';
+}
+
+/**
+ * Called when the plugin fails to load.
+ *
+ * @param {Object} event
+ */
+function moduleLoadError(event) {
+ updateStatus('Load failed.');
+}
+
+/**
+ * Called when the plugin reports progress events.
+ *
+ * @param {Object} event
+ */
+function moduleLoadProgress(event) {
+ $('progress').style.display = 'block';
+
+ var loadPercent = 0.0;
+ var bar = $('progress');
+ bar.max = 100;
+ if (event.lengthComputable && event.total > 0) {
+ loadPercent = event.loaded / event.total * 100.0;
+ } else {
+ // The total length is not yet known.
+ loadPercent = -1.0;
+ }
+ bar.value = loadPercent;
+}
+
+/**
+ * If the element with id 'statusField' exists, then set its HTML to the status
+ * message as well.
+ *
+ * @param {string} opt_message The message to set.
+ */
+function updateStatus(opt_message) {
+ var statusField = $('statusField');
+ if (statusField) {
+ statusField.style.display = 'block';
+ statusField.textContent = opt_message;
+ }
+}
+
+/**
+ * Send the current value of the element threadCount to the NaCl module.
+ *
+ * @param {number} threads The number of threads to use to render.
+ */
+function setThreadCount(threads) {
+ var value = parseInt($('threadCount').value);
+ naclModule.postMessage({'message': 'set_threads',
+ 'value': value});
+}
+
+/**
+ * Add event listeners after the NaCl module has loaded. These listeners will
+ * forward messages to the NaCl module via postMessage()
+ */
+function attachListeners() {
+ $('threadCount').addEventListener('change', setThreadCount);
+ $('drawPoints').addEventListener('click',
+ function() {
+ var checked = $('drawPoints').checked;
+ naclModule.postMessage({'message' : 'draw_points',
+ 'value' : checked});
+ });
+ $('drawInteriors').addEventListener('click',
+ function() {
+ var checked = $('drawInteriors').checked;
+ naclModule.postMessage({'message' : 'draw_interiors',
+ 'value' : checked});
+ });
+ $('pointRange').addEventListener('change',
+ function() {
+ var value = parseFloat($('pointRange').value);
+ naclModule.postMessage({'message' : 'set_points',
+ 'value' : value});
+ $('pointCount').textContent = value + ' points';
+ });
+}
+
+/**
+ * Listen for the DOM content to be loaded. This event is fired when parsing of
+ * the page's document has finished.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ updateStatus('Loading...');
+ if (!browserSupportsPNaCl()) {
+ updateStatus('Browser does not support PNaCl or PNaCl is disabled');
+ } else if (naclModule == null) {
+ createNaClModule('voronoi', 512, 512);
+ attachDefaultListeners();
+ } else {
+ // It's possible that the Native Client module onload event fired
+ // before the page's onload event. In this case, the status message
+ // will reflect 'SUCCESS', but won't be displayed. This call will
+ // display the current message.
+ updateStatus('Waiting.');
+ }
+});
diff --git a/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html
new file mode 100644
index 0000000000..f5167b0c8b
--- /dev/null
+++ b/native_client_sdk/src/gonacl_appengine/static/pnacl-demo-voronoi/index.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright (c) 2013 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.
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Voronoi</title>
+ <script type="text/javascript" src="example.js"></script>
+ <link href="/static/common.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+ <div class="absolute-fill">
+ <div class="flex-container">
+ <div class="main absolute-fill-parent">
+ <div class="absolute-fill">
+ <div class="flex-container flex-column flex-justify-center">
+ <div id="message">
+ <div id="statusField"></div>
+ <progress id="progress"></progress>
+ </div>
+ </div>
+ </div>
+ <div id="listener" class="absolute-fill"></div>
+ </div>
+ <div class="sidebar">
+ <h1>Voronoi</h1>
+ <p>
+ This demo renders the Voronoi diagram for a moving set of points using
+ a brute force technique.
+ </p>
+ <table id="config">
+ <tbody>
+ <tr>
+ <td class="name">Points:</td>
+ <td class="value">
+ <input type="range" id="pointRange"
+ min="1" max="1024" step="1" value="48">
+ <label id="pointCount">48 points</label>
+ </td>
+ </tr>
+ <tr>
+ <td class="name">Thread Count:</td>
+ <td class="value">
+ <select id="threadCount">
+ <option value="0">Main Thread only</option>
+ <option value="1">1 Thread</option>
+ <option value="2" selected="selected">2 Threads</option>
+ <option value="4">4 Threads</option>
+ <option value="6">6 Threads</option>
+ <option value="8">8 Threads</option>
+ <option value="12">12 Threads</option>
+ <option value="24">24 Threads</option>
+ <option value="32">32 Threads</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="name"><label for="drawPoints">Draw Points:</label></td>
+ <td class="value">
+ <input type="checkbox" id="drawPoints" checked="checked">
+ </td>
+ </tr>
+ <tr>
+ <td class="name">
+ <label for="drawInteriors">Draw Interiors:</label>
+ </td>
+ <td class="value">
+ <input type="checkbox" id="drawInteriors" checked="checked">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/native_client_sdk/src/libraries/nacl_io/include/poll.h b/native_client_sdk/src/libraries/nacl_io/include/poll.h
new file mode 100644
index 0000000000..553574d4cf
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/poll.h
@@ -0,0 +1,5 @@
+/* Copyright (c) 2013 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. */
+
+#include <sys/poll.h>
diff --git a/native_client_sdk/src/libraries/nacl_io/poll.h b/native_client_sdk/src/libraries/nacl_io/include/sys/poll.h
index 842d1ee7ab..17843447d6 100644
--- a/native_client_sdk/src/libraries/nacl_io/poll.h
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/poll.h
@@ -2,8 +2,8 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-#ifndef LIBRARIES_NACL_IO_POLL_H_
-#define LIBRARIES_NACL_IO_POLL_H_
+#ifndef LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_
+#define LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_
#include <stdint.h>
@@ -31,9 +31,8 @@ struct pollfd {
uint16_t revents;
};
-int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
+int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout);
EXTERN_C_END
-#endif /* LIBRARIES_NACL_IO_POLL_H_ */
-
+#endif /* LIBRARIES_NACL_IO_INCLUDE_SYS_POLL_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
index 6cb68faad2..566bf90215 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
@@ -145,6 +145,28 @@ Error KernelObject::SetCWD(const std::string& path) {
return 0;
}
+Error KernelObject::GetFDFlags(int fd, int* out_flags) {
+ AUTO_LOCK(handle_lock_);
+ if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+ return EBADF;
+
+ *out_flags = handle_map_[fd].flags;
+ return 0;
+}
+
+Error KernelObject::SetFDFlags(int fd, int flags) {
+ AUTO_LOCK(handle_lock_);
+ if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+ return EBADF;
+
+ // Only setting of FD_CLOEXEC is supported.
+ if (flags & ~FD_CLOEXEC)
+ return EINVAL;
+
+ handle_map_[fd].flags = flags;
+ return 0;
+}
+
Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
out_handle->reset(NULL);
@@ -152,7 +174,7 @@ Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
return EBADF;
- *out_handle = handle_map_[fd];
+ *out_handle = handle_map_[fd].handle;
if (out_handle) return 0;
return EBADF;
@@ -162,16 +184,18 @@ int KernelObject::AllocateFD(const ScopedKernelHandle& handle) {
AUTO_LOCK(handle_lock_);
int id;
+ Descriptor_t descriptor(handle);
+
// If we can recycle and FD, use that first
if (free_fds_.size()) {
id = free_fds_.front();
// Force lower numbered FD to be available first.
std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
free_fds_.pop_back();
- handle_map_[id] = handle;
+ handle_map_[id] = descriptor;
} else {
id = handle_map_.size();
- handle_map_.push_back(handle);
+ handle_map_.push_back(descriptor);
}
return id;
}
@@ -186,14 +210,14 @@ void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) {
if (fd >= (int)handle_map_.size())
handle_map_.resize(fd + 1);
- handle_map_[fd] = handle;
+ handle_map_[fd] = Descriptor_t(handle);
}
}
void KernelObject::FreeFD(int fd) {
AUTO_LOCK(handle_lock_);
- handle_map_[fd].reset(NULL);
+ handle_map_[fd].handle.reset(NULL);
free_fds_.push_back(fd);
// Force lower numbered FD to be available first.
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
index 0426f153a2..df6dba29d0 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -29,7 +29,14 @@ namespace nacl_io {
// All calls are assumed to be a relative path.
class KernelObject {
public:
- typedef std::vector<ScopedKernelHandle> HandleMap_t;
+ struct Descriptor_t {
+ Descriptor_t() : flags(0) {}
+ explicit Descriptor_t(const ScopedKernelHandle& h) : handle(h), flags(0) {}
+
+ ScopedKernelHandle handle;
+ int flags;
+ };
+ typedef std::vector<Descriptor_t> HandleMap_t;
typedef std::map<std::string, ScopedMount> MountMap_t;
KernelObject();
@@ -56,6 +63,11 @@ class KernelObject {
ScopedMount* out_mount,
ScopedMountNode* out_node);
+ // Get FD-specific flags (currently only FD_CLOEXEC is supported).
+ Error GetFDFlags(int fd, int* out_flags);
+ // Set FD-specific flags (currently only FD_CLOEXEC is supported).
+ Error SetFDFlags(int fd, int flags);
+
// Convert from FD to KernelHandle, and acquire the handle.
// Assumes |out_handle| is non-NULL.
Error AcquireHandle(int fd, ScopedKernelHandle* out_handle);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 38715ad978..1ae9e5b81f 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -648,8 +648,34 @@ int KernelProxy::fchmod(int fd, int mode) {
}
int KernelProxy::fcntl(int fd, int request, va_list args) {
+ Error error = 0;
+
+ // F_GETFD and F_SETFD are descirptor specific flags that
+ // are stored in the KernelObject's decriptor map unlink
+ // F_GETFL and F_SETFL which are handle specific.
+ switch (request) {
+ case F_GETFD: {
+ int rtn = -1;
+ error = GetFDFlags(fd, &rtn);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return rtn;
+ }
+ case F_SETFD: {
+ int flags = va_arg(args, int);
+ error = SetFDFlags(fd, flags);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+ }
+ }
+
ScopedKernelHandle handle;
- Error error = AcquireHandle(fd, &handle);
+ error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
@@ -1087,6 +1113,12 @@ int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
ScopedMountNode node(sock);
ScopedKernelHandle new_handle(new KernelHandle(stream_mount_, node));
+ error = sock->Init(O_RDWR);
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+
return AllocateFD(new_handle);
}
@@ -1419,6 +1451,12 @@ int KernelProxy::socket(int domain, int type, int protocol) {
}
ScopedKernelHandle handle(new KernelHandle(stream_mount_, node));
+ rtn = handle->Init(O_RDWR);
+ if (rtn != 0) {
+ errno = rtn;
+ return -1;
+ }
+
return AllocateFD(handle);
}
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 11660d1a25..53336e8506 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -219,6 +219,7 @@
"poll.h",
"sys/ioctl.h",
"sys/mount.h",
+ "sys/poll.h",
"sys/select.h",
"sys/signal.h",
"sys/socket.h",
@@ -237,6 +238,7 @@
"poll.h",
"sys/ioctl.h",
"sys/mount.h",
+ "sys/poll.h",
"sys/select.h",
"sys/signal.h",
"sys/socket.h",
@@ -248,6 +250,7 @@
{
'FILES': [
"poll.h",
+ "sys/poll.h",
],
'DEST': 'include/win',
},
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
index 12c5b9d1d5..1d8ac375d8 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
@@ -24,7 +24,9 @@ MountNodeSocket::MountNodeSocket(Mount* mount)
local_addr_(0),
remote_addr_(0),
socket_flags_(0),
- last_errno_(0) {
+ last_errno_(0),
+ keep_alive_(false) {
+ memset(&linger_, 0, sizeof(linger_));
SetType(S_IFSOCK);
}
@@ -34,7 +36,9 @@ MountNodeSocket::MountNodeSocket(Mount* mount, PP_Resource socket)
local_addr_(0),
remote_addr_(0),
socket_flags_(0),
- last_errno_(0) {
+ last_errno_(0),
+ keep_alive_(false) {
+ memset(&linger_, 0, sizeof(linger_));
SetType(S_IFSOCK);
mount_->ppapi()->AddRefResource(socket_resource_);
}
@@ -222,26 +226,41 @@ Error MountNodeSocket::GetSockOpt(int lvl,
if (lvl != SOL_SOCKET)
return ENOPROTOOPT;
+ int value = 0;
+ socklen_t value_len = 0;
+ void* value_ptr = NULL;
+
switch (optname) {
- case SO_REUSEADDR: {
- // SO_REUSEADDR is effectivly always on since we can't
+ case SO_REUSEADDR:
+ // SO_REUSEADDR is effectively always on since we can't
// disable it with PPAPI sockets.
- int value = 1;
- int copy_bytes = std::min(sizeof(int), *len);
- memcpy(optval, &value, copy_bytes);
- *len = sizeof(int);
- return 0;
- }
- case SO_ERROR: {
- int copy_bytes = std::min(sizeof(int), *len);
- memcpy(optval, &last_errno_, copy_bytes);
- *len = sizeof(int);
+ value = 1;
+ value_ptr = &value;
+ value_len = sizeof(value);
+ break;
+ case SO_LINGER:
+ value_ptr = &linger_;
+ value_len = sizeof(linger_);
+ break;
+ case SO_KEEPALIVE:
+ value = keep_alive_;
+ value_ptr = &value;
+ value_len = sizeof(value);
+ break;
+ case SO_ERROR:
+ value_ptr = &last_errno_;
+ value_len = sizeof(last_errno_);
last_errno_ = 0;
- return 0;
- }
+ break;
+ default:
+ return ENOPROTOOPT;
}
- return ENOPROTOOPT;
+
+ int copy_bytes = std::min(value_len, *len);
+ memcpy(optval, value_ptr, copy_bytes);
+ *len = value_len;
+ return 0;
}
Error MountNodeSocket::SetSockOpt(int lvl,
@@ -256,6 +275,32 @@ Error MountNodeSocket::SetSockOpt(int lvl,
// SO_REUSEADDR is effectivly always on since we can't
// disable it with PPAPI sockets. Just return success
// here regardless.
+ if (len < sizeof(int))
+ return EINVAL;
+ return 0;
+ }
+ case SO_LINGER: {
+ // Not supported by the PPAPI interface but we preserve
+ // the settings and pretend to support it.
+ if (len < sizeof(struct linger))
+ return EINVAL;
+ struct linger new_linger = *static_cast<const linger*>(optval);
+ // Don't allow setting linger to be enabled until we
+ // implement the required synchronous shutdown()/close().
+ // TODO(sbc): remove this after http://crbug.com/312401
+ // gets fixed.
+ if (new_linger.l_onoff != 0)
+ return EINVAL;
+ linger_ = new_linger;
+ return 0;
+ }
+ case SO_KEEPALIVE: {
+ // Not supported by the PPAPI interface but we preserve
+ // the flag and pretend to support it.
+ if (len < sizeof(int))
+ return EINVAL;
+ int value = *static_cast<const int*>(optval);
+ keep_alive_ = value != 0;
return 0;
}
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
index 900247f82b..3ecb3db300 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
@@ -157,6 +157,8 @@ class MountNodeSocket : public MountNodeStream {
PP_Resource remote_addr_;
uint32_t socket_flags_;
int last_errno_;
+ bool keep_alive_;
+ struct linger linger_;
friend class KernelProxy;
friend class MountStream;
diff --git a/native_client_sdk/src/resources/manifest.json.template b/native_client_sdk/src/resources/manifest.json.template
index e7e97609fe..31882ce3eb 100644
--- a/native_client_sdk/src/resources/manifest.json.template
+++ b/native_client_sdk/src/resources/manifest.json.template
@@ -1,6 +1,7 @@
{
"name": "{{name}}",
"version": "{{version}}",
+ "minimum_chrome_version": "{{version}}",
"manifest_version": 2,
"description": "{{description}}",
"offline_enabled": true,
@@ -16,7 +17,13 @@
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMN716Qyu0l2EHNFqIJVqVysFcTR6urqhaGGqW4UK7slBaURz9+Sb1b4Ot5P1uQNE5c+CTU5Vu61wpqmSqMMxqHLWdPPMh8uRlyctsb2cxWwG6XoGSvpX29NsQVUFXd4v2tkJm3G9t+V0X8TYskrvWQmnyOW8OEIDvrBhUEfFxWQIDAQAB",
[[]]
"oauth2": {
+[[if channel == 'Dev':]]
+ "client_id": "903965034255-q5lhuqj5eefbatdfif3gv0mdbo0a86pr.apps.googleusercontent.com",
+[[elif channel == 'Beta':]]
+ "client_id": "903965034255-gp3p4hqr1bd7a1v0etf6icdlu5rets1p.apps.googleusercontent.com",
+[[else:]]
"client_id": "903965034255.apps.googleusercontent.com",
+[[]]
"scopes": ["https://www.googleapis.com/auth/drive"]
},
"permissions": {{permissions}}
diff --git a/native_client_sdk/src/resources/screenshot_earth_1280.png b/native_client_sdk/src/resources/screenshot_earth_1280.png
new file mode 100644
index 0000000000..912c0b3231
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_earth_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_gles_1280.png b/native_client_sdk/src/resources/screenshot_gles_1280.png
deleted file mode 100644
index 853a6bc2f8..0000000000
--- a/native_client_sdk/src/resources/screenshot_gles_1280.png
+++ /dev/null
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_graphics2d_1280.png b/native_client_sdk/src/resources/screenshot_graphics2d_1280.png
new file mode 100644
index 0000000000..44ac44f1ab
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_graphics2d_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_graphics3d_1280.png b/native_client_sdk/src/resources/screenshot_graphics3d_1280.png
new file mode 100644
index 0000000000..ee0308727b
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_graphics3d_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_life_1280.png b/native_client_sdk/src/resources/screenshot_life_1280.png
new file mode 100644
index 0000000000..4a14e9b9fd
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_life_1280.png
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_pi_1280.png b/native_client_sdk/src/resources/screenshot_pi_1280.png
deleted file mode 100644
index 4dad188131..0000000000
--- a/native_client_sdk/src/resources/screenshot_pi_1280.png
+++ /dev/null
Binary files differ
diff --git a/native_client_sdk/src/resources/screenshot_voronoi_1280.png b/native_client_sdk/src/resources/screenshot_voronoi_1280.png
new file mode 100644
index 0000000000..1638ac7467
--- /dev/null
+++ b/native_client_sdk/src/resources/screenshot_voronoi_1280.png
Binary files differ
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
index 579337a70a..f0079da354 100644
--- a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
@@ -281,13 +281,14 @@ TEST_F(SocketTestWithServer, TCPConnect) {
IP4ToSockAddr(LOCAL_HOST, PORT1, &addr);
ASSERT_EQ(0, connect(sock_, (sockaddr*) &addr, addrlen))
- << "Failed with " << errno << ": " << strerror(errno) << "\n";
+ << "Failed with " << errno << ": " << strerror(errno) << "\n";
// Send two different messages to the echo server and verify the
// response matches.
strcpy(outbuf, "hello");
memset(inbuf, 0, sizeof(inbuf));
- ASSERT_EQ(sizeof(outbuf), write(sock_, outbuf, sizeof(outbuf)));
+ ASSERT_EQ(sizeof(outbuf), write(sock_, outbuf, sizeof(outbuf)))
+ << "socket write failed with: " << strerror(errno);
ASSERT_EQ(sizeof(outbuf), read(sock_, inbuf, sizeof(inbuf)));
EXPECT_EQ(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
@@ -340,11 +341,6 @@ TEST_F(SocketTest, Getsockopt) {
ASSERT_EQ(0, socket_error);
ASSERT_EQ(sizeof(socket_error), len);
- int reuse = 0;
- len = sizeof(reuse);
- ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &reuse, &len));
- ASSERT_EQ(1, reuse);
-
// Test for an invalid option (-1)
ASSERT_EQ(-1, getsockopt(sock1_, SOL_SOCKET, -1, &socket_error, &len));
ASSERT_EQ(ENOPROTOOPT, errno);
@@ -360,9 +356,72 @@ TEST_F(SocketTest, Setsockopt) {
ASSERT_EQ(-1, setsockopt(sock1_, SOL_SOCKET, SO_ERROR, &socket_error, len));
ASSERT_EQ(ENOPROTOOPT, errno);
- int reuse = 1;
- len = sizeof(reuse);
- ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &reuse, len));
+}
+
+TEST_F(SocketTest, Sockopt_KEEPALIVE) {
+ sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_GT(sock1_, -1);
+ sock2_ = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_GT(sock2_, -1);
+
+ int value = 0;
+ socklen_t len = sizeof(value);
+ ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_KEEPALIVE, &value, &len));
+ ASSERT_EQ(0, value);
+ ASSERT_EQ(sizeof(int), len);
+}
+
+// Disabled until we support SO_LINGER (i.e. syncronouse close()/shutdown())
+// TODO(sbc): re-enable once we fix http://crbug.com/312401
+TEST_F(SocketTest, DISABLED_Sockopt_LINGER) {
+ sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT_GT(sock1_, -1);
+ sock2_ = socket(AF_INET, SOCK_DGRAM, 0);
+ ASSERT_GT(sock2_, -1);
+
+ struct linger linger = { 7, 8 };
+ socklen_t len = sizeof(linger);
+ ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, &len));
+ ASSERT_EQ(0, linger.l_onoff);
+ ASSERT_EQ(0, linger.l_linger);
+ ASSERT_EQ(sizeof(struct linger), len);
+ ASSERT_EQ(0, getsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, &len));
+ ASSERT_EQ(0, linger.l_onoff);
+ ASSERT_EQ(0, linger.l_linger);
+ ASSERT_EQ(sizeof(struct linger), len);
+
+ linger.l_onoff = 1;
+ linger.l_linger = 77;
+ len = sizeof(linger);
+ ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, len));
+ linger.l_onoff = 1;
+ linger.l_linger = 88;
+ ASSERT_EQ(0, setsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, len));
+
+ len = sizeof(linger);
+ ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_LINGER, &linger, &len));
+ ASSERT_EQ(1, linger.l_onoff);
+ ASSERT_EQ(77, linger.l_linger);
+ ASSERT_EQ(sizeof(struct linger), len);
+ ASSERT_EQ(0, getsockopt(sock2_, SOL_SOCKET, SO_LINGER, &linger, &len));
+ ASSERT_EQ(1, linger.l_onoff);
+ ASSERT_EQ(88, linger.l_linger);
+ ASSERT_EQ(sizeof(struct linger), len);
+}
+
+TEST_F(SocketTest, Sockopt_REUSEADDR) {
+ int value = 1;
+ socklen_t len = sizeof(value);
+ sock1_ = socket(AF_INET, SOCK_STREAM, 0);
+
+ ASSERT_GT(sock1_, -1);
+ ASSERT_EQ(0, setsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &value, len));
+
+ value = 0;
+ len = sizeof(value);
+ ASSERT_EQ(0, getsockopt(sock1_, SOL_SOCKET, SO_REUSEADDR, &value, &len));
+ ASSERT_EQ(1, value);
+ ASSERT_EQ(sizeof(int), len);
}
// The size of the data to send is deliberately chosen to be
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
index a7ea159a62..5c0a772775 100644
--- a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
@@ -71,6 +71,39 @@ class KernelProxyTest : public ::testing::Test {
} // namespace
+static int ki_fcntl_wrapper(int fd, int request, ...) {
+ va_list ap;
+ va_start(ap, request);
+ int rtn = ki_fcntl(fd, request, ap);
+ va_end(ap);
+ return rtn;
+}
+
+/**
+ * Test for fcntl commands F_SETFD and F_GETFD. This
+ * is tested here rather than in the mount_node tests
+ * since the fd flags are not stored in the kernel_handle
+ * or the mount node but directly in the FD mapping.
+ */
+TEST_F(KernelProxyTest, Fcntl_GETFD) {
+ int fd = ki_open("/test", O_RDWR | O_CREAT);
+ ASSERT_NE(-1, fd);
+
+ // FD flags should start as zero.
+ ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
+
+ // Check that setting FD_CLOEXEC works
+ int flags = FD_CLOEXEC;
+ ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
+ << "fcntl failed with: " << strerror(errno);
+ ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
+
+ // Check that setting invalid flag causes EINVAL
+ flags = FD_CLOEXEC + 1;
+ ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
+ ASSERT_EQ(EINVAL, errno);
+}
+
TEST_F(KernelProxyTest, FileLeak) {
const size_t buffer_size = 1024;
char filename[128];
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
index 666b104ae0..751e9fea60 100644
--- a/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
@@ -161,13 +161,16 @@ TEST(MountNodeTest, FTruncate) {
EXPECT_EQ(0, memcmp(buffer, data, 100));
}
-TEST(MountNodeTest, Fcntl) {
+TEST(MountNodeTest, Fcntl_GETFL) {
MockNode* node = new MockNode();
ScopedMount mnt(new MockMount());
ScopedMountNode file(node);
KernelHandle handle(mnt, file);
ASSERT_EQ(0, handle.Init(O_CREAT | O_APPEND));
+ // Test invalid fcntl command.
+ ASSERT_EQ(ENOSYS, handle.Fcntl(-1, NULL));
+
// Test F_GETFL
ASSERT_EQ(0, node->Init(0));
int flags = 0;
diff --git a/native_client_sdk/src/tools/nacl_llvm.mk b/native_client_sdk/src/tools/nacl_llvm.mk
index 6ed84dd01b..a3df27102e 100644
--- a/native_client_sdk/src/tools/nacl_llvm.mk
+++ b/native_client_sdk/src/tools/nacl_llvm.mk
@@ -130,11 +130,6 @@ endef
# using the finalizing to a .pexe. This enables debugging.
#
define LINK_RULE
-ifeq ($(CONFIG),Debug)
-EXECUTABLES=$(OUTDIR)/$(1)_x86_32.nexe $(OUTDIR)/$(1)_x86_64.nexe $(OUTDIR)/$(1)_arm.nexe
-else
-EXECUTABLES=$(OUTDIR)/$(1).pexe
-endif
$(call LINKER_RULE,$(OUTDIR)/$(1),$(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_pnacl)),$(filter-out pthread,$(3)),$(4),$(LIB_PATHS),$(5))
endef
@@ -170,6 +165,12 @@ endef
#
NMF:=python $(NACL_SDK_ROOT)/tools/create_nmf.py
+ifeq ($(CONFIG),Debug)
+EXECUTABLES=$(OUTDIR)/$(1)_x86_32.nexe $(OUTDIR)/$(1)_x86_64.nexe $(OUTDIR)/$(1)_arm.nexe
+else
+EXECUTABLES=$(OUTDIR)/$(1).pexe
+endif
+
define NMF_RULE
all: $(OUTDIR)/$(1).nmf
$(OUTDIR)/$(1).nmf: $(EXECUTABLES)
diff --git a/native_client_sdk/src/tools/sel_ldr.py b/native_client_sdk/src/tools/sel_ldr.py
index e500192d17..d730ffbe71 100755
--- a/native_client_sdk/src/tools/sel_ldr.py
+++ b/native_client_sdk/src/tools/sel_ldr.py
@@ -59,8 +59,6 @@ def main(argv):
raise Error('not a file: %s' % nexe)
arch, dynamic = create_nmf.ParseElfHeader(nexe)
- if osname == 'mac' and arch == 'x86-64':
- raise Error('Running of x86-64 executables is not supported on mac')
if arch == 'arm':
raise Error('Cannot run ARM executables under sel_ldr')