Important
この記事は、Windows App SDK/WinUI の UWP ドキュメントから調整されています。 この記事の一部のコード例では、WinUI/Windows App SDK ではCoreWindow、CoreApplicationView、CoreDispatcher、などの UWP 固有の API を引き続き参照しています。 WinUI に相当するものは次のとおりです。
-
CoreWindow→ AppWindow クラスまたは WinUI Window クラスを使用する -
CoreDispatcherDispatcherQueue を使用する→ -
CoreApplicationView→ ウィンドウまたは AppWindow を使用する
コンポジション相互運用インターフェイス (ICompositorInterop、ICompositionDrawingSurfaceInterop など) は、 Microsoft.UI.Composition オブジェクトと同じように動作します。
Microsoft.UI.Composition API には、コンテンツをコンポジターに直接移動できる ICompositorInterop、 ICompositionDrawingSurfaceInterop、 および ICompositionGraphicsDeviceInterop ネイティブ相互運用インターフェイスが用意されています。
ネイティブ相互運用は、DirectX テクスチャによってサポートされるサーフェス オブジェクトを中心に構成されます。 サーフェスは、 CompositionGraphicsDevice というファクトリ オブジェクトから作成されます。 このオブジェクトは、基になる Direct2D または Direct3D デバイス オブジェクトによってサポートされ、サーフェスにビデオ メモリを割り当てるために使用されます。 コンポジション API は、基になる DirectX デバイスを作成しません。 アプリケーションで作成し、 それを CompositionGraphicsDevice オブジェクトに渡す必要があります。 アプリケーションは一度に複数の CompositionGraphicsDevice オブジェクトを作成でき、複数の CompositionGraphicsDevice オブジェクトのレンダリング デバイスと同じ DirectX デバイスを使用できます。
サーフェスの作成
各 CompositionGraphicsDevice は、サーフェス ファクトリとして機能します。 各サーフェスは初期サイズ (0,0) で作成されますが、有効なピクセルは作成されません。 初期状態のサーフェスは、たとえば CompositionSurfaceBrush や SpriteVisual を介してビジュアル ツリーですぐに使用できますが、初期状態では画面の出力には影響しません。 これは、指定されたアルファ モードが "不透明" であっても、すべての目的で完全に透過的です。
場合によっては、DirectX デバイスが使用できなくなる場合があります。 これは、アプリケーションが特定の DirectX API に無効な引数を渡した場合、またはグラフィックス アダプターがシステムによってリセットされた場合、またはドライバーが更新された場合などに発生する可能性があります。 Direct3D には、何らかの理由でデバイスが失われた場合に、アプリケーションが非同期的に検出するために使用できる API があります。 DirectX デバイスが失われた場合、アプリケーションはそれを破棄し、新しいデバイスを作成し、以前に無効な DirectX デバイスに関連付けられた CompositionGraphicsDevice オブジェクトに渡す必要があります。
サーフェスへのピクセルの読み込み
サーフェスにピクセルを読み込むには、アプリケーションが要求する内容に応じて、テクスチャまたは Direct2D コンテキストを表す DirectX インターフェイスを返す BeginDraw メソッドを呼び出す必要があります。 その後、アプリケーションはそのテクスチャにピクセルをレンダリングまたはアップロードする必要があります。 アプリケーションが完了したら、 EndDraw メソッドを呼び出す必要があります。 その時点でのみ、コンポジションに使用できる新しいピクセルになりますが、ビジュアル ツリーに対するすべての変更が次回コミットされるまで画面に表示されません。 EndDraw が呼び出される前にビジュアル ツリーがコミットされた場合、進行中の更新プログラムは画面に表示されず、BeginDraw より前の内容が画面に表示され続けます。 EndDraw が呼び出されると、BeginDraw によって返されるテクスチャまたは Direct2D コンテキスト ポインターが無効になります。 アプリケーションでは、 EndDraw 呼び出しを超えてポインターをキャッシュしないでください。
アプリケーションは、特定の CompositionGraphicsDevice に対して、一度に 1 つのサーフェスでのみ BeginDraw を呼び出します。 BeginDraw を呼び出した後、アプリケーションは、別の画面で BeginDraw を呼び出す前に、そのサーフェスで EndDraw を呼び出す必要があります。 API はアジャイルであるため、複数のワーカー スレッドからのレンダリングを実行する場合、アプリケーションはこれらの呼び出しを同期する必要があります。 あるサーフェスのレンダリングを中断し、一時的に別のサーフェスに切り替える場合、アプリケーションは SuspendDraw メソッドを使用できます。 これにより、別の BeginDraw が成功しますが、画面での合成に最初のサーフェスの更新を利用することはできません。 これにより、アプリケーションはトランザクション方式で複数の更新を実行できます。 サーフェスが一時停止されると、アプリケーションは ResumeDraw メソッドを呼び出して更新を続行するか、 EndDraw を呼び出して更新が行われることを宣言できます。 つまり、特定の CompositionGraphicsDevice に対して一度にアクティブに更新できるサーフェスは 1 つだけです。 各グラフィックス デバイスは、他のグラフィックス デバイスとは独立してこの状態を保持するため、異なるグラフィックス デバイスに属している場合、アプリケーションは 2 つのサーフェスに同時にレンダリングできます。 ただし、これにより、これら 2 つのサーフェスのビデオ メモリが一緒にプールされるのを妨げるので、メモリ効率が低下します。
BeginDraw、SuspendDraw、ResumeDraw、EndDraw のメソッドは、アプリケーションが正しくない操作を実行した場合にエラーを返します (無効な引数を渡す、または別の引数で EndDraw を呼び出す前にサーフェスで BeginDraw を呼び出すなど)。 このような種類の障害は、アプリケーションのバグを表しているため、迅速な対応で処理することが期待されています。 基になる DirectX デバイスが失われた場合、BeginDraw はエラーを返す場合もあります。 アプリケーションは DirectX デバイスを再作成してもう一度試すことができるので、このエラーは致命的ではありません。 そのため、アプリケーションはレンダリングをスキップするだけでデバイスの損失を処理することが期待されます。 何らかの理由で BeginDraw が失敗した場合、最初に開始が成功したことがないため、アプリケーションは EndDraw も呼び出さないでください。
スクロール
パフォーマンス上の理由から、アプリケーションが BeginDraw を呼び出すと、返されるテクスチャの内容がサーフェスの以前のコンテンツであるとは限りません。 アプリケーションでは、コンテンツがランダムであると想定する必要があります。そのため、レンダリングの前にサーフェスをクリアするか、更新された四角形全体をカバーするのに十分な不透明なコンテンツを描画することによって、すべてのピクセルがタッチされるようにする必要があります。 これは、テクスチャ ポインターが BeginDraw 呼び出しと EndDraw 呼び出しの間でのみ有効であるという事実と組み合わせることで、アプリケーションが前の内容をサーフェスからコピーできなくなります。 このため、アプリケーションが同じサーフェス ピクセル コピーを実行できるようにする Scroll メソッドを提供します。
C++/WinRT の使用例
次のコード例は、Windows App SDK コンテキストでのコンポジション相互運用の相互運用シナリオを示しています。 この例では、Microsoft.UI.Composition の Windows ランタイム ベースのサーフェス領域の型と相互運用ヘッダーの型、および COM ベースの DirectWrite API と Direct2D API を使用してテキストをレンダリングするコードを組み合わせます。 この例では 、BeginDraw と EndDraw を使用して、これらのテクノロジ間の相互運用をシームレスに行います。 この例では、DirectWrite を使用してテキストをレイアウトし、Direct2D を使用してテキストをレンダリングします。 コンポジション グラフィックス デバイスは、初期化時に Direct2D デバイスを直接受け入れます。 これにより 、BeginDraw は ID2D1DeviceContext インターフェイス ポインターを返すことができます。これは、アプリケーションで Direct2D コンテキストを作成して、各描画操作で返された ID3D11Texture2D インターフェイスをラップするよりもかなり効率的です。
以下の C++/WinRT コード例を試すには、まず Visual Studio で新しい WinUI アプリ プロジェクトを作成します (要件については、 C++/WinRT の Visual Studio サポートを参照してください)。
pch.hとApp.cppソース コード ファイルの内容を以下のコード一覧に置き換えてから、ビルドして実行します。 アプリケーションは、"Hello, World!" という文字列を黒いテキストで透明な背景にレンダリングします。
// NOTE: This example uses UWP-specific APIs. For WinUI, replace CoreWindow with your app's Window handle.
// pch.h
#pragma once
#include <windows.h>
#include <D2d1_1.h>
#include <D3d11_4.h>
#include <Dwrite.h>
#include <Windows.Graphics.DirectX.Direct3D11.interop.h>
#include <Windows.ui.composition.interop.h>
#include <unknwn.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Graphics.DirectX.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <winrt/Microsoft.UI.Composition.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Input.h>
// NOTE: This example uses UWP-specific APIs. For WinUI, replace CoreWindow with your app's Window handle.
// App.cpp
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//*********************************************************
#include "pch.h"
using namespace winrt;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Numerics;
using namespace winrt::Windows::Graphics::DirectX;
using namespace winrt::Windows::Graphics::DirectX::Direct3D11;
using namespace winrt::Windows::UI;
using namespace winrt::Microsoft::UI::Composition;
using namespace winrt::Windows::UI::Core;
namespace abi
{
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Graphics::DirectX;
using namespace ABI::Microsoft::UI::Composition;
}
// An app-provided helper to render lines of text.
struct SampleText
{
SampleText(winrt::com_ptr<::IDWriteTextLayout> const& text, CompositionGraphicsDevice const& compositionGraphicsDevice) :
m_text(text),
m_compositionGraphicsDevice(compositionGraphicsDevice)
{
// Create the surface just big enough to hold the formatted text block.
DWRITE_TEXT_METRICS metrics;
winrt::check_hresult(m_text->GetMetrics(&metrics));
winrt::Windows::Foundation::Size surfaceSize{ metrics.width, metrics.height };
CompositionDrawingSurface drawingSurface{ m_compositionGraphicsDevice.CreateDrawingSurface(
surfaceSize,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
DirectXAlphaMode::Premultiplied) };
// Cache the interop pointer, since that's what we always use.
m_drawingSurfaceInterop = drawingSurface.as<abi::ICompositionDrawingSurfaceInterop>();
// Draw the text
DrawText();
// If the rendering device is lost, the application will recreate and replace it. We then
// own redrawing our pixels.
m_deviceReplacedEventToken = m_compositionGraphicsDevice.RenderingDeviceReplaced(
[this](CompositionGraphicsDevice const&, RenderingDeviceReplacedEventArgs const&)
{
// Draw the text again.
DrawText();
return S_OK;
});
}
~SampleText()
{
m_compositionGraphicsDevice.RenderingDeviceReplaced(m_deviceReplacedEventToken);
}
// Return the underlying surface to the caller.
auto Surface()
{
// To the caller, the fact that we have a drawing surface is an implementation detail.
// Return the base interface instead.
return m_drawingSurfaceInterop.as<ICompositionSurface>();
}
private:
// The text to draw.
winrt::com_ptr<::IDWriteTextLayout> m_text;
// The composition surface that we use in the visual tree.
winrt::com_ptr<abi::ICompositionDrawingSurfaceInterop> m_drawingSurfaceInterop;
// The device that owns the surface.
CompositionGraphicsDevice m_compositionGraphicsDevice{ nullptr };
//winrt::com_ptr<abi::ICompositionGraphicsDevice> m_compositionGraphicsDevice2;
// For managing our event notifier.
winrt::event_token m_deviceReplacedEventToken;
// We may detect device loss on BeginDraw calls. This helper handles this condition or other
// errors.
bool CheckForDeviceRemoved(HRESULT hr)
{
if (hr == S_OK)
{
// Everything is fine: go ahead and draw.
return true;
}
if (hr == DXGI_ERROR_DEVICE_REMOVED)
{
// We can't draw at this time, but this failure is recoverable. Just skip drawing for
// now. We will be asked to draw again once the Direct3D device is recreated.
return false;
}
// Any other error is unexpected and, therefore, fatal.
winrt::check_hresult(hr);
return true;
}
// Renders the text into our composition surface
void DrawText()
{
// Begin our update of the surface pixels. If this is our first update, we are required
// to specify the entire surface, which nullptr is shorthand for (but, as it works out,
// any time we make an update we touch the entire surface, so we always pass nullptr).
winrt::com_ptr<::ID2D1DeviceContext> d2dDeviceContext;
POINT offset;
if (CheckForDeviceRemoved(m_drawingSurfaceInterop->BeginDraw(nullptr,
__uuidof(ID2D1DeviceContext), d2dDeviceContext.put_void(), &offset)))
{
d2dDeviceContext->Clear(D2D1::ColorF(D2D1::ColorF::Black, 0.f));
// Create a solid color brush for the text. A more sophisticated application might want
// to cache and reuse a brush across all text elements instead, taking care to recreate
// it in the event of device removed.
winrt::com_ptr<::ID2D1SolidColorBrush> brush;
winrt::check_hresult(d2dDeviceContext->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black, 1.0f), brush.put()));
// Draw the line of text at the specified offset, which corresponds to the top-left
// corner of our drawing surface. Notice we don't call BeginDraw on the D2D device
// context; this has already been done for us by the composition API.
d2dDeviceContext->DrawTextLayout(D2D1::Point2F((float)offset.x, (float)offset.y), m_text.get(),
brush.get());
// Our update is done. EndDraw never indicates rendering device removed, so any
// failure here is unexpected and, therefore, fatal.
winrt::check_hresult(m_drawingSurfaceInterop->EndDraw());
}
}
};
struct DeviceLostEventArgs
{
DeviceLostEventArgs(IDirect3DDevice const& device) : m_device(device) {}
IDirect3DDevice Device() { return m_device; }
static DeviceLostEventArgs Create(IDirect3DDevice const& device) { return DeviceLostEventArgs{ device }; }
private:
IDirect3DDevice m_device;
};
struct DeviceLostHelper
{
DeviceLostHelper() = default;
~DeviceLostHelper()
{
StopWatchingCurrentDevice();
m_onDeviceLostHandler = nullptr;
}
IDirect3DDevice CurrentlyWatchedDevice() { return m_device; }
void WatchDevice(winrt::com_ptr<::IDXGIDevice> const& dxgiDevice)
{
// If we're currently listening to a device, then stop.
StopWatchingCurrentDevice();
// Set the current device to the new device.
m_device = nullptr;
winrt::check_hresult(::CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast<::IInspectable**>(winrt::put_abi(m_device))));
// Get the DXGI Device.
m_dxgiDevice = dxgiDevice;
// QI For the ID3D11Device4 interface.
winrt::com_ptr<::ID3D11Device4> d3dDevice{ m_dxgiDevice.as<::ID3D11Device4>() };
// Create a wait struct.
m_onDeviceLostHandler = nullptr;
m_onDeviceLostHandler = ::CreateThreadpoolWait(DeviceLostHelper::OnDeviceLost, (PVOID)this, nullptr);
// Create a handle and a cookie.
m_eventHandle.attach(::CreateEvent(nullptr, false, false, nullptr));
winrt::check_bool(bool{ m_eventHandle });
m_cookie = 0;
// Register for device lost.
::SetThreadpoolWait(m_onDeviceLostHandler, m_eventHandle.get(), nullptr);
winrt::check_hresult(d3dDevice->RegisterDeviceRemovedEvent(m_eventHandle.get(), &m_cookie));
}
void StopWatchingCurrentDevice()
{
if (m_dxgiDevice)
{
// QI For the ID3D11Device4 interface.
auto d3dDevice{ m_dxgiDevice.as<::ID3D11Device4>() };
// Unregister from the device lost event.
::CloseThreadpoolWait(m_onDeviceLostHandler);
d3dDevice->UnregisterDeviceRemoved(m_cookie);
// Clear member variables.
m_onDeviceLostHandler = nullptr;
m_eventHandle.close();
m_cookie = 0;
m_device = nullptr;
}
}
void DeviceLost(winrt::delegate<DeviceLostHelper const*, DeviceLostEventArgs const&> const& handler)
{
m_deviceLost = handler;
}
winrt::delegate<DeviceLostHelper const*, DeviceLostEventArgs const&> m_deviceLost;
private:
void RaiseDeviceLostEvent(IDirect3DDevice const& oldDevice)
{
m_deviceLost(this, DeviceLostEventArgs::Create(oldDevice));
}
static void CALLBACK OnDeviceLost(PTP_CALLBACK_INSTANCE /* instance */, PVOID context, PTP_WAIT /* wait */, TP_WAIT_RESULT /* waitResult */)
{
auto deviceLostHelper = reinterpret_cast<DeviceLostHelper*>(context);
auto oldDevice = deviceLostHelper->m_device;
deviceLostHelper->StopWatchingCurrentDevice();
deviceLostHelper->RaiseDeviceLostEvent(oldDevice);
}
private:
IDirect3DDevice m_device;
winrt::com_ptr<::IDXGIDevice> m_dxgiDevice;
PTP_WAIT m_onDeviceLostHandler{ nullptr };
winrt::handle m_eventHandle;
DWORD m_cookie{ 0 };
};
struct SampleApp : implements<SampleApp, IFrameworkViewSource, IFrameworkView>
{
IFrameworkView CreateView()
{
return *this;
}
void Initialize(CoreApplicationView const&)
{
}
// Run once when the application starts up
void Initialize()
{
// Create a Direct2D device.
CreateDirect2DDevice();
// To create a composition graphics device, we need to QI for another interface
winrt::com_ptr<abi::ICompositorInterop> compositorInterop{ m_compositor.as<abi::ICompositorInterop>() };
// Create a graphics device backed by our D3D device
winrt::com_ptr<abi::ICompositionGraphicsDevice> compositionGraphicsDeviceIface;
winrt::check_hresult(compositorInterop->CreateGraphicsDevice(
m_d2dDevice.get(),
compositionGraphicsDeviceIface.put()));
m_compositionGraphicsDevice = compositionGraphicsDeviceIface.as<CompositionGraphicsDevice>();
}
void Load(hstring const&)
{
}
void Uninitialize()
{
}
void Run()
{
CoreWindow window = CoreWindow::GetForCurrentThread();
window.Activate();
CoreDispatcher dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
}
void SetWindow(CoreWindow const& window)
{
m_compositor = Compositor{};
m_target = m_compositor.CreateTargetForCurrentView();
ContainerVisual root = m_compositor.CreateContainerVisual();
m_target.Root(root);
Initialize();
winrt::check_hresult(
::DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(m_dWriteFactory),
reinterpret_cast<::IUnknown**>(m_dWriteFactory.put())
)
);
winrt::check_hresult(
m_dWriteFactory->CreateTextFormat(
L"Segoe UI",
nullptr,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
36.f,
L"en-US",
m_textFormat.put()
)
);
Rect windowBounds{ window.Bounds() };
std::wstring text{ L"Hello, World!" };
winrt::check_hresult(
m_dWriteFactory->CreateTextLayout(
text.c_str(),
(uint32_t)text.size(),
m_textFormat.get(),
windowBounds.Width,
windowBounds.Height,
m_textLayout.put()
)
);
Visual textVisual{ CreateVisualFromTextLayout(m_textLayout) };
textVisual.Size({ windowBounds.Width, windowBounds.Height });
root.Children().InsertAtTop(textVisual);
}
// Called when Direct3D signals the device lost event.
void OnDirect3DDeviceLost(DeviceLostHelper const* /* sender */, DeviceLostEventArgs const& /* args */)
{
// Create a new Direct2D device.
CreateDirect2DDevice();
// Restore our composition graphics device to good health.
winrt::com_ptr<abi::ICompositionGraphicsDeviceInterop> compositionGraphicsDeviceInterop{ m_compositionGraphicsDevice.as<abi::ICompositionGraphicsDeviceInterop>() };
winrt::check_hresult(compositionGraphicsDeviceInterop->SetRenderingDevice(m_d2dDevice.get()));
}
// Create a surface that is asynchronously filled with an image
ICompositionSurface CreateSurfaceFromTextLayout(winrt::com_ptr<::IDWriteTextLayout> const& text)
{
// Create our wrapper object that will handle downloading and decoding the image (assume
// throwing new here).
SampleText textSurface{ text, m_compositionGraphicsDevice };
// The caller is only interested in the underlying surface.
return textSurface.Surface();
}
// Create a visual that holds an image.
Visual CreateVisualFromTextLayout(winrt::com_ptr<::IDWriteTextLayout> const& text)
{
// Create a sprite visual
SpriteVisual spriteVisual{ m_compositor.CreateSpriteVisual() };
// The sprite visual needs a brush to hold the image.
CompositionSurfaceBrush surfaceBrush{
m_compositor.CreateSurfaceBrush(CreateSurfaceFromTextLayout(text))
};
// Associate the brush with the visual.
CompositionBrush brush{ surfaceBrush.as<CompositionBrush>() };
spriteVisual.Brush(brush);
// Return the visual to the caller as an IVisual.
return spriteVisual;
}
private:
CompositionTarget m_target{ nullptr };
Compositor m_compositor{ nullptr };
winrt::com_ptr<::ID2D1Device> m_d2dDevice;
winrt::com_ptr<::IDXGIDevice> m_dxgiDevice;
//winrt::com_ptr<abi::ICompositionGraphicsDevice> m_compositionGraphicsDevice;
CompositionGraphicsDevice m_compositionGraphicsDevice{ nullptr };
std::vector<SampleText> m_textSurfaces;
DeviceLostHelper m_deviceLostHelper;
winrt::com_ptr<::IDWriteFactory> m_dWriteFactory;
winrt::com_ptr<::IDWriteTextFormat> m_textFormat;
winrt::com_ptr<::IDWriteTextLayout> m_textLayout;
// This helper creates a Direct2D device, and registers for a device loss
// notification on the underlying Direct3D device. When that notification is
// raised, the OnDirect3DDeviceLost method is called.
void CreateDirect2DDevice()
{
uint32_t createDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
// Array with DirectX hardware feature levels in order of preference.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
winrt::com_ptr<::ID3D11Device> d3DDevice;
winrt::com_ptr<::ID3D11DeviceContext> d3DImmediateContext;
D3D_FEATURE_LEVEL d3dFeatureLevel{ D3D_FEATURE_LEVEL_9_1 };
winrt::check_hresult(
::D3D11CreateDevice(
nullptr, // Default adapter.
D3D_DRIVER_TYPE_HARDWARE,
0, // Not asking for a software driver, so not passing a module to one.
createDeviceFlags, // Set debug and Direct2D compatibility flags.
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
d3DDevice.put(),
&d3dFeatureLevel,
d3DImmediateContext.put()
)
);
// Initialize Direct2D resources.
D2D1_FACTORY_OPTIONS d2d1FactoryOptions{ D2D1_DEBUG_LEVEL_NONE };
// Initialize the Direct2D Factory.
winrt::com_ptr<::ID2D1Factory1> d2D1Factory;
winrt::check_hresult(
::D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(d2D1Factory),
&d2d1FactoryOptions,
d2D1Factory.put_void()
)
);
// Create the Direct2D device object.
// Obtain the underlying DXGI device of the Direct3D device.
m_dxgiDevice = d3DDevice.as<::IDXGIDevice>();
m_d2dDevice = nullptr;
winrt::check_hresult(
d2D1Factory->CreateDevice(m_dxgiDevice.get(), m_d2dDevice.put())
);
m_deviceLostHelper.WatchDevice(m_dxgiDevice);
m_deviceLostHelper.DeviceLost({ this, &SampleApp::OnDirect3DDeviceLost });
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoreApplication::Run(winrt::make<SampleApp>());
}
Windows developer