1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "FrameUniformityData.h"
7 
8 #include <map>
9 
10 #include "Units.h"
11 #include "gfxPoint.h"
12 #include "mozilla/TimeStamp.h"
13 #include "mozilla/dom/APZTestDataBinding.h"
14 #include "mozilla/dom/ToJSValue.h"
15 #include "nsTArray.h"
16 
17 namespace mozilla {
18 namespace layers {
19 
20 using namespace gfx;
21 
22 Point
GetAverage()23 LayerTransforms::GetAverage()
24 {
25   MOZ_ASSERT(!mTransforms.IsEmpty());
26 
27   Point current = mTransforms[0];
28   Point average;
29   size_t length = mTransforms.Length();
30 
31   for (size_t i = 1; i < length; i++) {
32     Point nextTransform = mTransforms[i];
33     Point movement = nextTransform - current;
34     average += Point(std::fabs(movement.x), std::fabs(movement.y));
35     current = nextTransform;
36   }
37 
38   average = average / (float) length;
39   return average;
40 }
41 
42 Point
GetStdDev()43 LayerTransforms::GetStdDev()
44 {
45   Point average = GetAverage();
46   Point stdDev;
47   Point current = mTransforms[0];
48 
49   for (size_t i = 1; i < mTransforms.Length(); i++) {
50     Point next = mTransforms[i];
51     Point move = next - current;
52     move.x = fabs(move.x);
53     move.y = fabs(move.y);
54 
55     Point diff = move - average;
56     diff.x = diff.x * diff.x;
57     diff.y = diff.y * diff.y;
58     stdDev += diff;
59 
60     current = next;
61   }
62 
63   stdDev = stdDev / mTransforms.Length();
64   stdDev.x = sqrt(stdDev.x);
65   stdDev.y = sqrt(stdDev.y);
66   return stdDev;
67 }
68 
~LayerTransformRecorder()69 LayerTransformRecorder::~LayerTransformRecorder()
70 {
71   Reset();
72 }
73 
74 void
RecordTransform(Layer * aLayer,const Point & aTransform)75 LayerTransformRecorder::RecordTransform(Layer* aLayer, const Point& aTransform)
76 {
77   LayerTransforms* layerTransforms = GetLayerTransforms((uintptr_t) aLayer);
78   layerTransforms->mTransforms.AppendElement(aTransform);
79 }
80 
81 void
EndTest(FrameUniformityData * aOutData)82 LayerTransformRecorder::EndTest(FrameUniformityData* aOutData)
83 {
84   for (auto iter = mFrameTransforms.begin(); iter != mFrameTransforms.end(); ++iter) {
85     uintptr_t layer = iter->first;
86     float uniformity = CalculateFrameUniformity(layer);
87 
88     std::pair<uintptr_t,float> result(layer, uniformity);
89     aOutData->mUniformities.insert(result);
90   }
91 
92   Reset();
93 }
94 
95 LayerTransforms*
GetLayerTransforms(uintptr_t aLayer)96 LayerTransformRecorder::GetLayerTransforms(uintptr_t aLayer)
97 {
98   if (!mFrameTransforms.count(aLayer)) {
99     LayerTransforms* newTransform = new LayerTransforms();
100     std::pair<uintptr_t, LayerTransforms*> newLayer(aLayer, newTransform);
101     mFrameTransforms.insert(newLayer);
102   }
103 
104   return mFrameTransforms.find(aLayer)->second;
105 }
106 
107 void
Reset()108 LayerTransformRecorder::Reset()
109 {
110   for (auto iter = mFrameTransforms.begin(); iter != mFrameTransforms.end(); ++iter) {
111     LayerTransforms* layerTransforms = iter->second;
112     delete layerTransforms;
113   }
114 
115   mFrameTransforms.clear();
116 }
117 
118 float
CalculateFrameUniformity(uintptr_t aLayer)119 LayerTransformRecorder::CalculateFrameUniformity(uintptr_t aLayer)
120 {
121   LayerTransforms* layerTransform = GetLayerTransforms(aLayer);
122   float yUniformity = -1;
123   if (!layerTransform->mTransforms.IsEmpty()) {
124     Point stdDev = layerTransform->GetStdDev();
125     yUniformity = stdDev.y;
126   }
127   return yUniformity;
128 }
129 
130 bool
ToJS(JS::MutableHandleValue aOutValue,JSContext * aContext)131 FrameUniformityData::ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext)
132 {
133   dom::FrameUniformityResults results;
134   dom::Sequence<dom::FrameUniformity>& layers = results.mLayerUniformities.Construct();
135 
136   for (auto iter = mUniformities.begin(); iter != mUniformities.end(); ++iter) {
137     uintptr_t layerAddr = iter->first;
138     float uniformity = iter->second;
139 
140     // FIXME: Make this infallible after bug 968520 is done.
141     MOZ_ALWAYS_TRUE(layers.AppendElement(fallible));
142     dom::FrameUniformity& entry = layers.LastElement();
143 
144     entry.mLayerAddress.Construct() = layerAddr;
145     entry.mFrameUniformity.Construct() = uniformity;
146   }
147 
148   return dom::ToJSValue(aContext, results, aOutValue);
149 }
150 
151 } // namespace layers
152 } // namespace mozilla
153