Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / SeaMonster / gaussian-blur.js
1 // Taken from: https://github.com/nodeca/glur
2
3 /*
4 * The MIT License (MIT)
5
6 * Copyright (c) 2014 Andrei Tupitcyn
7
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14
15 * The above copyright notice and this permission notice shall be included in all
16 * copies or substantial portions of the Software.
17
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 // Calculate Gaussian blur of an image using IIR filter
28 // The method is taken from Intel's white paper and code example attached to it:
29 // https://software.intel.com/en-us/articles/iir-gaussian-blur-filter
30 // -implementation-using-intel-advanced-vector-extensions
31
32 var a0, a1, a2, a3, b1, b2, left_corner, right_corner;
33
34 function gaussCoef(sigma) {
35   if (sigma < 0.5) {
36     sigma = 0.5;
37   }
38
39   var a = Math.exp(0.726 * 0.726) / sigma,
40       g1 = Math.exp(-a),
41       g2 = Math.exp(-2 * a),
42       k = (1 - g1) * (1 - g1) / (1 + 2 * a * g1 - g2);
43
44   a0 = k;
45   a1 = k * (a - 1) * g1;
46   a2 = k * (a + 1) * g1;
47   a3 = -k * g2;
48   b1 = 2 * g1;
49   b2 = -g2;
50   left_corner = (a0 + a1) / (1 - b1 - b2);
51   right_corner = (a2 + a3) / (1 - b1 - b2);
52
53   // Attempt to force type to FP32.
54   return new Float32Array([ a0, a1, a2, a3, b1, b2, left_corner, right_corner ]);
55 }
56
57 function convolveRGBA(src, out, line, coeff, width, height) {
58   // takes src image and writes the blurred and transposed result into out
59
60   var rgba;
61   var prev_src_r, prev_src_g, prev_src_b, prev_src_a;
62   var curr_src_r, curr_src_g, curr_src_b, curr_src_a;
63   var curr_out_r, curr_out_g, curr_out_b, curr_out_a;
64   var prev_out_r, prev_out_g, prev_out_b, prev_out_a;
65   var prev_prev_out_r, prev_prev_out_g, prev_prev_out_b, prev_prev_out_a;
66
67   var src_index, out_index, line_index;
68   var i, j;
69   var coeff_a0, coeff_a1, coeff_b1, coeff_b2;
70
71   for (i = 0; i < height; i++) {
72     src_index = i * width;
73     out_index = i;
74     line_index = 0;
75
76     // left to right
77     rgba = src[src_index];
78
79     prev_src_r = rgba & 0xff;
80     prev_src_g = (rgba >> 8) & 0xff;
81     prev_src_b = (rgba >> 16) & 0xff;
82     prev_src_a = (rgba >> 24) & 0xff;
83
84     prev_prev_out_r = prev_src_r * coeff[6];
85     prev_prev_out_g = prev_src_g * coeff[6];
86     prev_prev_out_b = prev_src_b * coeff[6];
87     prev_prev_out_a = prev_src_a * coeff[6];
88
89     prev_out_r = prev_prev_out_r;
90     prev_out_g = prev_prev_out_g;
91     prev_out_b = prev_prev_out_b;
92     prev_out_a = prev_prev_out_a;
93
94     coeff_a0 = coeff[0];
95     coeff_a1 = coeff[1];
96     coeff_b1 = coeff[4];
97     coeff_b2 = coeff[5];
98
99     for (j = 0; j < width; j++) {
100       rgba = src[src_index];
101       curr_src_r = rgba & 0xff;
102       curr_src_g = (rgba >> 8) & 0xff;
103       curr_src_b = (rgba >> 16) & 0xff;
104       curr_src_a = (rgba >> 24) & 0xff;
105
106       curr_out_r = curr_src_r * coeff_a0 + prev_src_r * coeff_a1 + prev_out_r * coeff_b1 + prev_prev_out_r * coeff_b2;
107       curr_out_g = curr_src_g * coeff_a0 + prev_src_g * coeff_a1 + prev_out_g * coeff_b1 + prev_prev_out_g * coeff_b2;
108       curr_out_b = curr_src_b * coeff_a0 + prev_src_b * coeff_a1 + prev_out_b * coeff_b1 + prev_prev_out_b * coeff_b2;
109       curr_out_a = curr_src_a * coeff_a0 + prev_src_a * coeff_a1 + prev_out_a * coeff_b1 + prev_prev_out_a * coeff_b2;
110
111       prev_prev_out_r = prev_out_r;
112       prev_prev_out_g = prev_out_g;
113       prev_prev_out_b = prev_out_b;
114       prev_prev_out_a = prev_out_a;
115
116       prev_out_r = curr_out_r;
117       prev_out_g = curr_out_g;
118       prev_out_b = curr_out_b;
119       prev_out_a = curr_out_a;
120
121       prev_src_r = curr_src_r;
122       prev_src_g = curr_src_g;
123       prev_src_b = curr_src_b;
124       prev_src_a = curr_src_a;
125
126       line[line_index] = prev_out_r;
127       line[line_index + 1] = prev_out_g;
128       line[line_index + 2] = prev_out_b;
129       line[line_index + 3] = prev_out_a;
130       line_index += 4;
131       src_index++;
132     }
133
134     src_index--;
135     line_index -= 4;
136     out_index += height * (width - 1);
137
138     // right to left
139     rgba = src[src_index];
140
141     prev_src_r = rgba & 0xff;
142     prev_src_g = (rgba >> 8) & 0xff;
143     prev_src_b = (rgba >> 16) & 0xff;
144     prev_src_a = (rgba >> 24) & 0xff;
145
146     prev_prev_out_r = prev_src_r * coeff[7];
147     prev_prev_out_g = prev_src_g * coeff[7];
148     prev_prev_out_b = prev_src_b * coeff[7];
149     prev_prev_out_a = prev_src_a * coeff[7];
150
151     prev_out_r = prev_prev_out_r;
152     prev_out_g = prev_prev_out_g;
153     prev_out_b = prev_prev_out_b;
154     prev_out_a = prev_prev_out_a;
155
156     curr_src_r = prev_src_r;
157     curr_src_g = prev_src_g;
158     curr_src_b = prev_src_b;
159     curr_src_a = prev_src_a;
160
161     coeff_a0 = coeff[2];
162     coeff_a1 = coeff[3];
163
164     for (j = width - 1; j >= 0; j--) {
165       curr_out_r = curr_src_r * coeff_a0 + prev_src_r * coeff_a1 + prev_out_r * coeff_b1 + prev_prev_out_r * coeff_b2;
166       curr_out_g = curr_src_g * coeff_a0 + prev_src_g * coeff_a1 + prev_out_g * coeff_b1 + prev_prev_out_g * coeff_b2;
167       curr_out_b = curr_src_b * coeff_a0 + prev_src_b * coeff_a1 + prev_out_b * coeff_b1 + prev_prev_out_b * coeff_b2;
168       curr_out_a = curr_src_a * coeff_a0 + prev_src_a * coeff_a1 + prev_out_a * coeff_b1 + prev_prev_out_a * coeff_b2;
169
170       prev_prev_out_r = prev_out_r;
171       prev_prev_out_g = prev_out_g;
172       prev_prev_out_b = prev_out_b;
173       prev_prev_out_a = prev_out_a;
174
175       prev_out_r = curr_out_r;
176       prev_out_g = curr_out_g;
177       prev_out_b = curr_out_b;
178       prev_out_a = curr_out_a;
179
180       prev_src_r = curr_src_r;
181       prev_src_g = curr_src_g;
182       prev_src_b = curr_src_b;
183       prev_src_a = curr_src_a;
184
185       rgba = src[src_index];
186       curr_src_r = rgba & 0xff;
187       curr_src_g = (rgba >> 8) & 0xff;
188       curr_src_b = (rgba >> 16) & 0xff;
189       curr_src_a = (rgba >> 24) & 0xff;
190
191       rgba = ((line[line_index] + prev_out_r) << 0) +
192         ((line[line_index + 1] + prev_out_g) << 8) +
193         ((line[line_index + 2] + prev_out_b) << 16) +
194         ((line[line_index + 3] + prev_out_a) << 24);
195
196       out[out_index] = rgba;
197
198       src_index--;
199       line_index -= 4;
200       out_index -= height;
201     }
202   }
203 }
204
205
206 function blurRGBA(src, width, height, radius) {
207   // Quick exit on zero radius
208   if (!radius) { return; }
209
210   // Unify input data type, to keep convolver calls isomorphic
211   var src32 = new Uint32Array(src.buffer);
212
213   var out      = new Uint32Array(src32.length),
214       tmp_line = new Float32Array(Math.max(width, height) * 4);
215
216   var coeff = gaussCoef(radius);
217
218   convolveRGBA(src32, out, tmp_line, coeff, width, height, radius);
219   convolveRGBA(out, src32, tmp_line, coeff, height, width, radius);
220 }
221
222 class Benchmark {
223     constructor() {
224         this.width = 800;
225         this.height = 450;
226         this.radius = 15;
227
228         const rand = (function() {
229             let seed = 49734321;
230             return function() {
231                 // Robert Jenkins' 32 bit integer hash function.
232                 seed = ((seed + 0x7ed55d16) + (seed << 12))  & 0xffffffff;
233                 seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
234                 seed = ((seed + 0x165667b1) + (seed << 5))   & 0xffffffff;
235                 seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
236                 seed = ((seed + 0xfd7046c5) + (seed << 3))   & 0xffffffff;
237                 seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
238                 return (seed & 0xfffffff) / 0x10000000;
239             };
240         })();
241
242         const buffer = new Uint32Array(this.width * this.height);
243         for (let i = 0; i < buffer.length; ++i)
244             buffer[i] = rand();
245
246         this.buffer = buffer;
247     }
248
249     runIteration() {
250          blurRGBA(this.buffer, this.width, this.height, this.radius);
251     }
252 }