| // 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 "ui/gl/hdr_metadata_helper_win.h" |
| |
| #include "media/base/win/d3d11_mocks.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::DoAll; |
| // using ::testing::Eq; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| // using ::testing::SaveArg; |
| using ::testing::SetArgPointee; |
| |
| namespace gl { |
| |
| class HDRMetadataHelperWinTest : public ::testing::Test { |
| public: |
| void SetUp() override { |
| mock_dxgi_factory_ = media::MakeComPtr<NiceMock<media::DXGIFactoryMock>>(); |
| ON_CALL(*mock_dxgi_factory_.Get(), EnumAdapters(_, _)) |
| .WillByDefault(Return(DXGI_ERROR_NOT_FOUND)); |
| |
| mock_dxgi_device_ = media::MakeComPtr<NiceMock<media::DXGIDeviceMock>>(); |
| |
| mock_d3d11_device_ = media::MakeComPtr<NiceMock<media::D3D11DeviceMock>>(); |
| ON_CALL(*mock_d3d11_device_.Get(), QueryInterface(IID_IDXGIDevice, _)) |
| .WillByDefault( |
| media::SetComPointeeAndReturnOk<1>(mock_dxgi_device_.Get())); |
| } |
| |
| std::unique_ptr<HDRMetadataHelperWin> CreateHelper() { |
| // Set the D3D11 device's adapter to the first one, somewhat arbitrarily. |
| ON_CALL(*mock_dxgi_device_.Get(), GetAdapter(_)) |
| .WillByDefault( |
| media::SetComPointeeAndReturnOk<0>(mock_dxgi_adapters_[0].Get())); |
| |
| return std::make_unique<HDRMetadataHelperWin>(mock_d3d11_device_); |
| } |
| |
| // Adds an adapter that |mock_dxgi_factory_| will enumerate. |
| void AddAdapter() { |
| Microsoft::WRL::ComPtr<media::DXGIAdapterMock> dxgi_adapter = |
| media::MakeComPtr<NiceMock<media::DXGIAdapterMock>>(); |
| ON_CALL(*dxgi_adapter.Get(), GetParent(_, _)) |
| .WillByDefault( |
| media::SetComPointeeAndReturnOk<1>(mock_dxgi_factory_.Get())); |
| |
| // By default, the adapter has no outputs. |
| ON_CALL(*dxgi_adapter.Get(), EnumOutputs(_, _)) |
| .WillByDefault(Return(DXGI_ERROR_NOT_FOUND)); |
| |
| // Make the factory enumerate this adapter. |
| ON_CALL(*mock_dxgi_factory_.Get(), |
| EnumAdapters(mock_dxgi_adapters_.size(), _)) |
| .WillByDefault(media::SetComPointeeAndReturnOk<1>(dxgi_adapter.Get())); |
| |
| mock_dxgi_adapters_.push_back(std::move(dxgi_adapter)); |
| } |
| |
| // Add |desc1| to the most recent adapter. |
| // Note that, for now, this can only be called once, since we only set |
| // an expectation for output 0. |
| void AddOutput(const DXGI_OUTPUT_DESC1& desc1) { |
| // Create a DXGIOutput6 that can return |desc1|. |
| Microsoft::WRL::ComPtr<media::DXGIOutput6Mock> output6 = |
| media::MakeComPtr<media::DXGIOutput6Mock>(); |
| mock_dxgi_output6s_.push_back(output6); |
| ON_CALL(*output6.Get(), GetDesc1(_)) |
| .WillByDefault(DoAll(SetArgPointee<0>(desc1), Return(S_OK))); |
| |
| // Tell the current adapter to return |output6| as its 0-th output. |
| auto& dxgi_adapter = mock_dxgi_adapters_[mock_dxgi_adapters_.size() - 1]; |
| ON_CALL(*dxgi_adapter.Get(), EnumOutputs(0, _)) |
| .WillByDefault(media::SetComPointeeAndReturnOk<1>(output6.Get())); |
| } |
| |
| Microsoft::WRL::ComPtr<media::D3D11DeviceMock> mock_d3d11_device_; |
| Microsoft::WRL::ComPtr<media::DXGIDeviceMock> mock_dxgi_device_; |
| Microsoft::WRL::ComPtr<media::DXGIFactoryMock> mock_dxgi_factory_; |
| std::vector<Microsoft::WRL::ComPtr<media::DXGIAdapterMock>> |
| mock_dxgi_adapters_; |
| std::vector<Microsoft::WRL::ComPtr<media::DXGIOutput6Mock>> |
| mock_dxgi_output6s_; |
| std::vector<Microsoft::WRL::ComPtr<media::DXGIOutputMock>> mock_dxgi_outputs_; |
| }; |
| |
| TEST_F(HDRMetadataHelperWinTest, CachesMetadataIfAvailable) { |
| // Set up two adapters with one monitor each. |
| AddAdapter(); |
| DXGI_OUTPUT_DESC1 desc{}; |
| desc.RedPrimary[0] = 0.1; |
| desc.RedPrimary[1] = 0.2; |
| desc.GreenPrimary[0] = 0.3; |
| desc.GreenPrimary[1] = 0.4; |
| desc.BluePrimary[0] = 0.5; |
| desc.BluePrimary[1] = 0.6; |
| desc.WhitePoint[0] = 0.7; |
| desc.WhitePoint[1] = 0.8; |
| desc.MinLuminance = 0.9; |
| desc.MaxLuminance = 1.0; |
| desc.MaxFullFrameLuminance = 100; |
| AddOutput(desc); |
| AddAdapter(); |
| DXGI_OUTPUT_DESC1 desc_second = desc; |
| // Make the second one less bright. |
| desc_second.RedPrimary[0] = 0.5; |
| desc_second.MaxLuminance /= 2.0; |
| AddOutput(desc); |
| auto helper = CreateHelper(); |
| auto result = helper->GetDisplayMetadata(); |
| EXPECT_TRUE(result); |
| // From MSDN. |
| static constexpr int kPrimariesFixedPoint = 50000; |
| static constexpr int kLuminanceFixedPoint = 10000; |
| EXPECT_EQ(result->RedPrimary[0], |
| static_cast<int>(desc.RedPrimary[0] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->RedPrimary[1], |
| static_cast<int>(desc.RedPrimary[1] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->GreenPrimary[0], |
| static_cast<int>(desc.GreenPrimary[0] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->GreenPrimary[1], |
| static_cast<int>(desc.GreenPrimary[1] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->BluePrimary[0], |
| static_cast<int>(desc.BluePrimary[0] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->BluePrimary[1], |
| static_cast<int>(desc.BluePrimary[1] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->WhitePoint[0], |
| static_cast<int>(desc.WhitePoint[0] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->WhitePoint[1], |
| static_cast<int>(desc.WhitePoint[1] * kPrimariesFixedPoint)); |
| EXPECT_EQ(result->MaxMasteringLuminance, |
| static_cast<unsigned>(desc.MaxLuminance * kLuminanceFixedPoint)); |
| EXPECT_EQ(result->MinMasteringLuminance, |
| static_cast<unsigned>(desc.MinLuminance * kLuminanceFixedPoint)); |
| EXPECT_EQ(result->MaxContentLightLevel, desc.MaxFullFrameLuminance); |
| EXPECT_EQ(result->MaxFrameAverageLightLevel, desc.MaxFullFrameLuminance); |
| } |
| |
| TEST_F(HDRMetadataHelperWinTest, DoesntCacheMetadataIfNotAvailble) { |
| // Add an empty adapter. |
| AddAdapter(); |
| auto helper = CreateHelper(); |
| EXPECT_FALSE(helper->GetDisplayMetadata()); |
| } |
| |
| } // namespace gl |