diff --git a/docs/api.md b/docs/api.md index 637a6e8e..dcfbf178 100644 --- a/docs/api.md +++ b/docs/api.md @@ -426,8 +426,6 @@ Use WebP format for the output image. #### raw() -_Requires libvips 7.42.0+_ - Provide raw, uncompressed uint8 (unsigned char) image data for Buffer and Stream based output. The number of channels depends on the input image and selected options. @@ -497,13 +495,11 @@ An advanced setting for the _zlib_ compression level of the lossless PNG output #### withoutAdaptiveFiltering() -_Requires libvips 7.42.0+_ - An advanced setting to disable adaptive row filtering for the lossless PNG output format. #### trellisQuantisation() / trellisQuantization() -_Requires libvips 8.0.0+ compiled against mozjpeg 3.0+_ +_Requires libvips to have been compiled with mozjpeg support_ An advanced setting to apply the use of [trellis quantisation](http://en.wikipedia.org/wiki/Trellis_quantization) with JPEG output. @@ -511,7 +507,7 @@ Reduces file size and slightly increases relative quality at the cost of increas #### overshootDeringing() -_Requires libvips 8.0.0+ compiled against mozjpeg 3.0+_ +_Requires libvips to have been compiled with mozjpeg support_ An advanced setting to reduce the effects of [ringing](http://en.wikipedia.org/wiki/Ringing_%28signal%29) in JPEG output, @@ -519,7 +515,7 @@ in particular where black text appears on a white background (or vice versa). #### optimiseScans() / optimizeScans() -_Requires libvips 8.0.0+ compiled against mozjpeg 3.0+_ +_Requires libvips to have been compiled with mozjpeg support_ An advanced setting for progressive (interlace) JPEG output. Calculates which spectrum of DCT coefficients uses the fewest bits. @@ -633,3 +629,31 @@ Provides access to internal task counters. ```javascript var counters = sharp.counters(); // { queue: 2, process: 4 } ``` + +#### sharp.simd([enable]) + +_Requires libvips to have been compiled with liborc support_ + +Improves the performance of `resize`, `blur` and `sharpen` operations +by taking advantage of the SIMD vector unit of the CPU. + +* `enable`, if present, is a boolean where `true` enables and `false` disables the use of SIMD. + +This method always returns the current state. + +This feature is currently disabled by default +but future versions may enable it by default. + +When enabled, versions of liborc prior to 0.4.24 +and versions of libvips prior to 8.2.0 +have been known to crash under heavy load. + +```javascript +var simd = sharp.simd(); +// simd is `true` is SIMD is currently enabled +``` + +```javascript +var simd = sharp.simd(true); +// attempts to enable the use of SIMD, returning true if available +``` diff --git a/docs/changelog.md b/docs/changelog.md index 44610b58..5bcdd147 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,7 +2,12 @@ ### v0.12 - "*look*" -#### v0.12.1 - TBD +#### v0.12.1 - 12th December 2015 + +* Allow use of SIMD vector instructions (via liborc) to be toggled on/off. + [#172](https://github.com/lovell/sharp/issues/172) + [@bkw](https://github.com/bkw) + [@puzrin](https://github.com/puzrin) * Ensure embedded ICC profiles output with perceptual intent. [#321](https://github.com/lovell/sharp/issues/321) diff --git a/index.js b/index.js index c0cac547..268796d0 100644 --- a/index.js +++ b/index.js @@ -863,3 +863,15 @@ module.exports.concurrency = function(concurrency) { module.exports.counters = function() { return sharp.counters(); }; + +/* + Get and set use of SIMD vector unit instructions +*/ +module.exports.simd = function(simd) { + if (typeof simd !== 'boolean') { + simd = null; + } + return sharp.simd(simd); +}; +// Switch off default +module.exports.simd(false); diff --git a/package.json b/package.json index 6da5aff5..6060ebcc 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "devDependencies": { "async": "^1.5.0", - "coveralls": "^2.11.4", + "coveralls": "^2.11.6", "exif-reader": "^1.0.0", "icc": "^0.0.2", "istanbul": "^0.4.0", diff --git a/src/sharp.cc b/src/sharp.cc old mode 100755 new mode 100644 index 07f30e31..7849b141 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -26,6 +26,8 @@ NAN_MODULE_INIT(init) { Nan::GetFunction(Nan::New(concurrency)).ToLocalChecked()); Nan::Set(target, Nan::New("counters").ToLocalChecked(), Nan::GetFunction(Nan::New(counters)).ToLocalChecked()); + Nan::Set(target, Nan::New("simd").ToLocalChecked(), + Nan::GetFunction(Nan::New(simd)).ToLocalChecked()); Nan::Set(target, Nan::New("libvipsVersion").ToLocalChecked(), Nan::GetFunction(Nan::New(libvipsVersion)).ToLocalChecked()); Nan::Set(target, Nan::New("format").ToLocalChecked(), diff --git a/src/utilities.cc b/src/utilities.cc index 8b5af4d3..1a20616a 100644 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include "nan.h" @@ -81,6 +82,20 @@ NAN_METHOD(counters) { info.GetReturnValue().Set(counters); } +/* + Get and set use of SIMD vector unit instructions +*/ +NAN_METHOD(simd) { + HandleScope(); + + // Set state + if (info[0]->IsBoolean()) { + vips_vector_set_enabled(To(info[0]).FromJust()); + } + // Get state + info.GetReturnValue().Set(New(vips_vector_isenabled())); +} + /* Get libvips version */ diff --git a/src/utilities.h b/src/utilities.h old mode 100755 new mode 100644 index a7cb80a1..2231ce67 --- a/src/utilities.h +++ b/src/utilities.h @@ -6,6 +6,7 @@ NAN_METHOD(cache); NAN_METHOD(concurrency); NAN_METHOD(counters); +NAN_METHOD(simd); NAN_METHOD(libvipsVersion); NAN_METHOD(format); NAN_METHOD(_maxColourDistance); diff --git a/test/bench/package.json b/test/bench/package.json index 76075b22..7aeb4fac 100644 --- a/test/bench/package.json +++ b/test/bench/package.json @@ -13,7 +13,7 @@ "gm": "^1.21.0", "imagemagick": "^0.1.3", "imagemagick-native": "elad/node-imagemagick-native", - "jimp": "^0.2.19", + "jimp": "^0.2.20", "lwip": "^0.0.8", "semver": "^5.1.0" }, diff --git a/test/bench/parallel.js b/test/bench/parallel.js index d0543e31..549783ce 100644 --- a/test/bench/parallel.js +++ b/test/bench/parallel.js @@ -12,6 +12,7 @@ var width = 720; var height = 480; sharp.concurrency(1); +sharp.simd(true); var timer = setInterval(function() { console.dir(sharp.counters()); diff --git a/test/bench/perf.js b/test/bench/perf.js index a19e1d67..7752cdd8 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -35,6 +35,8 @@ var magickFilterBicubic = 'Lanczos'; // Disable libvips cache to ensure tests are as fair as they can be sharp.cache(0); +// Enable use of SIMD +sharp.simd(true); async.series({ 'jpeg-linear': function(callback) { @@ -496,6 +498,24 @@ async.series({ } }); } + }).add('sharp-without-simd', { + defer: true, + fn: function(deferred) { + sharp.simd(false); + sharp(inputJpgBuffer) + .rotate(90) + .interpolateWith(sharp.interpolator.bilinear) + .resize(width, height) + .toBuffer(function(err, buffer) { + sharp.simd(true); + if (err) { + throw err; + } else { + assert.notStrictEqual(null, buffer); + deferred.resolve(); + } + }); + } }).add('sharp-sequentialRead', { defer: true, fn: function(deferred) { diff --git a/test/bench/random.js b/test/bench/random.js index a72b81a2..63344b47 100644 --- a/test/bench/random.js +++ b/test/bench/random.js @@ -8,6 +8,8 @@ var Benchmark = require('benchmark'); var sharp = require('../../index'); var fixtures = require('../fixtures'); +sharp.simd(true); + var min = 320; var max = 960; diff --git a/test/unit/util.js b/test/unit/util.js index d3b15428..a7efbf31 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -51,6 +51,21 @@ describe('Utilities', function() { }); }); + describe('SIMD', function() { + it('Can get current state', function() { + var simd = sharp.simd(); + assert.strictEqual(typeof simd, 'boolean'); + }); + it('Can disable', function() { + var simd = sharp.simd(false); + assert.strictEqual(simd, false); + }); + it('Can attempt to enable', function() { + var simd = sharp.simd(true); + assert.strictEqual(typeof simd, 'boolean'); + }); + }); + describe('Format', function() { it('Contains expected attributes', function() { assert.strictEqual('object', typeof sharp.format);