示例#1
0
void DesktopDuplication::init()
{
	IDXGIFactory1* dxgiFactory = nullptr;
	CHECKED(hr, CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory)));

	IDXGIAdapter1* dxgiAdapter = nullptr;
	CHECKED(hr, dxgiFactory->EnumAdapters1(adapter, &dxgiAdapter));
	dxgiFactory->Release();

	CHECKED(hr, D3D11CreateDevice(dxgiAdapter,
		D3D_DRIVER_TYPE_UNKNOWN,
		NULL,
		NULL,
		NULL,
		NULL,
		D3D11_SDK_VERSION,
		&d3dDevice,
		NULL,
		&d3dContext));

	IDXGIOutput* dxgiOutput = nullptr;
	CHECKED(hr, dxgiAdapter->EnumOutputs(output, &dxgiOutput));
	dxgiAdapter->Release();

	IDXGIOutput1* dxgiOutput1 = nullptr;
	CHECKED(hr, dxgiOutput->QueryInterface(__uuidof(dxgiOutput1), reinterpret_cast<void**>(&dxgiOutput1)));
	dxgiOutput->Release();

	IDXGIDevice* dxgiDevice = nullptr;
	CHECKED(hr, d3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice)));

	CHECKED(hr, dxgiOutput1->DuplicateOutput(dxgiDevice, &outputDuplication));
	dxgiOutput1->Release();
	dxgiDevice->Release();
}
bool CDuplicateOutputDx11::CreateOutputDuplicator()
{
	SAFE_RELEASE(m_pOutputDuplication);

	HRESULT hRes = S_OK;
	IDXGIDevice* pDxgiDevice = nullptr;

	hRes = m_pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDxgiDevice));
	if (!SUCCEEDED(hRes))
	{
		DOLOG("m_pDevice->QueryInterface failed!");
		return false;
	}
	
	IDXGIAdapter* pDxgiAdapter = nullptr;
	hRes = pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&pDxgiAdapter));
	SAFE_RELEASE(pDxgiDevice);
	if (!SUCCEEDED(hRes))
	{
		DOLOG("pDxgiDevice->GetParent failed!");
		return false;
	}
	
	DXGI_ADAPTER_DESC descAdapter;
	pDxgiAdapter->GetDesc(&descAdapter);

	// Get output
	IDXGIOutput* pDxgiOutput = nullptr;
	hRes = pDxgiAdapter->EnumOutputs(0, &pDxgiOutput);
	SAFE_RELEASE(pDxgiAdapter);
	if (!SUCCEEDED(hRes))
	{
		DOLOG("pDxgiAdapter->EnumOutputs failed!");
		return false;
	}

	// Get output1
    IDXGIOutput1* pDxgiOutput1 = nullptr;
    hRes = pDxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&pDxgiOutput1));
	SAFE_RELEASE(pDxgiOutput);
    if (!SUCCEEDED(hRes))
    {
		DOLOG("pDxgiOutput->QueryInterface failed!");
		return false;
    }
	
	// Get duplicate
	hRes = pDxgiOutput1->DuplicateOutput(m_pDevice, &m_pOutputDuplication);
	SAFE_RELEASE(pDxgiOutput1);
	if (!SUCCEEDED(hRes))
	{
		DOLOG("pDxgiOutput1->DuplicateOutput");
		return false;
	}
		
	return true;
}
示例#3
0
void RenderSettingsManager::InitFromDevice( HWND window, ID3D11Device *d3dDevice, IDXGIAdapter1 *adapter )
{
	_ASSERTE( d3dDevice );
	_ASSERTE( adapter );

	std::lock_guard<std::mutex> lock( _mutex );
	_window = window;
	Cleanup();

	IDXGIOutput *temp;
	if ( FAILED( adapter->EnumOutputs( 0, &temp ) ) ) {
		return;
	}
	IDXGIOutput1 *output;
	if ( FAILED( temp->QueryInterface( __uuidof(IDXGIOutput1), (void **)&output ) ) ) {
		return;
	}
	SAFE_RELEASE( temp );

	UINT32 maxAdaptorModes = 0U;
	if ( FAILED( output->GetDisplayModeList1( BACKBUFFER_FORMAT, 0, &maxAdaptorModes, nullptr ) ) ) {
		SAFE_RELEASE( output );
		return;
	}

	DXGI_MODE_DESC1 *modes = new DXGI_MODE_DESC1[maxAdaptorModes];
	if ( FAILED( output->GetDisplayModeList1( BACKBUFFER_FORMAT, 0, &maxAdaptorModes, modes ) ) ) {
		SAFE_RELEASE( output );
		delete[] modes;
		return;
	}

	bool foundMatchingCurrentAdaptor = false;

	for ( UINT32 mode = 0; mode < maxAdaptorModes; ++mode ) {
		DXGI_MODE_DESC1 *displayMode = &modes[mode];
		// Does this adaptor mode support  the desired format and is it above the minimum required resolution
		if ( displayMode->Format == BACKBUFFER_FORMAT && 
				!displayMode->Stereo && // Stereo adapters not currently supported
				displayMode->Width >= Resources::MIN_SCREEN_X && 
				displayMode->Height >= Resources::MIN_SCREEN_Y ) {

			LOG( "Found valid adapter mode " << displayMode->Width << "x" << displayMode->Height, LOG_MEDIUM );
			AdaptorMode adaptorMode;
			adaptorMode.Width = displayMode->Width;
			adaptorMode.Height = displayMode->Height;
			adaptorMode.RefreshRateNumerator = displayMode->RefreshRate.Numerator;
			adaptorMode.RefreshRateDenominator = displayMode->RefreshRate.Denominator;
			_adaptorModes.push_back( adaptorMode );

			// try to preserve the current adaptor mode settings when devices change
			if ( _currentAdaptorMode.Width == adaptorMode.Width &&
				_currentAdaptorMode.Height == adaptorMode.Height &&
				_currentAdaptorMode.RefreshRateNumerator == adaptorMode.RefreshRateNumerator &&
				_currentAdaptorMode.RefreshRateDenominator == adaptorMode.RefreshRateDenominator ) 
			{
				_currentAdaptorMode = adaptorMode;
				foundMatchingCurrentAdaptor = true;
			}
		}
	}

	// ensure we always have a current adaptor mode set
	if ( !foundMatchingCurrentAdaptor ) {
		_currentAdaptorMode = _adaptorModes.at( 0 );
	}

	delete[] modes;

	//determine the supported multisampling settings for this device
	for ( UINT32 i = 1; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++i ) {
		UINT32 quality = 0;
		if ( FAILED( d3dDevice->CheckMultisampleQualityLevels( BACKBUFFER_FORMAT, i, &quality ) ) || quality == 0 ) {
			continue;
		}
		LOG( "Found valid multisample level " << i , LOG_MEDIUM );
		_multiSampleLevels.push_back( i );
		_multiSampleQuality[i] = quality;
	}
	SAFE_RELEASE( output );
}
int main() {

  printf("\n\ntest_win_api_directx_research\n\n");

  /* Retrieve a IDXGIFactory that can enumerate the adapters. */
  IDXGIFactory1* factory = NULL;
  HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&factory));

  if (S_OK != hr) {
    printf("Error: failed to retrieve the IDXGIFactory.\n");
    exit(EXIT_FAILURE);
  }

  /* Enumerate the adapters.*/
  UINT i = 0;
  IDXGIAdapter1* adapter = NULL;
  std::vector<IDXGIAdapter1*> adapters; /* Needs to be Released(). */

  while (DXGI_ERROR_NOT_FOUND != factory->EnumAdapters1(i, &adapter)) {
    adapters.push_back(adapter);
    ++i;
  }

  /* Get some info about the adapters (GPUs). */
  for (size_t i = 0; i < adapters.size(); ++i) {
    
    DXGI_ADAPTER_DESC1 desc;
    adapter = adapters[i];
    hr = adapter->GetDesc1(&desc);
    
    if (S_OK != hr) {
      printf("Error: failed to get a description for the adapter: %lu\n", i);
      continue;
    }

    wprintf(L"Adapter: %lu, description: %s\n", i, desc.Description);
  }

  /* Check what devices/monitors are attached to the adapters. */
  UINT dx = 0;
  IDXGIOutput* output = NULL;
  std::vector<IDXGIOutput*> outputs; /* Needs to be Released(). */
  
  for (size_t i = 0; i < adapters.size(); ++i) {

    dx = 0;
    adapter = adapters[i];
    
    while (DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(dx, &output)) {
      printf("Found monitor %d on adapter: %lu\n", dx, i);
      outputs.push_back(output);
      ++dx;
    }
  }

  if (0 >= outputs.size()) {
    printf("Error: no outputs found (%lu).\n", outputs.size());
    exit(EXIT_FAILURE);
  }

  /* Print some info about the monitors. */
  for (size_t i = 0; i < outputs.size(); ++i) {
    
    DXGI_OUTPUT_DESC desc;
    output = outputs[i];
    hr = output->GetDesc(&desc);
    
    if (S_OK != hr) {
      printf("Error: failed to retrieve a DXGI_OUTPUT_DESC for output %lu.\n", i);
      continue;
    }

    wprintf(L"Monitor: %s, attached to desktop: %c\n", desc.DeviceName, (desc.AttachedToDesktop) ? 'y' : 'n');
  }

  /*

    To get access to a OutputDuplication interface we need to have a 
    Direct3D device which handles the actuall rendering and "gpu" 
    stuff. According to a gamedev stackexchange it seems we can create
    one w/o a HWND. 

   */

  ID3D11Device* d3d_device = NULL; /* Needs to be released. */
  ID3D11DeviceContext* d3d_context = NULL; /* Needs to be released. */
  IDXGIAdapter1* d3d_adapter = NULL;
  D3D_FEATURE_LEVEL d3d_feature_level; /* The selected feature level (D3D version), selected from the Feature Levels array, which is NULL here; when it's NULL the default list is used see:  https://msdn.microsoft.com/en-us/library/windows/desktop/ff476082%28v=vs.85%29.aspx ) */
  
  { /* Start creating a D3D11 device */

#if 1
    /* 
       NOTE:  Apparently the D3D11CreateDevice function returns E_INVALIDARG, when
              you pass a pointer to an adapter for the first parameter and use the 
              D3D_DRIVER_TYPE_HARDWARE. When you want to pass a valid pointer for the
              adapter, you need to set the DriverType parameter (2nd) to 
              D3D_DRIVER_TYPE_UNKNOWN.
             
              @todo figure out what would be the best solution; easiest to use is 
              probably using NULL here. 
     */
    int use_adapter = 0;
    if (use_adapter >= adapters.size()) {
      printf("Invalid adapter index: %d, we only have: %lu - 1\n", use_adapter, adapters.size());
      exit(EXIT_FAILURE);
    }

    d3d_adapter = adapters[use_adapter];
    if (NULL == d3d_adapter) {
      printf("Error: the stored adapter is NULL.\n");
      exit(EXIT_FAILURE);
    }
#endif

    hr = D3D11CreateDevice(d3d_adapter,              /* Adapter: The adapter (video card) we want to use. We may use NULL to pick the default adapter. */  
                           D3D_DRIVER_TYPE_UNKNOWN,  /* DriverType: We use the GPU as backing device. */
                           NULL,                     /* Software: we're using a D3D_DRIVER_TYPE_HARDWARE so it's not applicaple. */
                           NULL,                     /* Flags: maybe we need to use D3D11_CREATE_DEVICE_BGRA_SUPPORT because desktop duplication is using this. */
                           NULL,                     /* Feature Levels (ptr to array):  what version to use. */
                           0,                        /* Number of feature levels. */
                           D3D11_SDK_VERSION,        /* The SDK version, use D3D11_SDK_VERSION */
                           &d3d_device,              /* OUT: the ID3D11Device object. */
                           &d3d_feature_level,       /* OUT: the selected feature level. */
                           &d3d_context);            /* OUT: the ID3D11DeviceContext that represents the above features. */

    if (S_OK != hr) {
      printf("Error: failed to create the D3D11 Device.\n");
      if (E_INVALIDARG == hr) {
        printf("Got INVALID arg passed into D3D11CreateDevice. Did you pass a adapter + a driver which is not the UNKNOWN driver?.\n");
      }
      exit(EXIT_FAILURE);
    }
    
  } /* End creating a D3D11 device. */
  
  /* 
     Create a IDXGIOutputDuplication for the first monitor. 
     
     - From a IDXGIOutput which represents an monitor, we query a IDXGIOutput1
       because the IDXGIOutput1 has the DuplicateOutput feature. 
  */

  IDXGIOutput1* output1 = NULL;
  IDXGIOutputDuplication* duplication = NULL;
  
  { /* Start IDGIOutputDuplication init. */
    
    int use_monitor = 0;
    if (use_monitor >= outputs.size()) {
      printf("Invalid monitor index: %d, we only have: %lu - 1\n", use_monitor, outputs.size());
      exit(EXIT_FAILURE);
    }

    output = outputs[use_monitor];
    if (NULL == output) {
      printf("No valid output found. The output is NULL.\n");
      exit(EXIT_FAILURE);
    }
    
    hr = output->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1);
    if (S_OK != hr) {
      printf("Error: failed to query the IDXGIOutput1 interface.\n");
      exit(EXIT_FAILURE);
    }

    hr = output1->DuplicateOutput(d3d_device, &duplication);
    if (S_OK != hr) {
      printf("Error: failed to create the duplication output.\n");
      exit(EXIT_FAILURE);
    }
    printf("Queried the IDXGIOutput1.\n");
                                
  } /* End IDGIOutputDuplication init. */

  if (NULL == duplication) {
    printf("Error: okay, we shouldn't arrive here but the duplication var is NULL.\n");
    exit(EXIT_FAILURE);
  }

  /*
    To download the pixel data from the GPU we need a 
    staging texture. Therefore we need to determine the width and 
    height of the buffers that we receive. 
    
    @TODO - We could also retrieve the width/height from the texture we got 
            from through the acquired frame (see the 'tex' variable below).
            That may be a safer solution.
  */
  DXGI_OUTPUT_DESC output_desc;
  {
    hr = output->GetDesc(&output_desc);
    if (S_OK != hr) {
      printf("Error: failed to get the DXGI_OUTPUT_DESC from the output (monitor). We need this to create a staging texture when downloading the pixels from the gpu.\n");
      exit(EXIT_FAILURE);
    }

    printf("The monitor has the following dimensions: left: %d, right: %d, top: %d, bottom: %d.\n"
           ,(int)output_desc.DesktopCoordinates.left
           ,(int)output_desc.DesktopCoordinates.right
           ,(int)output_desc.DesktopCoordinates.top
           ,(int)output_desc.DesktopCoordinates.bottom
           );
  }

  if (0 == output_desc.DesktopCoordinates.right
      || 0 == output_desc.DesktopCoordinates.bottom)
    {
      printf("The output desktop coordinates are invalid.\n");
      exit(EXIT_FAILURE);
    }
    
  /* Create the staging texture that we need to download the pixels from gpu. */
  D3D11_TEXTURE2D_DESC tex_desc;
  tex_desc.Width = output_desc.DesktopCoordinates.right;
  tex_desc.Height = output_desc.DesktopCoordinates.bottom;
  tex_desc.MipLevels = 1;
  tex_desc.ArraySize = 1; /* When using a texture array. */
  tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; /* This is the default data when using desktop duplication, see https://msdn.microsoft.com/en-us/library/windows/desktop/hh404611(v=vs.85).aspx */
  tex_desc.SampleDesc.Count = 1; /* MultiSampling, we can use 1 as we're just downloading an existing one. */
  tex_desc.SampleDesc.Quality = 0; /* "" */
  tex_desc.Usage = D3D11_USAGE_STAGING;
  tex_desc.BindFlags = 0;
  tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  tex_desc.MiscFlags = 0;

  ID3D11Texture2D* staging_tex = NULL;
  hr = d3d_device->CreateTexture2D(&tex_desc, NULL, &staging_tex);
  if (E_INVALIDARG == hr) {
    printf("Error: received E_INVALIDARG when trying to create the texture.\n");
    exit(EXIT_FAILURE);
  }
  else if (S_OK != hr) {
    printf("Error: failed to create the 2D texture, error: %d.\n", hr);
    exit(EXIT_FAILURE);
  }
   
  /* 
     Get some info about the output duplication. 
     When the DesktopImageInSystemMemory is TRUE you can use 
     the MapDesktopSurface/UnMapDesktopSurface directly to retrieve the
     pixel data. If not, then you need to use a surface. 

  */
  DXGI_OUTDUPL_DESC duplication_desc;
  duplication->GetDesc(&duplication_desc);
  printf("duplication desc.DesktopImageInSystemMemory: %c\n", (duplication_desc.DesktopImageInSystemMemory) ? 'y' : 'n');
  
  /* Access a couple of frames. */
  DXGI_OUTDUPL_FRAME_INFO frame_info;
  IDXGIResource* desktop_resource = NULL;
  ID3D11Texture2D* tex = NULL;
  DXGI_MAPPED_RECT mapped_rect;
  
  for (int i = 0; i < 500; ++i) {
    //  printf("%02d - ", i);
    
    hr = duplication->AcquireNextFrame(1000, &frame_info, &desktop_resource);
    if (DXGI_ERROR_ACCESS_LOST == hr) {
      printf("Received a DXGI_ERROR_ACCESS_LOST.\n");
    }
    else if (DXGI_ERROR_WAIT_TIMEOUT == hr) {
      printf("Received a DXGI_ERROR_WAIT_TIMEOUT.\n");
    }
    else if (DXGI_ERROR_INVALID_CALL == hr) {
      printf("Received a DXGI_ERROR_INVALID_CALL.\n");
    }
    else if (S_OK == hr) {
      //printf("Yay we got a frame.\n");

      /* Print some info. */
      //printf("frame_info.TotalMetadataBufferSize: %u\n", frame_info.TotalMetadataBufferSize);
      //printf("frame_info.AccumulatedFrames: %u\n", frame_info.AccumulatedFrames);

      /* Get the texture interface .. */
#if 1      
      hr = desktop_resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&tex);
      if (S_OK != hr) {
        printf("Error: failed to query the ID3D11Texture2D interface on the IDXGIResource we got.\n");
        exit(EXIT_FAILURE);
      }
#endif      

      /* Map the desktop surface */
      hr = duplication->MapDesktopSurface(&mapped_rect);
      if (S_OK == hr) {
        printf("We got acess to the desktop surface\n");
        hr = duplication->UnMapDesktopSurface();
        if (S_OK != hr) {
          printf("Error: failed to unmap the desktop surface after successfully mapping it.\n");
        }
      }
      else if (DXGI_ERROR_UNSUPPORTED == hr) {
        //printf("MapDesktopSurface returned DXGI_ERROR_UNSUPPORTED.\n");
        /* 
           According to the docs, when we receive this error we need
           to transfer the image to a staging surface and then lock the 
            image by calling IDXGISurface::Map().

           To get the data from GPU to the CPU, we do:

               - copy the frame into our staging texture
               - map the texture 
               - ... do something 
               - unmap.

           @TODO figure out what solution is faster:

           There are multiple solutions to copy a texture. I have 
           to look into what solution is better. 
           -  d3d_context->CopySubresourceRegion();
           -  d3d_context->CopyResource(dest, src)

           @TODO we need to make sure that the width/height are valid. 
 
        */

        d3d_context->CopyResource(staging_tex, tex);

        D3D11_MAPPED_SUBRESOURCE map;
        HRESULT map_result = d3d_context->Map(staging_tex,          /* Resource */
                                              0,                    /* Subresource */ 
                                              D3D11_MAP_READ,       /* Map type. */
                                              0,                    /* Map flags. */
                                              &map);

        if (S_OK == map_result) {
          unsigned char* data = (unsigned char*)map.pData;
          //printf("Mapped the staging tex; we can access the data now.\n");
          printf("RowPitch: %u, DepthPitch: %u, %02X, %02X, %02X\n", map.RowPitch, map.DepthPitch, data[0], data[1], data[2]);
#if 0
          if (i < 25) {
            char fname[512];

            /* We have to make the image opaque. */

            for (int k = 0; k < tex_desc.Width; ++k) {
              for (int l = 0; l < tex_desc.Height; ++l) {
                int dx = l * tex_desc.Width * 4 + k * 4;
                data[dx + 3] = 0xFF;
              }
            }
            sprintf(fname, "capture_%03d.png", i);
            save_png(fname,
                     tex_desc.Width, tex_desc.Height, 8, PNG_COLOR_TYPE_RGBA,
                     (unsigned char*)map.pData, map.RowPitch, PNG_TRANSFORM_BGR);
          }
#endif
        }
        else {
          printf("Error: failed to map the staging tex. Cannot access the pixels.\n");
        }

        d3d_context->Unmap(staging_tex, 0);
      }
      else if (DXGI_ERROR_INVALID_CALL == hr) {
        printf("MapDesktopSurface returned DXGI_ERROR_INVALID_CALL.\n");
      }
      else if (DXGI_ERROR_ACCESS_LOST == hr) {
        printf("MapDesktopSurface returned DXGI_ERROR_ACCESS_LOST.\n");
      }
      else if (E_INVALIDARG == hr) {
        printf("MapDesktopSurface returned E_INVALIDARG.\n");
      }
      else {
        printf("MapDesktopSurface returned an unknown error.\n");
      }
    }

    /* Clean up */
    {

      if (NULL != tex) {
        tex->Release();
        tex = NULL;
      }
      
      if (NULL != desktop_resource) {
        desktop_resource->Release();
        desktop_resource = NULL;
      }

      /* We must release the frame. */
      hr = duplication->ReleaseFrame();
      if (S_OK != hr) {
        printf("Failed to release the duplication frame.\n");
      }
    }
  }
  
  //printf("Monitors connected to adapter: %lu\n", i);

  /* Cleanup */
  {

    if (NULL != staging_tex) {
      staging_tex->Release();
      staging_tex = NULL;
    }
    
    if (NULL != d3d_device) {
      d3d_device->Release();
      d3d_device = NULL;
    }

    if (NULL != d3d_context) {
      d3d_context->Release();
      d3d_context = NULL;
    }

    if (NULL != duplication) {
      duplication->Release();
      duplication = NULL;
    }
    
    for (size_t i = 0; i < adapters.size(); ++i) {
      if (NULL != adapters[i]) {
        adapters[i]->Release();
        adapters[i] = NULL;
      }
    }

    for (size_t i = 0; i < outputs.size(); ++i) {
      if (NULL != outputs[i]) {
        outputs[i]->Release();
        outputs[i] = NULL;
      }
    }

    if (NULL != output1) {
      output1->Release();
      output1 = NULL;
    }

    if (NULL != factory) {
      factory->Release();
      factory = NULL;
    }
  }
  
  return 0;
}
//
// Initialize duplication interfaces
//
DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, UINT Output)
{
    m_OutputNumber = Output;

    // Take a reference on the device
    m_Device = Device;
    m_Device->AddRef();

    // Get DXGI device
    IDXGIDevice* DxgiDevice = nullptr;
    HRESULT hr = m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&DxgiDevice));
    if (FAILED(hr))
    {
        return ProcessFailure(nullptr, L"Failed to QI for DXGI Device", L"Error", hr);
    }

    // Get DXGI adapter
    IDXGIAdapter* DxgiAdapter = nullptr;
    hr = DxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&DxgiAdapter));
    DxgiDevice->Release();
    DxgiDevice = nullptr;
    if (FAILED(hr))
    {
        return ProcessFailure(m_Device, L"Failed to get parent DXGI Adapter", L"Error", hr, SystemTransitionsExpectedErrors);
    }

    // Get output
    IDXGIOutput* DxgiOutput = nullptr;
    hr = DxgiAdapter->EnumOutputs(Output, &DxgiOutput);
    DxgiAdapter->Release();
    DxgiAdapter = nullptr;
    if (FAILED(hr))
    {
        return ProcessFailure(m_Device, L"Failed to get specified output in DUPLICATIONMANAGER", L"Error", hr, EnumOutputsExpectedErrors);
    }

    DxgiOutput->GetDesc(&m_OutputDesc);

    // QI for Output 1
    IDXGIOutput1* DxgiOutput1 = nullptr;
    hr = DxgiOutput->QueryInterface(__uuidof(DxgiOutput1), reinterpret_cast<void**>(&DxgiOutput1));
    DxgiOutput->Release();
    DxgiOutput = nullptr;
    if (FAILED(hr))
    {
        return ProcessFailure(nullptr, L"Failed to QI for DxgiOutput1 in DUPLICATIONMANAGER", L"Error", hr);
    }

    // Create desktop duplication
    hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl);
    DxgiOutput1->Release();
    DxgiOutput1 = nullptr;
    if (FAILED(hr))
    {
        if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
        {
            MessageBoxW(nullptr, L"There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again.", L"Error", MB_OK);
            return DUPL_RETURN_ERROR_UNEXPECTED;
        }
        return ProcessFailure(m_Device, L"Failed to get duplicate output in DUPLICATIONMANAGER", L"Error", hr, CreateDuplicationExpectedErrors);
    }

    return DUPL_RETURN_SUCCESS;
}
  int ScreenCaptureDuplicateOutputDirect3D11::configure(Settings cfg) {

    HRESULT hr = E_FAIL;
    
    /* Validate input. */
    if (cfg.display >= displays.size()) {
      printf("Error: given display index is invalid; out of bounds.\n");
      return -1;
    }

    if (NULL == device) {
      printf("Error: the D3D11 device is NULL. Did you call init?\n");
      return -2;
    }

    if (SC_BGRA != cfg.pixel_format) {
      printf("Trying to configure the Screen Capture, but we received an unsupported pixel format. %d\n", cfg.pixel_format);
      return -3;
    }
       
    /* Check state */
    if (NULL != output) {
      output->Release();
      output = NULL;
    }

    if (NULL != duplication) {
      duplication->Release();
      duplication = NULL;
    }

    if (0 != pixel_buffer.init(cfg.output_width, cfg.output_height, cfg.pixel_format)) {
      printf("Error: failed to initialize the pixel buffer.");
      return -4;
    }
    
    /* @todo > WE DON'T WANT TO MAKE THIS THE RESPONSIBILITY OF AN IMPLEMENTATION! */
    pixel_buffer.user = user;
    
    /*
      When the renderer is already initialized, we first deallocate/release
       all created objects that are used to perform the scaling. 
    */
    if (0 == renderer.isInit()) {
      renderer.shutdown();
    }

    /* We can only initialize the transform, after we know the output width/height. */
    ScreenCaptureRendererSettingsDirect3D11 trans_cfg;
    trans_cfg.device = device;
    trans_cfg.context = context;
    trans_cfg.output_width = cfg.output_width;
    trans_cfg.output_height = cfg.output_height;
    trans_cfg.cb_scaled = on_scaled_pixels;
    trans_cfg.cb_user = this;
    
    if (0 != renderer.init(trans_cfg)) {
      printf("Error: failed to initialize the tansform for the screen capture.\n");
      return -5;
    }

    Display* display = displays[cfg.display];
    if (NULL == display->info) {
      printf("Error: The display doesn't a valid info member. Not supposed to happen.\n");
      return -6;
    }
    
    IDXGIOutput* monitor = static_cast<IDXGIOutput*>(display->info);
    if (NULL == monitor) {
      printf("Error: failed to cast the info member of the display to IDXGIOutput*.\n");
      return -7;
    }
    
    hr = monitor->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output);
    if (S_OK != hr) {
      printf("Error: failed to query the IDXGIOutput1 which exposes the Output Duplication interface.\n");
      return -8;
    }

    hr = output->DuplicateOutput(device, &duplication);
    if (S_OK != hr) {
      printf("Error: failed to duplicate the output.\n");
      output->Release();
      output = NULL;
      return -9;
    }

    /* Get info about the output (monitor). */
    ZeroMemory(&output_desc, sizeof(output_desc));
    hr = output->GetDesc(&output_desc);
    
    if (S_OK != hr) {
      printf("Error: failed to retrieve output information.\n");
      output->Release();
      duplication->Release();
      output = NULL;
      duplication = NULL;
      return -10;
    }

#if !defined(NDEBUG)    
    printf("The monitor has the following dimensions: left: %d, right: %d, top: %d, bottom: %d.\n"
           ,(int)output_desc.DesktopCoordinates.left
           ,(int)output_desc.DesktopCoordinates.right
           ,(int)output_desc.DesktopCoordinates.top
           ,(int)output_desc.DesktopCoordinates.bottom
           );
#endif    

    /* Currently this class assumes the captured desktop image is in GPU
       mem; and we optimised for this. If the memory is already in CPU we
       need to change some stuff. Here I check if the mem is on GPU. */
    
    DXGI_OUTDUPL_DESC duplication_desc;
    duplication->GetDesc(&duplication_desc);

    if (TRUE == duplication_desc.DesktopImageInSystemMemory) {
      printf("Error: the desktop image is already in system memory; this is something we still need to implement.\n");
      output->Release();
      duplication->Release();
      output = NULL;
      duplication = NULL;
      return -11;
    }

    return 0;
  }
示例#7
0
bool RenderCore::Init(int screenWidth, int screenHeight, HWND hWnd)
{
	HRESULT hr;
		
	IDXGIAdapter1 *adapter;
	IDXGIOutput *adapterOutput;
	IDXGIOutput1 *adapterOutput1;

	DXGI_ADAPTER_DESC adapterDesc;	
	DXGI_MODE_DESC *displayModeList;
	DXGI_SWAP_CHAIN_DESC swapChainDesc;

	ID3D11Texture2D *pBackBuffer;

	D3D11_TEXTURE2D_DESC depthBufferDesc;
	D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
	D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;
	D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
	D3D11_RASTERIZER_DESC rasterDesc;	

	uint32_t numModes, fpsNumerator, fpsDenominator;
	size_t stringLength;
	int error;
	float fov, aspect;
		
	if (!EnumerateDisplayAdapters(&g_DXGIAdapters)) {
		return false;
	}
	adapter = g_DXGIAdapters.at(0);

	hr = adapter->EnumOutputs(0, &adapterOutput);
	if (FAILED(hr)) {
		return false;
	}
	
	// desktop duplication stuff
	hr = adapterOutput->QueryInterface(&adapterOutput1);
	
	hr = adapterOutput1->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
	if (FAILED(hr)) {
		return false;
	}

	displayModeList = new DXGI_MODE_DESC[numModes];
	if (!displayModeList) {
		return false;
	}

	hr = adapterOutput1->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
	if (FAILED(hr)) {
		return false;
	}
	
	for (UINT i = 0; i < numModes; i++) {
		if (displayModeList[i].Width == (unsigned int)screenWidth) {
			if (displayModeList[i].Height == (unsigned int)screenHeight) {
				fpsNumerator = displayModeList[i].RefreshRate.Numerator;
				fpsDenominator = displayModeList[i].RefreshRate.Denominator;
			}
		}
	}

	hr = adapter->GetDesc(&adapterDesc);
	if (FAILED(hr)) {
		return false;
	}
		
	// retrieve video adapter memory and name
	m_VideoMemory = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024);	
	
	error = wcstombs_s(&stringLength, m_VideoCardDesc, 128, adapterDesc.Description, 128);
	
	if (error != 0) {
		return false;
	}
	DebugOut("Found graphics adapter: %s (%dMB VRAM)\n", m_VideoCardDesc, m_VideoMemory);

	delete[] displayModeList;
	displayModeList = nullptr;

	adapterOutput->Release();
	adapter->Release();
	
	// set single back buffer
	ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
	swapChainDesc.BufferCount = 1;
	swapChainDesc.BufferDesc.Width = screenWidth;
	swapChainDesc.BufferDesc.Height = screenHeight;
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.OutputWindow = hWnd;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.Windowed = true;
	//swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	//swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	//swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	//swapChainDesc.Flags = 0;

	// create swap chain, direct3d device, and d3d context	
	uint32_t deviceFlags = 0;
#define D3D_DEVICE_DEBUG
#ifdef D3D_DEVICE_DEBUG
	deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	D3D_FEATURE_LEVEL featureLevels[] = {
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};
	uint32_t numFeatureLevels = ARRAYSIZE(featureLevels);

	hr = D3D11CreateDeviceAndSwapChain(		nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, deviceFlags, featureLevels, numFeatureLevels,
											D3D11_SDK_VERSION, &swapChainDesc, &m_SwapChain, &m_d3d11Device, nullptr, &m_d3d11DeviceContext);
	if (FAILED(hr)) { 
		DebugOut("D3D11CreateDeviceAndSwapChain failed!\n");
		return false;
	}

	// enable multithreaded device context protection
	ID3D10Multithread *contextMT = nullptr;
	m_d3d11DeviceContext->QueryInterface(&contextMT);

	if (contextMT) {
		contextMT->SetMultithreadProtected(true);
		contextMT->Release();
	}
	else {
		DebugOut("Fatal error! ID3D10Multithread::SetMultithreadProtected for D3D11 device context failed!\n");
		return false;
	}

	// get pointer to the back buffer
	hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)&pBackBuffer);
	if (FAILED(hr)) {
		DebugOut("IDXGISwapChain::GetBuffer failed!\n");
		return false;
	}

	// create render target view from back buffer
	hr = m_d3d11Device->CreateRenderTargetView(pBackBuffer, nullptr, &m_d3d11RenderTargetView);
	if (FAILED(hr)) {
		DebugOut("ID3D11Device::CreateRenderTargetView failed!\n");
		return false;
	}
	pBackBuffer->Release();

	// set up depth buffer description
	ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));		
	depthBufferDesc.Width = screenWidth;
	depthBufferDesc.Height = screenHeight;
	depthBufferDesc.MipLevels = 1;
	depthBufferDesc.ArraySize = 1;
	depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthBufferDesc.SampleDesc.Count = 1;
	depthBufferDesc.SampleDesc.Quality = 0;
	depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthBufferDesc.CPUAccessFlags = 0;
	depthBufferDesc.MiscFlags = 0;

	// create texture for depth buffer
	hr = m_d3d11Device->CreateTexture2D(&depthBufferDesc, nullptr, &m_d3d11DepthStencilBuffer);
	if (FAILED(hr)) {
		DebugOut("ID3D11Device::CreateTexture2D failed! Could not create texture for depth buffer.\n");
		return false;
	}

	// set up description of stencil state
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));	
	depthStencilDesc.DepthEnable = true; // z-buffer enabled
	depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

	depthStencilDesc.StencilEnable = true;
	depthStencilDesc.StencilReadMask = 0xFF;
	depthStencilDesc.StencilWriteMask = 0xFF;

	// Stencil operations if pixel is front-facing.
	depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// Stencil operations if pixel is back-facing.
	depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// create depth stencil state
	hr = m_d3d11Device->CreateDepthStencilState(&depthStencilDesc, &m_d3d11DepthStencilState);
	if (FAILED(hr)) {
		DebugOut("ID3D11Device::CreateDepthStencilState failed!\n");
		return false;
	}

	// Now create a second depth stencil state which turns off the Z buffer for 2D rendering.  The only difference is 
	// that DepthEnable is set to false, all other parameters are the same as the other depth stencil state.
	depthDisabledStencilDesc.DepthEnable = false;
	depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
	depthDisabledStencilDesc.StencilEnable = true;
	depthDisabledStencilDesc.StencilReadMask = 0xFF;
	depthDisabledStencilDesc.StencilWriteMask = 0xFF;
	depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
	depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// Create the state using the device.
	hr = m_d3d11Device->CreateDepthStencilState(&depthDisabledStencilDesc, &m_d3d11DepthStencilDisabledState);
	if (FAILED(hr))
	{
		return false;
	}

	// disable the Z-Buffer
	ZBufferState(0);

	// set up depth stencil view description
	ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));	
	depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	depthStencilViewDesc.Texture2D.MipSlice = 0;

	// create depth stencil view
	hr = m_d3d11Device->CreateDepthStencilView(m_d3d11DepthStencilBuffer, &depthStencilViewDesc, &m_d3d11DepthStencilView);
	if (FAILED(hr)) {
		DebugOut("ID3D11Device::CreateDepthStencilView failed!\n");
		return false;
	}

	// bind render target view and depth stencil buffer to the output render pipeline
	m_d3d11DeviceContext->OMSetRenderTargets(1, &m_d3d11RenderTargetView, m_d3d11DepthStencilView);

	// set up rasterizer description	
	rasterDesc.AntialiasedLineEnable = false;
	rasterDesc.CullMode = D3D11_CULL_NONE;
	rasterDesc.DepthBias = 0;
	rasterDesc.DepthBiasClamp = 0.0f;
	rasterDesc.DepthClipEnable = false;
	rasterDesc.FillMode = D3D11_FILL_SOLID;
	rasterDesc.FrontCounterClockwise = false;
	rasterDesc.MultisampleEnable = false;
	rasterDesc.ScissorEnable = false;
	rasterDesc.SlopeScaledDepthBias = 0.0f;

	// create the rasterizer
	hr = m_d3d11Device->CreateRasterizerState(&rasterDesc, &m_d3d11RasterState);
	if (FAILED(hr)) {
		DebugOut("ID3D11Device::CreateRasterizerState failed!");
		return false;
	}
	
	m_d3d11DeviceContext->RSSetState(m_d3d11RasterState);

	// set up viewport for rendering
	D3D11_VIEWPORT viewport;
	viewport.Width = (float)screenWidth;
	viewport.Height = (float)screenHeight;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;
	viewport.TopLeftX = 0.0f;
	viewport.TopLeftY = 0.0f;

	// create the viewport
	m_d3d11DeviceContext->RSSetViewports(1, &viewport);
		
	fov = (float)PI / 4.0f;
	aspect = (float)screenWidth / (float)screenHeight;
		
	m_ProjectionMatrix = DirectX::XMMatrixPerspectiveFovLH(fov, aspect, SCREEN_NEAR, SCREEN_DEPTH);
	m_WorldMatrix = DirectX::XMMatrixIdentity();
	m_OrthoMatrix = DirectX::XMMatrixOrthographicLH((float)screenWidth, (float)screenHeight, SCREEN_NEAR, SCREEN_DEPTH);

	// Scene is a textured quad to draw on
	g_Scene = new Scene(GetDevice(), GetDeviceContext(), screenWidth, screenHeight);
	//g_Scene2 = new Scene(GetDevice(), GetDeviceContext(), screenWidth, screenHeight);	

	// new DXGI Desktop Duplication object
	g_DesktopDuplication = new DXGIDuplication();
	if (!g_DesktopDuplication->Init(0, 0, &g_DXGIAdapters, GetDevice())) { DebugOut("Failed to init DXGI Desktop Duplication API!\n"); return false; }
	
	//g_DesktopDuplication2 = new DXGIDuplication();
	//if (!g_DesktopDuplication2->Init(0, 1, &g_DXGIAdapters, GetDevice())) { DebugOut("Failed to init DXGI Desktop Duplication API for Adapter 1/Output 2!\n"); return false; }

	// initialize Media Foundation
	g_MFEncoder = new MF_H264_Encoder(m_d3d11Device, m_d3d11DeviceContext);
	if (!g_MFEncoder->Init()) { DebugOut("Failed to init Media Foundation H.264 Encoder!\n"); return false; }

	return true;
};