xref: /aosp_15_r20/external/skia/tests/graphite/precompile/ThreadedPrecompileTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2024 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 #if defined(SK_GRAPHITE)
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextBlob.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/PrecompileContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Surface.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PaintOptions.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/Precompile.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/precompile/PrecompileShader.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextPriv.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipelineDesc.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RenderPassDesc.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "tools/graphite/UniqueKeyUtils.h"
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker #include <thread>
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker using namespace::skgpu::graphite;
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker namespace {
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kMaxNumStops = 9;
35*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor gColors[kMaxNumStops] = {
36*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorRED,
37*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorGREEN,
38*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorBLUE,
39*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorCYAN,
40*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorMAGENTA,
41*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorYELLOW,
42*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorBLACK,
43*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorDKGRAY,
44*c8dee2aaSAndroid Build Coastguard Worker         SK_ColorLTGRAY,
45*c8dee2aaSAndroid Build Coastguard Worker };
46*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint gPts[kMaxNumStops] = {
47*c8dee2aaSAndroid Build Coastguard Worker         { -100.0f, -100.0f },
48*c8dee2aaSAndroid Build Coastguard Worker         { -50.0f, -50.0f },
49*c8dee2aaSAndroid Build Coastguard Worker         { -25.0f, -25.0f },
50*c8dee2aaSAndroid Build Coastguard Worker         { -12.5f, -12.5f },
51*c8dee2aaSAndroid Build Coastguard Worker         { 0.0f, 0.0f },
52*c8dee2aaSAndroid Build Coastguard Worker         { 12.5f, 12.5f },
53*c8dee2aaSAndroid Build Coastguard Worker         { 25.0f, 25.0f },
54*c8dee2aaSAndroid Build Coastguard Worker         { 50.0f, 50.0f },
55*c8dee2aaSAndroid Build Coastguard Worker         { 100.0f, 100.0f }
56*c8dee2aaSAndroid Build Coastguard Worker };
57*c8dee2aaSAndroid Build Coastguard Worker static constexpr float gOffsets[kMaxNumStops] =
58*c8dee2aaSAndroid Build Coastguard Worker             { 0.0f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, 1.0f };
59*c8dee2aaSAndroid Build Coastguard Worker 
linear(int numStops)60*c8dee2aaSAndroid Build Coastguard Worker std::pair<SkPaint, PaintOptions> linear(int numStops) {
61*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(numStops <= kMaxNumStops);
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     PaintOptions paintOptions;
64*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setShaders({ PrecompileShaders::LinearGradient() });
65*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
68*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(SkGradientShader::MakeLinear(gPts,
69*c8dee2aaSAndroid Build Coastguard Worker                                                  gColors, gOffsets, numStops,
70*c8dee2aaSAndroid Build Coastguard Worker                                                  SkTileMode::kClamp));
71*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kSrcOver);
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker     return { paint, paintOptions };
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker 
radial(int numStops)76*c8dee2aaSAndroid Build Coastguard Worker std::pair<SkPaint, PaintOptions> radial(int numStops) {
77*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(numStops <= kMaxNumStops);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker     PaintOptions paintOptions;
80*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setShaders({ PrecompileShaders::RadialGradient() });
81*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
84*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(SkGradientShader::MakeRadial(/* center= */ {0, 0}, /* radius= */ 100,
85*c8dee2aaSAndroid Build Coastguard Worker                                                  gColors, gOffsets, numStops,
86*c8dee2aaSAndroid Build Coastguard Worker                                                  SkTileMode::kClamp));
87*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kSrcOver);
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker     return { paint, paintOptions };
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker 
sweep(int numStops)92*c8dee2aaSAndroid Build Coastguard Worker std::pair<SkPaint, PaintOptions> sweep(int numStops) {
93*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(numStops <= kMaxNumStops);
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker     PaintOptions paintOptions;
96*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setShaders({ PrecompileShaders::SweepGradient() });
97*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
100*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(SkGradientShader::MakeSweep(/* cx= */ 0, /* cy= */ 0,
101*c8dee2aaSAndroid Build Coastguard Worker                                                 gColors, gOffsets, numStops,
102*c8dee2aaSAndroid Build Coastguard Worker                                                 SkTileMode::kClamp,
103*c8dee2aaSAndroid Build Coastguard Worker                                                 /* startAngle= */ 0, /* endAngle= */ 359,
104*c8dee2aaSAndroid Build Coastguard Worker                                                 /* flags= */ 0, /* localMatrix= */ nullptr));
105*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kSrcOver);
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     return { paint, paintOptions };
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker 
conical(int numStops)110*c8dee2aaSAndroid Build Coastguard Worker std::pair<SkPaint, PaintOptions> conical(int numStops) {
111*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(numStops <= kMaxNumStops);
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     PaintOptions paintOptions;
114*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setShaders({ PrecompileShaders::TwoPointConicalGradient() });
115*c8dee2aaSAndroid Build Coastguard Worker     paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
118*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(SkGradientShader::MakeTwoPointConical(/* start= */ {100, 100},
119*c8dee2aaSAndroid Build Coastguard Worker                                                           /* startRadius= */ 100,
120*c8dee2aaSAndroid Build Coastguard Worker                                                           /* end= */ {-100, -100},
121*c8dee2aaSAndroid Build Coastguard Worker                                                           /* endRadius= */ 100,
122*c8dee2aaSAndroid Build Coastguard Worker                                                           gColors, gOffsets, numStops,
123*c8dee2aaSAndroid Build Coastguard Worker                                                           SkTileMode::kClamp));
124*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kSrcOver);
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     return { paint, paintOptions };
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker 
precompile_gradients(std::unique_ptr<PrecompileContext> precompileContext,skiatest::Reporter *,int)129*c8dee2aaSAndroid Build Coastguard Worker void precompile_gradients(std::unique_ptr<PrecompileContext> precompileContext,
130*c8dee2aaSAndroid Build Coastguard Worker                           skiatest::Reporter* /* reporter */,
131*c8dee2aaSAndroid Build Coastguard Worker                           int /* threadID */) {
132*c8dee2aaSAndroid Build Coastguard Worker     constexpr RenderPassProperties kProps = { DepthStencilFlags::kDepth,
133*c8dee2aaSAndroid Build Coastguard Worker                                               kBGRA_8888_SkColorType,
134*c8dee2aaSAndroid Build Coastguard Worker                                               /* requiresMSAA= */ false };
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker     for (auto createOptionsMtd : { linear, radial, sweep, conical }) {
137*c8dee2aaSAndroid Build Coastguard Worker         // numStops doesn't influence the paintOptions
138*c8dee2aaSAndroid Build Coastguard Worker         auto [_, paintOptions] = createOptionsMtd(/* numStops= */ 2);
139*c8dee2aaSAndroid Build Coastguard Worker         Precompile(precompileContext.get(),
140*c8dee2aaSAndroid Build Coastguard Worker                    paintOptions,
141*c8dee2aaSAndroid Build Coastguard Worker                    DrawTypeFlags::kBitmapText_Mask,
142*c8dee2aaSAndroid Build Coastguard Worker                    { &kProps, 1 });
143*c8dee2aaSAndroid Build Coastguard Worker     }
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     precompileContext.reset();
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker // A simple helper to call Context::insertRecording on the Recordings generated on the
149*c8dee2aaSAndroid Build Coastguard Worker // recorder threads. It collects (and keeps ownership) of all the generated Recordings.
150*c8dee2aaSAndroid Build Coastguard Worker class Listener : public SkRefCnt {
151*c8dee2aaSAndroid Build Coastguard Worker public:
Listener(int numSenders)152*c8dee2aaSAndroid Build Coastguard Worker     Listener(int numSenders) : fNumActiveSenders(numSenders) {}
153*c8dee2aaSAndroid Build Coastguard Worker 
addRecording(std::unique_ptr<Recording> recording)154*c8dee2aaSAndroid Build Coastguard Worker     void addRecording(std::unique_ptr<Recording> recording) SK_EXCLUDES(fLock) {
155*c8dee2aaSAndroid Build Coastguard Worker         {
156*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive lock(fLock);
157*c8dee2aaSAndroid Build Coastguard Worker             fRecordings.push_back(std::move(recording));
158*c8dee2aaSAndroid Build Coastguard Worker         }
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker         fWorkAvailable.signal(1);
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker 
deregister()163*c8dee2aaSAndroid Build Coastguard Worker     void deregister() SK_EXCLUDES(fLock) {
164*c8dee2aaSAndroid Build Coastguard Worker         {
165*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive lock(fLock);
166*c8dee2aaSAndroid Build Coastguard Worker             fNumActiveSenders--;
167*c8dee2aaSAndroid Build Coastguard Worker         }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker         fWorkAvailable.signal(1);
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker 
insertRecordings(Context * context)172*c8dee2aaSAndroid Build Coastguard Worker     void insertRecordings(Context* context) {
173*c8dee2aaSAndroid Build Coastguard Worker         do {
174*c8dee2aaSAndroid Build Coastguard Worker             fWorkAvailable.wait();
175*c8dee2aaSAndroid Build Coastguard Worker         } while (this->insertRecording(context));
176*c8dee2aaSAndroid Build Coastguard Worker     }
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker private:
179*c8dee2aaSAndroid Build Coastguard Worker     // This entry point is run in a loop waiting on the 'fWorkAvailable' semaphore until there
180*c8dee2aaSAndroid Build Coastguard Worker     // are no senders remaining (at which point it returns false) c.f. 'insertRecordings'.
insertRecording(Context * context)181*c8dee2aaSAndroid Build Coastguard Worker     bool insertRecording(Context* context) SK_EXCLUDES(fLock) {
182*c8dee2aaSAndroid Build Coastguard Worker         Recording* recording = nullptr;
183*c8dee2aaSAndroid Build Coastguard Worker         int numSendersLeft;
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker         {
186*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive lock(fLock);
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker             numSendersLeft = fNumActiveSenders;
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fRecordings.size() >= fCurHandled);
191*c8dee2aaSAndroid Build Coastguard Worker             if (fRecordings.size() > fCurHandled) {
192*c8dee2aaSAndroid Build Coastguard Worker                 recording = fRecordings[fCurHandled++].get();
193*c8dee2aaSAndroid Build Coastguard Worker             }
194*c8dee2aaSAndroid Build Coastguard Worker         }
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker         if (recording) {
197*c8dee2aaSAndroid Build Coastguard Worker             context->insertRecording({recording});
198*c8dee2aaSAndroid Build Coastguard Worker             return true;  // continue looping
199*c8dee2aaSAndroid Build Coastguard Worker         }
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(numSendersLeft); // continue looping if there are still active senders
202*c8dee2aaSAndroid Build Coastguard Worker     }
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     SkMutex fLock;
205*c8dee2aaSAndroid Build Coastguard Worker     SkSemaphore fWorkAvailable;
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker     skia_private::TArray<std::unique_ptr<Recording>> fRecordings SK_GUARDED_BY(fLock);
208*c8dee2aaSAndroid Build Coastguard Worker     int fCurHandled SK_GUARDED_BY(fLock) = 0;
209*c8dee2aaSAndroid Build Coastguard Worker     int fNumActiveSenders SK_GUARDED_BY(fLock);
210*c8dee2aaSAndroid Build Coastguard Worker };
211*c8dee2aaSAndroid Build Coastguard Worker 
compile_gradients(std::unique_ptr<Recorder> recorder,sk_sp<Listener> listener,skiatest::Reporter *,int)212*c8dee2aaSAndroid Build Coastguard Worker void compile_gradients(std::unique_ptr<Recorder> recorder,
213*c8dee2aaSAndroid Build Coastguard Worker                        sk_sp<Listener> listener,
214*c8dee2aaSAndroid Build Coastguard Worker                        skiatest::Reporter* /* reporter */,
215*c8dee2aaSAndroid Build Coastguard Worker                        int /* threadID */) {
216*c8dee2aaSAndroid Build Coastguard Worker     SkFont font(ToolUtils::DefaultPortableTypeface(), /* size= */ 16);
217*c8dee2aaSAndroid Build Coastguard Worker 
218*c8dee2aaSAndroid Build Coastguard Worker     const char text[] = "hambur1";
219*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText(text, strlen(text), font);
220*c8dee2aaSAndroid Build Coastguard Worker 
221*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo ii = SkImageInfo::Make(16, 16,
222*c8dee2aaSAndroid Build Coastguard Worker                                        kBGRA_8888_SkColorType,
223*c8dee2aaSAndroid Build Coastguard Worker                                        kPremul_SkAlphaType);
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder.get(), ii,
226*c8dee2aaSAndroid Build Coastguard Worker                                                      skgpu::Mipmapped::kNo,
227*c8dee2aaSAndroid Build Coastguard Worker                                                      /* surfaceProps= */ nullptr);
228*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surf->getCanvas();
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker     for (auto createOptionsMtd : { linear, radial, sweep, conical }) {
231*c8dee2aaSAndroid Build Coastguard Worker         for (int numStops : { 2, 7, kMaxNumStops }) {
232*c8dee2aaSAndroid Build Coastguard Worker             auto [paint, _] = createOptionsMtd(numStops);
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawTextBlob(blob, 0, 16, paint);
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker             // This will trigger pipeline creation via TaskList::prepareResources
237*c8dee2aaSAndroid Build Coastguard Worker             std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker             listener->addRecording(std::move(recording));
240*c8dee2aaSAndroid Build Coastguard Worker         }
241*c8dee2aaSAndroid Build Coastguard Worker     }
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker     listener->deregister();
244*c8dee2aaSAndroid Build Coastguard Worker }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
247*c8dee2aaSAndroid Build Coastguard Worker 
248*c8dee2aaSAndroid Build Coastguard Worker // This test precompiles all four flavors of gradient sequentially but on multiple
249*c8dee2aaSAndroid Build Coastguard Worker // threads with the goal of creating cache races.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ThreadedPrecompileTest,reporter,context,CtsEnforcement::kNever)250*c8dee2aaSAndroid Build Coastguard Worker DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ThreadedPrecompileTest,
251*c8dee2aaSAndroid Build Coastguard Worker                                    reporter,
252*c8dee2aaSAndroid Build Coastguard Worker                                    context,
253*c8dee2aaSAndroid Build Coastguard Worker                                    CtsEnforcement::kNever) {
254*c8dee2aaSAndroid Build Coastguard Worker     constexpr int kNumThreads = 4;
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker     std::thread threads[kNumThreads];
258*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kNumThreads; ++i) {
259*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker         threads[i] = std::thread(precompile_gradients, std::move(precompileContext), reporter, i);
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker     for (auto& thread : threads) {
265*c8dee2aaSAndroid Build Coastguard Worker         thread.join();
266*c8dee2aaSAndroid Build Coastguard Worker     }
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker     const GlobalCache::PipelineStats stats = context->priv().globalCache()->getStats();
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker     // Four types of gradient times three combinations (i.e., 4,8,N) for each one.
271*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsCacheAdditions == 12);
272*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsRaces > 0);
273*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsCacheMisses ==
274*c8dee2aaSAndroid Build Coastguard Worker                               stats.fGraphicsCacheAdditions + stats.fGraphicsRaces);
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker // This test runs two threads compiling the gradient flavours and two threads
278*c8dee2aaSAndroid Build Coastguard Worker // pre-compiling the gradient flavors. This is to exercise the tracking of the
279*c8dee2aaSAndroid Build Coastguard Worker // various race combinations (i.e., Normal vs Precompile, Normal vs. Normal, etc.).
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ThreadedCompilePrecompileTest,reporter,context,CtsEnforcement::kNever)280*c8dee2aaSAndroid Build Coastguard Worker DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ThreadedCompilePrecompileTest,
281*c8dee2aaSAndroid Build Coastguard Worker                                    reporter,
282*c8dee2aaSAndroid Build Coastguard Worker                                    context,
283*c8dee2aaSAndroid Build Coastguard Worker                                    CtsEnforcement::kNever) {
284*c8dee2aaSAndroid Build Coastguard Worker     constexpr int kNumRecordingThreads = 2;
285*c8dee2aaSAndroid Build Coastguard Worker     constexpr int kNumPrecompileThreads = 2;
286*c8dee2aaSAndroid Build Coastguard Worker     constexpr int kTotNumThreads = kNumRecordingThreads + kNumPrecompileThreads;
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<Listener> listener = sk_make_sp<Listener>(kNumRecordingThreads);
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker     std::thread threads[kTotNumThreads];
291*c8dee2aaSAndroid Build Coastguard Worker 
292*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kNumRecordingThreads; ++i) {
293*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<Recorder> recorder = context->makeRecorder();
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker         threads[i] = std::thread(compile_gradients,
296*c8dee2aaSAndroid Build Coastguard Worker                                  std::move(recorder),
297*c8dee2aaSAndroid Build Coastguard Worker                                  listener,
298*c8dee2aaSAndroid Build Coastguard Worker                                  reporter,
299*c8dee2aaSAndroid Build Coastguard Worker                                  i);
300*c8dee2aaSAndroid Build Coastguard Worker     }
301*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kNumPrecompileThreads; ++i) {
302*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker         int threadID = kNumRecordingThreads+i;
305*c8dee2aaSAndroid Build Coastguard Worker         threads[kNumRecordingThreads+i] = std::thread(precompile_gradients,
306*c8dee2aaSAndroid Build Coastguard Worker                                                       std::move(precompileContext),
307*c8dee2aaSAndroid Build Coastguard Worker                                                       reporter,
308*c8dee2aaSAndroid Build Coastguard Worker                                                       threadID);
309*c8dee2aaSAndroid Build Coastguard Worker     }
310*c8dee2aaSAndroid Build Coastguard Worker 
311*c8dee2aaSAndroid Build Coastguard Worker     // Process the work generated by the recording threads
312*c8dee2aaSAndroid Build Coastguard Worker     listener->insertRecordings(context);
313*c8dee2aaSAndroid Build Coastguard Worker 
314*c8dee2aaSAndroid Build Coastguard Worker     for (auto& thread : threads) {
315*c8dee2aaSAndroid Build Coastguard Worker         if (thread.joinable()) {
316*c8dee2aaSAndroid Build Coastguard Worker             thread.join();
317*c8dee2aaSAndroid Build Coastguard Worker         }
318*c8dee2aaSAndroid Build Coastguard Worker     }
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker     context->submit(SyncToCpu::kYes);
321*c8dee2aaSAndroid Build Coastguard Worker 
322*c8dee2aaSAndroid Build Coastguard Worker     const GlobalCache::PipelineStats stats = context->priv().globalCache()->getStats();
323*c8dee2aaSAndroid Build Coastguard Worker 
324*c8dee2aaSAndroid Build Coastguard Worker     // Four types of gradient times three combinations (i.e., 4,8,N) for each one.
325*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsCacheAdditions == 12);
326*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsRaces > 0);
327*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsCacheMisses ==
328*c8dee2aaSAndroid Build Coastguard Worker                               stats.fGraphicsCacheAdditions + stats.fGraphicsRaces);
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker     // The 48 comes from:
331*c8dee2aaSAndroid Build Coastguard Worker     //     4 gradient flavors (linear, radial, ...) *
332*c8dee2aaSAndroid Build Coastguard Worker     //     3 types of each flavor (4, 8, N) *
333*c8dee2aaSAndroid Build Coastguard Worker     //     4 threads (2 normal-compile + 2 pre-compile)
334*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stats.fGraphicsCacheHits + stats.fGraphicsCacheMisses == 48);
335*c8dee2aaSAndroid Build Coastguard Worker }
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_GRAPHITE
338