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