blob: f8f7984e8dbe02c6cdd20e558bcd4de31aff4e75 [file] [log] [blame]
// 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 <vector>
#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<uint8_t>(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<gpu::RasterInProcessContext>();
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<uint8_t*>(data), size));
context_support->UnmapAndCreateTransferCacheEntry(entry.UnsafeType(),
entry.Id());
}
private:
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
viz::TestImageFactory image_factory_;
std::unique_ptr<gpu::RasterInProcessContext> 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<std::unique_ptr<ClientRawMemoryTransferCacheEntry>> entries;
for (int i = 0; i < 10; ++i) {
entries.emplace_back(std::make_unique<ClientRawMemoryTransferCacheEntry>(
std::vector<uint8_t>(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<uint8_t> 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<uint8_t> service_data =
static_cast<ServiceRawMemoryTransferCacheEntry*>(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<uint8_t> 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<uint8_t> service_data =
static_cast<ServiceRawMemoryTransferCacheEntry*>(service_entry)->data();
EXPECT_EQ(data, service_data);
}
} // namespace
} // namespace cc