wglShareLists fails with error 6 : ERROR_INVALID_H

2019-08-11 14:21发布

问题:

I try to share a HPBUFFERARB between two classes : TGLForm and TGLForm2. (I tried FBO but having an old Borland Builder 6 version I can't manage using FBO)

My goal is to display the same buffer in two openGL windows.

So I declared outside of the first Form this object :

struct GLRenderToTexture
{
struct
{
    HDC          hdc;
    HGLRC        hGlRc;
    HPBUFFERARB  hBuffer;
    PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
    PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
    PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
    PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
    PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB;
    PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
    PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
    PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
    PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
} wgl;
unsigned int  texture;  // the texture we're going to render to
};

GLRenderToTexture  RTT;

I intialize it so as to have the same pixel format as the first GLForm :

void __fastcall TGLForm::FormCreate(TObject *Sender)
{
    ghDC = GetDC(Handle);
    if (!bSetupPixelFormat(ghDC)) Close();
    ghRC = wglCreateContext(ghDC);
wglMakeCurrent(ghDC, ghRC);
    InitializeGL();

    int     pixelFormats;
    int     intAttrs[32] ={WGL_RED_BITS_ARB,8,WGL_GREEN_BITS_ARB,8,WGL_BLUE_BITS_ARB,8,WGL_ALPHA_BITS_ARB,8,WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,WGL_BIND_TO_TEXTURE_RGBA_ARB, GL_TRUE,WGL_SUPPORT_OPENGL_ARB,GL_TRUE,WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,WGL_DOUBLE_BUFFER_ARB,GL_FALSE,0}; // 0 terminate the list
    unsigned int numFormats = 0;
    // get an acceptable pixel format to create the PBuffer with
    if (RTT.wgl.wglChoosePixelFormatARB(ghDC, intAttrs, NULL, 1, &pixelFormats, &numFormats)==FALSE)
        AnsiString error = AnsiString().sprintf("wglChoosePixelFormatARB returned %i", GetLastError()); // GetLastError will tell us why it failed

    //Set some p-buffer attributes so that we can use this p-buffer as a 2d texture target
    const int attributes[]= {WGL_TEXTURE_FORMAT_ARB,  WGL_TEXTURE_RGBA_ARB, // p-buffer will have RBA texture format
                    WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB, 0}; // Of texture target will be GL_TEXTURE_2D
    // the size of the PBuffer must be the same size as the texture
    RTT.wgl.hBuffer= RTT.wgl.wglCreatePbufferARB(ghDC, pixelFormats, ClientWidth, ClientHeight, attributes);
    RTT.wgl.hdc= RTT.wgl.wglGetPbufferDCARB(RTT.wgl.hBuffer);
    RTT.wgl.hGlRc= wglCreateContext(RTT.wgl.hdc);

wglMakeCurrent(NULL,NULL);
}

Here is my first DrawScene : the "PaintGL()" drawing is perfectly drawn on this form :

void TGLForm::DrawSceneForm1()
{
wglMakeCurrent(ghDC, ghRC);
            ClientWidth = 1920;
            ClientHeight = 1080;

    // create a texture to use as the backbuffer
    glGenTextures(1, &RTT.texture);
    glBindTexture(GL_TEXTURE_2D, RTT.texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    // make sure this is the same color format as the screen
    glTexImage2D(GL_TEXTURE_2D, 0, 4,  ClientWidth, ClientHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);


    // switch to the texture context
wglMakeCurrent(RTT.wgl.hdc, RTT.wgl.hGlRc);
    glEnable(GL_TEXTURE_2D);              // Enable Texture Mapping
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);

    glClear(GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    glDisable(GL_TEXTURE_2D);


    // switch back to the screen context
wglMakeCurrent(ghDC, ghRC);
    wglShareLists(ghRC, RTT.wgl.hGlRc);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);

    glClear(GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, ClientWidth, ClientHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


wglMakeCurrent(RTT.wgl.hdc, RTT.wgl.hGlRc);
    glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, RTT.texture);
        PaintGL();
    glDisable(GL_TEXTURE_2D);


wglMakeCurrent(ghDC, ghRC);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, RTT.texture);
    RTT.wgl.wglBindTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);

    glBegin(GL_QUADS);
        glColor4ub(255,255,255,255);
        glTexCoord2f (0.0, 0.0); glVertex2f (-1.0, -1.0);
        glTexCoord2f (1.0, 0.0); glVertex2f (1.0, -1.0);
        glTexCoord2f (1.0, 1.0); glVertex2f (1.0, 1.0);
        glTexCoord2f (0.0, 1.0); glVertex2f (-1.0, 1.0);
    glEnd();

    RTT.wgl.wglReleaseTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);
    glDisable(GL_TEXTURE_2D);

glFlush();
SwapBuffers(ghDC);

wglMakeCurrent(NULL,NULL);
}

And here is my second GLForm's DrawScene : the problem is that I only see the colored quad but this QUAD is not textured, or the texture is empty :

void TGLForm2::DrawSceneForm2()
{
wglMakeCurrent(ghDC2, ghRC2);
    ClientWidth = 1920;
    ClientHeight = 1080;

    wglShareLists(RTT.wgl.hGlRc, ghRC2);
    if (wglShareLists(RTT.wgl.hGlRc,ghRC2) == FALSE)
        SCmsgError(AnsiString().sprintf("wglShareLists returned %i", GetLastError()));

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE); //ARC

    glClear(GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, ClientWidth, ClientHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, RTT.texture);
    RTT.wgl.wglBindTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);

    glBegin(GL_QUADS);
        glColor4ub(200,200,200,200);
        glTexCoord2f (0.0, 0.0); glVertex2f (-1.0, -1.0);
        glTexCoord2f (1.0, 0.0); glVertex2f (1.0, -1.0);
        glTexCoord2f (1.0, 1.0); glVertex2f (1.0, 1.0);
        glTexCoord2f (0.0, 1.0); glVertex2f (-1.0, 1.0);
    glEnd();

    RTT.wgl.wglReleaseTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);
    glDisable(GL_TEXTURE_2D);

    glFlush();
    SwapBuffers(ghDC);
}

=> How may I check if this texture is empty or not ?

export it to a bitmap and check it ?

=> the wglShareLists in the DrawSceneForm2 returns an error with GetLastError :

Error 6 : ERROR_INVALID_HANDLE The handle is invalid.

=> Does somebody see what is wrong in this wglShareList or in my code ?

回答1:

When calling wglShareLists, the context must not be current. Preferrably share before you do anything else. Sharing contexts will share anything created thereafter just fine. The best thing is to create all contexts that need to be shared at startup. If you use WGL_ARB_create_context, then you can even do this atomically within the creation call.

If you can't for some reason (though, why?) then wglMakeCurrent(0,0); first (you do the opposite in your code, you make the context current just before sharing).



回答2:

I had a similar problem where :

wglShareLists returns 0

GetLastError() returns 3221684311 (0xc0070057)

It turns out you cant do much with the hglrc2 (2nd parameter passed into wglShareLists) before you call wglShareLists. In my case I created, and glUseProgram a shader, and then tried wglShareLists resulting in the errors shown above. Moving wglShareLists to immediately after wglCreateContext(hDC) of 2nd RC worked. I was able to share textures across the 2 contexts.