SDL2 + OpenGL + Radeon = Black Window

I wrote an OpenGL game engine that (so far) works just fine in Windows 7 (NVIDIA), Arch Linux (NVIDIA), and macOS (Radeon). However, I have a friend running Windows 7 who sees nothing but a black window.

SDL_GL_SetSwapInterval succeeded.
OpenGL Vendor: ATI Technologies Inc.
OpenGL Renderer: AMD Radeon R7 200 Series
OpenGL Version: 4.5.13399 Compatibility Profile/Debug Context 15.200.1062.1003
OpenGL Shading Language: 4.40

I am starting to lose my mind over this. My engine is not (yet) very complicated. Like, seriously, it draws textured triangles using OpenGL 2.1 (with shaders that are like 3 lines long). He is able to run a bunch of other games no problem, so I’m pretty sure it’s my code, but even after adding a mountain of verbose logging, I’m not seeing any OpenGL errors or missteps.

I had him build and run this sample program. (It has a couple code mistakes that are easily fixed.) It works fine on my machine and shows a triangle and a square for 5 seconds. On his machine, it’s just another black window… and it’s a really small program. =/

How do I make Radeon happy? T_T

This was the macOS driver (which worked):

SDL_GL_SetSwapInterval succeeded.
OpenGL Vendor: ATI Technologies Inc.
OpenGL Renderer: AMD Radeon Pro 555 OpenGL Engine
OpenGL Version: 2.1 ATI-1.51.8
OpenGL Shading Language: 1.20

I have no idea if this is the cause of the problem, but you are mixing OpenGL and SDL calls to the same context and that is not recommended nor, I think, officially supported. Create your own OpenGL context with SDL_GL_CreateContext and replace your SDL_RenderPresent with SDL_GL_SwapWindow to see if it helps.

My own engine is not doing that, but that sample program might not be the best. I’ll write up a proper minimal example to see if I can replicate it. My own program does use SDL_GL_SwapWindow.

Just a small observation on the small sample program: It doesn’t explicitly ask for an opengl renderer. For a quick fix, use SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); before SDL_CreateWindowAndRenderer. The automatic driver selection of the SDL render API will most likely use Direct3D on Windows and make the OpenGL calls fail, causing a black screen. Perhaps it would have worked on that other system that way.

I wrote this program instead. Lemme know if you see any obvious mistakes here.

EDIT – This program actually worked on the Radeon machine. So I’m going to progressively add features.

#include <iostream>
#include <SDL.h>
#include <GL/glew.h>
using namespace std;

static const char* GetString(GLenum name)
{
    auto text = (const char*)glGetString(name);
    return text ? text : "(null)";
}

static int GetInt(GLenum name)
{
    GLint value;
    glGetIntegerv(name, &value);
    return value;
}

static void MyCallback(
    GLenum source,
    GLenum type,
    GLuint id,
    GLenum severity,
    GLsizei length,
    const GLchar* msg,
    const void* data)
{
    if (msg && *msg) cout << "[OpenGL] " << msg << '\n';
}

int main(int argc, char** argv)
{
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    SDL_GL_SetAttribute(
        SDL_GL_CONTEXT_FLAGS,
        SDL_GL_CONTEXT_DEBUG_FLAG);
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    
    auto window = SDL_CreateWindow(
        "SDL2 OpenGL Test",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        1024,
        768,
        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
    
    auto context = SDL_GL_CreateContext(window);
    glewInit();
    glEnable(GL_DEBUG_OUTPUT);
    
    cout
        << "OpenGL Vendor: " << GetString(GL_VENDOR)
        << "\nOpenGL Renderer: " << GetString(GL_RENDERER)
        << "\nOpenGL Version: " << GetString(GL_VERSION)
        << "\nOpenGL Shading Language: "
        << GetString(GL_SHADING_LANGUAGE_VERSION)
        << "\nOpenGL Max Texture Size: " << GetInt(GL_MAX_TEXTURE_SIZE)
        << '\n';
    
    cout << "OpenGL debug context flag ";
    GLint v;
    glGetIntegerv(GL_CONTEXT_FLAGS, &v);
    if (v & GL_CONTEXT_FLAG_DEBUG_BIT)
    {
        cout << "enabled\n";
        glDebugMessageCallback((GLDEBUGPROC)MyCallback, nullptr);
    }
    else
    {
        cout << "disabled\n";
    }
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0, 0, 1024, 768);
    glClearColor(0.0f, 0.25f, 0.25f, 1.0f);
    
    bool run = true;
    bool doDraw = true;
    while (run)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_WINDOWEVENT:
                    switch (event.window.event)
                    {
                        case SDL_WINDOWEVENT_EXPOSED:
                            doDraw = true;
                            break;
                        case SDL_WINDOWEVENT_SIZE_CHANGED:
                            doDraw = true;
                            glViewport(
                                0,
                                0,
                                event.window.data1,
                                event.window.data2);
                            break;
                    }
                    break;
                case SDL_KEYDOWN:
                    if (event.key.keysym.sym == SDLK_ESCAPE) run = false;
                    break;
                case SDL_QUIT:
                    run = false;
                    break;
                default: break;
            }
        }
        
        if (doDraw)
        {
            doDraw = false;
            glClear(GL_COLOR_BUFFER_BIT);
            glBegin(GL_TRIANGLES);
            glColor3f(1.0f, 1.0f, 1.0f);
            glVertex2f(-0.5f, -0.5f);
            glVertex2f(+0.5f, -0.5f);
            glVertex2f(0.0f, 0.5f);
            glEnd();
            SDL_GL_SwapWindow(window);
        }
        
        SDL_Delay(1);
    }
    
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(window);
    
    SDL_Quit();
    return 0;
}