Day 244: White Rectangles

Summary: calling wglCreateContextAttribsARB on my machine (Windows 8.1 + Nvidia GPU) in the worker thread proc at startup doesn't work. Symptoms are white rectangles all around the screen instead of the expected pictures.

How to fix: create the shared context in the main thread, at initialization time of the low priority queues but not inside the thread proc. Do the wglMakeCurrent only in the thread proc of the queues.

(Actually I'm not yet sure if this is a complete fix, because the display is still quite weird and some rectangles seem to not show textures at all.., but I think that's because I still only have spinning HDD)

For the curious, it took me 1h30 to find the problem.

Summary of the paths I took:
1. Handmade Hero only shows black screen only. Fixed by setting HANDMADE_STREAMING=0
2. Handmade Hero now show only white rectangles. Fixed by #define GlobalConstants_Renderer_UseSoftware 1
This proves that OpenGL is capable of showing our assets.. So that's not an error having to do with the asset file.
3. Compared OpenGLDisplayBitmap (used by software renderer) and OpenGLRenderCommands.. We seem to use the same texture attributes in both so does not seem to be a trivial OpenGL error.
4. Add checks of glGetError() inside the Win32AllocateTexture function. Like so:
1
2
GLenum Error;
while ((Error = glGetError()) != GL_NO_ERROR) { /* breakpoint here */ }


This turns out to be an infinite loop, always returning GL_INVALID_OPERATION which is unexpected when you read the docs at http://docs.gl/es3/glGetError

That's at that point that I start to suspect a bigger, more general issue with the GL context of the worker thread and debug the Win32CreateOpenGLContextForWorkerThread function. ModernGLRC is there always 0.. Which is my clue that we have a problem calling wglCreateContextAttribsARB inside the thread proc.

I then fixed that by adding the HGLRC to the platform_work_queue structure, instantiate in the main thread and there you go, I start seeing bitmaps on the screen.

Edited by Nicolas Léveillé on
Hmm, interesting. I'm not aware of this kind of limitation. Afaik you should be able to create OpenGL context in thread. I'll later try it on my machine (Nvidia + Win10).

Btw, to get more meaningful errors I suggest to use ARB_debug_output extension instead of glGetError call. It provides callback with textual error message about the error happening, and also it can provide performance hints. All the recent drivers supports this extension.
Is it possible that consumer drivers behave differently from developer drivers? I'm using consumer drivers still. I have to read up on ARG_debug_output, I learned OpenGL with 2.0 so I'm, a bit behind ;)
What are the developer drivers you are talking about? I'm not aware of Nvidia releasing special developer drivers (except beta version of drivers which sometimes includes newer features).

Edited by Mārtiņš Možeiko on
I was reading some of their developer pages, where they were talking about installing the "required" drivers as a pre-requisite to install some of their debugging tools (Nsight for Visual Studio)

Ex:
https://developer.nvidia.com/game...sight-visual-studio-edition-5-0-0

This is what I interpreted as dedicated developer drivers, which I assumed folks here maybe were using. But maybe they just ask you to use some old driver version for which the tools are working.
For what it's worth, I encountered exactly the same problem. I was just about to write a long post about my findings, but it appears someone has saved me the trouble.
I can confirm this happens also to me. Just tried on my machine (Windows 10 x64, Nvidia GTX 970) and no textures. Only way it works, if context is created on main thread.

Edited by Mārtiņš Možeiko on
Interesting! Well, it is not troublesome to create the contexts on the main thread, so we can certainly switch to that tomorrow. Maybe the nVidia drivers require that there be an active context when you create new shared contexts?

- Casey
No, that's not a problem.
I tried calling wglMakeCurrent(0, 0) before creating thread context on main thread and wglMakeCurrent with correct dc/rc after creating all thread contexts, and textures are still on screen.
And actually my fix is incomplete, not totally correct. We need one GL context per thread and moving it naively outside of the thread proc makes it per queue! So one needs something like the win32_worker_thread_startup that existed for a couple of minutes on stream
Yeah, we should probably have it set up that way anyway (one struct per worker) for other reasons, so I'll make that change tonight.

- Casey
OK, as of 255 we've got only the main thread creating contexts. Did this fair better on your card/driver?

- Casey
cmuratori
OK, as of 255 we've got only the main thread creating contexts. Did this fair better on your card/driver?

- Casey


were there 10 episodes I missed? Last I checked we were are 245
That's a typo. Casey meant day 246.

It's almost good. The textures are visible, but super glitchy. Sometimes only half is showing, sometimes nothing is showing (just a white screen). Sometimes everything appears normal after couple of seconds.

Here is video I captured: https://drive.google.com/open?id=0B6NdBDx_PciXMFh1MGlJVW9tTHM
This is when I compiled with HANDMADE_STREAMING=0, so double buffering is enabled.

I fixed it by adding glFlush() at end of Win32AllocateTexture function. My guess is that main thread tries to use textures too soon - they haven't uploaded to GPU fully. With glFlush everything renders correctly.

Btw, there is small bug when calling Win32SetPixelFormat in Win32InitOpenGL function - it is called only for modern context. If creating modern context fails, this function won't be called, and creating regular context will fail:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
internal HGLRC
Win32InitOpenGL(HDC WindowDC)
{
    Win32LoadWGLExtensions();

    b32 ModernContext = true;
    HGLRC OpenGLRC = 0;
    if(wglCreateContextAttribsARB)
    {
        Win32SetPixelFormat(WindowDC);  // <---- setting pixel format for modern context
        OpenGLRC = wglCreateContextAttribsARB(WindowDC, 0, Win32OpenGLAttribs);
    }
    
    if(!OpenGLRC)
    {
        ModernContext = false;                 // <---- not setting pixel format :(
        OpenGLRC = wglCreateContext(WindowDC); // <---- this will fail
    }

This probably is not very important bug, because not having ARB_create_context extension is super rare case.

Edited by Mārtiņš Možeiko on
Hmm... well, we could try fencing the textures, just to see what happens, but that seems a little concerning in general due to the fact that it shouldn't be taking that long to download the textures in the first place. So I worry that it isn't actually trying to do the texture download when we tell it :( The glFlush() is probably just forcing to actually start the texture download. I wonder if there's some other way we can get the nVidia driver to believe us that we want to transfer the texture right away...

- Casey