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