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
47 QT_BEGIN_NAMESPACE
48
QGLPaintDevice()49 QGLPaintDevice::QGLPaintDevice()
50 : m_thisFBO(0)
51 {
52 }
53
~QGLPaintDevice()54 QGLPaintDevice::~QGLPaintDevice()
55 {
56 }
57
metric(QPaintDevice::PaintDeviceMetric metric) const58 int 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
beginPaint()79 void 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
ensureActiveTarget()109 void 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
endPaint()125 void 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
format() const141 QGLFormat QGLPaintDevice::format() const
142 {
143 return context()->format();
144 }
145
alphaRequested() const146 bool QGLPaintDevice::alphaRequested() const
147 {
148 return context()->d_func()->reqFormat.alpha();
149 }
150
isFlipped() const151 bool QGLPaintDevice::isFlipped() const
152 {
153 return false;
154 }
155
156 ////////////////// QGLWidgetGLPaintDevice //////////////////
157
QGLWidgetGLPaintDevice()158 QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice()
159 {
160 }
161
paintEngine() const162 QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const
163 {
164 return glWidget->paintEngine();
165 }
166
setWidget(QGLWidget * w)167 void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w)
168 {
169 glWidget = w;
170 }
171
beginPaint()172 void 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
endPaint()191 void QGLWidgetGLPaintDevice::endPaint()
192 {
193 if (glWidget->autoBufferSwap())
194 glWidget->swapBuffers();
195 QGLPaintDevice::endPaint();
196 }
197
198
size() const199 QSize QGLWidgetGLPaintDevice::size() const
200 {
201 return glWidget->size() * (glWidget->windowHandle() ?
202 glWidget->windowHandle()->devicePixelRatio() : qApp->devicePixelRatio());
203 }
204
context() const205 QGLContext* QGLWidgetGLPaintDevice::context() const
206 {
207 return const_cast<QGLContext*>(glWidget->context());
208 }
209
210 // returns the QGLPaintDevice for the given QPaintDevice
getDevice(QPaintDevice * pd)211 QGLPaintDevice* 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
239 QT_END_NAMESPACE
240