| Index: native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/3D-graphics.html
|
| diff --git a/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/3D-graphics.html b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/3D-graphics.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0e7cdb183833e7fcc98df960f44c4376c83f73ef
|
| --- /dev/null
|
| +++ b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/3D-graphics.html
|
| @@ -0,0 +1,442 @@
|
| +{{+bindTo:partials.standard_nacl_article}}
|
| +
|
| +<section id="d-graphics">
|
| +<span id="devguide-coding-3d-graphics"></span><h1 id="d-graphics"><span id="devguide-coding-3d-graphics"></span>3D Graphics</h1>
|
| +<p>Native Client applications use the <a class="reference external" href="http://en.wikipedia.org/wiki/OpenGL_ES">OpenGL ES 2.0</a> API for 3D rendering. This document
|
| +describes how to call the OpenGL ES 2.0 interface in a Native Client module and
|
| +how to build an efficient rendering loop. It also explains how to validate GPU
|
| +drivers and test for specific GPU capabilities, and provides tips to help ensure
|
| +your rendering code runs efficiently.</p>
|
| +<aside class="note">
|
| +<strong>Note</strong>: 3D drawing and OpenGL are complex topics. This document deals only
|
| +with issues directly related to programming in the Native Client
|
| +environment. To learn more about OpenGL ES 2.0 itself, see the <a class="reference external" href="http://opengles-book.com/">OpenGL ES 2.0
|
| +Programming Guide</a>.
|
| +</aside>
|
| +<section id="validating-the-client-graphics-platform">
|
| +<h2 id="validating-the-client-graphics-platform">Validating the client graphics platform</h2>
|
| +<p>Native Client is a software technology that lets you code an application once
|
| +and run it on multiple platforms without worrying about the implementation
|
| +details on every possible target platform. It’s difficult to provide the same
|
| +support at the hardware level. Graphics hardware comes from many different
|
| +manufacturers and is controlled by drivers of varying quality. A particular GPU
|
| +driver may not support every OpenGL ES 2.0 feature, and some drivers are known
|
| +to have vulnerabilities that can be exploited.</p>
|
| +<p>Even if the GPU driver is safe to use, your program should perform a validation
|
| +check before you launch your application to ensure that the driver supports all
|
| +the features you need.</p>
|
| +<section id="vetting-the-driver-in-javascript">
|
| +<h3 id="vetting-the-driver-in-javascript">Vetting the driver in JavaScript</h3>
|
| +<p>At startup, the application should perform a few additional tests that can be
|
| +implemented in JavaScript on its hosting web page. The script that performs
|
| +these tests should be included before the module’s <code>embed</code> tag, and ideally
|
| +the <code>embed</code> tag should appear on the hosting page only if these tests succeed.</p>
|
| +<p>The first thing to check is whether you can create a graphics context. If you
|
| +can, use the context to confirm the existence of any required OpenGL ES 2.0
|
| +extensions. You may want to refer to the <a class="reference external" href="http://www.khronos.org/registry/webgl/extensions/">extension registry</a> and include <a class="reference external" href="https://developer.mozilla.org/en-US/docs/WebGL/Using_Extensions">vendor
|
| +prefixes</a>
|
| +when checking for extensions.</p>
|
| +</section><section id="vetting-the-driver-in-native-client">
|
| +<h3 id="vetting-the-driver-in-native-client">Vetting the driver in Native Client</h3>
|
| +<section id="create-a-context">
|
| +<h4 id="create-a-context">Create a context</h4>
|
| +<p>Once you’ve passed the JavaScript validation tests, it’s safe to add a Native
|
| +Client embed tag to the hosting web page and load the module. As part of the
|
| +module initialization code, you must create a graphics context for the app by
|
| +either creating a C++ <code>Graphics3D</code> object or calling <code>PPB_Graphics3D</code> API
|
| +function <code>Create</code>. Don’t assume this will always succeed; you still might have
|
| +problems creating the context. If you are in development mode and can’t create
|
| +the context, try creating a simpler version to see if you’re asking for an
|
| +unsupported feature or exceeding a driver resource limit. Your production code
|
| +should always check that the context was created and fail gracefully if that’s
|
| +not the case.</p>
|
| +</section><section id="check-for-extensions-and-capabilities">
|
| +<h4 id="check-for-extensions-and-capabilities">Check for extensions and capabilities</h4>
|
| +<p>Not every GPU supports every extension or has the same amount of texture units,
|
| +vertex attributes, etc. On startup, call <code>glGetString(GL_EXTENSIONS)</code> and
|
| +check for the extensions and the features you need. For example:</p>
|
| +<ul class="small-gap">
|
| +<li>If you are using non power-of-2 texture with mipmaps, make sure
|
| +<code>GL_OES_texture_npot</code> exists.</li>
|
| +<li>If you are using floating point textures, make sure <code>GL_OES_texture_float</code>
|
| +exists.</li>
|
| +<li>If you are using DXT1, DXT3, or DXT5 textures, make sure the corresponding
|
| +extensions <code>EXT_texture_compression_dxt1</code>,
|
| +<code>GL_CHROMIUM_texture_compression_dxt3</code>, and
|
| +<code>GL_CHROMIUM_texture_compression_dxt5</code> exist.</li>
|
| +<li>If you are using the functions <code>glDrawArraysInstancedANGLE</code>,
|
| +<code>glDrawElementsInstancedANGLE</code>, <code>glVertexAttribDivisorANGLE</code>, or the PPAPI
|
| +interface <code>PPB_OpenGLES2InstancedArrays</code>, make sure the corresponding
|
| +extension <code>GL_ANGLE_instanced_arrays</code> exists.</li>
|
| +<li>If you are using the function <code>glRenderbufferStorageMultisampleEXT</code>, or the
|
| +PPAPI interface <code>PPB_OpenGLES2FramebufferMultisample</code>, make sure the
|
| +corresponding extension <code>GL_CHROMIUM_framebuffer_multisample</code> exists.</li>
|
| +<li>If you are using the functions <code>glGenQueriesEXT</code>, <code>glDeleteQueriesEXT</code>,
|
| +<code>glIsQueryEXT</code>, <code>glBeginQueryEXT</code>, <code>glEndQueryEXT</code>, <code>glGetQueryivEXT</code>,
|
| +<code>glGetQueryObjectuivEXT</code>, or the PPAPI interface <code>PPB_OpenGLES2Query</code>,
|
| +make sure the corresponding extension <code>GL_EXT_occlusion_query_boolean</code>
|
| +exists.</li>
|
| +<li>If you are using the functions <code>glMapBufferSubDataCHROMIUM</code>,
|
| +<code>glUnmapBufferSubDataCHROMIUM</code>, <code>glMapTexSubImage2DCHROMIUM</code>,
|
| +<code>glUnmapTexSubImage2DCHROMIUM</code>, or the PPAPI interface
|
| +<code>PPB_OpenGLES2ChromiumMapSub</code>, make sure the corresponding extension
|
| +<code>GL_CHROMIUM_map_sub</code> exists.</li>
|
| +</ul>
|
| +<p>Check for system capabilites with <code>glGetIntegerv</code> and adjust shader programs
|
| +as well as texture and vertex data accordingly:</p>
|
| +<ul class="small-gap">
|
| +<li>If you are using textures in vertex shaders, make sure
|
| +<code>glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, ...)</code> and
|
| +<code>glGetIntegerv(GL_MAX_TEXTURE_SIZE, ...)</code> return values greater than 0.</li>
|
| +<li>If you are using more than 8 textures in a single shader, make sure
|
| +<code>glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)</code> returns a value greater
|
| +than or equal to the number of simultaneous textures you need.</li>
|
| +</ul>
|
| +</section></section><section id="vetting-the-driver-in-the-chrome-web-store">
|
| +<h3 id="vetting-the-driver-in-the-chrome-web-store">Vetting the driver in the Chrome Web Store</h3>
|
| +<p>If you choose to place your application in the <a class="reference external" href="https://developers.google.com/chrome/web-store/docs/">Chrome Web
|
| +Store</a>, its Web Store
|
| +<a class="reference external" href="http://code.google.com/chrome/extensions/manifest.html">manifest file</a> can
|
| +include the <code>webgl</code> feature in the requirements parameter. It looks like this:</p>
|
| +<pre class="prettyprint">
|
| +"requirements": {
|
| + "3D": {
|
| + "features": ["webgl"]
|
| + }
|
| +}
|
| +</pre>
|
| +<p>While WebGL is technically a JavaScript API, specifying the <code>webgl</code> feature
|
| +also works for OpenGL ES 2.0 because both interfaces use the same driver.</p>
|
| +<p>This manifest item is not required, but if you include it, the Chrome Web Store
|
| +will prevent a user from installing the application if the browser is running on
|
| +a machine that does not support OpenGL ES 2.0 or that is using a known
|
| +blacklisted GPU driver that could invite an attack.</p>
|
| +<p>If the Web Store determines that the user’s driver is deficient, the app won’t
|
| +appear on the store’s tile display. However, it will appear in store search
|
| +results or if the user links to it directly, in which case the user could still
|
| +download it. But the manifest requirements will be checked when the user reaches
|
| +the install page, and if there is a problem, the browser will display the
|
| +message “This application is not supported on this computer. Installation has
|
| +been disabled.”</p>
|
| +<p>The manifest-based check applies only to downloads directly from the Chrome Web
|
| +Store. It is not performed when an application is loaded via <a class="reference external" href="https://developers.google.com/chrome/web-store/docs/inline_installation">inline
|
| +installation</a>.</p>
|
| +</section><section id="what-to-do-when-there-are-problems">
|
| +<h3 id="what-to-do-when-there-are-problems">What to do when there are problems</h3>
|
| +<p>Using the vetting procedure described above, you should be able to detect the
|
| +most common problems before your application runs. If there are problems, your
|
| +code should describe the issue as clearly as possible. That’s easy if there is a
|
| +missing feature. Failure to create a graphics context is tougher to diagnose. At
|
| +the very least, you can suggest that the user try to update the driver. You
|
| +might want to linke to the Chrome page that describes <a class="reference external" href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=1202946">how to do updates</a>.</p>
|
| +<p>If a user can’t update the driver, or their problem persists, be sure to gather
|
| +information about their graphics environment. Ask for the contents of the Chrome
|
| +<code>about:gpu</code> page.</p>
|
| +</section><section id="document-unreliable-drivers">
|
| +<h3 id="document-unreliable-drivers">Document unreliable drivers</h3>
|
| +<p>It can be helpful to include information about known dubious drivers in your
|
| +user documentation. This might help identify if a rogue driver is the cause of a
|
| +problem. There are many sources of GPU driver blacklists. Two such lists can be
|
| +found at the <a class="reference external" href="http://src.chromium.org/viewvc/chrome/trunk/deps/gpu/software_rendering_list/software_rendering_list.json">Chromium project</a>
|
| +and <a class="reference external" href="http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists">Khronos</a>. You
|
| +can use these lists to include information in your documentation that warns
|
| +users about dangerous drivers.</p>
|
| +</section><section id="test-your-defenses">
|
| +<h3 id="test-your-defenses">Test your defenses</h3>
|
| +<p>You can test your driver validation code by running Chrome with the following
|
| +flags (all at once) and watching how your application responds:</p>
|
| +<ul class="small-gap">
|
| +<li><code>--disable-webgl</code></li>
|
| +<li><code>--disable-pepper-3d</code></li>
|
| +<li><code>--disable-gl-multisampling</code></li>
|
| +<li><code>--disable-accelerated-compositing</code></li>
|
| +<li><code>--disable-accelerated-2d-canvas</code></li>
|
| +</ul>
|
| +</section></section><section id="calling-opengl-es-2-0-commands">
|
| +<h2 id="calling-opengl-es-2-0-commands">Calling OpenGL ES 2.0 commands</h2>
|
| +<p>There are three ways to write OpenGL ES 2.0 calls in Native Client.</p>
|
| +<section id="use-pure-opengl-es-2-0-function-calls">
|
| +<h3 id="use-pure-opengl-es-2-0-function-calls">Use “pure” OpenGL ES 2.0 function calls</h3>
|
| +<p>You can make OpenGL ES 2.0 calls through a Pepper extension library. The SDK
|
| +example <code>examples/api/graphics_3d</code> works this way. In the file
|
| +<code>graphics_3d.cc</code>, the key initialization steps are as follows:</p>
|
| +<ul class="small-gap">
|
| +<li><p class="first">Add these includes at the top of the file:</p>
|
| +<pre class="prettyprint">
|
| +#include <GLES2/gl2.h>
|
| +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
|
| +</pre>
|
| +</li>
|
| +<li><p class="first">Define the function <code>InitGL</code>. The exact specification of <code>attrib_list</code>
|
| +will be application specific.</p>
|
| +<pre class="prettyprint">
|
| +bool InitGL(int32_t new_width, int32_t new_height) {
|
| + if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
|
| + fprintf(stderr, "Unable to initialize GL PPAPI!\n");
|
| + return false;
|
| + }
|
| +
|
| + const int32_t attrib_list[] = {
|
| + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
|
| + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
|
| + PP_GRAPHICS3DATTRIB_WIDTH, new_width,
|
| + PP_GRAPHICS3DATTRIB_HEIGHT, new_height,
|
| + PP_GRAPHICS3DATTRIB_NONE
|
| + };
|
| +
|
| + context_ = pp::Graphics3D(this, attrib_list);
|
| + if (!BindGraphics(context_)) {
|
| + fprintf(stderr, "Unable to bind 3d context!\n");
|
| + context_ = pp::Graphics3D();
|
| + glSetCurrentContextPPAPI(0);
|
| + return false;
|
| + }
|
| +
|
| + glSetCurrentContextPPAPI(context_.pp_resource());
|
| + return true;
|
| +}
|
| +</pre>
|
| +</li>
|
| +<li>Include logic in <code>Instance::DidChangeView</code> to call <code>InitGL</code> whenever
|
| +necessary: upon application launch (when the graphics context is NULL) and
|
| +whenever the module’s View changes size.</li>
|
| +</ul>
|
| +</section><section id="use-regal">
|
| +<h3 id="use-regal">Use Regal</h3>
|
| +<p>If you are porting an OpenGL ES 2.0 application, or are comfortable writing in
|
| +OpenGL ES 2.0, you should stick with the Pepper APIs or pure OpenGL ES 2.0 calls
|
| +described above. If you are porting an application that uses features not in
|
| +OpenGL ES 2.0, consider using Regal. Regal is an open source library that
|
| +supports many versions of OpenGL. Regal recently added support for Native
|
| +Client. Regal forwards most OpenGL calls directly to the underlying graphics
|
| +library, but it can also emulate other calls that are not included (when
|
| +hardware support exists). See <a class="reference external" href="http://www.altdevblogaday.com/2012/09/04/bringing-regal-opengl-to-native-client/">libregal</a>
|
| +for more info.</p>
|
| +</section><section id="use-the-pepper-api">
|
| +<h3 id="use-the-pepper-api">Use the Pepper API</h3>
|
| +<p>Your code can call the Pepper <a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___open_g_l_e_s2">PPB_OpenGLES2</a>
|
| +API directly, as with any Pepper interface. When you write in this way, each
|
| +invocation of an OpenGL ES 2.0 function must begin with a reference to the
|
| +Pepper interface, and the first argument is the graphics context. To invoke the
|
| +function <code>glCompileShader</code>, your code might look like:</p>
|
| +<pre class="prettyprint">
|
| +ppb_g3d_interface->CompileShader(graphicsContext, shader);
|
| +</pre>
|
| +<p>This approach specifically targets the Pepper APIs. Each call corresponds to a
|
| +OpenGL ES 2.0 function, but the syntax is unique to Native Client, so the source
|
| +file is not portable.</p>
|
| +</section></section><section id="implementing-a-rendering-loop">
|
| +<h2 id="implementing-a-rendering-loop">Implementing a rendering loop</h2>
|
| +<p>Graphics applications require a continuous frame render-and-redraw cycle that
|
| +runs at a high frequency. To achieve the best frame rate, is important to
|
| +understand how the OpenGL ES 2.0 code in a Native Client module interacts with
|
| +Chrome.</p>
|
| +<section id="the-chrome-and-native-client-processes">
|
| +<h3 id="the-chrome-and-native-client-processes">The Chrome and Native Client processes</h3>
|
| +<p>Chrome is a multi-process browser. Each Chrome tab is a separate process that is
|
| +running an application with its own main thread (we’ll call it the Chrome main
|
| +thread). When an application launches a Native Client module, the module runs in
|
| +a new, separate sandboxed process. The module’s process has its own main thread
|
| +(the Native Client thread). The Chrome and Native Client processes communicate
|
| +with each other using Pepper API calls on their main threads.</p>
|
| +<p>When the Chrome main thread calls the Native Client thread (keyboard and mouse
|
| +callbacks, for example), the Chrome main thread will block. This means that
|
| +lengthy operations on the Native Client thread can steal cycles from Chrome, and
|
| +performing blocking operations on the Native Client thread can bring your app to
|
| +a standstill.</p>
|
| +<p>Native Client uses callback functions to synchronize the main threads of the two
|
| +processes. Only certain Pepper functions use callbacks; <a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___graphics3_d__1__0#a293c6941c0da084267ffba3954793497">SwapBuffers</a>
|
| +is one.</p>
|
| +</section><section id="swapbuffers-and-its-callback-function">
|
| +<h3 id="swapbuffers-and-its-callback-function"><code>SwapBuffers</code> and its callback function</h3>
|
| +<p><code>SwapBuffers</code> is non-blocking; it is called from the Native Client thread and
|
| +returns immediately. When <code>SwapBuffers</code> is called, it runs asynchronously on
|
| +the Chrome main thread. It switches the graphics data buffers, handles any
|
| +needed compositing operations, and redraws the screen. When the screen update is
|
| +complete, the callback function that was included as one of <code>SwapBuffer</code>‘s
|
| +arguments will be called from the Chrome thread and executed on the Native
|
| +Client thread.</p>
|
| +<p>To create a rendering loop, your Native Client module should include a function
|
| +that does the rendering work and then executes <code>SwapBuffers</code>, passing itself
|
| +as the <code>SwapBuffer</code> callback. If your rendering code is efficient and runs
|
| +quickly, this scheme will achieve the highest frame rate possible. The
|
| +documentation for <code>SwapBuffers</code> explains why this is optimal: because the
|
| +callback is executed only when the plugin’s current state is actually on the
|
| +screen, this function provides a way to rate-limit animations. By waiting until
|
| +the image is on the screen before painting the next frame, you can ensure you’re
|
| +not generating updates faster than the screen can be updated.</p>
|
| +<p>The following diagram illustrates the interaction between the Chrome and Native
|
| +Client processes. The application-specific rendering code runs in the function
|
| +called <code>Draw</code> on the Native Client thread. Blue down-arrows are blocking calls
|
| +from the main thread to Native Client, green up-arrows are non-blocking
|
| +<code>SwapBuffers</code> calls from Native Client to the main thread. All OpenGL ES 2.0
|
| +calls are made from <code>Draw</code> in the Native Client thread.</p>
|
| +<img alt="/native-client/images/3d-graphics-render-loop.png" src="/native-client/images/3d-graphics-render-loop.png" />
|
| +</section><section id="sdk-example-graphics-3d">
|
| +<h3 id="sdk-example-graphics-3d">SDK example <code>graphics_3d</code></h3>
|
| +<p>The SDK example <code>graphics_3d</code> uses the function <code>MainLoop</code> (in
|
| +<code>hello_world.cc</code>) to create a rendering loop as described above. <code>MainLoop</code>
|
| +calls <code>Render</code> to do the rendering work, and then invokes <code>SwapBuffers</code>,
|
| +passing itself as the callback.</p>
|
| +<pre class="prettyprint">
|
| +void MainLoop(void* foo, int bar) {
|
| + if (g_LoadCnt == 3) {
|
| + InitProgram();
|
| + g_LoadCnt++;
|
| + }
|
| + if (g_LoadCnt > 3) {
|
| + Render();
|
| + PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
|
| + ppb_g3d_interface->SwapBuffers(g_context, cc);
|
| + } else {
|
| + PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0);
|
| + ppb_core_interface->CallOnMainThread(0, cc, 0);
|
| + }
|
| +}
|
| +</pre>
|
| +</section></section><section id="managing-the-opengl-es-2-0-pipeline">
|
| +<h2 id="managing-the-opengl-es-2-0-pipeline">Managing the OpenGL ES 2.0 pipeline</h2>
|
| +<p>OpenGL ES 2.0 commands do not run in the Chrome or Native Client processes. They
|
| +are passed into a FIFO queue in shared memory which is best understood as a <a class="reference external" href="http://www.chromium.org/developers/design-documents/gpu-command-buffer">GPU
|
| +command buffer</a>. The
|
| +command buffer is shared by a dedicated GPU process. By using a separate GPU
|
| +process, Chrome implements another layer of runtime security, vetting all OpenGL
|
| +ES 2.0 commands and their arguments before they are sent on to the
|
| +GPU. Buffering commands through the FIFO also speeds up your code, since each
|
| +OpenGL ES 2.0 call in your Native Client thread returns immediately, while the
|
| +processing may be delayed as the GPU works down the commands queued up in the
|
| +FIFO.</p>
|
| +<p>Before the screen is updated, all the intervening OpenGL ES 2.0 commands must be
|
| +processed by the GPU. Programmers often try to ensure this by using the
|
| +<code>glFlush</code> and <code>glFinish</code> commands in their rendering code. In the case of
|
| +Native Client this is usually unnecessary. The <code>SwapBuffers</code> command does an
|
| +implicit flush, and the Chrome team is continually tweaking the GPU code to
|
| +consume the OpenGL ES 2.0 FIFO as fast as possible.</p>
|
| +<p>Sometimes a 3D application can write to the FIFO in a way that’s difficult to
|
| +handle. The command pipeline may fill up and your code will have to wait for the
|
| +GPU to flush the FIFO. If this is the case, you may be able to add <code>glFlush</code>
|
| +calls to speed up the flow of the OpenGL ES 2.0 command FIFO. Before you start
|
| +to add your own flushes, first try to determine if pipeline saturation is really
|
| +the problem by monitoring the rendering time per frame and looking for irregular
|
| +spikes that do not consistently fall on the same OpenGL ES 2.0 call. If you’re
|
| +convinced the pipeline needs to be accelerated, insert <code>glFlush</code> calls in your
|
| +code before starting blocks of processing that do not generate OpenGL ES 2.0
|
| +commands. For example, issue a flush before you begin any multithreaded particle
|
| +work, so that the command buffer will be clear when you start doing OpenGL ES
|
| +2.0 calls again. Determining where and how often to call <code>glFlush</code> can be
|
| +tricky, you will need to experiment to find the sweet spot.</p>
|
| +</section><section id="rendering-and-inactive-tabs">
|
| +<h2 id="rendering-and-inactive-tabs">Rendering and inactive tabs</h2>
|
| +<p>Users will often switch between tabs in a multi-tab browser. A well-behaved
|
| +application that’s performing 3D rendering should pause any real-time processing
|
| +and yield cycles to other processes when its tab becomes inactive.</p>
|
| +<p>In Chrome, an inactive tab will continue to execute timed functions (such as
|
| +<code>setInterval</code> and <code>setTimeout</code>) but the timer interval will be automatically
|
| +overridden and limited to not less than one second while the tab is inactive. In
|
| +addition, any callback associated with a <code>SwapBuffers</code> call will not be sent
|
| +until the tab is active again. You may receive asynchronous callbacks from
|
| +functions other than <code>SwapBuffers</code> while a tab is inactive. Depending on the
|
| +design of your application, you might choose to handle them as they arrive, or
|
| +to queue them in a buffer and process them when the tab becomes active.</p>
|
| +<p>The time that passes while a tab is inactive can be considerable. If your main
|
| +thread pulse is based on the <code>SwapBuffers</code> callback, your app won’t update
|
| +while a tab is inactive. A Native Client module should be able to detect and
|
| +respond to the state of the tab in which it’s running. For example, when a tab
|
| +becomes inactive, you can set an atomic flag in the Native Client thread that
|
| +will skip the 3D rendering and <code>SwapBuffers</code> calls and continue to call the
|
| +main thread every 30 msec or so. This provides time to update features that
|
| +should still run in the background, like audio. It may also be helpful to call
|
| +<code>sched_yield</code> or <code>usleep</code> on any worker threads to release resources and
|
| +cede cycles to the OS.</p>
|
| +<section id="handling-tab-activation-from-the-main-thread">
|
| +<h3 id="handling-tab-activation-from-the-main-thread">Handling tab activation from the main thread</h3>
|
| +<p>You can detect and respond to the activation or deactivation of a tab with
|
| +JavaScript on your hosting page. Add an EventListener for <code>visibilitychange</code>
|
| +that sends a message to the Native Client module, as in this example:</p>
|
| +<pre class="prettyprint">
|
| +document.addEventListener('visibilitychange', function(){
|
| + if (document.hidden) {
|
| + // PostMessage to your Native Client module
|
| + document.nacl_module.postMessage('INACTIVE');
|
| + } else {
|
| + // PostMessage to your Native Client module
|
| + document.nacl_module.postMessage('ACTIVE');
|
| + }
|
| +
|
| +}, false);
|
| +</pre>
|
| +</section><section id="handling-tab-activation-from-the-native-client-thread">
|
| +<h3 id="handling-tab-activation-from-the-native-client-thread">Handling tab activation from the Native Client thread</h3>
|
| +<p>You can also detect and respond to the activation or deactivation of a tab
|
| +directly from your Native Client module by including code in the function
|
| +<code>pp::Instance::DidChangeView</code>, which is called whenever a change in the
|
| +module’s view occurs. The code can call <code>ppb::View::IsPageVisible</code> to
|
| +determine if the page is visible or not. The most common cause of invisible
|
| +pages is that the page is in a background tab.</p>
|
| +</section></section><section id="tips-and-best-practices">
|
| +<h2 id="tips-and-best-practices">Tips and best practices</h2>
|
| +<p>Here are some suggestions for writing safe code and getting the maximum
|
| +performance with the Pepper 3D API.</p>
|
| +<section id="do-s">
|
| +<h3 id="do-s">Do’s</h3>
|
| +<ul class="small-gap">
|
| +<li><p class="first"><strong>Make sure to enable attrib 0.</strong> OpenGL requires that you enable attrib 0,
|
| +but OpenGL ES 2.0 does not. For example, you can define a vertex shader with 2
|
| +attributes, numbered like this:</p>
|
| +<pre class="prettyprint">
|
| +glBindAttribLocation(program, "positions", 1);
|
| +glBindAttribLocation(program, "normals", 2);
|
| +</pre>
|
| +<p>In this case the shader is not using attrib 0 and Chrome may have to perform
|
| +some additional work if it is emulating OpenGL ES 2.0 on top of OpenGL. It’s
|
| +always more efficient to enable attrib 0, even if you do not use it.</p>
|
| +</li>
|
| +<li><strong>Check how shaders compile.</strong> Shaders can compile differently on different
|
| +systems, which can result in <code>glGetAttrib*</code> functions returning different
|
| +results. Be sure that the vertex attribute indices match the corresponding
|
| +name each time you recompile a shader.</li>
|
| +<li><strong>Update indices sparingly.</strong> For security reasons, all indices must be
|
| +validated. If you change indices, Native Client will validate them
|
| +again. Structure your code so indices are not updated often.</li>
|
| +<li><strong>Use a smaller plugin and let CSS scale it.</strong> If you’re running into fillrate
|
| +issues, it may be beneficial to perform scaling via CSS. The size your plugin
|
| +renders is determined by the width and height attributes of the <code><embed></code>
|
| +element for the module. The actual size displayed on the web page is
|
| +controlled by the CSS styles applied to the element.</li>
|
| +<li><strong>Avoid matrix-to-matrix conversions.</strong> With some versions of Mac OS, there is
|
| +a driver problem when compiling shaders. If you get compiler errors for matrix
|
| +transforms, avoid matrix-to-matrix conversions. For instance, upres a vec3 to
|
| +a vec4 before transforming it by a mat4, rather than converting the mat4 to a
|
| +mat3.</li>
|
| +</ul>
|
| +</section><section id="don-ts">
|
| +<h3 id="don-ts">Don’ts</h3>
|
| +<ul class="small-gap">
|
| +<li><strong>Don’t use client side buffers.</strong> OpenGL ES 2.0 can use client side data with
|
| +<code>glVertexAttribPointer</code> and <code>glDrawElements</code>, but this is really slow. Try
|
| +to avoid client side buffers. Use Vertex Buffer Objects (VBOs) instead.</li>
|
| +<li><strong>Don’t mix vertex data and index data.</strong> By default, Pepper 3D binds buffers
|
| +to a single point. You could create a buffer and bind it to both
|
| +<code>GL_ARRAY_BUFFER</code> and <code>GL_ELEMENT_ARRAY_BUFFER</code>, but that would be
|
| +expensive overhead and it is not recommended.</li>
|
| +<li><strong>Don’t call ``glGet*`` or ``glCheck*`` during rendering.</strong> This is normal
|
| +advice for OpenGL programs, but is particularly important for 3D on
|
| +Chrome. Calls to any OpenGL ES 2.0 function whose name begins with these
|
| +strings blocks the Native Client thread. This includes <code>glGetError</code>; avoid
|
| +calling it in release builds.</li>
|
| +<li><strong>Don’t use fixed point (``GL_FIXED``) vertex attributes.</strong> Fixed point
|
| +attributes are not supported in OpenGL ES 2.0, so emulating them in OpenGL ES
|
| +2.0 is slow. By default, <code>GL_FIXED</code> support is turned off in the Pepper 3D
|
| +API.</li>
|
| +<li><strong>Don’t read data from the GPU.</strong> Don’t call <code>glReadPixels</code>, as it is slow.</li>
|
| +<li><strong>Don’t update a small portion of a large buffer.</strong> In the current OpenGL ES
|
| +2.0 implementation when you update a portion of a buffer (with
|
| +<code>glSubBufferData</code> for example) the entire buffer must be reprocessed. To
|
| +avoid this problem, keep static and dynamic data in different buffers.</li>
|
| +<li><strong>Don’t call ``glDisable(GL_TEXTURE_2D)``.</strong> This is an OpenGL ES 2.0
|
| +error. Each time it is called, an error messages will appear in Chrome’s
|
| +<code>about:gpu</code> tab.</li>
|
| +</ul>
|
| +</section></section></section>
|
| +
|
| +{{/partials.standard_nacl_article}}
|
|
|