Opengl Game Loop Multithreading - c++

I have been messing around with OpenGL lately, and I noticed that the windows message pump is blocking whenever i attempt to resize my window, so as a result rendering is halted whenever i click on the menu bar or resize the window.
To fix this, I am looking into multithreading.
I have the following:
_beginthread(RenderEntryPoint, 0, 0);
while (!done)
{
PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void RenderEntryPoint(void *args)
{
while (1)
{
//render code
}
}
However, my scene isn't being rendered, and I'm not sure why.

You need to make the OpenGL rendering context current in the rendering thread, and make sure it's not current in the windowing thread. This also means that you can't call any OpenGL functions from the windowing thread.

Related

Continue update&render whilst handling windowproc messages

I've created a win32 C++ app that uses direct2d to plot stuff in a window. In a loop as shown below, I call render and update whilst also peeking at any messages. But when ever I have WM_COMMAND that lets WindowProc call a MessageBox() or DiaLogBox(), my update&render loop no longer gets executed and the plot window freezes. Is there a simple fix with another loop structure or do I need to enter the, for me, unknown world of multithreading?
while (message.message != WM_QUIT)
{
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
DispatchMessage(&message);
else
{
Update();
BeginDraw();
Render();
EndDraw();
}
}
EDIT: By popular demand I have changed above "ugly" mechanism in to another approach, yet with the same issue
bool runGame = true;
while (runGame)
{
while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&message);
if (message.message == WM_QUIT)
runGame = false;
}
Update();
BeginDraw();
Render();
EndDraw();
}

Standard if(PeekMessage) else update&render-loop creates delay in message handling

Following a Direct2D tuturial I've created a realtime update&render-loop like below. But when the update&render-loop takes long (eg when I have a Sleep(5000) somewhere in the Update()), normal messages handling like clicking the close window, can have to wait up to 5s.
So what is the proper way to split the message handling and realtime update&render-loop in two separate threads?
while (message.message != WM_QUIT)
{
if (PeekMessage(&message, windowHandle, 0, 0, PM_REMOVE)) // check for events and pass them to WindowProc, otherwise
DispatchMessage(&message);
else // run the realtime update&render loop
{
GameController::Update();
graphics->BeginDraw();
GameController::Render();
graphics->EndDraw();
}
}

EnableWindow(hWnd, false) doesn't disable keyboard input

I am attempting to disable a window under certain conditions using EnableWindow(hWnd, false);
According to the documentation, this should "disable mouse and keyboard input to the specified window".
The problem I am seeing is that it does, in fact, disable like it says, except if the cursor is currently inside of a text box in the window and the window has the focus that does not get disabled. I was thinking of doing some sort of code to take the focus off of the window as well.
Is there a better way to go about this?
Note: The window being disabled is a binary ran via _spawnl().
I'm not sure if this is a Windows feature or a bug. Either way, disabling the foreground window is not a good idea.
If you are able to modify the program you start with _spawnl() then that is a better solution. You could make it respond to WM_APP or something like that when you need to control it.
If it is a 3rd-party application then you are left with hacks.
You could try to change the foreground window with SetForegroundWindow but this will only work if you do it very soon after _spawnl() before your thread loses the foreground lock. Using LockSetForegroundWindow before _spawnl() might be able to help you keep the lock longer. There are also various other hacks to change the foreground with AttachThreadInput etc.
If you don't want to change the foreground I was able to come up with a workaround:
ShellExecute(NULL, NULL, TEXT("Notepad"), NULL, NULL, SW_SHOW);
Sleep(2000);
HWND hNP = FindWindow(TEXT("Notepad"), NULL);
Sleep(2000); // Start typing in Notepad now...
if (hNP)
{
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, &gti))
{
HWND hChild = NULL;
if (gti.hwndFocus != hNP && gti.hwndFocus)
{
EnableWindow(hChild = gti.hwndFocus, false);
}
if (GetForegroundWindow() == hNP)
{
SendNotifyMessage(hNP, WM_ACTIVATE, WA_INACTIVE, NULL);
SendNotifyMessage(hNP, WM_ACTIVATE, WA_ACTIVE, NULL);
SendNotifyMessage(hNP, WM_SETFOCUS, NULL, NULL);
// SendNotifyMessage(hNP, WM_NCACTIVATE, false, NULL); // Uncomment to make it look like it is inactive
}
EnableWindow(hNP, false);
if (hChild)
{
EnableWindow(hChild, true);
}
}
MessageBox(NULL, TEXT("Done?"), NULL, MB_TOPMOST);
SetForegroundWindow(hNP);
PostMessage(hNP, WM_CLOSE, 0, 0);
}
This is certainly not optimal, it leaves Notepad in a state where it looks like it is enabled but it is really not. The idea is to disable the focused child window and trigger a fake activation change and forcing the focus to change. It might not work with other applications, who knows.
If you are willing to risk a deadlock you can do this instead:
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, &gti))
{
if (GetForegroundWindow() == hNP)
{
if (AttachThreadInput(GetCurrentThreadId(), tid, true))
{
SetFocus(NULL);
AttachThreadInput(GetCurrentThreadId(), tid, false);
}
}
EnableWindow(hNP, false);
}

Forcing a ListBox to Update

I am using C++ with MFC, and I have a ListBox tied to a variable that I'm updating as I run through a function:
void CFileSelection::OnBnClickedFiletousb()
{
m_LogC.AddString(_T("Starting move to USB, Please Wait..."));
UpdateData(FALSE);
// Code to move files from disk to USB
m_LogC.AddString(_T("Move to USB Successful."));
}
However, despite the UpdateData, the ListBox doesn't populate with either string until it has completed it's task. Is there a way to make it update the screen before the rest of the code is executed?
Use this function after changing the text on the listbox. Your issue is that the other calls are blocking the MessageThread, but you can force an update with this.
void ProcessWindowMessages()
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // let them see the message before we go into longer term wait
{
TranslateMessage(&msg); // translate it
DispatchMessage(&msg); // and let windows dispatch it to WinProc
}
}
Alternatively you can also call
yourlistboxVariable->UpdateWindow();

Win32 ReleaseDC and DestroyWindow returning 0

I have a single window created with the CS_OWNDC style for an engine I'm coding and it's showing properly, but when I'm closing the program and I call the ReleaseDC(hWnd, hDC) the function returns 0 always (and according to MSDN it means it couldn't be released).
The DestroyWindow(hWnd) is also returning 0.
I am calling GetDC(hWnd) during the window creation.
What is weird is that I only get this error if I pass through the messaging function, even if it has nothing coded inside.
My main code is looking like this:
WindowManager windowManager;
HWND mainWindow = windowManager.Initialize("Title", "ClassName", 1024, 768, 32, WindowProc);
MSG msg;
while(true)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT) { break; }
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
windowManager.Clear(); //this calls ReleaseDC(hWnd, DC) and DestroyWindow(hWnd) among other release codes
What I don't understand is that if I comment the whole while loop, I don't get the release or destroy window errors.
Calling GetLastError() gives me a 0 too.
On MSDN it says the DestroyWindow must be called from the same thread, but I'm not coding any multi thread functions so I don't think that's the case.
What could be causing this?