Just as some bloggers record unboxing of products, I'd like to share my first impressions from playing around with Direct2D library. What is it? As you can guess from its name, it is a library from Microsoft for efficient, hardware-accelerated drawing of immediate-mode 2D graphics. It is successor of the old GDI, as well as GDI+. It is native library, object-oriented, based on COM. It works on Windows 7, as well as Windows Vista (after installing SP2 and Platform Update) and Windows 2008. The API seems modern, clean and very elegant, much like Direct3D 10/11. But of course it could be just a matter of taste. You can find its documentation, as well as headers and libraries in DirectX SDK. Docs say something about Windows 7 SDK, so probably it's there too.
What can it interop with? You can create a render target that will send the graphics to either a window (using HWND), a GDI canvas (HDC), DXGI surface (interop with Direct3D 10/11) or WIC Bitmap. Interop with GDI is also possible in the opposite way - you can obtain a HDC from D2D render target. Microsoft advices using WIC (Windows Imaging Component) for loading bitmap files. Another important library that cooperates with Direct2D is DirectWrite, which enables text rendering.
I didn't find any good tutorial about Direct2D, but I haven't look for it very hard either. I think the official documentation is good enough teaching all aspects of the library. After reviewing the documentation, I'm very impressed not only by the looks of the API, but also by the list of features is supports, like:
Uses floats everywhere, as coordinates and colors. Rectangles use (left, top, right, bottom) representation, not (left, top, width, height) like many GUI API-s.
Arbitrary 2D affine transforms using 3x2 matrix.
Alpha blending, with straight or premultiplied alpha.
Gamma correction and linear space.
Alpha-only textures (A8 format).
No separate brush and pen objects to be used used simultaneously like in GDI. There is only brush in D2D - a solid one, the one with linear gradient, radial gradient or created from bitmap. It is used to either fill the surface of a shape or outline it, depending on the draw call.
No selecting "current" brush, no tons of states to switch like in OpenGL or Direct3D 9. You fill in a structure with the description of desired parameters, create an object from it and the object is quite immutable.
Clipping with a shape, masking with alpha channel of any image.
Uses GPU if possible, falls back to software rendering if not. Even then the performance is promised to be better than GDI+.
Manipulating and querying arbitrary 2D shapes (made of lines and bezier curves), including: transforming with a matrix, CSG (union, intersection, difference, xor), outlining, widening, simplification, triangulation, computing area and length, interpolating point and tangent vector along the geometry, hit-testing point against interior or border (with given stroke width), testing if two geometries overlap or if one fully contains another. Wow, that's a lot! I think D2D could serve as a geometric math library :)
Things I don't like so far about the library:
I can't find blending modes anywhere! Is there really only alpha-blending available (and additive blending with the help of premultiplied alpha)? Libraries that use integers like GDI have bitwise operations (including the famous XOR used to draw and un-draw frames). Libraries that use floats like Direct3D have addition, subtraction, multiplication etc. Some API-s even have both, like OpenGL ES. Direct2D has none? WTF?! (Much like GDI+)
Lost device horror is back! ID2D1RenderTarget::EndDraw method can return D2DERR_RECREATE_TARGET. You have to free and recreate your render target then, along with all resources associated with it, like brushes, bitmaps and so on. WTF Microsoft?! I thought this idea is gone after introducing Direct3D 10 and new graphics driver model? I now hope this error is returned only when user unplugs his graphics card ;)
Direct2D suffers from a phenomenon similar the famous half-texel offset in Direct3D 9. Render target starts from (0, 0) at the top-left corner, not at the center of the first pixel. So you have to offset everything by (0.5, 0.5). To draw a line starting exactly from the pixel at third column and second row, you have to start it at position (3.5, 2.5). Otherwise every line is blurred across two neighbour pixels, like on the image below. Which still looks pretty good and doesn't degrade performance though.