text: // Copyright 2020 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <d3d11.h>
  #include <mfapi.h>
  
  #include "base/win/windows_version.h"
  #include "media/base/test_helpers.h"
  #include "media/base/win/dxgi_device_manager.h"
  #include "media/base/win/mf_initializer.h"
  
  namespace media {
  
  using Microsoft::WRL::ComPtr;
  
  class DXGIDeviceScopedHandleTest : public testing::Test {
   public:
    DXGIDeviceScopedHandleTest()
        : test_supported_(base::win::GetVersion() >= base::win::Version::WIN10) {}
    ~DXGIDeviceScopedHandleTest() override = default;
  
   protected:
    void SetUp() override {
      if (!test_supported_)
        return;
  
      ASSERT_NE(nullptr, session_ = InitializeMediaFoundation());
  
      // Get a shared DXGI Device Manager from Media Foundation.
      ASSERT_HRESULT_SUCCEEDED(
          MFLockDXGIDeviceManager(&device_reset_token_, &dxgi_device_man_));
  
      // |dxgi_device_man_| does not create the device, creates Direct3D device.
      ComPtr<ID3D11Device> d3d11_device;
      UINT creation_flags =
          (D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT |
           D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS);
      static const D3D_FEATURE_LEVEL feature_levels[] = {
          D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
          D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3,  D3D_FEATURE_LEVEL_9_2,
          D3D_FEATURE_LEVEL_9_1};
      ASSERT_HRESULT_SUCCEEDED(
          D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, creation_flags,
                            feature_levels, ARRAYSIZE(feature_levels),
                            D3D11_SDK_VERSION, &d3d11_device, nullptr, nullptr));
  
      ComPtr<ID3D10Multithread> multithreaded_device;
      ASSERT_HRESULT_SUCCEEDED(d3d11_device.As(&multithreaded_device));
      multithreaded_device->SetMultithreadProtected(TRUE);
  
      // Set Direct3D device to the device manager.
      ASSERT_HRESULT_SUCCEEDED(
          dxgi_device_man_->ResetDevice(d3d11_device.Get(), device_reset_token_));
    }
  
    void TearDown() override {
      if (test_supported_) {
        ASSERT_HRESULT_SUCCEEDED(MFUnlockDXGIDeviceManager());
      }
    }
  
    MFSessionLifetime session_;
    Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> dxgi_device_man_ = nullptr;
    UINT device_reset_token_ = 0;
    const bool test_supported_;
  };
  
  TEST_F(DXGIDeviceScopedHandleTest, LockDevice) {
    if (!test_supported_)
      return;
  
    {
      // Create DXGIDeviceScopedHandle in an inner scope without LockDevice
      // call.
      DXGIDeviceScopedHandle device_handle_1(dxgi_device_man_.Get());
    }
    {
      // Create DXGIDeviceScopedHandle in an inner scope with LockDevice call.
      DXGIDeviceScopedHandle device_handle_2(dxgi_device_man_.Get());
      ComPtr<ID3D11Device> device2;
      ASSERT_HRESULT_SUCCEEDED(
          device_handle_2.LockDevice(IID_PPV_ARGS(&device2)));
    }
    // Use the device in an outer scope.
    DXGIDeviceScopedHandle device_handle_3(dxgi_device_man_.Get());
    ComPtr<ID3D11Device> device3;
    ASSERT_HRESULT_SUCCEEDED(device_handle_3.LockDevice(IID_PPV_ARGS(&device3)));
  }
  
  TEST_F(DXGIDeviceScopedHandleTest, GetDevice) {
    if (!test_supported_)
      return;
  
    {
      // Create DXGIDeviceScopedHandle in an inner scope.
      DXGIDeviceScopedHandle device_handle_1(dxgi_device_man_.Get());
    }
    {
      // Create DXGIDeviceScopedHandle in an inner scope with GetDevice call.
      DXGIDeviceScopedHandle device_handle_2(dxgi_device_man_.Get());
      ComPtr<ID3D11Device> device2 = device_handle_2.GetDevice();
      EXPECT_NE(device2, nullptr);
    }
    // Use the device in an outer scope.
    DXGIDeviceScopedHandle device_handle_3(dxgi_device_man_.Get());
    ComPtr<ID3D11Device> device3 = device_handle_3.GetDevice();
    EXPECT_NE(device3, nullptr);
  }
  
  }  // namespace media