blob: f6847d7cbae57a1cf67f82160254a4dc6adcec70 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include <memory>
#include "base/test/null_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/khronos/GLES2/gl2ext.h"
using testing::_;
using testing::Test;
namespace blink {
namespace {
template <class GLES2InterfaceType>
class SharedGpuContextTestBase : public Test {
public:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::NullTaskRunner>();
handle_ = std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
auto factory = [](GLES2InterfaceType* gl, bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = false;
gl->SetIsContextLost(false);
auto fake_context =
std::make_unique<FakeWebGraphicsContext3DProvider>(gl);
gpu::Capabilities capabilities;
capabilities.max_texture_size = 20;
fake_context->SetCapabilities(capabilities);
return fake_context;
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::BindRepeating(factory, WTF::Unretained(&gl_)));
}
void TearDown() override {
handle_.reset();
task_runner_.reset();
SharedGpuContext::ResetForTesting();
}
scoped_refptr<base::NullTaskRunner> task_runner_;
std::unique_ptr<base::ThreadTaskRunnerHandle> handle_;
GLES2InterfaceType gl_;
};
class TestGLES2Interface : public FakeGLES2Interface {
public:
GLuint CreateAndTexStorage2DSharedImageCHROMIUM(const GLbyte*) override {
return ++texture_id;
}
GLuint texture_id = 0u;
};
class SharedGpuContextTest
: public SharedGpuContextTestBase<TestGLES2Interface> {};
class MailboxMockGLES2Interface : public TestGLES2Interface {
public:
MOCK_METHOD2(ProduceTextureDirectCHROMIUM, void(GLuint, GLbyte*));
MOCK_METHOD1(GenSyncTokenCHROMIUM, void(GLbyte*));
MOCK_METHOD1(GenUnverifiedSyncTokenCHROMIUM, void(GLbyte*));
};
// Test fixure that simulate a graphics context creation failure, when using gpu
// compositing.
class BadSharedGpuContextTest : public Test {
public:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::NullTaskRunner>();
handle_ = std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
auto factory = [](bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = false;
return nullptr;
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::BindRepeating(factory));
}
void TearDown() override {
handle_.reset();
task_runner_.reset();
SharedGpuContext::ResetForTesting();
}
scoped_refptr<base::NullTaskRunner> task_runner_;
std::unique_ptr<base::ThreadTaskRunnerHandle> handle_;
};
// Test fixure that simulate not using gpu compositing.
class SoftwareCompositingTest : public Test {
public:
void SetUp() override {
auto factory = [](FakeGLES2Interface* gl, bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = true;
// Return a context anyway, to ensure that's not what the class checks
// to determine compositing mode.
gl->SetIsContextLost(false);
return std::make_unique<FakeWebGraphicsContext3DProvider>(gl);
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::BindRepeating(factory, WTF::Unretained(&gl_)));
}
void TearDown() override { SharedGpuContext::ResetForTesting(); }
FakeGLES2Interface gl_;
};
class SharedGpuContextTestViz : public Test {
public:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::NullTaskRunner>();
handle_ = std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
test_context_provider_ = viz::TestContextProvider::Create();
InitializeSharedGpuContext(test_context_provider_.get(),
/*cache = */ nullptr,
SetIsContextLost::kSetToFalse);
}
void TearDown() override {
handle_.reset();
task_runner_.reset();
SharedGpuContext::ResetForTesting();
}
scoped_refptr<base::NullTaskRunner> task_runner_;
std::unique_ptr<base::ThreadTaskRunnerHandle> handle_;
scoped_refptr<viz::TestContextProvider> test_context_provider_;
};
TEST_F(SharedGpuContextTest, contextLossAutoRecovery) {
EXPECT_NE(SharedGpuContext::ContextProviderWrapper(), nullptr);
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context =
SharedGpuContext::ContextProviderWrapper();
gl_.SetIsContextLost(true);
EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
EXPECT_TRUE(!!context);
// Context recreation results in old provider being discarded.
EXPECT_TRUE(!!SharedGpuContext::ContextProviderWrapper());
EXPECT_FALSE(!!context);
}
TEST_F(SharedGpuContextTest, Canvas2DLayerBridgeAutoRecovery) {
// Verifies that after a context loss, attempting to allocate a
// Canvas2DLayerBridge will restore the context and succeed.
gl_.SetIsContextLost(true);
EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
gfx::Size size(10, 10);
std::unique_ptr<Canvas2DLayerBridge> bridge =
std::make_unique<Canvas2DLayerBridge>(size, RasterMode::kGPU, kNonOpaque);
EXPECT_TRUE(bridge->IsAccelerated());
EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
}
TEST_F(SharedGpuContextTest, IsValidWithoutRestoring) {
EXPECT_NE(SharedGpuContext::ContextProviderWrapper(), nullptr);
EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
}
TEST_F(BadSharedGpuContextTest, IsValidWithoutRestoring) {
EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
}
TEST_F(BadSharedGpuContextTest, AllowSoftwareToAcceleratedCanvasUpgrade) {
EXPECT_FALSE(SharedGpuContext::AllowSoftwareToAcceleratedCanvasUpgrade());
}
TEST_F(BadSharedGpuContextTest, AccelerateImageBufferSurfaceCreationFails) {
// With a bad shared context, AccelerateImageBufferSurface should fail and
// return a nullptr provider
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
SkImageInfo::MakeN32Premul(10, 10),
cc::PaintFlags::FilterQuality::kLow,
CanvasResourceProvider::ShouldInitialize::kNo,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
true /*is_origin_top_left*/, 0u /*shared_image_usage_flags*/);
EXPECT_FALSE(resource_provider);
}
TEST_F(SharedGpuContextTest, CompositingMode) {
EXPECT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
}
TEST_F(BadSharedGpuContextTest, CompositingMode) {
EXPECT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
}
TEST_F(SoftwareCompositingTest, CompositingMode) {
EXPECT_FALSE(SharedGpuContext::IsGpuCompositingEnabled());
}
TEST_F(SharedGpuContextTestViz, AccelerateImageBufferSurfaceAutoRecovery) {
// Verifies that after a context loss, attempting to allocate an
// AcceleratedImageBufferSurface will restore the context and succeed
test_context_provider_->TestContextGL()->set_context_lost(true);
EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
std::unique_ptr<CanvasResourceProvider> resource_provider =
CanvasResourceProvider::CreateSharedImageProvider(
SkImageInfo::MakeN32Premul(10, 10),
cc::PaintFlags::FilterQuality::kLow,
CanvasResourceProvider::ShouldInitialize::kNo,
SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
true /*is_origin_top_left*/, 0u /*shared_image_usage_flags*/);
EXPECT_TRUE(resource_provider && resource_provider->IsValid());
EXPECT_TRUE(resource_provider->IsAccelerated());
EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
}
} // unnamed namespace
} // namespace blink