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

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