Przeglądaj źródła

Double Chrome hextile perf again. Add canvas test.

- By dereferencing the 'data' field of the imageData object before the
  loop, the hextile performance on Chrome is down to 140ms or so for
  a full 800x600 update. Still have to fall back to Canvas operations
  for firefox.

- Fix RQ empty after reorder bug.
Joel Martin 15 lat temu
rodzic
commit
97763d0eb8
3 zmienionych plików z 125 dodań i 49 usunięć
  1. 24 42
      include/canvas.js
  2. 98 6
      tests/canvas.html
  3. 3 1
      vnc.js

+ 24 - 42
include/canvas.js

@@ -12,6 +12,8 @@
 // Everything namespaced inside Canvas
 var Canvas = {
 
+prefer_js : false,
+
 c_x : 0,
 c_y : 0,
 c_wx : 0,
@@ -99,6 +101,10 @@ init: function (id, width, height, keyDown, keyUp,
     
     Canvas.prevStyle = "";
 
+    if (Browser.Engine.webkit) {
+        Canvas.prefer_js = true;
+    }
+
     console.log("<< Canvas.init");
 },
 
@@ -122,35 +128,6 @@ stop: function () {
     document.body.removeEvents('contextmenu');
 },
 
-draw: function () {
-    var img, x, y;
-    /* Border */
-    Canvas.ctx.stroke();  
-    Canvas.ctx.rect(0, 0, Canvas.c_wx, Canvas.c_wy);
-    Canvas.ctx.stroke();  
-
-    /*
-    // Does not work in firefox
-    var himg = new Image();
-    himg.src = "head_ani2.gif"
-    Canvas.ctx.drawImage(himg, 10, 10);
-    */
-
-    /* Test array image data */
-    //img = Canvas.ctx.createImageData(50, 50);
-    img = Canvas.ctx.getImageData(0, 0, 50, 50);
-    for (y=0; y< 50; y++) {
-        for (x=0; x< 50; x++) {
-            img.data[(y*50 + x)*4 + 0] = 255 - parseInt((255 / 50) * y, 10);
-            img.data[(y*50 + x)*4 + 1] = parseInt((255 / 50) * y, 10);
-            img.data[(y*50 + x)*4 + 2] = parseInt((255 / 50) * x, 10);
-            img.data[(y*50 + x)*4 + 3] = 255;
-        }
-    }
-    Canvas.ctx.putImageData(img, 100, 100);
-},
-
-
 /*
  * Tile rendering functions optimized for rendering engines.
  *
@@ -159,10 +136,11 @@ draw: function () {
  *   gecko, Javascript array handling is much slower.
  */
 getTile: function(x, y, width, height, color) {
-    var img, p, red, green, blue, j, i;
+    var img, data, p, red, green, blue, j, i;
     img = {'x': x, 'y': y, 'width': width, 'height': height,
            'data': []};
-    if (Browser.Engine.webkit) {
+    if (Canvas.prefer_js) {
+        data = img.data;
         red = color[0];
         green = color[1];
         blue = color[2];
@@ -182,8 +160,9 @@ getTile: function(x, y, width, height, color) {
 },
 
 setTile: function(img, x, y, w, h, color) {
-    var p, red, green, blue, width, j, i;
-    if (Browser.Engine.webkit) {
+    var data, p, red, green, blue, width, j, i;
+    if (Canvas.prefer_js) {
+        data = img.data;
         width = img.width;
         red = color[0];
         green = color[1];
@@ -191,9 +170,9 @@ setTile: function(img, x, y, w, h, color) {
         for (j = 0; j < h; j++) {
             for (i = 0; i < w; i++) {
                 p = (x + i + ((y + j) * width) ) * 4;
-                img.data[p + 0] = red;
-                img.data[p + 1] = green;
-                img.data[p + 2] = blue;
+                data[p + 0] = red;
+                data[p + 1] = green;
+                data[p + 2] = blue;
                 //img.data[p + 3] = 255; // Set Alpha
             }   
         } 
@@ -203,7 +182,7 @@ setTile: function(img, x, y, w, h, color) {
 },
 
 putTile: function(img) {
-    if (Browser.Engine.webkit) {
+    if (Canvas.prefer_js) {
         Canvas.rgbxImage(img.x, img.y, img.width, img.height, img.data);
         //Canvas.ctx.putImageData(img, img.x, img.y);
     } else {
@@ -213,14 +192,17 @@ putTile: function(img) {
 
 
 rgbxImage: function(x, y, width, height, arr) {
-    var img, i;
+    var img, i, data;
     /* Old firefox and Opera don't support createImageData */
     img = Canvas.ctx.getImageData(0, 0, width, height);
+    //console.log("rfbxImage: img: " + img + " x: " + x + " y: " + y + " width: " + width + " height: " + height);
+    //img.data = arr.slice();
+    data = img.data;
     for (i=0; i < (width * height); i++) {
-        img.data[i*4 + 0] = arr[i*4 + 0];
-        img.data[i*4 + 1] = arr[i*4 + 1];
-        img.data[i*4 + 2] = arr[i*4 + 2];
-        img.data[i*4 + 3] = 255; // Set Alpha
+        data[i*4 + 0] = arr[i*4 + 0];
+        data[i*4 + 1] = arr[i*4 + 1];
+        data[i*4 + 2] = arr[i*4 + 2];
+        data[i*4 + 3] = 255; // Set Alpha
     }
     Canvas.ctx.putImageData(img, x, y);
 

+ 98 - 6
tests/canvas.html

@@ -1,11 +1,22 @@
 <html>
-    <head><title>Canvas Experiments</title></head>
+    <head><title>Canvas Performance Test</title></head>
     <body>
+        Iterations: <input id='iterations' style='width:50' value="100">&nbsp;
+
+        <input id='startButton' type='button' value='Start' style='width:100px'
+            onclick="start();">&nbsp;
+
+        <br><br>
+
         Canvas:<br>
-        <canvas id="tutorial" width="640" height="480"
+        <canvas id="canvas" width="640" height="20"
                 style="border-style: dotted; border-width: 1px;">
             Canvas not supported.
         </canvas>
+
+        <br>
+        Results:<br>
+        <textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
     </body>
 
     <!--
@@ -18,11 +29,92 @@
     <script src="../include/canvas.js"></script>
 
     <script>
+        var msg_cnt = 0;
+        var width = 800, height = 600;
+        var iterations;
+
+        function message(str) {
+            console.log(str);
+            cell = $('messages');
+            cell.innerHTML += msg_cnt + ": " + str + "\n";
+            cell.scrollTop = cell.scrollHeight;
+        }
+
+        function draw () {
+            var img, x, y;
+            /* Border */
+            Canvas.ctx.stroke();  
+            Canvas.ctx.rect(0, 0, Canvas.c_wx, Canvas.c_wy);
+            Canvas.ctx.stroke();  
+
+            /*
+            // Does not work in firefox
+            var himg = new Image();
+            himg.src = "head_ani2.gif"
+            Canvas.ctx.drawImage(himg, 10, 10);
+            */
+
+            /* Test array image data */
+            //img = Canvas.ctx.createImageData(50, 50);
+            img = Canvas.ctx.getImageData(0, 0, 50, 50);
+            for (y=0; y< 50; y++) {
+                for (x=0; x< 50; x++) {
+                    img.data[(y*50 + x)*4 + 0] = 255 - parseInt((255 / 50) * y, 10);
+                    img.data[(y*50 + x)*4 + 1] = parseInt((255 / 50) * y, 10);
+                    img.data[(y*50 + x)*4 + 2] = parseInt((255 / 50) * x, 10);
+                    img.data[(y*50 + x)*4 + 3] = 255;
+                }
+            }
+            Canvas.ctx.putImageData(img, 100, 100);
+        }
+
+        function start () {
+            $('startButton').value = "Running";
+            $('startButton').disabled = true;
+            setTimeout(start_delayed, 250);
+            iterations = $('iterations').value;
+        }
+
+        function start_delayed () {
+
+            message("Running test: prefer Javascript");
+            Canvas.prefer_js = true;
+            var time1 = run_test();
+            message("prefer Javascript: " + time1 + "ms total, " +
+                    (time1 / iterations) + "ms per frame");
+
+            message("Running test: prefer Canvas ops");
+            Canvas.prefer_js = false;
+            var time2 = run_test();
+            message("prefer Canvas ops: " + time2 + "ms total, " +
+                    (time2 / iterations) + "ms per frame");
+
+            $('startButton').disabled = false;
+            $('startButton').value = "Start";
+        }
+
+        function run_test () {
+            var color, start_time = (new Date()).getTime();
+            for (var i=0; i < iterations; i++) {
+                color = [128, 128, (255 / iterations) * i, 0];
+                for (var x=0; x < width; x = x + 16) {
+                    for (var y=0; y < width; y = y + 16) {
+                        var tile = Canvas.getTile(x, y, 16, 16, color);
+                        Canvas.setTile(tile, 0, 0, 16, 16, color);
+                        Canvas.putTile(tile);
+                    }
+                }
+            }
+            var end_time = (new Date()).getTime();
+            return (end_time - start_time);
+        }
+
         window.onload = function() {
-            console.log("here1");
-            Canvas.init('tutorial', 640, 480);
-            Canvas.draw();
-            console.log("here2");
+            Canvas.init('canvas', width, height);
+            Canvas.stop();   // Shut-off event interception
+            $('iterations').value = 10;
+            draw();
+            message("Canvas initialized");
         }
     </script>
 </html>

+ 3 - 1
vnc.js

@@ -835,7 +835,9 @@ recv_message_reorder: function(e) {
         }
     }
 
-    RFB.handle_message();
+    if (RFB.RQ.length > 0) {
+        RFB.handle_message();
+    }
     //console.log("<< recv_message_reorder");
 },