There are many different graphics technologies in Windows, and with Windows 7 we are adding to that collection with new technologies such as Direct2D and DirectWrite. Additionally, technologies such as GDI and GDI+ continue to be used in Windows software for many applications.

As we have mentioned before, these technologies were all designed with some set of scenarios and customers in mind at some point. And many of these technologies have enjoyed success and are used by a variety of applications, some of which have a history going back more than a decade. For these reasons and more, adopting new technology typically is not done with a brand new application from scratch. Normally there is an existing body of code that either needs to be ported to a new technology, or needs to work with the new technology as seamlessly as possible.

In this post I want to cover the concept of API interoperability. For the purposes of this post, this is defined as a point in one API where resources from another API can be used. Basically, this denotes a point where the two technologies can be ‘joined together’ and is an opportunity for different versions of the same technology to work together (for example, using D3D11 with D3D10), or for technologies that do similar things to work together (for example, drawing to a GDI surface with D2D). This capability to use APIs together has always existed with DirectX, but some of the mechanisms have been more efficient than others in the past.

This post is not meant to be exhaustive – each of these points can sometimes require some depth of learning to be harnessed effectively, and future blog posts and white papers will do that. The main goal is to highlight the places where our technologies work together and discuss the philosophy we have around that moving forward.

The current landscape of DirectX technology is vast. Below is a diagram that I have created to attempt to show both existing technologies (in orange), our new / evolved technology for Windows 7 (in blue) and show an interface or method that links them together wherever possible.

Interoperability diagram

Note that this “subway map” of DirectX APIs does not cover every single way of making them work together, just the main supported or advised ways of doing so. Most APIs have a way of reading and writing raw memory for surfaces, and this is always the most basic way of making two things work together. However, this method of interoperability has the weakness of not allowing good performance when video memory is brought into the picture. It also does not allow an application to take advantage of improvements in how technologies can work together over time.

There are some key concepts that should be gleaned from this diagram:

  • The legacy runtimes were not the best at working together. D3D10.0 had no way to talk with GDI. D3D10.0 and D3D9Ex could share surfaces, but they had to manually synchronize. This was a known pain point for developers and is hard to do, because basically you have two different runtimes both asynchronously communicating to the hardware and knowing the state of synchronization between two APIs is difficult.
  • The Windows 7 technologies are all linked in a common sense way. D2D was designed to consume WIC bitmaps easily and to draw DWrite text easily. D2D can render to D3D10.1 textures without doing any copying or GPU / CPU synchronization. And D3D10.1 and D3D11 can share surfaces between their devices without GPU / CPU synchronization. Going forward we want to keep our new technologies working together this way as a cohesive, componentized stack.
  • The new Windows 7 APIs can work together with our legacy APIs. They can all talk to GDI (with D3D runtimes doing this through DXGI). This is important because so many applications are still built with GDI, and working with GDI allows incremental use of the new technology as well as an easier port of existing technology if desired. Legacy D3D runtimes can share surfaces with the new runtimes if need be as well.

Hopefully the current state of affairs is clear – we are committed to making sure that our current APIs and technologies work together as well as they can. We know that ideally every single API will work well with any other API, but the reality is that time is limited and we chose to focus on getting the new APIs to work well with GDI, since this is a known point where people need interoperability to work. We will never reach the point where we have 100% mixing of any two APIs, because not all combinations equal sense – we want to invest more heavily in the areas that have the most demand.

There are many challenges in making interoperability fast, but there are three main factors that are responsible for creating bottlenecks:

  • Copying resources around in system memory – this eats memory bandwidth and CPU time, either limiting the performance or making an experience eat more resources than it should.
  • Moving content between the GPU and the CPU – this can tie up the system bus, and tie up resources in managing the copy. It normally also involves similar memory access problems to the normal copying.
  • Synchronizing GPU / CPU state – the normal mode of operation for GPU communication is asynchronous, because this increases performance by allowing batching up of commands. Synchronization involves flushing these commands and causing a CPU wait.

In the future our goal is to continue to make our technologies work better together at the API level, mainly through developing all of the components as a cohesive stack that works better together by design and works to remove the above bottlenecks as much as possible. This will be a challenge going forward, but designing this in at the beginning is easier than bolting it on later.

If there is a particular connection or set of connections in the above diagram that you would like to see more detail on, please leave a comment and let us know. More data about the detail that people want is very useful.