5#include <QtOpenGL/QOpenGLFramebufferObject>
6#include <QtGui/QOpenGLContext>
7#include <QtGui/QWindow>
9#include <qpa/qplatformbackingstore.h>
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
44QOpenGLCompositor::QOpenGLCompositor()
49 Q_ASSERT(!compositor);
50 m_updateTimer.setSingleShot(
true);
51 m_updateTimer.setInterval(0);
52 connect(&m_updateTimer, SIGNAL(timeout()), SLOT(handleRenderAllRequest()));
55QOpenGLCompositor::~QOpenGLCompositor()
57 Q_ASSERT(compositor ==
this);
62void QOpenGLCompositor::setTargetWindow(QWindow *targetWindow,
const QRect &nativeTargetGeometry)
64 m_targetWindow = targetWindow;
65 m_nativeTargetGeometry = nativeTargetGeometry;
68void QOpenGLCompositor::setTargetContext(QOpenGLContext *context)
73void QOpenGLCompositor::setRotation(
int degrees)
76 m_rotationMatrix.setToIdentity();
77 m_rotationMatrix.rotate(degrees, 0, 0, 1);
80void QOpenGLCompositor::update()
82 if (!m_updateTimer.isActive())
83 m_updateTimer.start();
86QImage QOpenGLCompositor::grab()
88 Q_ASSERT(m_context && m_targetWindow);
89 QOpenGLFramebufferObject fbo(m_nativeTargetGeometry.size());
90 grabToFrameBufferObject(&fbo);
94bool QOpenGLCompositor::grabToFrameBufferObject(QOpenGLFramebufferObject *fbo, GrabOrientation orientation)
97 if (fbo->size() != m_nativeTargetGeometry.size()
98 || fbo->format().textureTarget() != GL_TEXTURE_2D)
101 m_context->makeCurrent(m_targetWindow);
103 orientation == Flipped ? QOpenGLTextureBlitter::OriginTopLeft
104 : QOpenGLTextureBlitter::OriginBottomLeft);
108void QOpenGLCompositor::handleRenderAllRequest()
110 Q_ASSERT(m_context && m_targetWindow);
111 m_context->makeCurrent(m_targetWindow);
115void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo, QOpenGLTextureBlitter::Origin origin)
120 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
121 glViewport(0, 0, m_nativeTargetGeometry.width(), m_nativeTargetGeometry.height());
123 if (!m_blitter.isCreated())
128 for (
int i = 0; i < m_windows.size(); ++i)
129 m_windows.at(i)->beginCompositing();
131 for (
int i = 0; i < m_windows.size(); ++i)
132 render(m_windows.at(i), origin);
136 m_context->swapBuffers(m_targetWindow);
140 for (
int i = 0; i < m_windows.size(); ++i)
141 m_windows.at(i)->endCompositing();
153 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
169 return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
170 topLeftRect.width(), topLeftRect.height());
173static void clippedBlit(
const QPlatformTextureList *textures,
int idx,
174 const QRect &sourceWindowRect,
const QRect &targetWindowRect,
175 QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix,
176 QOpenGLTextureBlitter::Origin sourceOrigin)
178 const QRect clipRect = textures->clipRect(idx);
179 if (clipRect.isEmpty())
182 const QRect rectInWindow = textures->geometry(idx).translated(sourceWindowRect.topLeft());
183 const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
184 const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
186 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(clippedRectInWindow, targetWindowRect);
188 target = *rotationMatrix * target;
190 const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(),
193 const uint textureId = textures->texture(idx)->nativeTexture().object;
194 blitter->blit(textureId, target, source);
197void QOpenGLCompositor::render(QOpenGLCompositorWindow *window, QOpenGLTextureBlitter::Origin origin)
199 const QPlatformTextureList *textures = window->textures();
203 const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size());
204 float currentOpacity = 1.0f;
205 BlendStateBinder blend;
206 const QRect sourceWindowRect = window->sourceWindow()->geometry();
207 auto clippedBlitSourceOrigin = origin == QOpenGLTextureBlitter::OriginTopLeft
208 ? QOpenGLTextureBlitter::OriginBottomLeft
209 : QOpenGLTextureBlitter::OriginTopLeft;
210 for (
int i = 0; i < textures->count(); ++i) {
211 const uint textureId = textures->texture(i)->nativeTexture().object;
212 const float opacity = window->sourceWindow()->opacity();
213 if (opacity != currentOpacity) {
214 currentOpacity = opacity;
215 m_blitter.setOpacity(currentOpacity);
218 if (textures->count() > 1 && i == textures->count() - 1) {
221 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
223 target = m_rotationMatrix * target;
224 m_blitter.blit(textureId, target, origin);
225 }
else if (textures->count() == 1) {
227 const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
228 blend.set(translucent);
229 QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
231 target = m_rotationMatrix * target;
232 m_blitter.blit(textureId, target, origin);
233 }
else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
236 clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
237 m_rotation ? &m_rotationMatrix :
nullptr, clippedBlitSourceOrigin);
241 for (
int i = 0; i < textures->count(); ++i) {
242 if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
244 clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
245 m_rotation ? &m_rotationMatrix :
nullptr, clippedBlitSourceOrigin);
249 m_blitter.setOpacity(1.0f);
252QOpenGLCompositor *QOpenGLCompositor::instance()
255 compositor =
new QOpenGLCompositor;
259void QOpenGLCompositor::destroy()
265void QOpenGLCompositor::addWindow(QOpenGLCompositorWindow *window)
267 if (!m_windows.contains(window)) {
268 m_windows.append(window);
269 ensureCorrectZOrder();
270 if (window == m_windows.constLast())
271 emit topWindowChanged(window);
275void QOpenGLCompositor::removeWindow(QOpenGLCompositorWindow *window)
277 bool couldChangeTopWindow = (m_windows.size() > 1) ? (window == m_windows.constLast()) :
false;
278 if (m_windows.removeOne(window) && couldChangeTopWindow)
279 emit topWindowChanged(m_windows.constLast());
282void QOpenGLCompositor::moveToTop(QOpenGLCompositorWindow *window)
284 if (!m_windows.isEmpty() && window == m_windows.constLast()) {
289 m_windows.removeOne(window);
290 m_windows.append(window);
291 ensureCorrectZOrder();
293 if (window == m_windows.constLast())
294 emit topWindowChanged(window);
297void QOpenGLCompositor::changeWindowIndex(QOpenGLCompositorWindow *window,
int newIdx)
299 int idx = m_windows.indexOf(window);
300 if (idx != -1 && idx != newIdx) {
301 m_windows.move(idx, newIdx);
302 ensureCorrectZOrder();
303 if (window == m_windows.constLast())
304 emit topWindowChanged(m_windows.last());
308void QOpenGLCompositor::ensureCorrectZOrder()
310 const auto originalOrder = m_windows;
312 std::sort(m_windows.begin(), m_windows.end(),
313 [
this, &originalOrder](QOpenGLCompositorWindow *cw1, QOpenGLCompositorWindow *cw2) {
314 QWindow *w1 = cw1->sourceWindow();
315 QWindow *w2 = cw2->sourceWindow();
319 if (w1 == m_targetWindow || w2 == m_targetWindow)
320 return w1 == m_targetWindow;
323 if (w2->isAncestorOf(w1)) {
328 if (w1->isAncestorOf(w2)) {
334 if (w1->modality() != Qt::NonModal && w2->modality() == Qt::NonModal)
337 if (w2->modality() != Qt::NonModal && w1->modality() == Qt::NonModal)
340 const bool isTool1 = (w1->flags() & Qt::Tool) == Qt::Tool;
341 const bool isTool2 = (w2->flags() & Qt::Tool) == Qt::Tool;
342 const bool isPurePopup1 = !isTool1 && (w1->flags() & Qt::Popup) == Qt::Popup;
343 const bool isPurePopup2 = !isTool2 && (w2->flags() & Qt::Popup) == Qt::Popup;
347 if (isPurePopup1 != isPurePopup2)
348 return !isPurePopup1;
351 if (isTool1 != isTool2)
355 return originalOrder.indexOf(cw1) < originalOrder.indexOf(cw2);
361#include "moc_qopenglcompositor_p.cpp"
Combined button and popup list for selecting options.
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)