Double buffering damage tracking

Optimise the copy from the hidden canvas to the visible one a bit
by only copying the modified area.
This commit is contained in:
Pierre Ossman 2016-10-25 16:58:24 +02:00
parent 2ba767a7fe
commit 84cd0e719e
1 changed files with 71 additions and 11 deletions

View File

@ -69,6 +69,10 @@
this._backbuffer = document.createElement('canvas'); this._backbuffer = document.createElement('canvas');
this._drawCtx = this._backbuffer.getContext('2d'); this._drawCtx = this._backbuffer.getContext('2d');
this._damageBounds = { left:0, top:0,
right: this._backbuffer.width,
bottom: this._backbuffer.height };
Util.Debug("User Agent: " + navigator.userAgent); Util.Debug("User Agent: " + navigator.userAgent);
if (Util.Engine.gecko) { Util.Debug("Browser: gecko " + Util.Engine.gecko); } if (Util.Engine.gecko) { Util.Debug("Browser: gecko " + Util.Engine.gecko); }
if (Util.Engine.webkit) { Util.Debug("Browser: webkit " + Util.Engine.webkit); } if (Util.Engine.webkit) { Util.Debug("Browser: webkit " + Util.Engine.webkit); }
@ -149,6 +153,8 @@
vp.x += deltaX; vp.x += deltaX;
vp.y += deltaY; vp.y += deltaY;
this._damage(vp.x, vp.y, vp.w, vp.h);
this.flip(); this.flip();
}, },
@ -186,6 +192,7 @@
canvas.height = height; canvas.height = height;
canvas.style.height = height + 'px'; canvas.style.height = height + 'px';
} }
this._damage(vp.x, vp.y, vp.w, vp.h);
this.flip(); this.flip();
} }
} }
@ -231,6 +238,22 @@
this.viewportChangeSize(); this.viewportChangeSize();
}, },
// Track what parts of the visible canvas that need updating
_damage: function(x, y, w, h) {
if (x < this._damageBounds.left) {
this._damageBounds.left = x;
}
if (y < this._damageBounds.top) {
this._damageBounds.top = y;
}
if ((x + w) > this._damageBounds.right) {
this._damageBounds.right = x + w;
}
if ((y + h) > this._damageBounds.bottom) {
this._damageBounds.bottom = y + h;
}
},
// Update the visible canvas with the contents of the // Update the visible canvas with the contents of the
// rendering canvas // rendering canvas
flip: function(from_queue) { flip: function(from_queue) {
@ -239,17 +262,45 @@
'type': 'flip' 'type': 'flip'
}); });
} else { } else {
// FIXME: We may need to disable image smoothing here var x, y, vx, vy, w, h;
// as well (see copyImage()), but we haven't
// noticed any problem yet. x = this._damageBounds.left;
this._targetCtx.drawImage(this._backbuffer, y = this._damageBounds.top;
this._viewportLoc.x, w = this._damageBounds.right - x;
this._viewportLoc.y, h = this._damageBounds.bottom - y;
this._viewportLoc.w,
this._viewportLoc.h, vx = x - this._viewportLoc.x;
0, 0, vy = y - this._viewportLoc.y;
this._viewportLoc.w,
this._viewportLoc.h); if (vx < 0) {
w += vx;
x -= vx;
vx = 0;
}
if (vy < 0) {
h += vy;
y -= vy;
vy = 0;
}
if ((vx + w) > this._viewportLoc.w) {
w = this._viewportLoc.w - vx;
}
if ((vy + h) > this._viewportLoc.h) {
h = this._viewportLoc.h - vy;
}
if ((w > 0) && (h > 0)) {
// FIXME: We may need to disable image smoothing here
// as well (see copyImage()), but we haven't
// noticed any problem yet.
this._targetCtx.drawImage(this._backbuffer,
x, y, w, h,
vx, vy, w, h);
}
this._damageBounds.left = this._damageBounds.top = 65535;
this._damageBounds.right = this._damageBounds.bottom = 0;
} }
}, },
@ -289,6 +340,7 @@
} else { } else {
this._setFillColor(color); this._setFillColor(color);
this._drawCtx.fillRect(x, y, width, height); this._drawCtx.fillRect(x, y, width, height);
this._damage(x, y, width, height);
} }
}, },
@ -319,6 +371,7 @@
this._drawCtx.drawImage(this._backbuffer, this._drawCtx.drawImage(this._backbuffer,
old_x, old_y, w, h, old_x, old_y, w, h,
new_x, new_y, w, h); new_x, new_y, w, h);
this._damage(new_x, new_y, w, h);
} }
}, },
@ -401,6 +454,8 @@
finishTile: function () { finishTile: function () {
if (this._prefer_js) { if (this._prefer_js) {
this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y); this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y);
this._damage(this._tile_x, this._tile_y,
this._tile.width, this._tile.height);
} }
// else: No-op -- already done by setSubTile // else: No-op -- already done by setSubTile
}, },
@ -472,6 +527,7 @@
drawImage: function (img, x, y) { drawImage: function (img, x, y) {
this._drawCtx.drawImage(img, x, y); this._drawCtx.drawImage(img, x, y);
this._damage(x, y, img.width, img.height);
}, },
changeCursor: function (pixels, mask, hotx, hoty, w, h) { changeCursor: function (pixels, mask, hotx, hoty, w, h) {
@ -613,6 +669,7 @@
data[i + 3] = 255; // Alpha data[i + 3] = 255; // Alpha
} }
this._drawCtx.putImageData(img, x, y); this._drawCtx.putImageData(img, x, y);
this._damage(x, y, img.width, img.height);
}, },
_bgrxImageData: function (x, y, width, height, arr, offset) { _bgrxImageData: function (x, y, width, height, arr, offset) {
@ -625,6 +682,7 @@
data[i + 3] = 255; // Alpha data[i + 3] = 255; // Alpha
} }
this._drawCtx.putImageData(img, x, y); this._drawCtx.putImageData(img, x, y);
this._damage(x, y, img.width, img.height);
}, },
_rgbxImageData: function (x, y, width, height, arr, offset) { _rgbxImageData: function (x, y, width, height, arr, offset) {
@ -637,6 +695,7 @@
img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4)); img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4));
} }
this._drawCtx.putImageData(img, x, y); this._drawCtx.putImageData(img, x, y);
this._damage(x, y, img.width, img.height);
}, },
_cmapImageData: function (x, y, width, height, arr, offset) { _cmapImageData: function (x, y, width, height, arr, offset) {
@ -651,6 +710,7 @@
data[i + 3] = 255; // Alpha data[i + 3] = 255; // Alpha
} }
this._drawCtx.putImageData(img, x, y); this._drawCtx.putImageData(img, x, y);
this._damage(x, y, img.width, img.height);
}, },
_renderQ_push: function (action) { _renderQ_push: function (action) {