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 QtGui 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 #ifndef QOPENGLPAINTENGINE_P_H
41 #define QOPENGLPAINTENGINE_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 #include <QDebug>
56 
57 #include <qopenglpaintdevice.h>
58 
59 #include <private/qpaintengineex_p.h>
60 #include <private/qopenglengineshadermanager_p.h>
61 #include <private/qopengl2pexvertexarray_p.h>
62 #include <private/qfontengine_p.h>
63 #include <private/qdatabuffer_p.h>
64 #include <private/qtriangulatingstroker_p.h>
65 
66 #include <private/qopenglextensions_p.h>
67 
68 #include <QOpenGLVertexArrayObject>
69 #include <QOpenGLBuffer>
70 
71 enum EngineMode {
72     ImageDrawingMode,
73     TextDrawingMode,
74     BrushDrawingMode,
75     ImageArrayDrawingMode,
76     ImageOpacityArrayDrawingMode
77 };
78 
79 QT_BEGIN_NAMESPACE
80 
81 #define GL_STENCIL_HIGH_BIT         GLuint(0x80)
82 #define QT_UNKNOWN_TEXTURE_UNIT     GLuint(-1)
83 #define QT_DEFAULT_TEXTURE_UNIT     GLuint(0)
84 #define QT_BRUSH_TEXTURE_UNIT       GLuint(0)
85 #define QT_IMAGE_TEXTURE_UNIT       GLuint(0) //Can be the same as brush texture unit
86 #define QT_MASK_TEXTURE_UNIT        GLuint(1)
87 #define QT_BACKGROUND_TEXTURE_UNIT  GLuint(2)
88 
89 class QOpenGL2PaintEngineExPrivate;
90 
91 class QOpenGL2PaintEngineState : public QPainterState
92 {
93 public:
94     QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other);
95     QOpenGL2PaintEngineState();
96     ~QOpenGL2PaintEngineState();
97 
98     uint isNew : 1;
99     uint needsClipBufferClear : 1;
100     uint clipTestEnabled : 1;
101     uint canRestoreClip : 1;
102     uint matrixChanged : 1;
103     uint compositionModeChanged : 1;
104     uint opacityChanged : 1;
105     uint renderHintsChanged : 1;
106     uint clipChanged : 1;
107     uint currentClip : 8;
108 
109     QRect rectangleClip;
110 };
111 
112 class Q_GUI_EXPORT QOpenGL2PaintEngineEx : public QPaintEngineEx
113 {
114     Q_DECLARE_PRIVATE(QOpenGL2PaintEngineEx)
115 public:
116     QOpenGL2PaintEngineEx();
117     ~QOpenGL2PaintEngineEx();
118 
119     bool begin(QPaintDevice *device) override;
120     void ensureActive();
121     bool end() override;
122 
123     virtual void clipEnabledChanged() override;
124     virtual void penChanged() override;
125     virtual void brushChanged() override;
126     virtual void brushOriginChanged() override;
127     virtual void opacityChanged() override;
128     virtual void compositionModeChanged() override;
129     virtual void renderHintsChanged() override;
130     virtual void transformChanged() override;
131 
132     virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override;
133     virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
134                                      QPainter::PixmapFragmentHints hints) override;
135     virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
136                            Qt::ImageConversionFlags flags = Qt::AutoColor) override;
137     virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) override;
138     virtual void fill(const QVectorPath &path, const QBrush &brush) override;
139     virtual void stroke(const QVectorPath &path, const QPen &pen) override;
140     virtual void clip(const QVectorPath &path, Qt::ClipOperation op) override;
141 
142     virtual void drawStaticTextItem(QStaticTextItem *textItem) override;
143 
144     bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
145 
type()146     Type type() const override { return OpenGL2; }
147 
148     virtual void setState(QPainterState *s) override;
149     virtual QPainterState *createState(QPainterState *orig) const override;
state()150     inline QOpenGL2PaintEngineState *state() {
151         return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
152     }
state()153     inline const QOpenGL2PaintEngineState *state() const {
154         return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
155     }
156 
157     void beginNativePainting() override;
158     void endNativePainting() override;
159 
160     void invalidateState();
161 
162     void setRenderTextActive(bool);
163 
164     bool isNativePaintingActive() const;
requiresPretransformedGlyphPositions(QFontEngine *,const QTransform &)165     bool requiresPretransformedGlyphPositions(QFontEngine *, const QTransform &) const override { return false; }
166     bool shouldDrawCachedGlyphs(QFontEngine *, const QTransform &) const override;
167 
168 private:
169     Q_DISABLE_COPY_MOVE(QOpenGL2PaintEngineEx)
170 
171     friend class QOpenGLEngineShaderManager;
172 };
173 
174 // This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
175 // all the GL2 engine uses:
176 #define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
177 
178 class QOpenGL2PaintEngineExPrivate : public QPaintEngineExPrivate
179 {
180     Q_DECLARE_PUBLIC(QOpenGL2PaintEngineEx)
181 public:
182     enum StencilFillMode {
183         OddEvenFillMode,
184         WindingFillMode,
185         TriStripStrokeFillMode
186     };
187 
188     QOpenGL2PaintEngineExPrivate(QOpenGL2PaintEngineEx *q_ptr) :
189             q(q_ptr),
190             shaderManager(nullptr),
191             width(0), height(0),
192             ctx(nullptr),
193             useSystemClip(true),
194             elementIndicesVBOId(0),
195             opacityArray(0),
196             snapToPixelGrid(false),
197             nativePaintingActive(false),
198             inverseScale(1),
199             lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT),
200             vertexBuffer(QOpenGLBuffer::VertexBuffer),
201             texCoordBuffer(QOpenGLBuffer::VertexBuffer),
202             opacityBuffer(QOpenGLBuffer::VertexBuffer),
203             indexBuffer(QOpenGLBuffer::IndexBuffer)
204     { }
205 
206     ~QOpenGL2PaintEngineExPrivate();
207 
208     void updateBrushTexture();
209     void updateBrushUniforms();
210     void updateMatrix();
211     void updateCompositionMode();
212 
213     enum TextureUpdateMode { UpdateIfNeeded, ForceUpdate };
214     template<typename T>
215     void updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode = UpdateIfNeeded);
216     template<typename T>
217     GLuint bindTexture(const T &texture);
218     void activateTextureUnit(GLenum textureUnit);
219 
220     void resetGLState();
221 
222     // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points,
223     // however writeClip can also be thought of as en entry point as it does similar things.
224     void fill(const QVectorPath &path);
225     void stroke(const QVectorPath &path, const QPen &pen);
226     void drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
227     void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
228                              QPainter::PixmapFragmentHints hints);
229     void drawCachedGlyphs(QFontEngine::GlyphFormat glyphFormat, QStaticTextItem *staticTextItem);
230 
231     // Calls glVertexAttributePointer if the pointer has changed
232     inline void uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count);
233     inline bool uploadIndexData(const void *data, GLenum indexValueType, GLuint count);
234 
235     // draws whatever is in the vertex array:
236     void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
237     void drawVertexArrays(QOpenGL2PEXVertexArray &vertexArray, GLenum primitive) {
238         drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive);
239     }
240 
241     // Composites the bounding rect onto dest buffer:
242     void composite(const QOpenGLRect& boundingRect);
243 
244     // Calls drawVertexArrays to render into stencil buffer:
245     void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QOpenGLRect &bounds, StencilFillMode mode);
246     void fillStencilWithVertexArray(QOpenGL2PEXVertexArray& vertexArray, bool useWindingFill) {
247         fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(),
248                                    vertexArray.boundingRect(),
249                                    useWindingFill ? WindingFillMode : OddEvenFillMode);
250     }
251 
252     void setBrush(const QBrush& brush);
253     void transferMode(EngineMode newMode);
254     bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed
255     bool prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache);
256     inline void useSimpleShader();
257     inline GLuint location(const QOpenGLEngineShaderManager::Uniform uniform) {
258         return shaderManager->getUniformLocation(uniform);
259     }
260 
261     void clearClip(uint value);
262     void writeClip(const QVectorPath &path, uint value);
263     void resetClipIfNeeded();
264 
265     void updateClipScissorTest();
266     void setScissor(const QRect &rect);
267     void regenerateClip();
268     void systemStateChanged() override;
269 
270     void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
271     void syncGlState();
272 
273     static QOpenGLEngineShaderManager* shaderManagerForEngine(QOpenGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
274     static QOpenGL2PaintEngineExPrivate *getData(QOpenGL2PaintEngineEx *engine) { return engine->d_func(); }
275     static void cleanupVectorPath(QPaintEngineEx *engine, void *data);
276 
277     QOpenGLExtensions funcs;
278 
279     QOpenGL2PaintEngineEx* q;
280     QOpenGLEngineShaderManager* shaderManager;
281     QOpenGLPaintDevice* device;
282     int width, height;
283     QOpenGLContext *ctx;
284     EngineMode mode;
285     QFontEngine::GlyphFormat glyphCacheFormat;
286 
287     bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
288 
289     // Dirty flags
290     bool matrixDirty; // Implies matrix uniforms are also dirty
291     bool compositionModeDirty;
292     bool brushTextureDirty;
293     bool brushUniformsDirty;
294     bool opacityUniformDirty;
295     bool matrixUniformDirty;
296 
297     bool stencilClean; // Has the stencil not been used for clipping so far?
298     bool useSystemClip;
299     QRegion dirtyStencilRegion;
300     QRect currentScissorBounds;
301     uint maxClip;
302 
303     QBrush currentBrush; // May not be the state's brush!
304     const QBrush noBrush;
305 
306     QImage currentBrushImage;
307 
308     QOpenGL2PEXVertexArray vertexCoordinateArray;
309     QOpenGL2PEXVertexArray textureCoordinateArray;
310     QVector<GLushort> elementIndices;
311     GLuint elementIndicesVBOId;
312     QDataBuffer<GLfloat> opacityArray;
313     GLfloat staticVertexCoordinateArray[8];
314     GLfloat staticTextureCoordinateArray[8];
315 
316     bool snapToPixelGrid;
317     bool nativePaintingActive;
318     GLfloat pmvMatrix[3][3];
319     GLfloat inverseScale;
320 
321     GLenum lastTextureUnitUsed;
322     GLuint lastTextureUsed;
323 
324     QOpenGLVertexArrayObject vao;
325     QOpenGLBuffer vertexBuffer;
326     QOpenGLBuffer texCoordBuffer;
327     QOpenGLBuffer opacityBuffer;
328     QOpenGLBuffer indexBuffer;
329 
330     bool needsSync;
331     bool multisamplingAlwaysEnabled;
332 
333     QTriangulatingStroker stroker;
334     QDashedStrokeProcessor dasher;
335 
336     QVector<GLuint> unusedVBOSToClean;
337     QVector<GLuint> unusedIBOSToClean;
338 
339     const GLfloat *vertexAttribPointers[3];
340 };
341 
342 
343 void QOpenGL2PaintEngineExPrivate::uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count)
344 {
345     Q_ASSERT(arrayIndex < 3);
346 
347     // If a vertex array object is created we have a profile that supports them
348     // and we will upload the data via a QOpenGLBuffer. Otherwise we will use
349     // the legacy way of uploading the data via glVertexAttribPointer.
350     if (vao.isCreated()) {
351         if (arrayIndex == QT_VERTEX_COORDS_ATTR) {
352             vertexBuffer.bind();
353             vertexBuffer.allocate(data, count * sizeof(float));
354         }
355         if (arrayIndex == QT_TEXTURE_COORDS_ATTR) {
356             texCoordBuffer.bind();
357             texCoordBuffer.allocate(data, count * sizeof(float));
358         }
359         if (arrayIndex == QT_OPACITY_ATTR) {
360             opacityBuffer.bind();
361             opacityBuffer.allocate(data, count * sizeof(float));
362         }
363         if (arrayIndex == QT_OPACITY_ATTR)
364             funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
365         else
366             funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
367     } else {
368         // If we already uploaded the data we don't have to do it again
369         if (data == vertexAttribPointers[arrayIndex])
370             return;
371 
372         // Store the data in cache and upload it to the graphics card.
373         vertexAttribPointers[arrayIndex] = data;
374         if (arrayIndex == QT_OPACITY_ATTR)
375             funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, data);
376         else
377             funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, data);
378     }
379 }
380 
381 bool QOpenGL2PaintEngineExPrivate::uploadIndexData(const void *data, GLenum indexValueType, GLuint count)
382 {
383     // Follow the uploadData() logic: VBOs are used only when VAO support is available.
384     // Otherwise the legacy client-side pointer path is used.
385     if (vao.isCreated()) {
386         Q_ASSERT(indexValueType == GL_UNSIGNED_SHORT || indexValueType == GL_UNSIGNED_INT);
387         indexBuffer.bind();
388         indexBuffer.allocate(data, count * (indexValueType == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32)));
389         return true;
390     }
391     return false;
392 }
393 
394 QT_END_NAMESPACE
395 
396 #endif
397