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

时间:2016-03-20 19:51:45

标签: android opengl-es opengl-es-2.0 fragment-shader

我在iOS上制作了一个简单的Open GLES 2.0着色器,它可以毫无问题地工作,现在我试图在Android(5.1)上使用最新的NDK 10e编译GLES 3.0。但现在我得到一个全白色输出或非常奇怪的颜色。

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

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

在附带的代码中,我创建了一个不会对颜色做任何事情的查找表。注释这个for循环应该只给出黑色,因为上面的memset但仍然是白色或非常奇怪的颜色。

具有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;
}

1 个答案:

答案 0 :(得分:1)

您使用的采样器制服是错误的。以下代码片段您打算执行的操作:

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 ...