Direct2D との相互運用

Win2D は Direct2D 上のレイヤーとして実装され、双方向の相互運用をサポートします。 Win2D オブジェクトがある場合は、それを実装するために使用されるネイティブ Direct2D オブジェクトにアクセスできます。 Direct2D オブジェクトがある場合は、それをラップする Win2D オブジェクトを検索するか、まだ存在していない場合は新しいラッパーを作成できます。

相互運用機能を使用すると、Win2D とネイティブ DirectX API を組み合わせることができます。 ほとんどの場合、Win2D を使用するアプリを作成できますが、ネイティブ DirectX にドロップダウンして、ネイティブ インターフェイスを必要とする他の API またはサード パーティコンポーネントを呼び出すことができます。 または、ほとんどの場合、アプリをネイティブ DirectX にすることができますが、追加の利便性や C# のサポートが必要な特定の場所で Win2D に切り替えることができます。

相互運用 API

C++/CX 相互運用 API は、ヘッダー Microsoftで定義されます。Graphics.Canvas.native.h:

#include <Microsoft.Graphics.Canvas.native.h>

using namespace Microsoft::Graphics::Canvas;

Win2D オブジェクトによってラップされたネイティブ Direct2D オブジェクトを取得するには:

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(U^ wrapper);

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper);

template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper, float dpi);

ほとんどの型では、 GetWrappedResource は Win2D ラッパー オブジェクトのみをパラメーターとして呼び出すことができます。 いくつかの種類 (下の表を参照) では、デバイスや DPI 値も渡す必要があります。 必要のない型で GetWrappedResource を使用する場合、デバイスまたは DPI を渡してもエラーになりません。

ネイティブ Direct2D オブジェクトをラップする Win2D オブジェクトを取得するには:

template<typename WRAPPER>
WRAPPER^ GetOrCreate(IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource, float dpi);

template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource, float dpi);

GetOrCreate は、既に存在する場合は既存のラッパー インスタンスを返し、存在しない場合は新しいラッパーを作成します。 同じネイティブ オブジェクトで繰り返し呼び出すと、そのラッパー インスタンスが存在し続ける限り、毎回同じラッパーが返されます。 ラッパーへのすべての参照が解放され、その参照カウントがゼロになってラッパーが破棄された場合、この後で GetOrCreate を呼び出す際には、新しいラッパーを作成する必要があります。

一部の型 GetOrCreate Direct2D リソース オブジェクトのみをパラメーターとして呼び出すことができますが、他の型 (下の表を参照) の場合は、デバイスと DPI 値も渡す必要があります。 必要のない型で GetOrCreate を使用する場合、デバイスまたは DPI を渡してもエラーになりません。 Win2D ラッパーが既に存在する場合は、通常は必要な型であっても、デバイスと DPI を省略しても問題ありません。これらのパラメーターは、新しいラッパー インスタンスを作成するときにのみ使用されます。

GetOrCreate は継承階層を理解し、常に適切な最も派生したラッパー型を作成します。 たとえば、GetOrCreate<CanvasBitmap>(ID2D1Bitmap1*) フラグを持つID2D1Bitmap1を使用してD2D1_BITMAP_OPTIONS_TARGETを呼び出すと、返されるラッパー インスタンスは実際にはCanvasRenderTargetになります (CanvasBitmapから派生します)。 逆に、D2D1_BITMAP_OPTIONS_TARGET を持たない ID2D1Bitmap1 を使用して GetOrCreate<CanvasRenderTarget>(ID2D1Bitmap1*) を呼び出すと、無効な型変換の例外がスローされます。

これを極端に見ると、 GetOrCreate<Object>(IUnknown*)を呼び出し、また GetWrappedResource<IUnknown>(Object^)することが有効です。

相互運用をサポートする型

Win2D 型 Direct2D 型 GetOrCreate パラメーター GetWrappedResource パラメーター
CanvasBitmap ID2D1Bitmap1 なし D2D1_BITMAP_OPTIONS_TARGET Device -
CanvasCachedGeometry ID2D1GeometryRealization Device -
CanvasCommandList ID2D1CommandList Device -
CanvasDevice ID2D1Device1 - -
CanvasDrawingSession ID2D1DeviceContext1 - -
CanvasFontFace IDWriteFontFaceReference - -
CanvasFontSet IDWriteFontSet - -
CanvasGeometry ID2D1Geometry、またはその派生インターフェイスの 1 つ ID2D1PathGeometryID2D1RectangleGeometryID2D1RoundedRectangleGeometryID2D1EllipseGeometryID2D1TransformedGeometry、または ID2D1GeometryGroup Device -
CanvasGradientMesh ID2D1GradientMesh Device -
CanvasImageBrush ID2D1BitmapBrush1(イメージが CanvasBitmap で、SourceRectanglenullの場合)または ID2D1ImageBrush(その他の種類の ICanvasImageである場合、または SourceRectangle is setの場合) Device オプションの DPI^1
CanvasLinearGradientBrush ID2D1LinearGradientBrush Device -
CanvasNumberSubstitution IDWriteNumberSubstitution - -
CanvasRadialGradientBrush ID2D1RadialGradientBrush Device -
CanvasRenderTarget ID2D1Bitmap1D2D1_BITMAP_OPTIONS_TARGET Device -
CanvasSolidColorBrush ID2D1SolidColorBrush Device -
CanvasStrokeStyle ID2D1StrokeStyle1 - Device
CanvasSvgDocument ID2D1SvgDocument^2 Device -
CanvasSwapChain IDXGISwapChain1 デバイス、DPI -
CanvasTextFormat IDWriteTextFormat1 - -
CanvasTextLayout IDWriteTextLayout3 Device -
CanvasTextRenderingParameters IDWriteRenderingParams3 - -
CanvasTypography IDWriteTypography - -
CanvasVirtualBitmap ID2D1ImageSource または ID2D1TransformedImageSource Device -
ColorManagementProfile ID2D1ColorContext Device Device
EffectTransferTable3D ID2D1LookupTable3D Device -
Microsoft.Graphics.Canvas.Effects.* (複数の Win2D クラスが同じ D2D 型にマップされます) ID2D1Effect に適切な D2D1_PROPERTY_TYPE_CLSID を付けて Device デバイス、オプションの DPI^1

Note

^1: オプションの DPI は、DPI 値を指定せずにこの種類の GetWrappedResource を呼び出すことが有効であることを意味しますが、DPI を指定すると、Win2D は冗長 DPI 補正ノードを除外することで効果グラフをより効率的に構成できる可能性があります。 これは、エフェクトに対して GetWrappedResource を呼び出す場合、またはソース イメージとして効果を持つ CanvasImageBrush で呼び出すときに適用されます。

Note

^2: ネイティブ C++ 相互運用機能を使用してCanvasSvgDocumentからID2D1SvgDocumentが生成された場合、ID2D1SvgDocumentのビューポート サイズは無視されます。

C++/CX を使用した相互運用

C++ を使用して、Win2D を Direct2D と相互運用する方法の例を次に示します。

#include <Microsoft.Graphics.Canvas.native.h>
#include <d2d1_2.h>

using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::WRL;

// Interop Win2D -> Direct2D.
CanvasDevice^ canvasDevice = ...;
CanvasBitmap^ canvasBitmap = ...;

ComPtr<ID2D1Device> nativeDevice = GetWrappedResource<ID2D1Device>(canvasDevice);
ComPtr<ID2D1Bitmap1> nativeBitmap = GetWrappedResource<ID2D1Bitmap1>(canvasBitmap);

// Interop Direct2D -> Win2D.
canvasDevice = GetOrCreate<CanvasDevice>(nativeDevice.Get());
bitmap = GetOrCreate<CanvasBitmap>(canvasDevice, nativeBitmap.Get());

Note

相互運用は、C# を介して、さまざまな方法 (例: 組み込みの COM/WinRT 相互運用機能を使用する方法、 CsWinRT の API を使用する方法、blittable バインディングを使用する方法) を介して行うこともできます。 C# での手動相互運用の詳細については、CsWinRT に関するドキュメントを参照してください。

C++/WinRT を使用した相互運用

C++/WinRT を使用して相互運用を実行し、上記の変更を加えることもできます。 Win2D NuGet パッケージを C++/WinRT プロジェクトに追加すると、Win2D Windows ランタイム コンポーネントの C++/WinRT ヘッダーが自動的に生成されることに注意してください。 ただし、相互運用のためには、名前空間 ICanvasFactoryNative にある低レベルの ABI インターフェイス ABI::Microsoft::Graphics::Canvas を含むヘッダー ファイル Microsoft.Graphics.Canvas.native.h を引き続き使用する必要があります。 インターフェイスには、相互運用を実行するために使用できる次の関数があります。

HRESULT GetOrCreate(ICanvasDevice* device, IUnknown* resource, float dpi, IInspectable** wrapper);
HRESULT GetNativeResource(ICanvasDevice* device, float dpi, REFIID iid, void** resource);

以下に、CanvasVirtualBitmap と共有の IWICBitmapSource で始まる IWICBitmapSource から CanvasDevice を作成する方法の例を示します。

#include "pch.h"
#include <wincodec.h>
#include <wincodecsdk.h>
#include <winrt/Microsoft.Graphics.Canvas.h> //This defines the C++/WinRT interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.h> //This defines the low-level ABI interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.native.h> //This is for interop
#include <d2d1_3.h>

using namespace winrt::Microsoft::Graphics::Canvas;
namespace abi {
  using namespace ABI::Microsoft::Graphics::Canvas;
}

namespace winrt::Win2DInteropTest::implementation {
  CanvasVirtualBitmap CreateVirtualBitmapFromBitmapSource(com_ptr<IWICBitmapSource> const& pBitmapSource){
    CanvasDevice sharedDevice = CanvasDevice::GetSharedDevice();

    //First we need to get an ID2D1Device1 pointer from the shared CanvasDevice
    com_ptr<abi::ICanvasResourceWrapperNative> nativeDeviceWrapper = sharedDevice.as<abi::ICanvasResourceWrapperNative>();
    com_ptr<ID2D1Device1> pDevice{ nullptr };
    check_hresult(nativeDeviceWrapper->GetNativeResource(nullptr, 0.0f, guid_of<ID2D1Device1>(), pDevice.put_void()));

    //Next we need to call some Direct2D functions to create the ID2D1ImageSourceFromWic object
    com_ptr<ID2D1DeviceContext1> pContext{ nullptr };
    check_hresult(pDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, pContext.put()));
    com_ptr<ID2D1DeviceContext2> pContext2 = pContext.as<ID2D1DeviceContext2>();
    com_ptr<ID2D1ImageSourceFromWic> pImage{ nullptr };
    check_hresult(pContext2->CreateImageSourceFromWic(pBitmapSource.get(), D2D1_IMAGE_SOURCE_LOADING_OPTIONS_RELEASE_SOURCE, pImage.put()));

    //Finally we need to wrap the ID2D1ImageSourceFromWic object inside 
    com_ptr<::IInspectable> pInspectable{ nullptr };
    auto factory = winrt::get_activation_factory<CanvasDevice, abi::ICanvasFactoryNative>(); //abi::ICanvasFactoryNative is the activation factory for the CanvasDevice class
    check_hresult(factory->GetOrCreate(sharedDevice.as<abi::ICanvasDevice>().get(), pImage.as<::IUnknown>().get(), 0.0f, pInspectable.put())); //Note abi::ICanvasDevice is defined in the header Microsoft.Graphics.Canvas.h
    CanvasVirtualBitmap cvb = pInspectable.as<CanvasVirtualBitmap>();
    return cvb;
  }
}

WinRT ヘッダー (SDK 17763 以降で必要) の前に、必ずヘッダー <unknwn.h> を pch.h に含めます。