Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Belangrijk
Dit artikel wordt aangepast aan de UWP-documentatie voor Windows App SDK/WinUI. In sommige codevoorbeelden in dit artikel wordt nog steeds verwezen naar UWP-specifieke API's, zoals CoreWindow, CoreApplicationViewen CoreDispatcher, die niet beschikbaar zijn in WinUI/Windows App SDK. De WinUI-equivalenten zijn:
-
CoreWindow→ AppWindow of de WinUI-vensterklasse gebruiken -
CoreDispatcher→ DispatcherQueue gebruiken -
CoreApplicationView→ Venster of AppWindow gebruiken
De samenstellingsinteropinterfaces (ICompositorInterop, ICompositionDrawingSurfaceInterop, enzovoort) werken op dezelfde manier met Microsoft.UI.Composition objecten.
De Microsoft.UI.Composition-API biedt de natuurlijke interoperabiliteitsinterfaces ICompositorInterop, ICompositionDrawingSurfaceInterop en ICompositionGraphicsDeviceInterop, zodat inhoud rechtstreeks naar de compositor kan worden verplaatst.
Native interoperation is gestructureerd rond oppervlakteobjecten die worden ondersteund door DirectX-textures. De oppervlakken worden gemaakt op basis van een fabrieksobject met de naam CompositionGraphicsDevice. Dit object wordt ondersteund door een onderliggend Direct2D- of Direct3D-apparaatobject dat wordt gebruikt om videogeheugen toe te wijzen aan oppervlakken. Met de samenstellings-API wordt nooit het onderliggende DirectX-apparaat gemaakt. Het is de verantwoordelijkheid van de toepassing om er een te maken en door te geven aan het object CompositionGraphicsDevice . Een toepassing kan meer dan één CompositionGraphicsDevice-object tegelijk maken en kan hetzelfde DirectX-apparaat gebruiken als het renderingapparaat voor meerdere CompositionGraphicsDevice-objecten .
Een oppervlak maken
Elke CompositionGraphicsDevice fungeert als een surface factory. Elk oppervlak wordt gemaakt met een initiële grootte (mogelijk 0,0), maar geen geldige pixels. Een oppervlak in zijn oorspronkelijke toestand kan direct worden opgenomen in een visuele boom, bijvoorbeeld via een CompositionSurfaceBrush en een SpriteVisual, maar in zijn oorspronkelijke toestand heeft het oppervlak geen effect op het schermresultaat. Het is voor alle doeleinden volledig transparant, zelfs als de opgegeven alfamodus 'ondoorzichtig' is.
Soms kunnen DirectX-apparaten onbruikbaar worden weergegeven. Dit kan onder andere gebeuren als de toepassing ongeldige argumenten doorgeeft aan bepaalde DirectX-API's, of als de grafische adapter opnieuw wordt ingesteld door het systeem, of als het stuurprogramma wordt bijgewerkt. Direct3D heeft een API die een toepassing kan gebruiken om te detecteren, asynchroon, als het apparaat om welke reden dan ook verloren gaat. Wanneer een DirectX-apparaat verloren gaat, moet de toepassing het verwijderen, een nieuw apparaat maken en doorgeven aan eventuele CompositionGraphicsDevice-objecten die eerder aan het slechte DirectX-apparaat zijn gekoppeld.
Pixels in een oppervlak laden
Als u pixels in het oppervlak wilt laden, moet de toepassing de BeginDraw-methode aanroepen, die een DirectX-interface retourneert die een textuur of Direct2D-context vertegenwoordigt, afhankelijk van wat de toepassing aanvraagt. De toepassing moet vervolgens pixels weergeven of uploaden naar die textuur. Wanneer de toepassing is voltooid, moet deze de EndDraw-methode aanroepen. Alleen op dat moment zijn de nieuwe pixels beschikbaar voor compositie, maar ze worden nog steeds niet weergegeven op het scherm totdat alle wijzigingen in de visualstructuur de volgende keer worden doorgevoerd. Als de visuele boom wordt toegepast voordat EndDraw wordt aangeroepen, is de lopende update niet zichtbaar op het scherm en blijft het oppervlak de inhoud weergeven die het had vóór BeginDraw. Wanneer EndDraw wordt aangeroepen, wordt de bitmap of Direct2D-contextpointer die door BeginDraw wordt geretourneerd, ongeldig gemaakt. Een toepassing mag die aanwijzer nooit meer in de cache opslaan dan de EndDraw-aanroep .
De toepassing mag BeginDraw slechts op één oppervlak tegelijk aanroepen voor een bepaalde CompositionGraphicsDevice. Nadat u BeginDraw hebt aangeroepen, moet de toepassing EndDraw op dat oppervlak aanroepen voordat u BeginDraw op een andere plaats aanroept. Omdat de API agile is, is de applicatie verantwoordelijk om deze oproepen te synchroniseren als het rendering van meerdere werkdraadthreads wil uitvoeren. Als een toepassing het weergeven van één oppervlak wil onderbreken en tijdelijk naar een ander wilt overschakelen, kan de toepassing de SuspendDraw-methode gebruiken. Hierdoor kan een andere BeginDraw slagen, maar wordt de eerste oppervlakte-update niet beschikbaar gemaakt voor op het scherm. Hierdoor kan de toepassing meerdere updates op transactionele wijze uitvoeren. Zodra een oppervlak is onderbroken, kan de toepassing de update voortzetten door de ResumeDraw-methode aan te roepen of kan het declareren dat de update wordt uitgevoerd door EndDraw aan te roepen. Dit betekent dat slechts één oppervlak tegelijkertijd actief kan worden bijgewerkt voor elke opgegeven CompositionGraphicsDevice. Elk grafisch apparaat houdt deze status onafhankelijk van de andere, dus een toepassing kan tegelijkertijd worden weergegeven op twee oppervlakken als ze deel uitmaken van verschillende grafische apparaten. Dit voorkomt echter dat het videogeheugen voor deze twee oppervlakken samen wordt gegroepeerd en, als zodanig, minder geheugen efficiënt is.
De methoden BeginDraw, SuspendDraw, ResumeDraw en EndDraw retourneren fouten als de toepassing een onjuiste bewerking uitvoert (zoals het doorgeven van ongeldige argumenten of het aanroepen van BeginDraw op een oppervlak voordat EndDraw op een ander wordt aangeroepen). Deze typen fouten vertegenwoordigen toepassingsfouten en, als zodanig, is de verwachting dat ze worden verwerkt met een fail fast. BeginDraw kan ook een fout retourneren als het onderliggende DirectX-apparaat verloren gaat. Deze fout is niet fataal omdat de toepassing het DirectX-apparaat opnieuw kan maken en het opnieuw kan proberen. Als zodanig wordt verwacht dat de toepassing apparaatverlies afhandelt door simpelweg rendering over te slaan. Als BeginDraw om welke reden dan ook mislukt, moet de toepassing ook EndDraw niet aanroepen, omdat het begin nooit is geslaagd.
Scrollen
Om prestatieredenen is het niet gegarandeerd dat wanneer een toepassing BeginDraw aanroept, de inhoud van het geretourneerde patroon de vorige inhoud van het oppervlak is. De toepassing moet ervan uitgaan dat de inhoud willekeurig is en, als zodanig, moet de toepassing ervoor zorgen dat alle pixels worden aangeraakt, door het oppervlak te wissen voordat het wordt weergegeven of door voldoende ondoorzichtige inhoud te tekenen om de volledige bijgewerkte rechthoek te bedekken. Dit in combinatie met het feit dat de patroonpointer alleen geldig is tussen BeginDraw - en EndDraw-aanroepen , maakt het onmogelijk voor de toepassing om eerdere inhoud van het oppervlak te kopiëren. Daarom bieden we een Scroll-methode , waarmee de toepassing een pixelkopie op hetzelfde oppervlak kan uitvoeren.
Voorbeeld van C++/WinRT-gebruik
Het volgende codevoorbeeld illustreert een interoperatiescenario voor samenstellingsinteroperabiliteit in een Windows App SDK-context. In het voorbeeld worden typen gecombineerd uit het op Windows Runtime gebaseerde surface area van Microsoft.UI.Composition, samen met typen uit de interop-headers en code waarmee tekst wordt weergegeven met behulp van de OP COM gebaseerde DirectWrite- en Direct2D-API's. In het voorbeeld worden BeginDraw en EndDraw gebruikt om deze naadloos te laten samenwerken tussen deze technologieën. In het voorbeeld wordt DirectWrite gebruikt om de tekst in te richten en vervolgens wordt Direct2D gebruikt om deze weer te geven. Het apparaat voor samenstellingsafbeeldingen accepteert het Direct2D-apparaat rechtstreeks tijdens de initialisatie. Hierdoor kan BeginDraw een id2D1DeviceContext-interfaceaanwijzer retourneren, wat aanzienlijk efficiënter is dan wanneer de toepassing een Direct2D-context maakt om een geretourneerde ID3D11Texture2D-interface te verpakken bij elke tekenbewerking.
Als u het onderstaande C++/WinRT-codevoorbeeld wilt uitproberen, maakt u eerst een nieuw WinUI-app-project in Visual Studio (zie Visual Studio-ondersteuning voor C++/WinRT). Vervang de inhoud van uw pch.h en App.cpp broncodebestanden door de onderstaande codevermeldingen en bouw en voer deze uit. De toepassing geeft de tekenreeks 'Hallo wereld!' weer in zwarte tekst op een transparante achtergrond.
// 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