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 QtQuick 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 "qquicknvprfunctions_p.h"
41
42#if QT_CONFIG(opengl)
43
44#include <QOpenGLContext>
45#include <QOffscreenSurface>
46#include <QOpenGLExtraFunctions>
47#include "qquicknvprfunctions_p_p.h"
48
49QT_BEGIN_NAMESPACE
50
51/*!
52 \class QQuickNvprFunctions
53
54 \brief Function resolvers and other helpers for GL_NV_path_rendering
55 for both desktop (GL 4.3+) and mobile/embedded (GLES 3.1+) in a manner
56 that does not distract builds that do not have NVPR support either at
57 compile or run time.
58
59 \internal
60 */
61
62QQuickNvprFunctions::QQuickNvprFunctions()
63 : d(new QQuickNvprFunctionsPrivate(this))
64{
65}
66
67QQuickNvprFunctions::~QQuickNvprFunctions()
68{
69 delete d;
70}
71
72/*!
73 \return a recommended QSurfaceFormat suitable for GL_NV_path_rendering on top
74 of OpenGL 4.3 or OpenGL ES 3.1.
75 */
76QSurfaceFormat QQuickNvprFunctions::format()
77{
78 QSurfaceFormat fmt;
79 fmt.setDepthBufferSize(24);
80 fmt.setStencilBufferSize(8);
81 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
82 fmt.setVersion(major: 4, minor: 3);
83 fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
84 } else if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
85 fmt.setVersion(major: 3, minor: 1);
86 }
87 return fmt;
88}
89
90#define PROC(type, name) reinterpret_cast<type>(ctx->getProcAddress(#name))
91
92/*!
93 \return true if GL_NV_path_rendering is supported with the current OpenGL
94 context.
95
96 When there is no current context, a temporary dummy one will be created and
97 made current.
98 */
99bool QQuickNvprFunctions::isSupported()
100{
101 QOpenGLContext *ctx = QOpenGLContext::currentContext();
102 QScopedPointer<QOpenGLContext> tempContext;
103 QScopedPointer<QOffscreenSurface> tempSurface;
104 if (!ctx) {
105 tempContext.reset(other: new QOpenGLContext);
106 if (!tempContext->create())
107 return false;
108 ctx = tempContext.data();
109 tempSurface.reset(other: new QOffscreenSurface);
110 tempSurface->setFormat(ctx->format());
111 tempSurface->create();
112 if (!ctx->makeCurrent(surface: tempSurface.data()))
113 return false;
114 }
115
116 if (!ctx->hasExtension(QByteArrayLiteral("GL_NV_path_rendering")))
117 return false;
118
119 // Check that GL_NV_Path_rendering extension is at least API revision 1.3
120 if (!PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV))
121 return false;
122
123 // Do not check for DSA as the string may not be exposed on ES
124 // drivers, yet the functions we need are resolvable.
125#if 0
126 if (!ctx->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) {
127 qWarning("QtQuickPath/NVPR: GL_EXT_direct_state_access not supported");
128 return false;
129 }
130#endif
131
132 return true;
133}
134
135/*!
136 Initializes using the current OpenGL context.
137
138 \return true when GL_NV_path_rendering is supported and initialization was
139 successful.
140 */
141bool QQuickNvprFunctions::create()
142{
143 return isSupported() && d->resolve();
144}
145
146/*!
147 Creates a program pipeline consisting of a separable fragment shader program.
148
149 This is essential for using NVPR with OpenGL ES 3.1+ since normal,
150 GLES2-style programs would not work without a vertex shader.
151
152 \note \a fragmentShaderSource should be a \c{version 310 es} shader since
153 this works both on desktop and embedded NVIDIA drivers, thus avoiding the
154 need to fight GLSL and GLSL ES differences.
155
156 The pipeline object is stored into \a pipeline, the fragment shader program
157 into \a program.
158
159 Use QOpenGLExtraFunctions to set uniforms, bind the pipeline, etc.
160
161 \return \c false on failure in which case the error log is printed on the
162 debug output. \c true on success.
163 */
164bool QQuickNvprFunctions::createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program)
165{
166 QOpenGLContext *ctx = QOpenGLContext::currentContext();
167 if (!ctx)
168 return false;
169
170 QOpenGLExtraFunctions *f = ctx->extraFunctions();
171 *program = f->glCreateShaderProgramv(GL_FRAGMENT_SHADER, count: 1, strings: &fragmentShaderSource);
172 GLint status = 0;
173 f->glGetProgramiv(program: *program, GL_LINK_STATUS, params: &status);
174 if (!status) {
175 GLint len = 0;
176 f->glGetProgramiv(program: *program, GL_INFO_LOG_LENGTH, params: &len);
177 if (len) {
178 QByteArray s;
179 s.resize(size: len);
180 f->glGetProgramInfoLog(program: *program, bufsize: s.count(), length: nullptr, infolog: s.data());
181 qWarning(msg: "Failed to create separable shader program:\n%s", s.constData());
182 }
183 return false;
184 }
185
186 f->glGenProgramPipelines(n: 1, pipelines: pipeline);
187 f->glUseProgramStages(pipeline: *pipeline, GL_FRAGMENT_SHADER_BIT, program: *program);
188 f->glActiveShaderProgram(pipeline: *pipeline, program: *program);
189
190 f->glValidateProgramPipeline(pipeline: *pipeline);
191 status = 0;
192 f->glGetProgramPipelineiv(pipeline: *pipeline, GL_VALIDATE_STATUS, params: &status);
193 if (!status) {
194 GLint len = 0;
195 f->glGetProgramPipelineiv(pipeline: *pipeline, GL_INFO_LOG_LENGTH, params: &len);
196 if (len) {
197 QByteArray s;
198 s.resize(size: len);
199 f->glGetProgramPipelineInfoLog(pipeline: *pipeline, bufSize: s.count(), length: nullptr, infoLog: s.data());
200 qWarning(msg: "Program pipeline validation failed:\n%s", s.constData());
201 }
202 return false;
203 }
204
205 return true;
206}
207
208bool QQuickNvprFunctionsPrivate::resolve()
209{
210 QOpenGLContext *ctx = QOpenGLContext::currentContext();
211
212 q->genPaths = PROC(PFNGLGENPATHSNVPROC, glGenPathsNV);
213 q->deletePaths = PROC(PFNGLDELETEPATHSNVPROC, glDeletePathsNV);
214 q->isPath = PROC(PFNGLISPATHNVPROC, glIsPathNV);
215 q->pathCommands = PROC(PFNGLPATHCOMMANDSNVPROC, glPathCommandsNV);
216 q->pathCoords = PROC(PFNGLPATHCOORDSNVPROC, glPathCoordsNV);
217 q->pathSubCommands = PROC(PFNGLPATHSUBCOMMANDSNVPROC, glPathSubCommandsNV);
218 q->pathSubCoords = PROC(PFNGLPATHSUBCOORDSNVPROC, glPathSubCoordsNV);
219 q->pathString = PROC(PFNGLPATHSTRINGNVPROC, glPathStringNV);
220 q->pathGlyphs = PROC(PFNGLPATHGLYPHSNVPROC, glPathGlyphsNV);
221 q->pathGlyphRange = PROC(PFNGLPATHGLYPHRANGENVPROC, glPathGlyphRangeNV);
222 q->weightPaths = PROC(PFNGLWEIGHTPATHSNVPROC, glWeightPathsNV);
223 q->copyPath = PROC(PFNGLCOPYPATHNVPROC, glCopyPathNV);
224 q->interpolatePaths = PROC(PFNGLINTERPOLATEPATHSNVPROC, glInterpolatePathsNV);
225 q->transformPath = PROC(PFNGLTRANSFORMPATHNVPROC, glTransformPathNV);
226 q->pathParameteriv = PROC(PFNGLPATHPARAMETERIVNVPROC, glPathParameterivNV);
227 q->pathParameteri = PROC(PFNGLPATHPARAMETERINVPROC, glPathParameteriNV);
228 q->pathParameterfv = PROC(PFNGLPATHPARAMETERFVNVPROC, glPathParameterfvNV);
229 q->pathParameterf = PROC(PFNGLPATHPARAMETERFNVPROC, glPathParameterfNV);
230 q->pathDashArray = PROC(PFNGLPATHDASHARRAYNVPROC, glPathDashArrayNV);
231 q->pathStencilFunc = PROC(PFNGLPATHSTENCILFUNCNVPROC, glPathStencilFuncNV);
232 q->pathStencilDepthOffset = PROC(PFNGLPATHSTENCILDEPTHOFFSETNVPROC, glPathStencilDepthOffsetNV);
233 q->stencilFillPath = PROC(PFNGLSTENCILFILLPATHNVPROC, glStencilFillPathNV);
234 q->stencilStrokePath = PROC(PFNGLSTENCILSTROKEPATHNVPROC, glStencilStrokePathNV);
235 q->stencilFillPathInstanced = PROC(PFNGLSTENCILFILLPATHINSTANCEDNVPROC, glStencilFillPathInstancedNV);
236 q->stencilStrokePathInstanced = PROC(PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC, glStencilStrokePathInstancedNV);
237 q->pathCoverDepthFunc = PROC(PFNGLPATHCOVERDEPTHFUNCNVPROC, glPathCoverDepthFuncNV);
238 q->coverFillPath = PROC(PFNGLCOVERFILLPATHNVPROC, glCoverFillPathNV);
239 q->coverStrokePath = PROC(PFNGLCOVERSTROKEPATHNVPROC, glCoverStrokePathNV);
240 q->coverFillPathInstanced = PROC(PFNGLCOVERFILLPATHINSTANCEDNVPROC, glCoverFillPathInstancedNV);
241 q->coverStrokePathInstanced = PROC(PFNGLCOVERSTROKEPATHINSTANCEDNVPROC, glCoverStrokePathInstancedNV);
242 q->getPathParameteriv = PROC(PFNGLGETPATHPARAMETERIVNVPROC, glGetPathParameterivNV);
243 q->getPathParameterfv = PROC(PFNGLGETPATHPARAMETERFVNVPROC, glGetPathParameterfvNV);
244 q->getPathCommands = PROC(PFNGLGETPATHCOMMANDSNVPROC, glGetPathCommandsNV);
245 q->getPathCoords = PROC(PFNGLGETPATHCOORDSNVPROC, glGetPathCoordsNV);
246 q->getPathDashArray = PROC(PFNGLGETPATHDASHARRAYNVPROC, glGetPathDashArrayNV);
247 q->getPathMetrics = PROC(PFNGLGETPATHMETRICSNVPROC, glGetPathMetricsNV);
248 q->getPathMetricRange = PROC(PFNGLGETPATHMETRICRANGENVPROC, glGetPathMetricRangeNV);
249 q->getPathSpacing = PROC(PFNGLGETPATHSPACINGNVPROC, glGetPathSpacingNV);
250 q->isPointInFillPath = PROC(PFNGLISPOINTINFILLPATHNVPROC, glIsPointInFillPathNV);
251 q->isPointInStrokePath = PROC(PFNGLISPOINTINSTROKEPATHNVPROC, glIsPointInStrokePathNV);
252 q->getPathLength = PROC(PFNGLGETPATHLENGTHNVPROC, glGetPathLengthNV);
253 q->getPointAlongPath = PROC(PFNGLPOINTALONGPATHNVPROC, glPointAlongPathNV);
254 q->matrixLoad3x2f = PROC(PFNGLMATRIXLOAD3X2FNVPROC, glMatrixLoad3x2fNV);
255 q->matrixLoad3x3f = PROC(PFNGLMATRIXLOAD3X3FNVPROC, glMatrixLoad3x3fNV);
256 q->matrixLoadTranspose3x3f = PROC(PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC, glMatrixLoadTranspose3x3fNV);
257 q->matrixMult3x2f = PROC(PFNGLMATRIXMULT3X2FNVPROC, glMatrixMult3x2fNV);
258 q->matrixMult3x3f = PROC(PFNGLMATRIXMULT3X3FNVPROC, glMatrixMult3x3fNV);
259 q->matrixMultTranspose3x3f = PROC(PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC, glMatrixMultTranspose3x3fNV);
260 q->stencilThenCoverFillPath = PROC(PFNGLSTENCILTHENCOVERFILLPATHNVPROC, glStencilThenCoverFillPathNV);
261 q->stencilThenCoverStrokePath = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC, glStencilThenCoverStrokePathNV);
262 q->stencilThenCoverFillPathInstanced = PROC(PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC, glStencilThenCoverFillPathInstancedNV);
263 q->stencilThenCoverStrokePathInstanced = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC, glStencilThenCoverStrokePathInstancedNV);
264 q->pathGlyphIndexRange = PROC(PFNGLPATHGLYPHINDEXRANGENVPROC, glPathGlyphIndexRangeNV);
265 q->pathGlyphIndexArray = PROC(PFNGLPATHGLYPHINDEXARRAYNVPROC, glPathGlyphIndexArrayNV);
266 q->pathMemoryGlyphIndexArray = PROC(PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC, glPathMemoryGlyphIndexArrayNV);
267 q->programPathFragmentInputGen = PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV);
268 q->getProgramResourcefv = PROC(PFNGLGETPROGRAMRESOURCEFVNVPROC, glGetProgramResourcefvNV);
269
270 q->matrixLoadf = PROC(PFNGLMATRIXLOADFEXTPROC, glMatrixLoadfEXT);
271 q->matrixLoadIdentity = PROC(PFNGLMATRIXLOADIDENTITYEXTPROC, glMatrixLoadIdentityEXT);
272
273 return q->genPaths != nullptr // base path rendering ext
274 && q->programPathFragmentInputGen != nullptr // updated path rendering ext
275 && q->matrixLoadf != nullptr // direct state access ext
276 && q->matrixLoadIdentity != nullptr;
277}
278
279QT_END_NAMESPACE
280
281#endif // QT_CONFIG(opengl)
282

source code of qtdeclarative/src/quickshapes/qquicknvprfunctions.cpp