Closed LiveAsynchronousVisualizedArchitecture closed 1 year ago
Hey I'm having trouble reproducing this issue. I'm using VS studio 2017 community and MSCV v141 and v140. but still I cannot reproduce the crash
Thanks for looking into it. One more element is that I didn't have a wgext.h file in the include install so I used one from the Khronos website.
ok so I installed the latest version of wglext.h but still no crash
Thanks again for looking into it. On startup there is actually an error of "The specified module could not be loaded." I'll see what I can figure out about that. The Window utility Dependency Walker doesn't show anything out of the ordinary, just KERNEL32.dll USER32.dll GDI32.dll and OPENGL32.dll
it could be your driver. if you have an NVIDIA card that might be trouble as I don't have a NVIDIA card to dev with
It is possible but I don't think it is likely since glfw and even a previous version of TinyWindow.h have both worked before. I do have two monitors running at different refresh rates however. I took a quick look at glfw and it looks like they loop through lots of pixel formats on initialization. I'm not certain if the pixel format is even affecting the problem I'm having, but it is a a difference I noticed at a glance.
The module not loaded windows error seemed to be from compiling statically. When I use the debug DLL in msvc it goes away, though this does't solve the wgl problem.
Here is what I've been running: https://github.com/LiveAsynchronousVisualizedArchitecture/lava/tree/master/TinyWindow
it does seem like the most obvious answer. right now I'll be adding the ability to enumerate through pixel formats. I'm thinking of storing it either in the monitor class or making it a struct and having the window or manager store the information in a list. lucky i have the superbible to help me out
you could change up the RGB | depth values in the tWindow constructor to see what works for you. you could debug GLFW to see what RGB|depth values it has picked for you and plug them into TinyWindow to hack it
That is true, and a good idea. It would at least get rid of one possible source of error.
is this what you see?
Close - it crashes on wglCreateContextAttribsARB because the function pointer itself is NULL.
if its null then It hasn't been loaded at all which means it's not supported. is the EXT version of the function NULL too?
Yes. It doesn't get to that point normally though, because wglGetExtensionsStringARB and wglGetExtensionsStringEXT are both NULL, which makes the function return. If I comment out the error check, all the calls to wglGetProcAddress return NULL.
are any of the other extensions being loaded? if none are that could mean the dummy context that I create in order to load these extensions may not be working on your setup
Right. None of the extensions load as far as I can tell. dummyDeviceContextHandle from GetDC() is not NULL however its unused struct member can't be read by the msvc debugger (should it contain something?)
wglCreateContext returns a non-null handle with unused set to 0, then wglMakeCurrent returns false.
None of these functions create a windows error from what I've seen.
ok by default the openGL version TinyWindow uses is 4.5. make sure your GPU can handle that. also change it from a core context to a compatibility context. just in case while im researching this
Ok. I have a 970, but I have been using glfw with 3.3 so it is certainly worth a try.
How do I change the version? From what I can tell these errors all happen before any version numbers are used.
the dummy context does'nt use version numbers because it need to use the old context creation system in order to load the extensions for the new context creation system that uses those numbers
That makes sense, but the crash comes from the extensions not loading, so I don't get to the point where I can choose the version.
you can change the verision in the constructor for the window class as glMajor and glMinor parameters
in Windows_CreateDummyContext can you do some error checks before and after the dummy context is made. maybe the dummy is invalid
I see the glMajor and glMinor variables in the tWindow constructor, but that is never hit.
I'm checking for windows errors before and after the GetDC(GetDesktopWindow()); line and not getting anything. dummyDeviceContextHandle isn't NULL so I'm not sure what else to check.
in CreateDummyContexts try this. if it hits the error message then im out of ideas. make sure to comment out the code between pfd.redBits to pfd.Depthbits. this should widen the pool for creating dummy contexts
void Windows_CreateDummyContext() { dummyDeviceContextHandle = GetDC(GetDesktopWindow()); PIXELFORMATDESCRIPTOR pfd; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24;
int LocalPixelFormat = ChoosePixelFormat(dummyDeviceContextHandle,
&pfd);
if (LocalPixelFormat)
{
if (!SetPixelFormat(dummyDeviceContextHandle, LocalPixelFormat, &pfd))
{
printf("Error: dummy context pixel format is invalid\n");
return;
}
}
glDummyContextHandle = wglCreateContext(dummyDeviceContextHandle);
if (!glDummyContextHandle)
{
printf("Error: dummy context creation failed\n");
return;
}
if (!wglMakeCurrent(dummyDeviceContextHandle, glDummyContextHandle))
{
printf("failed to make dummy context current\n");
return;
}
}
Ok, I will try this, though it may be a few hours later.
no worries i got to sleep in a few hours anyway
just checking in. how'd it go?
I wasn't able to get it to work with the minimal settings. I took another look at glfw's source and didn't see anything that jumped out at me as too different. I think the next step might be for me to step through glfw to see it work. If I do that, maybe I can learn a lot.
Ok i made another update that if the dummy context fails, then TinyWindow will create windows using the old fashioned method. I doubt this will solve the problem but now you should at lest still be able to work somewhat. plus some more smaller updates
Your new update works to get a window up for me. The window title works and closing the window works. The screen is white however, even though it looks like it should be clearing to 0.25 grey.
Also I put
Platform_InitExtensions(); on line 2568 to see if the extensions would load correctly and they did.
Edit: 2658
OK... that's interesting to note. it still works on my setup so I'm not sure what could possibly still be missing.
also line 2568? you put it inside the event handle case for WM_KILLFOCUS?
it seems to be an overall issue with pixel formatting. the only time I've really had a real issue with that stuff is with NVIDIA cards? is that what you run?
I got that very wrong, it should be 2658. I put it just after Platform_InitializeGL()
#if !defined(TW_USE_VULKAN)
Platform_InitializeGL(window);
Platform_InitExtensions();
#endif
ShowWindow(window->windowHandle, 1);
UpdateWindow(window->windowHandle);
I do have an nvidia card, but glfw works, so although there might be something fishy going on it can work somehow. Maybe I'll still step through glfw to see what pixel format it ends up using like you suggested.
in InitializePixelFormat() at line 2729 if the variable localPixelFormat is NULL then it is definitely related to pixel formatting issues. basically choosePixelFormat() uses the RGB/depth/stencil values that are parsed in and sifts through all the available PFD's to find the one that is closest to the one you pick and hand it ack to you. if that fails then there are definately no compatible PFDs for your GPU in that case
That comes back as 1 for me using your updates. I've tried to pay close attention to that and I don't think it ever gave back false.
One thing is that the following is able to use the main path that sets attributes, since the initialization enables the extensions to work and the extensions working enables the typical path to execute.
Platform_InitializeGL(window); Platform_InitExtensions(); Platform_InitializeGL(window);
does that run in your setup? if that's so it it the weirdest thing Iv'e seen in awhile. it does make me wonder why the dummy context is giving so much trouble for loading extensions when compared to your hack
It creates a window, but the window is still white, it doesn't clear to grey.
ok in the printMonitorInfo function in the examaple, on the line where the moniror's rendering device name is used, can you tell me if the rendering device is your GPU or your CPU? i think that maybe your comp is using the CPU which doesnt really support accelerated PFD's which is causing your window to render white
in creating the dummy context can you swap out PFD_GENERIC_ACCELERATED in line 2754 with PFD_GENERIC_FORMAT to see if that makes a difference
Here is the printMonitorInfo output:
I added PFD_GENERIC_FORMAT to 2754 (neither of the flags you mentioned are there by default), though it didn't change the result or output from printMonitorInfo.
I also stepped through glfw and looked at their pixel format descriptors.
Separately one thing I noticed is that we have been working with the pfd for the dummy context, but not the attributes used to create the final context if extensions are loaded.
well you have been talking about the extensions not being loaded the first time around after creating the dummy context so I'm trying to fix that issue first.
it could be that you have multiple monitors maybe but i only have 1 so i can't test dual screening.
you can mess with the PFD used for creating proper windows in line 2717 to see if that helps as well
That makes sense, thanks.
My thought is that if the backup method of creating a context works, maybe that should be the method of creating the dummy context so that the extensions will load. I haven't even worked out the differences between the two methods, so I have no idea if this is silly and missing a fundamental problem that needs to be addressed.
well a dummy is just supposed to be a skeleton of a window (it doesn't even need to be rendered at all. It's made to be used and immediately killed like a sacrificial lamb). it shouldn't really matter what the PFD is as long as it works and doesn't crash or anything so making the dummy could be done easily as a copy-paste job or via a single function so the same block of code doesn't show up twice. but maybe the PFD ins't the problem when it comes to your setup.
The only real issue is that it's not loading your extensions with the dummy context. it instead uses the backup one which are basically the same. but the backup PFD seems to be invalid as any calls to openGL are invalid due to the white window. The single common thread between the 2 could be the PFD
im gonna look closer at PFD's and how to enumerate through them to get one that will always work GLFW style. i just assumed wglChoosePixelFormat would always work right off the bat since it does that automatically.
OK looking at the documentation for DescribePixelFormat and ChoosePixelformat more closely it seems that ChoosePixelformat will pick the first compaitble PFD which may or may not have the necessary flags needed to be used by OpenGL.
GLFW uses DescribePixelFormat to iterate through all the compatible PFDs in order to weed out PFD's that don't play well with OpenGL so I'm going to integrate that as well. hopefully that will be the silver bullet to this mess
ok made a big update for you hopefully this helps in both dummy creation and regular window creation for you. this should find the closest possible PFD for you that is compatible with OpenGL.
Unfortunately the updated version has the same behavior.
:| ok another theory. unplug one of your monitors to see if that makes any difference
Interestingly, if I deactivate one of my monitors (not unplug), windowManager::monitorList ends up with a size of 5. The loop to print the the monitors crashes due to some of the fields being NULL.
Unplugging a monitor did not make a difference in the behavior, there is still a window created that stays white. The monitor list only has 1 element in this case though. One thing to keep in mind is that I still get a 'handle is invalid' windows error after creating the manager.
hrmm there are a few handles that could be invalid in the window manager including the device context and GLrenderingcontext handles but the fact that it seems to be invalid for both the dummy and a regular window tells me that it's most likely the GL rendering context handle.
could you step through the constructor and CreateDummyContext and see where exactly the error pops up? say after line 3033 and 1575 just to determine which one is the problematic handle
ok for the monitor bug you mentioned I've got an old monitor to debug with. if the monitor has been deactivated it should still show up in the mointer list but some of its variables will obviously still be NULL since the monitor is deactivated.
also monitorList should only have 2 members instead of the 5 you reported. I'm also looking for a way to recieve and process events when a monitor's settings have changed and exposing a callback specifically for that
I've had TinyWindow working with a previous version and msvc 2013. With the latest version combined with msvc 2017, it crashes on the following line:
glRenderingContextHandle = wglCreateContextAttribsARB(window->deviceContextHandle, NULL, attribs);
I've traced it back to where I think the problem starts - this line:
wglMakeCurrent(dummyDeviceContextHandle, glDummyContextHandle);
This returns 0, but does not set a windows error. The extension function addresses end up NULL and eventually it crashes on wglCreateContextAttribsARB(...) because the function address is NULL.
I've also noticed that there is minimal error handling. I used the following function that I found elsewhere to help debug this issue. It seems that there are dozens of windows functions that are not error checked, which I can understand for a prototype, but for the library to mature I think it will be very helpful.
auto GetLastErrorStdStr() -> std::string { DWORD error = GetLastError(); if (error) { LPVOID lpMsgBuf; DWORD bufLen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); if (bufLen) { LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf; std::string result(lpMsgStr, lpMsgStr+bufLen);
} return std::string(); }
include
define printWinError std::cout << "\n" << LINE << " windows error " << GetLastErrorStdStr() << std::endl;
Let me know if I can do anything else to help!