// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/command_line.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "cc/paint/image_transfer_cache_entry.h" #include "cc/paint/raw_memory_transfer_cache_entry.h" #include "cc/paint/transfer_cache_entry.h" #include "components/viz/test/test_gpu_service_holder.h" #include "components/viz/test/test_in_process_context_provider.h" #include "gpu/command_buffer/client/client_transfer_cache.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/raster_interface.h" #include "gpu/command_buffer/client/shared_memory_limits.h" #include "gpu/command_buffer/common/context_creation_attribs.h" #include "gpu/command_buffer/service/service_transfer_cache.h" #include "gpu/config/gpu_switches.h" #include "gpu/ipc/raster_in_process_context.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkImage.h" #include "ui/gl/gl_implementation.h" namespace cc { namespace { class TransferCacheTest : public testing::Test { public: TransferCacheTest() : test_client_entry_(std::vector(100)) {} void SetUp() override { gpu::ContextCreationAttribs attribs; attribs.alpha_size = -1; attribs.depth_size = 24; attribs.stencil_size = 8; attribs.samples = 0; attribs.sample_buffers = 0; attribs.fail_if_major_perf_caveat = false; attribs.bind_generates_resource = false; // Enable OOP rasterization. attribs.enable_oop_rasterization = true; attribs.enable_raster_interface = true; attribs.enable_gles2_interface = false; context_ = std::make_unique(); auto result = context_->Initialize( viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_, &image_factory_, /*gpu_channel_manager_delegate=*/nullptr, nullptr, nullptr); ASSERT_EQ(result, gpu::ContextResult::kSuccess); ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster); } void TearDown() override { context_.reset(); } gpu::ServiceTransferCache* ServiceTransferCache() { return context_->GetTransferCacheForTest(); } int decoder_id() { return context_->GetRasterDecoderIdForTest(); } gpu::raster::RasterInterface* ri() { return context_->GetImplementation(); } gpu::ContextSupport* ContextSupport() { return context_->GetContextSupport(); } const ClientRawMemoryTransferCacheEntry& test_client_entry() const { return test_client_entry_; } void CreateEntry(const ClientTransferCacheEntry& entry) { auto* context_support = ContextSupport(); uint32_t size = entry.SerializedSize(); void* data = context_support->MapTransferCacheEntry(size); ASSERT_TRUE(data); entry.Serialize(base::make_span(static_cast(data), size)); context_support->UnmapAndCreateTransferCacheEntry(entry.UnsafeType(), entry.Id()); } private: viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_; viz::TestImageFactory image_factory_; std::unique_ptr context_; gl::DisableNullDrawGLBindings enable_pixel_output_; ClientRawMemoryTransferCacheEntry test_client_entry_; }; TEST_F(TransferCacheTest, Basic) { auto* service_cache = ServiceTransferCache(); auto* context_support = ContextSupport(); // Create an entry. const auto& entry = test_client_entry(); CreateEntry(entry); ri()->Finish(); // Validate service-side state. EXPECT_NE(nullptr, service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), entry.Type(), entry.Id()))); // Unlock on client side and flush to service. context_support->UnlockTransferCacheEntries( {{entry.UnsafeType(), entry.Id()}}); ri()->Finish(); // Re-lock on client side and validate state. No need to flush as lock is // local. EXPECT_TRUE(context_support->ThreadsafeLockTransferCacheEntry( entry.UnsafeType(), entry.Id())); // Delete on client side, flush, and validate that deletion reaches service. context_support->DeleteTransferCacheEntry(entry.UnsafeType(), entry.Id()); ri()->Finish(); EXPECT_EQ(nullptr, service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), entry.Type(), entry.Id()))); } TEST_F(TransferCacheTest, MemoryEviction) { auto* service_cache = ServiceTransferCache(); auto* context_support = ContextSupport(); const auto& entry = test_client_entry(); // Create an entry. CreateEntry(entry); ri()->Finish(); // Validate service-side state. EXPECT_NE(nullptr, service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), entry.Type(), entry.Id()))); // Unlock on client side and flush to service. context_support->UnlockTransferCacheEntries( {{entry.UnsafeType(), entry.Id()}}); ri()->Finish(); // Evict on the service side. service_cache->SetCacheSizeLimitForTesting(0); EXPECT_EQ(nullptr, service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), entry.Type(), entry.Id()))); // Try to re-lock on the client side. This should fail. EXPECT_FALSE(context_support->ThreadsafeLockTransferCacheEntry( entry.UnsafeType(), entry.Id())); } TEST_F(TransferCacheTest, CountEviction) { auto* service_cache = ServiceTransferCache(); auto* context_support = ContextSupport(); // Create 10 entries and leave them all unlocked. std::vector> entries; for (int i = 0; i < 10; ++i) { entries.emplace_back(std::make_unique( std::vector(4))); CreateEntry(*entries[i]); context_support->UnlockTransferCacheEntries( {{entries[i]->UnsafeType(), entries[i]->Id()}}); ri()->Finish(); } // These entries should be using up space. EXPECT_EQ(service_cache->cache_size_for_testing(), 40u); // Evict on the service side. service_cache->SetMaxCacheEntriesForTesting(5); // Half the entries should be evicted. EXPECT_EQ(service_cache->cache_size_for_testing(), 20u); } // This tests a size that is small enough that the transfer buffer is used // inside of RasterImplementation::MapTransferCacheEntry. TEST_F(TransferCacheTest, RawMemoryTransferSmall) { auto* service_cache = ServiceTransferCache(); // Create an entry with some initialized data. std::vector data; data.resize(100); for (size_t i = 0; i < data.size(); ++i) { data[i] = i; } // Add the entry to the transfer cache ClientRawMemoryTransferCacheEntry client_entry(data); CreateEntry(client_entry); ri()->Finish(); // Validate service-side data matches. ServiceTransferCacheEntry* service_entry = service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), client_entry.Type(), client_entry.Id())); EXPECT_EQ(service_entry->Type(), client_entry.Type()); const std::vector service_data = static_cast(service_entry)->data(); EXPECT_EQ(data, service_data); } // This tests a size that is large enough that mapped memory is used inside // of RasterImplementation::MapTransferCacheEntry. TEST_F(TransferCacheTest, RawMemoryTransferLarge) { auto* service_cache = ServiceTransferCache(); // Create an entry with some initialized data. std::vector data; data.resize(1500); for (size_t i = 0; i < data.size(); ++i) { data[i] = i; } // Add the entry to the transfer cache ClientRawMemoryTransferCacheEntry client_entry(data); CreateEntry(client_entry); ri()->Finish(); // Validate service-side data matches. ServiceTransferCacheEntry* service_entry = service_cache->GetEntry(gpu::ServiceTransferCache::EntryKey( decoder_id(), client_entry.Type(), client_entry.Id())); EXPECT_EQ(service_entry->Type(), client_entry.Type()); const std::vector service_data = static_cast(service_entry)->data(); EXPECT_EQ(data, service_data); } } // namespace } // namespace cc