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
CCHeadsUpDisplay(LayerRendererChromium * owner)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
~CCHeadsUpDisplay()74 CCHeadsUpDisplay::~CCHeadsUpDisplay()
75 {
76 }
77
draw()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
drawHudContents(GraphicsContext * ctx,const IntSize & hudSize)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
drawFPSCounter(GraphicsContext * ctx,int top,int height)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
drawPlatformLayerTree(GraphicsContext * ctx,int top)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
onPresent()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