1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtOpenGL 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 <private/qglpaintdevice_p.h>
41#include <private/qgl_p.h>
42#include <private/qglpixelbuffer_p.h>
43#include <private/qglframebufferobject_p.h>
44#include <qopenglfunctions.h>
45#include <qwindow.h>
46
47QT_BEGIN_NAMESPACE
48
49QGLPaintDevice::QGLPaintDevice()
50 : m_thisFBO(0)
51{
52}
53
54QGLPaintDevice::~QGLPaintDevice()
55{
56}
57
58int QGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
59{
60 switch(metric) {
61 case PdmWidth:
62 return size().width();
63 case PdmHeight:
64 return size().height();
65 case PdmDepth: {
66 const QGLFormat f = format();
67 return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize();
68 }
69 case PdmDevicePixelRatio:
70 return 1;
71 case PdmDevicePixelRatioScaled:
72 return 1 * QPaintDevice::devicePixelRatioFScale();
73 default:
74 qWarning("QGLPaintDevice::metric() - metric %d not known", metric);
75 return 0;
76 }
77}
78
79void QGLPaintDevice::beginPaint()
80{
81 // Make sure our context is the current one:
82 QGLContext *ctx = context();
83 ctx->makeCurrent();
84
85 ctx->d_func()->refreshCurrentFbo();
86
87 // Record the currently bound FBO so we can restore it again
88 // in endPaint() and bind this device's FBO
89 //
90 // Note: m_thisFBO could be zero if the paint device is not
91 // backed by an FBO (e.g. window back buffer). But there could
92 // be a previous FBO bound to the context which we need to
93 // explicitly unbind. Otherwise the painting will go into
94 // the previous FBO instead of to the window.
95 m_previousFBO = ctx->d_func()->current_fbo;
96
97 if (m_previousFBO != m_thisFBO) {
98 ctx->d_func()->setCurrentFbo(m_thisFBO);
99 ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
100 }
101
102 // Set the default fbo for the context to m_thisFBO so that
103 // if some raw GL code between beginNativePainting() and
104 // endNativePainting() calls QGLFramebufferObject::release(),
105 // painting will revert to the window surface's fbo.
106 ctx->d_ptr->default_fbo = m_thisFBO;
107}
108
109void QGLPaintDevice::ensureActiveTarget()
110{
111 QGLContext* ctx = context();
112 if (ctx != QGLContext::currentContext())
113 ctx->makeCurrent();
114
115 ctx->d_func()->refreshCurrentFbo();
116
117 if (ctx->d_ptr->current_fbo != m_thisFBO) {
118 ctx->d_func()->setCurrentFbo(m_thisFBO);
119 ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
120 }
121
122 ctx->d_ptr->default_fbo = m_thisFBO;
123}
124
125void QGLPaintDevice::endPaint()
126{
127 // Make sure the FBO bound at beginPaint is re-bound again here:
128 QGLContext *ctx = context();
129 ctx->makeCurrent();
130
131 ctx->d_func()->refreshCurrentFbo();
132
133 if (m_previousFBO != ctx->d_func()->current_fbo) {
134 ctx->d_func()->setCurrentFbo(m_previousFBO);
135 ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO);
136 }
137
138 ctx->d_ptr->default_fbo = 0;
139}
140
141QGLFormat QGLPaintDevice::format() const
142{
143 return context()->format();
144}
145
146bool QGLPaintDevice::alphaRequested() const
147{
148 return context()->d_func()->reqFormat.alpha();
149}
150
151bool QGLPaintDevice::isFlipped() const
152{
153 return false;
154}
155
156////////////////// QGLWidgetGLPaintDevice //////////////////
157
158QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice()
159{
160}
161
162QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const
163{
164 return glWidget->paintEngine();
165}
166
167void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w)
168{
169 glWidget = w;
170}
171
172void QGLWidgetGLPaintDevice::beginPaint()
173{
174 QGLPaintDevice::beginPaint();
175 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
176 if (!glWidget->d_func()->disable_clear_on_painter_begin && glWidget->autoFillBackground()) {
177 if (glWidget->testAttribute(Qt::WA_TranslucentBackground))
178 funcs->glClearColor(0.0, 0.0, 0.0, 0.0);
179 else {
180 const QColor &c = glWidget->palette().brush(glWidget->backgroundRole()).color();
181 float alpha = c.alphaF();
182 funcs->glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
183 }
184 if (context()->d_func()->workaround_needsFullClearOnEveryFrame)
185 funcs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
186 else
187 funcs->glClear(GL_COLOR_BUFFER_BIT);
188 }
189}
190
191void QGLWidgetGLPaintDevice::endPaint()
192{
193 if (glWidget->autoBufferSwap())
194 glWidget->swapBuffers();
195 QGLPaintDevice::endPaint();
196}
197
198
199QSize QGLWidgetGLPaintDevice::size() const
200{
201 return glWidget->size() * (glWidget->windowHandle() ?
202 glWidget->windowHandle()->devicePixelRatio() : qApp->devicePixelRatio());
203}
204
205QGLContext* QGLWidgetGLPaintDevice::context() const
206{
207 return const_cast<QGLContext*>(glWidget->context());
208}
209
210// returns the QGLPaintDevice for the given QPaintDevice
211QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd)
212{
213 QGLPaintDevice* glpd = 0;
214
215 switch(pd->devType()) {
216 case QInternal::Widget:
217 // Should not be called on a non-gl widget:
218 Q_ASSERT(qobject_cast<QGLWidget*>(static_cast<QWidget*>(pd)));
219 glpd = &(static_cast<QGLWidget*>(pd)->d_func()->glDevice);
220 break;
221 case QInternal::Pbuffer:
222 glpd = &(static_cast<QGLPixelBuffer*>(pd)->d_func()->glDevice);
223 break;
224 case QInternal::FramebufferObject:
225 glpd = &(static_cast<QGLFramebufferObject*>(pd)->d_func()->glDevice);
226 break;
227 case QInternal::Pixmap: {
228 qWarning("Pixmap type not supported for GL rendering");
229 break;
230 }
231 default:
232 qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
233 break;
234 }
235
236 return glpd;
237}
238
239QT_END_NAMESPACE
240