Skip to content

Commit

Permalink
Merge pull request #4286 from yurydelendik/webgl
Browse files Browse the repository at this point in the history
WebGL and misc memory optimizations
  • Loading branch information
brendandahl committed Apr 7, 2014
2 parents 31c260a + 30ab878 commit ed1f8c3
Show file tree
Hide file tree
Showing 14 changed files with 604 additions and 81 deletions.
1 change: 1 addition & 0 deletions examples/acroforms/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<script type="text/javascript" src="../../src/display/api.js"></script>
<script type="text/javascript" src="../../src/display/metadata.js"></script>
<script type="text/javascript" src="../../src/display/canvas.js"></script>
<script type="text/javascript" src="../../src/display/webgl.js"></script>
<script type="text/javascript" src="../../src/display/pattern_helper.js"></script>
<script type="text/javascript" src="../../src/display/font_loader.js"></script>

Expand Down
1 change: 1 addition & 0 deletions examples/helloworld/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<script type="text/javascript" src="../../src/display/api.js"></script>
<script type="text/javascript" src="../../src/display/metadata.js"></script>
<script type="text/javascript" src="../../src/display/canvas.js"></script>
<script type="text/javascript" src="../../src/display/webgl.js"></script>
<script type="text/javascript" src="../../src/display/pattern_helper.js"></script>
<script type="text/javascript" src="../../src/display/font_loader.js"></script>

Expand Down
1 change: 1 addition & 0 deletions make.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ target.bundle = function(args) {
'display/api.js',
'display/metadata.js',
'display/canvas.js',
'display/webgl.js',
'display/pattern_helper.js',
'display/font_loader.js'
]);
Expand Down
61 changes: 36 additions & 25 deletions src/core/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,38 @@ Shadings.Mesh = (function MeshClosure() {
mesh.bounds = [minX, minY, maxX, maxY];
}

function packData(mesh) {
var i, ii, j, jj;

var coords = mesh.coords;
var coordsPacked = new Float32Array(coords.length * 2);
for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
var xy = coords[i];
coordsPacked[j++] = xy[0];
coordsPacked[j++] = xy[1];
}
mesh.coords = coordsPacked;

var colors = mesh.colors;
var colorsPacked = new Uint8Array(colors.length * 3);
for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
var c = colors[i];
colorsPacked[j++] = c[0];
colorsPacked[j++] = c[1];
colorsPacked[j++] = c[2];
}
mesh.colors = colorsPacked;

var figures = mesh.figures;
for (i = 0, ii = figures.length; i < ii; i++) {
var figure = figures[i], ps = figure.coords, cs = figure.colors;
for (j = 0, jj = ps.length; j < jj; j++) {
ps[j] *= 2;
cs[j] *= 3;
}
}
}

function Mesh(stream, matrix, xref, res) {
assert(isStream(stream), 'Mesh data is not a stream');
var dict = stream.dict;
Expand Down Expand Up @@ -757,35 +789,14 @@ Shadings.Mesh = (function MeshClosure() {
}
// calculate bounds
updateBounds(this);

packData(this);
}

Mesh.prototype = {
getIR: function Mesh_getIR() {
var type = this.shadingType;
var i, ii, j;
var coords = this.coords;
var coordsPacked = new Float32Array(coords.length * 2);
for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
var xy = coords[i];
coordsPacked[j++] = xy[0];
coordsPacked[j++] = xy[1];
}
var colors = this.colors;
var colorsPacked = new Uint8Array(colors.length * 3);
for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
var c = colors[i];
colorsPacked[j++] = c[0];
colorsPacked[j++] = c[1];
colorsPacked[j++] = c[2];
}
var figures = this.figures;
var bbox = this.bbox;
var bounds = this.bounds;
var matrix = this.matrix;
var background = this.background;

return ['Mesh', type, coordsPacked, colorsPacked, figures, bounds,
matrix, bbox, background];
return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
this.bounds, this.matrix, this.bbox, this.background];
}
};

Expand Down
7 changes: 7 additions & 0 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ PDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?
PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
false : PDFJS.disableCreateObjectURL);

/**
* Disables WebGL usage.
* @var {boolean}
*/
PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
true : PDFJS.disableWebGL);

/**
* Controls the logging level.
* The constants from PDFJS.VERBOSITY_LEVELS should be used:
Expand Down
68 changes: 51 additions & 17 deletions src/display/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error, PDFJS,
FONT_IDENTITY_MATRIX, Uint32ArrayView, IDENTITY_MATRIX, ImageData,
ImageKind, isArray, isNum, TilingPattern, OPS, Promise, Util, warn,
assert, info, shadow, TextRenderingMode, getShadingPatternFromIR */
assert, info, shadow, TextRenderingMode, getShadingPatternFromIR,
WebGLUtils */

'use strict';

Expand All @@ -26,6 +27,7 @@

// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 16;
var MAX_GROUP_SIZE = 4096;

var COMPILE_TYPE3_GLYPHS = true;

Expand Down Expand Up @@ -600,15 +602,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
}

function composeSMask(ctx, smask, layerCtx) {
var mask = smask.canvas;
var maskCtx = smask.context;
var width = mask.width, height = mask.height;

function genericComposeSMask(maskCtx, layerCtx, width, height,
subtype, backdrop) {
var addBackdropFn;
if (smask.backdrop) {
var cs = smask.colorSpace || ColorSpace.singletons.rgb;
var backdrop = cs.getRgb(smask.backdrop, 0);
if (backdrop) {
addBackdropFn = function (r0, g0, b0, bytes) {
var length = bytes.length;
for (var i = 3; i < length; i += 4) {
Expand All @@ -630,7 +627,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}

var composeFn;
if (smask.subtype === 'Luminosity') {
if (subtype === 'Luminosity') {
composeFn = function (maskDataBytes, layerDataBytes) {
var length = maskDataBytes.length;
for (var i = 3; i < length; i += 4) {
Expand All @@ -651,7 +648,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}

// processing image in chunks to save memory
var chunkSize = 16;
var PIXELS_TO_PROCESS = 65536;
var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
for (var row = 0; row < height; row += chunkSize) {
var chunkHeight = Math.min(chunkSize, height - row);
var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
Expand All @@ -662,9 +660,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {

maskCtx.putImageData(layerData, 0, row);
}
}

ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.drawImage(mask, smask.offsetX, smask.offsetY);
function composeSMask(ctx, smask, layerCtx) {
var mask = smask.canvas;
var maskCtx = smask.context;

ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
smask.offsetX, smask.offsetY);

var backdrop;
if (smask.backdrop) {
var cs = smask.colorSpace || ColorSpace.singletons.rgb;
backdrop = cs.getRgb(smask.backdrop, 0);
}
if (WebGLUtils.isEnabled) {
var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
{subtype: smask.subtype, backdrop: backdrop});
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.drawImage(composed, smask.offsetX, smask.offsetY);
return;
}
genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
smask.subtype, backdrop);
ctx.drawImage(mask, 0, 0);
}

var LINE_CAP_STYLES = ['butt', 'round', 'square'];
Expand Down Expand Up @@ -781,6 +800,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
CachedCanvases.clear();
WebGLUtils.clear();

if (this.textLayer) {
this.textLayer.endLayout();
Expand Down Expand Up @@ -904,6 +924,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.save();

var groupCtx = scratchCanvas.context;
groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);

Expand Down Expand Up @@ -1792,8 +1813,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
// Use ceil in case we're between sizes so we don't create canvas that is
// too small and make the canvas at least 1x1 pixels.
var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
var offsetX = Math.floor(bounds[0]);
var offsetY = Math.floor(bounds[1]);
var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
var scaleX = 1, scaleY = 1;
if (drawnWidth > MAX_GROUP_SIZE) {
scaleX = drawnWidth / MAX_GROUP_SIZE;
drawnWidth = MAX_GROUP_SIZE;
}
if (drawnHeight > MAX_GROUP_SIZE) {
scaleY = drawnHeight / MAX_GROUP_SIZE;
drawnHeight = MAX_GROUP_SIZE;
}

var cacheId = 'groupAt' + this.groupLevel;
if (group.smask) {
Expand All @@ -1806,8 +1838,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {

// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
var offsetX = bounds[0];
var offsetY = bounds[1];
groupCtx.scale(1 / scaleX, 1 / scaleY);
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);

Expand All @@ -1818,6 +1849,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
context: groupCtx,
offsetX: offsetX,
offsetY: offsetY,
scaleX: scaleX,
scaleY: scaleY,
subtype: group.smask.subtype,
backdrop: group.smask.backdrop,
colorSpace: group.colorSpace && ColorSpace.fromIR(group.colorSpace)
Expand All @@ -1827,6 +1860,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// right location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
currentCtx.scale(scaleX, scaleY);
}
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
Expand Down
Loading

0 comments on commit ed1f8c3

Please sign in to comment.