2 * FreeRDP: A Remote Desktop Protocol Client
3 * FreeRDP Windows Server
5 * Copyright 2012 Corey Clayton <can.of.tuna@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
28 // Driver types supported
29 D3D_DRIVER_TYPE DriverTypes[] =
31 D3D_DRIVER_TYPE_HARDWARE,
33 D3D_DRIVER_TYPE_REFERENCE,
35 UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
37 // Feature levels supported
38 D3D_FEATURE_LEVEL FeatureLevels[] =
40 D3D_FEATURE_LEVEL_11_0,
41 D3D_FEATURE_LEVEL_10_1,
42 D3D_FEATURE_LEVEL_10_0,
45 UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
47 D3D_FEATURE_LEVEL FeatureLevel;
49 ID3D11Device* MeinDevice = NULL;
50 ID3D11DeviceContext* MeinContext = NULL;
51 IDXGIOutputDuplication* MeinDeskDupl = NULL;
52 ID3D11Texture2D* MeinAcquiredDesktopImage = NULL;
55 ID3D11Texture2D * sStage;
57 DXGI_OUTDUPL_FRAME_INFO FrameInfo;
59 int wf_dxgi_init(wfInfo* context)
64 IDXGIDevice* DxgiDevice = NULL;
65 IDXGIAdapter* DxgiAdapter = NULL;
66 DXGI_OUTPUT_DESC desc;
68 IDXGIOutput * pOutput;
70 IDXGIOutput* DxgiOutput = NULL;
72 IDXGIOutput1* DxgiOutput1 = NULL;
75 /////////////////////////////////////////////////////////
77 //guessing this must be null
78 MeinAcquiredDesktopImage = NULL;
81 _tprintf(_T("Hallo, welt!\n"));
83 _tprintf(_T("Trying to create a DX11 Device...\n"));
85 for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
87 hr = D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, D3D11_CREATE_DEVICE_DEBUG, FeatureLevels, NumFeatureLevels,
88 D3D11_SDK_VERSION, &MeinDevice, &FeatureLevel, &MeinContext);
91 // Device creation success, no need to loop anymore
97 _tprintf(_T("Failed to create device in InitializeDx\n"));
100 _tprintf(_T("Gut!\n"));
102 ///////////////////////////////////////////////////////
105 _tprintf(_T("Trying to get QI for DXGI Device...\n"));
107 hr = MeinDevice->lpVtbl->QueryInterface(MeinDevice, &IID_IDXGIDevice, (void**) &DxgiDevice);
110 _tprintf(_T("Failed to get QI for DXGI Device\n"));
113 _tprintf(_T("Gut!\n"));
115 //////////////////////////////////////////////////////////
117 _tprintf(_T("Trying to get adapter for DXGI Device...\n"));
119 hr = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (void**) &DxgiAdapter);
120 DxgiDevice->lpVtbl->Release(DxgiDevice);
124 _tprintf(_T("Failed to get parent DXGI Adapter\n"));
127 _tprintf(_T("Gut!\n"));
129 ////////////////////////////////////////////////////////////
132 memset(&desc, 0, sizeof(desc));
134 _tprintf(_T("\nLooping through ouputs on DXGI adapter...\n"));
135 while(DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
137 DXGI_OUTPUT_DESC* pDesc = &desc;
139 hr = pOutput->lpVtbl->GetDesc(pOutput, pDesc);
142 _tprintf(_T("Failed to get description\n"));
146 _tprintf(_T("Output %d: [%s] [%d]\n"), i, pDesc->DeviceName, pDesc->AttachedToDesktop);
148 if(pDesc->AttachedToDesktop)
151 pOutput->lpVtbl->Release(pOutput);
155 //for now stick to the first one
159 _tprintf(_T("\nTrying to get output...\n"));
160 hr = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput);
161 DxgiAdapter->lpVtbl->Release(DxgiAdapter);
165 _tprintf(_T("Failed to get output\n"));
168 _tprintf(_T("Gut!\n"));
170 //////////////////////////////////////////////
172 _tprintf(_T("Trying to get IDXGIOutput1...\n"));
173 hr = DxgiOutput->lpVtbl->QueryInterface(DxgiOutput, &IID_IDXGIOutput1, (void**) &DxgiOutput1);
174 DxgiOutput->lpVtbl->Release(DxgiOutput);
178 _tprintf(_T("Failed to get IDXGIOutput1\n"));
181 _tprintf(_T("Gut!\n"));
183 //////////////////////////////////////////////
186 _tprintf(_T("Trying to duplicate the output...\n"));
187 hr = DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, (IUnknown*)MeinDevice, &MeinDeskDupl);
188 DxgiOutput1->lpVtbl->Release(DxgiOutput1);
192 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
194 _tprintf(_T("There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again.\n"));
197 _tprintf(_T("Failed to get duplicate output\n"));
200 _tprintf(_T("Gut! Init Complete!\n"));
203 int wf_dxgi_cleanup(wfInfo* context)
205 if(MeinAcquiredDesktopImage)
207 MeinAcquiredDesktopImage->lpVtbl->Release(MeinAcquiredDesktopImage);
208 MeinAcquiredDesktopImage = NULL;
213 MeinDeskDupl->lpVtbl->Release(MeinDeskDupl);
219 MeinContext->lpVtbl->Release(MeinContext);
225 MeinDevice->lpVtbl->Release(MeinDevice);
232 int wf_dxgi_nextFrame(wfInfo* context, UINT timeout)
235 IDXGIResource* DesktopResource = NULL;
239 BYTE* MeinMetaDataBuffer = NULL;
240 UINT MeinMetaDataSize = 0;
243 if(MeinAcquiredDesktopImage)
245 MeinAcquiredDesktopImage->lpVtbl->Release(MeinAcquiredDesktopImage);
246 MeinAcquiredDesktopImage = NULL;
249 _tprintf(_T("\nTrying to acquire a frame...\n"));
250 hr = MeinDeskDupl->lpVtbl->AcquireNextFrame(MeinDeskDupl, timeout, &FrameInfo, &DesktopResource);
251 _tprintf(_T("hr = %#0X\n"), hr);
252 if (hr == DXGI_ERROR_WAIT_TIMEOUT)
254 _tprintf(_T("Timeout\n"));
259 _tprintf(_T("Failed to acquire next frame\n"));
261 hr = MeinDeskDupl->lpVtbl->ReleaseFrame(MeinDeskDupl);
264 _tprintf(_T("Failed to release frame\n"));
268 _tprintf(_T("Gut!\n"));
270 ///////////////////////////////////////////////
273 _tprintf(_T("Trying to QI for ID3D11Texture2D...\n"));
274 hr = DesktopResource->lpVtbl->QueryInterface(DesktopResource, &IID_ID3D11Texture2D, (void**) &MeinAcquiredDesktopImage);
275 DesktopResource->lpVtbl->Release(DesktopResource);
276 DesktopResource = NULL;
279 _tprintf(_T("Failed to QI for ID3D11Texture2D from acquired IDXGIResource\n"));
282 _tprintf(_T("Gut!\n"));
284 if(FrameInfo.AccumulatedFrames == 0)
290 _tprintf(_T("FrameInfo\n"));
291 _tprintf(_T("\tAccumulated Frames: %d\n"), FrameInfo.AccumulatedFrames);
292 _tprintf(_T("\tCoalesced Rectangles: %d\n"), FrameInfo.RectsCoalesced);
293 _tprintf(_T("\tMetadata buffer size: %d\n"), FrameInfo.TotalMetadataBufferSize);
296 if(FrameInfo.TotalMetadataBufferSize)
299 if (FrameInfo.TotalMetadataBufferSize > MeinMetaDataSize)
301 if (MeinMetaDataBuffer)
303 free(MeinMetaDataBuffer);
304 MeinMetaDataBuffer = NULL;
306 MeinMetaDataBuffer = (BYTE*) malloc(FrameInfo.TotalMetadataBufferSize);
307 if (!MeinMetaDataBuffer)
309 MeinMetaDataSize = 0;
310 _tprintf(_T("Failed to allocate memory for metadata\n"));
313 MeinMetaDataSize = FrameInfo.TotalMetadataBufferSize;
316 BufSize = FrameInfo.TotalMetadataBufferSize;
318 // Get move rectangles
319 hr = MeinDeskDupl->lpVtbl->GetFrameMoveRects(MeinDeskDupl, BufSize, (DXGI_OUTDUPL_MOVE_RECT*) MeinMetaDataBuffer, &BufSize);
322 _tprintf(_T("Failed to get frame move rects\n"));
325 _tprintf(_T("Move rects: %d\n"), BufSize / sizeof(DXGI_OUTDUPL_MOVE_RECT));
327 DirtyRects = MeinMetaDataBuffer + BufSize;
328 BufSize = FrameInfo.TotalMetadataBufferSize - BufSize;
330 // Get dirty rectangles
331 hr = MeinDeskDupl->lpVtbl->GetFrameDirtyRects(MeinDeskDupl, BufSize, (RECT*) DirtyRects, &BufSize);
334 _tprintf(_T("Failed to get frame dirty rects\n"));
337 dirty = BufSize / sizeof(RECT);
338 _tprintf(_T("Dirty rects: %d\n"), dirty);
340 pRect = (RECT*) DirtyRects;
341 for(i = 0; i<dirty; ++i)
343 _tprintf(_T("\tRect: (%d, %d), (%d, %d)\n"),
359 int wf_dxgi_getPixelData(wfInfo* context, BYTE** data, int* pitch, RECT* invalid)
362 DXGI_MAPPED_RECT MeinData;
363 D3D11_TEXTURE2D_DESC tDesc;
366 if(wf_dxgi_getInvalidRegion(invalid))
368 _tprintf(_T("dxgi_getInvalidRegion failed\n"));
372 tDesc.Width = (invalid->right - invalid->left) + 1;
373 tDesc.Height = (invalid->bottom - invalid->top) + 1;
376 tDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
377 tDesc.SampleDesc.Count = 1;
378 tDesc.SampleDesc.Quality = 0;
379 tDesc.Usage = D3D11_USAGE_STAGING;
381 tDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;// | D3D11_CPU_ACCESS_WRITE;
384 Box.top = invalid->top;
385 Box.left = invalid->left;
386 Box.right = invalid->right;
387 Box.bottom = invalid->bottom;
391 _tprintf(_T("Trying to create staging surface\n"));
392 hr = MeinDevice->lpVtbl->CreateTexture2D(MeinDevice, &tDesc, NULL, &sStage);
395 _tprintf(_T("Failed to create staging surface\n"));
398 _tprintf(_T("Gut!\n"));
400 MeinContext->lpVtbl->CopySubresourceRegion(MeinContext, (ID3D11Resource*)sStage, 0,0,0,0, (ID3D11Resource*)MeinAcquiredDesktopImage, 0, &Box);
402 _tprintf(_T("Trying to QI staging surface\n"));
403 hr = sStage->lpVtbl->QueryInterface(sStage, &IID_IDXGISurface, (void**)&surf);
406 _tprintf(_T("Failed to QI staging surface\n"));
409 _tprintf(_T("Gut!\n"));
411 _tprintf(_T("Trying to map staging surface\n"));
412 surf->lpVtbl->Map(surf, &MeinData, DXGI_MAP_READ);
415 _tprintf(_T("Failed to map staging surface\n"));
418 _tprintf(_T("Gut!\n"));
422 *data = MeinData.pBits;
423 *pitch = MeinData.Pitch;
428 int wf_dxgi_releasePixelData(wfInfo* context)
432 surf->lpVtbl->Unmap(surf);
433 surf->lpVtbl->Release(surf);
435 sStage->lpVtbl->Release(sStage);
438 hr = MeinDeskDupl->lpVtbl->ReleaseFrame(MeinDeskDupl);
441 _tprintf(_T("Failed to release frame\n"));
446 int wf_dxgi_getInvalidRegion(RECT* invalid)
449 UINT MeinMetaDataSize = 0;
456 //optimization note: make this buffer global and allocate only once (or grow only when needed)
457 BYTE* MeinMetaDataBuffer = NULL;
461 _tprintf(_T("FrameInfo\n"));
462 _tprintf(_T("\tAccumulated Frames: %d\n"), FrameInfo.AccumulatedFrames);
463 _tprintf(_T("\tCoalesced Rectangles: %d\n"), FrameInfo.RectsCoalesced);
464 _tprintf(_T("\tMetadata buffer size: %d\n"), FrameInfo.TotalMetadataBufferSize);
467 if(FrameInfo.TotalMetadataBufferSize)
470 if (FrameInfo.TotalMetadataBufferSize > MeinMetaDataSize)
472 if (MeinMetaDataBuffer)
474 free(MeinMetaDataBuffer);
475 MeinMetaDataBuffer = NULL;
477 MeinMetaDataBuffer = (BYTE*) malloc(FrameInfo.TotalMetadataBufferSize);
478 if (!MeinMetaDataBuffer)
480 MeinMetaDataSize = 0;
481 _tprintf(_T("Failed to allocate memory for metadata\n"));
484 MeinMetaDataSize = FrameInfo.TotalMetadataBufferSize;
487 BufSize = FrameInfo.TotalMetadataBufferSize;
489 // Get move rectangles
490 hr = MeinDeskDupl->lpVtbl->GetFrameMoveRects(MeinDeskDupl, BufSize, (DXGI_OUTDUPL_MOVE_RECT*) MeinMetaDataBuffer, &BufSize);
493 _tprintf(_T("Failed to get frame move rects\n"));
496 _tprintf(_T("Move rects: %d\n"), BufSize / sizeof(DXGI_OUTDUPL_MOVE_RECT));
498 DirtyRects = MeinMetaDataBuffer + BufSize;
499 BufSize = FrameInfo.TotalMetadataBufferSize - BufSize;
501 // Get dirty rectangles
502 hr = MeinDeskDupl->lpVtbl->GetFrameDirtyRects(MeinDeskDupl, BufSize, (RECT*) DirtyRects, &BufSize);
505 _tprintf(_T("Failed to get frame dirty rects\n"));
508 dirty = BufSize / sizeof(RECT);
509 _tprintf(_T("Dirty rects: %d\n"), dirty);
511 pRect = (RECT*) DirtyRects;
512 for(i = 0; i<dirty; ++i)
514 _tprintf(_T("\tRect: (%d, %d), (%d, %d)\n"),
520 UnionRect(invalid, invalid, pRect);