Handmade Hero»Forums»Code
Matyas
15 posts
Day 472 - Resizing the OpenGL window
Edited by Matyas on Reason: Initial post
Hi everyone!

On Day 472, Casey separates the win32 message loop from the actual game loop
by moving the game loop to a different thread. This allowed the game
to still render, even when the window is being moved / resized.

I have noticed however that when setting up my window class like Casey did,

1
2
3
4
5
6
7
8
9
WNDCLASS window_class;
Zero_Struct(window_class); {
    window_class.style          = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
    window_class.lpfnWndProc    = win32_window_callback;
    window_class.hInstance      = instance;
    window_class.hCursor        = LoadCursor(0, IDC_ARROW);
    window_class.hbrBackground  = 0; // /* NOTE(Matyas): Don't redraw! */
    window_class.lpszClassName  = "openglapp";
    }


I still get blinking when resizing my OpenGL window.
Casey towards the end of the stream said that this issue was mainly because of the
way the rendering engine was architected.
In my case however, I have tried setting up a very bare-bones renderer that just draws
a single triangle and the issue still remains.

I have tried messing with WM_PAINT, WM_ERASEBKGND with no success.

Does anyone know about this issue and how it could be solved?
Mārtiņš Možeiko
2559 posts / 2 projects
Day 472 - Resizing the OpenGL window
I believe CS_HREDRAW and CS_VREDRAW styles are making flickering to happen.

They send background erase/paint messages. I believe you can make OS ignore those by returning nonzero value for WM_ERASEBKGND message and calling ValidateRect in WM_PAINT.
Matyas
15 posts
Day 472 - Resizing the OpenGL window
Edited by Matyas on
Hi Mārtiņš,

Thank you for your help!
I tried what you suggested, I still getting flickering though unfortunately :(
Do you think this can be caused by something else?
I should probably add I have a direct3D11 backend, an I have none of these issues there.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// WinMain(...)

WNDCLASS window_class;
Zero_Struct(window_class); {
    window_class.style          = /*CS_HREDRAW|CS_VREDRAW|*/CS_OWNDC;
    window_class.lpfnWndProc    = win32_window_callback;
    window_class.hInstance      = instance;
    window_class.hCursor        = LoadCursor(0, IDC_ARROW);
    window_class.hbrBackground  = 0; // (HBRUSH)GetStockObject(BLACK_BRUSH);
    window_class.lpszClassName  = "BottleBee";
}

// win32_window_callback(...)

inline LRESULT CALLBACK
win32_window_callback(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
{
    LRESULT result = 0;
    switch (message) {

        case WM_DESTROY:
        case WM_CLOSE: {
            win32_running = false;
        } break;
        
        case WM_PAINT: {
            
            ValidateRect(window, 0);

        } break;
        
        case WM_ERASEBKGND: {
            
            result = 1; // NOTE(Matyas): Non-zero.
        } break;

        case WM_GETMINMAXINFO: {
           
            LPMINMAXINFO info = (LPMINMAXINFO)lparam;
            info->ptMinTrackSize.x = 640;
            info->ptMinTrackSize.y = 360;

        } break;

        default: {
            result = DefWindowProc(window, message, wparam, lparam);
        } break;
    }

    return(result);
}
Mārtiņš Možeiko
2559 posts / 2 projects
Day 472 - Resizing the OpenGL window
Ok, then the issue is somewhere else. It's hard to guess where...
How are you reading current window size? Maybe it is set to something like (0,0) and you simply don't render anything? Where are you doing SwapBuffers call? If I'm not mistaken it should be done on same thread as where HWND was created.
Matyas
15 posts
Day 472 - Resizing the OpenGL window
Edited by Matyas on
Aha, the SwapBuffers part may be the issue; I am _not_ calling it on the same
thread where I created my window.
However, I am not sure how to move SwapBuffers out of my game loop... wouldn't that
halt the program waiting for vsync? Doesn't also need to be on the same thread as the GL context? (I create my GL context in win32_program_loop right now)

Here is my current code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
inline DWORD
win32_program_loop(LPVOID user_pointer)
{
    Win32_State *win32_state = (Win32_State *)user_pointer;
    
    // NOTE(Matyas): initialize stuff...

    UpdateWindow(win32_state->window_handle);
    ShowWindow(win32_state->window_handle, SW_SHOW);

    while(win32_running) {

        uint32 width, height;
        RECT window_size;
        GetClientRect(state->window_handle, &window_size);
    
        width  = (window_size.right - window_size.left);
        height = (window_size.bottom - window_size.top);
        
        Render_Commands render_commands;
        render_commands = default_render_commands(width, height, render_memory);

        hotcode.update_and_render(&memory, &render_commands);

        Rect2 draw_region = rect2(0, 0, (f32)width, (f32)height);

        renderer_execute_commands(&renderer, &render_commands, draw_region);
        
        // NOTE(Matyas): This is just SwapBuffers (in a separate dll)
        renderer_present_buffers(&renderer, 1);
    }

    return(0);
}



int __stdcall
WinMain(HINSTANCE instance, HINSTANCE previous_instance, LPSTR, int)
{
    Win32_State win32_state;
    Zero_Struct(win32_state);

    WNDCLASS window_class;
    Zero_Struct(window_class); {
        window_class.style          = /*CS_HREDRAW|CS_VREDRAW|*/CS_OWNDC;
        window_class.lpfnWndProc    = win32_window_callback;
        window_class.hInstance      = instance;
        window_class.hCursor        = LoadCursor(0, IDC_ARROW);
        window_class.hbrBackground  = 0; // (HBRUSH)GetStockObject(BLACK_BRUSH);
        window_class.lpszClassName  = "BottleBee";
    }

    if (RegisterClass(&window_class)) {
        
        win32_state.window_handle = CreateWindowEx( 0,
                                                    window_class.lpszClassName,
                                                    Stringize(PROGRAM_NAME),
                                                    WS_OVERLAPPEDWINDOW,
                                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                                    1280, 854,
                                                    0, 0, instance, 0);
    
        if (win32_state.window_handle) {
        
            DWORD worker_thread_id;
            HANDLE worker_thread = CreateThread(0, Megabytes(16), win32_program_loop, &win32_state, 0, &worker_thread_id);
            CloseHandle(worker_thread);

            win32_running = true;
            while(win32_running) {
                win32_process_pending_messages(&win32_state);
            }
        }

    } else {
        Assert(false, "failed to register win32 window class");
    }

    return(0);
}

Mārtiņš Možeiko
2559 posts / 2 projects
Day 472 - Resizing the OpenGL window
Edited by Mārtiņš Možeiko on
I think another issue could be that you are not allowed to touch HWND from other threads. That means you can use HWND only in that thread which created it. I'm not 100% sure on this, but long time ago this was definitely an issue when you accessed HWND from other threads.

To have SwapBuffers on main thread you'll need to move all rendering commands to main thread (including GL context). Or you probably can share two GL context's created in different threads.