Chrome's Native Client backend implementation
authorGabriel Jacobo <gabomdq@gmail.com>
Fri, 06 Jun 2014 15:45:59 -0300
changeset 8833 ae720d61d14d
parent 8832 408b0d563b27
child 8834 b300e097899d
Chrome's Native Client backend implementation
README-nacl.txt
WhatsNew.txt
build-scripts/config.sub
build-scripts/naclbuild.sh
configure
configure.in
include/SDL_assert.h
include/SDL_config.h.in
include/SDL_main.h
include/SDL_platform.h
include/SDL_rwops.h
src/SDL_log.c
src/audio/SDL_audio.c
src/audio/nacl/SDL_naclaudio.c
src/audio/nacl/SDL_naclaudio.h
src/dynapi/SDL_dynapi.h
src/file/SDL_rwops.c
src/main/nacl/SDL_nacl_main.c
src/render/opengles2/SDL_gles2funcs.h
src/thread/pthread/SDL_systhread.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/nacl/SDL_naclevents.c
src/video/nacl/SDL_naclevents_c.h
src/video/nacl/SDL_naclglue.c
src/video/nacl/SDL_naclopengles.c
src/video/nacl/SDL_naclopengles.h
src/video/nacl/SDL_naclvideo.c
src/video/nacl/SDL_naclvideo.h
src/video/nacl/SDL_naclwindow.c
src/video/nacl/SDL_naclwindow.h
test/nacl/background.js
test/nacl/common.js
test/nacl/index.html
test/nacl/manifest.json
test/testgles2.c
test/testrendercopyex.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README-nacl.txt	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,60 @@
+================================================================================
+Simple DirectMedia Layer for Native Client
+================================================================================
+
+Requirements: 
+    
+    * Native Client SDK (https://developer.chrome.com/native-client), 
+      (tested with Pepper version 33 or higher).
+
+The SDL backend for Chrome's Native Client has been tested only with the PNaCl
+toolchain, which generates binaries designed to run on ARM and x86_32/64 
+platforms. This does not mean it won't work with the other toolchains!
+
+================================================================================
+Building SDL for NaCl
+================================================================================
+
+Set up the right environment variables (see naclbuild.sh), then configure SDL with:
+
+    configure --host=pnacl --prefix some/install/destination
+    
+Then "make". 
+
+As an example of how to create a deployable app a Makefile project is provided 
+in test/nacl/Makefile, which includes some monkey patching of the common.mk file 
+provided by NaCl, without which linking properly to SDL won't work (the search 
+path can't be modified externally, so the linker won't find SDL's binaries unless 
+you dump them into the SDK path, which is inconvenient).
+Also provided in test/nacl is the required support file, such as index.html, 
+manifest.json, etc.
+
+
+================================================================================
+Running tests
+================================================================================
+
+Due to the nature of NaCl programs, building and running SDL tests is not as
+straightforward as one would hope. The script naclbuild.sh in build-scripts 
+automates the process and should serve as a guide for users of SDL trying to build 
+their own applications.
+
+Basic usage:
+    
+    ./naclbuild.sh path/to/pepper/toolchain (i.e. ~/naclsdk/pepper_35)
+    
+This will build testgles2.c by default.
+
+If you want to build a different test, for example testrendercopyex.c:
+    
+    SOURCES=~/sdl/SDL/test/testrendercopyex.c ./naclbuild.sh ~/naclsdk/pepper_35
+    
+Once the build finishes, you have to serve the contents with a web server (the
+script will give you instructions on how to do that with Python).
+
+================================================================================
+TODO - Known Issues
+================================================================================
+* Audio backend is not usable yet.
+* Testing of all systems with a real application (something other than SDL's tests)
+
--- a/WhatsNew.txt	Thu Jun 05 15:37:33 2014 -0700
+++ b/WhatsNew.txt	Fri Jun 06 15:45:59 2014 -0300
@@ -9,6 +9,7 @@
 * Added an event SDL_RENDER_DEVICE_RESET that is sent from the D3D renderers 
   when the D3D device is lost, and from Android's event loop when the GLES
   context had to be re created.
+* Native Client backend
 
 ---------------------------------------------------------------------------
 2.0.3:
--- a/build-scripts/config.sub	Thu Jun 05 15:37:33 2014 -0700
+++ b/build-scripts/config.sub	Fri Jun 06 15:45:59 2014 -0300
@@ -359,6 +359,19 @@
 	i*86 | x86_64)
 	  basic_machine=$basic_machine-pc
 	  ;;
+	nacl64*)
+		basic_machine=x86_64-pc
+		os=-nacl
+		;;
+	nacl*)
+		basic_machine=i686-pc
+		os=-nacl
+		;;
+    pnacl*)
+        # le32-unknown-pnacl comes from http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi
+        basic_machine=le32-unknown
+        os=-pnacl
+        ;;
 	# Object if more than one company name word.
 	*-*-*)
 		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
@@ -843,6 +856,10 @@
 		basic_machine=le32-unknown
 		os=-nacl
 		;;
+    pnacl)
+        basic_machine=le32-unknown
+        os=-pnacl
+        ;;
 	ncr3000)
 		basic_machine=i486-ncr
 		os=-sysv4
@@ -1384,6 +1401,12 @@
 			;;
 		esac
 		;;
+	-nacl*)
+		os=-nacl
+		;;
+    -pnacl*)
+        os=-pnacl
+        ;;
 	-nto-qnx*)
 		;;
 	-nto*)
@@ -1506,6 +1529,10 @@
 		os=-dicos
 		;;
 	-nacl*)
+        os=-nacl
+        ;;
+	-pnacl*)
+        os=-pnacl
 		;;
 	-none)
 		;;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build-scripts/naclbuild.sh	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,105 @@
+#!/bin/bash
+if [ -z "$1" ] && [ -z "$NACL_SDK_ROOT" ]; then
+    echo "Usage: ./naclbuild ~/nacl/pepper_33"
+    echo "This will build SDL for Native Client, and testgles2.c as a demo"
+    echo "You can set env vars CC, AR, LD and RANLIB to override the default PNaCl toolchain used"
+    echo "You can set env var SOURCES to select a different source file than testgles2.c"
+    exit 1
+fi
+
+if [ -n "$1" ]; then
+    NACL_SDK_ROOT="$1"
+fi
+
+CC=""
+
+if [ -n "$2" ]; then
+    CC="$2"
+fi
+
+echo "Using SDK at $NACL_SDK_ROOT"
+
+export NACL_SDK_ROOT="$NACL_SDK_ROOT"
+export CFLAGS="$CFLAGS -I$NACL_SDK_ROOT/include"
+
+NCPUS="1"
+case "$OSTYPE" in
+    darwin*)
+        NCPU=`sysctl -n hw.ncpu`
+        ;; 
+    linux*)
+        if [ -n `which nproc` ]; then
+            NCPUS=`nproc`
+        fi  
+        ;;
+  *);;
+esac
+
+CURDIR=`pwd -P`
+SDLPATH="$( cd "$(dirname "$0")/.." ; pwd -P )"
+BUILDPATH="$SDLPATH/build/nacl"
+TESTBUILDPATH="$BUILDPATH/test"
+SDL2_STATIC="$BUILDPATH/build/.libs/libSDL2.a"
+mkdir -p $BUILDPATH
+mkdir -p $TESTBUILDPATH
+
+if [ -z "$CC" ]; then
+    export CC="$NACL_SDK_ROOT/toolchain/linux_pnacl/bin/pnacl-clang"
+fi
+if [ -z "$AR" ]; then
+    export AR="$NACL_SDK_ROOT/toolchain/linux_pnacl/bin/pnacl-ar"
+fi
+if [ -z "$LD" ]; then
+    export LD="$NACL_SDK_ROOT/toolchain/linux_pnacl/bin/pnacl-ar"
+fi
+if [ -z "$RANLIB" ]; then
+    export RANLIB="$NACL_SDK_ROOT/toolchain/linux_pnacl/bin/pnacl-ranlib"
+fi
+
+if [ -z "$SOURCES" ]; then
+    export SOURCES="$SDLPATH/test/testgles2.c"
+fi
+
+if [ ! -f "$CC" ]; then
+    echo "Could not find compiler at $CC"
+    exit 1
+fi
+
+
+
+
+cd $BUILDPATH
+$SDLPATH/configure --host=pnacl --prefix $TESTBUILDPATH
+make -j$NCPUS CFLAGS="$CFLAGS -I./include"
+make install
+
+if [ ! -f "$SDL2_STATIC" ]; then
+    echo "Build failed! $SDL2_STATIC"
+    exit 1
+fi
+
+echo "Building test"
+cp -f $SDLPATH/test/nacl/* $TESTBUILDPATH
+# Some tests need these resource files
+cp -f $SDLPATH/test/*.bmp $TESTBUILDPATH
+cp -f $SDLPATH/test/*.wav $TESTBUILDPATH
+cp -f $SDL2_STATIC $TESTBUILDPATH
+
+# Copy user sources
+_SOURCES=($SOURCES)
+for src in "${_SOURCES[@]}"
+do
+    cp $src $TESTBUILDPATH
+done
+export SOURCES="$SOURCES"
+
+cd $TESTBUILDPATH
+make -j$NCPUS CONFIG="Release" CFLAGS="$CFLAGS -I$TESTBUILDPATH/include/SDL2 -I$SDLPATH/include"
+make -j$NCPUS CONFIG="Debug" CFLAGS="$CFLAGS -I$TESTBUILDPATH/include/SDL2 -I$SDLPATH/include"
+
+echo
+echo "Run the test with: "
+echo "cd $TESTBUILDPATH;python -m SimpleHTTPServer"
+echo "Then visit http://localhost:8000 with Chrome"
+
+cd $CURDIR
--- a/configure	Thu Jun 05 15:37:33 2014 -0700
+++ b/configure	Fri Jun 06 15:45:59 2014 -0300
@@ -18984,6 +18984,55 @@
     fi
 }
 
+CheckNativeClient()
+{
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+          #if !defined(__native_client__)
+          #error "NO NACL"
+          #endif
+
+int
+main ()
+{
+
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+        $as_echo "#define SDL_VIDEO_DRIVER_NACL 1" >>confdefs.h
+
+        $as_echo "#define SDL_AUDIO_DRIVER_NACL 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_POW 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_OPENGLES2 1" >>confdefs.h
+
+
+$as_echo "#define SDL_VIDEO_OPENGL_ES2 1" >>confdefs.h
+
+
+$as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h
+
+
+        SDL_LIBS="-lppapi_simple -lppapi_gles2 $SDL_LIBS"
+
+        SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.c"
+        SOURCES="$SOURCES $srcdir/src/audio/nacl/*.c"
+        SUMMARY_audio="${SUMMARY_audio} nacl"
+        SOURCES="$SOURCES $srcdir/src/video/nacl/*.c"
+        SUMMARY_video="${SUMMARY_video} nacl opengles2"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+
 
 CheckX11()
 {
@@ -23156,6 +23205,21 @@
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
         fi
         ;;
+    *-nacl|*-pnacl)
+        ARCH=nacl
+        CheckNativeClient
+        CheckDummyAudio
+        CheckDummyVideo
+        CheckInputEvents
+        # Set up files for the timer library
+        if test x$enable_timers = xyes; then
+            $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
+
+            SOURCES="$SOURCES $srcdir/src/timer/unix/*.c"
+            have_timers=yes
+        fi
+        CheckPTHREAD
+        ;;
     *)
         as_fn_error $? "
 *** Unsupported host:  Please add to configure.in
--- a/configure.in	Thu Jun 05 15:37:33 2014 -0700
+++ b/configure.in	Fri Jun 06 15:45:59 2014 -0300
@@ -1317,6 +1317,32 @@
     fi
 }
 
+dnl Check for Native Client stuff
+CheckNativeClient()
+{
+        AC_TRY_COMPILE([
+          #if !defined(__native_client__)
+          #error "NO NACL"
+          #endif
+        ],[
+        ],[
+        AC_DEFINE(SDL_VIDEO_DRIVER_NACL)
+        AC_DEFINE(SDL_AUDIO_DRIVER_NACL)
+        AC_DEFINE(HAVE_POW, 1, [ ])
+        AC_DEFINE(HAVE_OPENGLES2, 1, [ ])
+        AC_DEFINE(SDL_VIDEO_OPENGL_ES2, 1, [ ])
+        AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES2, 1, [ ])
+
+        SDL_LIBS="-lppapi_simple -lppapi_gles2 $SDL_LIBS"
+
+        SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.c"
+        SOURCES="$SOURCES $srcdir/src/audio/nacl/*.c"
+        SUMMARY_audio="${SUMMARY_audio} nacl"
+        SOURCES="$SOURCES $srcdir/src/video/nacl/*.c"
+        SUMMARY_video="${SUMMARY_video} nacl opengles2"
+        ])
+}
+
 
 dnl Find the X11 include and library directories
 CheckX11()
@@ -3119,6 +3145,20 @@
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
         fi
         ;;
+    *-nacl|*-pnacl)
+        ARCH=nacl
+        CheckNativeClient
+        CheckDummyAudio
+        CheckDummyVideo
+        CheckInputEvents
+        # Set up files for the timer library
+        if test x$enable_timers = xyes; then
+            AC_DEFINE(SDL_TIMER_UNIX)
+            SOURCES="$SOURCES $srcdir/src/timer/unix/*.c"
+            have_timers=yes
+        fi
+        CheckPTHREAD      
+        ;;
     *)
         AC_MSG_ERROR([
 *** Unsupported host:  Please add to configure.in
--- a/include/SDL_assert.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/include/SDL_assert.h	Fri Jun 06 15:45:59 2014 -0300
@@ -51,7 +51,7 @@
 /* Don't include intrin.h here because it contains C++ code */
     extern void __cdecl __debugbreak(void);
     #define SDL_TriggerBreakpoint() __debugbreak()
-#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
+#elif (!defined(__NACL__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
 #elif defined(HAVE_SIGNAL_H)
     #include <signal.h>
--- a/include/SDL_config.h.in	Thu Jun 05 15:37:33 2014 -0700
+++ b/include/SDL_config.h.in	Fri Jun 06 15:45:59 2014 -0300
@@ -208,6 +208,7 @@
 #undef SDL_AUDIO_DRIVER_DSOUND
 #undef SDL_AUDIO_DRIVER_ESD
 #undef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+#undef SDL_AUDIO_DRIVER_NACL
 #undef SDL_AUDIO_DRIVER_NAS
 #undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
 #undef SDL_AUDIO_DRIVER_SNDIO
@@ -297,6 +298,7 @@
 #undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32
 #undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY
 #undef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
+#undef SDL_VIDEO_DRIVER_NACL
 
 #undef SDL_VIDEO_RENDER_D3D
 #undef SDL_VIDEO_RENDER_D3D11
--- a/include/SDL_main.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/include/SDL_main.h	Fri Jun 06 15:45:59 2014 -0300
@@ -67,6 +67,15 @@
  */
 #define SDL_MAIN_NEEDED
 
+#elif defined(__NACL__)
+/* On NACL we use ppapi_simple to set up the application helper code,
+   then wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before 
+   starting the user main function.
+   All user code is run in a separate thread by ppapi_simple, thus 
+   allowing for blocking io to take place via nacl_io
+*/
+#define SDL_MAIN_NEEDED
+
 #endif
 #endif /* SDL_MAIN_HANDLED */
 
--- a/include/SDL_platform.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/include/SDL_platform.h	Fri Jun 06 15:45:59 2014 -0300
@@ -56,7 +56,7 @@
 #undef __IRIX__
 #define __IRIX__    1
 #endif
-#if defined(linux) || defined(__linux) || defined(__linux__)
+#if (defined(linux) || defined(__linux) || defined(__linux__))
 #undef __LINUX__
 #define __LINUX__   1
 #endif
@@ -142,6 +142,23 @@
 #define __PSP__ 1
 #endif
 
+/* The NACL compiler defines __native_client__ and __pnacl__
+ * Ref: http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi
+ */
+#if defined(__native_client__)
+#undef __LINUX__
+#undef __NACL__
+#define __NACL__ 1
+#endif
+#if defined(__pnacl__)
+#undef __LINUX__
+#undef __PNACL__
+#define __PNACL__ 1
+/* PNACL with newlib supports static linking only */
+#define __SDL_NOGETPROCADDR__
+#endif
+
+
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
--- a/include/SDL_rwops.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/include/SDL_rwops.h	Fri Jun 06 15:45:59 2014 -0300
@@ -220,6 +220,16 @@
 extern DECLSPEC size_t SDLCALL SDL_WriteBE64(SDL_RWops * dst, Uint64 value);
 /* @} *//* Write endian functions */
 
+/**
+ *  \name Mount/umount functions
+ *
+ *  Required for RWOps on Native Client
+ */
+/* @{ */
+extern DECLSPEC int SDLCALL SDL_RWMount(const char* source, const char* target, 
+                                        const char* filesystemtype, 
+                                        unsigned long mountflags, const void *data);
+extern DECLSPEC int SDLCALL SDL_RWUmount(const char *target);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
--- a/src/SDL_log.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/SDL_log.c	Fri Jun 06 15:45:59 2014 -0300
@@ -413,6 +413,9 @@
 #endif
 #if HAVE_STDIO_H
     fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
+#if __NACL__
+    fflush(stderr);
+#endif
 #endif
 }
 
--- a/src/audio/SDL_audio.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/audio/SDL_audio.c	Fri Jun 06 15:45:59 2014 -0300
@@ -51,6 +51,9 @@
 extern AudioBootStrap SUNAUDIO_bootstrap;
 extern AudioBootStrap ARTS_bootstrap;
 extern AudioBootStrap ESD_bootstrap;
+#if SDL_AUDIO_DRIVER_NACL
+extern AudioBootStrap NACLAUD_bootstrap;
+#endif
 extern AudioBootStrap NAS_bootstrap;
 extern AudioBootStrap XAUDIO2_bootstrap;
 extern AudioBootStrap DSOUND_bootstrap;
@@ -69,6 +72,7 @@
 extern AudioBootStrap PSPAUD_bootstrap;
 extern AudioBootStrap SNDIO_bootstrap;
 
+
 /* Available audio drivers */
 static const AudioBootStrap *const bootstrap[] = {
 #if SDL_AUDIO_DRIVER_PULSEAUDIO
@@ -98,6 +102,9 @@
 #if SDL_AUDIO_DRIVER_ESD
     &ESD_bootstrap,
 #endif
+#if SDL_AUDIO_DRIVER_NACL
+   &NACLAUD_bootstrap,
+#endif
 #if SDL_AUDIO_DRIVER_NAS
     &NAS_bootstrap,
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audio/nacl/SDL_naclaudio.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,135 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+#include "SDL_naclaudio.h"
+
+#include "SDL_audio.h"
+#include "SDL_mutex.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_event.h"
+
+/* The tag name used by NACL audio */
+#define NACLAUD_DRIVER_NAME         "nacl"
+
+#define SAMPLE_FRAME_COUNT 4096
+
+/* Audio driver functions */
+static int NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture);
+static void NACLAUD_CloseDevice(_THIS);
+static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
+
+/* FIXME: Make use of latency if needed */
+static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
+    SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
+    
+    SDL_LockMutex(private->mutex);
+    /*if (private->opened) {*/
+    SDL_memset(samples, _this->spec.silence, buffer_size);
+    SDL_LockMutex(_this->mixer_lock);
+    (*_this->spec.callback)(_this->spec.userdata, (Uint8*)samples, buffer_size);
+    SDL_UnlockMutex(_this->mixer_lock);
+    /*} else {
+        SDL_memset(samples, 0, buffer_size);
+    }*/
+    SDL_UnlockMutex(private->mutex);
+    
+    return;
+}
+
+static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
+    const PPB_Core *core = PSInterfaceCore();
+    const PPB_Audio *ppb_audio = PSInterfaceAudio();
+    SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
+    
+    ppb_audio->StopPlayback(hidden->audio);
+    SDL_DestroyMutex(hidden->mutex);
+    core->ReleaseResource(hidden->audio);
+}
+
+static int
+NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture) {
+    PP_Instance instance = PSGetInstanceId();
+    const PPB_Audio *ppb_audio = PSInterfaceAudio();
+    const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
+    
+    private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
+    if (private == NULL) {
+        SDL_OutOfMemory();
+        return 0;
+    }
+    
+    private->mutex = SDL_CreateMutex();
+    _this->spec.freq = 44100;
+    _this->spec.format = AUDIO_S16LSB;
+    _this->spec.channels = 2;
+    _this->spec.samples = ppb_audiocfg->RecommendSampleFrameCount(
+        instance, 
+        PP_AUDIOSAMPLERATE_44100, 
+        SAMPLE_FRAME_COUNT);
+    
+    private->audio = ppb_audio->Create(
+        instance,
+        ppb_audiocfg->CreateStereo16Bit(instance, PP_AUDIOSAMPLERATE_44100, _this->spec.samples),
+        nacl_audio_callback, 
+        _this);
+    
+    /* Start audio playback while we are still on the main thread. */
+    ppb_audio->StartPlayback(private->audio);
+    
+    return 1;
+}
+
+static int
+NACLAUD_Init(SDL_AudioDriverImpl * impl)
+{
+    if (PSGetInstanceId() == 0) {
+        return 0;
+    }
+    
+    /* Set the function pointers */
+    impl->OpenDevice = NACLAUD_OpenDevice;
+    impl->CloseDevice = NACLAUD_CloseDevice;
+    impl->HasCaptureSupport = 0;
+    impl->OnlyHasDefaultOutputDevice = 1;
+    impl->OnlyHasDefaultInputDevice = 1;
+    impl->ProvidesOwnCallbackThread = 1;
+    /*
+     *    impl->WaitDevice = NACLAUD_WaitDevice;
+     *    impl->GetDeviceBuf = NACLAUD_GetDeviceBuf;
+     *    impl->PlayDevice = NACLAUD_PlayDevice;
+     *    impl->Deinitialize = NACLAUD_Deinitialize;
+     */
+    
+    return 1;
+}
+
+AudioBootStrap NACLAUD_bootstrap = {
+    NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver",
+    NACLAUD_Init, 0
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audio/nacl/SDL_naclaudio.h	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,41 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_naclaudio_h
+#define _SDL_naclaudio_h
+
+#include "SDL_audio.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_mutex.h"
+
+#include "ppapi/c/ppb_audio.h"
+
+#define _THIS  SDL_AudioDevice *_this
+#define private _this->hidden
+
+typedef struct SDL_PrivateAudioData {
+  SDL_mutex* mutex;
+  PP_Resource audio;
+} SDL_PrivateAudioData;
+
+#endif /* _SDL_naclaudio_h */
--- a/src/dynapi/SDL_dynapi.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/dynapi/SDL_dynapi.h	Fri Jun 06 15:45:59 2014 -0300
@@ -43,7 +43,7 @@
 #include "TargetConditionals.h"
 #endif
 
-#if TARGET_OS_IPHONE  /* probably not useful on iOS. */
+#if TARGET_OS_IPHONE || __native_client__  /* probably not useful on iOS or NACL. */
 #define SDL_DYNAMIC_API 0
 #elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */
 #define SDL_DYNAMIC_API 0
--- a/src/file/SDL_rwops.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/file/SDL_rwops.c	Fri Jun 06 15:45:59 2014 -0300
@@ -43,6 +43,10 @@
 #include "SDL_system.h"
 #endif
 
+#if __NACL__
+#include "nacl_io/nacl_io.h"
+#endif
+
 #ifdef __WIN32__
 
 /* Functions to read/write Win32 API file pointers */
@@ -762,4 +766,28 @@
     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
 }
 
+
+/* SDL_RWops on NACL are implemented using nacl_io, and require mount points
+ * to be established before actual file operations are performed
+ * 
+ * Ref: https://developers.google.com/native-client/dev/devguide/coding/nacl_io?hl=es
+ */
+
+int 
+SDL_RWMount(const char* source, const char* target, const char* filesystemtype, 
+          unsigned long mountflags, const void *data) {
+#if __NACL__
+    return mount(source, target, filesystemtype, mountflags, data);
+#endif /* __NACL__ */
+    return SDL_SetError ("Mount not supported on this platform");
+}
+
+int 
+SDL_RWUmount(const char *target) {
+#if __NACL__
+    return umount(target);
+#endif /* __NACL__ */
+    return SDL_SetError ("Umount not supported on this platform");
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/nacl/SDL_nacl_main.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,77 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_NACL
+
+/* Include the SDL main definition header */
+#include "SDL_main.h"
+
+#include "ppapi_simple/ps_main.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+
+extern void NACL_SetScreenResolution(int width, int height, Uint32 format);
+
+int
+nacl_main(int argc, char *argv[])
+{
+    int status;
+    PSEvent* ps_event;
+    PP_Resource event;  
+    struct PP_Rect rect;
+    int ready = 0;
+    const PPB_View *ppb_view = PSInterfaceView();
+    
+    /* This is started in a worker thread by ppapi_simple! */
+    
+    /* Wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before starting the app */
+    
+    PSEventSetFilter(PSE_INSTANCE_DIDCHANGEVIEW);
+    while (!ready) {
+        /* Process all waiting events without blocking */
+        while (!ready && (ps_event = PSEventWaitAcquire()) != NULL) {
+            event = ps_event->as_resource;
+            switch(ps_event->type) {
+                /* From DidChangeView, contains a view resource */
+                case PSE_INSTANCE_DIDCHANGEVIEW:
+                    ppb_view->GetRect(event, &rect);
+                    NACL_SetScreenResolution(rect.size.width, rect.size.height, 0);
+                    ready = 1;
+                    break;
+                default:
+                    break;
+            }
+            PSEventRelease(ps_event);
+        }
+    }
+    
+    /* Everything is ready, start the user main function */
+    SDL_SetMainReady();
+    status = SDL_main(argc, argv);
+
+    return 0;
+}
+
+/* ppapi_simple will start nacl_main in a worker thread */
+PPAPI_SIMPLE_REGISTER_MAIN(nacl_main);
+
+#endif /* SDL_VIDEO_DRIVER_NACL */
\ No newline at end of file
--- a/src/render/opengles2/SDL_gles2funcs.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/render/opengles2/SDL_gles2funcs.h	Fri Jun 06 15:45:59 2014 -0300
@@ -68,4 +68,4 @@
 SDL_PROC(GLenum, glCheckFramebufferStatus, (GLenum))
 SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *))
 SDL_PROC(GLint, glGetAttribLocation, (GLuint, const GLchar *))
- 
+SDL_PROC(void, glGetProgramInfoLog, (GLuint, GLsizei, GLsizei*, GLchar*))
--- a/src/thread/pthread/SDL_systhread.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/thread/pthread/SDL_systhread.c	Fri Jun 06 15:45:59 2014 -0300
@@ -141,12 +141,15 @@
         #endif
     }
 
+   /* NativeClient does not yet support signals.*/
+#ifndef __NACL__
     /* Mask asynchronous signals for this thread */
     sigemptyset(&mask);
     for (i = 0; sig_list[i]; ++i) {
         sigaddset(&mask, sig_list[i]);
     }
     pthread_sigmask(SIG_BLOCK, &mask, 0);
+#endif
 
 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
     /* Allow ourselves to be asynchronously cancelled */
@@ -166,7 +169,10 @@
 int
 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
 {
-#ifdef __LINUX__
+#if __NACL__ 
+    /* FIXME: Setting thread priority does not seem to be supported in NACL */
+    return 0;
+#elif __LINUX__
     int value;
 
     if (priority == SDL_THREAD_PRIORITY_LOW) {
--- a/src/video/SDL_sysvideo.h	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/video/SDL_sysvideo.h	Fri Jun 06 15:45:59 2014 -0300
@@ -381,6 +381,9 @@
 #if SDL_VIDEO_DRIVER_WAYLAND
 extern VideoBootStrap Wayland_bootstrap;
 #endif
+#if SDL_VIDEO_DRIVER_NACL
+extern VideoBootStrap NACL_bootstrap;
+#endif
 
 extern SDL_VideoDevice *SDL_GetVideoDevice(void);
 extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode);
--- a/src/video/SDL_video.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/src/video/SDL_video.c	Fri Jun 06 15:45:59 2014 -0300
@@ -92,6 +92,9 @@
 #if SDL_VIDEO_DRIVER_WAYLAND
     &Wayland_bootstrap,
 #endif
+#if SDL_VIDEO_DRIVER_NACL
+    &NACL_bootstrap,
+#endif
 #if SDL_VIDEO_DRIVER_DUMMY
     &DUMMY_bootstrap,
 #endif
@@ -253,7 +256,7 @@
                 }
             }
         }
-
+        
         if (!renderer) {
             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
                 SDL_GetRenderDriverInfo(i, &info);
@@ -1239,7 +1242,7 @@
     }
 
     /* Some platforms have OpenGL enabled by default */
-#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
+#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
     flags |= SDL_WINDOW_OPENGL;
 #endif
     if (flags & SDL_WINDOW_OPENGL) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclevents.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,432 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#include "SDL.h"
+#include "../../events/SDL_sysevents.h"
+#include "../../events/SDL_events_c.h"
+#include "SDL_naclevents_c.h"
+#include "SDL_naclvideo.h"
+#include "ppapi_simple/ps_event.h"
+
+/* Ref: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent */
+
+static SDL_Scancode NACL_Keycodes[] = {
+    SDL_SCANCODE_UNKNOWN,               /* 0 */
+    SDL_SCANCODE_UNKNOWN,               /* 1 */
+    SDL_SCANCODE_UNKNOWN,               /* 2 */
+    SDL_SCANCODE_CANCEL,                /* DOM_VK_CANCEL 3 */
+    SDL_SCANCODE_UNKNOWN,               /* 4 */
+    SDL_SCANCODE_UNKNOWN,               /* 5 */
+    SDL_SCANCODE_HELP,                  /* DOM_VK_HELP 6 */
+    SDL_SCANCODE_UNKNOWN,               /* 7 */
+    SDL_SCANCODE_BACKSPACE,             /* DOM_VK_BACK_SPACE 8 */
+    SDL_SCANCODE_TAB,                   /* DOM_VK_TAB 9 */
+    SDL_SCANCODE_UNKNOWN,               /* 10 */
+    SDL_SCANCODE_UNKNOWN,               /* 11 */
+    SDL_SCANCODE_CLEAR,                 /* DOM_VK_CLEAR 12 */
+    SDL_SCANCODE_RETURN,                /* DOM_VK_RETURN 13 */
+    SDL_SCANCODE_RETURN,                /* DOM_VK_ENTER 14 */
+    SDL_SCANCODE_UNKNOWN,               /* 15 */
+    SDL_SCANCODE_LSHIFT,                /* DOM_VK_SHIFT 16 */
+    SDL_SCANCODE_LCTRL,                 /* DOM_VK_CONTROL 17 */
+    SDL_SCANCODE_LALT,                  /* DOM_VK_ALT 18 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_PAUSE 19 */
+    SDL_SCANCODE_CAPSLOCK,              /* DOM_VK_CAPS_LOCK 20 */
+    SDL_SCANCODE_LANG1,                 /* DOM_VK_KANA  DOM_VK_HANGUL 21 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_EISU 22 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_JUNJA 23 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_FINAL 24 */
+    SDL_SCANCODE_LANG2,                 /* DOM_VK_HANJA  DOM_VK_KANJI 25 */
+    SDL_SCANCODE_UNKNOWN,               /* 26 */
+    SDL_SCANCODE_ESCAPE,                /* DOM_VK_ESCAPE 27 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_CONVERT 28 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_NONCONVERT 29 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_ACCEPT 30 */
+    SDL_SCANCODE_MODE,                  /* DOM_VK_MODECHANGE 31 */
+    SDL_SCANCODE_SPACE,                 /* DOM_VK_SPACE 32 */
+    SDL_SCANCODE_PAGEUP,                /* DOM_VK_PAGE_UP 33 */
+    SDL_SCANCODE_PAGEDOWN,              /* DOM_VK_PAGE_DOWN 34 */
+    SDL_SCANCODE_END,                   /* DOM_VK_END 35 */
+    SDL_SCANCODE_HOME,                  /* DOM_VK_HOME 36 */
+    SDL_SCANCODE_LEFT,                  /* DOM_VK_LEFT 37 */
+    SDL_SCANCODE_UP,                    /* DOM_VK_UP 38 */
+    SDL_SCANCODE_RIGHT,                 /* DOM_VK_RIGHT 39 */
+    SDL_SCANCODE_DOWN,                  /* DOM_VK_DOWN 40 */
+    SDL_SCANCODE_SELECT,                /* DOM_VK_SELECT 41 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_PRINT 42 */
+    SDL_SCANCODE_EXECUTE,               /* DOM_VK_EXECUTE 43 */
+    SDL_SCANCODE_PRINTSCREEN,           /* DOM_VK_PRINTSCREEN 44 */
+    SDL_SCANCODE_INSERT,                /* DOM_VK_INSERT 45 */
+    SDL_SCANCODE_DELETE,                /* DOM_VK_DELETE 46 */
+    SDL_SCANCODE_UNKNOWN,               /* 47 */
+    SDL_SCANCODE_0,                     /* DOM_VK_0 48 */
+    SDL_SCANCODE_1,                     /* DOM_VK_1 49 */
+    SDL_SCANCODE_2,                     /* DOM_VK_2 50 */
+    SDL_SCANCODE_3,                     /* DOM_VK_3 51 */
+    SDL_SCANCODE_4,                     /* DOM_VK_4 52 */
+    SDL_SCANCODE_5,                     /* DOM_VK_5 53 */
+    SDL_SCANCODE_6,                     /* DOM_VK_6 54 */
+    SDL_SCANCODE_7,                     /* DOM_VK_7 55 */
+    SDL_SCANCODE_8,                     /* DOM_VK_8 56 */
+    SDL_SCANCODE_9,                     /* DOM_VK_9 57 */
+    SDL_SCANCODE_KP_COLON,              /* DOM_VK_COLON 58 */
+    SDL_SCANCODE_SEMICOLON,             /* DOM_VK_SEMICOLON 59 */
+    SDL_SCANCODE_KP_LESS,               /* DOM_VK_LESS_THAN 60 */
+    SDL_SCANCODE_EQUALS,                /* DOM_VK_EQUALS 61 */
+    SDL_SCANCODE_KP_GREATER,            /* DOM_VK_GREATER_THAN 62 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_QUESTION_MARK 63 */
+    SDL_SCANCODE_KP_AT,                 /* DOM_VK_AT 64 */
+    SDL_SCANCODE_A,                     /* DOM_VK_A 65 */
+    SDL_SCANCODE_B,                     /* DOM_VK_B 66 */
+    SDL_SCANCODE_C,                     /* DOM_VK_C 67 */
+    SDL_SCANCODE_D,                     /* DOM_VK_D 68 */
+    SDL_SCANCODE_E,                     /* DOM_VK_E 69 */
+    SDL_SCANCODE_F,                     /* DOM_VK_F 70 */
+    SDL_SCANCODE_G,                     /* DOM_VK_G 71 */
+    SDL_SCANCODE_H,                     /* DOM_VK_H 72 */
+    SDL_SCANCODE_I,                     /* DOM_VK_I 73 */
+    SDL_SCANCODE_J,                     /* DOM_VK_J 74 */
+    SDL_SCANCODE_K,                     /* DOM_VK_K 75 */
+    SDL_SCANCODE_L,                     /* DOM_VK_L 76 */
+    SDL_SCANCODE_M,                     /* DOM_VK_M 77 */
+    SDL_SCANCODE_N,                     /* DOM_VK_N 78 */
+    SDL_SCANCODE_O,                     /* DOM_VK_O 79 */
+    SDL_SCANCODE_P,                     /* DOM_VK_P 80 */
+    SDL_SCANCODE_Q,                     /* DOM_VK_Q 81 */
+    SDL_SCANCODE_R,                     /* DOM_VK_R 82 */
+    SDL_SCANCODE_S,                     /* DOM_VK_S 83 */
+    SDL_SCANCODE_T,                     /* DOM_VK_T 84 */
+    SDL_SCANCODE_U,                     /* DOM_VK_U 85 */
+    SDL_SCANCODE_V,                     /* DOM_VK_V 86 */
+    SDL_SCANCODE_W,                     /* DOM_VK_W 87 */
+    SDL_SCANCODE_X,                     /* DOM_VK_X 88 */
+    SDL_SCANCODE_Y,                     /* DOM_VK_Y 89 */
+    SDL_SCANCODE_Z,                     /* DOM_VK_Z 90 */
+    SDL_SCANCODE_LGUI,                  /* DOM_VK_WIN 91 */
+    SDL_SCANCODE_UNKNOWN,               /* 92 */
+    SDL_SCANCODE_APPLICATION,           /* DOM_VK_CONTEXT_MENU 93 */
+    SDL_SCANCODE_UNKNOWN,               /* 94 */
+    SDL_SCANCODE_SLEEP,                 /* DOM_VK_SLEEP 95 */
+    SDL_SCANCODE_KP_0,                  /* DOM_VK_NUMPAD0 96 */
+    SDL_SCANCODE_KP_1,                  /* DOM_VK_NUMPAD1 97 */
+    SDL_SCANCODE_KP_2,                  /* DOM_VK_NUMPAD2 98 */
+    SDL_SCANCODE_KP_3,                  /* DOM_VK_NUMPAD3 99 */
+    SDL_SCANCODE_KP_4,                  /* DOM_VK_NUMPAD4 100 */
+    SDL_SCANCODE_KP_5,                  /* DOM_VK_NUMPAD5 101 */
+    SDL_SCANCODE_KP_6,                  /* DOM_VK_NUMPAD6 102 */
+    SDL_SCANCODE_KP_7,                  /* DOM_VK_NUMPAD7 103 */
+    SDL_SCANCODE_KP_8,                  /* DOM_VK_NUMPAD8 104 */
+    SDL_SCANCODE_KP_9,                  /* DOM_VK_NUMPAD9 105 */
+    SDL_SCANCODE_KP_MULTIPLY,           /* DOM_VK_MULTIPLY 106 */
+    SDL_SCANCODE_KP_PLUS,               /* DOM_VK_ADD 107 */
+    SDL_SCANCODE_KP_COMMA,              /* DOM_VK_SEPARATOR 108 */
+    SDL_SCANCODE_KP_MINUS,              /* DOM_VK_SUBTRACT 109 */
+    SDL_SCANCODE_KP_PERIOD,             /* DOM_VK_DECIMAL 110 */
+    SDL_SCANCODE_KP_DIVIDE,             /* DOM_VK_DIVIDE 111 */
+    SDL_SCANCODE_F1,                    /* DOM_VK_F1 112 */
+    SDL_SCANCODE_F2,                    /* DOM_VK_F2 113 */
+    SDL_SCANCODE_F3,                    /* DOM_VK_F3 114 */
+    SDL_SCANCODE_F4,                    /* DOM_VK_F4 115 */
+    SDL_SCANCODE_F5,                    /* DOM_VK_F5 116 */
+    SDL_SCANCODE_F6,                    /* DOM_VK_F6 117 */
+    SDL_SCANCODE_F7,                    /* DOM_VK_F7 118 */
+    SDL_SCANCODE_F8,                    /* DOM_VK_F8 119 */
+    SDL_SCANCODE_F9,                    /* DOM_VK_F9 120 */
+    SDL_SCANCODE_F10,                   /* DOM_VK_F10 121 */
+    SDL_SCANCODE_F11,                   /* DOM_VK_F11 122 */
+    SDL_SCANCODE_F12,                   /* DOM_VK_F12 123 */
+    SDL_SCANCODE_F13,                   /* DOM_VK_F13 124 */
+    SDL_SCANCODE_F14,                   /* DOM_VK_F14 125 */
+    SDL_SCANCODE_F15,                   /* DOM_VK_F15 126 */
+    SDL_SCANCODE_F16,                   /* DOM_VK_F16 127 */
+    SDL_SCANCODE_F17,                   /* DOM_VK_F17 128 */
+    SDL_SCANCODE_F18,                   /* DOM_VK_F18 129 */
+    SDL_SCANCODE_F19,                   /* DOM_VK_F19 130 */
+    SDL_SCANCODE_F20,                   /* DOM_VK_F20 131 */
+    SDL_SCANCODE_F21,                   /* DOM_VK_F21 132 */
+    SDL_SCANCODE_F22,                   /* DOM_VK_F22 133 */
+    SDL_SCANCODE_F23,                   /* DOM_VK_F23 134 */
+    SDL_SCANCODE_F24,                   /* DOM_VK_F24 135 */
+    SDL_SCANCODE_UNKNOWN,               /* 136 */
+    SDL_SCANCODE_UNKNOWN,               /* 137 */
+    SDL_SCANCODE_UNKNOWN,               /* 138 */
+    SDL_SCANCODE_UNKNOWN,               /* 139 */
+    SDL_SCANCODE_UNKNOWN,               /* 140 */
+    SDL_SCANCODE_UNKNOWN,               /* 141 */
+    SDL_SCANCODE_UNKNOWN,               /* 142 */
+    SDL_SCANCODE_UNKNOWN,               /* 143 */
+    SDL_SCANCODE_NUMLOCKCLEAR,          /* DOM_VK_NUM_LOCK 144 */
+    SDL_SCANCODE_SCROLLLOCK,            /* DOM_VK_SCROLL_LOCK 145 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FJ_JISHO 146 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FJ_MASSHOU 147 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FJ_TOUROKU 148 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FJ_LOYA 149 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FJ_ROYA 150 */
+    SDL_SCANCODE_UNKNOWN,               /* 151 */
+    SDL_SCANCODE_UNKNOWN,               /* 152 */
+    SDL_SCANCODE_UNKNOWN,               /* 153 */
+    SDL_SCANCODE_UNKNOWN,               /* 154 */
+    SDL_SCANCODE_UNKNOWN,               /* 155 */
+    SDL_SCANCODE_UNKNOWN,               /* 156 */
+    SDL_SCANCODE_UNKNOWN,               /* 157 */
+    SDL_SCANCODE_UNKNOWN,               /* 158 */
+    SDL_SCANCODE_UNKNOWN,               /* 159 */
+    SDL_SCANCODE_GRAVE,                 /* DOM_VK_CIRCUMFLEX 160 */
+    SDL_SCANCODE_KP_EXCLAM,             /* DOM_VK_EXCLAMATION 161 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_DOUBLE_QUOTE 162 */
+    SDL_SCANCODE_KP_HASH,               /* DOM_VK_HASH 163 */
+    SDL_SCANCODE_CURRENCYUNIT,          /* DOM_VK_DOLLAR 164 */
+    SDL_SCANCODE_KP_PERCENT,            /* DOM_VK_PERCENT 165 */
+    SDL_SCANCODE_KP_AMPERSAND,          /* DOM_VK_AMPERSAND 166 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_UNDERSCORE 167 */
+    SDL_SCANCODE_KP_LEFTPAREN,          /* DOM_VK_OPEN_PAREN 168 */
+    SDL_SCANCODE_KP_RIGHTPAREN,         /* DOM_VK_CLOSE_PAREN 169 */
+    SDL_SCANCODE_KP_MULTIPLY,           /* DOM_VK_ASTERISK 170 */
+    SDL_SCANCODE_KP_PLUS,               /* DOM_VK_PLUS 171 */
+    SDL_SCANCODE_KP_PLUS,               /* DOM_VK_PIPE 172 */
+    SDL_SCANCODE_MINUS,                 /* DOM_VK_HYPHEN_MINUS 173 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_OPEN_CURLY_BRACKET 174 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_CLOSE_CURLY_BRACKET 175 */
+    SDL_SCANCODE_NONUSBACKSLASH,        /* DOM_VK_TILDE 176 */
+    SDL_SCANCODE_UNKNOWN,               /* 177 */
+    SDL_SCANCODE_UNKNOWN,               /* 178 */
+    SDL_SCANCODE_UNKNOWN,               /* 179 */
+    SDL_SCANCODE_UNKNOWN,               /* 180 */
+    SDL_SCANCODE_MUTE,                  /* DOM_VK_VOLUME_MUTE 181 */
+    SDL_SCANCODE_VOLUMEDOWN,            /* DOM_VK_VOLUME_DOWN 182 */
+    SDL_SCANCODE_VOLUMEUP,              /* DOM_VK_VOLUME_UP 183 */
+    SDL_SCANCODE_UNKNOWN,               /* 184 */
+    SDL_SCANCODE_UNKNOWN,               /* 185 */
+    SDL_SCANCODE_UNKNOWN,               /* 186 */
+    SDL_SCANCODE_UNKNOWN,               /* 187 */
+    SDL_SCANCODE_COMMA,                 /* DOM_VK_COMMA 188 */
+    SDL_SCANCODE_UNKNOWN,               /* 189 */
+    SDL_SCANCODE_PERIOD,                /* DOM_VK_PERIOD 190 */
+    SDL_SCANCODE_SLASH,                 /* DOM_VK_SLASH 191 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_BACK_QUOTE 192 */
+    SDL_SCANCODE_UNKNOWN,               /* 193 */
+    SDL_SCANCODE_UNKNOWN,               /* 194 */
+    SDL_SCANCODE_UNKNOWN,               /* 195 */
+    SDL_SCANCODE_UNKNOWN,               /* 196 */
+    SDL_SCANCODE_UNKNOWN,               /* 197 */
+    SDL_SCANCODE_UNKNOWN,               /* 198 */
+    SDL_SCANCODE_UNKNOWN,               /* 199 */
+    SDL_SCANCODE_UNKNOWN,               /* 200 */
+    SDL_SCANCODE_UNKNOWN,               /* 201 */
+    SDL_SCANCODE_UNKNOWN,               /* 202 */
+    SDL_SCANCODE_UNKNOWN,               /* 203 */
+    SDL_SCANCODE_UNKNOWN,               /* 204 */
+    SDL_SCANCODE_UNKNOWN,               /* 205 */
+    SDL_SCANCODE_UNKNOWN,               /* 206 */
+    SDL_SCANCODE_UNKNOWN,               /* 207 */
+    SDL_SCANCODE_UNKNOWN,               /* 208 */
+    SDL_SCANCODE_UNKNOWN,               /* 209 */
+    SDL_SCANCODE_UNKNOWN,               /* 210 */
+    SDL_SCANCODE_UNKNOWN,               /* 211 */
+    SDL_SCANCODE_UNKNOWN,               /* 212 */
+    SDL_SCANCODE_UNKNOWN,               /* 213 */
+    SDL_SCANCODE_UNKNOWN,               /* 214 */
+    SDL_SCANCODE_UNKNOWN,               /* 215 */
+    SDL_SCANCODE_UNKNOWN,               /* 216 */
+    SDL_SCANCODE_UNKNOWN,               /* 217 */
+    SDL_SCANCODE_UNKNOWN,               /* 218 */
+    SDL_SCANCODE_LEFTBRACKET,           /* DOM_VK_OPEN_BRACKET 219 */
+    SDL_SCANCODE_BACKSLASH,             /* DOM_VK_BACK_SLASH 220 */
+    SDL_SCANCODE_RIGHTBRACKET,          /* DOM_VK_CLOSE_BRACKET 221 */
+    SDL_SCANCODE_APOSTROPHE,            /* DOM_VK_QUOTE 222 */
+    SDL_SCANCODE_UNKNOWN,               /* 223 */
+    SDL_SCANCODE_RGUI,                  /* DOM_VK_META 224 */
+    SDL_SCANCODE_RALT,                  /* DOM_VK_ALTGR 225 */
+    SDL_SCANCODE_UNKNOWN,               /* 226 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_ICO_HELP 227 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_ICO_00 228 */
+    SDL_SCANCODE_UNKNOWN,               /* 229 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_ICO_CLEAR 230 */
+    SDL_SCANCODE_UNKNOWN,               /* 231 */
+    SDL_SCANCODE_UNKNOWN,               /* 232 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_RESET 233 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_JUMP 234 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_PA1 235 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_PA2 236 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_PA3 237 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_WSCTRL 238 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_CUSEL 239 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_ATTN 240 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_FINISH 241 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_COPY 242 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_AUTO 243 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_ENLW 244 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_BACKTAB 245 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_ATTN 246 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_CRSEL 247 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_EXSEL 248 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_EREOF 249 */
+    SDL_SCANCODE_AUDIOPLAY,             /* DOM_VK_PLAY 250 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_ZOOM 251 */
+    SDL_SCANCODE_UNKNOWN,               /* 252 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_PA1 253 */
+    SDL_SCANCODE_UNKNOWN,               /* DOM_VK_WIN_OEM_CLEAR 254 */
+    SDL_SCANCODE_UNKNOWN,               /* 255 */
+};
+
+static Uint8 SDL_NACL_translate_mouse_button(int32_t button) {
+    switch (button) {
+        case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
+            return SDL_BUTTON_LEFT;
+        case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
+            return SDL_BUTTON_MIDDLE;
+        case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
+            return SDL_BUTTON_RIGHT;
+            
+        case PP_INPUTEVENT_MOUSEBUTTON_NONE:
+        default:
+            return 0;
+    }
+}
+
+static SDL_Scancode
+SDL_NACL_translate_keycode(int keycode)
+{
+    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
+
+    if (keycode < SDL_arraysize(NACL_Keycodes)) {
+        scancode = NACL_Keycodes[keycode];
+    }
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> EVDEV KeyCode %d \n", keycode);
+    }
+    return scancode;
+}
+
+void NACL_PumpEvents(_THIS) {
+  PSEvent* ps_event;
+  PP_Resource event;  
+  PP_InputEvent_Type type;
+  PP_InputEvent_Modifier modifiers;
+  struct PP_Rect rect;
+  struct PP_FloatPoint fp;
+  struct PP_Point location;
+  struct PP_Var var;
+  const char *str;
+  char text[64];
+  Uint32 str_len;
+  SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+  SDL_Mouse *mouse = SDL_GetMouse();
+  
+  if (driverdata->window) {
+    while ((ps_event = PSEventTryAcquire()) != NULL) {
+        event = ps_event->as_resource;
+        switch(ps_event->type) {
+            /* From DidChangeView, contains a view resource */
+            case PSE_INSTANCE_DIDCHANGEVIEW:
+                driverdata->ppb_view->GetRect(event, &rect);
+                NACL_SetScreenResolution(rect.size.width, rect.size.height, SDL_PIXELFORMAT_UNKNOWN);
+                // FIXME: Rebuild context? See life.c UpdateContext
+                break;
+            
+            /* From HandleInputEvent, contains an input resource. */
+            case PSE_INSTANCE_HANDLEINPUT: 
+                type = driverdata->ppb_input_event->GetType(event);
+                modifiers = driverdata->ppb_input_event->GetModifiers(event);
+                switch(type) {
+                    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+                        SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, SDL_NACL_translate_mouse_button(driverdata->ppb_mouse_input_event->GetButton(event)));
+                        break;
+                    case PP_INPUTEVENT_TYPE_MOUSEUP:
+                        SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, SDL_NACL_translate_mouse_button(driverdata->ppb_mouse_input_event->GetButton(event)));
+                        break;
+                    case PP_INPUTEVENT_TYPE_WHEEL:
+                        /* FIXME: GetTicks provides high resolution scroll events */
+                        fp = driverdata->ppb_wheel_input_event->GetDelta(event);
+                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, (int) fp.x, (int) fp.y);
+                        break;
+                        
+                    case PP_INPUTEVENT_TYPE_MOUSEENTER:
+                    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
+                        /* FIXME: Mouse Focus */
+                        break;
+                        
+                        
+                    case PP_INPUTEVENT_TYPE_MOUSEMOVE: 
+                        location = driverdata->ppb_mouse_input_event->GetPosition(event);
+                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, location.x, location.y);
+                        break;
+                  
+                    case PP_INPUTEVENT_TYPE_TOUCHSTART:
+                    case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+                    case PP_INPUTEVENT_TYPE_TOUCHEND:
+                    case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
+                        /* FIXME: Touch events */
+                        break;
+                      
+                    case PP_INPUTEVENT_TYPE_KEYDOWN:
+                        SDL_SendKeyboardKey(SDL_PRESSED, SDL_NACL_translate_keycode(driverdata->ppb_keyboard_input_event->GetKeyCode(event)));
+                        break;
+                        
+                    case PP_INPUTEVENT_TYPE_KEYUP:
+                        SDL_SendKeyboardKey(SDL_RELEASED, SDL_NACL_translate_keycode(driverdata->ppb_keyboard_input_event->GetKeyCode(event)));
+                        break;
+                        
+                    case PP_INPUTEVENT_TYPE_CHAR:
+                        var = driverdata->ppb_keyboard_input_event->GetCharacterText(event);
+                        str = driverdata->ppb_var->VarToUtf8(var, &str_len);
+                        /* str is not null terminated! */
+                        if ( str_len >= SDL_arraysize(text) ) {
+                            str_len = SDL_arraysize(text) - 1;
+                        }
+                        SDL_strlcpy(text, str, str_len );
+                        text[str_len] = '\0';
+                        
+                        SDL_SendKeyboardText(text);
+                        /* FIXME: Do we have to handle ref counting? driverdata->ppb_var->Release(var);*/
+                        break;
+                        
+                    default:
+                        break;
+                }
+                break;
+                
+        
+            /* From HandleMessage, contains a PP_Var. */
+            case PSE_INSTANCE_HANDLEMESSAGE:
+                break;
+
+            /* From DidChangeFocus, contains a PP_Bool with the current focus state. */
+            case PSE_INSTANCE_DIDCHANGEFOCUS:
+                break;
+
+            /* When the 3D context is lost, no resource. */
+            case PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST:
+                break;
+                
+            /* When the mouse lock is lost. */
+            case PSE_MOUSELOCK_MOUSELOCKLOST:
+                break;
+
+            default:
+                break;
+        }
+        
+        PSEventRelease(ps_event);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclevents_c.h	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,30 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_naclevents_c_h
+#define _SDL_naclevents_c_h
+
+#include "SDL_naclvideo.h"
+
+extern void NACL_PumpEvents(_THIS);
+
+#endif /* _SDL_naclevents_c_h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclglue.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,24 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_NACL
+#endif /* SDL_VIDEO_DRIVER_NACL */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclopengles.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,171 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_NACL
+
+/* NaCl SDL video GLES 2 driver implementation */
+
+#include "SDL_video.h"
+#include "SDL_naclvideo.h"
+
+#if SDL_LOADSO_DLOPEN
+#include "dlfcn.h"
+#endif
+
+#include "ppapi/gles2/gl2ext_ppapi.h"
+#include "ppapi_simple/ps.h"
+
+/* GL functions */
+int
+NACL_GLES_LoadLibrary(_THIS, const char *path)
+{
+    /* FIXME: Support dynamic linking when PNACL supports it */
+    return glInitializePPAPI(PSGetInterface) == 0;
+}
+
+void *
+NACL_GLES_GetProcAddress(_THIS, const char *proc)
+{
+#if SDL_LOADSO_DLOPEN
+    return dlsym( 0 /* RTLD_DEFAULT */, proc);
+#else
+    return NULL;
+#endif
+}
+
+void
+NACL_GLES_UnloadLibrary(_THIS)
+{
+    /* FIXME: Support dynamic linking when PNACL supports it */
+    glTerminatePPAPI();
+}
+
+int
+NACL_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext sdl_context)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    /* FIXME: Check threading issues...otherwise use a hardcoded _this->context across all threads */
+    driverdata->ppb_instance->BindGraphics(driverdata->instance, (PP_Resource) sdl_context);
+    glSetCurrentContextPPAPI((PP_Resource) sdl_context);
+    return 0;
+}
+
+SDL_GLContext
+NACL_GLES_CreateContext(_THIS, SDL_Window * window)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    PP_Resource context, share_context = 0;
+    /* 64 seems nice. */
+    Sint32 attribs[64];
+    int i = 0;
+    
+    if (_this->gl_config.share_with_current_context) {
+        share_context = (PP_Resource) SDL_GL_GetCurrentContext();
+    }
+
+    /* FIXME: Some ATTRIBS from PP_Graphics3DAttrib are not set here */
+    
+    attribs[i++] = PP_GRAPHICS3DATTRIB_WIDTH;
+    attribs[i++] = window->w;
+    attribs[i++] = PP_GRAPHICS3DATTRIB_HEIGHT;
+    attribs[i++] = window->h;
+    attribs[i++] = PP_GRAPHICS3DATTRIB_RED_SIZE;
+    attribs[i++] = _this->gl_config.red_size;
+    attribs[i++] = PP_GRAPHICS3DATTRIB_GREEN_SIZE;
+    attribs[i++] = _this->gl_config.green_size;
+    attribs[i++] = PP_GRAPHICS3DATTRIB_BLUE_SIZE;
+    attribs[i++] = _this->gl_config.blue_size;
+    
+    if (_this->gl_config.alpha_size) {
+        attribs[i++] = PP_GRAPHICS3DATTRIB_ALPHA_SIZE;
+        attribs[i++] = _this->gl_config.alpha_size;
+    }
+    
+    /*if (_this->gl_config.buffer_size) {
+        attribs[i++] = EGL_BUFFER_SIZE;
+        attribs[i++] = _this->gl_config.buffer_size;
+    }*/
+    
+    attribs[i++] = PP_GRAPHICS3DATTRIB_DEPTH_SIZE;
+    attribs[i++] = _this->gl_config.depth_size;
+    
+    if (_this->gl_config.stencil_size) {
+        attribs[i++] = PP_GRAPHICS3DATTRIB_STENCIL_SIZE;
+        attribs[i++] = _this->gl_config.stencil_size;
+    }
+    
+    if (_this->gl_config.multisamplebuffers) {
+        attribs[i++] = PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS;
+        attribs[i++] = _this->gl_config.multisamplebuffers;
+    }
+    
+    if (_this->gl_config.multisamplesamples) {
+        attribs[i++] = PP_GRAPHICS3DATTRIB_SAMPLES;
+        attribs[i++] = _this->gl_config.multisamplesamples;
+    }
+       
+    attribs[i++] = PP_GRAPHICS3DATTRIB_NONE;
+    
+    context = driverdata->ppb_graphics->Create(driverdata->instance, share_context, attribs);
+
+    if (context) {
+        /* We need to make the context current, otherwise nothing works */
+        SDL_GL_MakeCurrent(window, (SDL_GLContext) context);
+    }
+    
+    return (SDL_GLContext) context;
+}
+
+
+
+int
+NACL_GLES_SetSwapInterval(_THIS, int interval)
+{
+    /* STUB */
+    return 0;
+}
+
+int
+NACL_GLES_GetSwapInterval(_THIS)
+{
+    /* STUB */
+    return 0;
+}
+
+void
+NACL_GLES_SwapWindow(_THIS, SDL_Window * window)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    struct PP_CompletionCallback callback = { NULL, 0, PP_COMPLETIONCALLBACK_FLAG_NONE };
+    driverdata->ppb_graphics->SwapBuffers((PP_Resource) SDL_GL_GetCurrentContext(), callback );
+}
+
+void
+NACL_GLES_DeleteContext(_THIS, SDL_GLContext context)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    driverdata->ppb_core->ReleaseResource((PP_Resource) context);
+}
+
+#endif /* SDL_VIDEO_DRIVER_NACL */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclopengles.h	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,38 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_naclgl_h
+#define _SDL_naclgl_h
+
+extern int NACL_GLES_LoadLibrary(_THIS, const char *path);
+extern void *NACL_GLES_GetProcAddress(_THIS, const char *proc);
+extern void NACL_GLES_UnloadLibrary(_THIS);
+extern SDL_GLContext NACL_GLES_CreateContext(_THIS, SDL_Window * window);
+extern int NACL_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+extern int NACL_GLES_SetSwapInterval(_THIS, int interval);
+extern int NACL_GLES_GetSwapInterval(_THIS);
+extern void NACL_GLES_SwapWindow(_THIS, SDL_Window * window);
+extern void NACL_GLES_DeleteContext(_THIS, SDL_GLContext context);
+
+#endif /* _SDL_naclgl_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclvideo.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,183 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_NACL
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_event.h"
+#include "nacl_io/nacl_io.h"
+
+#include "SDL_naclvideo.h"
+#include "SDL_naclwindow.h"
+#include "SDL_naclevents_c.h"
+#include "SDL_naclopengles.h"   
+#include "SDL_video.h"
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_events_c.h"
+
+#define NACLVID_DRIVER_NAME "nacl"
+
+/* Static init required because NACL_SetScreenResolution 
+ * may appear even before SDL starts and we want to remember
+ * the window width and height
+ */
+static SDL_VideoData nacl = {0};
+
+void
+NACL_SetScreenResolution(int width, int height, Uint32 format)
+{
+    PP_Resource context;
+    
+    nacl.w = width;
+    nacl.h = height;   
+    nacl.format = format;
+    
+    if (nacl.window) {
+        nacl.window->w = width;
+        nacl.window->h = height;
+        SDL_SendWindowEvent(nacl.window, SDL_WINDOWEVENT_RESIZED, width, height);
+    }
+    
+    /* FIXME: Check threading issues...otherwise use a hardcoded _this->context across all threads */
+    context = (PP_Resource) SDL_GL_GetCurrentContext();
+    if (context) {
+        PSInterfaceGraphics3D()->ResizeBuffers(context, width, height);
+    }
+
+}
+
+
+
+/* Initialization/Query functions */
+static int NACL_VideoInit(_THIS);
+static void NACL_VideoQuit(_THIS);
+
+static int NACL_Available(void) {
+    return PSGetInstanceId() != 0;
+}
+
+static void NACL_DeleteDevice(SDL_VideoDevice *device) {
+    SDL_VideoData *driverdata = (SDL_VideoData*) device->driverdata;
+    driverdata->ppb_core->ReleaseResource((PP_Resource) driverdata->ppb_message_loop);
+    SDL_free(device->driverdata);
+    SDL_free(device);
+}
+
+static int
+NACL_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
+{
+    return 0;
+}
+
+static SDL_VideoDevice *NACL_CreateDevice(int devindex) {
+    SDL_VideoDevice *device;
+    
+    /* Initialize all variables that we clean on shutdown */
+    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
+    if (!device) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+    device->driverdata = &nacl;
+  
+    /* Set the function pointers */
+    device->VideoInit = NACL_VideoInit;
+    device->VideoQuit = NACL_VideoQuit;
+    device->PumpEvents = NACL_PumpEvents;
+    
+    device->CreateWindow = NACL_CreateWindow;
+    device->SetWindowTitle = NACL_SetWindowTitle;
+    device->DestroyWindow = NACL_DestroyWindow;
+    
+    device->SetDisplayMode = NACL_SetDisplayMode;
+    
+    device->free = NACL_DeleteDevice;
+    
+    /* GL pointers */
+    device->GL_LoadLibrary = NACL_GLES_LoadLibrary;
+    device->GL_GetProcAddress = NACL_GLES_GetProcAddress;
+    device->GL_UnloadLibrary = NACL_GLES_UnloadLibrary;
+    device->GL_CreateContext = NACL_GLES_CreateContext;
+    device->GL_MakeCurrent = NACL_GLES_MakeCurrent;
+    device->GL_SetSwapInterval = NACL_GLES_SetSwapInterval;
+    device->GL_GetSwapInterval = NACL_GLES_GetSwapInterval;
+    device->GL_SwapWindow = NACL_GLES_SwapWindow;
+    device->GL_DeleteContext = NACL_GLES_DeleteContext;
+    
+    
+    return device;
+}
+
+VideoBootStrap NACL_bootstrap = {
+    NACLVID_DRIVER_NAME, "SDL Native Client Video Driver",
+    NACL_Available, NACL_CreateDevice
+};
+
+int NACL_VideoInit(_THIS) {
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    SDL_DisplayMode mode;
+
+    mode.format = driverdata->format;
+    mode.w = driverdata->w;
+    mode.h = driverdata->h;
+    mode.refresh_rate = 0;
+    mode.driverdata = NULL;
+    if (SDL_AddBasicVideoDisplay(&mode) < 0) {
+        return -1;
+    }
+    
+    SDL_zero(mode);
+    SDL_AddDisplayMode(&_this->displays[0], &mode);
+    
+    PSInterfaceInit();
+    driverdata->instance = PSGetInstanceId();
+    driverdata->ppb_graphics = PSInterfaceGraphics3D();
+    driverdata->ppb_message_loop = PSInterfaceMessageLoop();
+    driverdata->ppb_core = PSInterfaceCore();
+    driverdata->ppb_fullscreen = PSInterfaceFullscreen();
+    driverdata->ppb_instance = PSInterfaceInstance();
+    driverdata->ppb_image_data = PSInterfaceImageData();
+    driverdata->ppb_view = PSInterfaceView();
+    driverdata->ppb_var = PSInterfaceVar();
+    driverdata->ppb_input_event = (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE);
+    driverdata->ppb_keyboard_input_event = (PPB_KeyboardInputEvent*) PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE);
+    driverdata->ppb_mouse_input_event = (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE);
+    driverdata->ppb_wheel_input_event = (PPB_WheelInputEvent*) PSGetInterface(PPB_WHEEL_INPUT_EVENT_INTERFACE);
+    driverdata->ppb_touch_input_event = (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE);
+    
+    
+    driverdata->message_loop = driverdata->ppb_message_loop->Create(driverdata->instance);
+    
+    PSEventSetFilter(PSE_ALL);
+    
+    /* We're done! */
+    return 0;
+}
+
+void NACL_VideoQuit(_THIS) {
+}
+
+#endif /* SDL_VIDEO_DRIVER_NACL */
+/* vi: set ts=4 sw=4 expandtab: */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclvideo.h	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,67 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_naclvideo_h
+#define _SDL_naclvideo_h
+
+#include "../SDL_sysvideo.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi/c/pp_input_event.h"
+
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS  SDL_VideoDevice *_this
+
+
+/* Private display data */
+
+typedef struct SDL_VideoData {
+  Uint32 format;
+  int w, h;
+  SDL_Window *window;
+
+  const PPB_Graphics3D *ppb_graphics;
+  const PPB_MessageLoop *ppb_message_loop;
+  const PPB_Core *ppb_core;
+  const PPB_Fullscreen *ppb_fullscreen;
+  const PPB_Instance *ppb_instance;
+  const PPB_ImageData *ppb_image_data;
+  const PPB_View *ppb_view;
+  const PPB_Var *ppb_var;
+  const PPB_InputEvent *ppb_input_event;
+  const PPB_KeyboardInputEvent *ppb_keyboard_input_event;
+  const PPB_MouseInputEvent *ppb_mouse_input_event;
+  const PPB_WheelInputEvent *ppb_wheel_input_event;
+  const PPB_TouchInputEvent *ppb_touch_input_event;
+      
+  PP_Resource message_loop;
+  PP_Instance instance;
+  
+  /* FIXME: Check threading issues...otherwise use a hardcoded _this->context across all threads */
+  /* PP_Resource context; */
+
+} SDL_VideoData;
+
+extern void NACL_SetScreenResolution(int width, int height, Uint32 format);
+
+
+#endif /* _SDL_naclvideo_h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclwindow.c	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,74 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_NACL
+
+#include "../SDL_sysvideo.h"
+
+#include "SDL_naclvideo.h"
+#include "SDL_naclwindow.h"
+
+int
+NACL_CreateWindow(_THIS, SDL_Window * window)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    
+    if (driverdata->window) {
+        SDL_SetError("NaCl only supports one window");
+        return -1;
+    }
+    driverdata->window = window;
+
+    /* Adjust the window data to match the screen */
+    window->x = 0;
+    window->y = 0;
+    window->w = driverdata->w;
+    window->h = driverdata->h;
+
+    window->flags &= ~SDL_WINDOW_RESIZABLE;     /* window is NEVER resizeable */
+    window->flags |= SDL_WINDOW_FULLSCREEN;     /* window is always fullscreen */
+    window->flags &= ~SDL_WINDOW_HIDDEN;
+    window->flags |= SDL_WINDOW_SHOWN;          /* only one window on NaCl */
+    window->flags |= SDL_WINDOW_INPUT_FOCUS;    /* always has input focus */    
+    window->flags |= SDL_WINDOW_OPENGL;
+  
+    return 0;
+}
+
+void
+NACL_SetWindowTitle(_THIS, SDL_Window * window)
+{
+    /* TODO */
+}
+
+void
+NACL_DestroyWindow(_THIS, SDL_Window * window)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata;
+    if (window == driverdata->window) {
+        driverdata->window = NULL;
+    }
+}
+
+#endif /* SDL_VIDEO_DRIVER_NACL */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/nacl/SDL_naclwindow.h	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,32 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_naclwindow_h
+#define _SDL_naclwindow_h
+
+extern int NACL_CreateWindow(_THIS, SDL_Window * window);
+extern void NACL_SetWindowTitle(_THIS, SDL_Window * window);
+extern void NACL_DestroyWindow(_THIS, SDL_Window * window);
+
+#endif /* _SDL_naclwindow_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nacl/background.js	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,40 @@
+// 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.
+
+function makeURL(toolchain, config) {
+  return 'index.html?tc=' + toolchain + '&config=' + config;
+}
+
+function createWindow(url) {
+  console.log('loading ' + url);
+  chrome.app.window.create(url, {
+    width: 1024,
+    height: 800,
+    frame: 'none'
+  });
+}
+
+function onLaunched(launchData) {
+  // Send and XHR to get the URL to load from a configuration file.
+  // Normally you won't need to do this; just call:
+  //
+  // chrome.app.window.create('<your url>', {...});
+  //
+  // In the SDK we want to be able to load different URLs (for different
+  // toolchain/config combinations) from the commandline, so we to read
+  // this information from the file "run_package_config".
+  var xhr = new XMLHttpRequest();
+  xhr.open('GET', 'run_package_config', true);
+  xhr.onload = function() {
+    var toolchain_config = this.responseText.split(' ');
+    createWindow(makeURL.apply(null, toolchain_config));
+  };
+  xhr.onerror = function() {
+    // Can't find the config file, just load the default.
+    createWindow('index.html');
+  };
+  xhr.send();
+}
+
+chrome.app.runtime.onLaunched.addListener(onLaunched);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nacl/common.js	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,469 @@
+// 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 to true when the Document is loaded IFF "test=true" is in the query
+// string.
+var isTest = false;
+
+// Set to true when loading a "Release" NaCl module, false when loading a
+// "Debug" NaCl module.
+var isRelease = true;
+
+// Javascript module pattern:
+//   see http://en.wikipedia.org/wiki/Unobtrusive_JavaScript#Namespaces
+// In essence, we define an anonymous function which is immediately called and
+// returns a new object. The new object contains only the exported definitions;
+// all other definitions in the anonymous function are inaccessible to external
+// code.
+var common = (function() {
+
+  function isHostToolchain(tool) {
+    return tool == 'win' || tool == 'linux' || tool == 'mac';
+  }
+
+  /**
+   * Return the mime type for NaCl plugin.
+   *
+   * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc.
+   * @return {string} The mime-type for the kind of NaCl plugin matching
+   * the given toolchain.
+   */
+  function mimeTypeForTool(tool) {
+    // For NaCl modules use application/x-nacl.
+    var mimetype = 'application/x-nacl';
+    if (isHostToolchain(tool)) {
+      // For non-NaCl PPAPI plugins use the x-ppapi-debug/release
+      // mime type.
+      if (isRelease)
+        mimetype = 'application/x-ppapi-release';
+      else
+        mimetype = 'application/x-ppapi-debug';
+    } else if (tool == 'pnacl' && isRelease) {
+      mimetype = 'application/x-pnacl';
+    }
+    return mimetype;
+  }
+
+  /**
+   * Check if the browser supports NaCl plugins.
+   *
+   * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc.
+   * @return {bool} True if the browser supports the type of NaCl plugin
+   * produced by the given toolchain.
+   */
+  function browserSupportsNaCl(tool) {
+    // Assume host toolchains always work with the given browser.
+    // The below mime-type checking might not work with
+    // --register-pepper-plugins.
+    if (isHostToolchain(tool)) {
+      return true;
+    }
+    var mimetype = mimeTypeForTool(tool);
+    return navigator.mimeTypes[mimetype] !== undefined;
+  }
+
+  /**
+   * Inject a script into the DOM, and call a callback when it is loaded.
+   *
+   * @param {string} url The url of the script to load.
+   * @param {Function} onload The callback to call when the script is loaded.
+   * @param {Function} onerror The callback to call if the script fails to load.
+   */
+  function injectScript(url, onload, onerror) {
+    var scriptEl = document.createElement('script');
+    scriptEl.type = 'text/javascript';
+    scriptEl.src = url;
+    scriptEl.onload = onload;
+    if (onerror) {
+      scriptEl.addEventListener('error', onerror, false);
+    }
+    document.head.appendChild(scriptEl);
+  }
+
+  /**
+   * Run all tests for this example.
+   *
+   * @param {Object} moduleEl The module DOM element.
+   */
+  function runTests(moduleEl) {
+    console.log('runTests()');
+    common.tester = new Tester();
+
+    // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the
+    // NaCl module returns 0 or calls exit(0)).
+    //
+    // Without this exception, the browser_tester thinks that the module
+    // has crashed.
+    common.tester.exitCleanlyIsOK();
+
+    common.tester.addAsyncTest('loaded', function(test) {
+      test.pass();
+    });
+
+    if (typeof window.addTests !== 'undefined') {
+      window.addTests();
+    }
+
+    common.tester.waitFor(moduleEl);
+    common.tester.run();
+  }
+
+  /**
+   * Create the Native Client <embed> element as a child of the DOM element
+   * named "listener".
+   *
+   * @param {string} name The name of the example.
+   * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc.
+   * @param {string} path Directory name where .nmf file can be found.
+   * @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, 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');
+
+    // Add any optional arguments
+    if (attrs) {
+      for (var key in attrs) {
+        moduleEl.setAttribute(key, attrs[key]);
+      }
+    }
+
+    var mimetype = mimeTypeForTool(tool);
+    moduleEl.setAttribute('type', mimetype);
+
+    // 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 = document.getElementById('listener');
+    listenerDiv.appendChild(moduleEl);
+
+    // Host plugins don't send a moduleDidLoad message. We'll fake it here.
+    var isHost = isHostToolchain(tool);
+    if (isHost) {
+      window.setTimeout(function() {
+        moduleEl.readyState = 1;
+        moduleEl.dispatchEvent(new CustomEvent('loadstart'));
+        moduleEl.readyState = 4;
+        moduleEl.dispatchEvent(new CustomEvent('load'));
+        moduleEl.dispatchEvent(new CustomEvent('loadend'));
+      }, 100);  // 100 ms
+    }
+
+    // This is code that is only used to test the SDK.
+    if (isTest) {
+      var loadNaClTest = function() {
+        injectScript('nacltest.js', function() {
+          runTests(moduleEl);
+        });
+      };
+
+      // Try to load test.js for the example. Whether or not it exists, load
+      // nacltest.js.
+      injectScript('test.js', loadNaClTest, loadNaClTest);
+    }
+  }
+
+  /**
+   * Add the default "load" and "message" event listeners to the element with
+   * id "listener".
+   *
+   * The "load" event is sent when the module is successfully loaded. The
+   * "message" event is sent when the naclModule posts a message using
+   * PPB_Messaging.PostMessage() (in C) or pp::Instance().PostMessage() (in
+   * C++).
+   */
+  function attachDefaultListeners() {
+    var listenerDiv = document.getElementById('listener');
+    listenerDiv.addEventListener('load', moduleDidLoad, true);
+    listenerDiv.addEventListener('message', handleMessage, true);
+    listenerDiv.addEventListener('error', handleError, true);
+    listenerDiv.addEventListener('crash', handleCrash, true);
+    if (typeof window.attachListeners !== 'undefined') {
+      window.attachListeners();
+    }
+  }
+
+  /**
+   * Called when the NaCl module fails to load.
+   *
+   * This event listener is registered in createNaClModule above.
+   */
+  function handleError(event) {
+    // We can't use common.naclModule yet because the module has not been
+    // loaded.
+    var moduleEl = document.getElementById('nacl_module');
+    updateStatus('ERROR [' + moduleEl.lastError + ']');
+  }
+
+  /**
+   * Called when the Browser can not communicate with the Module
+   *
+   * This event listener is registered in attachDefaultListeners above.
+   */
+  function handleCrash(event) {
+    if (common.naclModule.exitStatus == -1) {
+      updateStatus('CRASHED');
+    } else {
+      updateStatus('EXITED [' + common.naclModule.exitStatus + ']');
+    }
+    if (typeof window.handleCrash !== 'undefined') {
+      window.handleCrash(common.naclModule.lastError);
+    }
+  }
+
+  /**
+   * Called when the NaCl module is loaded.
+   *
+   * This event listener is registered in attachDefaultListeners above.
+   */
+  function moduleDidLoad() {
+    common.naclModule = document.getElementById('nacl_module');
+    updateStatus('RUNNING');
+
+    if (typeof window.moduleDidLoad !== 'undefined') {
+      window.moduleDidLoad();
+    }
+  }
+
+  /**
+   * Hide the NaCl module's embed element.
+   *
+   * We don't want to hide by default; if we do, it is harder to determine that
+   * a plugin failed to load. Instead, call this function inside the example's
+   * "moduleDidLoad" function.
+   *
+   */
+  function hideModule() {
+    // Setting common.naclModule.style.display = "None" doesn't work; the
+    // module will no longer be able to receive postMessages.
+    common.naclModule.style.height = '0';
+  }
+
+  /**
+   * Remove the NaCl module from the page.
+   */
+  function removeModule() {
+    common.naclModule.parentNode.removeChild(common.naclModule);
+    common.naclModule = null;
+  }
+
+  /**
+   * Return true when |s| starts with the string |prefix|.
+   *
+   * @param {string} s The string to search.
+   * @param {string} prefix The prefix to search for in |s|.
+   */
+  function startsWith(s, prefix) {
+    // indexOf would search the entire string, lastIndexOf(p, 0) only checks at
+    // the first index. See: http://stackoverflow.com/a/4579228
+    return s.lastIndexOf(prefix, 0) === 0;
+  }
+
+  /** Maximum length of logMessageArray. */
+  var kMaxLogMessageLength = 20;
+
+  /** An array of messages to display in the element with id "log". */
+  var logMessageArray = [];
+
+  /**
+   * Add a message to an element with id "log".
+   *
+   * This function is used by the default "log:" message handler.
+   *
+   * @param {string} message The message to log.
+   */
+  function logMessage(message) {
+    logMessageArray.push(message);
+    if (logMessageArray.length > kMaxLogMessageLength)
+      logMessageArray.shift();
+
+    document.getElementById('log').textContent = logMessageArray.join('\n');
+    console.log(message);
+  }
+
+  /**
+   */
+  var defaultMessageTypes = {
+    'alert': alert,
+    'log': logMessage
+  };
+
+  /**
+   * Called when the NaCl module sends a message to JavaScript (via
+   * PPB_Messaging.PostMessage())
+   *
+   * This event listener is registered in createNaClModule above.
+   *
+   * @param {Event} message_event A message event. message_event.data contains
+   *     the data sent from the NaCl module.
+   */
+  function handleMessage(message_event) {
+    if (typeof message_event.data === 'string') {
+      for (var type in defaultMessageTypes) {
+        if (defaultMessageTypes.hasOwnProperty(type)) {
+          if (startsWith(message_event.data, type + ':')) {
+            func = defaultMessageTypes[type];
+            func(message_event.data.slice(type.length + 1));
+            return;
+          }
+        }
+      }
+    }
+
+    if (typeof window.handleMessage !== 'undefined') {
+      window.handleMessage(message_event);
+      return;
+    }
+
+    logMessage('Unhandled message: ' + message_event.data);
+  }
+
+  /**
+   * Called when the DOM content has loaded; i.e. the page's document is fully
+   * parsed. At this point, we can safely query any elements in the document via
+   * document.querySelector, document.getElementById, etc.
+   *
+   * @param {string} name The name of the example.
+   * @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc.
+   * @param {string} path Directory name where .nmf file can be found.
+   * @param {number} width The width to create the plugin.
+   * @param {number} height The height to create the plugin.
+   * @param {Object} attrs Optional dictionary of additional attributes.
+   */
+  function domContentLoaded(name, tool, path, width, height, attrs) {
+    // If the page loads before the Native Client module loads, then set the
+    // status message indicating that the module is still loading.  Otherwise,
+    // do not change the status message.
+    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.');
+    }
+  }
+
+  /** Saved text to display in the element with id 'statusField'. */
+  var statusText = 'NO-STATUSES';
+
+  /**
+   * Set the global status message. 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. If null or undefined, then
+   *     set element 'statusField' to the message from the last call to
+   *     updateStatus.
+   */
+  function updateStatus(opt_message) {
+    if (opt_message) {
+      statusText = opt_message;
+    }
+    var statusField = document.getElementById('statusField');
+    if (statusField) {
+      statusField.innerHTML = statusText;
+    }
+  }
+
+  // The symbols to export.
+  return {
+    /** A reference to the NaCl module, once it is loaded. */
+    naclModule: null,
+
+    attachDefaultListeners: attachDefaultListeners,
+    domContentLoaded: domContentLoaded,
+    createNaClModule: createNaClModule,
+    hideModule: hideModule,
+    removeModule: removeModule,
+    logMessage: logMessage,
+    updateStatus: updateStatus
+  };
+
+}());
+
+// 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() {
+  var body = document.body;
+
+  // The data-* attributes on the body can be referenced via body.dataset.
+  if (body.dataset) {
+    var loadFunction;
+    if (!body.dataset.customLoad) {
+      loadFunction = common.domContentLoaded;
+    } else if (typeof window.domContentLoaded !== 'undefined') {
+      loadFunction = window.domContentLoaded;
+    }
+
+    // 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]) : '';
+      }
+    }
+
+    if (loadFunction) {
+      var toolchains = body.dataset.tools.split(' ');
+      var configs = body.dataset.configs.split(' ');
+
+      var attrs = {};
+      if (body.dataset.attrs) {
+        var attr_list = body.dataset.attrs.split(' ');
+        for (var key in attr_list) {
+          var attr = attr_list[key].split('=');
+          var key = attr[0];
+          var value = attr[1];
+          attrs[key] = value;
+        }
+      }
+
+      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];
+
+      var pathFormat = body.dataset.path;
+      var path = pathFormat.replace('{tc}', tc).replace('{config}', config);
+
+      isTest = searchVars.test === 'true';
+      isRelease = path.toLowerCase().indexOf('release') != -1;
+
+      loadFunction(body.dataset.name, tc, path, body.dataset.width,
+                   body.dataset.height, attrs);
+    }
+  }
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nacl/index.html	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<!--
+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.
+-->
+<head>
+  <meta http-equiv="Pragma" content="no-cache">
+  <meta http-equiv="Expires" content="-1">
+  <title>SDL NACL Test</title>
+  <script type="text/javascript" src="common.js"></script>
+</head>
+<body data-width="640" data-height="640" data-name="sdl_app" data-tools="pnacl" data-configs="Debug Release" data-path="{tc}/{config}">
+  <h1>SDL NACL Test</h1>
+  <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+  <!-- The NaCl plugin will be embedded inside the element with id "listener".
+      See common.js.-->
+  <div id="listener"></div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nacl/manifest.json	Fri Jun 06 15:45:59 2014 -0300
@@ -0,0 +1,22 @@
+{
+  "name": "SDL testgles2",
+  "version": "33.0.1750.117",
+  "minimum_chrome_version": "33.0.1750.117",
+  "manifest_version": 2,
+  "description": "testgles2",
+  "offline_enabled": true,
+  "icons": {
+    "128": "icon128.png"
+  },
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  },
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMN716Qyu0l2EHNFqIJVqVysFcTR6urqhaGGqW4UK7slBaURz9+Sb1b4Ot5P1uQNE5c+CTU5Vu61wpqmSqMMxqHLWdPPMh8uRlyctsb2cxWwG6XoGSvpX29NsQVUFXd4v2tkJm3G9t+V0X8TYskrvWQmnyOW8OEIDvrBhUEfFxWQIDAQAB",
+  "oauth2": {
+    "client_id": "903965034255.apps.googleusercontent.com",
+    "scopes": ["https://www.googleapis.com/auth/drive"]
+  },
+  "permissions": []
+}
--- a/test/testgles2.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/test/testgles2.c	Fri Jun 06 15:45:59 2014 -0300
@@ -16,7 +16,7 @@
 
 #include "SDL_test_common.h"
 
-#if defined(__IPHONEOS__) || defined(__ANDROID__)
+#if defined(__IPHONEOS__) || defined(__ANDROID__) || defined(__NACL__)
 #define HAVE_OPENGLES2
 #endif
 
@@ -195,6 +195,8 @@
 {
     GLint status = GL_FALSE;
     const char *shaders[1] = { NULL };
+    char buffer[1024];
+    GLsizei length;
 
     /* Create shader and load into GL. */
     *shader = GL_CHECK(ctx.glCreateShader(shader_type));
@@ -212,7 +214,9 @@
 
     /* Dump debug info (source and log) if compilation failed. */
     if(status != GL_TRUE) {
-        SDL_Log("Shader compilation failed");
+        ctx.glGetProgramInfoLog(*shader, sizeof(buffer), &length, &buffer[0]);
+        buffer[length] = '\0';
+        SDL_Log("Shader compilation failed: %s", buffer);fflush(stderr);
         quit(-1);
     }
 }
@@ -675,7 +679,7 @@
         SDL_Log("%2.2f frames per second\n",
                ((double) frames * 1000) / (now - then));
     }
-#if !defined(__ANDROID__)    
+#if !defined(__ANDROID__) && !defined(__NACL__)  
     quit(0);
 #endif    
     return 0;
--- a/test/testrendercopyex.c	Thu Jun 05 15:37:33 2014 -0700
+++ b/test/testrendercopyex.c	Fri Jun 06 15:45:59 2014 -0300
@@ -161,6 +161,16 @@
         quit(2);
     }
 
+#if __NACL__
+    SDL_RWUmount("/");
+    SDL_RWMount(
+        "",  /* source */
+        "/",  /* target */
+        "httpfs",  /* filesystemtype */
+        0,  /* mountflags */
+        "");  /* data specific to the html5fs type */
+#endif    
+    
     drawstates = SDL_stack_alloc(DrawState, state->num_windows);
     for (i = 0; i < state->num_windows; ++i) {
         DrawState *drawstate = &drawstates[i];