Applications Graphics Performance in Rich Internet Applications

Applications Graphics Performance in Rich Internet Applications

Applications Editor: Mike Potel Graphics Performance in Rich Internet Applications Rama C. Hoetzlein Aalborg University Copenhagen magine an Internet experience in which online The test was implemented and rendered in four data visualization and interaction are fully dy- frameworks (Flash, HTML5, OpenGL, and We- namic and smooth even when displaying large- bGL) using three programming languages (C/C++, Iscale networks. Several rich Internet application ActionScript 3, and JavaScript). Figure 1 shows (RIA) frameworks are working in this direction. screenshots of the tests for various combinations Most browsers have integrated HTML5 and the of RIA frameworks and languages. new canvas elements, pending fi nal specifi ca- tion, and Adobe recently released Flash Player 10.1 The Basic Simulation Loop with GPU-accelerated video playback. The major The simulation loop is identical in all systems. RIA players are exploring GPU-accelerated designs Shown in Figure 2 for C/C++, it consists of a basic while competing to maintain an interactive expe- Eulerian integrator and a directional gravitational rience by reducing virtual code execution and CPU force toward the canvas center, resulting in a to- rendering time.1 tal of seven additions, six multiplications, and one So, what’s the best RIA framework for developing square root for each simulated particle per cycle. large-scale, dynamic online data visualizations, ap- plications, or games? To answer this, I developed Flash with Sprites a test suite to consistently measure raw graph- Rendering differs considerably in each framework. ics performance in RIAs. It consists of a simple The simplest framework is Flash using sprites be- sprite-based particle system coded and optimized cause it requires no direct rendering. Programmers on each framework. By testing under a variety of can add sprites to the master DisplayList for languages, RIAs, browsers, and rendering options, each n particles, using a master bitmap, and posi- I developed a coherent picture of the current op- tion them dynamically at runtime (see Figure 3). tions for online 2D graphics. Flash with bitmapData Implementation For rendering in Flash using the bitmapData The basic test consists of n transparent 2D sprites method instead of sprites, the main program loop of 32 × 32 pixels each, rendered and randomly needs additional code to rasterize the sprites into placed on a 1,280 × 960-pixel canvas. The sprites the bitmap data object using the copyPixels are then animated according to a simple physics method (see Figure 4). system, with a point gravity at the canvas’s center. The user can control the number of sprites, up to HTML5 one million. To render the particle system in HTML5, the new The test also measures the simulation and ren- canvas 2D tag is used. Retrieval of the canvas and dering times separately. This enables me to analyze its context occurs during page initialization. The code execution independently of graphics perfor- code then preloads the sprite image into a new mance on each framework and browser. Network Image object. The main loop uses the context’s download time, video playback, or 3D graphics drawImage function to render the sprite at each aren’t tested here, just raw graphics performance particle location (see Figure 5). Unlike the Flash for 2D sprites, as you would fi nd in online data sprite method, and similarly to the Flash bit- visualization or gaming. mapData method, this method doesn’t reposition 6 September/October 2012 Published by the IEEE Computer Society 0272-1716/12/$31.00 © 2012 IEEE (a) (b) (c) (d) Figure 1. Rendering tests with 10,000 sprites in (a) Flash with ActionScript 3 (AS3), (b) HTML5 with JavaScript, (c) native OpenGL with C++, and (d) WebGL with JavaScript, on Google Chrome. sprite objects and renders the bitmap directly at float dx, dy, dist; // For each particle … the particle locations per frame. for (int n=0; n < num_p; n++ ) { dx = 640 - pos[n].x; OpenGL with C/C++ dy = 480 - pos[n].y; The baseline test uses OpenGL in native C/C++. dist = sqrt(dx*dx+dy*dy); Because OpenGL is a low-level API, the code is vel[n].x += dx / dist; // Gravitational force somewhat more involved. A naive method sends vel[n].y += dy / dist; repeated draw calls to the GPU by using glBegin pos[n].x += vel[n].x*0.1; // Euler integration and glEnd commands (see Figure 6). This requires pos[n].y += vel[n].y*0.1; a separate PCI bus transfer from the CPU to the } GPU for each sprite. Figure 6 also shows that, be- cause OpenGL is low level, programmers must ex- Figure 2. The simulation loop in C/C++. This loop animates the particles plicitly specify each sprite’s four corners and their using a gravity source at the screen’s center. texture coordinates. WebGL OpenGL with Vertex Buffer Objects WebGL is similar to OpenGL but implements A much more efficient OpenGL strategy is to use OpenGL ES (Embedded Systems), a simplified graph- vertex buffer objects (VBOs), which transfer all sprite ics API designed for mobile devices. Developers must geometry as a single block of data to the GPU per specify the shaders being used to transfer individ- frame (see Figure 7). ual pixels to the display. In this case, the fragment IEEE Computer Graphics and Applications 7 Applications Figure 3. The // Global class for embedded sprite image rendering [Embed(source = ‘../assets/ball32.png’)] setup for private var ballImage:Class; Flash using ActionScript // Reset rendering – Run only when N changes 3 with sprites. while ( this.numChildren > 0 ) The main this.removeChildAt ( 0 ); // Clear previous display list loop, not this.addChild ( textFPS ); // Add frame counter to display // For each particle … shown here, for ( var n:Number=0; n < particleNum; n++ ) { repositions ballSprite = new ballImage(); // Create new sprite each sprite to ballSprite.x = particlePos[n].x; // Position at particle new particle ballSprite.y = particlePos[n].y; positions. this.addChild ( ballSprite ); // Add to display list } // Main Loop – Run per frame shader returns the pixel at a particular texture RenderBuffer.lock(); coordinate in the sprite. RenderBuffer.fillRect ( canvasRect, 0x222233 ); Because WebGL doesn’t contain OpenGL’s direct RenderBuffer.unlock(); draw methods, graphics programmers use VBOs for ( var n:Number=0; n < particleNum; n++ ) { instead. In addition, only triangles, not quads, can RenderBuffer.copyPixels ( ballBitmap.bitmapData, be rendered. So, the code must specify six corners ballBitmap.bitmapData.rect, particlePos[n] ); of two triangles to draw each sprite (see Figure 8). } Figure 4. The rendering loop for Flash using ActionScript 3 with the Discussion bitmapData method. This loop uses the copyPixels method to Although the code becomes increasingly complex rasterize the sprites into the bitmap data object. with the more low-level frameworks, GPU usage in OpenGL and WebGL clearly improves perfor- // Setup mance. Flash and HTML5 hide much graphics var canvas = document.getElementById(‘mycanvas’); magic, which is their primary responsibility. In the var context = canvas.getContext( ‘2d’ ); future, these frameworks will likely become more var ball_img = new Image(); flexible and more efficient. ball_img.src = “ball32.png”; Testing and Results // Main loop I measured the simulation and rendering frame for( var i = 0, j = particles.length; i < j; i++ ) context.drawImage ( ball_img, particles[i].posX, rates separately at 15 data points for n sprites from particles[i].posY ); 1,000 to 100,000 in each combination of frame- work and browser (Firefox, Chrome, and Internet Figure 5. The rendering setup and main loop for HTML5 using Explorer 9). At times, results were outside the CPU JavaScript. (Only relevant portions of the code are shown.) This method timer’s measureable limits, such as with OpenGL renders the bitmap directly at the particle locations per frame. using VBOs, which started at 240,000 sprites. In those cases, I estimated values in the test range glEnable ( GL_TEXTURE_2D ); through linear extrapolation. I conducted the tests glBindTexture ( GL_TEXTURE_2D, ball_glid ); on a Sager NP8690 Core i7 640M laptop with a for (int n=0; n < num_p; n++ ) { GeForce GTX 460M graphics card. The source code glLoadIdentity (); and results are freely available at www.rchoetzlein. glTranslatef ( particle_pos[n].x, particle_pos[n].y, 0 ); com/sprites. glBegin ( GL_QUADS ); // Transfer each quad to GPU glTexCoord2f ( 0, 0 ); glVertex2f ( 0, 0 ); Scalability glTexCoord2f ( 1, 0 ); glVertex2f ( 32, 0 ); Figure 9 shows some surprising outcomes regard- glTexCoord2f ( 1, 1 ); glVertex2f ( 32, 32 ); ing scalability with the number of sprites. The glTexCoord2f ( 0, 1 ); glVertex2f ( 0, 32 ); newly released HTML5 specification has sparked glEnd (); } considerable debate over HTML5 versus Flash per- formance.2 However, I found the browser choice Figure 6. The rendering loop for OpenGL using C/C++ with naive draw to be more important to rendering performance. methods. Because OpenGL is low level, graphic programmers must Firefox performed one-third as well as Chrome explicitly specify each sprite’s four corners and their texture coordinates. and Internet Explorer 9 (IE 9) when using Flash 8 September/October 2012 // Pack 4-corners of each quad (all done on CPU) float* dat = bufdat; for (int n=0; n < num_p; n++ ) { *dat++ = pos[n].x; *dat++ = pos[n].y; *dat++ = pos[n].x+32; *dat++ = pos[n].y; *dat++ = pos[n].x+32; *dat++ = pos[n].y+32; *dat++ = pos[n].x; *dat++ = pos[n].y+32; } glEnable ( GL_TEXTURE_2D ); glBindTexture ( GL_TEXTURE_2D, img.getGLID() ); glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbo ); // Transfer all to GPU glBufferDataARB ( GL_ARRAY_BUFFER_ARB, sizeof(float)*2*4*num_p, bufdat, GL_DYNAMIC_ DRAW_ARB ); glEnableClientState ( GL_VERTEX_ARRAY ); glVertexPointer ( 2, GL_FLOAT, 0, 0 ); glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbotex ); glEnableClientState ( GL_TEXTURE_COORD_ARRAY ); glTexCoordPointer(2, GL_FLOAT, 0, 0 ); glDrawArrays ( GL_QUADS, 0, num_p ); // Ask GPU to draw all sprites Figure 7. The rendering loop for OpenGL using C/C++ with vertex buffer objects (VBOs). Earlier in the code (not shown), data buffers are allocated to store the 2D coordinates representing the four corners of every sprite, resulting in 2 * 4 * N floats.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    7 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us