1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Context.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextPriv.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ProxyCache.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Texture.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxy.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/graphite/GraphiteTestContext.h"
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker #include <thread>
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker // This test exercises the basic MessageBus behavior of the ProxyCache by manually inserting an
29*c8dee2aaSAndroid Build Coastguard Worker // SkBitmap into the proxy cache and then changing its contents. This simple test should create
30*c8dee2aaSAndroid Build Coastguard Worker // an IDChangeListener that will remove the entry in the cache when the bitmap is changed and
31*c8dee2aaSAndroid Build Coastguard Worker // the resulting message processed.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest1,r,context,CtsEnforcement::kApiLevel_V)32*c8dee2aaSAndroid Build Coastguard Worker DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest1, r, context, CtsEnforcement::kApiLevel_V) {
33*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
34*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
35*c8dee2aaSAndroid Build Coastguard Worker
36*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bitmap;
37*c8dee2aaSAndroid Build Coastguard Worker bool success = ToolUtils::GetResourceAsBitmap("images/mandrill_128.png", &bitmap);
38*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, success);
39*c8dee2aaSAndroid Build Coastguard Worker if (!success) {
40*c8dee2aaSAndroid Build Coastguard Worker return;
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy = proxyCache->findOrCreateCachedProxy(recorder.get(), bitmap,
46*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker bitmap.eraseColor(SK_ColorBLACK);
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceProcessInvalidKeyMsgs();
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker // This test checks that, if the same bitmap is added to two separate ProxyCaches, when it is
58*c8dee2aaSAndroid Build Coastguard Worker // changed, both of the ProxyCaches will receive the message.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest2,r,context,CtsEnforcement::kApiLevel_V)59*c8dee2aaSAndroid Build Coastguard Worker DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest2, r, context, CtsEnforcement::kApiLevel_V) {
60*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder1 = context->makeRecorder();
61*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache1 = recorder1->priv().proxyCache();
62*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder2 = context->makeRecorder();
63*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache2 = recorder2->priv().proxyCache();
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bitmap;
66*c8dee2aaSAndroid Build Coastguard Worker bool success = ToolUtils::GetResourceAsBitmap("images/mandrill_128.png", &bitmap);
67*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, success);
68*c8dee2aaSAndroid Build Coastguard Worker if (!success) {
69*c8dee2aaSAndroid Build Coastguard Worker return;
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache1->numCached() == 0);
73*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache2->numCached() == 0);
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy1 = proxyCache1->findOrCreateCachedProxy(recorder1.get(), bitmap,
76*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
77*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy2 = proxyCache2->findOrCreateCachedProxy(recorder2.get(), bitmap,
78*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache1->numCached() == 1);
81*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache2->numCached() == 1);
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker bitmap.eraseColor(SK_ColorBLACK);
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Worker proxyCache1->forceProcessInvalidKeyMsgs();
86*c8dee2aaSAndroid Build Coastguard Worker proxyCache2->forceProcessInvalidKeyMsgs();
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache1->numCached() == 0);
89*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache2->numCached() == 0);
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker namespace {
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker struct ProxyCacheSetup {
validskgpu::graphite::__anoncd1e84aa0111::ProxyCacheSetup95*c8dee2aaSAndroid Build Coastguard Worker bool valid() const {
96*c8dee2aaSAndroid Build Coastguard Worker return !fBitmap1.empty() && !fBitmap2.empty() && fProxy1 && fProxy2;
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker SkBitmap fBitmap1;
100*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> fProxy1;
101*c8dee2aaSAndroid Build Coastguard Worker SkBitmap fBitmap2;
102*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> fProxy2;
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker skgpu::StdSteadyClock::time_point fTimeBetweenProxyCreation;
105*c8dee2aaSAndroid Build Coastguard Worker skgpu::StdSteadyClock::time_point fTimeAfterAllProxyCreation;
106*c8dee2aaSAndroid Build Coastguard Worker };
107*c8dee2aaSAndroid Build Coastguard Worker
setup_test(Context * context,skiatest::graphite::GraphiteTestContext * testContext,Recorder * recorder,skiatest::Reporter * r)108*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup_test(Context* context,
109*c8dee2aaSAndroid Build Coastguard Worker skiatest::graphite::GraphiteTestContext* testContext,
110*c8dee2aaSAndroid Build Coastguard Worker Recorder* recorder,
111*c8dee2aaSAndroid Build Coastguard Worker skiatest::Reporter* r) {
112*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup;
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker bool success1 = ToolUtils::GetResourceAsBitmap("images/mandrill_32.png", &setup.fBitmap1);
117*c8dee2aaSAndroid Build Coastguard Worker bool success2 = ToolUtils::GetResourceAsBitmap("images/mandrill_64.png", &setup.fBitmap2);
118*c8dee2aaSAndroid Build Coastguard Worker if (!success1 || !success2) {
119*c8dee2aaSAndroid Build Coastguard Worker return {};
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy1 = proxyCache->findOrCreateCachedProxy(recorder, setup.fBitmap1,
125*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
126*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker {
129*c8dee2aaSAndroid Build Coastguard Worker // Ensure proxy1's Texture is created (and timestamped) at this time
130*c8dee2aaSAndroid Build Coastguard Worker auto recording = recorder->snap();
131*c8dee2aaSAndroid Build Coastguard Worker context->insertRecording({ recording.get() });
132*c8dee2aaSAndroid Build Coastguard Worker context->submit(SyncToCpu::kYes);
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker
135*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
136*c8dee2aaSAndroid Build Coastguard Worker setup.fTimeBetweenProxyCreation = skgpu::StdSteadyClock::now();
137*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy2 = proxyCache->findOrCreateCachedProxy(recorder, setup.fBitmap2,
140*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
141*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker {
144*c8dee2aaSAndroid Build Coastguard Worker // Ensure proxy2's Texture is created (and timestamped) at this time
145*c8dee2aaSAndroid Build Coastguard Worker auto recording = recorder->snap();
146*c8dee2aaSAndroid Build Coastguard Worker context->insertRecording({ recording.get() });
147*c8dee2aaSAndroid Build Coastguard Worker testContext->syncedSubmit(context);
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
151*c8dee2aaSAndroid Build Coastguard Worker setup.fTimeAfterAllProxyCreation = skgpu::StdSteadyClock::now();
152*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker return setup;
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker // This test exercises the ProxyCache's freeUniquelyHeld method.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest4,r,context,testContext,true,CtsEnforcement::kApiLevel_V)160*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest4,
161*c8dee2aaSAndroid Build Coastguard Worker r,
162*c8dee2aaSAndroid Build Coastguard Worker context,
163*c8dee2aaSAndroid Build Coastguard Worker testContext,
164*c8dee2aaSAndroid Build Coastguard Worker true,
165*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
166*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
167*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
170*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
171*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
172*c8dee2aaSAndroid Build Coastguard Worker return;
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceFreeUniquelyHeld();
176*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy1.reset();
179*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceFreeUniquelyHeld();
180*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy2.reset();
183*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceFreeUniquelyHeld();
184*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker // This test exercises the ProxyCache's purgeProxiesNotUsedSince method.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest5,r,context,testContext,true,CtsEnforcement::kApiLevel_V)188*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest5,
189*c8dee2aaSAndroid Build Coastguard Worker r,
190*c8dee2aaSAndroid Build Coastguard Worker context,
191*c8dee2aaSAndroid Build Coastguard Worker testContext,
192*c8dee2aaSAndroid Build Coastguard Worker true,
193*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
194*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
195*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
196*c8dee2aaSAndroid Build Coastguard Worker
197*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
198*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
199*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
200*c8dee2aaSAndroid Build Coastguard Worker return;
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(setup.fTimeBetweenProxyCreation);
204*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
205*c8dee2aaSAndroid Build Coastguard Worker
206*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> test = proxyCache->find(setup.fBitmap1);
207*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, !test); // proxy1 should've been purged
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(setup.fTimeAfterAllProxyCreation);
210*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker
213*c8dee2aaSAndroid Build Coastguard Worker // This test simply verifies that the ProxyCache is correctly updating the Resource's
214*c8dee2aaSAndroid Build Coastguard Worker // last access time stamp.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest6,r,context,testContext,true,CtsEnforcement::kApiLevel_V)215*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest6,
216*c8dee2aaSAndroid Build Coastguard Worker r,
217*c8dee2aaSAndroid Build Coastguard Worker context,
218*c8dee2aaSAndroid Build Coastguard Worker testContext,
219*c8dee2aaSAndroid Build Coastguard Worker true,
220*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
221*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
222*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
225*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
226*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
227*c8dee2aaSAndroid Build Coastguard Worker return;
228*c8dee2aaSAndroid Build Coastguard Worker }
229*c8dee2aaSAndroid Build Coastguard Worker
230*c8dee2aaSAndroid Build Coastguard Worker // update proxy1's timestamp
231*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> test = proxyCache->findOrCreateCachedProxy(recorder.get(), setup.fBitmap1,
232*c8dee2aaSAndroid Build Coastguard Worker "ProxyCacheTestTexture");
233*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, test == setup.fProxy1);
234*c8dee2aaSAndroid Build Coastguard Worker
235*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
236*c8dee2aaSAndroid Build Coastguard Worker auto timeAfterProxy1Update = skgpu::StdSteadyClock::now();
237*c8dee2aaSAndroid Build Coastguard Worker
238*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(setup.fTimeBetweenProxyCreation);
239*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(setup.fTimeAfterAllProxyCreation);
242*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
243*c8dee2aaSAndroid Build Coastguard Worker
244*c8dee2aaSAndroid Build Coastguard Worker test = proxyCache->find(setup.fBitmap2);
245*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, !test); // proxy2 should've been purged
246*c8dee2aaSAndroid Build Coastguard Worker
247*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(timeAfterProxy1Update);
248*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
249*c8dee2aaSAndroid Build Coastguard Worker }
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker // Verify that the ProxyCache's purgeProxiesNotUsedSince method can clear out multiple proxies.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest7,r,context,testContext,true,CtsEnforcement::kApiLevel_V)252*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest7,
253*c8dee2aaSAndroid Build Coastguard Worker r,
254*c8dee2aaSAndroid Build Coastguard Worker context,
255*c8dee2aaSAndroid Build Coastguard Worker testContext,
256*c8dee2aaSAndroid Build Coastguard Worker true,
257*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
258*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
259*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
262*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
263*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
264*c8dee2aaSAndroid Build Coastguard Worker return;
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forcePurgeProxiesNotUsedSince(setup.fTimeAfterAllProxyCreation);
268*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
269*c8dee2aaSAndroid Build Coastguard Worker }
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker // Verify that the ProxyCache's freeUniquelyHeld behavior is working in the ResourceCache.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest8,r,context,testContext,true,CtsEnforcement::kApiLevel_V)272*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest8,
273*c8dee2aaSAndroid Build Coastguard Worker r,
274*c8dee2aaSAndroid Build Coastguard Worker context,
275*c8dee2aaSAndroid Build Coastguard Worker testContext,
276*c8dee2aaSAndroid Build Coastguard Worker true,
277*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
278*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
279*c8dee2aaSAndroid Build Coastguard Worker ResourceCache* resourceCache = recorder->priv().resourceCache();
280*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker resourceCache->setMaxBudget(0);
283*c8dee2aaSAndroid Build Coastguard Worker
284*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
285*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
286*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
287*c8dee2aaSAndroid Build Coastguard Worker return;
288*c8dee2aaSAndroid Build Coastguard Worker }
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker resourceCache->forcePurgeAsNeeded();
291*c8dee2aaSAndroid Build Coastguard Worker
292*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
293*c8dee2aaSAndroid Build Coastguard Worker
294*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy1.reset();
295*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceProcessInvalidKeyMsgs();
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker // unreffing fProxy1 and forcing message processing shouldn't purge proxy1 from the cache
298*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> test = proxyCache->find(setup.fBitmap1);
299*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, test);
300*c8dee2aaSAndroid Build Coastguard Worker test.reset();
301*c8dee2aaSAndroid Build Coastguard Worker
302*c8dee2aaSAndroid Build Coastguard Worker resourceCache->forcePurgeAsNeeded();
303*c8dee2aaSAndroid Build Coastguard Worker
304*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 1);
305*c8dee2aaSAndroid Build Coastguard Worker test = proxyCache->find(setup.fBitmap1);
306*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, !test); // proxy1 should've been purged
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy2.reset();
309*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceProcessInvalidKeyMsgs();
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker // unreffing fProxy2 and forcing message processing shouldn't purge proxy2 from the cache
312*c8dee2aaSAndroid Build Coastguard Worker test = proxyCache->find(setup.fBitmap2);
313*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, test);
314*c8dee2aaSAndroid Build Coastguard Worker test.reset();
315*c8dee2aaSAndroid Build Coastguard Worker
316*c8dee2aaSAndroid Build Coastguard Worker resourceCache->forcePurgeAsNeeded();
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker // Verify that the ProxyCache's purgeProxiesNotUsedSince behavior is working when triggered from
322*c8dee2aaSAndroid Build Coastguard Worker // ResourceCache.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest9,r,context,testContext,true,CtsEnforcement::kApiLevel_V)323*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest9,
324*c8dee2aaSAndroid Build Coastguard Worker r,
325*c8dee2aaSAndroid Build Coastguard Worker context,
326*c8dee2aaSAndroid Build Coastguard Worker testContext,
327*c8dee2aaSAndroid Build Coastguard Worker true,
328*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
329*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
330*c8dee2aaSAndroid Build Coastguard Worker ResourceCache* resourceCache = recorder->priv().resourceCache();
331*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
332*c8dee2aaSAndroid Build Coastguard Worker
333*c8dee2aaSAndroid Build Coastguard Worker ProxyCacheSetup setup = setup_test(context, testContext, recorder.get(), r);
334*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.valid());
335*c8dee2aaSAndroid Build Coastguard Worker if (!setup.valid()) {
336*c8dee2aaSAndroid Build Coastguard Worker return;
337*c8dee2aaSAndroid Build Coastguard Worker }
338*c8dee2aaSAndroid Build Coastguard Worker
339*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.fProxy1->isInstantiated());
340*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, setup.fProxy2->isInstantiated());
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker if (!setup.fProxy1->texture() || !setup.fProxy2->texture()) {
343*c8dee2aaSAndroid Build Coastguard Worker return;
344*c8dee2aaSAndroid Build Coastguard Worker }
345*c8dee2aaSAndroid Build Coastguard Worker
346*c8dee2aaSAndroid Build Coastguard Worker // Clear out resources used to setup bitmap proxies so we can track things easier.
347*c8dee2aaSAndroid Build Coastguard Worker resourceCache->setMaxBudget(0);
348*c8dee2aaSAndroid Build Coastguard Worker resourceCache->setMaxBudget(256 * (1 << 20));
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
351*c8dee2aaSAndroid Build Coastguard Worker int baselineResourceCount = resourceCache->getResourceCount();
352*c8dee2aaSAndroid Build Coastguard Worker // When buffer maps are async it can take extra time for buffers to be returned to the cache.
353*c8dee2aaSAndroid Build Coastguard Worker if (context->priv().caps()->bufferMapsAreAsync()) {
354*c8dee2aaSAndroid Build Coastguard Worker // We expect at least 2 textures (and possibly buffers).
355*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, baselineResourceCount >= 2);
356*c8dee2aaSAndroid Build Coastguard Worker } else {
357*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, baselineResourceCount == 2);
358*c8dee2aaSAndroid Build Coastguard Worker }
359*c8dee2aaSAndroid Build Coastguard Worker // Force a command buffer ref on the second proxy in the cache so it can't be purged immediately
360*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy2->texture()->refCommandBuffer();
361*c8dee2aaSAndroid Build Coastguard Worker
362*c8dee2aaSAndroid Build Coastguard Worker Resource* proxy1ResourcePtr = setup.fProxy1->texture();
363*c8dee2aaSAndroid Build Coastguard Worker Resource* proxy2ResourcePtr = setup.fProxy2->texture();
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy1.reset();
366*c8dee2aaSAndroid Build Coastguard Worker setup.fProxy2.reset();
367*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(2));
370*c8dee2aaSAndroid Build Coastguard Worker auto timeAfterProxyCreation = skgpu::StdSteadyClock::now();
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker // This should trigger both proxies to be purged from the ProxyCache. Neither proxy should be
373*c8dee2aaSAndroid Build Coastguard Worker // released from the ResourceCache since their timestamp gets reset when returned to the
374*c8dee2aaSAndroid Build Coastguard Worker // ResourceCache. However, the first proxy should be purgeable and the second not since it still
375*c8dee2aaSAndroid Build Coastguard Worker // has a command buffer ref.
376*c8dee2aaSAndroid Build Coastguard Worker resourceCache->purgeResourcesNotUsedSince(timeAfterProxyCreation);
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
379*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, resourceCache->getResourceCount() == baselineResourceCount);
380*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, resourceCache->topOfPurgeableQueue() == proxy1ResourcePtr);
381*c8dee2aaSAndroid Build Coastguard Worker
382*c8dee2aaSAndroid Build Coastguard Worker // Removing the command buffer ref and returning proxy2Resource to the cache should cause it to
383*c8dee2aaSAndroid Build Coastguard Worker // become purgeable.
384*c8dee2aaSAndroid Build Coastguard Worker proxy2ResourcePtr->unrefCommandBuffer();
385*c8dee2aaSAndroid Build Coastguard Worker resourceCache->forceProcessReturnedResources();
386*c8dee2aaSAndroid Build Coastguard Worker
387*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
388*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, resourceCache->getResourceCount() == baselineResourceCount);
389*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, resourceCache->topOfPurgeableQueue() == proxy1ResourcePtr);
390*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, resourceCache->testingInPurgeableQueue(proxy2ResourcePtr));
391*c8dee2aaSAndroid Build Coastguard Worker }
392*c8dee2aaSAndroid Build Coastguard Worker
find_or_create_by_key(Recorder * recorder,int id,bool * regenerated)393*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<TextureProxy> find_or_create_by_key(Recorder* recorder, int id, bool* regenerated) {
394*c8dee2aaSAndroid Build Coastguard Worker *regenerated = false;
395*c8dee2aaSAndroid Build Coastguard Worker
396*c8dee2aaSAndroid Build Coastguard Worker skgpu::UniqueKey key;
397*c8dee2aaSAndroid Build Coastguard Worker {
398*c8dee2aaSAndroid Build Coastguard Worker static const skgpu::UniqueKey::Domain kTestDomain = UniqueKey::GenerateDomain();
399*c8dee2aaSAndroid Build Coastguard Worker UniqueKey::Builder builder(&key, kTestDomain, 1, "TestExplicitKey");
400*c8dee2aaSAndroid Build Coastguard Worker builder[0] = id;
401*c8dee2aaSAndroid Build Coastguard Worker }
402*c8dee2aaSAndroid Build Coastguard Worker
403*c8dee2aaSAndroid Build Coastguard Worker struct Context {
404*c8dee2aaSAndroid Build Coastguard Worker int id;
405*c8dee2aaSAndroid Build Coastguard Worker bool* regenerated;
406*c8dee2aaSAndroid Build Coastguard Worker } params { id, regenerated };
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker return recorder->priv().proxyCache()->findOrCreateCachedProxy(
409*c8dee2aaSAndroid Build Coastguard Worker recorder, key, ¶ms,
410*c8dee2aaSAndroid Build Coastguard Worker [](const void* context) {
411*c8dee2aaSAndroid Build Coastguard Worker const Context* params = static_cast<const Context*>(context);
412*c8dee2aaSAndroid Build Coastguard Worker *params->regenerated = true;
413*c8dee2aaSAndroid Build Coastguard Worker
414*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bm;
415*c8dee2aaSAndroid Build Coastguard Worker if (params->id == 1) {
416*c8dee2aaSAndroid Build Coastguard Worker if (!ToolUtils::GetResourceAsBitmap("images/mandrill_32.png", &bm)) {
417*c8dee2aaSAndroid Build Coastguard Worker return SkBitmap();
418*c8dee2aaSAndroid Build Coastguard Worker }
419*c8dee2aaSAndroid Build Coastguard Worker } else if (!ToolUtils::GetResourceAsBitmap("images/mandrill_64.png", &bm)) {
420*c8dee2aaSAndroid Build Coastguard Worker return SkBitmap();
421*c8dee2aaSAndroid Build Coastguard Worker }
422*c8dee2aaSAndroid Build Coastguard Worker return bm;
423*c8dee2aaSAndroid Build Coastguard Worker });
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker
426*c8dee2aaSAndroid Build Coastguard Worker // Verify that the ProxyCache's explicit keying only generates the bitmaps as needed.
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest10,r,context,testContext,true,CtsEnforcement::kApiLevel_V)427*c8dee2aaSAndroid Build Coastguard Worker DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ProxyCacheTest10,
428*c8dee2aaSAndroid Build Coastguard Worker r,
429*c8dee2aaSAndroid Build Coastguard Worker context,
430*c8dee2aaSAndroid Build Coastguard Worker testContext,
431*c8dee2aaSAndroid Build Coastguard Worker true,
432*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_V) {
433*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> recorder = context->makeRecorder();
434*c8dee2aaSAndroid Build Coastguard Worker ProxyCache* proxyCache = recorder->priv().proxyCache();
435*c8dee2aaSAndroid Build Coastguard Worker
436*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
437*c8dee2aaSAndroid Build Coastguard Worker
438*c8dee2aaSAndroid Build Coastguard Worker bool regenerated;
439*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy1 = find_or_create_by_key(recorder.get(), 1, ®enerated);
440*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxy1 && proxy1->dimensions().width() == 32);
441*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, regenerated);
442*c8dee2aaSAndroid Build Coastguard Worker
443*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy2 = find_or_create_by_key(recorder.get(), 2, ®enerated);
444*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxy2 && proxy2->dimensions().width() == 64);
445*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, regenerated);
446*c8dee2aaSAndroid Build Coastguard Worker
447*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
448*c8dee2aaSAndroid Build Coastguard Worker
449*c8dee2aaSAndroid Build Coastguard Worker // These cached proxies shouldn't be deleted because we hold local refs still
450*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceFreeUniquelyHeld();
451*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 2);
452*c8dee2aaSAndroid Build Coastguard Worker
453*c8dee2aaSAndroid Build Coastguard Worker // Cache hit should not invoke the bitmap generation function.
454*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TextureProxy> proxy1b = find_or_create_by_key(recorder.get(), 1, ®enerated);
455*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxy1.get() == proxy1b.get());
456*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, !regenerated);
457*c8dee2aaSAndroid Build Coastguard Worker
458*c8dee2aaSAndroid Build Coastguard Worker proxy1.reset();
459*c8dee2aaSAndroid Build Coastguard Worker proxy1b.reset();
460*c8dee2aaSAndroid Build Coastguard Worker proxy2.reset();
461*c8dee2aaSAndroid Build Coastguard Worker (void) recorder->snap(); // Dump pending commands to release internal refs to the cached proxies
462*c8dee2aaSAndroid Build Coastguard Worker
463*c8dee2aaSAndroid Build Coastguard Worker // Now the cache should clean the cache entries up
464*c8dee2aaSAndroid Build Coastguard Worker proxyCache->forceFreeUniquelyHeld();
465*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxyCache->numCached() == 0);
466*c8dee2aaSAndroid Build Coastguard Worker
467*c8dee2aaSAndroid Build Coastguard Worker // And regeneration functions as expected
468*c8dee2aaSAndroid Build Coastguard Worker proxy1 = find_or_create_by_key(recorder.get(), 1, ®enerated);
469*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, proxy1 && proxy1->dimensions().width() == 32);
470*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(r, regenerated);
471*c8dee2aaSAndroid Build Coastguard Worker }
472*c8dee2aaSAndroid Build Coastguard Worker
473*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
474