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