Direct3D 11 with Qt 4

(If you’re in a hurry, the full source can be found on my BitBucket account)

When it comes to GUI frameworks for C++, it’s very hard to beat Qt.  It’s modular, easy to use, and available on practically any desktop system (and even a few mobile systems).  The MOC’ing can get a bit annoying, but IDE and command-line support is very mature at this point.  However, only OpenGL is supported currently for real-time 3D rendering. If you want to render to a Qt widget from a Direct3D 11 device, you end up having to do a lot of setup yourself.

Unfortunately, there is not a lot of information out on the internet about setting up Direct3D to play nice with Qt.  Most of the information is either out-dated, or only applies to Direct3D 9.  Lately, I’ve been playing around with this and I want to share my method for combining Direct3D 11 and Qt.

 

Creating a Widget

To start, we define a new widget sub-class specifically for Direct3D 11 rendering. On the Qt side, the key to eliminating flickering or UI artifacts is the paintEngine() method.  We need a way to tell Qt that we want complete control over drawing for our widget, so we can override paintEngine() in our widget definition:

(Note that for ease of viewing, all of the fields have been removed from this code snippet)

We also need to set a few attributes on our widget, as shown in the constructor:

First, we tell Qt that we do not want it to do any draw buffering for us. Second, we require a native window handle for our widget. Otherwise, Qt may re-use the same native handle for multiple widgets and cause problems for our Direct3D rendering. You may have also noticed the createDevice() method call; this will be explained in a bit.

 

Creating the Direct3D 11 Device

Now that we have a basic widget that can support Direct3D rendering, we can initialize the Direct3D 11 device we want. This procedure is mostly identical to setting up Direct3D in a raw window. The only difference is that we must use the width(), height(), and winId() methods to return the widget size and native window handle, respectively:

Everything else remains the same… pretty easy, huh? :)

 

Handling Paint Events

Remember the paintEvent override from the widget class definition? We can simply implement it with a call to some rendering function:

Here, render() is just some arbitrary method that uses the Direct3D 11 device to render something to the primary swap chain.

 

Handling Resize Events

Resize events are perhaps the hardest events to handle when integrating Direct3D 11 and Qt. To resize our swap chain, we need to release all device-allocated resources, and reallocate them. The procedure I follow is:

We start by releasing all of the buffers we had allocated (vertex buffers, index buffers, shaders, textures, etc.). We then issue a resize request to the swap chain, resize our rendering viewport, and then recreate all of our needed buffers. In this snippet, releaseBuffers() will call Release() on all buffers, and createBuffers() will create all of the needed resources (again).

It would probably be easier to just allow the swap chain to grow and just adjust the viewport if the widget shrinks, but this method shows how to keep the swap chain the exact same size as the widget.

 

Conclusion

At this point, you should have a functional Direct3D 11 rendering context for a Qt widget. For brevity, I have omitted most of the Direct3D initialization code (this can be found in many places on the web).

If you want to check out the complete sample program, it is located on my BitBucket account. To build it, you need a relatively recent Qt release, the DirectX SDK, and the Qt Visual Studio Add-in.

This entry was posted in Direct3D, Qt, Windows. Bookmark the permalink.

10 Responses to Direct3D 11 with Qt 4

  1. Mikhail says:

    Very good sample!
    But the question how i can paint widgets over directx widget with transparent background?
    Thank you for you attention!

    • ChenA says:

      mikhail, did you get the answer?
      i want to use qt in the game for gui.

      • Justin Holewinski says:

        I’m not sure you can do this in a reliable way. If you can force the widget to paint itself after the swap chain presentation, then maybe it would work. You would have to manually control the widget draw order and use blocking Present() calls.

        You’re probably better off with a Direct3D-based GUI if you want to draw over the rendered image.

  2. Michael says:

    Hi, thanks for this sample.

  3. Jack says:

    Hello,
    Just wondering how I can compile your source code with QT statically linked. I am using VS2010 and C++.
    Thanks
    Jack

    • Justin Holewinski says:

      I do not know of any reason why this would not work. You should be able to just link with the static libs instead of the dynamic libs.

      • Jack says:

        I tried qtmaind.lib and qtmain.lib to no avail.
        I’ve got link time error known as

        error LNK2001: public: static struct QMetaObject const QWidget::staticMetaObject” (?staticMetaObject@QWidget@@2UQMetaObject@@B)

  4. Marcel says:

    Hi, great sample but I was wondering if and how it were possible to not make the entire canvas the rendered window but define an area on the application’s surface as the render window. I’m trying to build an editor interface.

    • Justin Holewinski says:

      There is nothing special about the setup here. You can parent the QWidget into anything you wish, as long as the QWidget uses the following attributes:

      setAttribute(Qt::WA_PaintOnScreen, true);
      setAttribute(Qt::WA_NativeWindow, true);

      To build up an editor interface, you just use the D3DRenderWidget (or a subclass) wherever you want to render in the interface.

  5. Chris says:

    Hi, I develop an Qt5 3d editor and tons of resources are loaded at runtime. I don’t want to release all my resources when my D3D-Widget is resized. Do you have an idea how I can avoid that?
    Thanks, Chris

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>