Home | History | Annotate | Download | only in cc
      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