Bug: Texture is not updated through a texture view under certain circumstances

System: Linux (Fedora 30)
Driver: NVIDIA 430.40
GPU: GeForce GTX 1080 Mobile

The following program reproduce the problem. There is a texture view created and attached to the framebuffer. Then clear is executed, the value is read back from original texture (not from the view, which is important), and we get the expected color used for clear. Now when we do the same again with a different clear color, we don’t get the expected color back, the underlying texture exposed to framebuffer through the view seems to be not updated. There are various tweaks which can change this behaviour and make the texture updated. E. g., if we change line 104 to ‘glBindTexture(GL_TEXTURE_2D, view1);’, that is, first time read the data from the view instead of original texture, the test works as expected. Another work around is to remove glGetTexImage() at line 105, then the next one on line 120 gets the correct color. The test also succeeds if I attach texture texture itself instead of texture view to the framebuffer (replace line 84 with ‘glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);’).

The original case from which the problem originates are the tests in Wine project (d3d11 test suite). Some tests are failing for me with proprietary Nvidia driver. I managed to extract this short GL test case which reproduces the problem.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define GL_GLEXT_PROTOTYPES
#include<X11/X.h>
#include<X11/Xlib.h>
#include<GL/gl.h>
#include<GL/glx.h>
#include <GL/glext.h>
#include <math.h>


const char *debug_glerror(GLenum error) {
    switch(error) {
#define GLERROR_TO_STR(u) case u: return #u
        GLERROR_TO_STR(GL_NO_ERROR);
        GLERROR_TO_STR(GL_INVALID_ENUM);
        GLERROR_TO_STR(GL_INVALID_VALUE);
        GLERROR_TO_STR(GL_INVALID_OPERATION);
        GLERROR_TO_STR(GL_STACK_OVERFLOW);
        GLERROR_TO_STR(GL_STACK_UNDERFLOW);
        GLERROR_TO_STR(GL_OUT_OF_MEMORY);
        GLERROR_TO_STR(GL_INVALID_FRAMEBUFFER_OPERATION);
#undef GLERROR_TO_STR
        default:
            fprintf(stderr, "Unrecognized GL error 0x%08x.\n", error);
            return "unrecognized";
    }
}

void check_gl_call(const char *file, unsigned int line, const char *name)
{
    GLint err;

    if ((err = glGetError()) == GL_NO_ERROR)
        return;

    do
    {
        fprintf(stderr, ">>>>>>> %s (%#x) from %s @ %s / %u.\n",
                debug_glerror(err), err, name, file,line);
        err = glGetError();
    } while (err != GL_NO_ERROR);
}

#define checkGLcall(A) check_gl_call(__FILE__, __LINE__, A)

int main(int argc, char *argv[])
{
    static int attrib_list[] = {GLX_RGBA,  GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
    XSetWindowAttributes swa;
    GLuint tex, view1, fbo;
    unsigned int buf[1024];
    Window root, win;
    XVisualInfo *vi;
    GLXContext glc;
    Colormap cmap;
    Display *dpy;

    dpy = XOpenDisplay(NULL);
    vi = glXChooseVisual(dpy, 0, attrib_list);
    root = DefaultRootWindow(dpy);
    cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

    swa.colormap = cmap;
    swa.event_mask = ExposureMask | KeyPressMask;
    win = XCreateWindow(dpy, root, 0, 0, 640, 480, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    XMapWindow(dpy, win);
    XStoreName(dpy, win, "Rendering to texture view test");
    glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    glXMakeCurrent(dpy, win, glc);

    glDisable(GL_DEPTH_TEST);

    glGenFramebuffers(1, &fbo);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 8, 8);
    checkGLcall("glTexStorage2D");

    glGenTextures(1, &view1);
    glTextureView(view1, GL_TEXTURE_2D, tex, GL_SRGB8_ALPHA8, 0, 1, 0, 1);
    checkGLcall("glTextureView");

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    checkGLcall("glBindFramebuffer");

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, view1, 0);
    checkGLcall("glFramebufferTexture2D");

    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        puts("Frame buffer is not complete.\n");

    glDrawBuffer(GL_COLOR_ATTACHMENT0);
    checkGLcall("glDrawBuffer");

    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    checkGLcall("glClear");
    glFinish();
    checkGLcall("glFinish");
    memset(buf, 0, sizeof(buf));
    glBindTexture(GL_TEXTURE_2D, tex);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
    checkGLcall("glGetTexImage");
    printf("buf[0] %#x (expected 0xff0000ff).\n", buf[0]);
    glFinish();

    glDrawBuffer(GL_COLOR_ATTACHMENT0);
    checkGLcall("glDrawBuffer");

    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    checkGLcall("glClear");
    glFinish();
    checkGLcall("glFinish");
    memset(buf, 0, sizeof(buf));
    glBindTexture(GL_TEXTURE_2D, tex);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
    checkGLcall("glGetTexImage");
    printf("buf[0] %#x (expected 0xff00ff00).\n", buf[0]);
    return 0;
}

I also checked this, I also encountered with same problem of texture. i don’t know about this. but integral calculator might help you to solve the problem of cumbersome calculations.