1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
6 
7 #include "base/test/null_task_runner.h"
8 #include "base/test/task_environment.h"
9 #include "components/viz/common/resources/single_release_callback.h"
10 #include "components/viz/test/test_gles2_interface.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
14 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
15 #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
16 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
17 #include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
18 #include "third_party/blink/renderer/platform/wtf/functional.h"
19 #include "third_party/skia/include/core/SkSurface.h"
20 
21 namespace blink {
22 namespace {
23 
24 using testing::_;
25 using testing::ElementsAreArray;
26 using testing::InSequence;
27 using testing::MatcherCast;
28 using testing::Pointee;
29 using testing::SetArgPointee;
30 using testing::SetArrayArgument;
31 using testing::Test;
32 
33 class MockGLES2InterfaceWithSyncTokenSupport : public viz::TestGLES2Interface {
34  public:
35   MOCK_METHOD1(GenUnverifiedSyncTokenCHROMIUM, void(GLbyte*));
36   MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte*));
37 };
38 
SyncTokenMatcher(const gpu::SyncToken & token)39 GLbyte SyncTokenMatcher(const gpu::SyncToken& token) {
40   return reinterpret_cast<const GLbyte*>(&token)[0];
41 }
42 
GenTestSyncToken(GLbyte id)43 gpu::SyncToken GenTestSyncToken(GLbyte id) {
44   gpu::SyncToken token;
45   // Store id in the first byte
46   reinterpret_cast<GLbyte*>(&token)[0] = id;
47   return token;
48 }
49 
CreateBitmap()50 scoped_refptr<StaticBitmapImage> CreateBitmap() {
51   auto mailbox = gpu::Mailbox::GenerateForSharedImage();
52   auto release_callback = viz::SingleReleaseCallback::Create(
53       base::BindOnce([](const gpu::SyncToken&, bool) {}));
54   return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
55       mailbox, GenTestSyncToken(100), 0, SkImageInfo::MakeN32Premul(100, 100),
56       GL_TEXTURE_2D, true, SharedGpuContext::ContextProviderWrapper(),
57       base::PlatformThread::CurrentRef(),
58       base::MakeRefCounted<base::NullTaskRunner>(),
59       std::move(release_callback));
60 }
61 
62 class AcceleratedStaticBitmapImageTest : public Test {
63  public:
SetUp()64   void SetUp() override {
65     auto gl = std::make_unique<MockGLES2InterfaceWithSyncTokenSupport>();
66     gl_ = gl.get();
67     context_provider_ = viz::TestContextProvider::Create(std::move(gl));
68     InitializeSharedGpuContext(context_provider_.get());
69   }
TearDown()70   void TearDown() override {
71     gl_ = nullptr;
72     SharedGpuContext::ResetForTesting();
73   }
74 
75  protected:
76   base::test::TaskEnvironment task_environment_;
77   MockGLES2InterfaceWithSyncTokenSupport* gl_;
78   scoped_refptr<viz::TestContextProvider> context_provider_;
79 };
80 
TEST_F(AcceleratedStaticBitmapImageTest,SkImageCached)81 TEST_F(AcceleratedStaticBitmapImageTest, SkImageCached) {
82   auto bitmap = CreateBitmap();
83 
84   sk_sp<SkImage> stored_image =
85       bitmap->PaintImageForCurrentFrame().GetSkImage();
86   auto stored_image2 = bitmap->PaintImageForCurrentFrame().GetSkImage();
87   EXPECT_EQ(stored_image.get(), stored_image2.get());
88 }
89 
TEST_F(AcceleratedStaticBitmapImageTest,CopyToTextureSynchronization)90 TEST_F(AcceleratedStaticBitmapImageTest, CopyToTextureSynchronization) {
91   auto bitmap = CreateBitmap();
92 
93   MockGLES2InterfaceWithSyncTokenSupport destination_gl;
94 
95   testing::Mock::VerifyAndClearExpectations(gl_);
96   testing::Mock::VerifyAndClearExpectations(&destination_gl);
97 
98   InSequence s;  // Indicate to gmock that order of EXPECT_CALLs is important
99 
100   // Anterior synchronization. Wait on the sync token for the mailbox on the
101   // dest context.
102   EXPECT_CALL(destination_gl, WaitSyncTokenCHROMIUM(Pointee(SyncTokenMatcher(
103                                   bitmap->GetMailboxHolder().sync_token))));
104 
105   // Posterior synchronization. Generate a sync token on the destination context
106   // to ensure mailbox is destroyed after the copy.
107   const gpu::SyncToken sync_token2 = GenTestSyncToken(2);
108   EXPECT_CALL(destination_gl, GenUnverifiedSyncTokenCHROMIUM(_))
109       .WillOnce(SetArrayArgument<0>(
110           sync_token2.GetConstData(),
111           sync_token2.GetConstData() + sizeof(gpu::SyncToken)));
112 
113   IntPoint dest_point(0, 0);
114   IntRect source_sub_rectangle(0, 0, 10, 10);
115   ASSERT_TRUE(bitmap->CopyToTexture(
116       &destination_gl, GL_TEXTURE_2D, 1 /*dest_texture_id*/,
117       0 /*dest_texture_level*/, false /*unpack_premultiply_alpha*/,
118       false /*unpack_flip_y*/, dest_point, source_sub_rectangle));
119 
120   testing::Mock::VerifyAndClearExpectations(&gl_);
121   testing::Mock::VerifyAndClearExpectations(&destination_gl);
122 
123   // Final wait is postponed until destruction.
124   EXPECT_EQ(bitmap->GetMailboxHolder().sync_token, sync_token2);
125 }
126 
127 }  // namespace
128 }  // namespace blink
129