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}} |