blob: d32d1ef2a5c0bce72c3c6e8a5993849c8fe16b1a [file]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkSurface.h"
#include "include/gpu/ganesh/GrRecordingContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "include/private/chromium/GrDeferredDisplayListRecorder.h"
#include "include/private/chromium/GrSurfaceCharacterization.h"
#include "src/gpu/ResourceKey.h"
#include "src/gpu/ganesh/GrProxyProvider.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrTextureProxy.h"
#include "tests/CtsEnforcement.h"
#include "tests/Test.h"
#include "tools/ganesh/ProxyUtils.h"
#include <thread>
namespace {
skgpu::UniqueKey create_key(int keyValue) {
static skgpu::UniqueKey::Domain d = skgpu::UniqueKey::GenerateDomain();
skgpu::UniqueKey key;
skgpu::UniqueKey::Builder builder(&key, d, 1, nullptr);
builder[0] = keyValue;
builder.finish();
return key;
}
sk_sp<SkImage> create_keyed_image(GrRecordingContext* rContext, int keyValue) {
SkImageInfo ii = SkImageInfo::MakeN32Premul(16, 16);
sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kYes, ii);
surf->getCanvas()->clear(SK_ColorWHITE);
surf->getCanvas()->drawCircle(8, 8, 8, SkPaint());
sk_sp<SkImage> img = surf->makeImageSnapshot();
GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(img.get(),
surf->recordingContext());
skgpu::UniqueKey key = create_key(keyValue);
rContext->priv().proxyProvider()->assignUniqueKeyToProxy(key, proxy);
return img;
}
void ddl_deleter(skiatest::Reporter* reporter,
sk_sp<GrUniquelyKeyedProxyRegistry> registry,
sk_sp<GrDeferredDisplayList> ddl,
int keyValue) {
const auto kSleepDuration = std::chrono::milliseconds(1);
std::this_thread::sleep_for(kSleepDuration);
skgpu::UniqueKey key = create_key(keyValue);
REPORTER_ASSERT(reporter, registry->find(key));
ddl.reset();
REPORTER_ASSERT(reporter, !registry->find(key));
}
} // anonymous namespace
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrUniqueProxyTest,
reporter,
ctxInfo,
CtsEnforcement::kNever) {
GrDirectContext* dContext = ctxInfo.directContext();
GrSurfaceCharacterization characterization;
// Grab a characterization
{
SkImageInfo ii = SkImageInfo::MakeN32Premul(16, 16);
sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, ii);
SkAssertResult(surf);
SkAssertResult(surf->characterize(&characterization));
}
// Create a recorder
std::unique_ptr<GrDeferredDisplayListRecorder> recorder;
recorder = std::make_unique<GrDeferredDisplayListRecorder>(characterization);
GrProxyProvider* proxyProvider = recorder->getCanvas()->recordingContext()->priv().proxyProvider();
sk_sp<GrUniquelyKeyedProxyRegistry> registry = proxyProvider->uniquelyKeyedProxyRegistry();
std::vector<std::thread> threads;
// Create DDLs and immediately hand them off to a thread for deletion. Each DDL will have
// a single uniquely keyed proxy.
for (int i = 0; i < 10; i++) {
SkCanvas* canvas = recorder->getCanvas();
canvas->clear(SkColors::kRed);
sk_sp<SkImage> img = create_keyed_image(canvas->recordingContext(), i);
canvas->drawImage(img.get(), 0, 0);
sk_sp<GrDeferredDisplayList> ddl = recorder->detach();
threads.push_back(std::thread(ddl_deleter, reporter, registry, std::move(ddl), i));
}
// Delete the recorder - hopefully before all the DDLs are deleted
recorder.reset();
for (auto& thread : threads) {
if (thread.joinable()) {
thread.join();
}
}
// All the texture proxies should be deleted and have deregistered their keys
REPORTER_ASSERT(reporter, registry->count() == 0);
REPORTER_ASSERT(reporter, registry->unique());
}