1 define([ 'sprites/sources', 'sprites/transformers', 'sprites/renderers', 'util/ensureCallback', 'util/chainAsync', 'util/benchAsync' ], function (sources
, transformers
, renderers
, ensureCallback
, chainAsync
, benchAsync
) {
3 var TARGET_FRAMERATE
= 30;
5 function frameGenerator(transformer
, frameCount
) {
6 // objectIndex => frameIndex => transform
9 return function generateFrames(objectCount
) {
10 // Generate frame data for new objects, if necessary
11 while (objectDatas
.length
< objectCount
) {
12 var objectIndex
= objectDatas
.length
;
14 // frameIndex => transform
16 objectDatas
.push(transforms
);
18 for (var frameIndex
= 0; frameIndex
< FRAME_COUNT
; ++frameIndex
) {
19 transforms
.push(transformer(frameIndex
, objectIndex
));
23 // frameIndex => objectIndex => transform
24 // Transpose objectDatas, with `objectCount` transforms.
26 for (var i
= 0; i
< FRAME_COUNT
; ++i
) {
29 for (var j
= 0; j
< objectCount
; ++j
) {
30 frame
.push(objectDatas
[j
][i
]);
38 function runTest(sourceData
, frames
, renderer
, callback
) {
39 callback
= ensureCallback(callback
);
41 var renderContext
= renderer(sourceData
, frames
);
43 renderContext
.load(function (err
) {
44 if (err
) return callback(err
);
48 function frame(i
, next
) {
51 var frame
= i
% FRAME_COUNT
;
52 var jsStartTime
= Date
.now();
53 renderContext
.renderFrame(frame
);
54 var jsEndTime
= Date
.now();
55 jsTime
+= jsEndTime
- jsStartTime
;
58 function done(err
, results
) {
59 renderContext
.unload();
68 // We must run the tests twice
69 // due to Android CSS background loading bugs.
70 benchAsync(1000, frame
, function (err
, _
) {
71 if (typeof renderContext
.clear
=== 'function') {
72 renderContext
.clear();
75 benchAsync(1000, frame
, done
);
80 function runTestToFramerate(targetFramerate
, sourceData
, transformer
, renderer
, callback
) {
81 callback
= ensureCallback(callback
);
83 // objectCount => { js, fps }
86 // (objectCount, { js, fps })
89 var generateFrames
= frameGenerator(transformer
, FRAME_COUNT
);
92 var mostObjectsAboveThirtyFPS
= -1;
93 var minObjectsBelowThirtyFPS
= -1;
94 for (var i
= 0; i
< rawData
.length
; i
++) {
95 var temp
= rawData
[i
];
96 if (temp
[1].fps
> 30) {
97 if (mostObjectsAboveThirtyFPS
=== -1 || temp
[0] > rawData
[mostObjectsAboveThirtyFPS
][0]) {
98 mostObjectsAboveThirtyFPS
= i
;
101 if (minObjectsBelowThirtyFPS
=== -1 || temp
[0] < rawData
[minObjectsBelowThirtyFPS
][0]) {
102 minObjectsBelowThirtyFPS
= i
;
107 if (mostObjectsAboveThirtyFPS
=== -1 || minObjectsBelowThirtyFPS
=== -1) {
108 callback(new Error("Bad test results"));
112 var aboveData
= rawData
[mostObjectsAboveThirtyFPS
];
113 var belowData
= rawData
[minObjectsBelowThirtyFPS
];
115 var m
= (aboveData
[0] - belowData
[0]) / (aboveData
[1].fps
- belowData
[1].fps
);
116 var objectCount
= belowData
[0] + m
* (30 - belowData
[1].fps
);
118 m
= (aboveData
[1].js
- belowData
[1].js
) / (aboveData
[1].fps
- belowData
[1].fps
);
119 var jsTime
= belowData
[1].js
+ m
* (30 - belowData
[1].fps
);
122 objectCount
: objectCount
,
128 function nextNumberToTry(fpsResults
, objectCount
){
130 while( objectCount
> 100 ){
132 objectCount
= Math
.floor(objectCount
/ 10);
135 var testValue
= objectCount
*factor
;
136 if( !Object
.prototype.hasOwnProperty
.call(fpsResults
, testValue
) ){
140 testValue
= (objectCount
+1)*factor
;
141 if( !Object
.prototype.hasOwnProperty
.call(fpsResults
, testValue
) ){
145 testValue
= (objectCount
-1)*factor
;
146 if( testValue
<= 1 ){
149 if( !Object
.prototype.hasOwnProperty
.call(fpsResults
, testValue
) ){
156 function test(objectCount
) {
157 //alert(objectCount);
158 if( objectCount
=== -1 ){
163 var frames
= generateFrames(objectCount
);
165 runTest(sourceData
, frames
, renderer
, function testDone(err
, results
) {
166 if (err
) return callback(err
);
167 fpsResults
[objectCount
] = results
;
168 rawData
.push([ objectCount
, results
]);
170 var timePerObjectEstimate
= 1/(objectCount
*results
.fps
);
171 var estimatedMaxObjects
= Math
.min(5000, Math
.floor(1/(targetFramerate
* timePerObjectEstimate
)));
173 var nextObjectCount
= nextNumberToTry(fpsResults
, estimatedMaxObjects
);
174 test(nextObjectCount
);
181 // source => renderer => transformer => test
184 Object
.keys(sources
).forEach(function (sourceName
) {
185 var source
= sources
[sourceName
];
188 tests
[sourceName
] = subTests
;
190 Object
.keys(renderers
).forEach(function (rendererName
) {
191 var renderer
= renderers
[rendererName
];
193 var subSubTests
= { };
194 subTests
[rendererName
] = subSubTests
;
196 Object
.keys(transformers
).forEach(function (transformerName
) {
197 var transformer
= transformers
[transformerName
];
199 subSubTests
[transformerName
] = function spriteTest(callback
) {
200 source(function (err
, sourceData
) {
201 if (err
) return callback(err
);
202 runTestToFramerate(TARGET_FRAMERATE
, sourceData
, transformer
, renderer
, callback
);