123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861 | // Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qopenglengineshadermanager_p.h"#include"qopenglengineshadersource_p.h"#include"qopenglpaintengine_p.h"#include <private/qopenglshadercache_p.h>#include <QtGui/private/qopenglcontext_p.h>#include <QtCore/qthreadstorage.h>#include <algorithm>#include <memory>#if defined(QT_DEBUG)#include <QMetaEnum>#endif// #define QT_GL_SHARED_SHADER_DEBUG QT_BEGIN_NAMESPACE class QOpenGLEngineSharedShadersResource :public QOpenGLSharedResource {public:QOpenGLEngineSharedShadersResource(QOpenGLContext *ctx):QOpenGLSharedResource(ctx->shareGroup()),m_shaders(newQOpenGLEngineSharedShaders(ctx)){}~QOpenGLEngineSharedShadersResource(){delete m_shaders;}voidinvalidateResource() override {delete m_shaders; m_shaders =nullptr;}voidfreeResource(QOpenGLContext *) override {} QOpenGLEngineSharedShaders *shaders()const{return m_shaders; }private: QOpenGLEngineSharedShaders *m_shaders;};class QOpenGLShaderStorage {public: QOpenGLEngineSharedShaders *shadersForThread(QOpenGLContext *context) { QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData();if(!shaders) shaders =new QOpenGLMultiGroupSharedResource; QOpenGLEngineSharedShadersResource *resource = shaders->value<QOpenGLEngineSharedShadersResource>(context);return resource ? resource->shaders() :nullptr;}private: QThreadStorage<QOpenGLMultiGroupSharedResource *> m_storage;};Q_GLOBAL_STATIC(QOpenGLShaderStorage, qt_shader_storage); QOpenGLEngineSharedShaders *QOpenGLEngineSharedShaders::shadersForContext(QOpenGLContext *context){returnqt_shader_storage()->shadersForThread(context);}const char*QOpenGLEngineSharedShaders::qShaderSnippets[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context):blitShaderProg(nullptr),simpleShaderProg(nullptr){/* Rather than having the shader source array statically initialised, it is initialised here instead. This is to allow new shader names to be inserted or existing names moved around without having to change the order of the glsl strings. It is hoped this will make future hard-to-find runtime bugs more obvious and generally give more solid code.*/// Check if the user has requested an OpenGL 3.2 Core Profile or higher// and if so use GLSL 1.50 core shaders instead of legacy ones.const QSurfaceFormat &fmt = context->format();const bool isCoreProfile = fmt.profile() ==QSurfaceFormat::CoreProfile && fmt.version() >=std::pair(3,2);const char** code = qShaderSnippets;// shortcutif(isCoreProfile) { code[MainVertexShader] = qopenglslMainVertexShader_core; code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader_core; code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader_core; code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader_core; code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader_core; code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader_core; code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader_core; code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader_core; code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader_core; code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader_core; code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader_core; code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader_core; code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader_core; code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader_core; code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core; code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core; code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core; code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core; code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core; code[MainFragmentShader] = qopenglslMainFragmentShader_core; code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core; code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader_core; code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader_core; code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader_core; code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader_core; code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader_core; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core;// Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core; code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_core; code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core; code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core; code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core; code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader_core; code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader_core; code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader_core; code[NoMaskFragmentShader] =""; code[MaskFragmentShader] = qopenglslMaskFragmentShader_core; code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1_core; code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2_core; code[RgbMaskWithGammaFragmentShader] ="";//###}else{ code[MainVertexShader] = qopenglslMainVertexShader; code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader; code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader; code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader; code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader; code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader; code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader; code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader; code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader; code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader; code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader; code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader; code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader; code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader; code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader; code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader; code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO; code[MainFragmentShader_M] = qopenglslMainFragmentShader_M; code[MainFragmentShader_O] = qopenglslMainFragmentShader_O; code[MainFragmentShader] = qopenglslMainFragmentShader; code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays; code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader; code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader; code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader; code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader;// Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader; code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader; code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader; code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader; code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader; code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader; code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader; code[NoMaskFragmentShader] =""; code[MaskFragmentShader] = qopenglslMaskFragmentShader; code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1; code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2; code[RgbMaskWithGammaFragmentShader] ="";//###}// The composition shaders are just layout qualifiers and the same// for all profiles that support them. code[NoCompositionModeFragmentShader] =""; code[MultiplyCompositionModeFragmentShader] = qopenglslMultiplyCompositionModeFragmentShader; code[ScreenCompositionModeFragmentShader] = qopenglslScreenCompositionModeFragmentShader; code[OverlayCompositionModeFragmentShader] = qopenglslOverlayCompositionModeFragmentShader; code[DarkenCompositionModeFragmentShader] = qopenglslDarkenCompositionModeFragmentShader; code[LightenCompositionModeFragmentShader] = qopenglslLightenCompositionModeFragmentShader; code[ColorDodgeCompositionModeFragmentShader] = qopenglslColorDodgeCompositionModeFragmentShader; code[ColorBurnCompositionModeFragmentShader] = qopenglslColorBurnCompositionModeFragmentShader; code[HardLightCompositionModeFragmentShader] = qopenglslHardLightCompositionModeFragmentShader; code[SoftLightCompositionModeFragmentShader] = qopenglslSoftLightCompositionModeFragmentShader; code[DifferenceCompositionModeFragmentShader] = qopenglslDifferenceCompositionModeFragmentShader; code[ExclusionCompositionModeFragmentShader] = qopenglslExclusionCompositionModeFragmentShader;#if defined(QT_DEBUG)// Check that all the elements have been filled:for(int i =0; i < TotalSnippetCount; ++i) {if(Q_UNLIKELY(!qShaderSnippets[i])) {qFatal("Shader snippet for %s (#%d) is missing!",snippetNameStr(SnippetName(i)).constData(), i);}}#endif QByteArray vertexSource; QByteArray fragSource;// Compile up the simple shader:#ifdef Q_OS_WASM vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]); vertexSource.append(qShaderSnippets[MainVertexShader]);#else vertexSource.append(qShaderSnippets[MainVertexShader]); vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);#endif fragSource.append(qShaderSnippets[MainFragmentShader]); fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); simpleShaderProg =new QOpenGLShaderProgram; CachedShader simpleShaderCache(fragSource, vertexSource);bool inCache = simpleShaderCache.load(simpleShaderProg, context);if(!inCache) {if(!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");if(!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource))qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);} simpleShaderProg->link();if(Q_UNLIKELY(!simpleShaderProg->isLinked())) {qCritical("Errors linking simple shader: %s",qPrintable(simpleShaderProg->log()));}else{if(!inCache) simpleShaderCache.store(simpleShaderProg, context);}// Compile the blit shader: vertexSource.clear(); vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]); vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]); fragSource.clear(); fragSource.append(qShaderSnippets[MainFragmentShader]); fragSource.append(qShaderSnippets[ImageSrcFragmentShader]); blitShaderProg =new QOpenGLShaderProgram; CachedShader blitShaderCache(fragSource, vertexSource); inCache = blitShaderCache.load(blitShaderProg, context);if(!inCache) {if(!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");if(!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource))qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);} blitShaderProg->link();if(Q_UNLIKELY(!blitShaderProg->isLinked())) {qCritical("Errors linking blit shader: %s",qPrintable(blitShaderProg->log()));}else{if(!inCache) blitShaderCache.store(blitShaderProg, context);}#ifdef QT_GL_SHARED_SHADER_DEBUGqDebug(" -> QOpenGLEngineSharedShaders() %p for thread %p.",this,QThread::currentThread());#endif}QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders(){#ifdef QT_GL_SHARED_SHADER_DEBUGqDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.",this,QThread::currentThread());#endifqDeleteAll(cachedPrograms); cachedPrograms.clear();if(blitShaderProg) {delete blitShaderProg; blitShaderProg =nullptr;}if(simpleShaderProg) {delete simpleShaderProg; simpleShaderProg =nullptr;}}#if defined (QT_DEBUG) QByteArray QOpenGLEngineSharedShaders::snippetNameStr(SnippetName name){ QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));returnQByteArray(m.valueToKey(name));}#endif// The address returned here will only be valid until next time this function is called.// The program is return bound. QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QOpenGLEngineShaderProg &prog){for(int i =0; i < cachedPrograms.size(); ++i) { QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i];if(*cachedProg == prog) {// Move the program to the top of the list as a poor-man's cache algo cachedPrograms.move(i,0); cachedProg->program->bind();return cachedProg;}}std::unique_ptr<QOpenGLEngineShaderProg> newProg;do{ QByteArray fragSource;// Insert the custom stage before the srcPixel shader to work around an ATI driver bug// where you cannot forward declare a function that takes a sampler as argument.if(prog.srcPixelFragShader == CustomImageSrcFragmentShader) fragSource.append(prog.customStageSource); fragSource.append(qShaderSnippets[prog.mainFragShader]); fragSource.append(qShaderSnippets[prog.srcPixelFragShader]);if(prog.compositionFragShader) fragSource.append(qShaderSnippets[prog.compositionFragShader]);if(prog.maskFragShader) fragSource.append(qShaderSnippets[prog.maskFragShader]); QByteArray vertexSource;#ifdef Q_OS_WASM vertexSource.append(qShaderSnippets[prog.positionVertexShader]); vertexSource.append(qShaderSnippets[prog.mainVertexShader]);#else vertexSource.append(qShaderSnippets[prog.mainVertexShader]); vertexSource.append(qShaderSnippets[prog.positionVertexShader]);#endifauto shaderProgram =std::make_unique<QOpenGLShaderProgram>(); CachedShader shaderCache(fragSource, vertexSource);bool inCache = shaderCache.load(shaderProgram.get(),QOpenGLContext::currentContext());if(!inCache) {if(!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) { QByteArray description;#if defined(QT_DEBUG) description.append("Vertex shader: main="); description.append(snippetNameStr(prog.mainVertexShader)); description.append(", position="); description.append(snippetNameStr(prog.positionVertexShader));#endifqWarning("Warning:\"%s\"failed to compile!", description.constData());break;}if(!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) { QByteArray description;#if defined(QT_DEBUG) description.append("Fragment shader: main="); description.append(snippetNameStr(prog.mainFragShader)); description.append(", srcPixel="); description.append(snippetNameStr(prog.srcPixelFragShader));if(prog.compositionFragShader) { description.append(", composition="); description.append(snippetNameStr(prog.compositionFragShader));}if(prog.maskFragShader) { description.append(", mask="); description.append(snippetNameStr(prog.maskFragShader));}#endifqWarning("Warning:\"%s\"failed to compile!", description.constData());break;}// We have to bind the vertex attribute names before the program is linked: shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);if(prog.useTextureCoords) shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);if(prog.useOpacityAttribute) shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);if(prog.usePmvMatrixAttribute) { shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);}} newProg.reset(newQOpenGLEngineShaderProg(prog)); newProg->program = shaderProgram.release(); newProg->program->link();if(newProg->program->isLinked()) {if(!inCache) shaderCache.store(newProg->program,QOpenGLContext::currentContext());}else{qWarning("Shader program failed to link\n"" Error Log:\n"" %ls",qUtf16Printable(newProg->program->log()));break;} newProg->program->bind();if(newProg->maskFragShader !=QOpenGLEngineSharedShaders::NoMaskFragmentShader) { GLuint location = newProg->program->uniformLocation("maskTexture"); newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT);}if(cachedPrograms.size() >30) {// The cache is full, so delete the last 5 programs in the list.// These programs will be least used, as a program us bumped to// the top of the list when it's used.for(int i =0; i <5; ++i) {delete cachedPrograms.last(); cachedPrograms.removeLast();}} cachedPrograms.insert(0, newProg.get());}while(false);return newProg.release();}voidQOpenGLEngineSharedShaders::cleanupCustomStage(QOpenGLCustomShaderStage* stage){auto hasStageAsCustomShaderSouce = [stage](QOpenGLEngineShaderProg *cachedProg) ->bool{if(cachedProg->customStageSource == stage->source()) {delete cachedProg;return true;}return false;}; cachedPrograms.removeIf(hasStageAsCustomShaderSouce);}QOpenGLEngineShaderManager::QOpenGLEngineShaderManager(QOpenGLContext* context):ctx(context),shaderProgNeedsChanging(true),complexGeometry(false),srcPixelType(Qt::NoBrush),opacityMode(NoOpacity),maskType(NoMask),compositionMode(QPainter::CompositionMode_SourceOver),customSrcStage(nullptr),currentShaderProg(nullptr){ sharedShaders =QOpenGLEngineSharedShaders::shadersForContext(context);}QOpenGLEngineShaderManager::~QOpenGLEngineShaderManager(){//###removeCustomStage();} GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id){if(!currentShaderProg)return0; QList<uint> &uniformLocations = currentShaderProg->uniformLocations;if(uniformLocations.isEmpty()) uniformLocations.fill(GLuint(-1), NumUniforms);const char uniformNames[][26] = {"imageTexture","patternColor","globalOpacity","depth","maskTexture","fragmentColor","linearData","angle","halfViewportSize","fmp","fmp2_m_radius2","inverse_2_fmp2_m_radius2","sqrfr","bradius","invertedTextureSize","brushTransform","brushTexture","matrix"};if(uniformLocations.at(id) ==GLuint(-1)) uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);return uniformLocations.at(id);}voidQOpenGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType){Q_UNUSED(transformType);// Currently ignored}voidQOpenGLEngineShaderManager::setDirty(){ shaderProgNeedsChanging =true;}voidQOpenGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style){Q_ASSERT(style !=Qt::NoBrush);if(srcPixelType ==PixelSrcType(style))return; srcPixelType = style; shaderProgNeedsChanging =true;//###}voidQOpenGLEngineShaderManager::setSrcPixelType(PixelSrcType type){if(srcPixelType == type)return; srcPixelType = type; shaderProgNeedsChanging =true;//###}voidQOpenGLEngineShaderManager::setOpacityMode(OpacityMode mode){if(opacityMode == mode)return; opacityMode = mode; shaderProgNeedsChanging =true;//###}voidQOpenGLEngineShaderManager::setMaskType(MaskType type){if(maskType == type)return; maskType = type; shaderProgNeedsChanging =true;//###}voidQOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode){if(compositionMode == mode)return;bool wasAdvanced = compositionMode >QPainter::CompositionMode_Plus;bool isAdvanced = mode >QPainter::CompositionMode_Plus; compositionMode = mode; shaderProgNeedsChanging = shaderProgNeedsChanging || wasAdvanced || isAdvanced;}voidQOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage){if(customSrcStage)removeCustomStage(); customSrcStage = stage; shaderProgNeedsChanging =true;}voidQOpenGLEngineShaderManager::removeCustomStage(){if(customSrcStage) customSrcStage->setInactive(); customSrcStage =nullptr; shaderProgNeedsChanging =true;} QOpenGLShaderProgram*QOpenGLEngineShaderManager::currentProgram(){if(currentShaderProg)return currentShaderProg->program;elsereturn sharedShaders->simpleProgram();}voidQOpenGLEngineShaderManager::useSimpleProgram(){ sharedShaders->simpleProgram()->bind(); QOpenGLContextPrivate* ctx_d = ctx->d_func();Q_UNUSED(ctx_d); QOpenGL2PaintEngineEx *active_engine =static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR,true); active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR,false); active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR,false); shaderProgNeedsChanging =true;}voidQOpenGLEngineShaderManager::useBlitProgram(){ sharedShaders->blitProgram()->bind(); QOpenGLContextPrivate* ctx_d = ctx->d_func(); QOpenGL2PaintEngineEx *active_engine =static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR,true); active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR,true); active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR,false); shaderProgNeedsChanging =true;} QOpenGLShaderProgram*QOpenGLEngineShaderManager::simpleProgram(){return sharedShaders->simpleProgram();} QOpenGLShaderProgram*QOpenGLEngineShaderManager::blitProgram(){return sharedShaders->blitProgram();}// Select & use the correct shader program using the current state.// Returns \c true if program needed changing.boolQOpenGLEngineShaderManager::useCorrectShaderProg(){if(!shaderProgNeedsChanging)return false;bool useCustomSrc = customSrcStage !=nullptr;if(useCustomSrc && srcPixelType !=QOpenGLEngineShaderManager::ImageSrc && srcPixelType !=Qt::TexturePattern) { useCustomSrc =false;qWarning("QOpenGLEngineShaderManager - Ignoring custom shader stage for non image src");} QOpenGLEngineShaderProg requiredProgram;bool texCoords =false;// Choose vertex shader shader position function (which typically also sets// varyings) and the source pixel (srcPixel) fragment shader function: requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::InvalidSnippetName; requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::InvalidSnippetName;bool isAffine = brushTransform.isAffine();if( (srcPixelType >=Qt::Dense1Pattern) && (srcPixelType <=Qt::DiagCrossPattern) ) {if(isAffine) requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;else requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionWithPatternBrushVertexShader; requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::PatternBrushSrcFragmentShader;}else switch(srcPixelType) {default:caseQt::NoBrush:qFatal("QOpenGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");break;caseQOpenGLEngineShaderManager::ImageSrc: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::ImageSrcFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords =true;break;caseQOpenGLEngineShaderManager::NonPremultipliedImageSrc: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords =true;break;caseQOpenGLEngineShaderManager::GrayscaleImageSrc: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::GrayscaleImageSrcFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords =true;break;caseQOpenGLEngineShaderManager::AlphaImageSrc: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::AlphaImageSrcFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords =true;break;caseQOpenGLEngineShaderManager::PatternSrc: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords =true;break;caseQOpenGLEngineShaderManager::TextureSrcWithPattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; requiredProgram.positionVertexShader = isAffine ?QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader :QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader;break;caseQt::SolidPattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::SolidBrushSrcFragmentShader; requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::PositionOnlyVertexShader;break;caseQt::LinearGradientPattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; requiredProgram.positionVertexShader = isAffine ?QOpenGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader :QOpenGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;break;caseQt::ConicalGradientPattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; requiredProgram.positionVertexShader = isAffine ?QOpenGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader :QOpenGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;break;caseQt::RadialGradientPattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; requiredProgram.positionVertexShader = isAffine ?QOpenGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader :QOpenGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;break;caseQt::TexturePattern: requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::TextureBrushSrcFragmentShader; requiredProgram.positionVertexShader = isAffine ?QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader :QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader;break;};if(useCustomSrc) { requiredProgram.srcPixelFragShader =QOpenGLEngineSharedShaders::CustomImageSrcFragmentShader; requiredProgram.customStageSource = customSrcStage->source();}const bool hasCompose = compositionMode >QPainter::CompositionMode_Plus;const bool hasMask = maskType !=QOpenGLEngineShaderManager::NoMask;// Choose fragment shader main function:if(opacityMode == AttributeOpacity) {Q_ASSERT(!hasCompose && !hasMask); requiredProgram.mainFragShader =QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays;}else{bool useGlobalOpacity = (opacityMode == UniformOpacity);if(hasMask && useGlobalOpacity) requiredProgram.mainFragShader =QOpenGLEngineSharedShaders::MainFragmentShader_MO;if(hasMask && !useGlobalOpacity) requiredProgram.mainFragShader =QOpenGLEngineSharedShaders::MainFragmentShader_M;if(!hasMask && useGlobalOpacity) requiredProgram.mainFragShader =QOpenGLEngineSharedShaders::MainFragmentShader_O;if(!hasMask && !useGlobalOpacity) requiredProgram.mainFragShader =QOpenGLEngineSharedShaders::MainFragmentShader;}if(hasMask) {if(maskType == PixelMask) { requiredProgram.maskFragShader =QOpenGLEngineSharedShaders::MaskFragmentShader; texCoords =true;}else if(maskType == SubPixelMaskPass1) { requiredProgram.maskFragShader =QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass1; texCoords =true;}else if(maskType == SubPixelMaskPass2) { requiredProgram.maskFragShader =QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass2; texCoords =true;}else if(maskType == SubPixelWithGammaMask) { requiredProgram.maskFragShader =QOpenGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; texCoords =true;}else{qCritical("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");}}else{ requiredProgram.maskFragShader =QOpenGLEngineSharedShaders::NoMaskFragmentShader;}if(hasCompose) {switch(compositionMode) {caseQPainter::CompositionMode_Multiply: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Screen: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::ScreenCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Overlay: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::OverlayCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Darken: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::DarkenCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Lighten: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::LightenCompositionModeFragmentShader;break;caseQPainter::CompositionMode_ColorDodge: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;break;caseQPainter::CompositionMode_ColorBurn: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;break;caseQPainter::CompositionMode_HardLight: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::HardLightCompositionModeFragmentShader;break;caseQPainter::CompositionMode_SoftLight: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Difference: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;break;caseQPainter::CompositionMode_Exclusion: requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;break;default:qWarning("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");}}else{ requiredProgram.compositionFragShader =QOpenGLEngineSharedShaders::NoCompositionModeFragmentShader;}// Choose vertex shader main functionif(opacityMode == AttributeOpacity) {Q_ASSERT(texCoords); requiredProgram.mainVertexShader =QOpenGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;}else if(texCoords) { requiredProgram.mainVertexShader =QOpenGLEngineSharedShaders::MainWithTexCoordsVertexShader;}else{ requiredProgram.mainVertexShader =QOpenGLEngineSharedShaders::MainVertexShader;} requiredProgram.useTextureCoords = texCoords; requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);if(complexGeometry && srcPixelType ==Qt::SolidPattern) { requiredProgram.positionVertexShader =QOpenGLEngineSharedShaders::ComplexGeometryPositionOnlyVertexShader; requiredProgram.usePmvMatrixAttribute =false;}else{ requiredProgram.usePmvMatrixAttribute =true;// Force complexGeometry off, since we currently don't support that mode for// non-solid brushes complexGeometry =false;}// At this point, requiredProgram is fully populated so try to find the program in the cache currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);if(currentShaderProg && useCustomSrc) { customSrcStage->setUniforms(currentShaderProg->program);}// Make sure all the vertex attribute arrays the program uses are enabled (and the ones it// doesn't use are disabled) QOpenGLContextPrivate* ctx_d = ctx->d_func(); QOpenGL2PaintEngineEx *active_engine =static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR,true); active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg && currentShaderProg->useTextureCoords); active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg && currentShaderProg->useOpacityAttribute); shaderProgNeedsChanging =false;return true;} QT_END_NAMESPACE #include"moc_qopenglengineshadermanager_p.cpp"
|