1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 27 #if USE(ACCELERATED_COMPOSITING) 28 #include "CCHeadsUpDisplay.h" 29 30 #include "CurrentTime.h" 31 #include "Font.h" 32 #include "FontDescription.h" 33 #include "GraphicsContext3D.h" 34 #include "LayerChromium.h" 35 #include "LayerRendererChromium.h" 36 #include "LayerTexture.h" 37 #include "TextRun.h" 38 #include "TextStream.h" 39 #include "TextureManager.h" 40 #include <wtf/text/CString.h> 41 #include <wtf/text/WTFString.h> 42 43 namespace WebCore { 44 45 using namespace std; 46 47 CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner) 48 : m_currentFrameNumber(1) 49 , m_filteredFrameTime(0) 50 , m_layerRenderer(owner) 51 , m_showFPSCounter(false) 52 , m_showPlatformLayerTree(false) 53 { 54 m_presentTimeHistoryInSec[0] = currentTime(); 55 m_presentTimeHistoryInSec[1] = m_presentTimeHistoryInSec[0]; 56 for (int i = 2; i < kPresentHistorySize; i++) 57 m_presentTimeHistoryInSec[i] = 0; 58 59 FontDescription mediumFontDesc; 60 mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily); 61 mediumFontDesc.setComputedSize(20); 62 63 m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0)); 64 m_mediumFont->update(0); 65 66 FontDescription smallFontDesc; 67 smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily); 68 smallFontDesc.setComputedSize(10); 69 70 m_smallFont = adoptPtr(new Font(smallFontDesc, 0, 0)); 71 m_smallFont->update(0); 72 } 73 74 CCHeadsUpDisplay::~CCHeadsUpDisplay() 75 { 76 } 77 78 void CCHeadsUpDisplay::draw() 79 { 80 GraphicsContext3D* context = m_layerRenderer->context(); 81 if (!m_hudTexture) 82 m_hudTexture = LayerTexture::create(context, m_layerRenderer->textureManager()); 83 84 // Use a fullscreen texture only if we need to... 85 IntSize hudSize; 86 if (m_showPlatformLayerTree) { 87 hudSize.setWidth(min(2048, m_layerRenderer->viewportSize().width())); 88 hudSize.setHeight(min(2048, m_layerRenderer->viewportSize().height())); 89 } else { 90 hudSize.setWidth(512); 91 hudSize.setHeight(128); 92 } 93 94 m_hudTexture->reserve(hudSize, GraphicsContext3D::RGBA); 95 96 // Render pixels into the texture. 97 PlatformCanvas canvas; 98 canvas.resize(hudSize); 99 { 100 PlatformCanvas::Painter painter(&canvas, PlatformCanvas::Painter::GrayscaleText); 101 drawHudContents(painter.context(), hudSize); 102 } 103 104 // Upload to GL. 105 { 106 PlatformCanvas::AutoLocker locker(&canvas); 107 108 m_hudTexture->bindTexture(); 109 GLC(context.get(), context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, canvas.size().width(), canvas.size().height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, locker.pixels())); 110 } 111 112 // Draw the HUD onto the default render surface. 113 const Program* program = m_layerRenderer->headsUpDisplayProgram(); 114 ASSERT(program && program->initialized()); 115 GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); 116 m_hudTexture->bindTexture(); 117 m_layerRenderer->useShader(program->program()); 118 GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); 119 120 TransformationMatrix matrix; 121 matrix.translate3d(hudSize.width() * 0.5, hudSize.height() * 0.5, 0); 122 LayerChromium::drawTexturedQuad(context, m_layerRenderer->projectionMatrix(), 123 matrix, hudSize.width(), hudSize.height(), 124 1.0f, program->vertexShader().matrixLocation(), 125 program->fragmentShader().alphaLocation()); 126 } 127 128 void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize) 129 { 130 if (m_showPlatformLayerTree) { 131 ctx->setFillColor(Color(0, 0, 0, 192), ColorSpaceDeviceRGB); 132 ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height())); 133 } 134 135 int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 2; 136 int fpsCounterTop = 2; 137 int platformLayerTreeTop; 138 if (m_showFPSCounter) 139 platformLayerTreeTop = fpsCounterTop + fpsCounterHeight + 2; 140 else 141 platformLayerTreeTop = 0; 142 143 if (m_showFPSCounter) 144 drawFPSCounter(ctx, fpsCounterTop, fpsCounterHeight); 145 146 if (m_showPlatformLayerTree) 147 drawPlatformLayerTree(ctx, platformLayerTreeTop); 148 } 149 150 void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height) 151 { 152 // Note that since we haven't finished the current frame, the FPS counter 153 // actually reports the last frame's time. 154 double secForLastFrame = m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 1) % kPresentHistorySize] - 155 m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 2) % kPresentHistorySize]; 156 157 // Filter the frame times to avoid spikes. 158 const float alpha = 0.1; 159 if (!m_filteredFrameTime) { 160 if (m_currentFrameNumber == 2) 161 m_filteredFrameTime = secForLastFrame; 162 } else 163 m_filteredFrameTime = ((1.0 - alpha) * m_filteredFrameTime) + (alpha * secForLastFrame); 164 165 // Create & measure FPS text. 166 String text(String::format("FPS: %5.1f", 1.0 / m_filteredFrameTime)); 167 TextRun run(text); 168 float textWidth = m_mediumFont->width(run) + 2.0f; 169 float graphWidth = kPresentHistorySize; 170 171 // Draw background. 172 ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB); 173 ctx->fillRect(FloatRect(2, top, textWidth + graphWidth, height)); 174 175 // Draw FPS text. 176 if (m_filteredFrameTime) { 177 ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); 178 ctx->drawText(*m_mediumFont, run, IntPoint(3, top + height - 6)); 179 } 180 181 // Draw FPS graph. 182 const double loFPS = 0.0; 183 const double hiFPS = 120.0; 184 ctx->setStrokeStyle(SolidStroke); 185 ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB); 186 int graphLeft = static_cast<int>(textWidth + 3); 187 IntPoint prev(-1, 0); 188 int x = 0; 189 double h = static_cast<double>(height - 2); 190 for (int i = m_currentFrameNumber % kPresentHistorySize; i != (m_currentFrameNumber - 1) % kPresentHistorySize; i = (i + 1) % kPresentHistorySize) { 191 int j = (i + 1) % kPresentHistorySize; 192 double fps = 1.0 / (m_presentTimeHistoryInSec[j] - m_presentTimeHistoryInSec[i]); 193 double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); 194 if (p < 0) 195 p = 0; 196 if (p > 1) 197 p = 1; 198 IntPoint cur(graphLeft + x, 1 + top + p*h); 199 if (prev.x() != -1) 200 ctx->drawLine(prev, cur); 201 prev = cur; 202 x += 1; 203 } 204 } 205 206 void CCHeadsUpDisplay::drawPlatformLayerTree(GraphicsContext* ctx, int top) 207 { 208 float smallFontHeight = m_smallFont->fontMetrics().floatHeight(); 209 int y = top + smallFontHeight - 4; 210 ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); 211 Vector<String> lines; 212 m_layerRenderer->layerTreeAsText().split('\n', lines); 213 for (size_t i = 0; i < lines.size(); ++i) { 214 ctx->drawText(*m_smallFont, TextRun(lines[i]), IntPoint(2, y)); 215 y += smallFontHeight; 216 } 217 } 218 219 void CCHeadsUpDisplay::onPresent() 220 { 221 m_presentTimeHistoryInSec[m_currentFrameNumber % kPresentHistorySize] = currentTime(); 222 m_currentFrameNumber += 1; 223 } 224 225 } 226 227 #endif // USE(ACCELERATED_COMPOSITING) 228