18d5c5c4e334d0785c93fe9990105419478c6242
[WebKit-https.git] / Source / WebKitLegacy / win / WebCoreSupport / AcceleratedCompositingContext.cpp
1 /*
2  * Copyright (C) 2014 Apple, Inc.
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''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "AcceleratedCompositingContext.h"
27
28 #if USE(TEXTURE_MAPPER_GL)
29
30 #include "WebView.h"
31
32 #include <WebCore/DefWndProcWindowClass.h>
33 #include <WebCore/Document.h>
34 #include <WebCore/Frame.h>
35 #include <WebCore/FrameView.h>
36 #include <WebCore/GraphicsLayerTextureMapper.h>
37 #include <WebCore/HWndDC.h>
38 #include <WebCore/Page.h>
39 #include <WebCore/Settings.h>
40 #include <WebCore/SystemInfo.h>
41 #include <WebCore/TemporaryOpenGLSetting.h>
42 #include <WebCore/TextureMapperGL.h>
43 #include <WebCore/TextureMapperLayer.h>
44
45 #if USE(OPENGL_ES)
46 #define GL_GLEXT_PROTOTYPES 1
47 #include <GLES2/gl2.h>
48 #else
49 #include <GL/gl.h>
50 #endif
51
52 using namespace WebCore;
53
54 AcceleratedCompositingContext::AcceleratedCompositingContext(WebView& webView)
55     : m_webView(webView)
56     , m_layerFlushTimer(*this)
57     , m_context(nullptr)
58     , m_window(0)
59 {
60 }
61
62 static IntSize getWebViewSize(WebView& webView)
63 {
64     RECT r;
65     webView.frameRect(&r);
66     return IntSize(r.right - r.left, r.bottom - r.top);
67 }
68
69 void AcceleratedCompositingContext::initialize()
70 {
71     if (m_rootLayer)
72         return;
73
74     IntSize pageSize = getWebViewSize(m_webView);
75
76     m_window = m_webView.viewWindow();
77
78     if (!m_window)
79         return;
80
81     m_rootLayer = GraphicsLayer::create(nullptr, *this);
82     m_rootLayer->setDrawsContent(false);
83     m_rootLayer->setSize(pageSize);
84
85     applyDeviceScaleFactor();
86
87     // The non-composited contents are a child of the root layer.
88     m_nonCompositedContentLayer = GraphicsLayer::create(nullptr, *this);
89     m_nonCompositedContentLayer->setDrawsContent(true);
90     m_nonCompositedContentLayer->setContentsOpaque(!m_webView.transparent());
91     m_nonCompositedContentLayer->setSize(pageSize);
92     if (core(&m_webView)->settings().acceleratedDrawingEnabled())
93         m_nonCompositedContentLayer->setAcceleratesDrawing(true);
94
95 #ifndef NDEBUG
96     m_rootLayer->setName("Root layer");
97     m_nonCompositedContentLayer->setName("Non-composited content");
98 #endif
99
100     m_rootLayer->addChild(m_nonCompositedContentLayer.get());
101     m_nonCompositedContentLayer->setNeedsDisplay();
102
103     // The creation of the TextureMapper needs an active OpenGL context.
104     if (!m_context)
105         m_context = GLContext::createContextForWindow(m_window);
106
107     if (!m_context)
108         return;
109
110     m_context->makeContextCurrent();
111
112     m_textureMapper = TextureMapperGL::create();
113     downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setTextureMapper(m_textureMapper.get());
114
115     scheduleLayerFlush();
116 }
117
118 AcceleratedCompositingContext::~AcceleratedCompositingContext()
119 {
120     stopAnyPendingLayerFlush();
121 }
122
123 void AcceleratedCompositingContext::stopAnyPendingLayerFlush()
124 {
125     m_layerFlushTimer.stop();
126 }
127
128 bool AcceleratedCompositingContext::enabled()
129 {
130     return m_window && m_rootLayer && m_textureMapper;
131 }
132
133 bool AcceleratedCompositingContext::prepareForRendering()
134 {
135     if (!enabled())
136         return false;
137
138     if (!m_context)
139         return false;
140
141     if (!m_context->makeContextCurrent())
142         return false;
143
144     return true;
145 }
146
147 bool AcceleratedCompositingContext::startedAnimation(WebCore::GraphicsLayer* layer)
148 {
149     if (!layer)
150         return false;
151
152     return downcast<GraphicsLayerTextureMapper>(*layer).layer().descendantsOrSelfHaveRunningAnimations();
153 }
154
155 void AcceleratedCompositingContext::applyDeviceScaleFactor()
156 {
157     if (!m_rootLayer)
158         return;
159
160     const FloatSize& size = m_rootLayer->size();
161
162     TransformationMatrix m;
163     m.scale(deviceScaleFactor());
164     // Center view
165     double tx = (size.width() - size.width() / deviceScaleFactor()) / 2.0;
166     double ty = (size.height() - size.height() / deviceScaleFactor()) / 2.0;
167     m.translate(tx, ty);
168     m_rootLayer->setTransform(m);
169 }
170
171 void AcceleratedCompositingContext::compositeLayersToContext(CompositePurpose purpose)
172 {
173     if (!prepareForRendering())
174         return;
175
176     RECT r;
177     if (!::GetClientRect(m_window, &r))
178         return;
179     IntSize windowSize(r.right, r.bottom);
180     glViewport(0, 0, windowSize.width(), windowSize.height());
181
182     if (purpose == ForResize) {
183         TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE);
184         glClearColor(1, 1, 1, 0);
185         glClear(GL_COLOR_BUFFER_BIT);
186     }
187
188     m_textureMapper->beginPainting();
189     downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().paint();
190     m_fpsCounter.updateFPSAndDisplay(*m_textureMapper);
191     m_textureMapper->endPainting();
192
193     m_context->swapBuffers();
194 }
195
196 void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
197 {
198     prepareForRendering();
199
200     if (!graphicsLayer) {
201         stopAnyPendingLayerFlush();
202         m_rootLayer = nullptr;
203         m_nonCompositedContentLayer = nullptr;
204         m_textureMapper = nullptr;
205         return;
206     }
207
208     // Add the accelerated layer tree hierarchy.
209     initialize();
210     if (!m_window)
211         return;
212
213     m_nonCompositedContentLayer->removeAllChildren();
214     m_nonCompositedContentLayer->addChild(graphicsLayer);
215
216     stopAnyPendingLayerFlush();
217
218     scheduleLayerFlush();
219 }
220
221 void AcceleratedCompositingContext::setNonCompositedContentsNeedDisplay(const IntRect& rect)
222 {
223     if (!m_rootLayer)
224         return;
225     if (rect.isEmpty()) {
226         m_rootLayer->setNeedsDisplay();
227         return;
228     }
229     m_nonCompositedContentLayer->setNeedsDisplayInRect(rect);
230     scheduleLayerFlush();
231 }
232
233 void AcceleratedCompositingContext::resizeRootLayer(const IntSize& newSize)
234 {
235     if (!enabled())
236         return;
237
238     if (m_rootLayer->size() == newSize)
239         return;
240
241     m_rootLayer->setSize(newSize);
242
243     applyDeviceScaleFactor();
244
245     // If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed
246     // for those newly exposed areas.
247     FloatSize oldSize = m_nonCompositedContentLayer->size();
248     m_nonCompositedContentLayer->setSize(newSize);
249
250     if (newSize.width() > oldSize.width()) {
251         float height = std::min(static_cast<float>(newSize.height()), oldSize.height());
252         m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height));
253     }
254
255     if (newSize.height() > oldSize.height())
256         m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height()));
257
258     m_nonCompositedContentLayer->setNeedsDisplayInRect(IntRect(IntPoint(), newSize));
259     compositeLayersToContext(ForResize);
260     scheduleLayerFlush();
261 }
262
263 void AcceleratedCompositingContext::scrollNonCompositedContents(const IntRect& scrollRect, const IntSize& /* scrollOffset */)
264 {
265     m_nonCompositedContentLayer->setNeedsDisplay();
266     scheduleLayerFlush();
267 }
268
269 bool AcceleratedCompositingContext::acceleratedCompositingAvailable()
270 {
271     const int width = 10;
272     const int height = 10;
273
274     // ANGLE requires Win7 or later.
275     if (windowsVersion() < Windows7)
276         return false;
277
278     // Create test window to render texture in.
279     HWND testWindow = ::CreateWindowEx(WS_EX_NOACTIVATE, defWndProcWindowClassName(), L"AcceleratedCompositingTesterWindow", WS_POPUP | WS_VISIBLE | WS_DISABLED, -width, -height, width, height, 0, 0, 0, 0);
280
281     if (!testWindow)
282         return false;
283
284     // Create GL context.
285     std::unique_ptr<WebCore::GLContext> context = GLContext::createContextForWindow(testWindow);
286
287     if (!context) {
288         ::DestroyWindow(testWindow);
289         return false;
290     }
291
292     context->makeContextCurrent();
293
294     std::unique_ptr<WebCore::TextureMapper> textureMapper = TextureMapperGL::create();
295
296     if (!textureMapper) {
297         ::DestroyWindow(testWindow);
298         return false;
299     }
300
301     // Create texture.
302     RefPtr<BitmapTexture> texture = textureMapper->createTexture();
303
304     if (!texture) {
305         ::DestroyWindow(testWindow);
306         return false;
307     }
308
309     texture->reset(IntSize(width, height));
310
311     // Copy bitmap data to texture.
312     const int bitmapSize = width * height;
313     int data[bitmapSize];
314     const COLORREF colorRed = RGB(255, 0, 0);
315     const COLORREF colorGreen = RGB(0, 255, 0);
316     for (int i = 0; i < bitmapSize; i++)
317         data[i] = colorGreen;
318     IntRect targetRect(0, 0, width, height);
319     IntPoint offset(0, 0);
320     int bytesPerLine = width * 4;
321     texture->updateContents(data, targetRect, offset, bytesPerLine);
322
323     // Render texture.
324     textureMapper->beginPainting();
325     FloatRect rect(0, 0, width, height);
326     textureMapper->drawTexture(*texture, rect);
327     textureMapper->endPainting();
328
329     // Set color of pixel (0, 0) to red, to make sure it is different from the bitmap color.
330     HWndDC hdc(testWindow);
331     ::SetPixel(hdc, 0, 0, colorRed);
332
333     context->swapBuffers();
334
335     // Check if pixel (0, 0) has expected color.
336     COLORREF pixelColor = ::GetPixel(hdc, 0, 0);
337
338     ::DestroyWindow(testWindow);
339
340     return pixelColor == colorGreen;
341 }
342
343 void AcceleratedCompositingContext::scheduleLayerFlush()
344 {
345     if (!enabled())
346         return;
347
348     if (m_layerFlushTimer.isActive())
349         return;
350
351     m_layerFlushTimer.startOneShot(50_ms);
352 }
353
354 bool AcceleratedCompositingContext::flushPendingLayerChanges()
355 {
356     FrameView* frameView = core(&m_webView)->mainFrame().view();
357     m_rootLayer->flushCompositingStateForThisLayerOnly();
358     m_nonCompositedContentLayer->flushCompositingStateForThisLayerOnly();
359     if (!frameView->flushCompositingStateIncludingSubframes())
360         return false;
361
362     downcast<GraphicsLayerTextureMapper>(*m_rootLayer).updateBackingStoreIncludingSubLayers();
363     return true;
364 }
365
366 bool AcceleratedCompositingContext::flushPendingLayerChangesSoon()
367 {
368     scheduleLayerFlush();
369     return true;
370 }
371
372 void AcceleratedCompositingContext::flushAndRenderLayers()
373 {
374     if (!enabled())
375         return;
376
377     Frame& frame = core(&m_webView)->mainFrame();
378     if (!frame.contentRenderer() || !frame.view())
379         return;
380
381     frame.view()->updateLayoutAndStyleIfNeededRecursive();
382
383     if (!enabled())
384         return;
385
386     if (m_context && !m_context->makeContextCurrent())
387         return;
388
389     if (!flushPendingLayerChanges())
390         return;
391
392     compositeLayersToContext();
393 }
394
395 void AcceleratedCompositingContext::layerFlushTimerFired()
396 {
397     flushAndRenderLayers();
398
399     // In case an animation is running, we should flush again soon.
400     if (startedAnimation(m_rootLayer.get()))
401         scheduleLayerFlush();
402 }
403
404 void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& rectToPaint, GraphicsLayerPaintBehavior)
405 {
406     context.save();
407     context.clip(rectToPaint);
408     core(&m_webView)->mainFrame().view()->paint(context, enclosingIntRect(rectToPaint));
409     context.restore();
410 }
411
412 float AcceleratedCompositingContext::deviceScaleFactor() const
413 {
414     return m_webView.deviceScaleFactor();
415 }
416
417 #endif // USE(TEXTURE_MAPPER_GL)