OLD | NEW |
| (Empty) |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCHeadsUpDisplayLayerImpl.h" | |
8 | |
9 #include "base/stringprintf.h" | |
10 #include "ui/gfx/point.h" | |
11 #include "CCDebugRectHistory.h" | |
12 #include "CCFontAtlas.h" | |
13 #include "CCFrameRateCounter.h" | |
14 #include "CCLayerTreeHostImpl.h" | |
15 #include "CCQuadSink.h" | |
16 #include "CCTextureDrawQuad.h" | |
17 #include "Extensions3DChromium.h" | |
18 #include "GraphicsContext3D.h" | |
19 #include "SkBitmap.h" | |
20 #include "SkColorMatrixFilter.h" | |
21 #include "SkPaint.h" | |
22 #include "skia/ext/platform_canvas.h" | |
23 | |
24 namespace cc { | |
25 | |
26 static inline SkPaint createPaint() | |
27 { | |
28 // The SkCanvas is in RGBA but the shader is expecting BGRA, so we need to | |
29 // swizzle our colors when drawing to the SkCanvas. | |
30 SkColorMatrix swizzleMatrix; | |
31 for (int i = 0; i < 20; ++i) | |
32 swizzleMatrix.fMat[i] = 0; | |
33 swizzleMatrix.fMat[0 + 5 * 2] = 1; | |
34 swizzleMatrix.fMat[1 + 5 * 1] = 1; | |
35 swizzleMatrix.fMat[2 + 5 * 0] = 1; | |
36 swizzleMatrix.fMat[3 + 5 * 3] = 1; | |
37 | |
38 SkPaint paint; | |
39 paint.setColorFilter(new SkColorMatrixFilter(swizzleMatrix))->unref(); | |
40 return paint; | |
41 } | |
42 | |
43 CCHeadsUpDisplayLayerImpl::CCHeadsUpDisplayLayerImpl(int id) | |
44 : CCLayerImpl(id) | |
45 { | |
46 } | |
47 | |
48 CCHeadsUpDisplayLayerImpl::~CCHeadsUpDisplayLayerImpl() | |
49 { | |
50 } | |
51 | |
52 void CCHeadsUpDisplayLayerImpl::setFontAtlas(scoped_ptr<CCFontAtlas> fontAtlas) | |
53 { | |
54 m_fontAtlas = fontAtlas.Pass(); | |
55 } | |
56 | |
57 void CCHeadsUpDisplayLayerImpl::willDraw(CCResourceProvider* resourceProvider) | |
58 { | |
59 CCLayerImpl::willDraw(resourceProvider); | |
60 | |
61 if (!m_hudTexture) | |
62 m_hudTexture = CCScopedTexture::create(resourceProvider); | |
63 | |
64 // FIXME: Scale the HUD by deviceScale to make it more friendly under high D
PI. | |
65 | |
66 if (m_hudTexture->size() != bounds()) | |
67 m_hudTexture->free(); | |
68 | |
69 if (!m_hudTexture->id()) | |
70 m_hudTexture->allocate(CCRenderer::ImplPool, bounds(), GraphicsContext3D
::RGBA, CCResourceProvider::TextureUsageAny); | |
71 } | |
72 | |
73 void CCHeadsUpDisplayLayerImpl::appendQuads(CCQuadSink& quadSink, CCAppendQuadsD
ata& appendQuadsData) | |
74 { | |
75 if (!m_hudTexture->id()) | |
76 return; | |
77 | |
78 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createShare
dQuadState()); | |
79 | |
80 IntRect quadRect(IntPoint(), bounds()); | |
81 bool premultipliedAlpha = true; | |
82 FloatRect uvRect(0, 0, 1, 1); | |
83 bool flipped = false; | |
84 quadSink.append(CCTextureDrawQuad::create(sharedQuadState, quadRect, m_hudTe
xture->id(), premultipliedAlpha, uvRect, flipped).PassAs<CCDrawQuad>(), appendQu
adsData); | |
85 } | |
86 | |
87 void CCHeadsUpDisplayLayerImpl::updateHudTexture(CCResourceProvider* resourcePro
vider) | |
88 { | |
89 if (!m_hudTexture->id()) | |
90 return; | |
91 | |
92 SkISize canvasSize; | |
93 if (m_hudCanvas) | |
94 canvasSize = m_hudCanvas->getDeviceSize(); | |
95 else | |
96 canvasSize.set(0, 0); | |
97 | |
98 if (canvasSize.fWidth != bounds().width() || canvasSize.fHeight != bounds().
height() || !m_hudCanvas) | |
99 m_hudCanvas = adoptPtr(skia::CreateBitmapCanvas(bounds().width(), bounds
().height(), false /* opaque */)); | |
100 | |
101 m_hudCanvas->clear(SkColorSetARGB(0, 0, 0, 0)); | |
102 drawHudContents(m_hudCanvas.get()); | |
103 | |
104 const SkBitmap* bitmap = &m_hudCanvas->getDevice()->accessBitmap(false); | |
105 SkAutoLockPixels locker(*bitmap); | |
106 | |
107 IntRect layerRect(IntPoint(), bounds()); | |
108 ASSERT(bitmap->config() == SkBitmap::kARGB_8888_Config); | |
109 resourceProvider->upload(m_hudTexture->id(), static_cast<const uint8_t*>(bit
map->getPixels()), layerRect, layerRect, IntSize()); | |
110 } | |
111 | |
112 void CCHeadsUpDisplayLayerImpl::didDraw(CCResourceProvider* resourceProvider) | |
113 { | |
114 CCLayerImpl::didDraw(resourceProvider); | |
115 | |
116 if (!m_hudTexture->id()) | |
117 return; | |
118 | |
119 // FIXME: the following assert will not be true when sending resources to a | |
120 // parent compositor. We will probably need to hold on to m_hudTexture for | |
121 // longer, and have several HUD textures in the pipeline. | |
122 ASSERT(!resourceProvider->inUseByConsumer(m_hudTexture->id())); | |
123 } | |
124 | |
125 void CCHeadsUpDisplayLayerImpl::didLoseContext() | |
126 { | |
127 m_hudTexture.clear(); | |
128 } | |
129 | |
130 bool CCHeadsUpDisplayLayerImpl::layerIsAlwaysDamaged() const | |
131 { | |
132 return true; | |
133 } | |
134 | |
135 void CCHeadsUpDisplayLayerImpl::drawHudContents(SkCanvas* canvas) | |
136 { | |
137 const CCLayerTreeSettings& settings = layerTreeHostImpl()->settings(); | |
138 | |
139 if (settings.showPlatformLayerTree) { | |
140 SkPaint paint = createPaint(); | |
141 paint.setColor(SkColorSetARGB(192, 0, 0, 0)); | |
142 canvas->drawRect(SkRect::MakeXYWH(0, 0, bounds().width(), bounds().heigh
t()), paint); | |
143 } | |
144 | |
145 int fpsCounterHeight = 40; | |
146 int fpsCounterTop = 2; | |
147 int platformLayerTreeTop; | |
148 | |
149 if (settings.showFPSCounter) | |
150 platformLayerTreeTop = fpsCounterTop + fpsCounterHeight; | |
151 else | |
152 platformLayerTreeTop = 0; | |
153 | |
154 if (settings.showFPSCounter) | |
155 drawFPSCounter(canvas, layerTreeHostImpl()->fpsCounter(), fpsCounterTop,
fpsCounterHeight); | |
156 | |
157 if (settings.showPlatformLayerTree && m_fontAtlas.get()) { | |
158 std::string layerTree = layerTreeHostImpl()->layerTreeAsText(); | |
159 m_fontAtlas->drawText(canvas, createPaint(), layerTree, gfx::Point(2, pl
atformLayerTreeTop), bounds()); | |
160 } | |
161 | |
162 if (settings.showDebugRects()) | |
163 drawDebugRects(canvas, layerTreeHostImpl()->debugRectHistory()); | |
164 } | |
165 | |
166 void CCHeadsUpDisplayLayerImpl::drawFPSCounter(SkCanvas* canvas, CCFrameRateCoun
ter* fpsCounter, int top, int height) | |
167 { | |
168 float textWidth = 170; // so text fits on linux. | |
169 float graphWidth = fpsCounter->timeStampHistorySize(); | |
170 | |
171 // Draw the FPS text. | |
172 drawFPSCounterText(canvas, fpsCounter, top, textWidth, height); | |
173 | |
174 // Draw FPS graph. | |
175 const double loFPS = 0; | |
176 const double hiFPS = 80; | |
177 SkPaint paint = createPaint(); | |
178 paint.setColor(SkColorSetRGB(154, 205, 50)); | |
179 canvas->drawRect(SkRect::MakeXYWH(2 + textWidth, top, graphWidth, height / 2
), paint); | |
180 | |
181 paint.setColor(SkColorSetRGB(255, 250, 205)); | |
182 canvas->drawRect(SkRect::MakeXYWH(2 + textWidth, top + height / 2, graphWidt
h, height / 2), paint); | |
183 | |
184 int graphLeft = static_cast<int>(textWidth + 3); | |
185 int x = 0; | |
186 double h = static_cast<double>(height - 2); | |
187 SkPath path; | |
188 for (int i = 0; i < fpsCounter->timeStampHistorySize() - 1; ++i) { | |
189 int j = i + 1; | |
190 double delta = fpsCounter->timeStampOfRecentFrame(j) - fpsCounter->timeS
tampOfRecentFrame(i); | |
191 | |
192 // Skip plotting this particular instantaneous frame rate if it is not l
ikely to have been valid. | |
193 if (fpsCounter->isBadFrameInterval(delta)) { | |
194 x += 1; | |
195 continue; | |
196 } | |
197 | |
198 double fps = 1.0 / delta; | |
199 | |
200 // Clamp the FPS to the range we want to plot visually. | |
201 double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); | |
202 if (p < 0) | |
203 p = 0; | |
204 if (p > 1) | |
205 p = 1; | |
206 | |
207 // Plot this data point. | |
208 SkPoint cur = SkPoint::Make(graphLeft + x, 1 + top + p*h); | |
209 if (path.isEmpty()) | |
210 path.moveTo(cur); | |
211 else | |
212 path.lineTo(cur); | |
213 x += 1; | |
214 } | |
215 paint.setColor(SK_ColorRED); | |
216 paint.setStyle(SkPaint::kStroke_Style); | |
217 paint.setStrokeWidth(1); | |
218 paint.setAntiAlias(true); | |
219 canvas->drawPath(path, paint); | |
220 } | |
221 | |
222 void CCHeadsUpDisplayLayerImpl::drawFPSCounterText(SkCanvas* canvas, CCFrameRate
Counter* fpsCounter, int top, int width, int height) | |
223 { | |
224 double averageFPS, stdDeviation; | |
225 fpsCounter->getAverageFPSAndStandardDeviation(averageFPS, stdDeviation); | |
226 | |
227 // Draw background. | |
228 SkPaint paint = createPaint(); | |
229 paint.setColor(SK_ColorBLACK); | |
230 canvas->drawRect(SkRect::MakeXYWH(2, top, width, height), paint); | |
231 | |
232 // Draw FPS text. | |
233 if (m_fontAtlas.get()) | |
234 m_fontAtlas->drawText(canvas, createPaint(), base::StringPrintf("FPS: %4
.1f +/- %3.1f", averageFPS, stdDeviation), gfx::Point(10, height / 3), IntSize(w
idth, height)); | |
235 } | |
236 | |
237 void CCHeadsUpDisplayLayerImpl::drawDebugRects(SkCanvas* canvas, CCDebugRectHist
ory* debugRectHistory) | |
238 { | |
239 const Vector<CCDebugRect>& debugRects = debugRectHistory->debugRects(); | |
240 | |
241 for (size_t i = 0; i < debugRects.size(); ++i) { | |
242 SkColor strokeColor = 0; | |
243 SkColor fillColor = 0; | |
244 | |
245 switch (debugRects[i].type) { | |
246 case PaintRectType: | |
247 // Paint rects in red | |
248 strokeColor = SkColorSetARGB(255, 255, 0, 0); | |
249 fillColor = SkColorSetARGB(30, 255, 0, 0); | |
250 break; | |
251 case PropertyChangedRectType: | |
252 // Property-changed rects in blue | |
253 strokeColor = SkColorSetARGB(255, 255, 0, 0); | |
254 fillColor = SkColorSetARGB(30, 0, 0, 255); | |
255 break; | |
256 case SurfaceDamageRectType: | |
257 // Surface damage rects in yellow-orange | |
258 strokeColor = SkColorSetARGB(255, 200, 100, 0); | |
259 fillColor = SkColorSetARGB(30, 200, 100, 0); | |
260 break; | |
261 case ReplicaScreenSpaceRectType: | |
262 // Screen space rects in green. | |
263 strokeColor = SkColorSetARGB(255, 100, 200, 0); | |
264 fillColor = SkColorSetARGB(30, 100, 200, 0); | |
265 break; | |
266 case ScreenSpaceRectType: | |
267 // Screen space rects in purple. | |
268 strokeColor = SkColorSetARGB(255, 100, 0, 200); | |
269 fillColor = SkColorSetARGB(10, 100, 0, 200); | |
270 break; | |
271 case OccludingRectType: | |
272 // Occluding rects in a reddish color. | |
273 strokeColor = SkColorSetARGB(255, 200, 0, 100); | |
274 fillColor = SkColorSetARGB(10, 200, 0, 100); | |
275 break; | |
276 } | |
277 | |
278 const FloatRect& rect = debugRects[i].rect; | |
279 SkRect skRect = SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.
height()); | |
280 SkPaint paint = createPaint(); | |
281 paint.setColor(fillColor); | |
282 canvas->drawRect(skRect, paint); | |
283 | |
284 paint.setColor(strokeColor); | |
285 paint.setStyle(SkPaint::kStroke_Style); | |
286 paint.setStrokeWidth(2); | |
287 canvas->drawRect(skRect, paint); | |
288 } | |
289 } | |
290 | |
291 const char* CCHeadsUpDisplayLayerImpl::layerTypeAsString() const | |
292 { | |
293 return "HeadsUpDisplayLayer"; | |
294 } | |
295 | |
296 } | |
OLD | NEW |