|
1 // |jit-test| slow; |
|
2 |
|
3 // XXXbz I would dearly like to wrap it up into a function to avoid polluting |
|
4 // the global scope, but the function ends up heavyweight, and then we lose on |
|
5 // the jit. |
|
6 load(libdir + "mandelbrot-results.js"); |
|
7 //function testMandelbrotAll() { |
|
8 // Configuration options that affect which codepaths we follow. |
|
9 var doImageData = true; |
|
10 var avoidSparseArray = true; |
|
11 |
|
12 // Control of iteration numbers and sizing. We'll do |
|
13 // scaler * colorNames.length iterations or so before deciding that we |
|
14 // don't escape. |
|
15 const scaler = 5; |
|
16 const numRows = 600; |
|
17 const numCols = 600; |
|
18 |
|
19 const colorNames = [ |
|
20 "black", |
|
21 "green", |
|
22 "blue", |
|
23 "red", |
|
24 "purple", |
|
25 "orange", |
|
26 "cyan", |
|
27 "yellow", |
|
28 "magenta", |
|
29 "brown", |
|
30 "pink", |
|
31 "chartreuse", |
|
32 "darkorange", |
|
33 "crimson", |
|
34 "gray", |
|
35 "deeppink", |
|
36 "firebrick", |
|
37 "lavender", |
|
38 "lawngreen", |
|
39 "lightsalmon", |
|
40 "lime", |
|
41 "goldenrod" |
|
42 ]; |
|
43 const threshold = (colorNames.length - 1) * scaler; |
|
44 |
|
45 // Now set up our colors |
|
46 var colors = []; |
|
47 // 3-part for loop (iterators buggy, we will add a separate test for them) |
|
48 for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) { |
|
49 //for (var colorNameIdx in colorNames) { |
|
50 colorNameIdx = parseInt(colorNameIdx); |
|
51 colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]); |
|
52 } |
|
53 |
|
54 // Storage for our point data |
|
55 var points; |
|
56 |
|
57 var scratch = {}; |
|
58 var scratchZ = {}; |
|
59 function complexMult(a, b) { |
|
60 var newr = a.r * b.r - a.i * b.i; |
|
61 var newi = a.r * b.i + a.i * b.r; |
|
62 scratch.r = newr; |
|
63 scratch.i = newi; |
|
64 return scratch; |
|
65 } |
|
66 function complexAdd(a, b) { |
|
67 scratch.r = a.r + b.r; |
|
68 scratch.i = a.i + b.i; |
|
69 return scratch; |
|
70 } |
|
71 function abs(a) { |
|
72 return Math.sqrt(a.r * a.r + a.i * a.i); |
|
73 } |
|
74 |
|
75 function escapeAbsDiff(normZ, absC) { |
|
76 var absZ = Math.sqrt(normZ); |
|
77 return normZ > absZ + absC; |
|
78 } |
|
79 |
|
80 function escapeNorm2(normZ) { |
|
81 return normZ > 4; |
|
82 } |
|
83 |
|
84 function fuzzyColors(i) { |
|
85 return Math.floor(i / scaler) + 1; |
|
86 } |
|
87 |
|
88 function moddedColors(i) { |
|
89 return (i % (colorNames.length - 1)) + 1; |
|
90 } |
|
91 |
|
92 function computeEscapeSpeedObjects(real, imag) { |
|
93 var c = { r: real, i: imag } |
|
94 scratchZ.r = scratchZ.i = 0; |
|
95 var absC = abs(c); |
|
96 for (var i = 0; i < threshold; ++i) { |
|
97 scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ)); |
|
98 if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i, |
|
99 absC)) { |
|
100 return colorMap(i); |
|
101 } |
|
102 } |
|
103 return 0; |
|
104 } |
|
105 |
|
106 function computeEscapeSpeedOneObject(real, imag) { |
|
107 // fold in the fact that we start with 0 |
|
108 var r = real; |
|
109 var i = imag; |
|
110 var absC = abs({r: real, i: imag}); |
|
111 for (var j = 0; j < threshold; ++j) { |
|
112 var r2 = r * r; |
|
113 var i2 = i * i; |
|
114 if (escape(r2 + i2, absC)) { |
|
115 return colorMap(j); |
|
116 } |
|
117 i = 2 * r * i + imag; |
|
118 r = r2 - i2 + real; |
|
119 } |
|
120 return 0; |
|
121 } |
|
122 |
|
123 function computeEscapeSpeedDoubles(real, imag) { |
|
124 // fold in the fact that we start with 0 |
|
125 var r = real; |
|
126 var i = imag; |
|
127 var absC = Math.sqrt(real * real + imag * imag); |
|
128 for (var j = 0; j < threshold; ++j) { |
|
129 var r2 = r * r; |
|
130 var i2 = i * i; |
|
131 if (escape(r2 + i2, absC)) { |
|
132 return colorMap(j); |
|
133 } |
|
134 i = 2 * r * i + imag; |
|
135 r = r2 - i2 + real; |
|
136 } |
|
137 return 0; |
|
138 } |
|
139 |
|
140 var computeEscapeSpeed = computeEscapeSpeedDoubles; |
|
141 var escape = escapeNorm2; |
|
142 var colorMap = fuzzyColors; |
|
143 |
|
144 function addPointOrig(pointArray, n, i, j) { |
|
145 if (!points[n]) { |
|
146 points[n] = []; |
|
147 points[n].push([i, j, 1, 1]); |
|
148 } else { |
|
149 var point = points[n][points[n].length-1]; |
|
150 if (point[0] == i && point[1] == j - point[3]) { |
|
151 ++point[3]; |
|
152 } else { |
|
153 points[n].push([i, j, 1, 1]); |
|
154 } |
|
155 } |
|
156 } |
|
157 |
|
158 function addPointImagedata(pointArray, n, col, row) { |
|
159 var slotIdx = ((row * numCols) + col) * 4; |
|
160 pointArray[slotIdx] = colors[n][0]; |
|
161 pointArray[slotIdx+1] = colors[n][1]; |
|
162 pointArray[slotIdx+2] = colors[n][2]; |
|
163 pointArray[slotIdx+3] = colors[n][3]; |
|
164 } |
|
165 |
|
166 function createMandelSet() { |
|
167 var realRange = { min: -2.1, max: 1 }; |
|
168 var imagRange = { min: -1.5, max: 1.5 }; |
|
169 |
|
170 var addPoint; |
|
171 if (doImageData) { |
|
172 addPoint = addPointImagedata; |
|
173 points = new Array(4*numCols*numRows); |
|
174 if (avoidSparseArray) { |
|
175 for (var idx = 0; idx < 4*numCols*numRows; ++idx) { |
|
176 points[idx] = 0; |
|
177 } |
|
178 } |
|
179 } else { |
|
180 addPoint = addPointOrig; |
|
181 points = []; |
|
182 } |
|
183 var realStep = (realRange.max - realRange.min)/numCols; |
|
184 var imagStep = (imagRange.min - imagRange.max)/numRows; |
|
185 for (var i = 0, curReal = realRange.min; |
|
186 i < numCols; |
|
187 ++i, curReal += realStep) { |
|
188 for (var j = 0, curImag = imagRange.max; |
|
189 j < numRows; |
|
190 ++j, curImag += imagStep) { |
|
191 var n = computeEscapeSpeed(curReal, curImag); |
|
192 addPoint(points, n, i, j) |
|
193 } |
|
194 } |
|
195 var result; |
|
196 if (doImageData) { |
|
197 if (colorMap == fuzzyColors) { |
|
198 result = mandelbrotImageDataFuzzyResult; |
|
199 } else { |
|
200 result = mandelbrotImageDataModdedResult; |
|
201 } |
|
202 } else { |
|
203 result = mandelbrotNoImageDataResult; |
|
204 } |
|
205 return points.toSource() == result; |
|
206 } |
|
207 |
|
208 const escapeTests = [ escapeAbsDiff ]; |
|
209 const colorMaps = [ fuzzyColors, moddedColors ]; |
|
210 const escapeComputations = [ computeEscapeSpeedObjects, |
|
211 computeEscapeSpeedOneObject, |
|
212 computeEscapeSpeedDoubles ]; |
|
213 // Test all possible escape-speed generation codepaths, using the |
|
214 // imageData + sparse array avoidance storage. |
|
215 doImageData = true; |
|
216 avoidSparseArray = true; |
|
217 for (var escapeIdx in escapeTests) { |
|
218 escape = escapeTests[escapeIdx]; |
|
219 for (var colorMapIdx in colorMaps) { |
|
220 colorMap = colorMaps[colorMapIdx]; |
|
221 for (var escapeComputationIdx in escapeComputations) { |
|
222 computeEscapeSpeed = escapeComputations[escapeComputationIdx]; |
|
223 assertEq(createMandelSet(), true); |
|
224 } |
|
225 } |
|
226 } |
|
227 |
|
228 // Test all possible storage strategies. Note that we already tested |
|
229 // doImageData == true with avoidSparseArray == true. |
|
230 escape = escapeAbsDiff; |
|
231 colorMap = fuzzyColors; // This part doesn't really matter too much here |
|
232 computeEscapeSpeed = computeEscapeSpeedDoubles; |
|
233 |
|
234 doImageData = true; |
|
235 avoidSparseArray = false; |
|
236 assertEq(createMandelSet(), true); |
|
237 |
|
238 escape = escapeNorm2; |
|
239 doImageData = false; // avoidSparseArray doesn't matter here |
|
240 assertEq(createMandelSet(), true); |
|
241 //} |
|
242 //testMandelbrotAll(); |