From 7b68dc2e0ae3ed1531f2605b5fce871c7c1d6c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 13 Jun 2013 17:37:47 +0200 Subject: [PATCH] Platform: added WindowlessNaClApplication. Stripped-down version of NaClApplication with unusable default framebuffer and no event handling, primarily for various testing usage. --- CMakeLists.txt | 1 + PKGBUILD-nacl-newlib | 2 + modules/FindMagnum.cmake | 4 +- src/Platform/CMakeLists.txt | 12 ++ src/Platform/WindowlessNaClApplication.cpp | 109 +++++++++++ src/Platform/WindowlessNaClApplication.h | 200 +++++++++++++++++++++ 6 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 src/Platform/WindowlessNaClApplication.cpp create mode 100644 src/Platform/WindowlessNaClApplication.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7778ddd04..883aef87f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ option(WITH_MAGNUMINFO "Build magnum-info utility" OFF) # Application libraries if(CORRADE_TARGET_NACL) option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF) + cmake_dependent_option(WITH_WINDOWLESSNACLAPPLICATION "Build WindowlessNaClApplication library" OFF "NOT WITH_MAGNUMINFO" ON) else() option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF) cmake_dependent_option(WITH_WINDOWLESSGLXAPPLICATION "Build WindowlessGlxApplication library" OFF "NOT WITH_MAGNUMINFO" ON) diff --git a/PKGBUILD-nacl-newlib b/PKGBUILD-nacl-newlib index 19d95f7c9..2bf84ac4e 100644 --- a/PKGBUILD-nacl-newlib +++ b/PKGBUILD-nacl-newlib @@ -22,6 +22,7 @@ build() { -DCMAKE_INSTALL_PREFIX=/usr/nacl \ -DWITH_MAGNUMINFO=OFF \ -DWITH_NACLAPPLICATION=ON \ + -DWITH_WINDOWLESSNACLAPPLICATION=ON \ -DBUILD_STATIC=ON \ -DLIB_SUFFIX=/32 make @@ -37,6 +38,7 @@ build() { -DCMAKE_INSTALL_PREFIX=/usr/nacl \ -DWITH_MAGNUMINFO=OFF \ -DWITH_NACLAPPLICATION=ON \ + -DWITH_WINDOWLESSNACLAPPLICATION=ON \ -DBUILD_STATIC=ON make } diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 7c871037a..768449907 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -185,8 +185,8 @@ foreach(component ${Magnum_FIND_COMPONENTS}) endif() endif() - # NaCl application dependencies - if(${component} STREQUAL NaClApplication) + # (Windowless) NaCl application dependencies + if(${component} STREQUAL NaClApplication OR ${component} STREQUAL WindowlessNaClApplication) set(_MAGNUM_${_COMPONENT}_LIBRARIES ppapi_cpp ppapi ${_WINDOWCONTEXT_MAGNUM_LIBRARIES_DEPENDENCY}) endif() diff --git a/src/Platform/CMakeLists.txt b/src/Platform/CMakeLists.txt index 6f7b75b18..4de76dcf2 100644 --- a/src/Platform/CMakeLists.txt +++ b/src/Platform/CMakeLists.txt @@ -72,6 +72,18 @@ if(WITH_NACLAPPLICATION) install(TARGETS MagnumNaClApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) endif() +# Windowless NaCl application +if(WITH_WINDOWLESSNACLAPPLICATION) + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL NaCl) + message(FATAL_ERROR "WindowlessNaClApplication is available only when targeting Google Chrome Native Client. Set WITH_WINDOWLESSNACLAPPLICATION to OFF to skip building it.") + endif() + + add_library(MagnumWindowlessNaClApplication STATIC + WindowlessNaClApplication.cpp) + install(FILES WindowlessNaClApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) + install(TARGETS MagnumWindowlessNaClApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +endif() + # GLX application if(WITH_GLXAPPLICATION) set(NEED_ABSTRACTXAPPLICATION 1) diff --git a/src/Platform/WindowlessNaClApplication.cpp b/src/Platform/WindowlessNaClApplication.cpp new file mode 100644 index 000000000..84c695b55 --- /dev/null +++ b/src/Platform/WindowlessNaClApplication.cpp @@ -0,0 +1,109 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "WindowlessNaClApplication.h" + +#include +#include +#include + +#include "Context.h" + +namespace Magnum { namespace Platform { + +struct WindowlessNaClApplication::ConsoleDebugOutput { + explicit ConsoleDebugOutput(pp::Instance* instance); + + Utility::NaClConsoleStreamBuffer debugBuffer, warningBuffer, errorBuffer; + std::ostream debugOutput, warningOutput, errorOutput; +}; + +WindowlessNaClApplication::ConsoleDebugOutput::ConsoleDebugOutput(pp::Instance* instance): debugBuffer(instance, Utility::NaClConsoleStreamBuffer::LogLevel::Log), warningBuffer(instance, Utility::NaClConsoleStreamBuffer::LogLevel::Warning), errorBuffer(instance, Utility::NaClConsoleStreamBuffer::LogLevel::Error), debugOutput(&debugBuffer), warningOutput(&warningBuffer), errorOutput(&errorBuffer) { + /* Inform about this change on standard output */ + Debug() << "Platform::NaClApplication: redirecting Debug, Warning and Error output to JavaScript console"; + + Debug::setOutput(&debugOutput); + Warning::setOutput(&warningOutput); + Error::setOutput(&errorOutput); +} + +WindowlessNaClApplication::WindowlessNaClApplication(const Arguments& arguments): Instance(arguments), Graphics3DClient(this), c(nullptr) { + debugOutput = new ConsoleDebugOutput(this); + createContext(new Configuration); +} + +WindowlessNaClApplication::WindowlessNaClApplication(const Arguments& arguments, Configuration* configuration): Instance(arguments), Graphics3DClient(this), graphics(nullptr), c(nullptr) { + debugOutput = new ConsoleDebugOutput(this); + if(configuration) createContext(configuration); +} + +void WindowlessNaClApplication::createContext(Configuration* configuration) { + if(!tryCreateContext(configuration)) { + Error() << "Platform::WindowlessNaClApplication::createContext(): cannot create context"; + delete configuration; + std::exit(1); + + } else delete configuration; +} + +bool WindowlessNaClApplication::tryCreateContext(Configuration* configuration) { + CORRADE_ASSERT(!c, "Platform::WindowlessNaClApplication::tryCreateContext(): context already created", false); + + const std::int32_t attributes[] = { + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, + PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, + PP_GRAPHICS3DATTRIB_WIDTH, 1, + PP_GRAPHICS3DATTRIB_HEIGHT, 1, + PP_GRAPHICS3DATTRIB_NONE + }; + + graphics = new pp::Graphics3D(this, attributes); + if(graphics->is_null()) { + delete graphics; + graphics = nullptr; + return false; + } + if(!BindGraphics(*graphics)) { + Error() << "Platform::WindowlessNaClApplication::tryCreateContext(): cannot bind graphics"; + std::exit(1); + } + + glSetCurrentContextPPAPI(graphics->pp_resource()); + + c = new Context; + return true; +} + +WindowlessNaClApplication::~WindowlessNaClApplication() { + delete c; + delete graphics; + delete debugOutput; +} + +bool WindowlessNaClApplication::Init(uint32_t , const char* , const char*) { + return exec() == 0; +} + +}} diff --git a/src/Platform/WindowlessNaClApplication.h b/src/Platform/WindowlessNaClApplication.h new file mode 100644 index 000000000..89685a3dc --- /dev/null +++ b/src/Platform/WindowlessNaClApplication.h @@ -0,0 +1,200 @@ +#ifndef Magnum_Platform_WindowlessNaClApplication_h +#define Magnum_Platform_WindowlessNaClApplication_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Platform::WindowlessNaClApplication + */ + +#include +#include +#include +#include +#include +#include + +#include "Math/Vector2.h" +#include "Magnum.h" + +#include "corradeCompatibility.h" + +namespace pp { + class Graphics3D; + class Fullscreen; +} + +namespace Magnum { namespace Platform { + +/** @nosubgrouping +@brief Windowless NaCl application + +Application running in [Google Chrome Native Client](https://developers.google.com/native-client/). +See @ref platform for brief introduction. + +@section WindowlessNaClApplication-usage Usage + +Place your code into exec(). The subclass must be then registered to NaCl API +using MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN() macro. +@code +class MyApplication: public Magnum::Platform::WindowlessNaClApplication { + // implement required methods... +}; +MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN(MyApplication) +@endcode + +If no other application header is included this class is also aliased to +`Platform::WindowlessApplication` and the macro is aliased to +`MAGNUM_WINDOWLESSAPPLICATION_MAIN()` to simplify porting. + +@section WindowlessNaClApplication-html HTML markup and NMF file + +You need to provide HTML markup containing `<embed>` pointing to `*.nmf` +file describing the application. + +@todoc Document this better, add "bootstrap" examples + +@subsection WindowlessNaClApplication-html-console Redirecting output to Chrome's JavaScript console + +The application redirects @ref Debug, @ref Warning and @ref Error output to +JavaScript console. See also @ref Corrade::Utility::NaClConsoleStreamBuffer for +more information. +*/ +class WindowlessNaClApplication: public pp::Instance, public pp::Graphics3DClient { + public: + /** @brief Application arguments */ + typedef PP_Instance Arguments; + + class Configuration; + + /** + * @brief Default constructor + * @param arguments Application arguments + * + * Creates application with default configuration. See Configuration + * for more information. + */ + explicit WindowlessNaClApplication(const Arguments& arguments); + + /** + * @brief Constructor + * @param arguments Application arguments + * @param configuration Configuration + * + * The @p configuration is deleted afterwards. If `nullptr` is passed + * as @p configuration, the context is not created and must be created + * with createContext(). + */ + explicit WindowlessNaClApplication(const Arguments& arguments, Configuration* configuration); + + /** + * @brief Execute application + * @return Value for returning from `main()`. + */ + virtual int exec() = 0; + + protected: + /* Nobody will need to have (and delete) WindowlessNaClApplication*, + thus this is faster than public pure virtual destructor */ + ~WindowlessNaClApplication(); + + /** @copydoc GlutApplication::createContext() */ + void createContext(Configuration* configuration); + + /** @copydoc GlutApplication::tryCreateContext() */ + bool tryCreateContext(Configuration* configuration); + + private: + struct ConsoleDebugOutput; + + void Graphics3DContextLost() override { + CORRADE_ASSERT(false, "NaClApplication: context unexpectedly lost", ); + } + + bool Init(std::uint32_t, const char*, const char*) override; + + pp::Graphics3D* graphics; + Context* c; + ConsoleDebugOutput* debugOutput; +}; + +/** +@brief %Configuration + +@see WindowlessNaClApplication(), createContext(), tryCreateContext() +*/ +class WindowlessNaClApplication::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + constexpr explicit Configuration() {} +}; + +namespace Implementation { + template class WindowlessNaClModule: public pp::Module { + public: + ~WindowlessNaClModule() { glTerminatePPAPI(); } + + bool Init() override { + return glInitializePPAPI(get_browser_interface()); + } + + pp::Instance* CreateInstance(PP_Instance instance) { + return new Application(instance); + } + }; +} + +/** @hideinitializer +@brief Entry point for windowless NaCl application +@param application Application class name + +See WindowlessNaClApplication and @ref portability-applications for more +information. When no other windowless application header is included this macro +is also aliased to `MAGNUM_WINDOWLESSAPPLICATION_MAIN()`. +*/ +/* look at that insane placement of __attribute__. WTF. */ +#define MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN(application) \ + namespace pp { \ + Module __attribute__ ((visibility ("default"))) * CreateModule(); \ + Module __attribute__ ((visibility ("default"))) * CreateModule() { \ + return new Magnum::Platform::Implementation::WindowlessNaClModule(); \ + } \ + } + +#ifndef DOXYGEN_GENERATING_OUTPUT +#ifndef MAGNUM_WINDOWLESSAPPLICATION_MAIN +typedef WindowlessNaClApplication WindowlessApplication; +#define MAGNUM_WINDOWLESSAPPLICATION_MAIN(className) MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN(className) +#else +#undef MAGNUM_WINDOWLESSAPPLICATION_MAIN +#endif +#endif + +}} + +#endif