20 #include <freerdp/config.h>
22 #include "wf_interface.h"
34 #include <freerdp/log.h>
35 #define TAG SERVER_TAG("windows")
38 D3D_DRIVER_TYPE DriverTypes[] = {
39 D3D_DRIVER_TYPE_HARDWARE,
41 D3D_DRIVER_TYPE_REFERENCE,
43 UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
46 D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
47 D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
49 UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
51 D3D_FEATURE_LEVEL FeatureLevel;
53 ID3D11Device* gDevice = NULL;
54 ID3D11DeviceContext* gContext = NULL;
55 IDXGIOutputDuplication* gOutputDuplication = NULL;
56 ID3D11Texture2D* gAcquiredDesktopImage = NULL;
59 ID3D11Texture2D* sStage;
61 DXGI_OUTDUPL_FRAME_INFO FrameInfo;
63 int wf_dxgi_init(wfInfo* wfi)
65 gAcquiredDesktopImage = NULL;
67 if (wf_dxgi_createDevice(wfi) != 0)
72 if (wf_dxgi_getDuplication(wfi) != 0)
80 int wf_dxgi_createDevice(wfInfo* wfi)
85 for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
87 status = D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, 0, FeatureLevels,
88 NumFeatureLevels, D3D11_SDK_VERSION, &gDevice, &FeatureLevel,
90 if (SUCCEEDED(status))
93 WLog_INFO(TAG,
"D3D11CreateDevice returned [%ld] for Driver Type %d", status,
94 DriverTypes[DriverTypeIndex]);
99 WLog_ERR(TAG,
"Failed to create device in InitializeDx");
106 int wf_dxgi_getDuplication(wfInfo* wfi)
110 DXGI_OUTPUT_DESC desc = { 0 };
111 IDXGIOutput* pOutput;
112 IDXGIDevice* DxgiDevice = NULL;
113 IDXGIAdapter* DxgiAdapter = NULL;
114 IDXGIOutput* DxgiOutput = NULL;
115 IDXGIOutput1* DxgiOutput1 = NULL;
117 status = gDevice->lpVtbl->QueryInterface(gDevice, &IID_IDXGIDevice, (
void**)&DxgiDevice);
121 WLog_ERR(TAG,
"Failed to get QI for DXGI Device");
125 status = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (
void**)&DxgiAdapter);
126 DxgiDevice->lpVtbl->Release(DxgiDevice);
131 WLog_ERR(TAG,
"Failed to get parent DXGI Adapter");
137 while (DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
139 DXGI_OUTPUT_DESC* pDesc = &desc;
141 status = pOutput->lpVtbl->GetDesc(pOutput, pDesc);
145 WLog_ERR(TAG,
"Failed to get description");
149 WLog_INFO(TAG,
"Output %u: [%s] [%d]", i, pDesc->DeviceName, pDesc->AttachedToDesktop);
151 if (pDesc->AttachedToDesktop)
154 pOutput->lpVtbl->Release(pOutput);
158 dTop = wfi->screenID;
160 status = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput);
161 DxgiAdapter->lpVtbl->Release(DxgiAdapter);
166 WLog_ERR(TAG,
"Failed to get output");
171 DxgiOutput->lpVtbl->QueryInterface(DxgiOutput, &IID_IDXGIOutput1, (
void**)&DxgiOutput1);
172 DxgiOutput->lpVtbl->Release(DxgiOutput);
177 WLog_ERR(TAG,
"Failed to get IDXGIOutput1");
182 DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, (IUnknown*)gDevice, &gOutputDuplication);
183 DxgiOutput1->lpVtbl->Release(DxgiOutput1);
188 if (status == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
192 "There is already the maximum number of applications using the Desktop Duplication "
193 "API running, please close one of those applications and then try again.");
197 WLog_ERR(TAG,
"Failed to get duplicate output. Status = %ld", status);
204 int wf_dxgi_cleanup(wfInfo* wfi)
206 if (wfi->framesWaiting > 0)
208 wf_dxgi_releasePixelData(wfi);
211 if (gAcquiredDesktopImage)
213 gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
214 gAcquiredDesktopImage = NULL;
217 if (gOutputDuplication)
219 gOutputDuplication->lpVtbl->Release(gOutputDuplication);
220 gOutputDuplication = NULL;
225 gContext->lpVtbl->Release(gContext);
231 gDevice->lpVtbl->Release(gDevice);
238 int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout)
242 UINT DataBufferSize = 0;
243 BYTE* DataBuffer = NULL;
244 IDXGIResource* DesktopResource = NULL;
246 if (wfi->framesWaiting > 0)
248 wf_dxgi_releasePixelData(wfi);
251 if (gAcquiredDesktopImage)
253 gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
254 gAcquiredDesktopImage = NULL;
257 status = gOutputDuplication->lpVtbl->AcquireNextFrame(gOutputDuplication, timeout, &FrameInfo,
260 if (status == DXGI_ERROR_WAIT_TIMEOUT)
267 if (status == DXGI_ERROR_ACCESS_LOST)
269 WLog_ERR(TAG,
"Failed to acquire next frame with status=%ld", status);
270 WLog_ERR(TAG,
"Trying to reinitialize due to ACCESS LOST...");
272 if (gAcquiredDesktopImage)
274 gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage);
275 gAcquiredDesktopImage = NULL;
278 if (gOutputDuplication)
280 gOutputDuplication->lpVtbl->Release(gOutputDuplication);
281 gOutputDuplication = NULL;
284 wf_dxgi_getDuplication(wfi);
290 WLog_ERR(TAG,
"Failed to acquire next frame with status=%ld", status);
291 status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
295 WLog_ERR(TAG,
"Failed to release frame with status=%ld", status);
302 status = DesktopResource->lpVtbl->QueryInterface(DesktopResource, &IID_ID3D11Texture2D,
303 (
void**)&gAcquiredDesktopImage);
304 DesktopResource->lpVtbl->Release(DesktopResource);
305 DesktopResource = NULL;
312 wfi->framesWaiting = FrameInfo.AccumulatedFrames;
314 if (FrameInfo.AccumulatedFrames == 0)
316 status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
320 WLog_ERR(TAG,
"Failed to release frame with status=%ld", status);
327 int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data,
int* pitch, RECT* invalid)
331 DXGI_MAPPED_RECT mappedRect;
332 D3D11_TEXTURE2D_DESC tDesc;
334 tDesc.Width = (invalid->right - invalid->left);
335 tDesc.Height = (invalid->bottom - invalid->top);
338 tDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
339 tDesc.SampleDesc.Count = 1;
340 tDesc.SampleDesc.Quality = 0;
341 tDesc.Usage = D3D11_USAGE_STAGING;
343 tDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
346 Box.top = invalid->top;
347 Box.left = invalid->left;
348 Box.right = invalid->right;
349 Box.bottom = invalid->bottom;
353 status = gDevice->lpVtbl->CreateTexture2D(gDevice, &tDesc, NULL, &sStage);
357 WLog_ERR(TAG,
"Failed to create staging surface");
362 gContext->lpVtbl->CopySubresourceRegion(gContext, (ID3D11Resource*)sStage, 0, 0, 0, 0,
363 (ID3D11Resource*)gAcquiredDesktopImage, 0, &Box);
365 status = sStage->lpVtbl->QueryInterface(sStage, &IID_IDXGISurface, (
void**)&surf);
369 WLog_ERR(TAG,
"Failed to QI staging surface");
374 surf->lpVtbl->Map(surf, &mappedRect, DXGI_MAP_READ);
378 WLog_ERR(TAG,
"Failed to map staging surface");
383 *data = mappedRect.pBits;
384 *pitch = mappedRect.Pitch;
389 int wf_dxgi_releasePixelData(wfInfo* wfi)
393 surf->lpVtbl->Unmap(surf);
394 surf->lpVtbl->Release(surf);
396 sStage->lpVtbl->Release(sStage);
399 status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication);
403 WLog_ERR(TAG,
"Failed to release frame");
407 wfi->framesWaiting = 0;
412 int wf_dxgi_getInvalidRegion(RECT* invalid)
419 UINT DataBufferSize = 0;
420 BYTE* DataBuffer = NULL;
422 if (FrameInfo.AccumulatedFrames == 0)
427 if (FrameInfo.TotalMetadataBufferSize)
430 if (FrameInfo.TotalMetadataBufferSize > DataBufferSize)
438 DataBuffer = (BYTE*)malloc(FrameInfo.TotalMetadataBufferSize);
443 WLog_ERR(TAG,
"Failed to allocate memory for metadata");
447 DataBufferSize = FrameInfo.TotalMetadataBufferSize;
450 BufSize = FrameInfo.TotalMetadataBufferSize;
452 status = gOutputDuplication->lpVtbl->GetFrameMoveRects(
453 gOutputDuplication, BufSize, (DXGI_OUTDUPL_MOVE_RECT*)DataBuffer, &BufSize);
457 WLog_ERR(TAG,
"Failed to get frame move rects");
461 DirtyRects = DataBuffer + BufSize;
462 BufSize = FrameInfo.TotalMetadataBufferSize - BufSize;
464 status = gOutputDuplication->lpVtbl->GetFrameDirtyRects(gOutputDuplication, BufSize,
465 (RECT*)DirtyRects, &BufSize);
469 WLog_ERR(TAG,
"Failed to get frame dirty rects");
472 dirty = BufSize /
sizeof(RECT);
474 pRect = (RECT*)DirtyRects;
476 for (UINT i = 0; i < dirty; ++i)
478 UnionRect(invalid, invalid, pRect);