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);