4#include <QtOpenGL/QOpenGLFramebufferObject>
5#include <QtGui/QOpenGLContext>
6#include <QtGui/QWindow>
8#include <qpa/qplatformbackingstore.h>
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
43QOpenGLCompositor::QOpenGLCompositor()
48 Q_ASSERT(!compositor);
49 m_updateTimer.setSingleShot(
true);
50 m_updateTimer.setInterval(0);
51 connect(&m_updateTimer, SIGNAL(timeout()), SLOT(handleRenderAllRequest()));
54QOpenGLCompositor::~QOpenGLCompositor()
56 Q_ASSERT(compositor ==
this);
61void QOpenGLCompositor::setTargetWindow(QWindow *targetWindow,
const QRect &nativeTargetGeometry)
63 m_targetWindow = targetWindow;
64 m_nativeTargetGeometry = nativeTargetGeometry;
67void QOpenGLCompositor::setTargetContext(QOpenGLContext *context)
72void QOpenGLCompositor::setRotation(
int degrees)
75 m_rotationMatrix.setToIdentity();
76 m_rotationMatrix.rotate(degrees, 0, 0, 1);
79void QOpenGLCompositor::update()
81 if (!m_updateTimer.isActive())
82 m_updateTimer.start();
85QImage QOpenGLCompositor::grab()
87 Q_ASSERT(m_context && m_targetWindow);
88 QOpenGLFramebufferObject fbo(m_nativeTargetGeometry.size());
89 grabToFrameBufferObject(&fbo);
93bool QOpenGLCompositor::grabToFrameBufferObject(QOpenGLFramebufferObject *fbo, GrabOrientation orientation)
96 if (fbo->size() != m_nativeTargetGeometry.size()
97 || fbo->format().textureTarget() != GL_TEXTURE_2D)
100 m_context->makeCurrent(m_targetWindow);
102 orientation == Flipped ? QOpenGLTextureBlitter::OriginTopLeft
103 : QOpenGLTextureBlitter::OriginBottomLeft);
107void QOpenGLCompositor::handleRenderAllRequest()
109 Q_ASSERT(m_context && m_targetWindow);
110 m_context->makeCurrent(m_targetWindow);
114void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo, QOpenGLTextureBlitter::Origin origin)
119 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
120 glViewport(0, 0, m_nativeTargetGeometry.width(), m_nativeTargetGeometry.height());
122 if (!m_blitter.isCreated())
127 for (
int i = 0; i < m_windows.size(); ++i)
128 m_windows.at(i)->beginCompositing();
130 for (
int i = 0; i < m_windows.size(); ++i)
131 render(m_windows.at(i), origin);
135 m_context->swapBuffers(m_targetWindow);
139 for (
int i = 0; i < m_windows.size(); ++i)
140 m_windows.at(i)->endCompositing();
152 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
168 return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
169 topLeftRect.width(), topLeftRect.height());
172static void clippedBlit(
const QPlatformTextureList *textures,
int idx,
173 const QRect &sourceWindowRect,
const QRect &targetWindowRect,
174 QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix,
175 QOpenGLTextureBlitter::Origin sourceOrigin)
177 const QRect clipRect = textures->clipRect(idx);
178 if (clipRect.isEmpty())
181 const QRect rectInWindow = textures->geometry(idx).translated(sourceWindowRect.topLeft());
182 const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
183 const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
185 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(clippedRectInWindow, targetWindowRect);
187 target = *rotationMatrix * target;
189 const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(),
192 const uint textureId = textures->texture(idx)->nativeTexture().object;
193 blitter->blit(textureId, target, source);
196void QOpenGLCompositor::render(QOpenGLCompositorWindow *window, QOpenGLTextureBlitter::Origin origin)
198 const QPlatformTextureList *textures = window->textures();
202 const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size());
203 float currentOpacity = 1.0f;
204 BlendStateBinder blend;
205 const QRect sourceWindowRect = window->sourceWindow()->geometry();
206 auto clippedBlitSourceOrigin = origin == QOpenGLTextureBlitter::OriginTopLeft
207 ? QOpenGLTextureBlitter::OriginBottomLeft
208 : QOpenGLTextureBlitter::OriginTopLeft;
209 for (
int i = 0; i < textures->count(); ++i) {
210 const uint textureId = textures->texture(i)->nativeTexture().object;
211 const float opacity = window->sourceWindow()->opacity();
212 if (opacity != currentOpacity) {
213 currentOpacity = opacity;
214 m_blitter.setOpacity(currentOpacity);
217 if (textures->count() > 1 && i == textures->count() - 1) {
220 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
222 target = m_rotationMatrix * target;
223 m_blitter.blit(textureId, target, origin);
224 }
else if (textures->count() == 1) {
226 const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
227 blend.set(translucent);
228 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
230 target = m_rotationMatrix * target;
231 m_blitter.blit(textureId, target, origin);
232 }
else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
235 clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
236 m_rotation ? &m_rotationMatrix :
nullptr, clippedBlitSourceOrigin);
240 for (
int i = 0; i < textures->count(); ++i) {
241 if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
243 clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
244 m_rotation ? &m_rotationMatrix :
nullptr, clippedBlitSourceOrigin);
248 m_blitter.setOpacity(1.0f);
251QOpenGLCompositor *QOpenGLCompositor::instance()
254 compositor =
new QOpenGLCompositor;
258void QOpenGLCompositor::destroy()
264void QOpenGLCompositor::addWindow(QOpenGLCompositorWindow *window)
266 if (!m_windows.contains(window)) {
267 m_windows.append(window);
268 ensureCorrectZOrder();
269 if (window == m_windows.constLast())
270 emit topWindowChanged(window);
274void QOpenGLCompositor::removeWindow(QOpenGLCompositorWindow *window)
276 bool couldChangeTopWindow = (m_windows.size() > 1) ? (window == m_windows.constLast()) :
false;
277 if (m_windows.removeOne(window) && couldChangeTopWindow)
278 emit topWindowChanged(m_windows.constLast());
281void QOpenGLCompositor::moveToTop(QOpenGLCompositorWindow *window)
283 if (!m_windows.isEmpty() && window == m_windows.constLast()) {
288 m_windows.removeOne(window);
289 m_windows.append(window);
290 ensureCorrectZOrder();
292 if (window == m_windows.constLast())
293 emit topWindowChanged(window);
296void QOpenGLCompositor::changeWindowIndex(QOpenGLCompositorWindow *window,
int newIdx)
298 int idx = m_windows.indexOf(window);
299 if (idx != -1 && idx != newIdx) {
300 m_windows.move(idx, newIdx);
301 ensureCorrectZOrder();
302 if (window == m_windows.constLast())
303 emit topWindowChanged(m_windows.last());
307void QOpenGLCompositor::ensureCorrectZOrder()
309 const auto originalOrder = m_windows;
311 std::sort(m_windows.begin(), m_windows.end(),
312 [
this, &originalOrder](QOpenGLCompositorWindow *cw1, QOpenGLCompositorWindow *cw2) {
313 QWindow *w1 = cw1->sourceWindow();
314 QWindow *w2 = cw2->sourceWindow();
318 if (w1 == m_targetWindow || w2 == m_targetWindow)
319 return w1 == m_targetWindow;
322 if (w2->isAncestorOf(w1)) {
327 if (w1->isAncestorOf(w2)) {
333 if (w1->modality() != Qt::NonModal && w2->modality() == Qt::NonModal)
336 if (w2->modality() != Qt::NonModal && w1->modality() == Qt::NonModal)
339 const bool isTool1 = (w1->flags() & Qt::Tool) == Qt::Tool;
340 const bool isTool2 = (w2->flags() & Qt::Tool) == Qt::Tool;
341 const bool isPurePopup1 = !isTool1 && (w1->flags() & Qt::Popup) == Qt::Popup;
342 const bool isPurePopup2 = !isTool2 && (w2->flags() & Qt::Popup) == Qt::Popup;
346 if (isPurePopup1 != isPurePopup2)
347 return !isPurePopup1;
350 if (isTool1 != isTool2)
354 return originalOrder.indexOf(cw1) < originalOrder.indexOf(cw2);
360#include "moc_qopenglcompositor_p.cpp"
static QOpenGLCompositor * compositor
static QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect, const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix, QOpenGLTextureBlitter::Origin sourceOrigin)