1e5892851875525ceb9afc169d85f55079ca31cd
[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
28 #if USE(COORDINATED_GRAPHICS_THREADED)
29 #include "ThreadedCompositor.h"
30
31 #include <WebCore/TransformationMatrix.h>
32 #include <wtf/CurrentTime.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 class CompositingRunLoop {
47     WTF_MAKE_NONCOPYABLE(CompositingRunLoop);
48     WTF_MAKE_FAST_ALLOCATED;
49 public:
50     enum UpdateTiming {
51         Immediate,
52         WaitUntilNextFrame,
53     };
54
55     CompositingRunLoop(std::function<void()> updateFunction)
56         : m_runLoop(RunLoop::current())
57         , m_updateTimer(m_runLoop, this, &CompositingRunLoop::updateTimerFired)
58         , m_updateFunction(WTF::move(updateFunction))
59         , m_lastUpdateTime(0)
60     {
61     }
62
63     void callOnCompositingRunLoop(std::function<void()> function)
64     {
65         if (&m_runLoop == &RunLoop::current()) {
66             function();
67             return;
68         }
69
70         m_runLoop.dispatch(WTF::move(function));
71     }
72
73     void setUpdateTimer(UpdateTiming timing = Immediate)
74     {
75         if (m_updateTimer.isActive())
76             return;
77
78         const static double targetFPS = 60;
79         double nextUpdateTime = 0;
80         if (timing == WaitUntilNextFrame)
81             nextUpdateTime = std::max((1 / targetFPS) - (monotonicallyIncreasingTime() - m_lastUpdateTime), 0.0);
82
83         m_updateTimer.startOneShot(nextUpdateTime);
84     }
85
86     void stopUpdateTimer()
87     {
88         if (m_updateTimer.isActive())
89             m_updateTimer.stop();
90     }
91
92     RunLoop& runLoop()
93     {
94         return m_runLoop;
95     }
96
97 private:
98
99     void updateTimerFired()
100     {
101         m_updateFunction();
102         m_lastUpdateTime = monotonicallyIncreasingTime();
103     }
104
105     RunLoop& m_runLoop;
106     RunLoop::Timer<CompositingRunLoop> m_updateTimer;
107     std::function<void()> m_updateFunction;
108
109     double m_lastUpdateTime;
110 };
111
112 Ref<ThreadedCompositor> ThreadedCompositor::create(Client* client)
113 {
114     return adoptRef(*new ThreadedCompositor(client));
115 }
116
117 ThreadedCompositor::ThreadedCompositor(Client* client)
118     : m_client(client)
119     , m_threadIdentifier(0)
120 {
121     createCompositingThread();
122 }
123
124 ThreadedCompositor::~ThreadedCompositor()
125 {
126     terminateCompositingThread();
127 }
128
129 void ThreadedCompositor::setNeedsDisplay()
130 {
131     RefPtr<ThreadedCompositor> protector(this);
132     callOnCompositingThread([=] {
133         protector->scheduleDisplayImmediately();
134     });
135 }
136
137 void ThreadedCompositor::setNativeSurfaceHandleForCompositing(uint64_t handle)
138 {
139     RefPtr<ThreadedCompositor> protector(this);
140     callOnCompositingThread([=] {
141         protector->m_nativeSurfaceHandle = handle;
142         protector->m_scene->setActive(true);
143     });
144 }
145
146
147 void ThreadedCompositor::didChangeViewportSize(const IntSize& newSize)
148 {
149     RefPtr<ThreadedCompositor> protector(this);
150     callOnCompositingThread([=] {
151         protector->viewportController()->didChangeViewportSize(newSize);
152     });
153 }
154
155 void ThreadedCompositor::didChangeViewportAttribute(const ViewportAttributes& attr)
156 {
157     RefPtr<ThreadedCompositor> protector(this);
158     callOnCompositingThread([=] {
159         protector->viewportController()->didChangeViewportAttribute(attr);
160     });
161 }
162
163 void ThreadedCompositor::didChangeContentsSize(const IntSize& size)
164 {
165     RefPtr<ThreadedCompositor> protector(this);
166     callOnCompositingThread([=] {
167         protector->viewportController()->didChangeContentsSize(size);
168     });
169 }
170
171 void ThreadedCompositor::scrollTo(const IntPoint& position)
172 {
173     RefPtr<ThreadedCompositor> protector(this);
174     callOnCompositingThread([=] {
175         protector->viewportController()->scrollTo(position);
176     });
177 }
178
179 void ThreadedCompositor::scrollBy(const IntSize& delta)
180 {
181     RefPtr<ThreadedCompositor> protector(this);
182     callOnCompositingThread([=] {
183         protector->viewportController()->scrollBy(delta);
184     });
185 }
186
187 void ThreadedCompositor::purgeBackingStores()
188 {
189     m_client->purgeBackingStores();
190 }
191
192 void ThreadedCompositor::renderNextFrame()
193 {
194     m_client->renderNextFrame();
195 }
196
197 void ThreadedCompositor::updateViewport()
198 {
199     m_compositingRunLoop->setUpdateTimer(CompositingRunLoop::WaitUntilNextFrame);
200 }
201
202 void ThreadedCompositor::commitScrollOffset(uint32_t layerID, const IntSize& offset)
203 {
204     m_client->commitScrollOffset(layerID, offset);
205 }
206
207 bool ThreadedCompositor::ensureGLContext()
208 {
209     if (!glContext())
210         return false;
211
212     glContext()->makeContextCurrent();
213     // The window size may be out of sync with the page size at this point, and getting
214     // the viewport parameters incorrect, means that the content will be misplaced. Thus
215     // we set the viewport parameters directly from the window size.
216     IntSize contextSize = glContext()->defaultFrameBufferSize();
217     if (m_viewportSize != contextSize) {
218         glViewport(0, 0, contextSize.width(), contextSize.height());
219         m_viewportSize = contextSize;
220     }
221
222     return true;
223 }
224
225 GLContext* ThreadedCompositor::glContext()
226 {
227     if (m_context)
228         return m_context.get();
229
230     if (!m_nativeSurfaceHandle)
231         return 0;
232
233     m_context = GLContext::createContextForWindow(reinterpret_cast<GLNativeWindowType>(m_nativeSurfaceHandle), GLContext::sharingContext());
234     return m_context.get();
235 }
236
237 void ThreadedCompositor::scheduleDisplayImmediately()
238 {
239     m_compositingRunLoop->setUpdateTimer(CompositingRunLoop::Immediate);
240 }
241
242 void ThreadedCompositor::didChangeVisibleRect()
243 {
244     FloatRect visibleRect = viewportController()->visibleContentsRect();
245     float scale = viewportController()->pageScaleFactor();
246     callOnMainThread([=] {
247         m_client->setVisibleContentsRect(visibleRect, FloatPoint::zero(), scale);
248     });
249
250     scheduleDisplayImmediately();
251 }
252
253 void ThreadedCompositor::renderLayerTree()
254 {
255     if (!m_scene)
256         return;
257
258     if (!ensureGLContext())
259         return;
260
261     FloatRect clipRect(0, 0, m_viewportSize.width(), m_viewportSize.height());
262
263     TransformationMatrix viewportTransform;
264     FloatPoint scrollPostion = viewportController()->visibleContentsRect().location();
265     viewportTransform.scale(viewportController()->pageScaleFactor());
266     viewportTransform.translate(-scrollPostion.x(), -scrollPostion.y());
267
268     m_scene->paintToCurrentGLContext(viewportTransform, 1, clipRect, Color::white, false, scrollPostion);
269
270     glContext()->swapBuffers();
271 }
272
273 void ThreadedCompositor::updateSceneState(const CoordinatedGraphicsState& state)
274 {
275     RefPtr<CoordinatedGraphicsScene> scene = m_scene;
276     m_scene->appendUpdate([scene, state] {
277         scene->commitSceneState(state);
278     });
279
280     setNeedsDisplay();
281 }
282
283 void ThreadedCompositor::callOnCompositingThread(std::function<void()> function)
284 {
285     m_compositingRunLoop->callOnCompositingRunLoop(WTF::move(function));
286 }
287
288 void ThreadedCompositor::compositingThreadEntry(void* coordinatedCompositor)
289 {
290     static_cast<ThreadedCompositor*>(coordinatedCompositor)->runCompositingThread();
291 }
292
293 void ThreadedCompositor::createCompositingThread()
294 {
295     if (m_threadIdentifier)
296         return;
297
298     DeprecatedMutexLocker locker(m_initializeRunLoopConditionMutex);
299     m_threadIdentifier = createThread(compositingThreadEntry, this, "WebCore: ThreadedCompositor");
300
301     m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex);
302 }
303
304 void ThreadedCompositor::runCompositingThread()
305 {
306     {
307         DeprecatedMutexLocker locker(m_initializeRunLoopConditionMutex);
308
309         m_compositingRunLoop = std::make_unique<CompositingRunLoop>([&] {
310             renderLayerTree();
311         });
312         m_scene = adoptRef(new CoordinatedGraphicsScene(this));
313         m_viewportController = std::make_unique<SimpleViewportController>(this);
314
315         m_initializeRunLoopCondition.signal();
316     }
317
318     m_compositingRunLoop->runLoop().run();
319
320     m_compositingRunLoop->stopUpdateTimer();
321     m_scene->purgeGLResources();
322
323     {
324         DeprecatedMutexLocker locker(m_terminateRunLoopConditionMutex);
325         m_compositingRunLoop = nullptr;
326         m_context = nullptr;
327         m_terminateRunLoopCondition.signal();
328     }
329
330     detachThread(m_threadIdentifier);
331 }
332
333 void ThreadedCompositor::terminateCompositingThread()
334 {
335     DeprecatedMutexLocker locker(m_terminateRunLoopConditionMutex);
336
337     m_scene->detach();
338     m_compositingRunLoop->runLoop().stop();
339
340     m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex);
341 }
342
343 }
344 #endif // USE(COORDINATED_GRAPHICS_THREADED)