1 {{+bindTo:partials.standard_nacl_article}}
3 <section id=
"d-graphics">
4 <span id=
"devguide-coding-3d-graphics"></span><h1 id=
"d-graphics"><span id=
"devguide-coding-3d-graphics"></span>3D Graphics
</h1>
5 <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
6 describes how to call the OpenGL ES
2.0 interface in a Native Client module and
7 how to build an efficient rendering loop. It also explains how to validate GPU
8 drivers and test for specific GPU capabilities, and provides tips to help ensure
9 your rendering code runs efficiently.
</p>
11 <strong>Note
</strong>:
3D drawing and OpenGL are complex topics. This document deals only
12 with issues directly related to programming in the Native Client
13 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
14 Programming Guide
</a>.
16 <h2 id=
"validating-the-client-graphics-platform">Validating the client graphics platform
</h2>
17 <p>Native Client is a software technology that lets you code an application once
18 and run it on multiple platforms without worrying about the implementation
19 details on every possible target platform. It
’s difficult to provide the same
20 support at the hardware level. Graphics hardware comes from many different
21 manufacturers and is controlled by drivers of varying quality. A particular GPU
22 driver may not support every OpenGL ES
2.0 feature, and some drivers are known
23 to have vulnerabilities that can be exploited.
</p>
24 <p>Even if the GPU driver is safe to use, your program should perform a validation
25 check before you launch your application to ensure that the driver supports all
26 the features you need.
</p>
27 <h3 id=
"vetting-the-driver-in-javascript">Vetting the driver in JavaScript
</h3>
28 <p>At startup, the application should perform a few additional tests that can be
29 implemented in JavaScript on its hosting web page. The script that performs
30 these tests should be included before the module
’s
<code>embed
</code> tag, and ideally
31 the
<code>embed
</code> tag should appear on the hosting page only if these tests succeed.
</p>
32 <p>The first thing to check is whether you can create a graphics context. If you
33 can, use the context to confirm the existence of any required OpenGL ES
2.0
34 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
36 when checking for extensions.
</p>
37 <h3 id=
"vetting-the-driver-in-native-client">Vetting the driver in Native Client
</h3>
38 <h4 id=
"create-a-context">Create a context
</h4>
39 <p>Once you
’ve passed the JavaScript validation tests, it
’s safe to add a Native
40 Client embed tag to the hosting web page and load the module. As part of the
41 module initialization code, you must create a graphics context for the app by
42 either creating a C++
<code>Graphics3D
</code> object or calling
<code>PPB_Graphics3D
</code> API
43 function
<code>Create
</code>. Don
’t assume this will always succeed; you still might have
44 problems creating the context. If you are in development mode and can
’t create
45 the context, try creating a simpler version to see if you
’re asking for an
46 unsupported feature or exceeding a driver resource limit. Your production code
47 should always check that the context was created and fail gracefully if that
’s
49 <h4 id=
"check-for-extensions-and-capabilities">Check for extensions and capabilities
</h4>
50 <p>Not every GPU supports every extension or has the same amount of texture units,
51 vertex attributes, etc. On startup, call
<code>glGetString(GL_EXTENSIONS)
</code> and
52 check for the extensions and the features you need. For example:
</p>
53 <ul class=
"small-gap">
54 <li>If you are using non power-of-
2 texture with mipmaps, make sure
55 <code>GL_OES_texture_npot
</code> exists.
</li>
56 <li>If you are using floating point textures, make sure
<code>GL_OES_texture_float
</code>
58 <li>If you are using DXT1, DXT3, or DXT5 textures, make sure the corresponding
59 extensions
<code>EXT_texture_compression_dxt1
</code>,
60 <code>GL_CHROMIUM_texture_compression_dxt3
</code>, and
61 <code>GL_CHROMIUM_texture_compression_dxt5
</code> exist.
</li>
62 <li>If you are using the functions
<code>glDrawArraysInstancedANGLE
</code>,
63 <code>glDrawElementsInstancedANGLE
</code>,
<code>glVertexAttribDivisorANGLE
</code>, or the PPAPI
64 interface
<code>PPB_OpenGLES2InstancedArrays
</code>, make sure the corresponding
65 extension
<code>GL_ANGLE_instanced_arrays
</code> exists.
</li>
66 <li>If you are using the function
<code>glRenderbufferStorageMultisampleEXT
</code>, or the
67 PPAPI interface
<code>PPB_OpenGLES2FramebufferMultisample
</code>, make sure the
68 corresponding extension
<code>GL_CHROMIUM_framebuffer_multisample
</code> exists.
</li>
69 <li>If you are using the functions
<code>glGenQueriesEXT
</code>,
<code>glDeleteQueriesEXT
</code>,
70 <code>glIsQueryEXT
</code>,
<code>glBeginQueryEXT
</code>,
<code>glEndQueryEXT
</code>,
<code>glGetQueryivEXT
</code>,
71 <code>glGetQueryObjectuivEXT
</code>, or the PPAPI interface
<code>PPB_OpenGLES2Query
</code>,
72 make sure the corresponding extension
<code>GL_EXT_occlusion_query_boolean
</code>
74 <li>If you are using the functions
<code>glMapBufferSubDataCHROMIUM
</code>,
75 <code>glUnmapBufferSubDataCHROMIUM
</code>,
<code>glMapTexSubImage2DCHROMIUM
</code>,
76 <code>glUnmapTexSubImage2DCHROMIUM
</code>, or the PPAPI interface
77 <code>PPB_OpenGLES2ChromiumMapSub
</code>, make sure the corresponding extension
78 <code>GL_CHROMIUM_map_sub
</code> exists.
</li>
80 <p>Check for system capabilites with
<code>glGetIntegerv
</code> and adjust shader programs
81 as well as texture and vertex data accordingly:
</p>
82 <ul class=
"small-gap">
83 <li>If you are using textures in vertex shaders, make sure
84 <code>glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, ...)
</code> and
85 <code>glGetIntegerv(GL_MAX_TEXTURE_SIZE, ...)
</code> return values greater than
0.
</li>
86 <li>If you are using more than
8 textures in a single shader, make sure
87 <code>glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)
</code> returns a value greater
88 than or equal to the number of simultaneous textures you need.
</li>
90 <h3 id=
"vetting-the-driver-in-the-chrome-web-store">Vetting the driver in the Chrome Web Store
</h3>
91 <p>If you choose to place your application in the
<a class=
"reference external" href=
"/webstore">Chrome Web Store
</a>,
92 its Web Store
<a class=
"reference external" href=
"/extensions/manifest">manifest file
</a> can include the
<code>webgl
</code>
93 feature in the requirements parameter. It looks like this:
</p>
94 <pre class=
"prettyprint">
95 "requirements
": {
97 "features
": [
"webgl
"]
101 <p>While WebGL is technically a JavaScript API, specifying the
<code>webgl
</code> feature
102 also works for OpenGL ES
2.0 because both interfaces use the same driver.
</p>
103 <p>This manifest item is not required, but if you include it, the Chrome Web Store
104 will prevent a user from installing the application if the browser is running on
105 a machine that does not support OpenGL ES
2.0 or that is using a known
106 blacklisted GPU driver that could invite an attack.
</p>
107 <p>If the Web Store determines that the user
’s driver is deficient, the app won
’t
108 appear on the store
’s tile display. However, it will appear in store search
109 results or if the user links to it directly, in which case the user could still
110 download it. But the manifest requirements will be checked when the user reaches
111 the install page, and if there is a problem, the browser will display the
112 message
“This application is not supported on this computer. Installation has
113 been disabled.
”</p>
114 <p>The manifest-based check applies only to downloads directly from the Chrome Web
115 Store. It is not performed when an application is loaded via
<a class=
"reference external" href=
"/webstore/inline_installation">inline
116 installation
</a>.
</p>
117 <h3 id=
"what-to-do-when-there-are-problems">What to do when there are problems
</h3>
118 <p>Using the vetting procedure described above, you should be able to detect the
119 most common problems before your application runs. If there are problems, your
120 code should describe the issue as clearly as possible. That
’s easy if there is a
121 missing feature. Failure to create a graphics context is tougher to diagnose. At
122 the very least, you can suggest that the user try to update the driver. You
123 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>
124 <p>If a user can
’t update the driver, or their problem persists, be sure to gather
125 information about their graphics environment. Ask for the contents of the Chrome
126 <code>about:gpu
</code> page.
</p>
127 <h3 id=
"document-unreliable-drivers">Document unreliable drivers
</h3>
128 <p>It can be helpful to include information about known dubious drivers in your
129 user documentation. This might help identify if a rogue driver is the cause of a
130 problem. There are many sources of GPU driver blacklists. Two such lists can be
131 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>
132 and
<a class=
"reference external" href=
"http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists">Khronos
</a>. You
133 can use these lists to include information in your documentation that warns
134 users about dangerous drivers.
</p>
135 <h3 id=
"test-your-defenses">Test your defenses
</h3>
136 <p>You can test your driver validation code by running Chrome with the following
137 flags (all at once) and watching how your application responds:
</p>
138 <ul class=
"small-gap">
139 <li><code>--disable-webgl
</code></li>
140 <li><code>--disable-pepper-
3d
</code></li>
141 <li><code>--disable_multisampling
</code></li>
142 <li><code>--disable-accelerated-compositing
</code></li>
143 <li><code>--disable-accelerated-
2d-canvas
</code></li>
145 <h2 id=
"calling-opengl-es-2-0-commands">Calling OpenGL ES
2.0 commands
</h2>
146 <p>There are three ways to write OpenGL ES
2.0 calls in Native Client.
</p>
147 <h3 id=
"use-pure-opengl-es-2-0-function-calls">Use
“pure
” OpenGL ES
2.0 function calls
</h3>
148 <p>You can make OpenGL ES
2.0 calls through a Pepper extension library. The SDK
149 example
<code>examples/api/graphics_3d
</code> works this way. In the file
150 <code>graphics_3d.cc
</code>, the key initialization steps are as follows:
</p>
151 <ul class=
"small-gap">
152 <li><p class=
"first">Add these includes at the top of the file:
</p>
153 <pre class=
"prettyprint">
154 #include
<GLES2/gl2.h
>
155 #include
"ppapi/lib/gl/gles2/gl2ext_ppapi.h
"
158 <li><p class=
"first">Define the function
<code>InitGL
</code>. The exact specification of
<code>attrib_list
</code>
159 will be application specific.
</p>
160 <pre class=
"prettyprint">
161 bool InitGL(int32_t new_width, int32_t new_height) {
162 if (!glInitializePPAPI(pp::Module::Get()-
>get_browser_interface())) {
163 fprintf(stderr,
"Unable to initialize GL PPAPI!\n
");
167 const int32_t attrib_list[] = {
168 PP_GRAPHICS3DATTRIB_ALPHA_SIZE,
8,
169 PP_GRAPHICS3DATTRIB_DEPTH_SIZE,
24,
170 PP_GRAPHICS3DATTRIB_WIDTH, new_width,
171 PP_GRAPHICS3DATTRIB_HEIGHT, new_height,
172 PP_GRAPHICS3DATTRIB_NONE
175 context_ = pp::Graphics3D(this, attrib_list);
176 if (!BindGraphics(context_)) {
177 fprintf(stderr,
"Unable to bind
3d context!\n
");
178 context_ = pp::Graphics3D();
179 glSetCurrentContextPPAPI(
0);
183 glSetCurrentContextPPAPI(context_.pp_resource());
188 <li>Include logic in
<code>Instance::DidChangeView
</code> to call
<code>InitGL
</code> whenever
189 necessary: upon application launch (when the graphics context is NULL) and
190 whenever the module
’s View changes size.
</li>
192 <h3 id=
"use-regal">Use Regal
</h3>
193 <p>If you are porting an OpenGL ES
2.0 application, or are comfortable writing in
194 OpenGL ES
2.0, you should stick with the Pepper APIs or pure OpenGL ES
2.0 calls
195 described above. If you are porting an application that uses features not in
196 OpenGL ES
2.0, consider using Regal. Regal is an open source library that
197 supports many versions of OpenGL. Regal recently added support for Native
198 Client. Regal forwards most OpenGL calls directly to the underlying graphics
199 library, but it can also emulate other calls that are not included (when
200 hardware support exists). See
<a class=
"reference external" href=
"http://www.altdevblogaday.com/2012/09/04/bringing-regal-opengl-to-native-client/">libregal
</a>
202 <h3 id=
"use-the-pepper-api">Use the Pepper API
</h3>
203 <p>Your code can call the Pepper PPB_OpenGLES2 API directly, as with any Pepper
204 interface. When you write in this way, each invocation of an OpenGL ES
2.0
205 function must begin with a reference to the Pepper interface, and the first
206 argument is the graphics context. To invoke the function
<code>glCompileShader
</code>,
207 your code might look like:
</p>
208 <pre class=
"prettyprint">
209 ppb_g3d_interface-
>CompileShader(graphicsContext, shader);
211 <p>This approach specifically targets the Pepper APIs. Each call corresponds to a
212 OpenGL ES
2.0 function, but the syntax is unique to Native Client, so the source
213 file is not portable.
</p>
214 <h2 id=
"implementing-a-rendering-loop">Implementing a rendering loop
</h2>
215 <p>Graphics applications require a continuous frame render-and-redraw cycle that
216 runs at a high frequency. To achieve the best frame rate, is important to
217 understand how the OpenGL ES
2.0 code in a Native Client module interacts with
219 <h3 id=
"the-chrome-and-native-client-processes">The Chrome and Native Client processes
</h3>
220 <p>Chrome is a multi-process browser. Each Chrome tab is a separate process that is
221 running an application with its own main thread (we
’ll call it the Chrome main
222 thread). When an application launches a Native Client module, the module runs in
223 a new, separate sandboxed process. The module
’s process has its own main thread
224 (the Native Client thread). The Chrome and Native Client processes communicate
225 with each other using Pepper API calls on their main threads.
</p>
226 <p>When the Chrome main thread calls the Native Client thread (keyboard and mouse
227 callbacks, for example), the Chrome main thread will block. This means that
228 lengthy operations on the Native Client thread can steal cycles from Chrome, and
229 performing blocking operations on the Native Client thread can bring your app to
231 <p>Native Client uses callback functions to synchronize the main threads of the
232 two processes. Only certain Pepper functions use callbacks;
<a class=
"reference external" href=
"/native-client/pepper_stable/c/struct_p_p_b___graphics3_d__1__0#a293c6941c0da084267ffba3954793497">SwapBuffers
</a>
234 <h3 id=
"swapbuffers-and-its-callback-function"><code>SwapBuffers
</code> and its callback function
</h3>
235 <p><code>SwapBuffers
</code> is non-blocking; it is called from the Native Client thread and
236 returns immediately. When
<code>SwapBuffers
</code> is called, it runs asynchronously on
237 the Chrome main thread. It switches the graphics data buffers, handles any
238 needed compositing operations, and redraws the screen. When the screen update is
239 complete, the callback function that was included as one of
<code>SwapBuffer
</code>‘s
240 arguments will be called from the Chrome thread and executed on the Native
242 <p>To create a rendering loop, your Native Client module should include a function
243 that does the rendering work and then executes
<code>SwapBuffers
</code>, passing itself
244 as the
<code>SwapBuffer
</code> callback. If your rendering code is efficient and runs
245 quickly, this scheme will achieve the highest frame rate possible. The
246 documentation for
<code>SwapBuffers
</code> explains why this is optimal: because the
247 callback is executed only when the plugin
’s current state is actually on the
248 screen, this function provides a way to rate-limit animations. By waiting until
249 the image is on the screen before painting the next frame, you can ensure you
’re
250 not generating updates faster than the screen can be updated.
</p>
251 <p>The following diagram illustrates the interaction between the Chrome and Native
252 Client processes. The application-specific rendering code runs in the function
253 called
<code>Draw
</code> on the Native Client thread. Blue down-arrows are blocking calls
254 from the main thread to Native Client, green up-arrows are non-blocking
255 <code>SwapBuffers
</code> calls from Native Client to the main thread. All OpenGL ES
2.0
256 calls are made from
<code>Draw
</code> in the Native Client thread.
</p>
257 <img alt=
"/native-client/images/3d-graphics-render-loop.png" src=
"/native-client/images/3d-graphics-render-loop.png" />
258 <h3 id=
"sdk-example-graphics-3d">SDK example
<code>graphics_3d
</code></h3>
259 <p>The SDK example
<code>graphics_3d
</code> uses the function
<code>MainLoop
</code> (in
260 <code>hello_world.cc
</code>) to create a rendering loop as described above.
<code>MainLoop
</code>
261 calls
<code>Render
</code> to do the rendering work, and then invokes
<code>SwapBuffers
</code>,
262 passing itself as the callback.
</p>
263 <pre class=
"prettyprint">
264 void MainLoop(void* foo, int bar) {
265 if (g_LoadCnt ==
3) {
269 if (g_LoadCnt
> 3) {
271 PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop,
0);
272 ppb_g3d_interface-
>SwapBuffers(g_context, cc);
274 PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop,
0);
275 ppb_core_interface-
>CallOnMainThread(
0, cc,
0);
279 <h2 id=
"managing-the-opengl-es-2-0-pipeline">Managing the OpenGL ES
2.0 pipeline
</h2>
280 <p>OpenGL ES
2.0 commands do not run in the Chrome or Native Client processes. They
281 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
282 command buffer
</a>. The
283 command buffer is shared by a dedicated GPU process. By using a separate GPU
284 process, Chrome implements another layer of runtime security, vetting all OpenGL
285 ES
2.0 commands and their arguments before they are sent on to the
286 GPU. Buffering commands through the FIFO also speeds up your code, since each
287 OpenGL ES
2.0 call in your Native Client thread returns immediately, while the
288 processing may be delayed as the GPU works down the commands queued up in the
290 <p>Before the screen is updated, all the intervening OpenGL ES
2.0 commands must be
291 processed by the GPU. Programmers often try to ensure this by using the
292 <code>glFlush
</code> and
<code>glFinish
</code> commands in their rendering code. In the case of
293 Native Client this is usually unnecessary. The
<code>SwapBuffers
</code> command does an
294 implicit flush, and the Chrome team is continually tweaking the GPU code to
295 consume the OpenGL ES
2.0 FIFO as fast as possible.
</p>
296 <p>Sometimes a
3D application can write to the FIFO in a way that
’s difficult to
297 handle. The command pipeline may fill up and your code will have to wait for the
298 GPU to flush the FIFO. If this is the case, you may be able to add
<code>glFlush
</code>
299 calls to speed up the flow of the OpenGL ES
2.0 command FIFO. Before you start
300 to add your own flushes, first try to determine if pipeline saturation is really
301 the problem by monitoring the rendering time per frame and looking for irregular
302 spikes that do not consistently fall on the same OpenGL ES
2.0 call. If you
’re
303 convinced the pipeline needs to be accelerated, insert
<code>glFlush
</code> calls in your
304 code before starting blocks of processing that do not generate OpenGL ES
2.0
305 commands. For example, issue a flush before you begin any multithreaded particle
306 work, so that the command buffer will be clear when you start doing OpenGL ES
307 2.0 calls again. Determining where and how often to call
<code>glFlush
</code> can be
308 tricky, you will need to experiment to find the sweet spot.
</p>
309 <h2 id=
"rendering-and-inactive-tabs">Rendering and inactive tabs
</h2>
310 <p>Users will often switch between tabs in a multi-tab browser. A well-behaved
311 application that
’s performing
3D rendering should pause any real-time processing
312 and yield cycles to other processes when its tab becomes inactive.
</p>
313 <p>In Chrome, an inactive tab will continue to execute timed functions (such as
314 <code>setInterval
</code> and
<code>setTimeout
</code>) but the timer interval will be automatically
315 overridden and limited to not less than one second while the tab is inactive. In
316 addition, any callback associated with a
<code>SwapBuffers
</code> call will not be sent
317 until the tab is active again. You may receive asynchronous callbacks from
318 functions other than
<code>SwapBuffers
</code> while a tab is inactive. Depending on the
319 design of your application, you might choose to handle them as they arrive, or
320 to queue them in a buffer and process them when the tab becomes active.
</p>
321 <p>The time that passes while a tab is inactive can be considerable. If your main
322 thread pulse is based on the
<code>SwapBuffers
</code> callback, your app won
’t update
323 while a tab is inactive. A Native Client module should be able to detect and
324 respond to the state of the tab in which it
’s running. For example, when a tab
325 becomes inactive, you can set an atomic flag in the Native Client thread that
326 will skip the
3D rendering and
<code>SwapBuffers
</code> calls and continue to call the
327 main thread every
30 msec or so. This provides time to update features that
328 should still run in the background, like audio. It may also be helpful to call
329 <code>sched_yield
</code> or
<code>usleep
</code> on any worker threads to release resources and
330 cede cycles to the OS.
</p>
331 <h3 id=
"handling-tab-activation-from-the-main-thread">Handling tab activation from the main thread
</h3>
332 <p>You can detect and respond to the activation or deactivation of a tab with
333 JavaScript on your hosting page. Add an EventListener for
<code>visibilitychange
</code>
334 that sends a message to the Native Client module, as in this example:
</p>
335 <pre class=
"prettyprint">
336 document.addEventListener('visibilitychange', function(){
337 if (document.hidden) {
338 // PostMessage to your Native Client module
339 document.nacl_module.postMessage('INACTIVE');
341 // PostMessage to your Native Client module
342 document.nacl_module.postMessage('ACTIVE');
347 <h3 id=
"handling-tab-activation-from-the-native-client-thread">Handling tab activation from the Native Client thread
</h3>
348 <p>You can also detect and respond to the activation or deactivation of a tab
349 directly from your Native Client module by including code in the function
350 <code>pp::Instance::DidChangeView
</code>, which is called whenever a change in the
351 module
’s view occurs. The code can call
<code>ppb::View::IsPageVisible
</code> to
352 determine if the page is visible or not. The most common cause of invisible
353 pages is that the page is in a background tab.
</p>
354 <h2 id=
"tips-and-best-practices">Tips and best practices
</h2>
355 <p>Here are some suggestions for writing safe code and getting the maximum
356 performance with the Pepper
3D API.
</p>
357 <h3 id=
"do-s">Do
’s
</h3>
358 <ul class=
"small-gap">
359 <li><p class=
"first"><strong>Make sure to enable attrib
0.
</strong> OpenGL requires that you enable attrib
0,
360 but OpenGL ES
2.0 does not. For example, you can define a vertex shader with
2
361 attributes, numbered like this:
</p>
362 <pre class=
"prettyprint">
363 glBindAttribLocation(program,
"positions
",
1);
364 glBindAttribLocation(program,
"normals
",
2);
366 <p>In this case the shader is not using attrib
0 and Chrome may have to perform
367 some additional work if it is emulating OpenGL ES
2.0 on top of OpenGL. It
’s
368 always more efficient to enable attrib
0, even if you do not use it.
</p>
370 <li><strong>Check how shaders compile.
</strong> Shaders can compile differently on different
371 systems, which can result in
<code>glGetAttrib*
</code> functions returning different
372 results. Be sure that the vertex attribute indices match the corresponding
373 name each time you recompile a shader.
</li>
374 <li><strong>Update indices sparingly.
</strong> For security reasons, all indices must be
375 validated. If you change indices, Native Client will validate them
376 again. Structure your code so indices are not updated often.
</li>
377 <li><strong>Use a smaller plugin and let CSS scale it.
</strong> If you
’re running into fillrate
378 issues, it may be beneficial to perform scaling via CSS. The size your plugin
379 renders is determined by the width and height attributes of the
<code><embed
></code>
380 element for the module. The actual size displayed on the web page is
381 controlled by the CSS styles applied to the element.
</li>
382 <li><strong>Avoid matrix-to-matrix conversions.
</strong> With some versions of Mac OS, there is
383 a driver problem when compiling shaders. If you get compiler errors for matrix
384 transforms, avoid matrix-to-matrix conversions. For instance, upres a vec3 to
385 a vec4 before transforming it by a mat4, rather than converting the mat4 to a
388 <h3 id=
"don-ts">Don
’ts
</h3>
389 <ul class=
"small-gap">
390 <li><strong>Don
’t use client side buffers.
</strong> OpenGL ES
2.0 can use client side data with
391 <code>glVertexAttribPointer
</code> and
<code>glDrawElements
</code>, but this is really slow. Try
392 to avoid client side buffers. Use Vertex Buffer Objects (VBOs) instead.
</li>
393 <li><strong>Don
’t mix vertex data and index data.
</strong> By default, Pepper
3D binds buffers
394 to a single point. You could create a buffer and bind it to both
395 <code>GL_ARRAY_BUFFER
</code> and
<code>GL_ELEMENT_ARRAY_BUFFER
</code>, but that would be
396 expensive overhead and it is not recommended.
</li>
397 <li><strong>Don
’t call glGet* or glCheck* during rendering.
</strong> This is normal
398 advice for OpenGL programs, but is particularly important for
3D on
399 Chrome. Calls to any OpenGL ES
2.0 function whose name begins with these
400 strings blocks the Native Client thread. This includes
<code>glGetError
</code>; avoid
401 calling it in release builds.
</li>
402 <li><strong>Don
’t use fixed point (GL_FIXED) vertex attributes.
</strong> Fixed point
403 attributes are not supported in OpenGL ES
2.0, so emulating them in OpenGL ES
404 2.0 is slow. By default,
<code>GL_FIXED
</code> support is turned off in the Pepper
3D
406 <li><strong>Don
’t read data from the GPU.
</strong> Don
’t call
<code>glReadPixels
</code>, as it is slow.
</li>
407 <li><strong>Don
’t update a small portion of a large buffer.
</strong> In the current OpenGL ES
408 2.0 implementation when you update a portion of a buffer (with
409 <code>glSubBufferData
</code> for example) the entire buffer must be reprocessed. To
410 avoid this problem, keep static and dynamic data in different buffers.
</li>
411 <li><strong>Don
’t call glDisable(GL_TEXTURE_2D).
</strong> This is an OpenGL ES
2.0
412 error. Each time it is called, an error messages will appear in Chrome
’s
413 <code>about:gpu
</code> tab.
</li>
417 {{/partials.standard_nacl_article}}