Skip to content

Commit 3ed8ed4

Browse files
authored
Handle device-lost for text in DrawingIslands sample. (#351)
* Add RecreateGraphicsDevice method. * Implement TextRenderer::RecreateDirect2DDevice. * Catch device-removed exceptions. * Add DeviceLostHelper class. * Handle device lost event. * DeviceLostHelper cleanup.
1 parent a65dfb9 commit 3ed8ed4

File tree

12 files changed

+286
-80
lines changed

12 files changed

+286
-80
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include "pch.h"
5+
#include "DeviceLostHelper.h"
6+
7+
namespace winrt::DrawingIslandComponents::implementation
8+
{
9+
void DeviceLostHelper::WatchDevice(winrt::com_ptr<::IDXGIDevice> const& dxgiDevice)
10+
{
11+
// If we're currently listening to a device, then stop.
12+
StopWatchingCurrentDevice();
13+
14+
// Set the current device to the new device.
15+
m_device = nullptr;
16+
winrt::check_hresult(::CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast<::IInspectable**>(winrt::put_abi(m_device))));
17+
18+
// Get the DXGI Device.
19+
m_dxgiDevice = dxgiDevice;
20+
21+
// QI For the ID3D11Device4 interface.
22+
winrt::com_ptr<::ID3D11Device4> d3dDevice{ m_dxgiDevice.as<::ID3D11Device4>() };
23+
24+
// Create a wait struct.
25+
m_onDeviceLostHandler = nullptr;
26+
m_onDeviceLostHandler = ::CreateThreadpoolWait(DeviceLostHelper::OnDeviceLost, (PVOID)this, nullptr);
27+
28+
// Create a handle and a cookie.
29+
m_eventHandle.attach(::CreateEvent(nullptr, false, false, nullptr));
30+
winrt::check_bool(bool{ m_eventHandle });
31+
m_cookie = 0;
32+
33+
// Register for device lost.
34+
::SetThreadpoolWait(m_onDeviceLostHandler, m_eventHandle.get(), nullptr);
35+
winrt::check_hresult(d3dDevice->RegisterDeviceRemovedEvent(m_eventHandle.get(), &m_cookie));
36+
}
37+
38+
void DeviceLostHelper::StopWatchingCurrentDevice()
39+
{
40+
if (m_dxgiDevice)
41+
{
42+
// QI For the ID3D11Device4 interface.
43+
auto d3dDevice{ m_dxgiDevice.as<::ID3D11Device4>() };
44+
45+
// Unregister from the device lost event.
46+
::CloseThreadpoolWait(m_onDeviceLostHandler);
47+
d3dDevice->UnregisterDeviceRemoved(m_cookie);
48+
49+
// Clear member variables.
50+
m_onDeviceLostHandler = nullptr;
51+
m_eventHandle.close();
52+
m_cookie = 0;
53+
m_device = nullptr;
54+
m_dxgiDevice = nullptr;
55+
}
56+
}
57+
58+
void CALLBACK DeviceLostHelper::OnDeviceLost(PTP_CALLBACK_INSTANCE /* instance */, PVOID context, PTP_WAIT /* wait */, TP_WAIT_RESULT /* waitResult */)
59+
{
60+
// Get the DeviceLostHelper context object.
61+
auto deviceLostHelper = reinterpret_cast<DeviceLostHelper*>(context);
62+
63+
// Create a local reference to the old device before releasing the helper object's reference.
64+
auto oldDevice = deviceLostHelper->m_device;
65+
66+
// Stop listening for device lost events on the old device.
67+
deviceLostHelper->StopWatchingCurrentDevice();
68+
69+
// Invoke the event handler.
70+
deviceLostHelper->RaiseDeviceLostEvent(oldDevice);
71+
}
72+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
namespace winrt::DrawingIslandComponents::implementation
7+
{
8+
struct DeviceLostEventArgs
9+
{
10+
DeviceLostEventArgs(IDirect3DDevice const& device) : m_device(device)
11+
{
12+
}
13+
14+
IDirect3DDevice Device() { return m_device; }
15+
16+
private:
17+
IDirect3DDevice m_device;
18+
};
19+
20+
struct DeviceLostHelper
21+
{
22+
DeviceLostHelper() = default;
23+
24+
~DeviceLostHelper()
25+
{
26+
StopWatchingCurrentDevice();
27+
}
28+
29+
// Not copyable or assignable.
30+
DeviceLostHelper(DeviceLostHelper const&) = delete;
31+
void operator=(DeviceLostHelper const&) = delete;
32+
33+
void WatchDevice(winrt::com_ptr<::IDXGIDevice> const& dxgiDevice);
34+
35+
void StopWatchingCurrentDevice();
36+
37+
void DeviceLost(winrt::delegate<DeviceLostHelper const*, DeviceLostEventArgs const&> const& handler)
38+
{
39+
m_deviceLost = handler;
40+
}
41+
42+
private:
43+
void RaiseDeviceLostEvent(IDirect3DDevice const& oldDevice)
44+
{
45+
m_deviceLost(this, DeviceLostEventArgs{ oldDevice });
46+
}
47+
48+
static void CALLBACK OnDeviceLost(PTP_CALLBACK_INSTANCE /* instance */, PVOID context, PTP_WAIT /* wait */, TP_WAIT_RESULT /* waitResult */);
49+
50+
private:
51+
winrt::delegate<DeviceLostHelper const*, DeviceLostEventArgs const&> m_deviceLost;
52+
IDirect3DDevice m_device;
53+
winrt::com_ptr<::IDXGIDevice> m_dxgiDevice;
54+
PTP_WAIT m_onDeviceLostHandler{ nullptr };
55+
winrt::handle m_eventHandle;
56+
DWORD m_cookie{ 0 };
57+
};
58+
}

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace winrt::DrawingIslandComponents::implementation
1212
{
1313
m_output.Compositor = compositor;
1414
m_output.TextRenderer = std::make_shared<TextRenderer>(m_output.Compositor);
15+
m_output.DeviceLostHelper.WatchDevice(m_output.TextRenderer->GetDevice());
16+
m_output.DeviceLostHelper.DeviceLost({ this, &DrawingIsland::OnDirect3DDeviceLost });
1517

1618
// Create the Compositor and the Content:
1719
// - The Bridge's connection to the Window will keep everything alive, and perform an
@@ -774,6 +776,25 @@ namespace winrt::DrawingIslandComponents::implementation
774776
}
775777

776778

779+
void
780+
DrawingIsland::OnDirect3DDeviceLost(
781+
DeviceLostHelper const* /* sender */,
782+
DeviceLostEventArgs const& /* args */)
783+
{
784+
// Recreate the text renderer's D3D and D2D devices.
785+
m_output.TextRenderer->RecreateDirect2DDevice();
786+
787+
// Give each item an opportunity to recreate its device-dependent resources.
788+
for (auto& item : m_items.Items)
789+
{
790+
item->OnDeviceLost();
791+
}
792+
793+
// Listen for device lost on the new device.
794+
m_output.DeviceLostHelper.WatchDevice(m_output.TextRenderer->GetDevice());
795+
}
796+
797+
777798
void
778799
DrawingIsland::Output_Initialize()
779800
{

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "AutomationFragmentRoot.h"
88
#include "AutomationPeer.h"
99
#include "TextRenderer.h"
10+
#include "DeviceLostHelper.h"
1011
#include "TextItem.h"
1112

1213
namespace winrt::DrawingIslandComponents::implementation
@@ -136,6 +137,10 @@ namespace winrt::DrawingIslandComponents::implementation
136137

137138
void Island_OnStateChanged();
138139

140+
void OnDirect3DDeviceLost(
141+
DeviceLostHelper const* /* sender */,
142+
DeviceLostEventArgs const& /* args */);
143+
139144
void Output_Initialize();
140145

141146
void Output_AddVisual(
@@ -197,6 +202,7 @@ namespace winrt::DrawingIslandComponents::implementation
197202
winrt::ContainerVisual RootVisual{ nullptr };
198203

199204
std::shared_ptr<TextRenderer> TextRenderer;
205+
DeviceLostHelper DeviceLostHelper;
200206

201207
float Opacity{ 0.5f };
202208

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@
129129
<ClInclude Include="AutomationFragmentRoot.h" />
130130
<ClInclude Include="AutomationFragment.h" />
131131
<ClInclude Include="AutomationPeer.h" />
132+
<ClInclude Include="DeviceLostHelper.h" />
133+
<ClInclude Include="IslandFragmentRoot.h" />
134+
<ClInclude Include="NodeSimpleFragment.h" />
132135
<ClInclude Include="pch.h" />
133136
<ClInclude Include="DrawingIsland.h">
134137
<DependentUpon>Components.idl</DependentUpon>
@@ -140,6 +143,9 @@
140143
<ItemGroup>
141144
<ClCompile Include="AutomationFragmentRoot.cpp" />
142145
<ClCompile Include="AutomationFragment.cpp" />
146+
<ClCompile Include="DeviceLostHelper.cpp" />
147+
<ClCompile Include="IslandFragmentRoot.cpp" />
148+
<ClCompile Include="NodeSimpleFragment.cpp" />
143149
<ClCompile Include="pch.cpp">
144150
<PrecompiledHeader>Create</PrecompiledHeader>
145151
</ClCompile>

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<ClCompile Include="Item.cpp">
3434
<Filter>Source Files</Filter>
3535
</ClCompile>
36+
<ClCompile Include="DeviceLostHelper.cpp" />
3637
</ItemGroup>
3738
<ItemGroup>
3839
<ClInclude Include="pch.h" />
@@ -57,6 +58,9 @@
5758
<ClInclude Include="AutomationPeer.h">
5859
<Filter>Header Files</Filter>
5960
</ClInclude>
61+
<ClInclude Include="DeviceLostHelper.h">
62+
<Filter>Header Files</Filter>
63+
</ClInclude>
6064
</ItemGroup>
6165
<ItemGroup>
6266
<Midl Include="Components.idl" />

Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace winrt::DrawingIslandComponents::implementation
2020
{
2121
}
2222

23+
virtual void OnDeviceLost()
24+
{
25+
}
26+
2327
winrt::SpriteVisual const& GetVisual() const noexcept
2428
{
2529
return m_visual;

Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,4 @@ namespace winrt::DrawingIslandComponents::implementation
2525
// Render the text to the sprite visual.
2626
m_textRenderer->Render(m_text.c_str(), m_backgroundColor, m_textColor, GetVisual());
2727
}
28-
29-
void TextItem::OnDpiScaleChanged()
30-
{
31-
// Re-render the text using the current DPI scale.
32-
InitializeVisual();
33-
}
3428
}

Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ namespace winrt::DrawingIslandComponents::implementation
1717
Windows::UI::Color textColor,
1818
std::wstring const& text);
1919

20-
void OnDpiScaleChanged() override;
20+
void OnDpiScaleChanged() override
21+
{
22+
// Re-render the text using the current DPI scale.
23+
InitializeVisual();
24+
}
25+
26+
void OnDeviceLost() override
27+
{
28+
// Re-render the text using the current device.
29+
InitializeVisual();
30+
}
2131

2232
private:
2333
void InitializeVisual();

0 commit comments

Comments
 (0)