1c68e67e4e247ffddb32762fb860648fd58934cd
[WebKit-https.git] / Source / WebKit2 / Shared / CoordinatedGraphics / threadedcompositor / ThreadedCompositor.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L.
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 "config.h"
27 #include "ThreadedCompositor.h"
28
29 #if USE(COORDINATED_GRAPHICS_THREADED)
30
31 #include "CompositingRunLoop.h"
32 #include <WebCore/TransformationMatrix.h>
33 #include <wtf/RunLoop.h>
34 #include <wtf/StdLibExtras.h>
35
36 #if USE(OPENGL_ES_2)
37 #include <GLES2/gl2.h>
38 #else
39 #include <GL/gl.h>
40 #endif
41
42 using namespace WebCore;
43
44 namespace WebKit {
45
46 Ref<ThreadedCompositor> ThreadedCompositor::create(Client* client)
47 {
48     return adoptRef(*new ThreadedCompositor(client));
49 }
50
51 ThreadedCompositor::ThreadedCompositor(Client* client)
52     : m_client(client)
53     , m_deviceScaleFactor(1)
54     , m_threadIdentifier(0)
55 {
56     createCompositingThread();
57 }
58
59 ThreadedCompositor::~ThreadedCompositor()
60 {
61     terminateCompositingThread();
62 }
63
64 void ThreadedCompositor::setNativeSurfaceHandleForCompositing(uint64_t handle)
65 {
66     RefPtr<ThreadedCompositor> protector(this);
67     m_compositingRunLoop->performTask([protector, handle] {
68         protector->m_nativeSurfaceHandle = handle;
69         protector->m_scene->setActive(true);
70     });
71 }
72
73 void ThreadedCompositor::setDeviceScaleFactor(float scale)
74 {
75     RefPtr<ThreadedCompositor> protector(this);
76     m_compositingRunLoop->performTask([protector, scale] {
77         protector->m_deviceScaleFactor = scale;
78         protector->scheduleDisplayImmediately();
79     });
80 }
81
82 void ThreadedCompositor::didChangeViewportSize(const IntSize& size)
83 {
84     RefPtr<ThreadedCompositor> protector(this);
85     m_compositingRunLoop->performTaskSync([protector, size] {
86         protector->viewportController()->didChangeViewportSize(size);
87     });
88 }
89
90 void ThreadedCompositor::didChangeViewportAttribute(const ViewportAttributes& attr)
91 {
92     RefPtr<ThreadedCompositor> protector(this);
93     m_compositingRunLoop->performTask([protector, attr] {
94         protector->viewportController()->didChangeViewportAttribute(attr);
95     });
96 }
97
98 void ThreadedCompositor::didChangeContentsSize(const IntSize& size)
99 {
100     RefPtr<ThreadedCompositor> protector(this);
101     m_compositingRunLoop->performTask([protector, size] {
102         protector->viewportController()->didChangeContentsSize(size);
103     });
104 }
105
106 void ThreadedCompositor::scrollTo(const IntPoint& position)
107 {
108     RefPtr<ThreadedCompositor> protector(this);
109     m_compositingRunLoop->performTask([protector, position] {
110         protector->viewportController()->scrollTo(position);
111     });
112 }
113
114 void ThreadedCompositor::scrollBy(const IntSize& delta)
115 {
116     RefPtr<ThreadedCompositor> protector(this);
117     m_compositingRunLoop->performTask([protector, delta] {
118         protector->viewportController()->scrollBy(delta);
119     });
120 }
121
122 void ThreadedCompositor::purgeBackingStores()
123 {
124     m_client->purgeBackingStores();
125 }
126
127 void ThreadedCompositor::renderNextFrame()
128 {
129     m_client->renderNextFrame();
130 }
131
132 void ThreadedCompositor::updateViewport()
133 {
134     m_compositingRunLoop->setUpdateTimer(CompositingRunLoop::WaitUntilNextFrame);
135 }
136
137 void ThreadedCompositor::commitScrollOffset(uint32_t layerID, const IntSize& offset)
138 {
139     m_client->commitScrollOffset(layerID, offset);
140 }
141
142 bool ThreadedCompositor::ensureGLContext()
143 {
144     if (!glContext())
145         return false;
146
147     glContext()->makeContextCurrent();
148     // The window size may be out of sync with the page size at this point, and getting
149     // the viewport parameters incorrect, means that the content will be misplaced. Thus
150     // we set the viewport parameters directly from the window size.
151     IntSize contextSize = glContext()->defaultFrameBufferSize();
152     if (m_viewportSize != contextSize) {
153         glViewport(0, 0, contextSize.width(), contextSize.height());
154         m_viewportSize = contextSize;
155     }
156
157     return true;
158 }
159
160 GLContext* ThreadedCompositor::glContext()
161 {
162     ASSERT(&RunLoop::current() == &m_compositingRunLoop->runLoop());
163
164     if (m_context)
165         return m_context.get();
166
167     if (!m_nativeSurfaceHandle)
168         return 0;
169
170     m_context = GLContext::createContextForWindow(reinterpret_cast<GLNativeWindowType>(m_nativeSurfaceHandle), GLContext::sharingContext());
171     return m_context.get();
172 }
173
174 void ThreadedCompositor::scheduleDisplayImmediately()
175 {
176     m_compositingRunLoop->setUpdateTimer(CompositingRunLoop::Immediate);
177 }
178
179 void ThreadedCompositor::didChangeVisibleRect()
180 {
181     ASSERT(&RunLoop::current() == &m_compositingRunLoop->runLoop());
182
183     RefPtr<ThreadedCompositor> protector(this);
184     FloatRect visibleRect = viewportController()->visibleContentsRect();
185     float scale = viewportController()->pageScaleFactor();
186     RunLoop::main().dispatch([protector, visibleRect, scale] {
187         protector->m_client->setVisibleContentsRect(visibleRect, FloatPoint::zero(), scale);
188     });
189
190     scheduleDisplayImmediately();
191 }
192
193 void ThreadedCompositor::renderLayerTree()
194 {
195     ASSERT(&RunLoop::current() == &m_compositingRunLoop->runLoop());
196     if (!m_scene)
197         return;
198
199     if (!ensureGLContext())
200         return;
201
202     FloatRect clipRect(0, 0, m_viewportSize.width(), m_viewportSize.height());
203
204     TransformationMatrix viewportTransform;
205     FloatPoint scrollPostion = viewportController()->visibleContentsRect().location();
206     viewportTransform.scale(viewportController()->pageScaleFactor() * m_deviceScaleFactor);
207     viewportTransform.translate(-scrollPostion.x(), -scrollPostion.y());
208
209     m_scene->paintToCurrentGLContext(viewportTransform, 1, clipRect, Color::white, false, scrollPostion);
210
211     glContext()->swapBuffers();
212 }
213
214 void ThreadedCompositor::updateSceneState(const CoordinatedGraphicsState& state)
215 {
216     ASSERT(isMainThread());
217     RefPtr<CoordinatedGraphicsScene> scene = m_scene;
218     m_scene->appendUpdate([scene, state] {
219         scene->commitSceneState(state);
220     });
221
222     scheduleDisplayImmediately();
223 }
224
225 void ThreadedCompositor::compositingThreadEntry(void* coordinatedCompositor)
226 {
227     static_cast<ThreadedCompositor*>(coordinatedCompositor)->runCompositingThread();
228 }
229
230 void ThreadedCompositor::createCompositingThread()
231 {
232     if (m_threadIdentifier)
233         return;
234
235     LockHolder locker(m_initializeRunLoopConditionMutex);
236     m_threadIdentifier = createThread(compositingThreadEntry, this, "WebCore: ThreadedCompositor");
237
238     m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex);
239 }
240
241 void ThreadedCompositor::runCompositingThread()
242 {
243     {
244         LockHolder locker(m_initializeRunLoopConditionMutex);
245
246         m_compositingRunLoop = std::make_unique<CompositingRunLoop>([&] {
247             renderLayerTree();
248         });
249         m_scene = adoptRef(new CoordinatedGraphicsScene(this));
250         m_viewportController = std::make_unique<SimpleViewportController>(this);
251
252         m_initializeRunLoopCondition.notifyOne();
253     }
254
255     m_compositingRunLoop->runLoop().run();
256
257     m_compositingRunLoop->stopUpdateTimer();
258     m_scene->purgeGLResources();
259
260     {
261         LockHolder locker(m_terminateRunLoopConditionMutex);
262         m_context = nullptr;
263         m_scene = nullptr;
264         m_viewportController = nullptr;
265         m_compositingRunLoop = nullptr;
266         m_terminateRunLoopCondition.notifyOne();
267     }
268
269     detachThread(m_threadIdentifier);
270 }
271
272 void ThreadedCompositor::terminateCompositingThread()
273 {
274     LockHolder locker(m_terminateRunLoopConditionMutex);
275
276     m_scene->detach();
277     m_compositingRunLoop->runLoop().stop();
278
279     m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex);
280 }
281
282 }
283 #endif // USE(COORDINATED_GRAPHICS_THREADED)