20#include <freerdp/config.h> 
   22#include "wf_interface.h" 
   34#include <freerdp/log.h> 
   35#define TAG SERVER_TAG("windows") 
   38D3D_DRIVER_TYPE DriverTypes[] = {
 
   39  D3D_DRIVER_TYPE_HARDWARE,
 
   41  D3D_DRIVER_TYPE_REFERENCE,
 
   43UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
 
   46D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
 
   47                                    D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
 
   49UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
 
   51D3D_FEATURE_LEVEL FeatureLevel;
 
   53ID3D11Device* gDevice = NULL;
 
   54ID3D11DeviceContext* gContext = NULL;
 
   55IDXGIOutputDuplication* gOutputDuplication = NULL;
 
   56ID3D11Texture2D* gAcquiredDesktopImage = NULL;
 
   59ID3D11Texture2D* sStage;
 
   61DXGI_OUTDUPL_FRAME_INFO FrameInfo;
 
   63int wf_dxgi_init(wfInfo* wfi)
 
   65  gAcquiredDesktopImage = NULL;
 
   67  if (wf_dxgi_createDevice(wfi) != 0)
 
   72  if (wf_dxgi_getDuplication(wfi) != 0)
 
   80int 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");
 
  106int 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);
 
  204int 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);
 
  238int 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);
 
  327int 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;
 
  389int 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;
 
  412int 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);