zl程序教程

您现在的位置是:首页 >  其它

当前栏目

qtav shader处理

处理 Shader
2023-09-27 14:21:18 时间

链接shader,标准opengl shader处理过程

bool VideoShader::build(QOpenGLShaderProgram *shaderProgram)
{
     if (shaderProgram->isLinked()) {
         qWarning("Shader program is already linked");
     }
     shaderProgram->removeAllShaders();
     shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader());
     shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader());

。。。

}


vertexShader这里把模板shaders/video.vert"));, 替换掉里面的 %userHeader%*,

const char* VideoShader::vertexShader() const
{
     DPTR_D(const VideoShader);
     // because we have to modify the shader, and shader source must be kept, so read the origin
     d.vert = shaderSourceFromFile(QStringLiteral("shaders/video.vert"));
     QByteArray& vert = d.vert;
     if (vert.isEmpty()) {
         qWarning("Empty vertex shader!");
         return 0;
     }
     if (textureTarget() == GL_TEXTURE_RECTANGLE && d.video_format.isPlanar()) {
         vert.prepend("#define MULTI_COORD\n");
#if YUVA_DONE
         if (d.video_format.hasAlpha())
             vert.prepend("#define HAS_ALPHA\n");
#endif
     }
     vert.prepend(OpenGLHelper::compatibleShaderHeader(QOpenGLShader::Vertex));

    if (userShaderHeader(QOpenGLShader::Vertex)) {
         QByteArray header("*/");
         header.append(userShaderHeader(QOpenGLShader::Vertex));
         header += "/*";
         vert.replace("%userHeader%", header);
     }

#ifdef QTAV_DEBUG_GLSL
     QString s(vert);
     s = OpenGLHelper::removeComments(s);
     qDebug() << s.toUtf8().constData();
#endif //QTAV_DEBUG_GLSL
     return vert.constData();
}

fragmentShader 这里把模板shaders/planar.f.glsl, 替换掉里面的 %userHeader%*, %userSample% 和 %userPostProcess% 部分内容

const char* VideoShader::fragmentShader() const
{
     DPTR_D(const VideoShader);
     // because we have to modify the shader, and shader source must be kept, so read the origin
     if (d.video_format.isPlanar()) {
         d.planar_frag = shaderSourceFromFile(QStringLiteral("shaders/planar.f.glsl"));
     } else {
         d.packed_frag = shaderSourceFromFile(QStringLiteral("shaders/packed.f.glsl"));
     }
     QByteArray& frag = d.video_format.isPlanar() ? d.planar_frag : d.packed_frag;
     if (frag.isEmpty()) {
         qWarning("Empty fragment shader!");
         return 0;
     }
     const int nb_planes = d.video_format.planeCount();
     if (nb_planes == 2) //TODO: nv21 must be swapped
         frag.prepend("#define IS_BIPLANE\n");
     if (OpenGLHelper::hasRG() && !OpenGLHelper::useDeprecatedFormats())
         frag.prepend("#define USE_RG\n");
     const bool has_alpha = d.video_format.hasAlpha();
     if (d.video_format.isPlanar()) {
         const int bpc = d.video_format.bitsPerComponent();
         if (bpc > 8) {
             //// has and use 16 bit texture (r16 for example): If channel depth is 16 bit, no range convertion required. Otherwise, must convert to color.r*(2^16-1)/(2^bpc-1)
             if (OpenGLHelper::depth16BitTexture() < 16 || !OpenGLHelper::has16BitTexture() || d.video_format.isBigEndian())
                 frag.prepend("#define CHANNEL16_TO8\n");
         }
#if YUVA_DONE
         if (has_alpha)
             frag.prepend("#define HAS_ALPHA\n");
#endif
     } else {
         if (has_alpha)
             frag.prepend("#define HAS_ALPHA\n");
         if (d.video_format.isXYZ())
             frag.prepend("#define XYZ_GAMMA\n");
     }

    if (d.texture_target == GL_TEXTURE_RECTANGLE) {
         frag.prepend("#extension GL_ARB_texture_rectangle : enable\n"
                      "#define sampler2D sampler2DRect\n");
         if (OpenGLHelper::GLSLVersion() < 140)
             frag.prepend("#undef texture\n"
                         "#define texture texture2DRect\n"
                         );
         frag.prepend("#define MULTI_COORD\n");
     }
     frag.prepend(OpenGLHelper::compatibleShaderHeader(QOpenGLShader::Fragment));

    QByteArray header("*/");
     if (userShaderHeader(QOpenGLShader::Fragment))
         header += QByteArray(userShaderHeader(QOpenGLShader::Fragment));
     header += "\n";
     header += "uniform vec2 u_texelSize[" + QByteArray::number(nb_planes) + "];\n";
     header += "uniform vec2 u_textureSize[" + QByteArray::number(nb_planes) + "];\n";
     header += "/*";
     frag.replace("%userHeader%", header);

    if (userSample()) {
         QByteArray sample_code("*/\n#define USER_SAMPLER\n");
         sample_code += QByteArray(userSample());
         sample_code += "/*";
         frag.replace("%userSample%", sample_code);
     }

    if (userPostProcess()) {
         QByteArray pp_code("*/");
         pp_code += QByteArray(userPostProcess()); //why the content is wrong sometimes if no ctor?
         pp_code += "/*";
        frag.replace("%userPostProcess%", pp_code);
     }
     frag.replace("%planes%", QByteArray::number(nb_planes));
#ifdef QTAV_DEBUG_GLSL
     QString s(frag);
     s = OpenGLHelper::removeComments(s);
     qDebug() << s.toUtf8().constData();
#endif //QTAV_DEBUG_GLSL
     return frag.constData();//返回组装好的frag
}


VideoShader 里面可以定制的部分:

/// User configurable shader APIs BEGIN
/*!
  * Keywords will be replaced in user shader code:
  * %planes% => plane count
  * Uniforms can be used: (N: 0 ~ planes-1)
  * u_Matrix (vertex shader),
  * u_TextureN, v_TexCoordsN, u_texelSize(array of vec2, normalized), u_textureSize(array of vec2), u_opacity, u_c(channel map), u_colorMatrix, u_to8(vec2, computing 16bit value with 8bit components)
  * Vertex shader in: a_Position, a_TexCoordsN (see attributeNames())
  * Vertex shader out: v_TexCoordsN
  */
/*!
  * \brief userShaderHeader
  * Must add additional uniform declarations here
  */
virtual const char* userShaderHeader(QOpenGLShader::ShaderType) const {return 0;}
/*!
  * \brief setUserUniformValues
  * Call program()->setUniformValue(...) here
  * You can upload a texture for blending in userPostProcess(),
  * or LUT texture used by userSample() or userPostProcess() etc.
  * \return false if use use setUserUniformValue(Uniform& u), true if call program()->setUniformValue() here
  */
virtual bool setUserUniformValues() {return false;}
/*!
  * \brief setUserUniformValue
  * Update value of uniform u. Call Uniform.set(const T& value, int count); VideoShader will call Uniform.setGL() later if value is changed
  */
virtual void setUserUniformValue(Uniform&) {}
/*!
  * \brief userSample
  * Fragment shader only. The custom sampling function to replace texture2D()/texture() (replace %1 in shader).
  * \code
  *     vec4 sample2d(sampler2D tex, vec2 pos, int plane) { .... }
  * \endcode
  * The 3rd parameter can be used to get texel/texture size of a given plane u_texelSize[plane]/textureSize[plane];
  * Convolution of result rgb and kernel has the same effect as convolution of input yuv and kernel, ensured by
  * Σ_i c_i* Σ_j k_j*x_j=Σ_i k_i* Σ_j c_j*x_j
  * Because because the input yuv is from a real rgb color, so no clamp() is required for the transformed color.
  */
virtual const char* userSample() const { return 0;}
/*!
  * \brief userPostProcess
  * Fragment shader only. Process rgb color
  * TODO: parameter ShaderType?
  */
virtual const char* userPostProcess() const {return 0;}
/// User configurable shader APIs END