现在的位置: 首页 > 综合 > 正文

Creating DirectX Interop Libraries for XAML Metro Style Apps – Part 1

2014年02月17日 ⁄ 综合 ⁄ 共 7866字 ⁄ 字号 评论关闭

The XAML-based UI stack for Metro Style Apps is quite rich for the youngest member of the XAML UI frameworks family, but sometimes the basic controls even with their rich APIs are not enough. That is where the most
powerful point of extensibility of the XAML UI comes in – the DirectX integration.

With DirectX you can create the highest quality real time Direct3D graphics, high performance Direct2D drawings, apply stunning looking pixel shader effects, read and write images of many different formats with
WIC, play back video with the Media Framework and high quality audio with XAudio2. You can do all these things in a XAML-based app, so you can use all the rich UI APIs of the XAML framework to quickly create a beautiful looking application and add some special
DirectX touch that will make it unique.

In this article I will show you how to create a libraries for drawing Direct2D or Direct3D scenes in the background of an otherwise XAML-rendered UI.

The DirectX
and XAML interop article
 on MSDN talks about 3 different ways to mix XAML and DirectX in WinRT:

  1. SurfaceImageSource – which is good for mostly static scenes that get drawn into an Image control
  2. VirtualSurfaceImageSource – which is similar to SurfaceImageSource, but allows to work with surfaces larger than the size of the screen – perhaps for working with high resolution photos or maps
  3. SwapChainBackgroundPanel – which can be used for high performance graphics with almost the same level of control you would otherwise get if you created a solely DirectX-driven app or game

The last option is what we’ll use to create a DirectX-based background for a XAML app. A lot of the things we will use are already available as part of the Metro
style app samples
 available from MSDN. There is no sample however, with the DirectX stuff packaged as a separate library so that you could use it in any C++, C# or VB application and have some reusable code that you would not have to write repeatedly.

To learn how to create a reusable library it helps to know what the basics are of a DirectX application. When you create a basic Direct2D Application from the template that ships with Visual Studio 11 for Windows
8 Consumer Preview you get this:

The pch files are for the precompiled header with references to DirectX headers and WRL(Windows
Runtime C++ Template Library), which is an ATL-inspired library that helps to work with COM in a WinRT app – quite useful since DirectX is built on COM.

DirectXHelper.h contains a simple inline function that throws WinRT platform exceptions for failed HRESULTs. This is useful since these exceptions get projected to CLR Exceptions, so if you are planning on consuming the
code with .NET you should get regular .NET exceptions on failed HRESULTs.

DirectXBase is an abstract base class that helps to build basic DirectX applications that use D2D, D3D, WIC or DirectWrite by providing basic access to the global class factories and shared resources. Its main entry point
is the Initialize() method that takes an instance of theCoreWindow class,
which is the core UI piece of every WinRT app and makes that window into a DirectX-managed one. This is also the thing we’ll need to change when we use the SwapChainBackgroundPanel since we want to only associate that panel with DirectX and not the entire
UI. Initialization code is divided into 3 methods:

  1. CreateDeviceIndependentResources that in the case of a Direct2D app creates D2D and DWrite factories,
  2. CreateDeviceResources that creates so called D3D 11 device, its context, D2D device and sets the DPI
  3. CreateWindowSizeDependentResources creates
    1. The swap chain, which is a collection of bitmaps or textures that get presented on screen in quick succession to create an illusion of motion,
    2. The render target view, which tells the GPU what to render to (the back buffer of the swap chain),
    3. The depth stencil texture, which is used to control layering/z-ordering of pixels in the scene,
    4. The view port, which controls the view of the swap chain that is shown on screen,
    5. Finally – it associates the D2D device with the back buffer and sets the text anti-aliasing mode

UpdateForWindowSizeChange() is what you need to call whenever the screen resolution changes (e.g. when the app gets snapped, goes into portrait mode or back or when display
monitor configuration changes). It basically clears out old window size dependent resources and calls CreateWindowSizeDependentResources to recreate these in different resolution.
The Render() method is where you put all your scene rendering code calls and is what you call when you want to update the view.
Present() should be called after Render() and it basically flips the buffers in the swap chain or reinitializes everything if something failed.
BasicDirect2DApplication.cpp/.h is named after my application name. It is the main entry point of the application and inherits from DirectXBase, overriding its methods to actually render some content on the screen, so
you end up with a simple text displayed in the middle of the screen when the app is run. It also has the code that wires up DirectX to the CoreWindow and controls the rendering events. If you are interested in how to do it for a purely DirectX-based application
– you can read the How to
set up your Metro style DirectX app to display a view
 on MSDN. For DirectX-XAML interop – we will do things differently.

The Direct3D app is a bit similar, where Direct3DBase is analogue to the DirectXBase class of the Direct2D app, but has a few more files worth noting:

My BasicDirect3DApplication class in this case does not include any DirectX code except for calling out to CubeRenderer which is the
subclass of the Direct3DBase class in this case. The Direct3DBase class in the template D3D app is a bit different from its D2D version. Obviously it does not do anything with D2D or DWrite, so it does not deal with these class factories.
CubeRenderer defines the vertices of a cube and allows to render it animated based on system time.
SimplePixel/VertexShader.hlsl are the pixel and vertex shader files that are used to process the cube vertices and turn them into a rasterized output on your screen.

I could just share a complete library, which I will at the end, but I think it helps to know how it is done in the first place, so in case you disagree with something I have done or if something changes in the future
versions of the tools which currently are in flux you will be able to do it again yourself.

If you want to create the library you start with an empty C++ WinRT Component Library project. You can remove the stub WinRTComponent.cpp/.h files. Next you should to copy the list of referenced project linker input
files (static libraries) from the template DX application to the library. The screenshot below shows where to do it. Note – you need to do it once per each solution configuration, so if you switch between Win32, x64
or ARM you will need to reenter these. The right thing to do then would be to switch between all configurations and set these for all of them now to save some trouble later once you start building the solution for other platforms. Here is the list:

d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies)

The second step is to copy the header file includes from the template DX app pch into your project’s pch file.
Finally, copy the Direct3DBase and DirectXHelper files into the library and we are ready to do some coding. Note that copying and pasting between C++ projects in the Solution Explorer works differently than with say C#.
If you do it for files in a C# project – they get copied between projects. If you do it for C++ they only get referenced in another project, so make sure you do not do it and delete a temporary project! You can instead just copy the files in Windows Explorer
and add them to the project after making the copy outside.

Add a new class to the project called Direct2DBaseForComposition. You can do it by pressing Alt+Shift+C in the Solution Explorer. The class will derive from DirectXBase and will hook up to the SwapChainBackgroundPanel
instead of the CoreWindow in the way described in the MSDN article, so
we’ll need to hide the version of the Initialize method that only takes a CoreWindow reference and add one that takes a SwapChainBackgroundPanel, save the native interface to the panel, modify the swap chain initialization to set its dimensions based on panel
size and set scaling to DXGI_SCALING_STRETCH, replace the CreateSwapChainForCoreWindow call with one for CreateSwapChainForComposition, hook up the swap chain to the swap chain panel and finally override the Present() method to call the version of the Initialize()
method that takes the swap chain panel when the device gets reset.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma
once
#include
"DirectXBase.h"
#include
"windows.ui.xaml.media.dxinterop.h"
 
ref
class

Direct2DBaseForComposition abstract
    :
public

DirectXBase
{
public:
    Direct2DBaseForComposition(void);
    ~Direct2DBaseForComposition(void);
 
public:
    virtual

void

CreateWindowSizeDependentResources() override;
    virtual

void

Initialize(Windows::UI::Core::CoreWindow^ window) override;
    void

Initialize(
        _In_
Windows::UI::Core::CoreWindow^ window,

抱歉!评论已关闭.