melowntech / vts-browser-cpp

VTS Browser C++ library
BSD 2-Clause "Simplified" License
53 stars 19 forks source link

vts-browser-qt app is crashing after launch. #7

Closed VrushalNanavati closed 4 years ago

VrushalNanavati commented 4 years ago

The vts-browser-qt sample is crashing while making any OpenGL call. In my case it is crashing at glBindBufferBase(GL_UNIFORM_BUFFER, index, ubo); call.

I'm using, Qt5.13.0 VS2017

Here are a few logs from command line for your reference.

2020-03-21 01:00:47 I3 [21536(0)]: Creating map {mapApiCpp.cpp:vts::Map::Map():137} ARB::createContext: wglCreateContextAttribsARB() failed (GL error code: 0x502) for format: QSurfaceFormat(version 3.3, options QFlags(DebugContext), depthBufferSize 0, redBufferSize -1, greenBufferSize -1, blueBufferSize -1, alphaBufferSize -1, stencilBufferSize 0, samples -1, swapBehavior QSurfaceFormat::DefaultSwapBehavior, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::CoreProfile), shared context: 0x30000 (The operation completed successfully.) GDI::createContext: wglShareLists() failed. (The requested resource is in use.) 2020-03-21 01:00:49 I3 [21536(0)]: Mapconfig is available. {map.cpp:vts::MapImpl::prerequisitesCheck():248} 2020-03-21 01:00:50 I3 [21536(0)]: Mapconfig is ready. {map.cpp:vts::MapImpl::prerequisitesCheck():281} 2020-03-21 01:01:10 E3 [21536(0)]: OpenGL: <1282>, , , , <Error has been generated. GL error GL_INVALID_OPERATION in BindBufferBase: (ID: 3981759341) Generic error> {log.cpp:vts::log():94}

I think the context is not being set properly in the thread making OpenGL draw calls. (Just a guess I'm not an expert in OpenGL.)

Can anyone please guide if I'm missing something?

malytomas commented 4 years ago

Hi, indeed the logs says wglCreateContextAttribsARB failed. I guess that it has created context for old version of OpenGL, but VTS requires at least 3.3. Please make sure that your GPU supports the required version. Also, if you have switchable graphics cards (this is common on laptops), make sure that the driver is configured to use the dedicated gpu for all vts applications. I will need more information in case this does not help. Let me know.

VrushalNanavati commented 4 years ago

Hello @malytomas Thanks for your answer.

I'm not sure about the old OpenGL version context creation, because other vts apps are working just fine. It's just the vts-browser-qt app which is failing in my case. Is there any possibility of something's being wrong with QT?

Here is my laptop configuration (Windows), Processor - Intel(R) Core(TM) i7-7700 HQ. Internal Graphics - Intel(R) HD Graphics 630 Additional Graphics - NVIDIA GeForce GTX 1050 Ti

I've all the latest drivers installed. (And I think they support OpenGL 3.3) As per your suggestion, I went to the NVIDIA control panel and used the NVIDIA graphics for all the vts applications. But, still, I'm getting the same error. (I tried restarting my laptop as well)

Could you please let me know what other information you need for the investigation?

malytomas commented 4 years ago

other vts apps are working just fine.

Good, this narrows the problem down a lot.

Here is my laptop configuration (Windows), Processor - Intel(R) Core(TM) i7-7700 HQ. Internal Graphics - Intel(R) HD Graphics 630 Additional Graphics - NVIDIA GeForce GTX 1050 Ti

Do you, by any chance, have multiple monitors connected? My quick search on QT issues with multiple gpus has shown that is a frequent problem. Such as https://bugreports.qt.io/browse/QTBUG-50371 (the title states amd, but comments also mention nvidia). Please try it with just one monitor connected.

Could you please try different qt application, eg. the hellogl, and possibly modify it to request opengl 3.3? If that works, another test would be with two shared contexts (I will guide you if need be).

The goal here is to determine whether the problem is in VTS or QT.

VrushalNanavati commented 4 years ago

Hello @malytomas,

I'm using only one monitor(laptop screen) I also tried the QT sample by creating the OpenGL 3.3 version context. It works just fine. (It doesn't seem like a Qt problem to me now.) Could you please provide more details on the test with two shared contexts?

Thanks.

malytomas commented 4 years ago

Hi, can you try adding this:

QGuiApplication::setAttribute(Qt::AA_UseDesktopOpenGL);

right before this:

https://github.com/melowntech/vts-browser-cpp/blob/110fe9453f40b8d18451bafc272f454e84bed115/browser/src/vts-browser-qt/main.cpp#L35


If that does not help, please add some code after this:

https://github.com/melowntech/vts-browser-cpp/blob/110fe9453f40b8d18451bafc272f454e84bed115/browser/src/vts-browser-qt/gpuContext.cpp#L47

to print the renderer string etc so that we know what we are dealing with:

    setFormat(surface->format());
    create();
    auto fnc = functions();
    const std::string vendor = reinterpret_cast<const char*>(fnc->glGetString(GL_VENDOR));
    const std::string renderer = reinterpret_cast<const char*>(fnc->glGetString(GL_RENDERER));
    const std::string version = reinterpret_cast<const char*>(fnc->glGetString(GL_VERSION));
    qDebug() << "OpenGL vendor: " << vendor << " "
             << "renderer: " << renderer << " "
             << "version: " << version;
    if (!isValid())
        throw std::runtime_error("unable to create opengl context");
    current(true);
VrushalNanavati commented 4 years ago

Hi @malytomas,

I added following snippet,

QGuiApplication::setAttribute(Qt::AA_UseDesktopOpenGL);

But still getting the same error.

I copied the 2nd code snippet in GL::initialize(), but fnc->glGetString() methods are failing, I think that make sense, because in main thread, the gl functions are loaded after gl->initiaize() call. as shown below,

gl = std::make_shared<Gl>(this);
gl->initialize();

openglFunctionPointerInstance = gl.get();
vts::renderer::loadGlFunctions(&openglFunctionPointerProc);

then I added the scond code snippent after vts::renderer::loadGlFunctions() call and I'm getting follwoing line printed on the console.

OpenGL vendor: NVIDIA Corporation renderer: GeForce GTX 1050 Ti/PCIe/SSE2 version: 3.3.0 NVIDIA 441.872020-03-31

I think the first context is being created correctly, but the second context creation(which is in separate thread) is failing.

void MainWindow::dataEntry()
{
    vts::setLogThreadName("data");
    gl2 = std::make_shared<Gl>(this);
    gl2->setShareContext(gl.get());
    gl2->initialize();
    vts::renderer::installGlDebugCallback();
    map->dataAllRun();
}

gl2->initialize(); gives those failed context creation logs.(ARB::createContext: wglCreateContextAttribsARB() failed) If you scroll the logs a bit you will notice one more error, GDI::createContext: wglShareLists() failed. (The requested resource is in use.) I think it has to do with context sharing within two threads, not really context creation, because first context in main thread (gl) is being created properly without any error.

malytomas commented 4 years ago

Thanks for the experiments. The vendor and version are good.

I did not notice the wglShareLists before. I have made a branch: https://github.com/melowntech/vts-browser-cpp/tree/fixingQt The two contexts are both created in the main thread and then one is transferred to the data thread. I have also added the code to force the use of opengl, as mentioned in the previous message. I really hope this will work. Please, try it and let me know.

VrushalNanavati commented 4 years ago

Thanks a lot, @malytomas Now it's working well. (I think we can close the issue.)

By the way, what was the exact issue? (I'm learning OpenGL, so just curious ;D)

  1. We can't create two contexts in different threads?
  2. Or we can't share the main thread context in a different thread?
  3. I read somewhere that unless we unset current context from the main thread, we can't make another context current in other thread. (I tried to unset main thread context but didn't work.)

Thanks again.

malytomas commented 4 years ago
1. We can't create two contexts in different threads?

We can.

2. Or we can't share the main thread context in a different thread?

Generally, we can.

3. I read somewhere that unless we unset current context from the main thread, we can't make another context current in other thread. (I tried to unset main thread context but didn't work.)

Each context can be current (associated) in at most one thread at a moment. (Each thread can have at most one context current in it too, but that is not relevant here.)

The problem was that the function wglShareLists (which is part of Microsoft Windows's window management, not part of OpenGL) has additional restriction, that the context we want to share with must not be current (associated) in any thread at the moment.

This restriction would be easily satisfied even if we created the contexts in separate threads, but it would require additional synchronization between the threads (eg. a mutex or a barrier). It seems easier to me to just create them upfront and make them current (associated) later.

Unfortunately, Qt has some additional shenanigans too, such as the moveToThread function, which is needlessly complicated thing and forced me to use QThread instead of std::thread. But that is another story entirely :D

Anyway, I am glad it is working for you now. And thanks for letting us know about the issue.