Browse Source

Optimize Context2d::PutImageData. Benchmarked 53% faster.

Benchmark:
var canvas = new Canvas(300, 600);
var ctx = canvas.getContext("2d");
// any manipulation of canvas/ctx here.
var data = ctx.getImageData(0,0,300,600);
// time 1000x:
ctx.putImageData(data, 0, 0);
v1.x
Zach Bjornson 10 years ago
parent
commit
76580a8199
  1. 48
      src/CanvasRenderingContext2d.cc

48
src/CanvasRenderingContext2d.cc

@ -605,12 +605,15 @@ NAN_METHOD(Context2d::PutImageData) {
sy = args[4]->Int32Value();
sw = args[5]->Int32Value();
sh = args[6]->Int32Value();
// clamp the left edge
if (sx < 0) sw += sx, sx = 0;
if (sy < 0) sh += sy, sy = 0;
// clamp the right edge
if (sx + sw > imageData->width()) sw = imageData->width() - sx;
if (sy + sh > imageData->height()) sh = imageData->height() - sy;
dx += sx;
dy += sy;
// clamp width at canvas size
cols = std::min(sw, context->canvas()->width - dx);
rows = std::min(sh, context->canvas()->height - dy);
break;
@ -620,27 +623,36 @@ NAN_METHOD(Context2d::PutImageData) {
if (cols <= 0 || rows <= 0) NanReturnUndefined();
uint8_t *srcRows = src + sy * srcStride + sx * 4;
src += sy * srcStride + sx * 4;
dst += dstStride * dy + 4 * dx;
for (int y = 0; y < rows; ++y) {
uint32_t *row = (uint32_t *)(dst + dstStride * (y + dy));
uint8_t *dstRow = dst;
uint8_t *srcRow = src;
for (int x = 0; x < cols; ++x) {
int bx = x * 4;
uint32_t *pixel = row + x + dx;
// RGBA
uint8_t a = srcRows[bx + 3];
uint8_t r = srcRows[bx + 0];
uint8_t g = srcRows[bx + 1];
uint8_t b = srcRows[bx + 2];
float alpha = (float) a / 255;
// ARGB
*pixel = a << 24
| (int)((float) r * alpha) << 16
| (int)((float) g * alpha) << 8
| (int)((float) b * alpha);
// rgba
uint8_t r = *srcRow++;
uint8_t g = *srcRow++;
uint8_t b = *srcRow++;
uint8_t a = *srcRow++;
// argb
// performance optimization: fully transparent/opaque pixels can be
// processed more efficiently.
if (a == 0 || a == 255) {
*dstRow++ = b;
*dstRow++ = g;
*dstRow++ = r;
*dstRow++ = a;
} else {
float alpha = (float)a / 255;
*dstRow++ = b * alpha;
*dstRow++ = g * alpha;
*dstRow++ = r * alpha;
*dstRow++ = a;
}
}
srcRows += srcStride;
dst += dstStride;
src += srcStride;
}
cairo_surface_mark_dirty_rectangle(

Loading…
Cancel
Save