blob: c447aafbae09c9d19dd48c5e308114a90dfe6534 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h"
#include "base/test/task_environment.h"
#include "cc/test/stub_decode_cache.h"
#include "components/viz/test/test_context_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
namespace blink {
class WebGPURecyclableResourceCacheTest : public testing::Test {
public:
WebGPURecyclableResourceCacheTest() = default;
~WebGPURecyclableResourceCacheTest() override = default;
// Implements testing::Test
void SetUp() override;
void TearDown() override;
protected:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<WebGPURecyclableResourceCache> recyclable_resource_cache_;
cc::StubDecodeCache image_decode_cache_;
scoped_refptr<viz::TestContextProvider> test_context_provider_;
};
void WebGPURecyclableResourceCacheTest::SetUp() {
Platform::SetMainThreadTaskRunnerForTesting();
test_context_provider_ = viz::TestContextProvider::Create();
InitializeSharedGpuContext(test_context_provider_.get(),
&image_decode_cache_);
recyclable_resource_cache_ = std::make_unique<WebGPURecyclableResourceCache>(
SharedGpuContext::ContextProviderWrapper(),
scheduler::GetSingleThreadTaskRunnerForTesting());
}
void WebGPURecyclableResourceCacheTest::TearDown() {
Platform::UnsetMainThreadTaskRunnerForTesting();
SharedGpuContext::ResetForTesting();
}
TEST_F(WebGPURecyclableResourceCacheTest, MRUSameSize) {
SkImageInfo kInfo =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Vector<CanvasResourceProvider*> returned_resource_providers;
std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_0->resource_provider());
std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_1->resource_provider());
// Now release the holders to recycle the resource_providers.
provider_holder_0.reset();
provider_holder_1.reset(); // MRU
std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_2->resource_provider());
// GetOrCreateCanvasResource should return the MRU provider, which is
// provider_holder_1, for provider_holder_2.
EXPECT_EQ(returned_resource_providers[1], returned_resource_providers[2]);
}
TEST_F(WebGPURecyclableResourceCacheTest, DifferentSize) {
const SkImageInfo kInfos[] = {
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
SkImageInfo::Make(20, 20, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
};
Vector<CanvasResourceProvider*> returned_resource_providers;
std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfos[0], /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_0->resource_provider());
std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfos[1], /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_1->resource_provider());
// Now release the holders to recycle the resource_providers.
provider_holder_1.reset();
provider_holder_0.reset();
std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfos[0], /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_2->resource_provider());
std::unique_ptr<RecyclableCanvasResource> provider_holder_3 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfos[1], /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_3->resource_provider());
// GetOrCreateCanvasResource should return the same resource provider
// for the request with the same size.
EXPECT_EQ(returned_resource_providers[0], returned_resource_providers[2]);
EXPECT_EQ(returned_resource_providers[1], returned_resource_providers[3]);
}
TEST_F(WebGPURecyclableResourceCacheTest, CacheMissHit) {
Vector<CanvasResourceProvider*> returned_resource_providers;
const auto info_0 =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_0, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_0->resource_provider());
// Now release the holder to recycle the resource_provider.
provider_holder_0.reset();
// (1) For different size.
const auto info_1 =
SkImageInfo::Make(20, 20, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_1, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_1->resource_provider());
// Cache miss. A new resource provider should be created.
EXPECT_NE(returned_resource_providers[0], returned_resource_providers[1]);
// (2) For different is_origin_top_left.
const auto info_2 =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
std::unique_ptr<RecyclableCanvasResource> provider_holder_2 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_2, /*is_origin_top_left=*/false);
returned_resource_providers.push_back(provider_holder_2->resource_provider());
// Cache miss. A new resource provider should be created.
EXPECT_NE(returned_resource_providers[0], returned_resource_providers[2]);
// (3) For different SkImageInfo: color space
const SkImageInfo info_3 =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
SkColorSpace::MakeSRGBLinear());
std::unique_ptr<RecyclableCanvasResource> provider_holder_3 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_3, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_3->resource_provider());
// Cache miss. A new resource provider should be created.
EXPECT_NE(returned_resource_providers[0], returned_resource_providers[3]);
// (4) For different SkImageInfo: color type.
const SkImageInfo info_4 =
SkImageInfo::Make(10, 10, kRGBA_F16_SkColorType, kPremul_SkAlphaType);
std::unique_ptr<RecyclableCanvasResource> provider_holder_4 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_4, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_4->resource_provider());
// Cache miss. A new resource provider should be created.
EXPECT_NE(returned_resource_providers[0], returned_resource_providers[4]);
// (5) For different SkImageInfo: alpha type.
const auto info_5 =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
std::unique_ptr<RecyclableCanvasResource> provider_holder_5 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_5, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_5->resource_provider());
// Cache miss. A new resource provider should be created.
EXPECT_NE(returned_resource_providers[0], returned_resource_providers[5]);
// (6) For the same config again.
std::unique_ptr<RecyclableCanvasResource> provider_holder_6 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
info_0, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_6->resource_provider());
// Should get the same provider.
EXPECT_EQ(returned_resource_providers[0], returned_resource_providers[6]);
}
TEST_F(WebGPURecyclableResourceCacheTest, StaleResourcesCleanUp) {
SkImageInfo kInfo =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Vector<CanvasResourceProvider*> returned_resource_providers;
// The loop count for CleanUpResources before the resource gets cleaned up.
int wait_count =
recyclable_resource_cache_->GetWaitCountBeforeDeletionForTesting();
std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_0->resource_provider());
std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_1->resource_provider());
// Now release the holders to recycle the resource_providers.
provider_holder_0.reset();
provider_holder_1.reset();
// Before the intended delay, the recycled resources should not be released
// from cache.
for (int i = 0; i < wait_count; i++) {
wtf_size_t size =
recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
EXPECT_EQ(2u, size);
}
// After the intended delay, all stale resources should be released now.
wtf_size_t size_after =
recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
EXPECT_EQ(0u, size_after);
}
TEST_F(WebGPURecyclableResourceCacheTest, ReuseBeforeCleanUp) {
SkImageInfo kInfo =
SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Vector<CanvasResourceProvider*> returned_resource_providers;
// The loop count for CleanUpResources before the resource gets cleaned up.
int wait_count =
recyclable_resource_cache_->GetWaitCountBeforeDeletionForTesting();
std::unique_ptr<RecyclableCanvasResource> provider_holder_0 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(provider_holder_0->resource_provider());
// Release the holder to recycle the resource_provider.
provider_holder_0.reset();
// Before the intended delay, the recycled resources should not be released
// from cache.
for (int i = 0; i < wait_count; i++) {
if (i == 1) {
// Now request a resource with the same configuration.
std::unique_ptr<RecyclableCanvasResource> provider_holder_1 =
recyclable_resource_cache_->GetOrCreateCanvasResource(
kInfo, /*is_origin_top_left=*/true);
returned_resource_providers.push_back(
provider_holder_1->resource_provider());
// Release the holders again to recycle the resource_providers.
provider_holder_1.reset();
}
wtf_size_t size =
recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
EXPECT_EQ(1u, size);
}
// Since the resource is reused before it gets deleted, it should not be
// cleaned up on the next scheduled clean up. Instead, it will be cleaned up
// with a new schedule.
//
wtf_size_t size =
recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
EXPECT_EQ(1u, size);
// Now, the resource should be deleted.
size = recyclable_resource_cache_->CleanUpResourcesAndReturnSizeForTesting();
EXPECT_EQ(0u, size);
}
} // namespace blink