From 1e352d7929be2cec7976139d449c9b3e53252abc Mon Sep 17 00:00:00 2001 From: Gabriel Jacobo Date: Fri, 6 Jun 2014 15:45:59 -0300 Subject: [PATCH] Chrome's Native Client backend implementation --- README-nacl.txt | 60 ++++ WhatsNew.txt | 1 + build-scripts/config.sub | 27 ++ build-scripts/naclbuild.sh | 105 ++++++ configure | 64 ++++ configure.in | 40 +++ include/SDL_assert.h | 2 +- include/SDL_config.h.in | 2 + include/SDL_main.h | 9 + include/SDL_platform.h | 19 +- include/SDL_rwops.h | 10 + src/SDL_log.c | 3 + src/audio/SDL_audio.c | 7 + src/audio/nacl/SDL_naclaudio.c | 135 ++++++++ src/audio/nacl/SDL_naclaudio.h | 41 +++ src/dynapi/SDL_dynapi.h | 2 +- src/file/SDL_rwops.c | 28 ++ src/main/nacl/SDL_nacl_main.c | 77 +++++ src/render/opengles2/SDL_gles2funcs.h | 2 +- src/thread/pthread/SDL_systhread.c | 8 +- src/video/SDL_sysvideo.h | 3 + src/video/SDL_video.c | 7 +- src/video/nacl/SDL_naclevents.c | 432 ++++++++++++++++++++++++ src/video/nacl/SDL_naclevents_c.h | 30 ++ src/video/nacl/SDL_naclglue.c | 24 ++ src/video/nacl/SDL_naclopengles.c | 171 ++++++++++ src/video/nacl/SDL_naclopengles.h | 38 +++ src/video/nacl/SDL_naclvideo.c | 183 ++++++++++ src/video/nacl/SDL_naclvideo.h | 67 ++++ src/video/nacl/SDL_naclwindow.c | 74 ++++ src/video/nacl/SDL_naclwindow.h | 32 ++ test/nacl/background.js | 40 +++ test/nacl/common.js | 469 ++++++++++++++++++++++++++ test/nacl/index.html | 21 ++ test/nacl/manifest.json | 22 ++ test/testgles2.c | 10 +- test/testrendercopyex.c | 10 + 37 files changed, 2265 insertions(+), 10 deletions(-) create mode 100644 README-nacl.txt create mode 100644 build-scripts/naclbuild.sh create mode 100644 src/audio/nacl/SDL_naclaudio.c create mode 100644 src/audio/nacl/SDL_naclaudio.h create mode 100644 src/main/nacl/SDL_nacl_main.c create mode 100644 src/video/nacl/SDL_naclevents.c create mode 100644 src/video/nacl/SDL_naclevents_c.h create mode 100644 src/video/nacl/SDL_naclglue.c create mode 100644 src/video/nacl/SDL_naclopengles.c create mode 100644 src/video/nacl/SDL_naclopengles.h create mode 100644 src/video/nacl/SDL_naclvideo.c create mode 100644 src/video/nacl/SDL_naclvideo.h create mode 100644 src/video/nacl/SDL_naclwindow.c create mode 100644 src/video/nacl/SDL_naclwindow.h create mode 100644 test/nacl/background.js create mode 100644 test/nacl/common.js create mode 100644 test/nacl/index.html create mode 100644 test/nacl/manifest.json diff --git a/README-nacl.txt b/README-nacl.txt new file mode 100644 index 000000000..f2e562264 --- /dev/null +++ b/README-nacl.txt @@ -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) + diff --git a/WhatsNew.txt b/WhatsNew.txt index cadd3157d..48209e85b 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -9,6 +9,7 @@ General: * 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: diff --git a/build-scripts/config.sub b/build-scripts/config.sub index bdda9e4a3..1d3e5d063 100644 --- a/build-scripts/config.sub +++ b/build-scripts/config.sub @@ -359,6 +359,19 @@ case $basic_machine in 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 @@ case $basic_machine in basic_machine=le32-unknown os=-nacl ;; + pnacl) + basic_machine=le32-unknown + os=-pnacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -1384,6 +1401,12 @@ case $os in ;; esac ;; + -nacl*) + os=-nacl + ;; + -pnacl*) + os=-pnacl + ;; -nto-qnx*) ;; -nto*) @@ -1506,6 +1529,10 @@ case $os in os=-dicos ;; -nacl*) + os=-nacl + ;; + -pnacl*) + os=-pnacl ;; -none) ;; diff --git a/build-scripts/naclbuild.sh b/build-scripts/naclbuild.sh new file mode 100644 index 000000000..56218061e --- /dev/null +++ b/build-scripts/naclbuild.sh @@ -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 diff --git a/configure b/configure index 6bbf71774..58cbd7520 100755 --- a/configure +++ b/configure @@ -18984,6 +18984,55 @@ _ACEOF 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 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h 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 diff --git a/configure.in b/configure.in index fa247f433..40b968864 100644 --- a/configure.in +++ b/configure.in @@ -1317,6 +1317,32 @@ AC_HELP_STRING([--enable-mir-shared], [dynamically load Mir support [[default=ma 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 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau 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 diff --git a/include/SDL_assert.h b/include/SDL_assert.h index 42348f7d1..c8a944d9c 100644 --- a/include/SDL_assert.h +++ b/include/SDL_assert.h @@ -51,7 +51,7 @@ assert can have unique static variables associated with it. /* 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 diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 884fd9bac..5f1d0db9b 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -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 diff --git a/include/SDL_main.h b/include/SDL_main.h index 2e8fae95e..5dd73a9f5 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -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 */ diff --git a/include/SDL_platform.h b/include/SDL_platform.h index 83381be91..e6b3e9d91 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -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 diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h index e404bae3c..2d583008a 100644 --- a/include/SDL_rwops.h +++ b/include/SDL_rwops.h @@ -220,6 +220,16 @@ extern DECLSPEC size_t SDLCALL SDL_WriteLE64(SDL_RWops * dst, Uint64 value); 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 diff --git a/src/SDL_log.c b/src/SDL_log.c index 56d0b4289..5ebab0152 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -413,6 +413,9 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, #endif #if HAVE_STDIO_H fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message); +#if __NACL__ + fflush(stderr); +#endif #endif } diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 6023182eb..2de22b280 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -51,6 +51,9 @@ extern AudioBootStrap QSAAUDIO_bootstrap; 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 ANDROIDAUD_bootstrap; 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 @@ static const AudioBootStrap *const bootstrap[] = { #if SDL_AUDIO_DRIVER_ESD &ESD_bootstrap, #endif +#if SDL_AUDIO_DRIVER_NACL + &NACLAUD_bootstrap, +#endif #if SDL_AUDIO_DRIVER_NAS &NAS_bootstrap, #endif diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c new file mode 100644 index 000000000..8b62f60fd --- /dev/null +++ b/src/audio/nacl/SDL_naclaudio.c @@ -0,0 +1,135 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 +}; diff --git a/src/audio/nacl/SDL_naclaudio.h b/src/audio/nacl/SDL_naclaudio.h new file mode 100644 index 000000000..4683c7850 --- /dev/null +++ b/src/audio/nacl/SDL_naclaudio.h @@ -0,0 +1,41 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 */ diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h index 144af245f..2a5403a4e 100644 --- a/src/dynapi/SDL_dynapi.h +++ b/src/dynapi/SDL_dynapi.h @@ -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 diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index 70f8b24d2..14f3cd1a7 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -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 @@ SDL_WriteBE64(SDL_RWops * dst, Uint64 value) 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: */ diff --git a/src/main/nacl/SDL_nacl_main.c b/src/main/nacl/SDL_nacl_main.c new file mode 100644 index 000000000..509f6415d --- /dev/null +++ b/src/main/nacl/SDL_nacl_main.c @@ -0,0 +1,77 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 diff --git a/src/render/opengles2/SDL_gles2funcs.h b/src/render/opengles2/SDL_gles2funcs.h index c2a20f7db..1ac53ee47 100644 --- a/src/render/opengles2/SDL_gles2funcs.h +++ b/src/render/opengles2/SDL_gles2funcs.h @@ -68,4 +68,4 @@ SDL_PROC(void, glFramebufferTexture2D, (GLenum, GLenum, GLenum, GLuint, GLint)) 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*)) diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index b570b2abd..d8902c682 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -141,12 +141,15 @@ SDL_SYS_SetupThread(const char *name) #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 @@ SDL_ThreadID(void) 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) { diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 35dd940c7..c2abe847f 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -381,6 +381,9 @@ extern VideoBootStrap DUMMY_bootstrap; #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); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index f642f7c25..aa5b2cf45 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -92,6 +92,9 @@ static VideoBootStrap *bootstrap[] = { #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 @@ SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pix } } } - + if (!renderer) { for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { SDL_GetRenderDriverInfo(i, &info); @@ -1239,7 +1242,7 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) } /* 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) { diff --git a/src/video/nacl/SDL_naclevents.c b/src/video/nacl/SDL_naclevents.c new file mode 100644 index 000000000..424535d90 --- /dev/null +++ b/src/video/nacl/SDL_naclevents.c @@ -0,0 +1,432 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 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); + } + } +} diff --git a/src/video/nacl/SDL_naclevents_c.h b/src/video/nacl/SDL_naclevents_c.h new file mode 100644 index 000000000..6e3436833 --- /dev/null +++ b/src/video/nacl/SDL_naclevents_c.h @@ -0,0 +1,30 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 */ diff --git a/src/video/nacl/SDL_naclglue.c b/src/video/nacl/SDL_naclglue.c new file mode 100644 index 000000000..722f26ef4 --- /dev/null +++ b/src/video/nacl/SDL_naclglue.c @@ -0,0 +1,24 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 diff --git a/src/video/nacl/SDL_naclopengles.c b/src/video/nacl/SDL_naclopengles.c new file mode 100644 index 000000000..081cc8a4f --- /dev/null +++ b/src/video/nacl/SDL_naclopengles.c @@ -0,0 +1,171 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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: */ diff --git a/src/video/nacl/SDL_naclopengles.h b/src/video/nacl/SDL_naclopengles.h new file mode 100644 index 000000000..d5c3e97ef --- /dev/null +++ b/src/video/nacl/SDL_naclopengles.h @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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: */ diff --git a/src/video/nacl/SDL_naclvideo.c b/src/video/nacl/SDL_naclvideo.c new file mode 100644 index 000000000..724d7bf3f --- /dev/null +++ b/src/video/nacl/SDL_naclvideo.c @@ -0,0 +1,183 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 diff --git a/src/video/nacl/SDL_naclvideo.h b/src/video/nacl/SDL_naclvideo.h new file mode 100644 index 000000000..7e1c77fe6 --- /dev/null +++ b/src/video/nacl/SDL_naclvideo.h @@ -0,0 +1,67 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 */ diff --git a/src/video/nacl/SDL_naclwindow.c b/src/video/nacl/SDL_naclwindow.c new file mode 100644 index 000000000..dca145291 --- /dev/null +++ b/src/video/nacl/SDL_naclwindow.c @@ -0,0 +1,74 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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: */ diff --git a/src/video/nacl/SDL_naclwindow.h b/src/video/nacl/SDL_naclwindow.h new file mode 100644 index 000000000..ee94e60c1 --- /dev/null +++ b/src/video/nacl/SDL_naclwindow.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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: */ diff --git a/test/nacl/background.js b/test/nacl/background.js new file mode 100644 index 000000000..5c3b1b7c9 --- /dev/null +++ b/test/nacl/background.js @@ -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('', {...}); + // + // 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); diff --git a/test/nacl/common.js b/test/nacl/common.js new file mode 100644 index 000000000..a108fad32 --- /dev/null +++ b/test/nacl/common.js @@ -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 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 element is wrapped inside a
, 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 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); + } + } +}); diff --git a/test/nacl/index.html b/test/nacl/index.html new file mode 100644 index 000000000..4695b7e9c --- /dev/null +++ b/test/nacl/index.html @@ -0,0 +1,21 @@ + + + + + + + SDL NACL Test + + + +

SDL NACL Test

+

Status: NO-STATUS

+ +
+ + diff --git a/test/nacl/manifest.json b/test/nacl/manifest.json new file mode 100644 index 000000000..df6772b4c --- /dev/null +++ b/test/nacl/manifest.json @@ -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": [] +} diff --git a/test/testgles2.c b/test/testgles2.c index c4a62d5aa..8d0ac0aec 100644 --- a/test/testgles2.c +++ b/test/testgles2.c @@ -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 @@ process_shader(GLuint *shader, const char * source, GLint shader_type) { 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 @@ process_shader(GLuint *shader, const char * source, GLint shader_type) /* 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 @@ main(int argc, char *argv[]) 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; diff --git a/test/testrendercopyex.c b/test/testrendercopyex.c index 95a77a17f..086d64b0b 100644 --- a/test/testrendercopyex.c +++ b/test/testrendercopyex.c @@ -161,6 +161,16 @@ main(int argc, char *argv[]) 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];