We have a 3D rendering window created using GLFW and we want to use QWebkit for displaying a QWebPage inside the rendering (aka render the QWebPage to an OpenGL texture). Using only the CPU version is too slow and Qt supports rendering QWebkit into QOpenGLFramebufferObjects (using QOpenGLPaintDevice).
However, doing so requires the creation of a QOpenGLContext (which requires its own window and so on), eventually interfering with our whole application. (Switching between GLFW and Qt Context also causes an infinite amount of GL_INVALID_OPERATIONs)
Best case solution: we get Qt to use the GLFW Context.
Code example:
QOpenGLFramebufferObject qfbo(mWidth, mHeight); //< this crashes because he will implicitly try to get QOpenGLFunctions which gets the default context which is null
qfbo.bind();
QOpenGLPaintDevice paintdev(mWidth, mHeight);
QPainter painter(&paintdev);
painter.beginNativePainting();
mPage->mainFrame()->render( &painter );
painter.endNativePainting();
So here are some questions:
is it possible to get Qt to use the GLFW OpenGL context?
if not, how can we switch between GLFW context and Qt context? (using texture sharing for transferring the rendered QWebPage)
if all of this is impossible, is there a free Webkit project with 64bit, Windows/Linux/Mac support that can render using OpenGL?
#Sebastian Cabot wrote:
You can't directly mix the two context objects using QT. QT is great but in order to keep itself portable it also has some limitations - mainly accessing the low level handles of the objects and manipulating them directly. So Even trying to use a QOpenGLContext from a different thread then the one it was created in will fail. And in order to use any of the QT OpenGL wrappers you will need a valid QOpenGLContext current. So what you want is not possible without hacking into the QT implementation.
Related
I'm trying to port the code from https://github.com/eryar/occQt to gtkmm, by creating a custom widget and overriding the Gtk::widget::on_realize() method like
void OccView::on_realize() {
// Create Aspect_DisplayConnection
Handle(Aspect_DisplayConnection) display_connection = new Aspect_DisplayConnection();
// Get graphic driver if it exists, otherwise initialize it.
Handle(Graphic3d_GraphicDriver) graphic_driver;
if (!graphic_driver) {
graphic_driver = new OpenGl_GraphicDriver(display_connection);
}
// Get window handle. This returns something suitable for all platforms.
Window x_window = GDK_SURFACE_XID(get_native()->get_surface()->gobj());
// Create window for platform.
Handle(Xw_Window) xw_window = new Xw_Window(display_connection, x_window);
// Create V3dViewer and V3d_View
mViewer = new V3d_Viewer(graphic_driver, Standard_ExtString("viewer3d"));
mView = mViewer->CreateView();
// Set window for the view
mView->SetWindow(xw_window);
if (!xw_window->IsMapped()) {
xw_window->Map();
}
// Create AISInteractiveContext
mContext = new AIS_InteractiveContext(mViewer);
// Set up lights etc
mViewer->SetDefaultLights();
mViewer->SetLightOn();
mView->SetBackgroundColor(Quantity_NOC_BLACK);
mView->MustBeResized();
mView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_ZBUFFER);
mContext->SetDisplayMode(AIS_Shaded, Standard_True);
// Call base method
Gtk::Widget::on_realize();
}
but the Gtk::Window stays empty after appending the OccView object. What am I doing wrong? Is there a working example on how to integrate the Opencascade V3d_View into a Gtk::Widget, or the gtkmm framework in general?
I haven't used GTK since university, so my experience is pretty basic here.
There are two basic approaches for embedding OpenGL-based viewer into GTK:
Ask OCCT to create OpenGL context for a native window taken from a normal Widget or entire window.
Wrap existing OpenGL context created by GUI library itself, e.g. Gtk::GLArea.
Your current code tries to follow the first approach used by conventional samples for Qt Widgets and MFC coming with OCCT. I guess it should be feasible, but implies some limitations and issues with mixing GTK widgets, as GTK will not be aware of OpenGL usage.
In contrast, Gtk::GLArea looks like a "modern" way for embedding OpenGL renderer designed by GTK developers and expected to work transparently.
Therefore, I've tried implementing a Hello-World sample using Gtk::GLArea (based on a development snapshot of OCCT 7.6.0dev):
https://github.com/gkv311/occt-samples-gtk
I don't bring the whole code of the sample here, as it is quite large in size.
Putting OCCT Viewer into Gtk::GLArea includes some tricky parts like:
Wrapping native Window into Aspect_Window (it could be also Xw_Window like in your sample, more general Aspect_NeutralWindow or another subclass).
Wrapping OpenGL context created by Gtk::GLArea into Aspect_RenderingContext/OpenGl_Context.
Wrapping offscreen buffer (FBO) used by Gtk::GLArea for rendering content into OpenGl_FrameBuffer.
Putting all viewer redraws into dedicated callback for Gtk::GLArea::signal_render().
Redirecting user input to viewer (with help of AIS_ViewController).
It is important to note, that GTK may be run in different context:
X11 server - X Window is created and GLX is used for OpenGL.
This is default OCCT configuration for Linux;
Wayland - native window is not X Window and EGL is used for OpenGL context.
OCCT does support EGL but as a dedicated configuration as alternative to GLX, while GTK handles this in runtime somehow. In addition, OCCT does not (yet) provide any wrapper for a Wayland native window, though it might be not critical for using.
GTK also has an option to use OpenGL ES instead of OpenGL.
Initially I expected Gtk::GLArea to work natively, but instead a very basic sample (without OCCT viewer) displays artifacts to me (widgets randomly blacked) on Xubuntu 18.04, though it works as expected on Ubuntu 21.04 (within Xorg session). I don't know if it is a bug fixed in GTK implementation, or there is something that should be fixed in a sample to workaround problem on older Linux.
I want to get the unity context into opengl so I can display a unity render texture in an opengl glfw window. I tried using
oldContext = glfwGetCurrentContext(); but the value of oldContext is just null.
I am trying to use the low-level native unity plugin and Texture.GetNativeTexturePtr
Any help would be greatly appreciated!
OpenGL context cannot be queried like OpenGL state related objects via some glGet* API.Context is not part of OpenGL API,it is a part of the system you're running on and it exists to allow you maintaining of OpenGL state and issue command to the driver. You must access a system specific handle that points to the context via system specific API.On Windows (WinGDI)that's would be
HGLRC wglGetCurrentContext();
On linux see related GLX API. You need to find functions to access GLXContext
I did it once in Unity3D (framebuffer readout plugin). But it used Unity's OpenGL or DirectX context to issue API commands only.
Also,I am not sure you can 'inject' or share a context for a window that doesn't own that context. You see, when you (or Unity) init display it creates context and related GL resources,like the default FBO with all required attachments on its own,and that FBO is mapped to some system resource(device) which takes actually care of presenting those pixels on the screen. Therefore, I am not sure display context can be moved from Window to Window in the same manner that a context can be shared between threads.(But I can be wrong on this one)
You can create your plugin Window on some thread,with its own GL context. Then create and share a texture object between those two. Remember, GL textures are shareable. If you copy contents from Unity's screen FBO into that texture,then you can copy it into your plugin's screen FBO from that texture as well.
Btw,look at this SO question .You can see there vendor specific GL extensions which allow copying data into texture from different contexts without requiring shared context,share lists setup.
Regarding why GLFW returns you nullptr. In your example you use GLFW library.
glfwGetCurrentContext()
But if you look at the source code,you see this:
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.contextSlot);
}
Which probably means that it retrieves a pointer to GLFWWindow from its own cache and not from the system.And if you didn't create that context via GLFW,you won't get any valid pointer. So try working directly with your system related API as explained above.
I'm creating an application, which interacts with OpenGL via QOpenGL* classes. The graphics is shown through a QOpenGLWidget, which is placed in a UI-form.
Now, there is a library for CAD purposes (Open CASCADE), an OpenGL interface of which requires a handle to the render window. The question is: can I somehow say the library to render everything to the mentioned widget?
In other words, is there a way to interpret the widget as a native, probably, platform-specific (HWND here) window, so that the library renders its own stuff exactly there?
Thanks
QOpenGLWidget is not the same thing as QGLWidget.
The classical approach for embedding OCCT 3D viewer, which you can find in Qt IESample coming with OCCT, creates QWidget with unique window handle flag, takes this window handle and ask OCCT to take care about OpenGL context creation for this window. This is most straightforward, robust and portable way with one limitation - Qt will not be able drawing semitransparent widgets on top of this QWidget. This is not a limitation of OCCT, but rather limitation of Qt Widgets design.
QOpenGLWidget was intended to solve this limitation by allowing to mix custom OpenGL rendering and normal widgets. The integration of external OpenGL graphics engine, however, became more complicated and fragile. It is not very helpful stealing winId() from QOpenGLWidget, as rendering content is expected to be drawn not into window itself, but rather into OpenGL framebufer object (FBO), created by QOpenGLWidget - see QOpenGLWidget::defaultFramebufferObject() property.
External renderer is expected to render into this FBO for proper composition of Qt widgets. Luckily, OCCT is flexible enough to allow such integration. Unluckily, such integration requires some knowledge of OpenGL, as well as its usage by Qt and OCCT.
For that, you need to ask OCCT wrapping OpenGL context already created by Qt (for that V3d_View::SetWindow() provides an optional argument of type Aspect_RenderingContext, which corresponds to HGLRC on Windows and can be fetched using wglGetCurrentContext() within rendering thread) as well as FBO created by QOpenGLWidget (for that, OCCT provides OpenGl_FrameBuffer::InitWrapper() and OpenGl_Context::SetDefaultFrameBuffer() methods, as well as OpenGl_Caps::buffersNoSwap flag to leave window buffer swapping management to Qt).
OCCT doesn't come yet with a sample using QOpenGLWidget, but you can find also qt/AndroidQt sample implementing similar thing for embedding OCCT 3D Viewer into QtQuick application.
After some investigation, I found that method QOpenGLWidget::winId() returns the correct handle. It's been found out only now, because the rendered scene disappeared immediately, leaving a black picture instead. However, when the viewport is resized, the scene returns back (and disappears again, though). Looks like Open CASCADE has problems with Qt 5 OpenGL implementation, since QGLWidget didn't have such problems, as far as I know.
We have a QWidget based application that was previously using a QWindow for OpenGL rendering. To fit that window in our application we had to use
QWidget QWidget::createWindowContainer(QWindow);
Previously we only used external to Qt OpenGL libraries for rendering.
We have a desire to switch from using QWindow to some kind of QWidget for compatibility with touch gestures, and generally better overall compatibility with the rest of our application. The latest recommended OpenGL compatible QWidget seems to be QOpenGLWidget, so we are trying to use that.
glContext is an OpenGLContext that we manage ourselves.
The problem now is that QOpenGLWidget is not a QSurface, so I cannot call
glContext->makeCurrent(this);
to make the context current on my custom QOpenGLWidget like we could before with our custom QWindow and our own OpenGLContext.
If I try to use QOpenGLWidget::makeCurrent(); then this uses the wrong context and tries to do stuff with some magical QT handled context or something I don't understand.
The result is that after creating our OpenGLContext when we try to call
glFunctions = glContext->versionFunctions<QOpenGLFunctions_3_3_Core>();
if(!glFunctions->initializeOpenGLFunctions())
printf("Could not initialize OpenGL functions.");
It always fails to initialize the OpenGL functions.
I have been reading over all the other resources I can find on the subject and came across this older Stack Overflow question that was similar:
QOpenGLWidget with shared OpenGL context?
The answer to that question did not solve my issue because we are using QApplication, not QGuiApplication as this is a QWidget based application.
QGuiApplicationPrivate::init() is never called and the QOpenGLContext::globalShareContext() returns a null pointer since it is not initialized.
Unfortunately I cannot wait for QOpenGLWidget::initializeGL() to be called to initialize the QT managed OpenGLContext since we already have lots of OpenGL resources over various classes that attempt to get initialized before that.
Has anyone else come across this same problem?
Any suggestions?
I am doing a little guess work here.
Probably your OpenGL is defaulting to ANGLE.
And your previous application OpenGL calls are platform specific OpenGL API.
try setting below attribute to your QApplication object.
appObject->setAttribute(Qt::AA_UseDesktopOpenGL, true);
then try calling
QOpenGLWidget::makeCurrent();
If things are still not working, configure your QT libraries for desktop OpenGL.
configure -opengl desktop
the below link gives you some information on Qt approach to OpenGL.
http://doc.qt.io/qt-5/windows-requirements.html
Put in comments, if this is not helping you, will delete the answer.
We have an OpenGL Application (using Ogre3d and SDL, not directly calling OpenGL) and we are trying to change the Resolution at runtime. It seems that we need to re-initialize our OpenGL context with the new Resolution but a number of items are breaking along the way. On Linux it seems to work for a while, then we get graphical corruption on screen. On Windows it simply crashes the next time we try to render a frame. We have forced the reloading of textures in Ogre, and if we rendering nothing but textures (no 3d models) then this works fine, but any 3d models cause a crash and reloading before rendering them has no effect.
Here is a link to an in depth explanation of Ogre3d calls we are doing: http://www.ogre3d.org/forums/viewtopic.php?f=2&t=62825
All we really need to know is, When re-initializing an Opengl context what resources need to be restored?
Why does adjusting an OpenGL context affect other resources? Is it the way OpenGL works, or did one of the libraries we use introduce this issue? Could we have added this issue without knowing it?
Did you have a look at this forum thread ?
SDL seems to destroy the OpenGL when changing resolution. In this case, all you GL resources are destroyed with the context.
One possible solution would be to create another 'dummy' GL context, sharing resources with you 'real' GL context, and to keep it alive with SDL destroys the 'main' context. This way most of your resources should survive.
Note that some resources can't be shared, textures and VBO are fine, but VAO can't.
OpenGL support was added SDL after its surface code had been established. That's why changing the size of a SDL window is destructive. You were pointed to OpenGL context sharing and its caveats. However I'd avoid the problem alltogether by not using SDL for creating an OpenGL window. You can use all the other facilities SDL provides without a window managed by SDL, so the only thing that would change is input event processing and how the window's created. Instead of SDL I'd use GLFW, which like SDL requires you to implement your own event processing loop, so using GLFW as a drop-in replacement for OpenGL window and context creation is straightforward.