| // Copyright 2018 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 "components/viz/common/gl_scaler.h" |
| |
| #include "components/viz/common/gpu/context_provider.h" |
| #include "gpu/GLES2/gl2chromium.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| #include "gpu/command_buffer/client/gles2_implementation.h" |
| #include "gpu/command_buffer/common/capabilities.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::ByRef; |
| using ::testing::Eq; |
| using ::testing::Mock; |
| using ::testing::NiceMock; |
| using ::testing::NotNull; |
| using ::testing::Return; |
| using ::testing::ReturnRef; |
| using ::testing::SaveArg; |
| using ::testing::Sequence; |
| |
| namespace viz { |
| namespace { |
| |
| class MockContextProvider : public ContextProvider { |
| public: |
| MockContextProvider() { |
| ON_CALL(*this, ContextGL()) |
| .WillByDefault( |
| Return(reinterpret_cast<gpu::gles2::GLES2Interface*>(0xdeadbeef))); |
| ON_CALL(*this, ContextCapabilities()).WillByDefault(ReturnRef(caps_)); |
| } |
| |
| MOCK_METHOD1(AddObserver, void(ContextLostObserver* obs)); |
| MOCK_METHOD1(RemoveObserver, void(ContextLostObserver* obs)); |
| MOCK_CONST_METHOD0(ContextCapabilities, const gpu::Capabilities&()); |
| MOCK_METHOD0(ContextGL, gpu::gles2::GLES2Interface*()); |
| |
| // Stubbed-out, because the tests just stack-allocate this object. |
| void AddRef() const final {} |
| void Release() const final {} |
| |
| private: |
| gpu::Capabilities caps_; |
| |
| // Other ContextProvider methods; but stubbed-out because they are never |
| // called. |
| gpu::ContextResult BindToCurrentThread() final { |
| NOTREACHED(); |
| return gpu::ContextResult::kSuccess; |
| } |
| base::Lock* GetLock() final { |
| NOTREACHED(); |
| return nullptr; |
| } |
| ContextCacheController* CacheController() final { |
| NOTREACHED(); |
| return nullptr; |
| } |
| gpu::ContextSupport* ContextSupport() final { |
| NOTREACHED(); |
| return nullptr; |
| } |
| class GrContext* GrContext() final { |
| NOTREACHED(); |
| return nullptr; |
| } |
| gpu::SharedImageInterface* SharedImageInterface() final { |
| NOTREACHED(); |
| return nullptr; |
| } |
| const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const final { |
| NOTREACHED(); |
| return *reinterpret_cast<gpu::GpuFeatureInfo*>(0xdeadbeef); |
| } |
| }; |
| |
| class GLScalerTest : public testing::Test {}; |
| |
| TEST_F(GLScalerTest, AddAndRemovesSelfAsContextLossObserver) { |
| NiceMock<MockContextProvider> provider; |
| ContextLostObserver* registered_observer = nullptr; |
| Sequence s; |
| EXPECT_CALL(provider, AddObserver(NotNull())) |
| .InSequence(s) |
| .WillOnce(SaveArg<0>(®istered_observer)); |
| EXPECT_CALL(provider, RemoveObserver(Eq(ByRef(registered_observer)))) |
| .InSequence(s); |
| GLScaler scaler(base::WrapRefCounted(&provider)); |
| } |
| |
| TEST_F(GLScalerTest, CleansUpWhenContextIsLost) { |
| NiceMock<MockContextProvider> provider; |
| ContextLostObserver* registered_observer = nullptr; |
| Sequence s; |
| EXPECT_CALL(provider, AddObserver(NotNull())) |
| .InSequence(s) |
| .WillOnce(SaveArg<0>(®istered_observer)); |
| EXPECT_CALL(provider, RemoveObserver(Eq(ByRef(registered_observer)))) |
| .InSequence(s); |
| GLScaler scaler(base::WrapRefCounted(&provider)); |
| static_cast<ContextLostObserver&>(scaler).OnContextLost(); |
| // Verify RemoveObserver() was called before |scaler| goes out-of-scope. |
| Mock::VerifyAndClearExpectations(&provider); |
| } |
| |
| TEST_F(GLScalerTest, Configure_RequiresValidScalingVectors) { |
| NiceMock<MockContextProvider> provider; |
| GLScaler scaler(base::WrapRefCounted(&provider)); |
| |
| GLScaler::Parameters params; |
| EXPECT_TRUE(scaler.Configure(params)); |
| |
| for (int i = 0; i < 4; ++i) { |
| params.scale_from = gfx::Vector2d(i == 0 ? 0 : 1, i == 1 ? 0 : 1); |
| params.scale_to = gfx::Vector2d(i == 2 ? 0 : 1, i == 3 ? 0 : 1); |
| EXPECT_FALSE(scaler.Configure(params)); |
| } |
| } |
| |
| TEST_F(GLScalerTest, Configure_ResolvesUnspecifiedColorSpaces) { |
| NiceMock<MockContextProvider> provider; |
| GLScaler scaler(base::WrapRefCounted(&provider)); |
| |
| // Neither source nor output space specified: Both should resolve to sRGB. |
| GLScaler::Parameters params; |
| EXPECT_TRUE(scaler.Configure(params)); |
| const auto srgb = gfx::ColorSpace::CreateSRGB(); |
| EXPECT_EQ(srgb, scaler.params().source_color_space); |
| EXPECT_EQ(srgb, scaler.params().output_color_space); |
| |
| // Source space set to XYZD50 with no output space specified: Both should |
| // resolve to XYZD50. |
| const auto xyzd50 = gfx::ColorSpace::CreateXYZD50(); |
| params.source_color_space = xyzd50; |
| EXPECT_TRUE(scaler.Configure(params)); |
| EXPECT_EQ(xyzd50, scaler.params().source_color_space); |
| EXPECT_EQ(xyzd50, scaler.params().output_color_space); |
| |
| // Source space set to XYZD50 with output space set to P3D65: Nothing should |
| // change. |
| const auto p3d65 = gfx::ColorSpace::CreateDisplayP3D65(); |
| params.output_color_space = p3d65; |
| EXPECT_TRUE(scaler.Configure(params)); |
| EXPECT_EQ(xyzd50, scaler.params().source_color_space); |
| EXPECT_EQ(p3d65, scaler.params().output_color_space); |
| } |
| |
| TEST_F(GLScalerTest, Configure_RequiresValidSwizzles) { |
| NiceMock<MockContextProvider> provider; |
| GLScaler scaler(base::WrapRefCounted(&provider)); |
| GLScaler::Parameters params; |
| |
| // Test that all valid combinations work. |
| for (int i = 0; i < 4; ++i) { |
| params.swizzle[0] = (i % 2 == 0) ? GL_RGBA : GL_BGRA_EXT; |
| params.swizzle[1] = (i / 2 == 0) ? GL_RGBA : GL_BGRA_EXT; |
| EXPECT_TRUE(scaler.Configure(params)) << "i=" << i; |
| } |
| |
| // Test that invalid combinations don't work. |
| for (int i = 1; i < 4; ++i) { |
| params.swizzle[0] = (i % 2 == 0) ? GL_RGBA : GL_RGB; |
| params.swizzle[1] = (i / 2 == 0) ? GL_RGBA : GL_RGB; |
| EXPECT_FALSE(scaler.Configure(params)) << "i=" << i; |
| } |
| } |
| |
| TEST_F(GLScalerTest, DetectsEquivalentScaleRatios) { |
| GLScaler::Parameters params; |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(1, 1), |
| gfx::Vector2d(1, 1))); |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(15, 15), gfx::Vector2d(15, 15))); |
| |
| params.scale_from = gfx::Vector2d(2, 1); |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(2, 1), |
| gfx::Vector2d(1, 1))); |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(30, 15), gfx::Vector2d(15, 15))); |
| |
| params.scale_from = gfx::Vector2d(1, 2); |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(1, 2), |
| gfx::Vector2d(1, 1))); |
| EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(15, 30), gfx::Vector2d(15, 15))); |
| |
| params.scale_from = gfx::Vector2d(2, 1); |
| EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(1, 2), gfx::Vector2d(1, 1))); |
| EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(15, 30), gfx::Vector2d(15, 15))); |
| |
| params.scale_from = gfx::Vector2d(1, 2); |
| EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(2, 1), gfx::Vector2d(1, 1))); |
| EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio( |
| params, gfx::Vector2d(30, 15), gfx::Vector2d(15, 15))); |
| } |
| |
| } // namespace |
| } // namespace viz |