Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: GLFW Framebuffer Code Works, WGL Code Fails On glBlitFramebuffer()

  1. #1
    Intern Contributor
    Join Date
    Jan 2017
    Posts
    54

    GLFW Framebuffer Code Works, WGL Code Fails On glBlitFramebuffer()

    Hi Folks:

    I've enjoyed Joey DeVries amazing Learn OpenGL tutorials, but I've been hung on the "Off-screen MSAA" section of this lesson.

    I'm applying these lessons to a Blender model I've made. His examples are GLFW oriented. I'm developing for Windows right now so I've been rendering my model with code from the samples, altered to use WGL.

    This particular tutorial involves the use of anti aliasing when using a frame buffer.

    I can get the GLFW code from the sample to work fine. My sample using WGL blows up after rendering the image to the buffer, in the glBlitFramebuffer() call. I bracketed that statement with glGetError() calls.

    I can separate the GLFW code from the example into a setup portion, called from the Windows message loop's WM_CREATE clause and the sample's game loop code called from code that services the message loop's WM_TIMER message. This works too, as long as I'm using GLFW.

    I comment out the following GLFW code from the function that sets up OpenGL:
    Code :
        // Init GLFW
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
     
        window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed
        glfwMakeContextCurrent(window);
     
        // Set the required callback functions
        glfwSetKeyCallback(window, key_callback);
        glfwSetCursorPosCallback(window, mouse_callback);
        glfwSetScrollCallback(window, scroll_callback);
     
        // Options
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    These statements are replaced by a call WGL setup functions I lifted from this tutorial.

    These WGL setup functions have been working for a few of my versions of the tutorial's sample code.

    As I use this WGL startup code, I've found that I've needed to add things to the context attributes, like WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, as I work through the tutorials.

    Here is the game loop code, mostly a straight lift from the tutorial's samples. A few lines of GLFW code are commented out, replaced with WGL code.

    Code :
    void loop_from_tutorial_with_wgl(HWND hdlg, GRAPHICS_PARAMETER *graphics_parameter_ptr)
    {
    #if 0
        // Set frame time
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
    #endif
     
        // Check and call events
        // glfwPollEvents();
        // Do_Movement();      
     
        // 1. Draw scene as normal in multisampled buffers
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);   
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        // Set transformation matrices        
        shader_ptr->Use();
     
        glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)screenWidth/(GLfloat)screenHeight, 0.1f, 1000.0f);
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "view"), 1, GL_FALSE, glm::value_ptr(camera.GetViewMatrix()));    
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "model"), 1, GL_FALSE, glm::value_ptr(glm::mat4()));
     
        glBindVertexArray(cubeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
     
        glBindVertexArray(0);
     
        // 2. Now blit multisampled buffer(s) to default framebuffers
        glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);                
     
        // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
     
        glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); 
     
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     
        // Swap the buffers
        //  glfwSwapBuffers(window);
        SwapBuffers(graphics_parameter_ptr->get_hdc());
    }
     
    GLuint generateMultiSampleTexture(GLuint samples)
    {
        GLuint texture;
        glGenTextures(1, &texture);
     
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
        glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, screenWidth, screenHeight, GL_TRUE);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
     
        return texture; 
    }

    I can start flooding this thread with many lines of code. Perhaps someone can see something I'm overlooking before that happens.

    Thanks
    Larry
    Last edited by Dark Photon; 05-23-2017 at 05:48 AM.

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,123
    Quote Originally Posted by larryl View Post
    ...I've been hung on the "Off-screen MSAA" section of this lesson. ...altered to use WGL.

    This particular tutorial involves the use of anti aliasing when using a frame buffer. I can get the GLFW code from the sample to work fine. My sample using WGL blows up after rendering the image to the buffer, in the glBlitFramebuffer() call. I bracketed that statement with glGetError() calls.
    What GL error is being thrown? GL_INVALID_OPERATION?

    Though you do show the texture used for the off-screen FBO, you don't really show the code for creating your two framebuffers (the system framebuffer and your off-screen framebuffer), I think the key lies there. Let's see your WGL framebuffer and off-screen FBO setup.

    I suspect what you want is to have your source (off-screen) framebuffer to be multisampled and your destination (WGL system) framebuffer to be single-sampled. If both are multisampled, and the number of samples is different between them, that is one reason why glBlitFramebuffer could throw an error.

    Also on your glTexImage2DMultisample() call... GL_RGB is not a specific internal format. Consider using GL_RGB8 or GL_RGBA8. For more on this, see:

    * Common Mistakes#Image precision (OpenGL wiki)
    Last edited by Dark Photon; 05-23-2017 at 05:44 AM.

  3. #3
    Intern Contributor
    Join Date
    Jan 2017
    Posts
    54
    Thanks Again Dark Photon:

    Quote Originally Posted by Dark Photon View Post
    What GL error is being thrown? GL_INVALID_OPERATION?
    Yes, GL_INVALID_OPERATION.

    Quote Originally Posted by Dark Photon View Post
    Though you do show the texture used for the off-screen FBO, you don't really show the code for creating your two framebuffers (the system framebuffer and your off-screen framebuffer), I think the key lies there. Let's see your WGL framebuffer and off-screen FBO setup.
    Oh yea, leaving the buffer creation out of the post wasn't smart.

    I don't usually slavishly copy and paste code from tutorials when trying to learn something. I was doing that here in order to isolate that elusive difference that broke the WGL version of the code.

    This was cut and pasted from the sample code and inserted at the end of the OpenGL setup function, for both the GLFW and the WGL code:

    Code :
        // Framebuffers
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);  
        // Create a multisampled color attachment texture
        GLuint textureColorBufferMultiSampled = generateMultiSampleTexture(4);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
        // Create a renderbuffer object for depth and stencil attachments
        GLuint rbo;
        glGenRenderbuffers(1, &rbo);
        glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); 
        glBindRenderbuffer(GL_RENDERBUFFER, 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); 
     
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

    Here is generateMultiSampleTexture(), called from the code above:

    Code :
    GLuint generateMultiSampleTexture(GLuint samples)
    {
        GLuint texture;
        glGenTextures(1, &texture);
     
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
        glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, screenWidth, screenHeight, GL_TRUE);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
     
        return texture;
    }

    Quote Originally Posted by Dark Photon View Post
    I suspect what you want is to have your source (off-screen) framebuffer to be multisampled and your destination (WGL system) framebuffer to be single-sampled. If both are multisampled, and the number of samples is different between them, that is one reason why glBlitFramebuffer could throw an error.
    It looks like both buffers are doing four points of multi sampling.

    Quote Originally Posted by Dark Photon View Post
    Also on your glTexImage2DMultisample() call... GL_RGB is not a specific internal format. Consider using GL_RGB8 or GL_RGBA8. For more on this, see:

    * Common Mistakes#Image precision (OpenGL wiki)
    Attempts to pass GL_RGB8 and GL_RGBA8 to glTexImage2DMultisample() didn't seem to have any effect.

    Thanks for your suggestions.

    Larry

  4. #4
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,123
    Quote Originally Posted by larryl View Post
    This was cut and pasted from the sample code and inserted at the end of the OpenGL setup function, for both the GLFW and the WGL code:
    Ok, now how about the creation of your system framebuffer (e.g. WGL window)?

    It looks like both buffers are doing four points of multi sampling.
    That's fine. The buffers in a framebuffer should have the same sampling rate. What I was referrering to was the number of samples in your source framebuffer (your FBO) and your destination framebuffer (e.g. WGL window).

  5. #5
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    417
    thte usual way to approch it is:
    -- find out what function call provokes an error
    -- find out why that function has thrown that error by reading the registy description of that function

    example:
    Code :
    if (glGetError() != GL_NO_ERROR)
    {
    std::cout << "uuuppss! GL error occured before line " << __LINE__ << std::endl;
    std::cin.get(); /* just stop the app */
    }

    past this piece of code at several locations in your code, until you know what function has thrown the error. then click here, find that function: https://www.khronos.org/registry/OpenGL-Refpages/gl4/
    each function description has a "Errors" section, there you can find out why that type of GL_ERROR was thrown. if it was GHL_INVALID_OPERATION and glBlitFramebuffer() has thrown it:
    Quote Originally Posted by OpenGL ref pages
    GL_INVALID_OPERATION is generated by BlitNamedFramebuffer if readFramebuffer or drawFramebuffer is not zero or the name of an existing framebuffer object.

    GL_INVALID_OPERATION is generated if mask contains any of the GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT and filter is not GL_NEAREST.

    GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT and any of the following conditions hold:

    The read buffer contains fixed-point or floating-point values and any draw buffer contains neither fixed-point nor floating-point values.

    The read buffer contains unsigned integer values and any draw buffer does not contain unsigned integer values.

    The read buffer contains signed integer values and any draw buffer does not contain signed integer values.

    GL_INVALID_OPERATION is generated if mask contains GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT and the source and destination depth and stencil formats do not match.

    GL_INVALID_OPERATION is generated if filter is GL_LINEAR and the read buffer contains integer data.

    GL_INVALID_OPERATION is generated if the effective value of GL_SAMPLES for the read and draw framebuffers is not identical.

    GL_INVALID_OPERATION is generated if the value of GL_SAMPLE_BUFFERS for both read and draw buffers is greater than zero and the dimensions of the source and destination rectangles is not identical.

    GL_INVALID_FRAMEBUFFER_OPERATION is generated if the specified read and draw framebuffers are not framebuffer complete.
    one reason, (for example) could be that the "samples count" of the default framebuffer and your FBOs drawbuffer dont match

  6. #6
    Intern Contributor
    Join Date
    Jan 2017
    Posts
    54
    Thanks again Dark Photon:

    Quote Originally Posted by Dark Photon View Post
    Ok, now how about the creation of your system framebuffer (e.g. WGL window)?
    This is my prime suspect.

    As I stated in this thread's original post, the code in my init_opengl() was lifted from this tutorial. I'd read about the need to create a fake window to initialize GLEW before creating the context used by the application. It got me started and I'm grateful for the way it laid out the issues.

    I don't have a solid understanding of the pixel format and context attributes. I've needed to alter the context attributes.

    Here's the OpenGL initialization code:

    Code :
    #include "stdafx.h"
     
    #include <windows.h>
    #include <iostream>
     
    // GLEW
    #define GLEW_STATIC
    #include <GL/glew.h>
    #include <GL/wglew.h>
     
    #include <opengl_utilities.h>
     
    #include "initializing_and_terminating_openglP.h"
     
    const char *FAKE_OPENGL_CLASS_NAME = "FAKE_OPENGL_CLASS";
     
    // This code was lifted, with a little reorganization, from 
    // http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=2
    // The OpenGL groupdescribes what's happening here:
    // https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL)#Pixel_Format
    HGLRC init_opengl(HWND hwnd, HDC *hdc_ptr, HINSTANCE hinstance, int major_version,
        int minor_version, const int *PixelFormatAttribList_ptr, std::string *message_string_ptr)
    {
        int gl_errors_found_count = 0;
        std::string gl_error_message;
        HGLRC return_val = NULL;
        bool error_found = false;
        std::string local_message_string;
        PIXELFORMATDESCRIPTOR pfd;
        int pixel_format = 0;
        int number_of_formats_found = 0;
        HDC hdc = GetDC(hwnd);
        HWND fake_window = NULL;
        std::string text_buffer;
        DWORD callers_error = GetLastError();
        DWORD error_code = 0;
        std::string string_buffer;
     
        SetLastError(0);
     
        if (!init_glew(hinstance, &local_message_string))
        {
            gl_errors_found_count = gl_error_to_text(&gl_error_message);
     
            error_found = true;
     
            if (message_string_ptr != NULL)
            {
                *message_string_ptr += "init_opengl()\n";
                *message_string_ptr += "   Failed to initialize glew.\n";
                *message_string_ptr += local_message_string.c_str();
            }
        }
        else
        {
            if (major_version <= 2)
            {
                memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
                pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
                pfd.nVersion = 1;
                pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
                pfd.iPixelType = PFD_TYPE_RGBA;
                pfd.cColorBits = 32;
                pfd.cDepthBits = 32;
                pfd.iLayerType = PFD_MAIN_PLANE;
     
                pixel_format = ChoosePixelFormat(hdc, &pfd);
     
                if (pixel_format == 0)
                {
                    error_found = true;
     
                    if (message_string_ptr != NULL)
                    {
                        *message_string_ptr += "init_opengl()\n";
                        *message_string_ptr += "   Failed to choose pixel format.\n";
                        error_code = GetLastError();
     
                        if (error_code == 0)
                        {
                            *message_string_ptr += "Error code is 0\n";
                        }
                        else
                        {
                            *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                            *message_string_ptr += "\n";
                        }
                    }
                }
                else
                {
                    if (!SetPixelFormat(hdc, pixel_format, &pfd))
                    {
                        error_found = true;
     
                        if (message_string_ptr != NULL)
                        {
                            *message_string_ptr += "init_opengl()\n";
                            *message_string_ptr += "   Failed to set pixel format.\n";
                            error_code = GetLastError();
     
                            if (error_code == 0)
                            {
                                *message_string_ptr += "Error code is 0\n";
                            }
                            else
                            {
                                *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                *message_string_ptr += "\n";
                            }
                        }
                    }
                    else
                    {
                        // Create the old style context (OpenGL 2.1 and before)
                        return_val = wglCreateContext(hdc);
     
                        if (return_val == NULL)
                        {
                            error_found = true;
     
                            if (message_string_ptr != NULL)
                            {
                                *message_string_ptr += "init_opengl()\n";
                                *message_string_ptr += "   Failed to create context.\n";
                                error_code = GetLastError();
     
                                if (error_code == 0)
                                {
                                    *message_string_ptr += "Error code is 0\n";
                                }
                                else
                                {
                                    *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                    *message_string_ptr += "\n";
                                }
                            }
                        }
                        else
                        {
                            if(!wglMakeCurrent(hdc, return_val))
                            {
                                error_found = true;
     
                                if (message_string_ptr != NULL)
                                {
                                    *message_string_ptr += "init_opengl()\n";
                                    *message_string_ptr += "   wglMakeCurrent() failed.\n";
                                    error_code = GetLastError();
     
                                    if (error_code == 0)
                                    {
                                        *message_string_ptr += "Error code is 0\n";
                                    }
                                    else
                                    {
                                        *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                        *message_string_ptr += "\n";
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // Version number > 2
                if (WGLEW_ARB_create_context && WGLEW_ARB_pixel_format)
                {
                    const int iPixelFormatAttribList[] =
                    {
                        WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
                        WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
                        WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
                        WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
                        WGL_COLOR_BITS_ARB, 32,
                        WGL_DEPTH_BITS_ARB, 24,
                        WGL_STENCIL_BITS_ARB, 8,
                        WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
                        WGL_SAMPLES_ARB, 16,
                        0 // End of attributes list
                    };
     
                    if (PixelFormatAttribList_ptr == NULL)
                    {
                        PixelFormatAttribList_ptr = iPixelFormatAttribList;
                    }
     
                    int iContextAttribs[] =
                    {
                        WGL_CONTEXT_MAJOR_VERSION_ARB, major_version,
                        WGL_CONTEXT_MINOR_VERSION_ARB, minor_version,
                        // WGL_CONTEXT_FLAGS_ARB,
                        WGL_CONTEXT_PROFILE_MASK_ARB,
                        WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
                        // WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
                        0 // End of attributes list
                    };
     
                    if (!wglChoosePixelFormatARB(hdc,
                        PixelFormatAttribList_ptr,
                        // iPixelFormatAttribList, // Integer attribute pairs
                        NULL,					// Floating attribute pairs
                        1,	// Max num of formats that can be stored next argument.
                        &pixel_format,	// List of acceptable formats go here.
                        (UINT*)&number_of_formats_found))	// Number of formats saved in list.
                    {
                        error_found = true;
     
                        if (message_string_ptr != NULL)
                        {
                            *message_string_ptr += "init_opengl()\n";
                            *message_string_ptr += "   Failed to choose pixel format.\n";
                            error_code = GetLastError();
     
                            if (error_code == 0)
                            {
                                *message_string_ptr += "Error code is 0\n";
                            }
                            else
                            {
                                *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                *message_string_ptr += "\n";
                            }
                        }
                    }
                    else
                    {
                        // PFD seems to be only redundant parameter now
                        // Apparently the PIXELFORMATDESCRIPTOR isn't necessary for SetPixelFormat():
                        // https://msdn.microsoft.com/en-us/library/windows/desktop/dd369049%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
                        if (!SetPixelFormat(hdc, pixel_format, NULL))
                        {
                            error_found = true;
     
                            if (message_string_ptr != NULL)
                            {
                                *message_string_ptr += "init_opengl()\n";
                                *message_string_ptr += "   Failed to set pixel format.\n";
                                error_code = GetLastError();
     
                                if (error_code == 0)
                                {
                                    *message_string_ptr += "Error code is 0\n";
                                }
                                else
                                {
                                    *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                    *message_string_ptr += "\n";
                                }
                            }
                        }
                        else
                        {
                            return_val = wglCreateContextAttribsARB(hdc, 0, iContextAttribs);
     
                            // If everything went OK
                            if (return_val == NULL)
                            {
                                error_found = true;
     
                                if (message_string_ptr != NULL)
                                {
                                    *message_string_ptr += "init_opengl()\n";
                                    *message_string_ptr += "   Faild to create OpenGL context.\n";
                                    *message_string_ptr += "   OpelGL version:";
                                    totext_s(major_version, &text_buffer, 10);
                                    *message_string_ptr += text_buffer.c_str();
                                    *message_string_ptr += ".";
                                    totext_s(minor_version, &text_buffer, 10);
                                    *message_string_ptr += text_buffer.c_str();
                                    *message_string_ptr += "\n";
                                    error_code = GetLastError();
     
                                    if (error_code == 0)
                                    {
                                        *message_string_ptr += "Error code is 0\n";
                                    }
                                    else
                                    {
                                        *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                        *message_string_ptr += "\n";
                                    }
                                }
                            }
                            else
                            {
                                if(!wglMakeCurrent(hdc, return_val))
                                {
                                    error_found = true;
     
                                    if (message_string_ptr != NULL)
                                    {
                                        *message_string_ptr += "init_opengl()\n";
                                        *message_string_ptr += "   wglMakeCurrent() failed.\n";
                                        error_code = GetLastError();
     
                                        if (error_code == 0)
                                        {
                                            *message_string_ptr += "Error code is 0\n";
                                        }
                                        else
                                        {
                                            *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                            *message_string_ptr += "\n";
                                        }
                                    }
                                }
     
                                gl_errors_found_count = gl_error_to_text(&gl_error_message);
                            }
                        }
                    }
                }
            }
        }
     
        gl_errors_found_count = gl_error_to_text(&gl_error_message);
     
        if (hdc_ptr != NULL)
        {
            *hdc_ptr = hdc;
        }
     
        // Restore caller's error code, if any.
        SetLastError(callers_error);
     
        gl_errors_found_count = gl_error_to_text(&gl_error_message);
     
        return return_val;
    }
     
    bool init_glew(HINSTANCE hinstance, std::string *message_string_ptr)
    {
        // This code is inspired by http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=2
     
        // From https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL)
        // The key problem is this: the function you use to get WGL extensions is, 
        // itself, an OpenGL extension. Thus like any OpenGL function, it requires an 
        // OpenGL context to call it. So in order to get the functions we need to 
        // create a context, we have to... create a context. 
        bool error_found = false;
        WNDCLASS fake_window_class;
        HDC hdc = NULL;
        HGLRC fake_hglrc = NULL;
        DWORD error_code = 0;
        std::string string_buffer;
     
        memset(&fake_window_class, 0x00, sizeof fake_window_class);
     
        fake_window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// Redraw On Move, And Own DC For Window
        fake_window_class.lpfnWndProc = fake_WndProc;
        fake_window_class.cbClsExtra = 0;						// No Extra Window Data
        fake_window_class.cbWndExtra = 0;						// No Extra Window Data
        fake_window_class.hInstance = hinstance;	// Set The Instance
        fake_window_class.hIcon = NULL;			// Load The Default Icon
        fake_window_class.hCursor = NULL;		// Load The Arrow Pointer
        fake_window_class.hbrBackground = HBRUSH(BLACK_BRUSH);			// No Background Required For GL
        fake_window_class.lpszMenuName = NULL;
        fake_window_class.lpszClassName = FAKE_OPENGL_CLASS_NAME;		// Set The Class Name
     
        if (!RegisterClass(&fake_window_class))					// Attempt To Register The Window Class
        {
            error_found = true;
     
            if (message_string_ptr != NULL)
            {
                *message_string_ptr += "init_glew()\n";
                *message_string_ptr += "   Failed To Register The Window Class ";
                *message_string_ptr += FAKE_OPENGL_CLASS_NAME;
                *message_string_ptr += ".\n";
                error_code = GetLastError();
     
                if (error_code == 0)
                {
                    *message_string_ptr += "Error code is 0\n";
                }
                else
                {
                    *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                    *message_string_ptr += "\n";
                }
            }
        }
     
        HWND fake_window_handle = CreateWindow(FAKE_OPENGL_CLASS_NAME,
            "FAKE",
            WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | WS_CLIPCHILDREN,
            0,
            0,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hinstance,
            NULL);
     
        if (fake_window_handle == NULL)
        {
            error_found = true;
     
            if (message_string_ptr != NULL)
            {
                *message_string_ptr += "init_glew()\n";
                *message_string_ptr += "   Failed To create ";
                *message_string_ptr += FAKE_OPENGL_CLASS_NAME;
                *message_string_ptr += " class window.\n";
                *message_string_ptr += "   Hinstance ";
                *message_string_ptr += totext_s(int(hinstance), &string_buffer, 16, 8, '0')->c_str();
                *message_string_ptr += ".\n";
                error_code = GetLastError();
     
                if (error_code == 0)
                {
                    *message_string_ptr += "Error code is 0\n";
                }
                else
                {
                    *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                    *message_string_ptr += "\n";
                }
            }
        }
        else
        {
            hdc = GetDC(fake_window_handle);
     
            if(hdc == NULL)
            {
                error_found = true;
     
                if (message_string_ptr != NULL)
                {
                    *message_string_ptr += "init_glew()\n";
                    *message_string_ptr += "   GetDC() returned NULL.\n";
                }
            }
            else
            {
                // Choose a pixel format
                PIXELFORMATDESCRIPTOR pfd;
                memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
                pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
                pfd.nVersion = 1;
                pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
                pfd.iPixelType = PFD_TYPE_RGBA;
                pfd.cColorBits = 32;
                pfd.cDepthBits = 32;
                pfd.iLayerType = PFD_MAIN_PLANE;
     
                int pixel_format = ChoosePixelFormat(hdc, &pfd);
     
                if (pixel_format == 0)
                {
                    error_found = true;
     
                    if (message_string_ptr != NULL)
                    {
                        *message_string_ptr += "init_glew()\n";
                        *message_string_ptr += "   ChoosePixelFormat() failed.\n";
                        error_code = GetLastError();
     
                        if (error_code == 0)
                        {
                            *message_string_ptr += "Error code is 0\n";
                        }
                        else
                        {
                            *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                            *message_string_ptr += "\n";
                        }
                    }
                }
                else
                {
                    if (!SetPixelFormat(hdc, pixel_format, &pfd))
                    {
                        error_found = true;
     
                        if (message_string_ptr != NULL)
                        {
                            *message_string_ptr += "init_glew()\n";
                            *message_string_ptr += "   SetPixelFormat() failed.\n";
                            error_code = GetLastError();
     
                            if (error_code == 0)
                            {
                                *message_string_ptr += "Error code is 0\n";
                            }
                            else
                            {
                                *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                *message_string_ptr += "\n";
                            }
                        }
                    }
                    else
                    {
                        // Create the false, old style context (OpenGL 2.1 and before)
                        fake_hglrc = wglCreateContext(hdc);
                        if(fake_hglrc == NULL)
                        {
                            error_found = true;
     
                            if (message_string_ptr != NULL)
                            {
                                *message_string_ptr += "init_glew()\n";
                                *message_string_ptr += "   wglCreateContext() failed.\n";
                                error_code = GetLastError();
     
                                if (error_code == 0)
                                {
                                    *message_string_ptr += "Error code is 0\n";
                                }
                                else
                                {
                                    *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                    *message_string_ptr += "\n";
                                }
                            }
                        }
                        else
                        {
                            wglMakeCurrent(hdc, fake_hglrc);
     
                            if (glewInit() != GLEW_OK)
                            {
                                error_found = true;
     
                                if (message_string_ptr != NULL)
                                {
                                    *message_string_ptr += "init_glew()\n";
                                    *message_string_ptr += "   Couldn't initialize GLEW!\n";
                                    error_code = GetLastError();
     
                                    if (error_code == 0)
                                    {
                                        *message_string_ptr += "Error code is 0\n";
                                    }
                                    else
                                    {
                                        *message_string_ptr += error_code_to_string(error_code, &string_buffer)->c_str();
                                        *message_string_ptr += "\n";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
     
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(fake_hglrc);
        DestroyWindow(fake_window_handle);
     
        return !error_found;
    }
     
    LRESULT CALLBACK fake_WndProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_CREATE:
     
            return 0;
        }
     
        return DefWindowProc(hdlg, message, wParam, lParam);
    }

    Quote Originally Posted by Dark Photon View Post
    That's fine. The buffers in a framebuffer should have the same sampling rate. What I was referrering to was the number of samples in your source framebuffer (your FBO) and your destination framebuffer (e.g. WGL window).
    I see where, because of the cut and paste, I did pass a different window size to glViewport() before setting up the buffers. That doesn't seem to be the source of my problem. glRenderbufferStorageMultisample() and glTexImage2DMultisample() are being passed the same width and height.

    Here's the graphic C++ module. It in no way represents coding practices I use. Most notably, I have a strong aversion to passing global arguments.

    For reference I've preserved, in commented out form, the original GLFW code.

    This is basically a cut and paste of the tutorial's sample code which can be found here, altered to use WGL instead of GLFW and broken into a function, main_from_tutorial_with_wgl(), called by the window procedure's message loop's WM_CREATE clause. The sample's game loop code is loop_from_tutorial_with_wgl(), which is called when the message loop's WM_TIMER is serviced.

    Code :
    // GLEW
    #define GLEW_STATIC
    #include <GL/glew.h>
     
    // GLFW
    // #include <GLFW/glfw3.h>
     
    // GL includes
    #include "Shader.h"
    #include "Camera.h"
     
    // GLM Mathemtics
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
     
    #include <opengl_utilities.h>
     
    #include "learn_opengl_common.h"
     
    // Properties
    GLuint screenWidth = 800, screenHeight = 600;
     
    #if 0
    // Function prototypes
    void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
    void mouse_callback(GLFWwindow* window, double xpos, double ypos);
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
    #endif
     
    void Do_Movement();
    GLuint generateMultiSampleTexture(GLuint samples);
     
    // Camera
    Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
    bool keys[1024];
    GLfloat lastX = 400, lastY = 300;
    bool firstMouse = true;
     
    GLfloat deltaTime = 0.0f;
    GLfloat lastFrame = 0.0f;
     
    // New globals for seperate loop function
    GLuint framebuffer;
    // GLFWwindow* window;
    GLuint cubeVAO;
    Shader *shader_ptr = NULL;
     
    // The MAIN function, from here we start our application and run our Game loop
    GRAPHICS_PARAMETER *main_from_tutorial_with_wgl(HWND hdlg, HINSTANCE hinstance,
                                                                    std::string *message_string_ptr)
    {
     
    #if 0
        // Init GLFW
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
     
        window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed
        glfwMakeContextCurrent(window);
     
        // Set the required callback functions
        glfwSetKeyCallback(window, key_callback);
        glfwSetCursorPosCallback(window, mouse_callback);
        glfwSetScrollCallback(window, scroll_callback);
     
        // Options
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    #endif
     
        int gl_errors_found_count = 0;
        std::string gl_error_message;
        bool error_found = false;
        GRAPHICS_PARAMETER *graphics_parameter_ptr = new GRAPHICS_PARAMETER();
        windows_camera_wrapper_basic::CAMERA_WRAPPER *free_camera_wrapper_ptr = NULL;
        opengl_camera::CAMERA *camera_ptr = NULL;
        vector<Mesh> *meshes_vector_ptr = NULL;
     
        HDC hdc = NULL;
        std::string local_message_string;
        RECT client_rect;
        int width = 0;
        int height = 0;
     
        graphics_parameter_ptr->set_hwnd(hdlg);
     
        graphics_parameter_ptr->set_hrc(init_opengl(hdlg, &hdc, hinstance, 3, 3,
            NULL,
            &local_message_string));
     
        if (graphics_parameter_ptr->get_hrc() == NULL)
        {
            error_found = true;
     
            if (message_string_ptr != NULL)
            {
                *message_string_ptr += "setup_splash_screen()\n";
                *message_string_ptr += "   HRC is NULL.\n";
                *message_string_ptr += local_message_string.c_str();
                local_message_string.erase();
            }
        }
        else
        {
            graphics_parameter_ptr->set_hdc(hdc);
     
            if (graphics_parameter_ptr->get_hrc() == NULL)
            {
                error_found = true;
     
                if (message_string_ptr != NULL)
                {
                    *message_string_ptr += "setup_splash_screen()\n";
                    *message_string_ptr += "   OpenGL failed to open.\n";
                    *message_string_ptr += local_message_string.c_str();
                    local_message_string.erase();
                }
            }
            else
            {
                GetClientRect(hdlg, &client_rect);
                width = client_rect.right - client_rect.left;
                height = client_rect.bottom - client_rect.top;
     
                graphics_parameter_ptr->set_client_rect(&client_rect);
     
                glViewport(0, 0, width, height);
     
                initialize_cameras(graphics_parameter_ptr, width, height, VK_TAB, VK_TAB, 0.001);
            }
        }
     
        screenWidth = width;
        screenHeight = height;
     
        // Initialize GLEW to setup the OpenGL Function pointers
        glewExperimental = GL_TRUE;
        glewInit();
     
        // Define the viewport dimensions
        glViewport(0, 0, screenWidth, screenHeight);
     
        // Setup OpenGL options
        glEnable(GL_MULTISAMPLE); // Enabled by default on some drivers, but not all so always enable to make sure
        glEnable(GL_DEPTH_TEST);
     
        // Setup and compile our shaders
       // Shader shader("advanced.shv", "advanced.shf");
       // shader_ptr = &shader;
       shader_ptr = new Shader("advanced.shv", "advanced.shf");
     
        #pragma region "object_initialization"
        // Set the object data (buffers, vertex attributes)
        GLfloat cubeVertices[] = {
            // Positions       
            -0.5f, -0.5f, -0.5f, 
             0.5f, -0.5f, -0.5f, 
             0.5f,  0.5f, -0.5f, 
             0.5f,  0.5f, -0.5f,  
            -0.5f,  0.5f, -0.5f,  
            -0.5f, -0.5f, -0.5f, 
     
            -0.5f, -0.5f,  0.5f, 
             0.5f, -0.5f,  0.5f, 
             0.5f,  0.5f,  0.5f, 
             0.5f,  0.5f,  0.5f,  
            -0.5f,  0.5f,  0.5f, 
            -0.5f, -0.5f,  0.5f, 
     
            -0.5f,  0.5f,  0.5f, 
            -0.5f,  0.5f, -0.5f,  
            -0.5f, -0.5f, -0.5f,  
            -0.5f, -0.5f, -0.5f, 
            -0.5f, -0.5f,  0.5f, 
            -0.5f,  0.5f,  0.5f, 
     
             0.5f,  0.5f,  0.5f,  
             0.5f,  0.5f, -0.5f, 
             0.5f, -0.5f, -0.5f, 
             0.5f, -0.5f, -0.5f, 
             0.5f, -0.5f,  0.5f,  
             0.5f,  0.5f,  0.5f,  
     
            -0.5f, -0.5f, -0.5f, 
             0.5f, -0.5f, -0.5f,  
             0.5f, -0.5f,  0.5f, 
             0.5f, -0.5f,  0.5f, 
            -0.5f, -0.5f,  0.5f,  
            -0.5f, -0.5f, -0.5f,  
     
            -0.5f,  0.5f, -0.5f,  
             0.5f,  0.5f, -0.5f,
             0.5f,  0.5f,  0.5f,  
             0.5f,  0.5f,  0.5f,  
            -0.5f,  0.5f,  0.5f,  
            -0.5f,  0.5f, -0.5f
        };
        // Setup cube VAO
        GLuint cubeVBO;
        glGenVertexArrays(1, &cubeVAO);
        glGenBuffers(1, &cubeVBO);
        glBindVertexArray(cubeVAO);
        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
        glBindVertexArray(0);
        #pragma endregion
     
     
        // Framebuffers
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);  
        // Create a multisampled color attachment texture
        GLuint textureColorBufferMultiSampled = generateMultiSampleTexture(4);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
        // Create a renderbuffer object for depth and stencil attachments
        GLuint rbo;
        glGenRenderbuffers(1, &rbo);
        glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); 
        glBindRenderbuffer(GL_RENDERBUFFER, 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); 
     
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
        return graphics_parameter_ptr;
    }
     
    void loop_from_tutorial_with_wgl(HWND hdlg, GRAPHICS_PARAMETER *graphics_parameter_ptr)
    {
    #if 0
        // Set frame time
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
    #endif
     
        // Check and call events
        // glfwPollEvents();
        // Do_Movement();      
     
        report_opengl_error_in_popup(hdlg, "After glfwPollEvents()");
     
        // 1. Draw scene as normal in multisampled buffers
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);   
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        report_opengl_error_in_popup(hdlg, "After glClear()");
     
        // Set transformation matrices		
        shader_ptr->Use();
     
        report_opengl_error_in_popup(hdlg, "After shader_ptr->Use()");
     
        glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)screenWidth/(GLfloat)screenHeight, 0.1f, 1000.0f);
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "view"), 1, GL_FALSE, glm::value_ptr(camera.GetViewMatrix()));	
        glUniformMatrix4fv(glGetUniformLocation(shader_ptr->Program, "model"), 1, GL_FALSE, glm::value_ptr(glm::mat4()));
     
        glBindVertexArray(cubeVAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
     
        report_opengl_error_in_popup(hdlg, "After glDrawArrays()");
     
        glBindVertexArray(0);
     
        // 2. Now blit multisampled buffer(s) to default framebuffers
        glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);				
     
        report_opengl_error_in_popup(hdlg, "After glBindFramebuffer(GL_READ_FRAMEBUFFER) and glBindFramebuffer(GL_DRAW_FRAMEBUFFER)");
     
        glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);     
     
        report_opengl_error_in_popup(hdlg, "After glBlitFramebuffer()");
     
        // Swap the buffers
        //  glfwSwapBuffers(window);
        SwapBuffers(graphics_parameter_ptr->get_hdc());
     
        report_opengl_error_in_popup(hdlg, "At end of loop, after SwapBuffers()");
    }
     
    GLuint generateMultiSampleTexture(GLuint samples)
    {
        GLuint texture;
        glGenTextures(1, &texture);
     
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
        glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB8, screenWidth, screenHeight, GL_TRUE);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
     
        return texture;
    }

    As always Dark Photon, I appreciate your assistance.

    Thanks
    Larry
    Last edited by larryl; 05-23-2017 at 08:00 PM.

  7. #7
    Intern Contributor
    Join Date
    Jan 2017
    Posts
    54
    Thanks again John:

    I have an inline function that calls glGetError(). It has text arguments that describe where it was called from.

    I'm trying to use WGL code that's identical to the GLFW code to setup, draw and blit the frame buffer, with a call to glBlitFramebuffer(). I haven't been able to find a difference that would cause the problem.

    I don't understand why OpenGL can't provide more descriptive error messages.

    I used to be a Unix programmer using Solaris. After a decade and a half of Microsoft's abuse of developers I've come to accept it as a price for the massive user base. But I am looking at the Android platform.

    What's the reason OpenGL uses GL_INVALID_OPERATION to describe 10 different problems. The OpenGL code that detected the problem knows why it failed. Why not tell the developer?

    Thanks once more for your help.
    Larry
    Last edited by larryl; 05-23-2017 at 08:05 PM.

  8. #8
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    417
    Quote Originally Posted by larryl View Post
    I'm trying to use WGL code that's identical to the GLFW code to setup, draw and blit the frame buffer, with a call to glBlitFramebuffer(). I haven't been able to find a difference that would cause the problem.

    I don't understand why OpenGL can't provide more descriptive error messages.
    why not ? you know how glGetError() worls and you know a GL_INVALID_OPERATION is thrown somewhere, its a matter of minutes to find the function throwing that error. you said you have a "inliner" for that, try something like this:

    Code :
    #define CheckForGLErrors      CheckForGLErrors__(__FILE__, __LINE__);
     
    void CheckForGLErrors__(const char* file, unsigned int line)
    {
        string errorstring;
        for (GLenum error; (error = glGetError()) != GL_NO_ERROR;)
        {
            if (error == GL_INVALID_ENUM)
                errorstring += " GL_INVALID_ENUM";
            if (error == GL_INVALID_VALUE)
                errorstring += " GL_INVALID_VALUE";
            if (error == GL_INVALID_OPERATION)
                errorstring += " GL_INVALID_OPERATION";
            if (error == GL_STACK_OVERFLOW)
                errorstring += " GL_STACK_OVERFLOW";
            if (error == GL_STACK_UNDERFLOW)
                errorstring += " GL_STACK_UNDERFLOW";
            if (error == GL_OUT_OF_MEMORY)
                errorstring += " GL_OUT_OF_MEMORY";
            if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
                errorstring += " GL_INVALID_FRAMEBUFFER_OPERATION";
            if (error == GL_CONTEXT_LOST)
                errorstring += " GL_CONTEXT_LOST";
        }
        if (!errorstring.empty())
        {
            cout
                << (char)7
                << "OpenGL Error: " << endl
                << "\tLine: \t" << line << endl
                << "\tFile: \t" << file << endl
                << "\tErrors: \t" << errorstring << endl << endl;
            cin.get();
        }
    }

    that gives you the file + line where the error was detected, with that anyone should be able to track the error throwing functiion in a few minutes. if it actually is glBlitFramebuffer(for example), you also know the reasons for the error. the next thing is to exclude each possible reason until 1 is left over. but without figuring out what function has thrown that error, you can guess all day long without much success ...

    a "more descriptive" message is what you get if you enable a debug message output, but that requires a debug context

    https://www.khronos.org/opengl/wiki/Debug_Output
    https://www.learnopengl.com/#!In-Practice/Debugging
    https://sites.google.com/site/john87.../debug-context

  9. #9
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,402
    Quote Originally Posted by larryl View Post
    What's the reason OpenGL uses GL_INVALID_OPERATION to describe 10 different problems. The OpenGL code that detected the problem knows why it failed.
    What code? In all probability, the original glGetError() simply read, cleared and returned the graphics hardware's status flags. GL_INVALID_OPERATION means that the "invalid operation" flag was set.

  10. #10
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,123
    Quote Originally Posted by larryl View Post
    Here's the OpenGL initialization code:

    Code cpp:
    HGLRC init_opengl(HWND hwnd, HDC *hdc_ptr, HINSTANCE hinstance, int major_version,
        int minor_version, const int *PixelFormatAttribList_ptr, std::string *message_string_ptr)
    {
        ...
        init_glew(hinstance, &local_message_string);
     
        if (major_version <= 2)
        {
            ...
            pixel_format = ChoosePixelFormat(hdc, &pfd);
            ...
            SetPixelFormat(hdc, pixel_format, &pfd);
            ...
            // Create the old style context (OpenGL 2.1 and before)
            return_val = wglCreateContext(hdc);
            ...
            wglMakeCurrent(hdc, return_val);
        }
        else
        {
            // Version number > 2
            if (WGLEW_ARB_create_context && WGLEW_ARB_pixel_format)
            {
                const int iPixelFormatAttribList[] =
                {
                    ...
                    WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
                    WGL_SAMPLES_ARB, 16,
                    0 // End of attributes list
                };
     
                if (PixelFormatAttribList_ptr == NULL)
                {
                    PixelFormatAttribList_ptr = iPixelFormatAttribList;
                }
     
                ...
                wglChoosePixelFormatARB(hdc,
                    PixelFormatAttribList_ptr,
                    NULL,
                    1,
                    &pixel_format,
                    (UINT*)&number_of_formats_found);
                ...
                SetPixelFormat(hdc, pixel_format, NULL);
                    return_val = wglCreateContextAttribsARB(hdc, 0, iContextAttribs);
                ...
                wglMakeCurrent(hdc, return_val);
            }
        }
     
        ...
    }
     
    bool init_glew(HINSTANCE hinstance, std::string *message_string_ptr)
    {
        // This code is inspired by [url]http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=2[/url]
     
        // From [url]https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL)[/url]
        // The key problem is this: the function you use to get WGL extensions is,
        // itself, an OpenGL extension. Thus like any OpenGL function, it requires an
        // OpenGL context to call it. So in order to get the functions we need to
        // create a context, we have to... create a context.
        bool error_found = false;
        WNDCLASS fake_window_class;
        HDC hdc = NULL;
        HGLRC fake_hglrc = NULL;
        DWORD error_code = 0;
        std::string string_buffer;
     
        ...
        HWND fake_window_handle = CreateWindow(FAKE_OPENGL_CLASS_NAME, ...);
        ...
        hdc = GetDC(fake_window_handle);
     
        ...
        int pixel_format = ChoosePixelFormat(hdc, &pfd);
        ...
        SetPixelFormat(hdc, pixel_format, &pfd);
        ...
        fake_hglrc = wglCreateContext(hdc);
        ...
        wglMakeCurrent(hdc, fake_hglrc);
        ...
        glewInit();
        ...
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(fake_hglrc);
        DestroyWindow(fake_window_handle);
     
        return !error_found;
    }
    Ok, there two context creation paths here. The question is which one is your code taking.

    I've excised all the error handling from your code snippet above in this post so we can see what the code is actually trying to do.

    Notice that one path (the path you're likely taking, where "major_version > 2") is using WGL_ARB_pixel_format to create a context using a "multisample" pixel format, where the number of samples is 16 (notice the values set for WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB). That means that, if it succeeds, your system framebuffer will be a 16x MSAA framebuffer.

    This number of samples (16) is different than the number of samples you were using for your off-screen FBO textures (4). If your code is taking this path, then this could very well be the cause of your GL_INVALID_OPERATION when blitting from the off-screen FBO to the system framebuffer.

    Try WGL_SAMPLE_BUFFERS_ARB = 0 (GL_FALSE) instead and just delete the WGL_SAMPLES_ARB = 16 line. That should create a single-sampled system framebuffer, which ideally will clear up your problem.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •