| 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 |