30aa82c78149786619f819e3fcb54a648a7b8e28
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / cc / CCHeadsUpDisplay.cpp
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 "Extensions3DChromium.h"
31 #include "Font.h"
32 #include "FontCache.h"
33 #include "FontDescription.h"
34 #include "GraphicsContext3D.h"
35 #include "LayerChromium.h"
36 #include "LayerRendererChromium.h"
37 #include "ManagedTexture.h"
38 #include "PlatformCanvas.h"
39 #include "TextRun.h"
40 #include "TextStream.h"
41 #include "TextureManager.h"
42 #include <wtf/CurrentTime.h>
43 #include <wtf/text/CString.h>
44 #include <wtf/text/WTFString.h>
45
46 namespace WebCore {
47
48 using namespace std;
49
50 CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner)
51     : m_currentFrameNumber(1)
52     , m_filteredFrameTime(0)
53     , m_layerRenderer(owner)
54     , m_useMapSubForUploads(owner->contextSupportsMapSub())
55 {
56     m_beginTimeHistoryInSec[0] = currentTime();
57     m_beginTimeHistoryInSec[1] = m_beginTimeHistoryInSec[0];
58     for (int i = 2; i < kBeginFrameHistorySize; i++)
59         m_beginTimeHistoryInSec[i] = 0;
60
61     FontDescription mediumFontDesc;
62     mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily);
63     mediumFontDesc.setComputedSize(20);
64
65     m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0));
66     m_mediumFont->update(0);
67
68     FontDescription smallFontDesc;
69     smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily);
70     smallFontDesc.setComputedSize(10);
71
72     m_smallFont = adoptPtr(new Font(smallFontDesc, 0, 0));
73     m_smallFont->update(0);
74 }
75
76 CCHeadsUpDisplay::~CCHeadsUpDisplay()
77 {
78 }
79
80 void CCHeadsUpDisplay::onFrameBegin(double timestamp)
81 {
82     m_beginTimeHistoryInSec[m_currentFrameNumber % kBeginFrameHistorySize] = timestamp;
83 }
84
85 void CCHeadsUpDisplay::onPresent()
86 {
87     m_currentFrameNumber += 1;
88 }
89
90 bool CCHeadsUpDisplay::enabled() const
91 {
92     return settings().showPlatformLayerTree || settings().showFPSCounter;
93 }
94
95 void CCHeadsUpDisplay::draw()
96 {
97     GraphicsContext3D* context = m_layerRenderer->context();
98     if (!m_hudTexture)
99         m_hudTexture = ManagedTexture::create(m_layerRenderer->renderSurfaceTextureManager());
100
101     // Use a fullscreen texture only if we need to...
102     IntSize hudSize;
103     if (settings().showPlatformLayerTree) {
104         hudSize.setWidth(min(2048, m_layerRenderer->viewportWidth()));
105         hudSize.setHeight(min(2048, m_layerRenderer->viewportHeight()));
106     } else {
107         hudSize.setWidth(512);
108         hudSize.setHeight(128);
109     }
110
111     if (!m_hudTexture->reserve(hudSize, GraphicsContext3D::RGBA))
112         return;
113
114     // Render pixels into the texture.
115     PlatformCanvas canvas;
116     canvas.resize(hudSize);
117     {
118         PlatformCanvas::Painter painter(&canvas, PlatformCanvas::Painter::GrayscaleText);
119         drawHudContents(painter.context(), hudSize);
120     }
121
122     // Upload to GL.
123     {
124         PlatformCanvas::AutoLocker locker(&canvas);
125
126         m_hudTexture->bindTexture(context);
127         bool uploadedViaMap = false;
128         if (m_useMapSubForUploads) {
129             Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context->getExtensions());
130             uint8_t* pixelDest = static_cast<uint8_t*>(extensions->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, hudSize.width(), hudSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY));
131
132             if (pixelDest) {
133                 uploadedViaMap = true;
134                 memcpy(pixelDest, locker.pixels(), hudSize.width() * hudSize.height() * 4);
135                 extensions->unmapTexSubImage2DCHROMIUM(pixelDest);
136             }
137         }
138
139         if (!uploadedViaMap) {
140             GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, canvas.size().width(), canvas.size().height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, locker.pixels()));
141         }
142     }
143
144     // Draw the HUD onto the default render surface.
145     const Program* program = m_layerRenderer->headsUpDisplayProgram();
146     ASSERT(program && program->initialized());
147     GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
148     m_hudTexture->bindTexture(context);
149     GLC(context, context->useProgram(program->program()));
150     GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0));
151
152     TransformationMatrix matrix;
153     matrix.translate3d(hudSize.width() * 0.5, hudSize.height() * 0.5, 0);
154     m_layerRenderer->drawTexturedQuad(matrix, hudSize.width(), hudSize.height(),
155                                       1.0f, m_layerRenderer->sharedGeometryQuad(), program->vertexShader().matrixLocation(),
156                                       program->fragmentShader().alphaLocation(),
157                                       -1);
158     m_hudTexture->unreserve();
159 }
160
161 void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize)
162 {
163     FontCachePurgePreventer fontCachePurgePreventer;
164
165     if (settings().showPlatformLayerTree) {
166         ctx->setFillColor(Color(0, 0, 0, 192), ColorSpaceDeviceRGB);
167         ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height()));
168     }
169
170     int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 2;
171     int fpsCounterTop = 2;
172     int platformLayerTreeTop;
173     if (settings().showFPSCounter)
174         platformLayerTreeTop = fpsCounterTop + fpsCounterHeight + 2;
175     else
176         platformLayerTreeTop = 0;
177
178     if (settings().showFPSCounter)
179         drawFPSCounter(ctx, fpsCounterTop, fpsCounterHeight);
180
181     if (settings().showPlatformLayerTree)
182         drawPlatformLayerTree(ctx, platformLayerTreeTop);
183 }
184
185 void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height)
186 {
187     // Note that since we haven't finished the current frame, the FPS counter
188     // actually reports the last frame's time.
189     double secForLastFrame = m_beginTimeHistoryInSec[(m_currentFrameNumber + kBeginFrameHistorySize - 1) % kBeginFrameHistorySize] -
190                              m_beginTimeHistoryInSec[(m_currentFrameNumber + kBeginFrameHistorySize - 2) % kBeginFrameHistorySize];
191
192     // Filter the frame times to avoid spikes.
193     const float alpha = 0.1;
194     if (!m_filteredFrameTime) {
195         if (m_currentFrameNumber == 2)
196             m_filteredFrameTime = secForLastFrame;
197     } else
198         m_filteredFrameTime = ((1.0 - alpha) * m_filteredFrameTime) + (alpha * secForLastFrame);
199
200     // Create & measure FPS text.
201     String text(String::format("FPS: %5.1f", 1.0 / m_filteredFrameTime));
202     TextRun run(text);
203     float textWidth = m_mediumFont->width(run) + 2.0f;
204     float graphWidth = kBeginFrameHistorySize;
205
206     // Draw background.
207     ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB);
208     ctx->fillRect(FloatRect(2, top, textWidth + graphWidth, height));
209
210     // Draw FPS text.
211     if (m_filteredFrameTime) {
212         ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
213         ctx->drawText(*m_mediumFont, run, IntPoint(3, top + height - 6));
214     }
215
216     // Draw FPS graph.
217     const double loFPS = 0.0;
218     const double hiFPS = 120.0;
219     ctx->setStrokeStyle(SolidStroke);
220     ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
221     int graphLeft = static_cast<int>(textWidth + 3);
222     IntPoint prev(-1, 0);
223     int x = 0;
224     double h = static_cast<double>(height - 2);
225     for (int i = m_currentFrameNumber % kBeginFrameHistorySize; i != (m_currentFrameNumber - 1) % kBeginFrameHistorySize; i = (i + 1) % kBeginFrameHistorySize) {
226         int j = (i + 1) % kBeginFrameHistorySize;
227         double fps = 1.0 / (m_beginTimeHistoryInSec[j] - m_beginTimeHistoryInSec[i]);
228         double p = 1 - ((fps - loFPS) / (hiFPS - loFPS));
229         if (p < 0)
230             p = 0;
231         if (p > 1)
232             p = 1;
233         IntPoint cur(graphLeft + x, 1 + top + p*h);
234         if (prev.x() != -1)
235             ctx->drawLine(prev, cur);
236         prev = cur;
237         x += 1;
238     }
239 }
240
241 void CCHeadsUpDisplay::drawPlatformLayerTree(GraphicsContext* ctx, int top)
242 {
243     float smallFontHeight = m_smallFont->fontMetrics().floatHeight();
244     int y = top + smallFontHeight - 4;
245     ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
246     Vector<String> lines;
247     m_layerRenderer->layerTreeAsText().split('\n', lines);
248     for (size_t i = 0; i < lines.size(); ++i) {
249         ctx->drawText(*m_smallFont, TextRun(lines[i]), IntPoint(2, y));
250         y += smallFontHeight;
251     }
252 }
253
254 const CCSettings& CCHeadsUpDisplay::settings() const
255 {
256     return m_layerRenderer->settings();
257 }
258
259 }
260
261 #endif // USE(ACCELERATED_COMPOSITING)