blob: 99ad653a6e5e4751f0cf4358a89bfea255eafdfe [file] [log] [blame]
// Copyright 2016 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 "platform/graphics/gpu/SharedGpuContext.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "platform/graphics/Canvas2DLayerBridge.h"
#include "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
#include "platform/graphics/test/FakeGLES2Interface.h"
#include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2ext.h"
using ::testing::Test;
namespace blink {
namespace {
template <class GLES2InterfaceType>
class SharedGpuContextTestBase : public Test {
public:
void SetUp() override {
auto factory = [](GLES2InterfaceType* gl, bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = false;
gl->SetIsContextLost(false);
return std::make_unique<FakeWebGraphicsContext3DProvider>(gl);
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::BindRepeating(factory, WTF::Unretained(&gl_)));
}
void TearDown() override { SharedGpuContext::ResetForTesting(); }
GLES2InterfaceType gl_;
};
class SharedGpuContextTest
: public SharedGpuContextTestBase<FakeGLES2Interface> {};
class MailboxMockGLES2Interface : public FakeGLES2Interface {
public:
MOCK_METHOD1(GenMailboxCHROMIUM, void(GLbyte*));
MOCK_METHOD2(GenSyncTokenCHROMIUM, void(GLuint64, GLbyte*));
MOCK_METHOD2(GenUnverifiedSyncTokenCHROMIUM, void(GLuint64, GLbyte*));
MOCK_METHOD0(InsertFenceSyncCHROMIUM, GLuint64(void));
};
class MailboxSharedGpuContextTest
: public SharedGpuContextTestBase<MailboxMockGLES2Interface> {};
// Test fixure that simulate a graphics context creation failure, when using gpu
// compositing.
class BadSharedGpuContextTest : public Test {
public:
void SetUp() override {
auto factory = [](bool* gpu_compositing_disabled)
-> std::unique_ptr<WebGraphicsContext3DProvider> {
*gpu_compositing_disabled = false;
return nullptr;
};
SharedGpuContext::SetContextProviderFactoryForTesting(
WTF::BindRepeating(factory));
}
void TearDown() override { SharedGpuContext::ResetForTesting(); }
};
// 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_;
};
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, AccelerateImageBufferSurfaceAutoRecovery) {
// Verifies that after a context loss, attempting to allocate an
// AcceleratedImageBufferSurface will restore the context and succeed
gl_.SetIsContextLost(true);
EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
IntSize size(10, 10);
std::unique_ptr<ImageBufferSurface> surface =
WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
EXPECT_TRUE(surface->IsValid());
EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
}
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());
IntSize size(10, 10);
CanvasColorParams color_params;
std::unique_ptr<Canvas2DLayerBridge> bridge =
WTF::WrapUnique(new Canvas2DLayerBridge(
size, 0, /*msaa sample count*/
Canvas2DLayerBridge::kEnableAcceleration, color_params));
EXPECT_TRUE(bridge->IsAccelerated());
EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
bridge->BeginDestruction();
}
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 creation should
// fail gracefully
IntSize size(10, 10);
std::unique_ptr<ImageBufferSurface> surface =
WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
EXPECT_FALSE(surface->IsValid());
}
TEST_F(SharedGpuContextTest, CompositingMode) {
EXPECT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
}
TEST_F(BadSharedGpuContextTest, CompositingMode) {
EXPECT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
}
TEST_F(SoftwareCompositingTest, CompositingMode) {
EXPECT_FALSE(SharedGpuContext::IsGpuCompositingEnabled());
}
class FakeMailboxGenerator {
public:
void GenMailbox(GLbyte* name) { *name = counter_++; }
GLbyte counter_ = 1;
};
TEST_F(MailboxSharedGpuContextTest, MailboxCaching) {
IntSize size(10, 10);
std::unique_ptr<ImageBufferSurface> surface =
WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
EXPECT_TRUE(surface->IsValid());
scoped_refptr<StaticBitmapImage> image =
surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
::testing::Mock::VerifyAndClearExpectations(&gl_);
FakeMailboxGenerator mailboxGenerator;
gpu::Mailbox mailbox;
mailbox.name[0] = 0;
EXPECT_CALL(gl_, GenMailboxCHROMIUM(mailbox.name))
.Times(1)
.WillOnce(::testing::Invoke(&mailboxGenerator,
&FakeMailboxGenerator::GenMailbox));
SharedGpuContext::ContextProviderWrapper()->Utils()->GetMailboxForSkImage(
mailbox, image->PaintImageForCurrentFrame().GetSkImage(), GL_NEAREST);
EXPECT_EQ(mailbox.name[0], 1);
::testing::Mock::VerifyAndClearExpectations(&gl_);
EXPECT_CALL(gl_, GenMailboxCHROMIUM(mailbox.name))
.Times(0); // GenMailboxCHROMIUM must not be called!
mailbox.name[0] = 0;
SharedGpuContext::ContextProviderWrapper()->Utils()->GetMailboxForSkImage(
mailbox, image->PaintImageForCurrentFrame().GetSkImage(), GL_NEAREST);
EXPECT_EQ(mailbox.name[0], 1);
::testing::Mock::VerifyAndClearExpectations(&gl_);
}
TEST_F(MailboxSharedGpuContextTest, MailboxCacheSurvivesSkiaRecycling) {
IntSize size(10, 10);
std::unique_ptr<ImageBufferSurface> surface =
WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
EXPECT_TRUE(surface->IsValid());
scoped_refptr<StaticBitmapImage> image =
surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
::testing::Mock::VerifyAndClearExpectations(&gl_);
FakeMailboxGenerator mailboxGenerator;
gpu::Mailbox mailbox;
mailbox.name[0] = 0;
EXPECT_CALL(gl_, GenMailboxCHROMIUM(mailbox.name))
.Times(1)
.WillOnce(::testing::Invoke(&mailboxGenerator,
&FakeMailboxGenerator::GenMailbox));
SharedGpuContext::ContextProviderWrapper()->Utils()->GetMailboxForSkImage(
mailbox, image->PaintImageForCurrentFrame().GetSkImage(), GL_NEAREST);
EXPECT_EQ(mailbox.name[0], 1);
::testing::Mock::VerifyAndClearExpectations(&gl_);
// Destroy image and surface to return texture to recleable resource pool
image = nullptr;
surface = nullptr;
::testing::Mock::VerifyAndClearExpectations(&gl_);
// Re-creating surface should recycle the old GrTexture inside skia
surface = WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
EXPECT_TRUE(surface->IsValid());
image =
surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
::testing::Mock::VerifyAndClearExpectations(&gl_);
EXPECT_CALL(gl_, GenMailboxCHROMIUM(mailbox.name))
.Times(0); // GenMailboxCHROMIUM must not be called!
mailbox.name[0] = 0;
SharedGpuContext::ContextProviderWrapper()->Utils()->GetMailboxForSkImage(
mailbox, image->PaintImageForCurrentFrame().GetSkImage(), GL_NEAREST);
EXPECT_EQ(mailbox.name[0], 1);
::testing::Mock::VerifyAndClearExpectations(&gl_);
}
} // unnamed namespace
} // blink