コード例 #1
0
QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
    : ctxGuard(context)
    , blitShaderProg(0)
    , simpleShaderProg(0)
{

/*
    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.
*/
    static bool snippetsPopulated = false;
    if (!snippetsPopulated) {

        const char** code = qShaderSnippets; // shortcut

        code[MainVertexShader] = qglslMainVertexShader;
        code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
        code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;

        code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
        code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
        code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
        code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
        code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader;
        code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader;
        code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader;
        code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader;
        code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader;
        code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader;
        code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader;
        code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader;

        code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO;
        code[MainFragmentShader_CM] = qglslMainFragmentShader_CM;
        code[MainFragmentShader_MO] = qglslMainFragmentShader_MO;
        code[MainFragmentShader_M] = qglslMainFragmentShader_M;
        code[MainFragmentShader_CO] = qglslMainFragmentShader_CO;
        code[MainFragmentShader_C] = qglslMainFragmentShader_C;
        code[MainFragmentShader_O] = qglslMainFragmentShader_O;
        code[MainFragmentShader] = qglslMainFragmentShader;
        code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;

        code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
        code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
        code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
        code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
        code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
        code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
        code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
        code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader;
        code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader;
        code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader;
        code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
        code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;

        code[NoMaskFragmentShader] = "";
        code[MaskFragmentShader] = qglslMaskFragmentShader;
        code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
        code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
        code[RgbMaskWithGammaFragmentShader] = ""; //###

        code[NoCompositionModeFragmentShader] = "";
        code[MultiplyCompositionModeFragmentShader] = ""; //###
        code[ScreenCompositionModeFragmentShader] = ""; //###
        code[OverlayCompositionModeFragmentShader] = ""; //###
        code[DarkenCompositionModeFragmentShader] = ""; //###
        code[LightenCompositionModeFragmentShader] = ""; //###
        code[ColorDodgeCompositionModeFragmentShader] = ""; //###
        code[ColorBurnCompositionModeFragmentShader] = ""; //###
        code[HardLightCompositionModeFragmentShader] = ""; //###
        code[SoftLightCompositionModeFragmentShader] = ""; //###
        code[DifferenceCompositionModeFragmentShader] = ""; //###
        code[ExclusionCompositionModeFragmentShader] = ""; //###

#if defined(QT_DEBUG)
        // Check that all the elements have been filled:
        for (int i = 0; i < TotalSnippetCount; ++i) {
            if (qShaderSnippets[i] == 0) {
                qFatal("Shader snippet for %s (#%d) is missing!",
                       snippetNameStr(SnippetName(i)).constData(), i);
            }
        }
#endif
        snippetsPopulated = true;
    }

    QGLShader* fragShader;
    QGLShader* vertexShader;
    QByteArray source;

    // Compile up the simple shader:
    source.clear();
    source.append(qShaderSnippets[MainVertexShader]);
    source.append(qShaderSnippets[PositionOnlyVertexShader]);
    vertexShader = new QGLShader(QGLShader::Vertex, context, this);
    vertexShader->compileSourceCode(source);

    source.clear();
    source.append(qShaderSnippets[MainFragmentShader]);
    source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
    fragShader = new QGLShader(QGLShader::Fragment, context, this);
    fragShader->compileSourceCode(source);

    simpleShaderProg = new QGLShaderProgram(context, this);
    simpleShaderProg->addShader(vertexShader);
    simpleShaderProg->addShader(fragShader);
    simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
    simpleShaderProg->link();
    if (!simpleShaderProg->isLinked()) {
        qCritical() << "Errors linking simple shader:"
                    << simpleShaderProg->log();
    }

    // Compile the blit shader:
    source.clear();
    source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
    source.append(qShaderSnippets[UntransformedPositionVertexShader]);
    vertexShader = new QGLShader(QGLShader::Vertex, context, this);
    vertexShader->compileSourceCode(source);

    source.clear();
    source.append(qShaderSnippets[MainFragmentShader]);
    source.append(qShaderSnippets[ImageSrcFragmentShader]);
    fragShader = new QGLShader(QGLShader::Fragment, context, this);
    fragShader->compileSourceCode(source);

    blitShaderProg = new QGLShaderProgram(context, this);
    blitShaderProg->addShader(vertexShader);
    blitShaderProg->addShader(fragShader);
    blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
    blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
    blitShaderProg->link();
    if (!blitShaderProg->isLinked()) {
        qCritical() << "Errors linking blit shader:"
                    << simpleShaderProg->log();
    }

}
コード例 #2
0
// The address returned here will only be valid until next time this function is called.
QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
{
    for (int i = 0; i < cachedPrograms.size(); ++i) {
        QGLEngineShaderProg *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);
            return cachedProg;
        }
    }

    QByteArray source;
    source.append(qShaderSnippets[prog.mainFragShader]);
    source.append(qShaderSnippets[prog.srcPixelFragShader]);
    if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
        source.append(prog.customStageSource);
    if (prog.compositionFragShader)
        source.append(qShaderSnippets[prog.compositionFragShader]);
    if (prog.maskFragShader)
        source.append(qShaderSnippets[prog.maskFragShader]);
    QGLShader* fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
    fragShader->compileSourceCode(source);

    source.clear();
    source.append(qShaderSnippets[prog.mainVertexShader]);
    source.append(qShaderSnippets[prog.positionVertexShader]);
    QGLShader* vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
    vertexShader->compileSourceCode(source);

#if defined(QT_DEBUG)
    // Name the shaders for easier debugging
    QByteArray description;
    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));
    }
    fragShader->setObjectName(QString::fromLatin1(description));

    description.clear();
    description.append("Vertex shader: main=");
    description.append(snippetNameStr(prog.mainVertexShader));
    description.append(", position=");
    description.append(snippetNameStr(prog.positionVertexShader));
    vertexShader->setObjectName(QString::fromLatin1(description));
#endif

    QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog);

    // If the shader program's not found in the cache, create it now.
    newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
    newProg->program->addShader(vertexShader);
    newProg->program->addShader(fragShader);

    // We have to bind the vertex attribute names before the program is linked:
    newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
    if (newProg->useTextureCoords)
        newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
    if (newProg->useOpacityAttribute)
        newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);

    newProg->program->link();
    if (!newProg->program->isLinked()) {
        QLatin1String none("none");
        QLatin1String br("\n");
        QString error;
        error = QLatin1String("Shader program failed to link,")
#if defined(QT_DEBUG)
            + br
            + QLatin1String("  Shaders Used:") + br
            + QLatin1String("    ") + vertexShader->objectName() + QLatin1String(": ") + br
            + QLatin1String(vertexShader->sourceCode()) + br
            + QLatin1String("    ") + fragShader->objectName() + QLatin1String(": ") + br
            + QLatin1String(fragShader->sourceCode()) + br
#endif
            + QLatin1String("  Error Log:\n")
            + QLatin1String("    ") + newProg->program->log();
        qWarning() << error;
        delete newProg; // Deletes the QGLShaderProgram in it's destructor
        newProg = 0;
    }
    else {
        if (cachedPrograms.count() > 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);
    }

    return newProg;
}
コード例 #3
0
QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
    : blitShaderProg(0)
    , simpleShaderProg(0)
{

    /*
        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.
    */
    static bool snippetsPopulated = false;
    if (!snippetsPopulated) {

        const char** code = qShaderSnippets; // shortcut

        code[MainVertexShader] = qglslMainVertexShader;
        code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
        code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;

        code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
        code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
        code[ComplexGeometryPositionOnlyVertexShader] = qglslComplexGeometryPositionOnlyVertexShader;
        code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
        code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
        code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader;
        code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader;
        code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader;
        code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader;
        code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader;
        code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader;
        code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader;
        code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader;

        code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO;
        code[MainFragmentShader_CM] = qglslMainFragmentShader_CM;
        code[MainFragmentShader_MO] = qglslMainFragmentShader_MO;
        code[MainFragmentShader_M] = qglslMainFragmentShader_M;
        code[MainFragmentShader_CO] = qglslMainFragmentShader_CO;
        code[MainFragmentShader_C] = qglslMainFragmentShader_C;
        code[MainFragmentShader_O] = qglslMainFragmentShader_O;
        code[MainFragmentShader] = qglslMainFragmentShader;
        code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;

        code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
        code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
        code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
        code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
        code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
        if (!context->contextHandle()->isOpenGLES())
            code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader_desktop;
        else
            code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader_ES;
        code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
        code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader;
        code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader;
        code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader;
        code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
        code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;

        code[NoMaskFragmentShader] = "";
        code[MaskFragmentShader] = qglslMaskFragmentShader;
        code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
        code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
        code[RgbMaskWithGammaFragmentShader] = ""; //###

        code[NoCompositionModeFragmentShader] = "";
        code[MultiplyCompositionModeFragmentShader] = ""; //###
        code[ScreenCompositionModeFragmentShader] = ""; //###
        code[OverlayCompositionModeFragmentShader] = ""; //###
        code[DarkenCompositionModeFragmentShader] = ""; //###
        code[LightenCompositionModeFragmentShader] = ""; //###
        code[ColorDodgeCompositionModeFragmentShader] = ""; //###
        code[ColorBurnCompositionModeFragmentShader] = ""; //###
        code[HardLightCompositionModeFragmentShader] = ""; //###
        code[SoftLightCompositionModeFragmentShader] = ""; //###
        code[DifferenceCompositionModeFragmentShader] = ""; //###
        code[ExclusionCompositionModeFragmentShader] = ""; //###

#if defined(QT_DEBUG)
        // Check that all the elements have been filled:
        for (int i = 0; i < TotalSnippetCount; ++i) {
            if (qShaderSnippets[i] == 0) {
                qFatal("Shader snippet for %s (#%d) is missing!",
                       snippetNameStr(SnippetName(i)).constData(), i);
            }
        }
#endif
        snippetsPopulated = true;
    }

    QGLShader* fragShader;
    QGLShader* vertexShader;
    QByteArray vertexSource;
    QByteArray fragSource;

    // Compile up the simple shader:
    vertexSource.append(qShaderSnippets[MainVertexShader]);
    vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);

    fragSource.append(qShaderSnippets[MainFragmentShader]);
    fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);

    simpleShaderProg = new QGLShaderProgram(context, 0);

    CachedShader simpleShaderCache(fragSource, vertexSource);

    bool inCache = simpleShaderCache.load(simpleShaderProg, context);

    if (!inCache) {
        vertexShader = new QGLShader(QGLShader::Vertex, context, 0);
        shaders.append(vertexShader);
        if (!vertexShader->compileSourceCode(vertexSource))
            qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");

        fragShader = new QGLShader(QGLShader::Fragment, context, 0);
        shaders.append(fragShader);
        if (!fragShader->compileSourceCode(fragSource))
            qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");

        simpleShaderProg->addShader(vertexShader);
        simpleShaderProg->addShader(fragShader);

        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 (simpleShaderProg->isLinked()) {
        if (!inCache)
            simpleShaderCache.store(simpleShaderProg, context);
    } else {
        qCritical("Errors linking simple shader: %s", qPrintable(simpleShaderProg->log()));
    }

    // 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 QGLShaderProgram(context, 0);

    CachedShader blitShaderCache(fragSource, vertexSource);

    inCache = blitShaderCache.load(blitShaderProg, context);

    if (!inCache) {
        vertexShader = new QGLShader(QGLShader::Vertex, context, 0);
        shaders.append(vertexShader);
        if (!vertexShader->compileSourceCode(vertexSource))
            qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");

        fragShader = new QGLShader(QGLShader::Fragment, context, 0);
        shaders.append(fragShader);
        if (!fragShader->compileSourceCode(fragSource))
            qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");

        blitShaderProg->addShader(vertexShader);
        blitShaderProg->addShader(fragShader);

        blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
        blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
    }

    blitShaderProg->link();
    if (blitShaderProg->isLinked()) {
        if (!inCache)
            blitShaderCache.store(blitShaderProg, context);
    } else {
        qCritical("Errors linking blit shader: %s", qPrintable(blitShaderProg->log()));
    }

#ifdef QT_GL_SHARED_SHADER_DEBUG
    qDebug(" -> QGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
#endif
}
コード例 #4
0
// The address returned here will only be valid until next time this function is called.
// The program is return bound.
QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
{
    for (int i = 0; i < cachedPrograms.size(); ++i) {
        QGLEngineShaderProg *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;
        }
    }

    QScopedPointer<QGLEngineShaderProg> 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;
        vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
        vertexSource.append(qShaderSnippets[prog.positionVertexShader]);

        QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram);

        CachedShader shaderCache(fragSource, vertexSource);
        bool inCache = shaderCache.load(shaderProgram.data(), QGLContext::currentContext());

        if (!inCache) {

            QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment));
            QByteArray description;
#if defined(QT_DEBUG)
            // Name the shader for easier debugging
            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));
            }
            fragShader->setObjectName(QString::fromLatin1(description));
#endif
            if (!fragShader->compileSourceCode(fragSource)) {
                qWarning() << "Warning:" << description << "failed to compile!";
                break;
            }

            QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex));
#if defined(QT_DEBUG)
            // Name the shader for easier debugging
            description.clear();
            description.append("Vertex shader: main=");
            description.append(snippetNameStr(prog.mainVertexShader));
            description.append(", position=");
            description.append(snippetNameStr(prog.positionVertexShader));
            vertexShader->setObjectName(QString::fromLatin1(description));
#endif
            if (!vertexShader->compileSourceCode(vertexSource)) {
                qWarning() << "Warning:" << description << "failed to compile!";
                break;
            }

            shaders.append(vertexShader.data());
            shaders.append(fragShader.data());
            shaderProgram->addShader(vertexShader.take());
            shaderProgram->addShader(fragShader.take());

            // 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(new QGLEngineShaderProg(prog));
        newProg->program = shaderProgram.take();

        newProg->program->link();
        if (newProg->program->isLinked()) {
            if (!inCache)
                shaderCache.store(newProg->program, QGLContext::currentContext());
        } else {
            QLatin1String none("none");
            QLatin1String br("\n");
            QString error;
            error = QLatin1String("Shader program failed to link,");
#if defined(QT_DEBUG)
            error += QLatin1String("\n  Shaders Used:\n");
            for (int i = 0; i < newProg->program->shaders().count(); ++i) {
                QGLShader *shader = newProg->program->shaders().at(i);
                error += QLatin1String("    ") + shader->objectName() + QLatin1String(": \n")
                         + QLatin1String(shader->sourceCode()) + br;
            }
#endif
            error += QLatin1String("  Error Log:\n")
                     + QLatin1String("    ") + newProg->program->log();
            qWarning() << error;
            break;
        }

        newProg->program->bind();

        if (newProg->maskFragShader != QGLEngineSharedShaders::NoMaskFragmentShader) {
            GLuint location = newProg->program->uniformLocation("maskTexture");
            newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT);
        }

        if (cachedPrograms.count() > 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.data());
    } while (false);

    return newProg.take();
}
コード例 #5
0
// The address returned here will only be valid until next time this function is called.
// The program is return bound.
QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
{
    for (int i = 0; i < cachedPrograms.size(); ++i) {
        QGLEngineShaderProg *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;
        }
    }

    QGLShader *vertexShader = 0;
    QGLShader *fragShader = 0;
    QGLEngineShaderProg *newProg = 0;
    bool success = false;

    do {
        QByteArray source;
        // 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)
            source.append(prog.customStageSource);
        source.append(qShaderSnippets[prog.mainFragShader]);
        source.append(qShaderSnippets[prog.srcPixelFragShader]);
        if (prog.compositionFragShader)
            source.append(qShaderSnippets[prog.compositionFragShader]);
        if (prog.maskFragShader)
            source.append(qShaderSnippets[prog.maskFragShader]);
        fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
        QByteArray description;
#if defined(QT_DEBUG)
        // Name the shader for easier debugging
        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));
        }
        fragShader->setObjectName(QString::fromLatin1(description));
#endif
        if (!fragShader->compileSourceCode(source)) {
            qWarning() << "Warning:" << description << "failed to compile!";
            break;
        }

        source.clear();
        source.append(qShaderSnippets[prog.mainVertexShader]);
        source.append(qShaderSnippets[prog.positionVertexShader]);
        vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
#if defined(QT_DEBUG)
        // Name the shader for easier debugging
        description.clear();
        description.append("Vertex shader: main=");
        description.append(snippetNameStr(prog.mainVertexShader));
        description.append(", position=");
        description.append(snippetNameStr(prog.positionVertexShader));
        vertexShader->setObjectName(QString::fromLatin1(description));
#endif
        if (!vertexShader->compileSourceCode(source)) {
            qWarning() << "Warning:" << description << "failed to compile!";
            break;
        }

        newProg = new QGLEngineShaderProg(prog);

        // If the shader program's not found in the cache, create it now.
        newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
        newProg->program->addShader(vertexShader);
        newProg->program->addShader(fragShader);

        // We have to bind the vertex attribute names before the program is linked:
        newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
        if (newProg->useTextureCoords)
            newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
        if (newProg->useOpacityAttribute)
            newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
        if (newProg->usePmvMatrixAttribute) {
            newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
            newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
            newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
        }

        newProg->program->link();
        if (!newProg->program->isLinked()) {
            QLatin1String none("none");
            QLatin1String br("\n");
            QString error;
            error = QLatin1String("Shader program failed to link,")
#if defined(QT_DEBUG)
                + br
                + QLatin1String("  Shaders Used:") + br
                + QLatin1String("    ") + vertexShader->objectName() + QLatin1String(": ") + br
                + QLatin1String(vertexShader->sourceCode()) + br
                + QLatin1String("    ") + fragShader->objectName() + QLatin1String(": ") + br
                + QLatin1String(fragShader->sourceCode()) + br
#endif
                + QLatin1String("  Error Log:\n")
                + QLatin1String("    ") + newProg->program->log();
            qWarning() << error;
            break;
        }

        newProg->program->bind();

        if (newProg->maskFragShader != QGLEngineSharedShaders::NoMaskFragmentShader) {
            GLuint location = newProg->program->uniformLocation("maskTexture");
            newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT);
        }

        if (cachedPrograms.count() > 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);

        success = true;
    } while (false);

    // Clean up everything if we weren't successful
    if (!success) {
        if (newProg) {
            delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
            newProg = 0;
        }
        else {
            if (vertexShader)
                delete vertexShader;
            if (fragShader)
                delete fragShader;
        }
    }

    return newProg;
}