added buffered instructions for canvas; seems to be performant
authorroot <root@brendanfh.com>
Thu, 24 Mar 2022 14:27:41 +0000 (14:27 +0000)
committerroot <root@brendanfh.com>
Thu, 24 Mar 2022 14:27:41 +0000 (14:27 +0000)
static/src/canvas.js
static/src/worker.js

index a880bfb3535032c994c1135b439b4fa646b7187a..58c74b1f68d2695ee6ed432b6d53f351acff1a56 100644 (file)
@@ -1,5 +1,6 @@
 let canvas_element = "";
 let ctx = null;
+let canvas_op_buffer = [];
 
 function update_canvas_data() {
     let canvas_data = new Int32Array(canvas_shared_buffer);
@@ -14,8 +15,26 @@ function update_canvas_data() {
     Atomics.notify(canvas_data, 2);
 }
 
+function canvas_buffer_flush() {
+    canvas_op_buffer.sort((a, b) => a[0] - b[0]);
+
+    for (let op of canvas_op_buffer) {
+        canvas_process(op);
+    }
+
+    canvas_op_buffer = [];
+}
+
 function canvas_handler(instr) {
-    switch (instr[0]) {
+    if (instr[1] == 'sync' || instr[1] == 'init') {
+        canvas_process(instr);
+    } else {
+        canvas_op_buffer.push(instr);
+    }
+}
+
+function canvas_process(instr) {
+    switch (instr[1]) {
         case 'init': {
             canvas_element = document.getElementById("render-target");
             ctx = canvas_element.getContext('2d');
@@ -25,6 +44,7 @@ function canvas_handler(instr) {
 
         case 'sync': {
             window.requestAnimationFrame(() => {
+                canvas_buffer_flush();
                 let canvas_data = new Int32Array(canvas_shared_buffer);
                 Atomics.store(canvas_data, 2, 1);
                 Atomics.notify(canvas_data, 2);
@@ -32,37 +52,37 @@ function canvas_handler(instr) {
             break;
         }
 
-        case 'fill_style': ctx.fillStyle = instr[1]; break;
-        case 'font': ctx.font = instr[1]; break;
-        case 'image_smoothing_enabled': ctx.imageSmoothingEnabled = instr[1]; break;
-        case 'line_join': ctx.lineJoin = instr[1]; break;
-        case 'line_width': ctx.lineWidth = instr[1]; break;
-        case 'stroke_style': ctx.strokeStyle = instr[1]; break;
-        case 'text_align': ctx.textAlign = instr[1]; break;
+        case 'fill_style': ctx.fillStyle = instr[2]; break;
+        case 'font': ctx.font = instr[2]; break;
+        case 'image_smoothing_enabled': ctx.imageSmoothingEnabled = instr[2]; break;
+        case 'line_join': ctx.lineJoin = instr[2]; break;
+        case 'line_width': ctx.lineWidth = instr[2]; break;
+        case 'stroke_style': ctx.strokeStyle = instr[2]; break;
+        case 'text_align': ctx.textAlign = instr[2]; break;
 
-        case 'arc': ctx.arc(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
-        case 'arc_to': ctx.arcTo(instr[1], instr[2], instr[3], instr[4], instr[5]); break;
+        case 'arc': ctx.arc(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
+        case 'arc_to': ctx.arcTo(instr[2], instr[3], instr[4], instr[5], instr[6]); break;
         case 'begin_path': ctx.beginPath(); break;
         case 'clear': ctx.clearRect(0, 0, canvas_element.width, canvas_element.height); break;
-        case 'clear_rect': ctx.clearRect(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'clip': ctx.clip(instr[1]); break;
+        case 'clear_rect': ctx.clearRect(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'clip': ctx.clip(instr[2]); break;
         case 'close_path': ctx.closePath(); break;
-        case 'ellipse': ctx.ellipse(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6], instr[7], instr[8]); break;
-        case 'fill': ctx.fill(instr[1]); break;
-        case 'fill_rect': ctx.fillRect(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'fill_text': ctx.fillText(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'line_to': ctx.lineTo(instr[1], instr[2]); break;
-        case 'move_to': ctx.moveTo(instr[1], instr[2]); break;
-        case 'quadratic_curve_to': ctx.quadraticCurveTo(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'rect': ctx.rect(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'rotate': ctx.rotate(instr[1]); break;
+        case 'ellipse': ctx.ellipse(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7], instr[8], instr[9]); break;
+        case 'fill': ctx.fill(instr[2]); break;
+        case 'fill_rect': ctx.fillRect(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'fill_text': ctx.fillText(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'line_to': ctx.lineTo(instr[2], instr[3]); break;
+        case 'move_to': ctx.moveTo(instr[2], instr[3]); break;
+        case 'quadratic_curve_to': ctx.quadraticCurveTo(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'rect': ctx.rect(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'rotate': ctx.rotate(instr[2]); break;
         case 'save': ctx.save(); break;
-        case 'scale': ctx.scale(instr[1], instr[2]); break;
-        case 'set_transform': ctx.setTransform(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
+        case 'scale': ctx.scale(instr[2], instr[3]); break;
+        case 'set_transform': ctx.setTransform(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
         case 'stroke': ctx.stroke(); break;
-        case 'stroke_rect': ctx.strokeRect(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'stroke_text': ctx.strokeText(instr[1], instr[2], instr[3], instr[4]); break;
-        case 'transform': ctx.transform(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
-        case 'translate': ctx.translate(instr[1], instr[2]); break;
+        case 'stroke_rect': ctx.strokeRect(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'stroke_text': ctx.strokeText(instr[2], instr[3], instr[4], instr[5]); break;
+        case 'transform': ctx.transform(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
+        case 'translate': ctx.translate(instr[2], instr[3]); break;
     }
 }
index b2a1df884a3b5a4baf04171ac0a97d027b4dfc50..1090777115b6ddc8549c0ef0c253479ab33e47bb 100644 (file)
@@ -7,6 +7,8 @@ function S(strptr, strlen) {
     return new TextDecoder().decode(strdata);
 }
 
+let canvas_order_id = 0;
+
 let import_obj = {
     host: {
         print_str(strptr, strlen) {
@@ -48,7 +50,8 @@ let import_obj = {
 
     canvas: {
         init() {
-            self.postMessage({ type: 'canvas', data: [ 'init' ] });
+            self.postMessage({ type: 'canvas', data: [ 0, 'init' ] });
+            canvas_order_id = 0;
 
             // Issue a synchronization because the data needs to be correct
             // before control should be handed back to the running program.
@@ -58,7 +61,7 @@ let import_obj = {
         },
 
         sync() {
-            self.postMessage({ type: 'canvas', data: [ 'sync'] });
+            self.postMessage({ type: 'canvas', data: [ 0, 'sync'] });
 
             let canvas_data = new Int32Array(canvas_data_buffer);
             Atomics.wait(canvas_data, 2, 0);
@@ -74,9 +77,9 @@ let import_obj = {
         },
 
         // Settings
-        fill_style(styleptr, stylelen) { self.postMessage({ type: 'canvas', data: [ 'fill_style', S(styleptr, stylelen) ] }); },
-        font(p, l) { self.postMessage({ type: 'canvas', data: [ 'font', S(p, l) ] }); },
-        image_smoothing_enabled(e) { self.postMessage({ type: 'canvas', data: [ 'image_smoothing_enabled', e != 0 ] }); },
+        fill_style(styleptr, stylelen) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_style', S(styleptr, stylelen) ] }); },
+        font(p, l) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'font', S(p, l) ] }); },
+        image_smoothing_enabled(e) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'image_smoothing_enabled', e != 0 ] }); },
         line_join(join) {
             let method = "";
             switch (join) {
@@ -86,11 +89,11 @@ let import_obj = {
             }
 
             if (method != "") {
-                self.postMessage({ type: 'canvas', data: [ 'line_join' , method ] });
+                self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_join' , method ] });
             }
         },
-        line_width(width) { self.postMessage({ type: 'canvas', data: [ 'line_width', width ] }); },
-        stroke_style(s, l) { self.postMessage({ type: 'canvas', data: [ 'stroke_style', S(s, l) ] }); },
+        line_width(width) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_width', width ] }); },
+        stroke_style(s, l) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_style', S(s, l) ] }); },
         text_align(align) {
             let method = "";
             switch (align) {
@@ -102,16 +105,16 @@ let import_obj = {
             }
 
             if (method != "") {
-                self.postMessage({ type: 'canvas', data: [ 'text_align' , method ] });
+                self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'text_align' , method ] });
             }
         },
 
         // Drawing
-        arc(x, y, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ 'arc', x, y, r, sa, ea, cc != 0 ] }); },
-        arc_to(x1, y1, x2, y2, r) { self.postMessage({ type: 'canvas', data: [ 'arc_to', x1, y1, x2, y2, r ] }); },
-        begin_path() { self.postMessage({ type: 'canvas', data: [ 'begin_path' ] }); },
-        clear() { self.postMessage({ type: 'canvas', data: [ 'clear' ] }); },
-        clear_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'clear_rect', x, y, w, h ] }); },
+        arc(x, y, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'arc', x, y, r, sa, ea, cc != 0 ] }); },
+        arc_to(x1, y1, x2, y2, r) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'arc_to', x1, y1, x2, y2, r ] }); },
+        begin_path() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'begin_path' ] }); },
+        clear() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clear' ] }); },
+        clear_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clear_rect', x, y, w, h ] }); },
         clip(cliprule) {
             let method = "";
             switch (cliprule) {
@@ -120,11 +123,11 @@ let import_obj = {
             }
 
             if (method != "") {
-                self.postMessage({ type: 'canvas', data: [ 'clip', method ] });
+                self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clip', method ] });
             }
         },
-        close_path() { self.postMessage({ type: 'canvas', data: [ 'close_path' ] }); },
-        ellipse(x, y, rx, ry, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ 'ellipse', x, y, rx, ry, r, sa, ea, cc != 0 ] }); },
+        close_path() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'close_path' ] }); },
+        ellipse(x, y, rx, ry, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'ellipse', x, y, rx, ry, r, sa, ea, cc != 0 ] }); },
         fill(fillrule) {
             let method = "";
             switch (fillrule) {
@@ -133,27 +136,27 @@ let import_obj = {
             }
 
             if (method != "") {
-                self.postMessage({ type: 'canvas', data: [ 'fill', method ] });
+                self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill', method ] });
             }
         },
-        fill_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'fill_rect', x, y, w, h ] }); },
+        fill_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_rect', x, y, w, h ] }); },
         fill_text(textptr, textlen, x, y, max_width) {
-            self.postMessage({ type: 'canvas', data: [ 'fill_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] });
+            self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] });
         },
-        line_to(x, y) { self.postMessage({ type: 'canvas', data: [ 'line_to', x, y ] }); },
-        move_to(x, y) { self.postMessage({ type: 'canvas', data: [ 'move_to', x, y ] }); },
-        quadratic_curve_to(cpx, cpy, x, y) { self.postMessage({ type: 'canvas', data: [ 'quadratic_curve_to', cpx, cpy, x, y ] }); },
-        rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'rect', x, y, w, h ] }); },
-        restore() { self.postMessage({ type: 'canvas', data: [ 'restore' ] }); },
-        rotate(angle) { self.postMessage({ type: 'canvas', data: [ 'rotate', angle ] }); },
-        save() { self.postMessage({ type: 'canvas', data: [ 'save' ] }); },
-        scale(x, y) { self.postMessage({ type: 'canvas', data: [ 'scale', x, y ] }); },
-        set_transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ 'set_transform', a, b, c, d, e, f ] }); },
-        stroke() { self.postMessage({ type: 'canvas', data: [ 'stroke' ] }); },
-        stroke_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'stroke_rect', x, y, w, h ] }); },
-        stroke_text(textptr, textlen, x, y, max_width) { self.postMessage({ type: 'canvas', data: [ 'stroke_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] }); },
-        transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ 'transform', a, b, c, d, e, f ] }); },
-        translate(x, y) { self.postMessage({ type: 'canvas', data: [ 'translate', x, y ] }); },
+        line_to(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_to', x, y ] }); },
+        move_to(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'move_to', x, y ] }); },
+        quadratic_curve_to(cpx, cpy, x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'quadratic_curve_to', cpx, cpy, x, y ] }); },
+        rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'rect', x, y, w, h ] }); },
+        restore() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'restore' ] }); },
+        rotate(angle) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'rotate', angle ] }); },
+        save() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'save' ] }); },
+        scale(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'scale', x, y ] }); },
+        set_transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'set_transform', a, b, c, d, e, f ] }); },
+        stroke() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke' ] }); },
+        stroke_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_rect', x, y, w, h ] }); },
+        stroke_text(textptr, textlen, x, y, max_width) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] }); },
+        transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'transform', a, b, c, d, e, f ] }); },
+        translate(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'translate', x, y ] }); },
     }
 };
 
@@ -176,6 +179,7 @@ onmessage = function(m) {
                     self.postMessage({ type: 'errored', data: e.toString() });
                 }
 
+                self.postMessage({ type: 'canvas', data: [ 0, 'sync' ] });
                 self.postMessage({ type: 'terminated' });
                 self.close();
             });
@@ -184,6 +188,7 @@ onmessage = function(m) {
         }
 
         case 'stop':
+            self.postMessage({ type: 'canvas', data: [ 0, 'sync' ] });
             self.postMessage({ type: 'terminated' });
             self.close();
             break;