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 <vector>
6 
7 #include "base/command_line.h"
8 #include "base/threading/thread_task_runner_handle.h"
9 #include "build/build_config.h"
10 #include "cc/paint/image_transfer_cache_entry.h"
11 #include "cc/paint/raw_memory_transfer_cache_entry.h"
12 #include "cc/paint/transfer_cache_entry.h"
13 #include "components/viz/test/test_gpu_service_holder.h"
14 #include "components/viz/test/test_in_process_context_provider.h"
15 #include "gpu/command_buffer/client/client_transfer_cache.h"
16 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
17 #include "gpu/command_buffer/client/gles2_implementation.h"
18 #include "gpu/command_buffer/client/raster_interface.h"
19 #include "gpu/command_buffer/client/shared_memory_limits.h"
20 #include "gpu/command_buffer/common/context_creation_attribs.h"
21 #include "gpu/command_buffer/service/service_transfer_cache.h"
22 #include "gpu/config/gpu_switches.h"
23 #include "gpu/ipc/raster_in_process_context.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/skia/include/core/SkImage.h"
26 #include "ui/gl/gl_implementation.h"
27 
28 namespace cc {
29 namespace {
30 
31 class TransferCacheTest : public testing::Test {
32  public:
TransferCacheTest()33   TransferCacheTest() : test_client_entry_(std::vector<uint8_t>(100)) {}
34 
SetUp()35   void SetUp() override {
36     gpu::ContextCreationAttribs attribs;
37     attribs.alpha_size = -1;
38     attribs.depth_size = 24;
39     attribs.stencil_size = 8;
40     attribs.samples = 0;
41     attribs.sample_buffers = 0;
42     attribs.fail_if_major_perf_caveat = false;
43     attribs.bind_generates_resource = false;
44     // Enable OOP rasterization.
45     attribs.enable_oop_rasterization = true;
46     attribs.enable_raster_interface = true;
47     attribs.enable_gles2_interface = false;
48 
49     context_ = std::make_unique<gpu::RasterInProcessContext>();
50     auto result = context_->Initialize(
51         viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs,
52         gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_, &image_factory_,
53         /*gpu_channel_manager_delegate=*/nullptr, nullptr, nullptr);
54 
55     ASSERT_EQ(result, gpu::ContextResult::kSuccess);
56     ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
57   }
58 
TearDown()59   void TearDown() override { context_.reset(); }
60 
ServiceTransferCache()61   gpu::ServiceTransferCache* ServiceTransferCache() {
62     return context_->GetTransferCacheForTest();
63   }
64 
decoder_id()65   int decoder_id() { return context_->GetRasterDecoderIdForTest(); }
66 
ri()67   gpu::raster::RasterInterface* ri() { return context_->GetImplementation(); }
68 
ContextSupport()69   gpu::ContextSupport* ContextSupport() {
70     return context_->GetContextSupport();
71   }
72 
test_client_entry() const73   const ClientRawMemoryTransferCacheEntry& test_client_entry() const {
74     return test_client_entry_;
75   }
CreateEntry(const ClientTransferCacheEntry & entry)76   void CreateEntry(const ClientTransferCacheEntry& entry) {
77     auto* context_support = ContextSupport();
78     uint32_t size = entry.SerializedSize();
79     void* data = context_support->MapTransferCacheEntry(size);
80     ASSERT_TRUE(data);
81     entry.Serialize(base::make_span(static_cast<uint8_t*>(data), size));
82     context_support->UnmapAndCreateTransferCacheEntry(entry.UnsafeType(),
83                                                       entry.Id());
84   }
85 
86  private:
87   viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
88   viz::TestImageFactory image_factory_;
89   std::unique_ptr<gpu::RasterInProcessContext> context_;
90   gl::DisableNullDrawGLBindings enable_pixel_output_;
91   ClientRawMemoryTransferCacheEntry test_client_entry_;
92 };
93 
TEST_F(TransferCacheTest,Basic)94 TEST_F(TransferCacheTest, Basic) {
95   auto* service_cache = ServiceTransferCache();
96   auto* context_support = ContextSupport();
97 
98   // Create an entry.
99   const auto& entry = test_client_entry();
100   CreateEntry(entry);
101   ri()->Finish();
102 
103   // Validate service-side state.
104   EXPECT_NE(nullptr,
105             service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
106                 decoder_id(), entry.Type(), entry.Id())));
107 
108   // Unlock on client side and flush to service.
109   context_support->UnlockTransferCacheEntries(
110       {{entry.UnsafeType(), entry.Id()}});
111   ri()->Finish();
112 
113   // Re-lock on client side and validate state. No need to flush as lock is
114   // local.
115   EXPECT_TRUE(context_support->ThreadsafeLockTransferCacheEntry(
116       entry.UnsafeType(), entry.Id()));
117 
118   // Delete on client side, flush, and validate that deletion reaches service.
119   context_support->DeleteTransferCacheEntry(entry.UnsafeType(), entry.Id());
120   ri()->Finish();
121   EXPECT_EQ(nullptr,
122             service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
123                 decoder_id(), entry.Type(), entry.Id())));
124 }
125 
TEST_F(TransferCacheTest,MemoryEviction)126 TEST_F(TransferCacheTest, MemoryEviction) {
127   auto* service_cache = ServiceTransferCache();
128   auto* context_support = ContextSupport();
129 
130   const auto& entry = test_client_entry();
131   // Create an entry.
132   CreateEntry(entry);
133   ri()->Finish();
134 
135   // Validate service-side state.
136   EXPECT_NE(nullptr,
137             service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
138                 decoder_id(), entry.Type(), entry.Id())));
139 
140   // Unlock on client side and flush to service.
141   context_support->UnlockTransferCacheEntries(
142       {{entry.UnsafeType(), entry.Id()}});
143   ri()->Finish();
144 
145   // Evict on the service side.
146   service_cache->SetCacheSizeLimitForTesting(0);
147   EXPECT_EQ(nullptr,
148             service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
149                 decoder_id(), entry.Type(), entry.Id())));
150 
151   // Try to re-lock on the client side. This should fail.
152   EXPECT_FALSE(context_support->ThreadsafeLockTransferCacheEntry(
153       entry.UnsafeType(), entry.Id()));
154 }
155 
TEST_F(TransferCacheTest,CountEviction)156 TEST_F(TransferCacheTest, CountEviction) {
157   auto* service_cache = ServiceTransferCache();
158   auto* context_support = ContextSupport();
159 
160   // Create 10 entries and leave them all unlocked.
161   std::vector<std::unique_ptr<ClientRawMemoryTransferCacheEntry>> entries;
162   for (int i = 0; i < 10; ++i) {
163     entries.emplace_back(std::make_unique<ClientRawMemoryTransferCacheEntry>(
164         std::vector<uint8_t>(4)));
165     CreateEntry(*entries[i]);
166     context_support->UnlockTransferCacheEntries(
167         {{entries[i]->UnsafeType(), entries[i]->Id()}});
168     ri()->Finish();
169   }
170 
171   // These entries should be using up space.
172   EXPECT_EQ(service_cache->cache_size_for_testing(), 40u);
173 
174   // Evict on the service side.
175   service_cache->SetMaxCacheEntriesForTesting(5);
176 
177   // Half the entries should be evicted.
178   EXPECT_EQ(service_cache->cache_size_for_testing(), 20u);
179 }
180 
181 // This tests a size that is small enough that the transfer buffer is used
182 // inside of RasterImplementation::MapTransferCacheEntry.
TEST_F(TransferCacheTest,RawMemoryTransferSmall)183 TEST_F(TransferCacheTest, RawMemoryTransferSmall) {
184   auto* service_cache = ServiceTransferCache();
185 
186   // Create an entry with some initialized data.
187   std::vector<uint8_t> data;
188   data.resize(100);
189   for (size_t i = 0; i < data.size(); ++i) {
190     data[i] = i;
191   }
192 
193   // Add the entry to the transfer cache
194   ClientRawMemoryTransferCacheEntry client_entry(data);
195   CreateEntry(client_entry);
196   ri()->Finish();
197 
198   // Validate service-side data matches.
199   ServiceTransferCacheEntry* service_entry =
200       service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
201           decoder_id(), client_entry.Type(), client_entry.Id()));
202   EXPECT_EQ(service_entry->Type(), client_entry.Type());
203   const std::vector<uint8_t> service_data =
204       static_cast<ServiceRawMemoryTransferCacheEntry*>(service_entry)->data();
205   EXPECT_EQ(data, service_data);
206 }
207 
208 // This tests a size that is large enough that mapped memory is used inside
209 // of RasterImplementation::MapTransferCacheEntry.
TEST_F(TransferCacheTest,RawMemoryTransferLarge)210 TEST_F(TransferCacheTest, RawMemoryTransferLarge) {
211   auto* service_cache = ServiceTransferCache();
212 
213   // Create an entry with some initialized data.
214   std::vector<uint8_t> data;
215   data.resize(1500);
216   for (size_t i = 0; i < data.size(); ++i) {
217     data[i] = i;
218   }
219 
220   // Add the entry to the transfer cache
221   ClientRawMemoryTransferCacheEntry client_entry(data);
222   CreateEntry(client_entry);
223   ri()->Finish();
224 
225   // Validate service-side data matches.
226   ServiceTransferCacheEntry* service_entry =
227       service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey(
228           decoder_id(), client_entry.Type(), client_entry.Id()));
229   EXPECT_EQ(service_entry->Type(), client_entry.Type());
230   const std::vector<uint8_t> service_data =
231       static_cast<ServiceRawMemoryTransferCacheEntry*>(service_entry)->data();
232   EXPECT_EQ(data, service_data);
233 }
234 
235 }  // namespace
236 }  // namespace cc
237