| OLD | NEW |
| (Empty) | |
| 1 define([ 'sprites/sources', 'sprites/transformers', 'sprites/renderers', 'util/e
nsureCallback', 'util/chainAsync', 'util/benchAsync' ], function (sources, trans
formers, renderers, ensureCallback, chainAsync, benchAsync) { |
| 2 var FRAME_COUNT = 100; |
| 3 var TARGET_FRAMERATE = 30; |
| 4 |
| 5 function generateFrames(transformer, frameCount, objectCount) { |
| 6 var frames = [ ]; |
| 7 |
| 8 var i, j; |
| 9 for (i = 0; i < frameCount; ++i) { |
| 10 var frame = [ ]; |
| 11 frames.push(frame); |
| 12 |
| 13 for (j = 0; j < objectCount; ++j) { |
| 14 frame.push(transformer(i, j)); |
| 15 } |
| 16 } |
| 17 |
| 18 return frames; |
| 19 } |
| 20 |
| 21 function runTest(sourceData, objectCount, transformer, renderer, callback) { |
| 22 callback = ensureCallback(callback); |
| 23 |
| 24 var frames = generateFrames(transformer, FRAME_COUNT, objectCount); |
| 25 var renderContext = renderer(sourceData, frames); |
| 26 |
| 27 renderContext.load(function (err) { |
| 28 if (err) return callback(err); |
| 29 |
| 30 var jsTime = 0; |
| 31 |
| 32 function frame(i, next) { |
| 33 setTimeout(next, 0); |
| 34 |
| 35 var frame = i % FRAME_COUNT; |
| 36 var jsStartTime = Date.now(); |
| 37 renderContext.renderFrame(frame); |
| 38 var jsEndTime = Date.now(); |
| 39 jsTime += jsEndTime - jsStartTime; |
| 40 } |
| 41 |
| 42 function done(err, score) { |
| 43 renderContext.unload(); |
| 44 |
| 45 callback(null, { |
| 46 js: jsTime, |
| 47 fps: score |
| 48 }); |
| 49 } |
| 50 |
| 51 // We must run the tests twice |
| 52 // due to Android CSS background loading bugs. |
| 53 benchAsync(1000, frame, function (err, _) { |
| 54 if (typeof renderContext.clear === 'function') { |
| 55 renderContext.clear(); |
| 56 } |
| 57 |
| 58 benchAsync(1000, frame, done); |
| 59 }); |
| 60 }); |
| 61 } |
| 62 |
| 63 function runTestToFramerate(targetFramerate, sourceData, transformer, render
er, callback) { |
| 64 callback = ensureCallback(callback); |
| 65 |
| 66 // objectCount => { js, fps } |
| 67 var fpsResults = { }; |
| 68 |
| 69 // (objectCount, { js, fps }) |
| 70 var rawData = [ ]; |
| 71 |
| 72 function done() { |
| 73 var mostObjectsAboveThirtyFPS = -1; |
| 74 var minObjectsBelowThirtyFPS = -1; |
| 75 for (var i = 0; i < rawData.length; i++) { |
| 76 var temp = rawData[i]; |
| 77 if (temp[1].fps > 30) { |
| 78 if (mostObjectsAboveThirtyFPS === -1 || temp[0] > rawData[mo
stObjectsAboveThirtyFPS][0]) { |
| 79 mostObjectsAboveThirtyFPS = i; |
| 80 } |
| 81 } else { |
| 82 if (minObjectsBelowThirtyFPS === -1 || temp[0] < rawData[min
ObjectsBelowThirtyFPS][0]) { |
| 83 minObjectsBelowThirtyFPS = i; |
| 84 } |
| 85 } |
| 86 } |
| 87 |
| 88 if (mostObjectsAboveThirtyFPS === -1 || minObjectsBelowThirtyFPS ===
-1) { |
| 89 callback(new Error("Bad test results")); |
| 90 return; |
| 91 } |
| 92 |
| 93 var aboveData = rawData[mostObjectsAboveThirtyFPS]; |
| 94 var belowData = rawData[minObjectsBelowThirtyFPS]; |
| 95 |
| 96 var m = (aboveData[0] - belowData[0]) / (aboveData[1].fps - belowDat
a[1].fps); |
| 97 var objectCount = belowData[0] + m * (30 - belowData[1].fps); |
| 98 var jsTime = belowData[0] + m * (30 - belowData[1].js); |
| 99 |
| 100 callback(null, { |
| 101 objectCount: objectCount, |
| 102 js: jsTime, |
| 103 rawData: rawData |
| 104 }); |
| 105 } |
| 106 |
| 107 // Run the test in steps of 25 (0, 25, 50, 75), |
| 108 // then in steps of 5 (20, 25, 30, 35) |
| 109 // then in steps of 1 (25, 26, 27, 28) |
| 110 var objectCountSteps = [ 1, 5, 25 ]; |
| 111 var objectCountStep = objectCountSteps.pop(); |
| 112 |
| 113 function test(objectCount) { |
| 114 if (Object.prototype.hasOwnProperty.call(fpsResults, objectCount)) { |
| 115 // Already tested; let's say we're done here |
| 116 done(); |
| 117 return; |
| 118 } |
| 119 |
| 120 runTest(sourceData, objectCount, transformer, renderer, function tes
tDone(err, results) { |
| 121 if (err) return callback(err); |
| 122 |
| 123 fpsResults[objectCount] = results; |
| 124 rawData.push([ objectCount, results ]); |
| 125 |
| 126 if (results.fps < targetFramerate) { |
| 127 // Hit too low (too many objects); go back and lower step |
| 128 // FIXME This may infloop (I think) |
| 129 var nextObjectCountStep = objectCountSteps.length ? objectCo
untSteps.pop() : 1; |
| 130 var newObjectCount = Math.max(0, objectCount - objectCountSt
ep + nextObjectCountStep); |
| 131 objectCountStep = nextObjectCountStep; |
| 132 test(newObjectCount); |
| 133 } else if (results.fps > targetFramerate) { |
| 134 // Hit too high (too few objects); keep going |
| 135 var newObjectCount = objectCount + objectCountStep; |
| 136 test(newObjectCount); |
| 137 } else { |
| 138 // Hit it exactly! (Creepy.) |
| 139 done(); |
| 140 } |
| 141 }); |
| 142 } |
| 143 |
| 144 test(0); |
| 145 } |
| 146 |
| 147 // source => renderer => transformer => test |
| 148 var tests = { }; |
| 149 |
| 150 Object.keys(sources).forEach(function (sourceName) { |
| 151 var source = sources[sourceName]; |
| 152 |
| 153 var subTests = { }; |
| 154 tests[sourceName] = subTests; |
| 155 |
| 156 Object.keys(renderers).forEach(function (rendererName) { |
| 157 var renderer = renderers[rendererName]; |
| 158 |
| 159 var subSubTests = { }; |
| 160 subTests[rendererName] = subSubTests; |
| 161 |
| 162 Object.keys(transformers).forEach(function (transformerName) { |
| 163 var transformer = transformers[transformerName]; |
| 164 |
| 165 subSubTests[transformerName] = function spriteTest(callback) { |
| 166 source(function (err, sourceData) { |
| 167 if (err) return callback(err); |
| 168 runTestToFramerate(TARGET_FRAMERATE, sourceData, transfo
rmer, renderer, callback); |
| 169 }); |
| 170 }; |
| 171 }); |
| 172 }); |
| 173 }); |
| 174 |
| 175 return tests; |
| 176 }); |
| OLD | NEW |