GLES Shader Lookup 产生全白或奇怪的颜色

GLES Shader Lookup produces all white or strange colors

我已经在 iOS 上制作了一个简单的 Open GLES 2.0 着色器,它可以正常工作,现在我正尝试在 Android (5.1) 上对 GLES 3.0 做同样的事情,使用最新的编译NDK 10e。但现在我得到全白输出或非常奇怪的颜色。

想法是查找 table 作为 2D 纹理传入,实际图像的颜色指向查找纹理中第 0.0 行的不同 x 坐标。我将查找纹理设置为 256x256 以避免它太小而不是 256x1 的问题。

验证片段着色器我将输入图像的颜色输出到左侧,它们正确显示,但右侧全是白色或颜色非常错误,具体取决于输入图像。我认为不是问题的一个问题是溢出,因为我没有限制这些值。我不这样做是在 iOS 中,texture() 采样器应该 return 0.0 <= value <= 1.0

在附加的代码中,我进行了查找 table,不会对颜色做任何事情。由于上面的 memset,评论这个 for loop out 应该只给出黑色,但仍然是白色或非常奇怪的颜色。

配备 ARM Mali 和 Qualcomm Adreno GPU 的两种设备都表现出相同的行为,代码执行时没有任何运行时片段编译或 GL 错误。 Android 5 或 6 也显示相同的错误。

现在我觉得我已经用尽了所有的选择,希望有人能指出我的错误

从 gl 设置附加的完整代码,程序编译到 gl 关闭,带有片段

static const char gVertexShader[] =
        "#version 300 es\n"
                "in vec4 vPosition;\n"
                "in vec4 inputTextureCoordinate;\n"
                "out vec2 texPosition;\n"
                "void main() {\n"
                "  gl_Position = vPosition;\n"
                "  texPosition = inputTextureCoordinate.xy;\n"
                "}\n";



static const char gFragmentShader[] =
        "#version 300 es\n"
        "layout(location = 0) out mediump vec4 color_frag_out;\n"
        "precision mediump float;\n"
        "in vec2 texPosition;\n"
        "uniform sampler2D lookupTex;\n"
        "uniform sampler2D rgbaTex;\n"
        "void main() {\n"
            "vec4 rgbaColor = texture(rgbaTex, texPosition);\n"
            "float redlookup   = texture(lookupTex, vec2(rgbaColor.r, 0.0)).b;\n"
            "float greenlookup = texture(lookupTex, vec2(rgbaColor.g, 0.0)).g;\n"
            "float bluelookup  = texture(lookupTex, vec2(rgbaColor.b, 0.0)).r;\n"
            "if (texPosition.x > 0.5) {\n"
                "color_frag_out = vec4(redlookup, greenlookup, bluelookup, 1.0);\n"
            "} else {\n"
                "color_frag_out = rgbaColor;\n"
            "}\n"

        "}\n";

void start_frag_test(char* rgbaIn, char* rgbaOut, int w, int h)
{

    EGLConfig eglConf;
    EGLSurface eglSurface;
    EGLContext eglCtx;
    EGLDisplay eglDisp;
    GLuint fboTexId;
    GLint fboId;
    GLuint gProgram;
    GLuint gvPositionHandle;
    GLint textureLocations[2];
    GLuint textureIds[2];
    GLint textCoordLoc = -10;
    char* lookuptable = 0;
    int lookuptableWidth = 256;
    int lookuptableHeight = 256;

    /// Init GL

    // EGL config attributes
    const EGLint confAttr[] = {
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,    // very important!
            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,          // we will create a pixelbuffer surface
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_ALPHA_SIZE, 8,     // if you need the alpha channel
            /*  EGL_DEPTH_SIZE, 16,    // if you need the depth buffer */
            EGL_NONE
    };

    // EGL context attributes
    const EGLint ctxAttr[] = {
            EGL_CONTEXT_CLIENT_VERSION, 3,              // very important!
            EGL_NONE
    };

    // surface attributes
    // the surface size is set to the input frame size
    const EGLint surfaceAttr[] = {
            EGL_WIDTH, w,
            EGL_HEIGHT, h,
            EGL_NONE
    };

    EGLint eglMajVers, eglMinVers;
    EGLint numConfigs;


    eglDisp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(eglDisp, &eglMajVers, &eglMinVers);

    MY_LOGI("EGL init with version %d.%d", eglMajVers, eglMinVers);

    // choose the first config, i.e. best config
    eglChooseConfig(eglDisp, confAttr, &eglConf, 1, &numConfigs);

    eglCtx = eglCreateContext(eglDisp, eglConf, EGL_NO_CONTEXT, ctxAttr);

    // create a pixelbuffer surface
    eglSurface = eglCreatePbufferSurface(eglDisp, eglConf, surfaceAttr);

    eglMakeCurrent(eglDisp, eglSurface, eglSurface, eglCtx);

    // Print GL info
    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);

    gProgram = createShaderProgram(gVertexShader, gFragmentShader);
    if (!gProgram) {
        MY_LOGE("Could not create program.");
        return;
    }
    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
    checkGlError("glGetAttribLocation");

    // Generate Frambuffer
    glGenFramebuffers(1, &fboId);
    checkGlError("glGenFramebuffers");

    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    checkGlError("glBindFramebuffer");

    // Now generate COLOR ATTACHMENT TEXTURE to use as output in fragment shader
    glGenTextures (1, &fboTexId);
    glBindTexture(GL_TEXTURE_2D, fboTexId);
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                           GL_TEXTURE_2D, fboTexId, 0);
    checkGlError("glFramebufferTexture2D");

    // Assign a drawbuffer the FBO
    GLenum drawBuffers [1] = {GL_COLOR_ATTACHMENT0};
    glDrawBuffers(1, drawBuffers);
    checkGlError("glDrawBuffers");

    // Clears color to none white
    glClearColor(.0f, 0.9f, .0f, .0f);

    glUseProgram(gProgram);
    checkGlError("glUseProgram");
    glViewport(0, 0, w, h);
    checkGlError("glViewport");

    glGenTextures(2, &textureIds);
    textureLocations[0] = glGetUniformLocation(gProgram, "rgbaTex");
    textureLocations[1] = glGetUniformLocation(gProgram, "lookupTex");

    // Bind texture with image data
    glActiveTexture(GL_TEXTURE0 + textureLocations[0]);
    checkGlError("glActiveTexture");
    glBindTexture(GL_TEXTURE_2D, textureIds[0]);    // bind input texture
    checkGlError("glBindTexture 0");
    MY_LOGI("rgbain id:%d loc:%d w:%d h:%d", textureIds[0], textureLocations[0], w, h);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbaIn);
    checkGlError("glTexImage2D");

    // Bind texture with lookup data
    int lookupTableSize = lookuptableWidth * lookuptableHeight * 4;
    MY_LOGI("Lookup table size:%d", lookupTableSize);
    lookuptable = malloc(lookupTableSize);
    memset(lookuptable, 0,lookupTableSize); // Make sure all are 0
    unsigned int lookupvalue = 0;
    int i;
    // Fill table with 0 to 255 for all color channels
    // With this for loop commented out the lookup table should represent all black
    // from the memset above. But output is still white.
    for (i = 0; i < lookuptableWidth*4; i+=4)
    {
        lookuptable[i]   = lookupvalue; // R
        lookuptable[i+1] = lookupvalue; // G
        lookuptable[i+2] = lookupvalue; // B
        lookuptable[i+3] = 255;         // A
        lookupvalue++;
    }

    glActiveTexture(GL_TEXTURE0 + textureLocations[1]);
    checkGlError("glActiveTexture");
    glBindTexture(GL_TEXTURE_2D, textureIds[1]);    // bind input texture
    checkGlError("glBindTexture 0");
    MY_LOGI("lookup id:%d loc:%d w:%d h:%d", textureIds[1], textureLocations[1], w, h);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, lookuptable);
    checkGlError("glTexImage2D");

    textCoordLoc = glGetAttribLocation(gProgram, "inputTextureCoordinate");

    glVertexAttribPointer( gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, screenVertices);
    glEnableVertexAttribArray( gvPositionHandle );
    glVertexAttribPointer( textCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, texVertices );
    glEnableVertexAttribArray( textCoordLoc );

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    checkGlError("glDrawArrays");

    glFinish();
    checkGlError("glFinish");

    glReadBuffer(GL_COLOR_ATTACHMENT0);
    checkGlError("glReadBuffer");
    glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaOut);
    checkGlError("glDrawArrays");

    if (!eglMakeCurrent(eglDisp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
    {
        MY_LOGE("eglMakeCurrent failed");
    }
    MY_LOGI("eglMakeCurrent");
    eglDestroyContext(eglDisp, eglCtx);
    MY_LOGI("eglDestroyContext");
    eglDestroySurface(eglDisp, eglSurface);
    MY_LOGI("eglDestroySurface");
    //eglReleaseThread();

    eglTerminate(eglDisp);
    MY_LOGI("eglTerminate");

    eglDisp = EGL_NO_DISPLAY;
    eglSurface = EGL_NO_SURFACE;
    eglCtx = EGL_NO_CONTEXT;

    free(lookuptable);
}

const GLfloat screenVertices[] = {
        -1.0f,  1.0f, // top left
        1.0f,  1.0f, // top right
        -1.0f, -1.0f, // bottom left
        1.0f, -1.0f // bottom right
};

static const float texVertices[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,

};

static void checkGlError(const char* op)
{
    GLint error;
    for (error = glGetError(); error; error = glGetError())
    {
        MY_LOGE("after %s() glError (0x%x)\n", op, error);
    }
}

static void printGLString(const char *name, GLenum s) {
    const char *v = (const char *) glGetString(s);
    MY_LOGI("GL %s = %s\n", name, v);
}

GLuint loadShaderFromString(GLenum shaderType, const char* pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        glShaderSource(shader, 1, &pSource, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    MY_LOGE("Could not compile shader %d:\n%s\n",
                             shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createShaderProgram(const char* pVertexSource, const char* pFragmentSource) {
    GLuint vertexShader = loadShaderFromString(GL_VERTEX_SHADER, pVertexSource);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = loadShaderFromString(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!pixelShader) {
        return 0;
    }

    GLuint program = glCreateProgram();
    if (program) {
        glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    MY_LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

你对采样器制服的使用是错误的。以下代码片段不是您想要它做的事情:

glGenTextures(2, &textureIds);
textureLocations[0] = glGetUniformLocation(gProgram, "rgbaTex");
textureLocations[1] = glGetUniformLocation(gProgram, "lookupTex");

// Bind texture with image data
glActiveTexture(GL_TEXTURE0 + textureLocations[0]);

不得使用统一位置作为纹理单元。 GLSL 中的 sampler* 数据类型表示必须设置为纹理单元索引的不透明句柄。默认情况下,所有制服都初始化为零,因此任何 sampler 将从绑定到纹理单元 GL_TEXTURE0 的纹理中采样。如果你想使用多纹理,你必须手动设置采样器的那些统一值,以匹配你想使用的纹理单元。所以你的代码应该是这样的:

// after the shader program was linked
textureLocations[0] = glGetUniformLocation(gProgram, "rgbaTex");
textureLocations[1] = glGetUniformLocation(gProgram, 

glUseProgram(your_program);
glUniform1i(textureLocations[0], 0); // sample unit 0 for rgba Texture
glUniform1i(textureLocations[1], 1); // sample unit 1 for the LUT

//  create the textures
glGenTextures(2, &textureIds);
// it doesn't matter which unit you use to create the texture objects
// ...


// at draw time: bind all the necessary textures
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(..., textureIs[0]);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(..., textureIs[1]);

// issue the draw call ...