1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWebEngine module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "compositor_resource_fence.h"
41 #include "ozone/gl_surface_qt.h"
42 #include "ui/gl/gl_context.h"
43 
44 #include <QtGui/private/qtguiglobal_p.h>
45 #include <QtGui/qopenglcontext.h>
46 
47 #ifndef GL_TIMEOUT_IGNORED
48 #define GL_TIMEOUT_IGNORED                0xFFFFFFFFFFFFFFFFull
49 #endif
50 
51 
52 #if QT_CONFIG(egl)
53 #include <EGL/egl.h>
54 #include <EGL/eglext.h>
55 #endif
56 
57 namespace QtWebEngineCore {
58 
wait()59 void CompositorResourceFence::wait()
60 {
61     if (!m_sync)
62         return;
63 
64     QOpenGLContext *context = QOpenGLContext::currentContext();
65     Q_ASSERT(context);
66 
67     // Chromium uses its own GL bindings and stores in in thread local storage.
68     // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium
69     // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread.
70     switch (m_sync.type) {
71     case gl::TransferableFence::NoSync:
72         break;
73     case gl::TransferableFence::EglSync:
74 #ifdef EGL_KHR_reusable_sync
75     {
76         static bool resolved = false;
77         static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0;
78 
79         if (!resolved) {
80             if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync"))
81                 eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR");
82             resolved = true;
83         }
84 
85         if (eglClientWaitSyncKHR)
86             // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync.
87             eglClientWaitSyncKHR(m_sync.egl.display, m_sync.egl.sync, 0, EGL_FOREVER_KHR);
88     }
89 #endif
90         break;
91     case gl::TransferableFence::ArbSync:
92         typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout);
93         static WaitSyncPtr glWaitSync_ = 0;
94         if (!glWaitSync_) {
95             glWaitSync_ = (WaitSyncPtr)context->getProcAddress("glWaitSync");
96             Q_ASSERT(glWaitSync_);
97         }
98         glWaitSync_(m_sync.arb.sync, 0, GL_TIMEOUT_IGNORED);
99         break;
100     }
101 
102     release();
103 }
104 
release()105 void CompositorResourceFence::release()
106 {
107     if (!m_sync)
108         return;
109 
110     QOpenGLContext *context = QOpenGLContext::currentContext();
111     if (!context)
112         return;
113 
114     // Chromium uses its own GL bindings and stores in in thread local storage.
115     // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium
116     // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread.
117     switch (m_sync.type) {
118     case gl::TransferableFence::NoSync:
119         break;
120     case gl::TransferableFence::EglSync:
121 #ifdef EGL_KHR_reusable_sync
122     {
123         static bool resolved = false;
124         static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0;
125 
126         if (!resolved) {
127             if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync"))
128                 eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR");
129             resolved = true;
130         }
131 
132         if (eglDestroySyncKHR) {
133             // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync.
134             eglDestroySyncKHR(m_sync.egl.display, m_sync.egl.sync);
135             m_sync.reset();
136         }
137     }
138 #endif
139         break;
140     case gl::TransferableFence::ArbSync:
141         typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync);
142         static DeleteSyncPtr glDeleteSync_ = 0;
143         if (!glDeleteSync_) {
144             glDeleteSync_ = (DeleteSyncPtr)context->getProcAddress("glDeleteSync");
145             Q_ASSERT(glDeleteSync_);
146         }
147         glDeleteSync_(m_sync.arb.sync);
148         m_sync.reset();
149         break;
150     }
151     // If Chromium was able to create a sync, we should have been able to handle its type here too.
152     Q_ASSERT(!m_sync);
153 }
154 
155 // static
create(std::unique_ptr<gl::GLFence> glFence)156 scoped_refptr<CompositorResourceFence> CompositorResourceFence::create(std::unique_ptr<gl::GLFence> glFence)
157 {
158     if (!glFence && gl::GLContext::GetCurrent() && gl::GLFence::IsSupported())
159         glFence = gl::GLFence::Create();
160     if (glFence)
161         return base::MakeRefCounted<CompositorResourceFence>(glFence->Transfer());
162     return nullptr;
163 }
164 
165 } // namespace QtWebEngineCore
166