blob: 7c16530190e1214891bc7b3b44140b3685e559ea [file] [log] [blame]
// 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;
}
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>(&registered_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>(&registered_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