Justin's Code Haus
Ramblings of a compiler engineer

Tag: C++

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.

Screenshot

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class D3DRenderWidget : public QWidget {
  Q_OBJECT
  Q_DISABLE_COPY(D3DRenderWidget)
public:
  D3DRenderWidget(QWidget* parent = NULL);
  virtual ~D3DRenderWidget();
  virtual QPaintEngine* paintEngine() const { return NULL; }
protected:
  virtual void resizeEvent(QResizeEvent* evt);
  virtual void paintEvent(QPaintEvent* evt);
};

(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:

1
2
3
4
5
6
7
8
D3DRenderWidget::D3DRenderWidget(QWidget* parent)
  : QWidget(parent) {
  setAttribute(Qt::WA_PaintOnScreen, true);
  setAttribute(Qt::WA_NativeWindow, true);

  // Create Device
  createDevice();
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
swapChainDesc_.BufferCount = 1;
swapChainDesc_.BufferDesc.Width = width();
swapChainDesc_.BufferDesc.Height = height();
swapChainDesc_.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc_.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc_.SampleDesc.Count = 4;
swapChainDesc_.SampleDesc.Quality = 0;
swapChainDesc_.Windowed = true;
swapChainDesc_.OutputWindow = winId();
swapChainDesc_.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc_.BufferDesc.RefreshRate.Denominator = 1;

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:

1
2
3
void D3DRenderWidget::paintEvent(QPaintEvent* evt) {
  render();
}

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:

1
2
3
4
5
6
7
8
void D3DRenderWidget::resizeEvent(QResizeEvent* evt) {
  releaseBuffers();
  swapChain_->ResizeBuffers(1, width(), height(), swapChainDesc_.BufferDesc.Format, 0);
  swapChain_->GetDesc(&swapChainDesc_);
  viewport_.Width = width();
  viewport_.Height = height();
  createBuffers();
}

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.

Posted Thu 16 February 2012 by Justin Holewinski in Programming (Direct3D, Qt, Windows, C++)

The Beauty of C++ Templates

Every so often, I'll get a random C++ question from a friend or colleague.  Most of the time the answers are trivial, at least for someone who has a history with the language.  Other questions make me stop and ponder, searching for the best "C++" way to do something.  Yesterday, the question was simple and the solution turned out to be equally simple, but getting to the solution made me stop and appreciate some of the cool things one can do with C++ templates.

The Problem

The problem was simple.  Suppose you have a C++ template class/struct that is parameterized by a single type, e.g.

template<typename T>
class my_data {
  // ...
private:
  T element_;
};

The Solution

Now, the question is, "how do I write a method for this class/struct that maps the type of T to an enumeration value?"  For context, the real problem involved mapping T to an MPI data type, e.g. (float -> MPI_FLOAT), (double -> MPI_DOUBLE), etc..

The first thought for anyone familiar with containers may be to explicitly generate a map, e.g. std::map in this case, to hold all possible mappings from the C++ type (via typeid()) to the MPI type (really just an integer).  Such a solution is certainly valid and may be the best way to approach the problem in another language such as C# or Java.  After pondering the "C++" solution to the problem for a few minutes, my colleague and I came up with a fairly elegant solution involving templates.  Or, at least I found it quite elegant.

/**
 * This struct wrappers the MPI data type value for the given C++ type.
 *
 * Any valid MPI data type value must have a corresponding explicit template
 * instantiation below.
 */
template<typename T>
struct mpi_type_wrapper {
  int mpi_type;
  mpi_type_wrapper();
};

// Explicit instantiation for `float'
template <>
mpi_type_wrapper::mpi_type_wrapper()
: mpi_type(MPI_FLOAT) {}

// Explicit instantiation for `double'
template <>
mpi_type_wrapper::mpi_type_wrapper()
: mpi_type(MPI_DOUBLE) {}

The mpi_type_wrapper struct is a convenient way to convert an arbitrary C++ type to an equivalent MPI type.  All one has to do is declare a local variable of type mpi_type_wrapper<T> (with appropriate T) and read the value of its mpi_type field.  Of course, none of this is specific to MPI in any way.  The only requirement is that an explicit instantiation of the constructor must be provided for any C++ types that are to be converted.

Why This Solution?

This solution strikes me as elegant for two reasons.  First, it is a solution that would be difficult, if not impossible, to express in many other languages.  Second, and most interesting to me, there is no run-time overhead associated with this solution.  You can even compile this with RTTI turned off.  Any reasonable compiler automatically inlines the appropriate constructor, then constant propagation replaces any uses of the mpi_type field with the appropriate MPI_* enumeration value.  There is no memory overhead associated with explicitly keeping a map at run-time, nor any time overhead of performing a map look-up.  The final code just uses the constant value!  If you do not believe me, check out this example:

/**
 * Some template class that needs to know the MPI_DataType value for its
 * template parameter type.
 */
template<typename T>
struct some_type {
  void printType() {
    mpi_type_wrapper<T> wrap;

    printf("My Type: %d", wrap.mpi_type);
  };
};

int main() {
  some_type<float> floatClass;
  some_type<double> doubleClass;

  floatClass.printType();
  doubleClass.printType();

  return 0;
}

And the generated code?

_main:
  pushq %rbx
  leaq L_.str(%rip), %rbx
  movq %rbx, %rdi
  xorl %esi, %esi
  xorb %al, %al
  callq _printf
  movl $1, %esi
  movq %rbx, %rdi
  xorb %al, %al
  callq _printf
  xorl %eax, %eax
  popq %rbx
  ret

Conclusion

While this example is probably trivial for most experienced C++ programmers out there, including myself, I always find myself stopping and appreciating such solutions.  In this case, C++ templates provide such an elegant and efficient solution that I cannot help feeling giddy.

Posted Fri 01 April 2011 by Justin Holewinski in Programming (C++)