1 // Copyright 2017 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 "components/viz/service/display/gl_renderer_copier.h"
6
7 #include <stdint.h>
8
9 #include <iterator>
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "components/viz/common/frame_sinks/copy_output_request.h"
15 #include "components/viz/test/test_context_provider.h"
16 #include "components/viz/test/test_gles2_interface.h"
17 #include "gpu/GLES2/gl2extchromium.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/gfx/geometry/vector2d.h"
20
21 namespace viz {
22
23 namespace {
24
25 class CopierTestGLES2Interface : public TestGLES2Interface {
26 public:
27 // Sets how GL will respond to queries regarding the implementation's internal
28 // read-back format.
SetOptimalReadbackFormat(GLenum format,GLenum type)29 void SetOptimalReadbackFormat(GLenum format, GLenum type) {
30 format_ = format;
31 type_ = type;
32 }
33
34 // GLES2Interface override.
GetIntegerv(GLenum pname,GLint * params)35 void GetIntegerv(GLenum pname, GLint* params) override {
36 switch (pname) {
37 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
38 ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
39 CheckFramebufferStatus(GL_FRAMEBUFFER));
40 params[0] = format_;
41 break;
42 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
43 ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
44 CheckFramebufferStatus(GL_FRAMEBUFFER));
45 params[0] = type_;
46 break;
47 default:
48 TestGLES2Interface::GetIntegerv(pname, params);
49 break;
50 }
51 }
52
53 private:
54 GLenum format_ = 0;
55 GLenum type_ = 0;
56 };
57
58 } // namespace
59
60 class GLRendererCopierTest : public testing::Test {
61 public:
62 using ReusableThings = GLRendererCopier::ReusableThings;
63
SetUp()64 void SetUp() override {
65 auto context_provider = TestContextProvider::Create(
66 std::make_unique<CopierTestGLES2Interface>());
67 context_provider->BindToCurrentThread();
68 copier_ = std::make_unique<GLRendererCopier>(std::move(context_provider),
69 nullptr);
70 }
71
TearDown()72 void TearDown() override { copier_.reset(); }
73
copier() const74 GLRendererCopier* copier() const { return copier_.get(); }
75
test_gl() const76 CopierTestGLES2Interface* test_gl() const {
77 return static_cast<CopierTestGLES2Interface*>(
78 copier_->context_provider_->ContextGL());
79 }
80
81 // These simply forward method calls to GLRendererCopier.
TakeReusableThingsOrCreate(const base::UnguessableToken & requester)82 std::unique_ptr<ReusableThings> TakeReusableThingsOrCreate(
83 const base::UnguessableToken& requester) {
84 return copier_->TakeReusableThingsOrCreate(requester);
85 }
StashReusableThingsOrDelete(const base::UnguessableToken & requester,std::unique_ptr<ReusableThings> things)86 void StashReusableThingsOrDelete(const base::UnguessableToken& requester,
87 std::unique_ptr<ReusableThings> things) {
88 return copier_->StashReusableThingsOrDelete(requester, std::move(things));
89 }
PeekReusableThings(const base::UnguessableToken & requester)90 ReusableThings* PeekReusableThings(const base::UnguessableToken& requester) {
91 const auto it = copier_->cache_.find(requester);
92 if (it == copier_->cache_.end())
93 return nullptr;
94 return it->second.get();
95 }
GetCopierCacheSize()96 size_t GetCopierCacheSize() { return copier_->cache_.size(); }
FreeUnusedCachedResources()97 void FreeUnusedCachedResources() { copier_->FreeUnusedCachedResources(); }
GetOptimalReadbackFormat() const98 GLenum GetOptimalReadbackFormat() const {
99 return copier_->GetOptimalReadbackFormat();
100 }
101
102 static constexpr int kKeepalivePeriod = GLRendererCopier::kKeepalivePeriod;
103
104 private:
105 std::unique_ptr<GLRendererCopier> copier_;
106 };
107
108 // Tests that named objects, such as textures or framebuffers, are only cached
109 // when the CopyOutputRequest has specified a "source" of requests.
TEST_F(GLRendererCopierTest,ReusesThingsFromSameSource)110 TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
111 // With no source set in a copy request, expect to never re-use any textures
112 // or framebuffers.
113 const base::UnguessableToken no_source;
114 EXPECT_EQ(0u, GetCopierCacheSize());
115 auto things = TakeReusableThingsOrCreate(no_source);
116 EXPECT_TRUE(!!things);
117 StashReusableThingsOrDelete(no_source, std::move(things));
118 EXPECT_EQ(nullptr, PeekReusableThings(no_source));
119 EXPECT_EQ(0u, GetCopierCacheSize());
120
121 // With a source set in the request, objects should now be cached and re-used.
122 const auto source = base::UnguessableToken::Create();
123 things = TakeReusableThingsOrCreate(source);
124 ReusableThings* things_raw_ptr = things.get();
125 EXPECT_TRUE(!!things_raw_ptr);
126 StashReusableThingsOrDelete(source, std::move(things));
127 EXPECT_EQ(things_raw_ptr, PeekReusableThings(source));
128 EXPECT_EQ(1u, GetCopierCacheSize());
129
130 // A second, separate source gets its own cache entry.
131 const auto source2 = base::UnguessableToken::Create();
132 things = TakeReusableThingsOrCreate(source2);
133 things_raw_ptr = things.get();
134 EXPECT_TRUE(!!things_raw_ptr);
135 EXPECT_EQ(1u, GetCopierCacheSize());
136 StashReusableThingsOrDelete(source2, std::move(things));
137 EXPECT_EQ(things_raw_ptr, PeekReusableThings(source2));
138 EXPECT_EQ(2u, GetCopierCacheSize());
139 }
140
141 // Tests that cached resources are freed if unused for a while.
TEST_F(GLRendererCopierTest,FreesUnusedResources)142 TEST_F(GLRendererCopierTest, FreesUnusedResources) {
143 // Take and then stash a ReusableThings instance for a valid source.
144 const base::UnguessableToken source = base::UnguessableToken::Create();
145 EXPECT_EQ(0u, GetCopierCacheSize());
146 StashReusableThingsOrDelete(source, TakeReusableThingsOrCreate(source));
147 EXPECT_TRUE(!!PeekReusableThings(source));
148 EXPECT_EQ(1u, GetCopierCacheSize());
149
150 // Call FreesUnusedCachedResources() the maximum number of times before the
151 // cache entry would be considered for freeing.
152 for (int i = 0; i < kKeepalivePeriod - 1; ++i) {
153 FreeUnusedCachedResources();
154 EXPECT_TRUE(!!PeekReusableThings(source));
155 EXPECT_EQ(1u, GetCopierCacheSize());
156 if (HasFailure())
157 break;
158 }
159
160 // Calling FreeUnusedCachedResources() just one more time should cause the
161 // cache entry to be freed.
162 FreeUnusedCachedResources();
163 EXPECT_FALSE(!!PeekReusableThings(source));
164 EXPECT_EQ(0u, GetCopierCacheSize());
165 }
166
TEST_F(GLRendererCopierTest,DetectsBGRAForReadbackFormat)167 TEST_F(GLRendererCopierTest, DetectsBGRAForReadbackFormat) {
168 test_gl()->SetOptimalReadbackFormat(GL_BGRA_EXT, GL_UNSIGNED_BYTE);
169 EXPECT_EQ(static_cast<GLenum>(GL_BGRA_EXT), GetOptimalReadbackFormat());
170 }
171
TEST_F(GLRendererCopierTest,DetectsRGBAForReadbackFormat)172 TEST_F(GLRendererCopierTest, DetectsRGBAForReadbackFormat) {
173 test_gl()->SetOptimalReadbackFormat(GL_RGBA, GL_UNSIGNED_BYTE);
174 EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
175 }
176
TEST_F(GLRendererCopierTest,FallsBackOnRGBAForReadbackFormat_BadFormat)177 TEST_F(GLRendererCopierTest, FallsBackOnRGBAForReadbackFormat_BadFormat) {
178 test_gl()->SetOptimalReadbackFormat(GL_RGB, GL_UNSIGNED_BYTE);
179 EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
180 }
181
TEST_F(GLRendererCopierTest,FallsBackOnRGBAForReadbackFormat_BadType)182 TEST_F(GLRendererCopierTest, FallsBackOnRGBAForReadbackFormat_BadType) {
183 test_gl()->SetOptimalReadbackFormat(GL_BGRA_EXT, GL_UNSIGNED_SHORT);
184 EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
185 }
186
187 } // namespace viz
188