blob: 1c9fe834ddb89ba81294087b0b00fb85644a354f [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/gr_cache_controller.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/init/gl_factory.h"
#include "ui/gl/test/gl_surface_test_support.h"
namespace gpu {
namespace raster {
class GrCacheControllerTest : public testing::Test {
public:
void SetUp() override {
display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
gpu::GpuDriverBugWorkarounds workarounds;
scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup();
scoped_refptr<gl::GLSurface> surface =
gl::init::CreateOffscreenGLSurface(display_, gfx::Size());
scoped_refptr<gl::GLContext> context = gl::init::CreateGLContext(
share_group.get(), surface.get(), gl::GLContextAttribs());
ASSERT_TRUE(context->MakeCurrent(surface.get()));
task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
context_state_ = base::MakeRefCounted<SharedContextState>(
std::move(share_group), std::move(surface), std::move(context),
false /* use_virtualized_gl_contexts */, base::DoNothing(),
GrContextType::kGL);
context_state_->InitializeSkia(GpuPreferences(), workarounds);
auto feature_info =
base::MakeRefCounted<gles2::FeatureInfo>(workarounds, GpuFeatureInfo());
context_state_->InitializeGL(GpuPreferences(), std::move(feature_info));
controller_ = base::WrapUnique(
new GrCacheController(context_state_.get(), task_runner_));
}
void CreateControllerWithoutTaskRunner() {
controller_ =
base::WrapUnique(new GrCacheController(context_state_.get(), nullptr));
}
void TearDown() override {
controller_ = nullptr;
context_state_ = nullptr;
task_runner_ = nullptr;
gl::GLSurfaceTestSupport::ShutdownGL(display_);
}
GrDirectContext* gr_context() { return context_state_->gr_context(); }
protected:
scoped_refptr<SharedContextState> context_state_;
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<GrCacheController> controller_;
raw_ptr<gl::GLDisplay> display_ = nullptr;
};
TEST_F(GrCacheControllerTest, PurgeGrCache) {
EXPECT_EQ(gr_context()->getResourceCachePurgeableBytes(), 0u);
{
// Use the GrContext to upload an image.
SkBitmap bm;
SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
ASSERT_TRUE(bm.tryAllocPixels(info));
sk_sp<SkImage> uploaded = SkImages::TextureFromImage(
gr_context(), SkImages::RasterFromBitmap(bm));
ASSERT_TRUE(uploaded);
}
EXPECT_GT(gr_context()->getResourceCachePurgeableBytes(), 0u);
// We should have a pending task to clear the cache.
controller_->ScheduleGrContextCleanup();
EXPECT_TRUE(task_runner_->HasPendingTask());
// Fast forward by a second, the task runs and the cache is cleared.
task_runner_->FastForwardBy(base::Seconds(1));
EXPECT_EQ(gr_context()->getResourceCachePurgeableBytes(), 0u);
}
TEST_F(GrCacheControllerTest, ResetPurgeGrCacheOnReuse) {
EXPECT_EQ(gr_context()->getResourceCachePurgeableBytes(), 0u);
{
// Use the GrContext to upload an image.
SkBitmap bm;
SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
ASSERT_TRUE(bm.tryAllocPixels(info));
sk_sp<SkImage> uploaded = SkImages::TextureFromImage(
gr_context(), SkImages::RasterFromBitmap(bm));
ASSERT_TRUE(uploaded);
}
EXPECT_GT(gr_context()->getResourceCachePurgeableBytes(), 0u);
// We should have a pending task to clear the cache.
controller_->ScheduleGrContextCleanup();
EXPECT_TRUE(task_runner_->HasPendingTask());
// Reuse the context. This should push clearing of the cache further by a
// second.
controller_->ScheduleGrContextCleanup();
// Fast forward by a second, the task runs but since the context was used
// since the task was posted, the cache is not cleared.
task_runner_->FastForwardBy(base::Seconds(1));
EXPECT_GT(gr_context()->getResourceCachePurgeableBytes(), 0u);
// Fast forward by another second. Since there is no activity, the cache is
// cleared.
task_runner_->FastForwardBy(base::Seconds(1));
EXPECT_EQ(gr_context()->getResourceCachePurgeableBytes(), 0u);
}
TEST_F(GrCacheControllerTest, NoTaskRunner) {
base::test::ScopedFeatureList scoped_list;
CreateControllerWithoutTaskRunner();
EXPECT_FALSE(context_state_->need_context_state_reset());
controller_->ScheduleGrContextCleanup();
EXPECT_TRUE(context_state_->need_context_state_reset());
}
} // namespace raster
} // namespace gpu