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

source code of qtbase/src/opengl/qopenglpaintengine_p.h