FreeRDP
Loading...
Searching...
No Matches
win_dxgi.c
1
19#include <freerdp/config.h>
20
21#include <winpr/assert.h>
22#include <winpr/crt.h>
23#include <winpr/print.h>
24#include <winpr/library.h>
25#include <freerdp/log.h>
26
27#include "win_dxgi.h"
28
29#define TAG SERVER_TAG("shadow.win")
30
31#ifdef WITH_DXGI_1_2
32
33static D3D_DRIVER_TYPE DriverTypes[] = {
34 D3D_DRIVER_TYPE_HARDWARE,
35 D3D_DRIVER_TYPE_WARP,
36 D3D_DRIVER_TYPE_REFERENCE,
37};
38
39static UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
40
41static D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
42 D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
43
44static UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
45
46static HMODULE d3d11_module = nullptr;
47
48typedef HRESULT(WINAPI* fnD3D11CreateDevice)(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType,
49 HMODULE Software, UINT Flags,
50 CONST D3D_FEATURE_LEVEL* pFeatureLevels,
51 UINT FeatureLevels, UINT SDKVersion,
52 ID3D11Device** ppDevice,
53 D3D_FEATURE_LEVEL* pFeatureLevel,
54 ID3D11DeviceContext** ppImmediateContext);
55
56static fnD3D11CreateDevice pfnD3D11CreateDevice = nullptr;
57
58#undef DEFINE_GUID
59#define INITGUID
60
61#include <initguid.h>
62
63/* d3d11.h GUIDs */
64
65DEFINE_GUID(IID_ID3D11DeviceChild, 0x1841e5c8, 0x16b0, 0x489b, 0xbc, 0xc8, 0x44, 0xcf, 0xb0, 0xd5,
66 0xde, 0xae);
67DEFINE_GUID(IID_ID3D11DepthStencilState, 0x03823efb, 0x8d8f, 0x4e1c, 0x9a, 0xa2, 0xf6, 0x4b, 0xb2,
68 0xcb, 0xfd, 0xf1);
69DEFINE_GUID(IID_ID3D11BlendState, 0x75b68faa, 0x347d, 0x4159, 0x8f, 0x45, 0xa0, 0x64, 0x0f, 0x01,
70 0xcd, 0x9a);
71DEFINE_GUID(IID_ID3D11RasterizerState, 0x9bb4ab81, 0xab1a, 0x4d8f, 0xb5, 0x06, 0xfc, 0x04, 0x20,
72 0x0b, 0x6e, 0xe7);
73DEFINE_GUID(IID_ID3D11Resource, 0xdc8e63f3, 0xd12b, 0x4952, 0xb4, 0x7b, 0x5e, 0x45, 0x02, 0x6a,
74 0x86, 0x2d);
75DEFINE_GUID(IID_ID3D11Buffer, 0x48570b85, 0xd1ee, 0x4fcd, 0xa2, 0x50, 0xeb, 0x35, 0x07, 0x22, 0xb0,
76 0x37);
77DEFINE_GUID(IID_ID3D11Texture1D, 0xf8fb5c27, 0xc6b3, 0x4f75, 0xa4, 0xc8, 0x43, 0x9a, 0xf2, 0xef,
78 0x56, 0x4c);
79DEFINE_GUID(IID_ID3D11Texture2D, 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3,
80 0x4f, 0x9c);
81DEFINE_GUID(IID_ID3D11Texture3D, 0x037e866e, 0xf56d, 0x4357, 0xa8, 0xaf, 0x9d, 0xab, 0xbe, 0x6e,
82 0x25, 0x0e);
83DEFINE_GUID(IID_ID3D11View, 0x839d1216, 0xbb2e, 0x412b, 0xb7, 0xf4, 0xa9, 0xdb, 0xeb, 0xe0, 0x8e,
84 0xd1);
85DEFINE_GUID(IID_ID3D11ShaderResourceView, 0xb0e06fe0, 0x8192, 0x4e1a, 0xb1, 0xca, 0x36, 0xd7, 0x41,
86 0x47, 0x10, 0xb2);
87DEFINE_GUID(IID_ID3D11RenderTargetView, 0xdfdba067, 0x0b8d, 0x4865, 0x87, 0x5b, 0xd7, 0xb4, 0x51,
88 0x6c, 0xc1, 0x64);
89DEFINE_GUID(IID_ID3D11DepthStencilView, 0x9fdac92a, 0x1876, 0x48c3, 0xaf, 0xad, 0x25, 0xb9, 0x4f,
90 0x84, 0xa9, 0xb6);
91DEFINE_GUID(IID_ID3D11UnorderedAccessView, 0x28acf509, 0x7f5c, 0x48f6, 0x86, 0x11, 0xf3, 0x16, 0x01,
92 0x0a, 0x63, 0x80);
93DEFINE_GUID(IID_ID3D11VertexShader, 0x3b301d64, 0xd678, 0x4289, 0x88, 0x97, 0x22, 0xf8, 0x92, 0x8b,
94 0x72, 0xf3);
95DEFINE_GUID(IID_ID3D11HullShader, 0x8e5c6061, 0x628a, 0x4c8e, 0x82, 0x64, 0xbb, 0xe4, 0x5c, 0xb3,
96 0xd5, 0xdd);
97DEFINE_GUID(IID_ID3D11DomainShader, 0xf582c508, 0x0f36, 0x490c, 0x99, 0x77, 0x31, 0xee, 0xce, 0x26,
98 0x8c, 0xfa);
99DEFINE_GUID(IID_ID3D11GeometryShader, 0x38325b96, 0xeffb, 0x4022, 0xba, 0x02, 0x2e, 0x79, 0x5b,
100 0x70, 0x27, 0x5c);
101DEFINE_GUID(IID_ID3D11PixelShader, 0xea82e40d, 0x51dc, 0x4f33, 0x93, 0xd4, 0xdb, 0x7c, 0x91, 0x25,
102 0xae, 0x8c);
103DEFINE_GUID(IID_ID3D11ComputeShader, 0x4f5b196e, 0xc2bd, 0x495e, 0xbd, 0x01, 0x1f, 0xde, 0xd3, 0x8e,
104 0x49, 0x69);
105DEFINE_GUID(IID_ID3D11InputLayout, 0xe4819ddc, 0x4cf0, 0x4025, 0xbd, 0x26, 0x5d, 0xe8, 0x2a, 0x3e,
106 0x07, 0xb7);
107DEFINE_GUID(IID_ID3D11SamplerState, 0xda6fea51, 0x564c, 0x4487, 0x98, 0x10, 0xf0, 0xd0, 0xf9, 0xb4,
108 0xe3, 0xa5);
109DEFINE_GUID(IID_ID3D11Asynchronous, 0x4b35d0cd, 0x1e15, 0x4258, 0x9c, 0x98, 0x1b, 0x13, 0x33, 0xf6,
110 0xdd, 0x3b);
111DEFINE_GUID(IID_ID3D11Query, 0xd6c00747, 0x87b7, 0x425e, 0xb8, 0x4d, 0x44, 0xd1, 0x08, 0x56, 0x0a,
112 0xfd);
113DEFINE_GUID(IID_ID3D11Predicate, 0x9eb576dd, 0x9f77, 0x4d86, 0x81, 0xaa, 0x8b, 0xab, 0x5f, 0xe4,
114 0x90, 0xe2);
115DEFINE_GUID(IID_ID3D11Counter, 0x6e8c49fb, 0xa371, 0x4770, 0xb4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xb7,
116 0x41);
117DEFINE_GUID(IID_ID3D11ClassInstance, 0xa6cd7faa, 0xb0b7, 0x4a2f, 0x94, 0x36, 0x86, 0x62, 0xa6, 0x57,
118 0x97, 0xcb);
119DEFINE_GUID(IID_ID3D11ClassLinkage, 0xddf57cba, 0x9543, 0x46e4, 0xa1, 0x2b, 0xf2, 0x07, 0xa0, 0xfe,
120 0x7f, 0xed);
121DEFINE_GUID(IID_ID3D11CommandList, 0xa24bc4d1, 0x769e, 0x43f7, 0x80, 0x13, 0x98, 0xff, 0x56, 0x6c,
122 0x18, 0xe2);
123DEFINE_GUID(IID_ID3D11DeviceContext, 0xc0bfa96c, 0xe089, 0x44fb, 0x8e, 0xaf, 0x26, 0xf8, 0x79, 0x61,
124 0x90, 0xda);
125DEFINE_GUID(IID_ID3D11VideoDecoder, 0x3C9C5B51, 0x995D, 0x48d1, 0x9B, 0x8D, 0xFA, 0x5C, 0xAE, 0xDE,
126 0xD6, 0x5C);
127DEFINE_GUID(IID_ID3D11VideoProcessorEnumerator, 0x31627037, 0x53AB, 0x4200, 0x90, 0x61, 0x05, 0xFA,
128 0xA9, 0xAB, 0x45, 0xF9);
129DEFINE_GUID(IID_ID3D11VideoProcessor, 0x1D7B0652, 0x185F, 0x41c6, 0x85, 0xCE, 0x0C, 0x5B, 0xE3,
130 0xD4, 0xAE, 0x6C);
131DEFINE_GUID(IID_ID3D11AuthenticatedChannel, 0x3015A308, 0xDCBD, 0x47aa, 0xA7, 0x47, 0x19, 0x24,
132 0x86, 0xD1, 0x4D, 0x4A);
133DEFINE_GUID(IID_ID3D11CryptoSession, 0x9B32F9AD, 0xBDCC, 0x40a6, 0xA3, 0x9D, 0xD5, 0xC8, 0x65, 0x84,
134 0x57, 0x20);
135DEFINE_GUID(IID_ID3D11VideoDecoderOutputView, 0xC2931AEA, 0x2A85, 0x4f20, 0x86, 0x0F, 0xFB, 0xA1,
136 0xFD, 0x25, 0x6E, 0x18);
137DEFINE_GUID(IID_ID3D11VideoProcessorInputView, 0x11EC5A5F, 0x51DC, 0x4945, 0xAB, 0x34, 0x6E, 0x8C,
138 0x21, 0x30, 0x0E, 0xA5);
139DEFINE_GUID(IID_ID3D11VideoProcessorOutputView, 0xA048285E, 0x25A9, 0x4527, 0xBD, 0x93, 0xD6, 0x8B,
140 0x68, 0xC4, 0x42, 0x54);
141DEFINE_GUID(IID_ID3D11VideoContext, 0x61F21C45, 0x3C0E, 0x4a74, 0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A,
142 0xD5, 0xE4);
143DEFINE_GUID(IID_ID3D11VideoDevice, 0x10EC4D5B, 0x975A, 0x4689, 0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F,
144 0xE3, 0x33);
145DEFINE_GUID(IID_ID3D11Device, 0xdb6f6ddb, 0xac77, 0x4e88, 0x82, 0x53, 0x81, 0x9d, 0xf9, 0xbb, 0xf1,
146 0x40);
147
148/* dxgi.h GUIDs */
149
150DEFINE_GUID(IID_IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a,
151 0x2e);
152DEFINE_GUID(IID_IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29,
153 0x92, 0xf1, 0xa6);
154DEFINE_GUID(IID_IDXGIResource, 0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96,
155 0x0b);
156DEFINE_GUID(IID_IDXGIKeyedMutex, 0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a,
157 0xf8, 0x5d);
158DEFINE_GUID(IID_IDXGISurface, 0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60,
159 0xec);
160DEFINE_GUID(IID_IDXGISurface1, 0x4AE63092, 0x6327, 0x4c1b, 0x80, 0xAE, 0xBF, 0xE1, 0x2E, 0xA3, 0x2B,
161 0x86);
162DEFINE_GUID(IID_IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d,
163 0xc0);
164DEFINE_GUID(IID_IDXGIOutput, 0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13,
165 0xaa);
166DEFINE_GUID(IID_IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8,
167 0x88, 0x6a);
168DEFINE_GUID(IID_IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3,
169 0x69);
170DEFINE_GUID(IID_IDXGIDevice, 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8,
171 0x4c);
172DEFINE_GUID(IID_IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3,
173 0x87);
174DEFINE_GUID(IID_IDXGIAdapter1, 0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a,
175 0x05);
176DEFINE_GUID(IID_IDXGIDevice1, 0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39,
177 0x2c);
178
179/* dxgi1_2.h GUIDs */
180
181DEFINE_GUID(IID_IDXGIDisplayControl, 0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38,
182 0xf3, 0x0c);
183DEFINE_GUID(IID_IDXGIOutputDuplication, 0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4,
184 0x28, 0x31, 0x9c);
185DEFINE_GUID(IID_IDXGISurface2, 0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f,
186 0xa2);
187DEFINE_GUID(IID_IDXGIResource1, 0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e,
188 0xe0, 0xc1);
189DEFINE_GUID(IID_IDXGIDevice2, 0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6,
190 0xa9);
191DEFINE_GUID(IID_IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6,
192 0xf4, 0xaa);
193DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6,
194 0xd0);
195DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC,
196 0xB5);
197DEFINE_GUID(IID_IDXGIOutput1, 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66,
198 0xcc);
199
200WINPR_ATTR_NODISCARD
201const char* GetDxgiErrorString(HRESULT hr)
202{
203 switch (hr)
204 {
205 case DXGI_STATUS_OCCLUDED:
206 return "DXGI_STATUS_OCCLUDED";
207 case DXGI_STATUS_CLIPPED:
208 return "DXGI_STATUS_CLIPPED";
209 case DXGI_STATUS_NO_REDIRECTION:
210 return "DXGI_STATUS_NO_REDIRECTION";
211 case DXGI_STATUS_NO_DESKTOP_ACCESS:
212 return "DXGI_STATUS_NO_DESKTOP_ACCESS";
213 case DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE:
214 return "DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE";
215 case DXGI_STATUS_MODE_CHANGED:
216 return "DXGI_STATUS_MODE_CHANGED";
217 case DXGI_STATUS_MODE_CHANGE_IN_PROGRESS:
218 return "DXGI_STATUS_MODE_CHANGE_IN_PROGRESS";
219 case DXGI_ERROR_INVALID_CALL:
220 return "DXGI_ERROR_INVALID_CALL";
221 case DXGI_ERROR_NOT_FOUND:
222 return "DXGI_ERROR_NOT_FOUND";
223 case DXGI_ERROR_MORE_DATA:
224 return "DXGI_ERROR_MORE_DATA";
225 case DXGI_ERROR_UNSUPPORTED:
226 return "DXGI_ERROR_UNSUPPORTED";
227 case DXGI_ERROR_DEVICE_REMOVED:
228 return "DXGI_ERROR_DEVICE_REMOVED";
229 case DXGI_ERROR_DEVICE_HUNG:
230 return "DXGI_ERROR_DEVICE_HUNG";
231 case DXGI_ERROR_DEVICE_RESET:
232 return "DXGI_ERROR_DEVICE_RESET";
233 case DXGI_ERROR_WAS_STILL_DRAWING:
234 return "DXGI_ERROR_WAS_STILL_DRAWING";
235 case DXGI_ERROR_FRAME_STATISTICS_DISJOINT:
236 return "DXGI_ERROR_FRAME_STATISTICS_DISJOINT";
237 case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE:
238 return "DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE";
239 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
240 return "DXGI_ERROR_DRIVER_INTERNAL_ERROR";
241 case DXGI_ERROR_NONEXCLUSIVE:
242 return "DXGI_ERROR_NONEXCLUSIVE";
243 case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
244 return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE";
245 case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED:
246 return "DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED";
247 case DXGI_ERROR_REMOTE_OUTOFMEMORY:
248 return "DXGI_ERROR_REMOTE_OUTOFMEMORY";
249 case DXGI_ERROR_ACCESS_LOST:
250 return "DXGI_ERROR_ACCESS_LOST";
251 case DXGI_ERROR_WAIT_TIMEOUT:
252 return "DXGI_ERROR_WAIT_TIMEOUT";
253 case DXGI_ERROR_SESSION_DISCONNECTED:
254 return "DXGI_ERROR_SESSION_DISCONNECTED";
255 case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE:
256 return "DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE";
257 case DXGI_ERROR_CANNOT_PROTECT_CONTENT:
258 return "DXGI_ERROR_CANNOT_PROTECT_CONTENT";
259 case DXGI_ERROR_ACCESS_DENIED:
260 return "DXGI_ERROR_ACCESS_DENIED";
261 case DXGI_ERROR_NAME_ALREADY_EXISTS:
262 return "DXGI_ERROR_NAME_ALREADY_EXISTS";
263 case DXGI_ERROR_SDK_COMPONENT_MISSING:
264 return "DXGI_ERROR_SDK_COMPONENT_MISSING";
265 case DXGI_STATUS_UNOCCLUDED:
266 return "DXGI_STATUS_UNOCCLUDED";
267 case DXGI_STATUS_DDA_WAS_STILL_DRAWING:
268 return "DXGI_STATUS_DDA_WAS_STILL_DRAWING";
269 case DXGI_ERROR_MODE_CHANGE_IN_PROGRESS:
270 return "DXGI_ERROR_MODE_CHANGE_IN_PROGRESS";
271 case DXGI_DDI_ERR_WASSTILLDRAWING:
272 return "DXGI_DDI_ERR_WASSTILLDRAWING";
273 case DXGI_DDI_ERR_UNSUPPORTED:
274 return "DXGI_DDI_ERR_UNSUPPORTED";
275 case DXGI_DDI_ERR_NONEXCLUSIVE:
276 return "DXGI_DDI_ERR_NONEXCLUSIVE";
277 case E_ACCESSDENIED:
278 return "E_ACCESSDENIED";
279 }
280
281 return "DXGI_ERROR_UNKNOWN";
282}
283
284static void win_shadow_d3d11_module_init()
285{
286 if (d3d11_module)
287 return;
288
289 d3d11_module = LoadLibraryA("d3d11.dll");
290
291 if (!d3d11_module)
292 return;
293
294 pfnD3D11CreateDevice = GetProcAddressAs(d3d11_module, "D3D11CreateDevice", fnD3D11CreateDevice);
295}
296
297WINPR_ATTR_NODISCARD
298static int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem);
299
300/* How often a paused capture tries to duplicate the output again */
301#define WIN_SHADOW_DXGI_DENIED_RETRY_MS 250
302
303/* How often the capture tries again after a failure which does not recover by
304 * itself (no D3D11 device, no output of the adapter duplicatable at all):
305 * unlike a refused desktop, that state does not go away on its own */
306#define WIN_SHADOW_DXGI_INIT_RETRY_MS 60000
307
308/* The input desktop is one this process may not capture: the secure desktop (logon, lock
309 * screen, UAC) for a process in the user's session. DuplicateOutput says E_ACCESSDENIED,
310 * AcquireNextFrame and Map DXGI_ERROR_ACCESS_DENIED. */
311WINPR_ATTR_NODISCARD
312static BOOL win_shadow_dxgi_is_denied(HRESULT hr)
313{
314 return (hr == DXGI_ERROR_ACCESS_DENIED) || (hr == E_ACCESSDENIED);
315}
316
317/* Pause the capture: said once, then quiet until it resumes; the capture loop tries again
318 * after WIN_SHADOW_DXGI_DENIED_RETRY_MS (and at once when the input desktop changes) */
319static void win_shadow_dxgi_pause(winShadowSubsystem* subsystem, const char* what, HRESULT hr)
320{
321 WINPR_ASSERT(subsystem);
322 WINPR_ASSERT(what);
323
324 if (!subsystem->dxgiDenied)
325 WLog_WARN(TAG,
326 "%s: %s (0x%08lX): this process may not capture the current desktop (the "
327 "secure desktop?), capture paused until it can",
328 what, GetDxgiErrorString(hr), hr);
329 subsystem->dxgiDenied = TRUE;
330 subsystem->dxgiRetryTime = GetTickCount64() + WIN_SHADOW_DXGI_DENIED_RETRY_MS;
331}
332
333static void win_shadow_dxgi_drop_duplication(winShadowSubsystem* subsystem)
334{
335 WINPR_ASSERT(subsystem);
336
337 (void)win_shadow_dxgi_release_frame_data(subsystem);
338
339 if (subsystem->dxgiDesktopImage)
340 {
341 subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
342 subsystem->dxgiDesktopImage = nullptr;
343 }
344
345 if (subsystem->dxgiOutputDuplication)
346 {
347 subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
348 subsystem->dxgiOutputDuplication = nullptr;
349 }
350
351 if (subsystem->dxgiStage)
352 {
353 subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
354 subsystem->dxgiStage = nullptr;
355 }
356}
357
358WINPR_ATTR_NODISCARD
359static int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
360{
361 HRESULT hr;
362 HRESULT refusedHr = E_FAIL;
363 HRESULT deniedHr = E_FAIL;
364 BOOL denied = FALSE;
365 BOOL refused = FALSE;
366 BOOL duplicated = FALSE;
367 UINT refusedIndex = 0;
368 UINT duplicatedIndex = 0;
369 D3D11_TEXTURE2D_DESC textureDesc;
370 IDXGIDevice* dxgiDevice = nullptr;
371 IDXGIAdapter* dxgiAdapter = nullptr;
372
373 WINPR_ASSERT(subsystem);
374
375 hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, &IID_IDXGIDevice,
376 (void**)&dxgiDevice);
377
378 if (FAILED(hr))
379 {
380 WLog_ERR(TAG, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%08lX)",
381 GetDxgiErrorString(hr), hr);
382 return -1;
383 }
384
385 hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**)&dxgiAdapter);
386
387 if (dxgiDevice)
388 {
389 dxgiDevice->lpVtbl->Release(dxgiDevice);
390 dxgiDevice = nullptr;
391 }
392
393 if (FAILED(hr))
394 {
395 WLog_ERR(TAG, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%08lX)",
396 GetDxgiErrorString(hr), hr);
397 return -1;
398 }
399
400 /* Two passes over the adapter's outputs: the primary one first (its top
401 * left corner is the desktop origin, the monitor win_shadow_enum_monitors()
402 * describes), then the remaining attached ones. One output refusing the
403 * duplication must not end the search: an output of a virtual or an
404 * indirect display adapter does so for good while another output of the
405 * same adapter may duplicate fine, and any output does so while this
406 * process may not see the desktop. Only an adapter without a single
407 * duplicatable output fails the initialization. */
408 for (UINT pass = 0; !duplicated && (pass < 2); pass++)
409 {
410 for (UINT index = 0; !duplicated; index++)
411 {
412 IDXGIOutput* output = nullptr;
413 IDXGIOutput1* output1 = nullptr;
414 DXGI_OUTPUT_DESC desc = WINPR_C_ARRAY_INIT;
415 BOOL primary;
416
417 hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, index, &output);
418
419 /* DXGI_ERROR_NOT_FOUND: no (more) output at this index */
420 if (FAILED(hr))
421 break;
422
423 hr = output->lpVtbl->GetDesc(output, &desc);
424
425 if (FAILED(hr))
426 {
427 WLog_WARN(TAG, "IDXGIOutput %u::GetDesc failure: %s (0x%08lX)", index,
428 GetDxgiErrorString(hr), hr);
429 output->lpVtbl->Release(output);
430 continue;
431 }
432
433 if (!desc.AttachedToDesktop)
434 {
435 output->lpVtbl->Release(output);
436 continue;
437 }
438
439 primary = (desc.DesktopCoordinates.left == 0) && (desc.DesktopCoordinates.top == 0);
440
441 /* the first pass takes the primary output, the second the others */
442 if (primary != (pass == 0))
443 {
444 output->lpVtbl->Release(output);
445 continue;
446 }
447
448 hr = output->lpVtbl->QueryInterface(output, &IID_IDXGIOutput1, (void**)&output1);
449 output->lpVtbl->Release(output);
450
451 if (FAILED(hr))
452 {
453 WLog_WARN(TAG, "IDXGIOutput %u::QueryInterface(IDXGIOutput1) failure: %s (0x%08lX)",
454 index, GetDxgiErrorString(hr), hr);
455 continue;
456 }
457
458 hr = output1->lpVtbl->DuplicateOutput(output1, (IUnknown*)subsystem->dxgiDevice,
459 &(subsystem->dxgiOutputDuplication));
460 output1->lpVtbl->Release(output1);
461
462 if (SUCCEEDED(hr))
463 {
464 duplicated = TRUE;
465 duplicatedIndex = index;
466 WLog_INFO(TAG, "duplicating output %u (%ldx%ld at %ld,%ld)", index,
467 desc.DesktopCoordinates.right - desc.DesktopCoordinates.left,
468 desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top,
469 desc.DesktopCoordinates.left, desc.DesktopCoordinates.top);
470 break;
471 }
472
473 WLog_DBG(TAG, "IDXGIOutput %u::DuplicateOutput failure: %s (0x%08lX)", index,
474 GetDxgiErrorString(hr), hr);
475
476 if (!refused)
477 {
478 refused = TRUE;
479 refusedIndex = index;
480 refusedHr = hr;
481 }
482
483 if (win_shadow_dxgi_is_denied(hr))
484 {
485 denied = TRUE;
486 deniedHr = hr;
487 }
488 }
489 }
490
491 if (dxgiAdapter)
492 {
493 dxgiAdapter->lpVtbl->Release(dxgiAdapter);
494 dxgiAdapter = nullptr;
495 }
496
497 if (!duplicated)
498 {
499 if (denied)
500 {
501 /* the outputs deny the duplication while this process may not see
502 * the desktop: the capture loop tries again from dxgiRetryTime on */
503 win_shadow_dxgi_pause(subsystem, "IDXGIOutput1::DuplicateOutput", deniedHr);
504 return -1;
505 }
506
507 /* this does not recover by itself (only virtual or indirect display
508 * adapter outputs, or none at all): the capture loop tries again at a
509 * low rate */
510 WLog_ERR(TAG, "no output of the adapter can be duplicated, next attempt in %u ms",
511 WIN_SHADOW_DXGI_INIT_RETRY_MS);
512 subsystem->dxgiRetryTime = GetTickCount64() + WIN_SHADOW_DXGI_INIT_RETRY_MS;
513 return -1;
514 }
515
516 if (refused)
517 WLog_WARN(TAG,
518 "IDXGIOutput %u refused the duplication: %s (0x%08lX), duplicating output "
519 "%u instead",
520 refusedIndex, GetDxgiErrorString(refusedHr), refusedHr, duplicatedIndex);
521
522 /* the staging texture must match the current desktop size; a fatal
523 * resize error fails the duplication, the caller retries next tick */
524 if (win_shadow_check_resize(subsystem) < 0)
525 return -1;
526
527 textureDesc.Width = subsystem->width;
528 textureDesc.Height = subsystem->height;
529 textureDesc.MipLevels = 1;
530 textureDesc.ArraySize = 1;
531 textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
532 textureDesc.SampleDesc.Count = 1;
533 textureDesc.SampleDesc.Quality = 0;
534 textureDesc.Usage = D3D11_USAGE_STAGING;
535 textureDesc.BindFlags = 0;
536 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
537 textureDesc.MiscFlags = 0;
538
539 hr = subsystem->dxgiDevice->lpVtbl->CreateTexture2D(subsystem->dxgiDevice, &textureDesc,
540 nullptr, &(subsystem->dxgiStage));
541
542 if (FAILED(hr))
543 {
544 WLog_ERR(TAG, "ID3D11Device::CreateTexture2D failure: %s (0x%08lX)", GetDxgiErrorString(hr),
545 hr);
546 return -1;
547 }
548
549 if (subsystem->dxgiDenied)
550 {
551 WLog_INFO(TAG, "capture resumed");
552 subsystem->dxgiDenied = FALSE;
553 }
554 return 1;
555}
556
557int win_shadow_dxgi_init(winShadowSubsystem* subsystem)
558{
559 UINT i = 0;
560 HRESULT hr;
561 int status;
562 UINT DriverTypeIndex;
563 IDXGIDevice* DxgiDevice = nullptr;
564 IDXGIAdapter* DxgiAdapter = nullptr;
565 IDXGIOutput* DxgiOutput = nullptr;
566 IDXGIOutput1* DxgiOutput1 = nullptr;
567
568 win_shadow_d3d11_module_init();
569
570 if (!pfnD3D11CreateDevice)
571 {
572 /* this does not recover by itself: the capture loop tries again at a
573 * low rate */
574 WLog_ERR(TAG, "d3d11.dll did not provide D3D11CreateDevice, next attempt in %u ms",
575 WIN_SHADOW_DXGI_INIT_RETRY_MS);
576 subsystem->dxgiRetryTime = GetTickCount64() + WIN_SHADOW_DXGI_INIT_RETRY_MS;
577 return -1;
578 }
579
580 for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
581 {
582 hr = pfnD3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels,
583 NumFeatureLevels, D3D11_SDK_VERSION, &(subsystem->dxgiDevice),
584 &(subsystem->featureLevel), &(subsystem->dxgiDeviceContext));
585
586 if (SUCCEEDED(hr))
587 break;
588 }
589
590 if (FAILED(hr))
591 {
592 /* this does not recover by itself: the capture loop tries again at a
593 * low rate */
594 WLog_ERR(TAG, "D3D11CreateDevice failure: 0x%08lX, next attempt in %u ms", hr,
595 WIN_SHADOW_DXGI_INIT_RETRY_MS);
596 subsystem->dxgiRetryTime = GetTickCount64() + WIN_SHADOW_DXGI_INIT_RETRY_MS;
597 return -1;
598 }
599
600 status = win_shadow_dxgi_init_duplication(subsystem);
601
602 return status;
603}
604
605int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem)
606{
607 if (subsystem->dxgiStage)
608 {
609 subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
610 subsystem->dxgiStage = nullptr;
611 }
612
613 if (subsystem->dxgiDesktopImage)
614 {
615 subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
616 subsystem->dxgiDesktopImage = nullptr;
617 }
618
619 if (subsystem->dxgiOutputDuplication)
620 {
621 subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
622 subsystem->dxgiOutputDuplication = nullptr;
623 }
624
625 if (subsystem->dxgiDeviceContext)
626 {
627 subsystem->dxgiDeviceContext->lpVtbl->Release(subsystem->dxgiDeviceContext);
628 subsystem->dxgiDeviceContext = nullptr;
629 }
630
631 if (subsystem->dxgiDevice)
632 {
633 subsystem->dxgiDevice->lpVtbl->Release(subsystem->dxgiDevice);
634 subsystem->dxgiDevice = nullptr;
635 }
636
637 return 1;
638}
639
640int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, BYTE** ppDstData,
641 int* pnDstStep, int x, int y, int width, int height)
642{
643 int status;
644 HRESULT hr;
645 D3D11_BOX Box;
646 DXGI_MAPPED_RECT mappedRect;
647
648 if ((width * height) < 1)
649 return 0;
650
651 {
652 /* The shadow surface may be a pixel larger than the desktop image
653 * (exclusive vs inclusive rect edges); clamp the requested region to
654 * the source texture, otherwise the out-of-bounds copy trips
655 * DXGI_ERROR_DEVICE_REMOVED and capture silently dies. */
656 D3D11_TEXTURE2D_DESC srcDesc;
657 subsystem->dxgiDesktopImage->lpVtbl->GetDesc(subsystem->dxgiDesktopImage, &srcDesc);
658 if (x + width > (int)srcDesc.Width)
659 width = (int)srcDesc.Width - x;
660 if (y + height > (int)srcDesc.Height)
661 height = (int)srcDesc.Height - y;
662 }
663
664 Box.top = y;
665 Box.left = x;
666 Box.right = x + width;
667 Box.bottom = y + height;
668 Box.front = 0;
669 Box.back = 1;
670
671 subsystem->dxgiDeviceContext->lpVtbl->CopySubresourceRegion(
672 subsystem->dxgiDeviceContext, (ID3D11Resource*)subsystem->dxgiStage, 0, 0, 0, 0,
673 (ID3D11Resource*)subsystem->dxgiDesktopImage, 0, &Box);
674
675 if (subsystem->dxgiSurface)
676 {
677 subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
678 subsystem->dxgiSurface = nullptr;
679 }
680
681 hr = subsystem->dxgiStage->lpVtbl->QueryInterface(subsystem->dxgiStage, &IID_IDXGISurface,
682 (void**)&(subsystem->dxgiSurface));
683
684 if (FAILED(hr))
685 {
686 WLog_ERR(TAG, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%08lX",
687 GetDxgiErrorString(hr), hr);
688 return -1;
689 }
690
691 hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ);
692
693 if (FAILED(hr))
694 {
695 if (win_shadow_dxgi_is_denied(hr))
696 {
697 win_shadow_dxgi_pause(subsystem, "IDXGISurface::Map", hr);
698 win_shadow_dxgi_drop_duplication(subsystem);
699 return 0;
700 }
701
702 WLog_ERR(TAG, "IDXGISurface::Map failure: %s 0x%08lX", GetDxgiErrorString(hr), hr);
703
704 if (hr == DXGI_ERROR_DEVICE_REMOVED)
705 {
706 win_shadow_dxgi_uninit(subsystem);
707
708 status = win_shadow_dxgi_init(subsystem);
709
710 if (status < 0)
711 return -1;
712
713 return 0;
714 }
715 else if (hr == DXGI_ERROR_ACCESS_DENIED)
716 {
717 /* The console desktop switched to the secure desktop (lock
718 * screen, UAC prompt, ...). Re-create the duplication with a
719 * bounded retry loop instead of killing the capture thread. */
720 if (subsystem->dxgiSurface)
721 {
722 subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
723 subsystem->dxgiSurface = nullptr;
724 subsystem->dxgiSurfaceMapped = FALSE;
725 }
726
727 if (subsystem->dxgiStage)
728 {
729 subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
730 subsystem->dxgiStage = nullptr;
731 }
732
733 if (subsystem->dxgiOutputDuplication)
734 {
735 subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
736 subsystem->dxgiOutputDuplication = nullptr;
737 }
738
739 for (int attempt = 0; attempt < 240; ++attempt)
740 {
741 if (WaitForSingleObject(subsystem->base.server->StopEvent, 0) == WAIT_OBJECT_0)
742 return -1;
743
744 Sleep(500);
745 status = win_shadow_dxgi_init_duplication(subsystem);
746 if (status >= 0)
747 return 0;
748 }
749
750 return -1;
751 }
752
753 return -1;
754 }
755
756 subsystem->dxgiSurfaceMapped = TRUE;
757
758 *ppDstData = mappedRect.pBits;
759 *pnDstStep = mappedRect.Pitch;
760
761 return 1;
762}
763
764int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem)
765{
766 if (subsystem->dxgiSurface)
767 {
768 if (subsystem->dxgiSurfaceMapped)
769 {
770 subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface);
771 subsystem->dxgiSurfaceMapped = FALSE;
772 }
773
774 subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
775 subsystem->dxgiSurface = nullptr;
776 }
777
778 if (subsystem->dxgiOutputDuplication)
779 {
780 if (subsystem->dxgiFrameAcquired)
781 {
782 subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(
783 subsystem->dxgiOutputDuplication);
784 subsystem->dxgiFrameAcquired = FALSE;
785 }
786 }
787
788 subsystem->pendingFrames = 0;
789
790 return 1;
791}
792
793/* A new duplication of the output, on the calling thread's desktop: after a
794 * switch between the user's desktop and the secure one (logon, lock screen,
795 * UAC), or when an earlier attempt failed. The device is kept when there is
796 * one. */
797int win_shadow_dxgi_restart_duplication(winShadowSubsystem* subsystem)
798{
799 WINPR_ASSERT(subsystem);
800
801 if (!subsystem->dxgiDevice)
802 return win_shadow_dxgi_init(subsystem);
803
804 win_shadow_dxgi_drop_duplication(subsystem);
805 return win_shadow_dxgi_init_duplication(subsystem);
806}
807
808int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
809{
810 UINT i = 0;
811 int status;
812 HRESULT hr = 0;
813 UINT timeout = 1;
814 UINT DataBufferSize = 0;
815 BYTE* DataBuffer = nullptr;
816
817 if (subsystem->dxgiFrameAcquired)
818 {
819 win_shadow_dxgi_release_frame_data(subsystem);
820 }
821
822 if (subsystem->dxgiDesktopImage)
823 {
824 subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
825 subsystem->dxgiDesktopImage = nullptr;
826 }
827
828 hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(
829 subsystem->dxgiOutputDuplication, timeout, &(subsystem->dxgiFrameInfo),
830 &(subsystem->dxgiResource));
831
832 if (SUCCEEDED(hr))
833 {
834 subsystem->dxgiFrameAcquired = TRUE;
835 subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames;
836 }
837
838 if (hr == DXGI_ERROR_WAIT_TIMEOUT)
839 return 0;
840
841 if (FAILED(hr))
842 {
843 if (win_shadow_dxgi_is_denied(hr))
844 {
845 /* the duplication is no good any more: drop it, the capture loop makes a new one
846 * (on the new input desktop when this process may open it) */
847 win_shadow_dxgi_pause(subsystem, "IDXGIOutputDuplication::AcquireNextFrame", hr);
848 win_shadow_dxgi_drop_duplication(subsystem);
849 return 0;
850 }
851
852 WLog_ERR(TAG, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%08lX)",
853 GetDxgiErrorString(hr), hr);
854
855 if (hr == DXGI_ERROR_ACCESS_LOST)
856 {
857 win_shadow_dxgi_release_frame_data(subsystem);
858
859 if (subsystem->dxgiDesktopImage)
860 {
861 subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
862 subsystem->dxgiDesktopImage = nullptr;
863 }
864
865 if (subsystem->dxgiStage)
866 {
867 subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
868 subsystem->dxgiStage = nullptr;
869 }
870
871 if (subsystem->dxgiOutputDuplication)
872 {
873 subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
874 subsystem->dxgiOutputDuplication = nullptr;
875 }
876
877 status = win_shadow_dxgi_init_duplication(subsystem);
878
879 if (status < 0)
880 return -1;
881
882 return 0;
883 }
884 else if (hr == DXGI_ERROR_ACCESS_DENIED)
885 {
886 /* The console desktop switched to the secure desktop (lock
887 * screen, UAC prompt, ...); the duplication stays denied while
888 * that desktop is active. Release it and re-create with a
889 * bounded retry loop instead of killing the capture thread. */
890 win_shadow_dxgi_release_frame_data(subsystem);
891
892 if (subsystem->dxgiDesktopImage)
893 {
894 subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
895 subsystem->dxgiDesktopImage = nullptr;
896 }
897
898 if (subsystem->dxgiStage)
899 {
900 subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
901 subsystem->dxgiStage = nullptr;
902 }
903
904 if (subsystem->dxgiOutputDuplication)
905 {
906 subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
907 subsystem->dxgiOutputDuplication = nullptr;
908 }
909
910 for (int attempt = 0; attempt < 240; ++attempt)
911 {
912 if (WaitForSingleObject(subsystem->base.server->StopEvent, 0) == WAIT_OBJECT_0)
913 return -1;
914
915 Sleep(500);
916 status = win_shadow_dxgi_init_duplication(subsystem);
917 if (status >= 0)
918 return 0;
919 }
920
921 return -1;
922 }
923 else if (hr == DXGI_ERROR_INVALID_CALL)
924 {
925 win_shadow_dxgi_uninit(subsystem);
926
927 status = win_shadow_dxgi_init(subsystem);
928
929 if (status < 0)
930 return -1;
931
932 return 0;
933 }
934
935 return -1;
936 }
937
938 hr = subsystem->dxgiResource->lpVtbl->QueryInterface(
939 subsystem->dxgiResource, &IID_ID3D11Texture2D, (void**)&(subsystem->dxgiDesktopImage));
940
941 if (subsystem->dxgiResource)
942 {
943 subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource);
944 subsystem->dxgiResource = nullptr;
945 }
946
947 if (FAILED(hr))
948 {
949 WLog_ERR(TAG, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%08lX)",
950 GetDxgiErrorString(hr), hr);
951 return -1;
952 }
953
954 return 1;
955}
956
957int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
958{
959 HRESULT hr;
960 POINT* pSrcPt;
961 RECT* pDstRect;
962 RECT* pDirtyRect;
963 UINT numMoveRects;
964 UINT numDirtyRects;
965 UINT UsedBufferSize;
966 RECTANGLE_16 invalidRect;
967 UINT MetadataBufferSize;
968 UINT MoveRectsBufferSize;
969 UINT DirtyRectsBufferSize;
970 RECT* pDirtyRectsBuffer;
971 DXGI_OUTDUPL_MOVE_RECT* pMoveRect;
972 DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer;
973 rdpShadowSurface* surface = nullptr;
974
975 WINPR_ASSERT(subsystem);
976 WINPR_ASSERT(subsystem->base.server);
977 surface = subsystem->base.server->surface;
978 WINPR_ASSERT(surface);
979
980 if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0)
981 return 0;
982
983 if (subsystem->dxgiFrameInfo.TotalMetadataBufferSize == 0)
984 return 0;
985
986 MetadataBufferSize = subsystem->dxgiFrameInfo.TotalMetadataBufferSize;
987
988 if (MetadataBufferSize > subsystem->MetadataBufferSize)
989 {
990 subsystem->MetadataBuffer = (BYTE*)realloc(subsystem->MetadataBuffer, MetadataBufferSize);
991
992 if (!subsystem->MetadataBuffer)
993 return -1;
994
995 subsystem->MetadataBufferSize = MetadataBufferSize;
996 }
997
998 /* GetFrameMoveRects */
999
1000 UsedBufferSize = 0;
1001
1002 MoveRectsBufferSize = MetadataBufferSize - UsedBufferSize;
1003 pMoveRectBuffer = (DXGI_OUTDUPL_MOVE_RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
1004
1005 hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameMoveRects(
1006 subsystem->dxgiOutputDuplication, MoveRectsBufferSize, pMoveRectBuffer,
1007 &MoveRectsBufferSize);
1008
1009 if (FAILED(hr))
1010 {
1011 WLog_ERR(TAG,
1012 "IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%08lX) Size: %u Total "
1013 "%u Used: %u",
1014 GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize,
1015 UsedBufferSize);
1016 return -1;
1017 }
1018
1019 /* GetFrameDirtyRects */
1020
1021 UsedBufferSize += MoveRectsBufferSize;
1022
1023 DirtyRectsBufferSize = MetadataBufferSize - UsedBufferSize;
1024 pDirtyRectsBuffer = (RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
1025
1026 hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameDirtyRects(
1027 subsystem->dxgiOutputDuplication, DirtyRectsBufferSize, pDirtyRectsBuffer,
1028 &DirtyRectsBufferSize);
1029
1030 if (FAILED(hr))
1031 {
1032 WLog_ERR(TAG,
1033 "IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%08lX) Size: %u Total "
1034 "%u Used: %u",
1035 GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize,
1036 UsedBufferSize);
1037 return -1;
1038 }
1039
1040 numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
1041
1042 for (UINT i = 0; i < numMoveRects; i++)
1043 {
1044 pMoveRect = &pMoveRectBuffer[i];
1045 pSrcPt = &(pMoveRect->SourcePoint);
1046 pDstRect = &(pMoveRect->DestinationRect);
1047
1048 invalidRect.left = (UINT16)pDstRect->left;
1049 invalidRect.top = (UINT16)pDstRect->top;
1050 invalidRect.right = (UINT16)pDstRect->right;
1051 invalidRect.bottom = (UINT16)pDstRect->bottom;
1052
1053 region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
1054 }
1055
1056 numDirtyRects = DirtyRectsBufferSize / sizeof(RECT);
1057
1058 for (UINT i = 0; i < numDirtyRects; i++)
1059 {
1060 pDirtyRect = &pDirtyRectsBuffer[i];
1061
1062 invalidRect.left = (UINT16)pDirtyRect->left;
1063 invalidRect.top = (UINT16)pDirtyRect->top;
1064 invalidRect.right = (UINT16)pDirtyRect->right;
1065 invalidRect.bottom = (UINT16)pDirtyRect->bottom;
1066
1067 region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
1068 }
1069
1070 return 1;
1071}
1072
1073#endif