xref: /aosp_15_r20/external/skia/src/gpu/graphite/Context.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 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 "include/gpu/graphite/Context.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTraceMemoryDump.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/BackendTexture.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/PrecompileContext.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recorder.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Recording.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Surface.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/TextureInfo.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRectMemcpy.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkAutoPixmapStorage.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkColorFilterPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkConvertPixels.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkYUVMath.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/RefCntedCallback.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/AtlasProvider.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/BufferManager.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Caps.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ClientMappedBufferManager.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/CommandBuffer.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextPriv.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/DrawAtlas.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GlobalCache.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipeline.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphicsPipelineDesc.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Image_Base_Graphite.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Image_Graphite.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyContext.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/QueueManager.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecordingPriv.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Renderer.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RendererProvider.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceProvider.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RuntimeEffectDictionary.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ShaderCodeDictionary.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/SharedContext.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Surface_Graphite.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureProxyView.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/TextureUtils.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/CopyTask.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/SynchronizeToCpuTask.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/task/UploadTask.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkSurface_Base.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLGraphiteModules.h"
59*c8dee2aaSAndroid Build Coastguard Worker 
60*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
61*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextOptionsPriv.h"
62*c8dee2aaSAndroid Build Coastguard Worker #endif
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())
67*c8dee2aaSAndroid Build Coastguard Worker 
Next()68*c8dee2aaSAndroid Build Coastguard Worker Context::ContextID Context::ContextID::Next() {
69*c8dee2aaSAndroid Build Coastguard Worker     static std::atomic<uint32_t> nextID{1};
70*c8dee2aaSAndroid Build Coastguard Worker     uint32_t id;
71*c8dee2aaSAndroid Build Coastguard Worker     do {
72*c8dee2aaSAndroid Build Coastguard Worker         id = nextID.fetch_add(1, std::memory_order_relaxed);
73*c8dee2aaSAndroid Build Coastguard Worker     } while (id == SK_InvalidUniqueID);
74*c8dee2aaSAndroid Build Coastguard Worker     return ContextID(id);
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker //--------------------------------------------------------------------------------------------------
Context(sk_sp<SharedContext> sharedContext,std::unique_ptr<QueueManager> queueManager,const ContextOptions & options)78*c8dee2aaSAndroid Build Coastguard Worker Context::Context(sk_sp<SharedContext> sharedContext,
79*c8dee2aaSAndroid Build Coastguard Worker                  std::unique_ptr<QueueManager> queueManager,
80*c8dee2aaSAndroid Build Coastguard Worker                  const ContextOptions& options)
81*c8dee2aaSAndroid Build Coastguard Worker         : fSharedContext(std::move(sharedContext))
82*c8dee2aaSAndroid Build Coastguard Worker         , fQueueManager(std::move(queueManager))
83*c8dee2aaSAndroid Build Coastguard Worker         , fContextID(ContextID::Next()) {
84*c8dee2aaSAndroid Build Coastguard Worker     // We need to move the Graphite SkSL code into the central SkSL data loader at least once
85*c8dee2aaSAndroid Build Coastguard Worker     // (but preferrably only once) before we try to use it. We assume that there's no way to
86*c8dee2aaSAndroid Build Coastguard Worker     // use the SkSL code without making a context, so we initialize it here.
87*c8dee2aaSAndroid Build Coastguard Worker     static SkOnce once;
88*c8dee2aaSAndroid Build Coastguard Worker     once([] { SkSL::Loader::SetGraphiteModuleData(SkSL::Loader::GetGraphiteModules()); });
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker     // We have to create this outside the initializer list because we need to pass in the Context's
91*c8dee2aaSAndroid Build Coastguard Worker     // SingleOwner object and it is declared last
92*c8dee2aaSAndroid Build Coastguard Worker     fResourceProvider = fSharedContext->makeResourceProvider(&fSingleOwner,
93*c8dee2aaSAndroid Build Coastguard Worker                                                              SK_InvalidGenID,
94*c8dee2aaSAndroid Build Coastguard Worker                                                              options.fGpuBudgetInBytes,
95*c8dee2aaSAndroid Build Coastguard Worker                                                              /* avoidBufferAlloc= */ false);
96*c8dee2aaSAndroid Build Coastguard Worker     fMappedBufferManager = std::make_unique<ClientMappedBufferManager>(this->contextID());
97*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
98*c8dee2aaSAndroid Build Coastguard Worker     if (options.fOptionsPriv) {
99*c8dee2aaSAndroid Build Coastguard Worker         fStoreContextRefInRecorder = options.fOptionsPriv->fStoreContextRefInRecorder;
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker #endif
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker 
~Context()104*c8dee2aaSAndroid Build Coastguard Worker Context::~Context() {
105*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
106*c8dee2aaSAndroid Build Coastguard Worker     SkAutoMutexExclusive lock(fTestingLock);
107*c8dee2aaSAndroid Build Coastguard Worker     for (auto& recorder : fTrackedRecorders) {
108*c8dee2aaSAndroid Build Coastguard Worker         recorder->priv().setContext(nullptr);
109*c8dee2aaSAndroid Build Coastguard Worker     }
110*c8dee2aaSAndroid Build Coastguard Worker #endif
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker 
finishInitialization()113*c8dee2aaSAndroid Build Coastguard Worker bool Context::finishInitialization() {
114*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fSharedContext->rendererProvider()); // Can only initialize once
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker     StaticBufferManager bufferManager{fResourceProvider.get(), fSharedContext->caps()};
117*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<RendererProvider> renderers{
118*c8dee2aaSAndroid Build Coastguard Worker             new RendererProvider(fSharedContext->caps(), &bufferManager)};
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker     auto result = bufferManager.finalize(this, fQueueManager.get(), fSharedContext->globalCache());
121*c8dee2aaSAndroid Build Coastguard Worker     if (result == StaticBufferManager::FinishResult::kFailure) {
122*c8dee2aaSAndroid Build Coastguard Worker         // If something went wrong filling out the static vertex buffers, any Renderer that would
123*c8dee2aaSAndroid Build Coastguard Worker         // use it will draw incorrectly, so it's better to fail the Context creation.
124*c8dee2aaSAndroid Build Coastguard Worker         return false;
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker     if (result == StaticBufferManager::FinishResult::kSuccess &&
127*c8dee2aaSAndroid Build Coastguard Worker         !fQueueManager->submitToGpu()) {
128*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("Failed to submit initial command buffer for Context creation.\n");
129*c8dee2aaSAndroid Build Coastguard Worker         return false;
130*c8dee2aaSAndroid Build Coastguard Worker     } // else result was kNoWork so skip submitting to the GPU
131*c8dee2aaSAndroid Build Coastguard Worker     fSharedContext->setRendererProvider(std::move(renderers));
132*c8dee2aaSAndroid Build Coastguard Worker     return true;
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker 
backend() const135*c8dee2aaSAndroid Build Coastguard Worker BackendApi Context::backend() const { return fSharedContext->backend(); }
136*c8dee2aaSAndroid Build Coastguard Worker 
makeRecorder(const RecorderOptions & options)137*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> Context::makeRecorder(const RecorderOptions& options) {
138*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker     // This is a client-owned Recorder so pass a null context so it creates its own ResourceProvider
141*c8dee2aaSAndroid Build Coastguard Worker     auto recorder = std::unique_ptr<Recorder>(new Recorder(fSharedContext, options, nullptr));
142*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
143*c8dee2aaSAndroid Build Coastguard Worker     if (fStoreContextRefInRecorder) {
144*c8dee2aaSAndroid Build Coastguard Worker         recorder->priv().setContext(this);
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker #endif
147*c8dee2aaSAndroid Build Coastguard Worker     return recorder;
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker 
makePrecompileContext()150*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<PrecompileContext> Context::makePrecompileContext() {
151*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker     return std::unique_ptr<PrecompileContext>(new PrecompileContext(fSharedContext));
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker 
makeInternalRecorder() const156*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Recorder> Context::makeInternalRecorder() const {
157*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     // Unlike makeRecorder(), this Recorder is meant to be short-lived and go
160*c8dee2aaSAndroid Build Coastguard Worker     // away before a Context public API function returns to the caller. As such
161*c8dee2aaSAndroid Build Coastguard Worker     // it shares the Context's resource provider (no separate budget) and does
162*c8dee2aaSAndroid Build Coastguard Worker     // not get tracked. The internal drawing performed with an internal recorder
163*c8dee2aaSAndroid Build Coastguard Worker     // should not require a client image provider.
164*c8dee2aaSAndroid Build Coastguard Worker     return std::unique_ptr<Recorder>(new Recorder(fSharedContext, {}, this));
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker 
insertRecording(const InsertRecordingInfo & info)167*c8dee2aaSAndroid Build Coastguard Worker bool Context::insertRecording(const InsertRecordingInfo& info) {
168*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
169*c8dee2aaSAndroid Build Coastguard Worker 
170*c8dee2aaSAndroid Build Coastguard Worker     return fQueueManager->addRecording(info, this);
171*c8dee2aaSAndroid Build Coastguard Worker }
172*c8dee2aaSAndroid Build Coastguard Worker 
submit(SyncToCpu syncToCpu)173*c8dee2aaSAndroid Build Coastguard Worker bool Context::submit(SyncToCpu syncToCpu) {
174*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     if (syncToCpu == SyncToCpu::kYes && !fSharedContext->caps()->allowCpuSync()) {
177*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_E("SyncToCpu::kYes not supported with ContextOptions::fNeverYieldToWebGPU. "
178*c8dee2aaSAndroid Build Coastguard Worker                     "The parameter is ignored and no synchronization will occur.");
179*c8dee2aaSAndroid Build Coastguard Worker         syncToCpu = SyncToCpu::kNo;
180*c8dee2aaSAndroid Build Coastguard Worker     }
181*c8dee2aaSAndroid Build Coastguard Worker     bool success = fQueueManager->submitToGpu();
182*c8dee2aaSAndroid Build Coastguard Worker     this->checkForFinishedWork(syncToCpu);
183*c8dee2aaSAndroid Build Coastguard Worker     return success;
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker 
hasUnfinishedGpuWork() const186*c8dee2aaSAndroid Build Coastguard Worker bool Context::hasUnfinishedGpuWork() const { return fQueueManager->hasUnfinishedGpuWork(); }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker template <typename SrcPixels>
189*c8dee2aaSAndroid Build Coastguard Worker struct Context::AsyncParams {
190*c8dee2aaSAndroid Build Coastguard Worker     const SrcPixels* fSrcImage;
191*c8dee2aaSAndroid Build Coastguard Worker     SkIRect          fSrcRect;
192*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo      fDstImageInfo;
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker     SkImage::ReadPixelsCallback* fCallback;
195*c8dee2aaSAndroid Build Coastguard Worker     SkImage::ReadPixelsContext   fCallbackContext;
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     template <typename S>
withNewSourceskgpu::graphite::Context::AsyncParams198*c8dee2aaSAndroid Build Coastguard Worker     AsyncParams<S> withNewSource(const S* newPixels, const SkIRect& newSrcRect) const {
199*c8dee2aaSAndroid Build Coastguard Worker         return AsyncParams<S>{newPixels, newSrcRect,
200*c8dee2aaSAndroid Build Coastguard Worker                                 fDstImageInfo, fCallback, fCallbackContext};
201*c8dee2aaSAndroid Build Coastguard Worker     }
202*c8dee2aaSAndroid Build Coastguard Worker 
failskgpu::graphite::Context::AsyncParams203*c8dee2aaSAndroid Build Coastguard Worker     void fail() const {
204*c8dee2aaSAndroid Build Coastguard Worker         (*fCallback)(fCallbackContext, nullptr);
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker 
validateskgpu::graphite::Context::AsyncParams207*c8dee2aaSAndroid Build Coastguard Worker     bool validate() const {
208*c8dee2aaSAndroid Build Coastguard Worker         if (!fSrcImage) {
209*c8dee2aaSAndroid Build Coastguard Worker             return false;
210*c8dee2aaSAndroid Build Coastguard Worker         }
211*c8dee2aaSAndroid Build Coastguard Worker         if (fSrcImage->isProtected()) {
212*c8dee2aaSAndroid Build Coastguard Worker             return false;
213*c8dee2aaSAndroid Build Coastguard Worker         }
214*c8dee2aaSAndroid Build Coastguard Worker         if (!SkIRect::MakeSize(fSrcImage->dimensions()).contains(fSrcRect)) {
215*c8dee2aaSAndroid Build Coastguard Worker             return false;
216*c8dee2aaSAndroid Build Coastguard Worker         }
217*c8dee2aaSAndroid Build Coastguard Worker         if (!SkImageInfoIsValid(fDstImageInfo)) {
218*c8dee2aaSAndroid Build Coastguard Worker             return false;
219*c8dee2aaSAndroid Build Coastguard Worker         }
220*c8dee2aaSAndroid Build Coastguard Worker         return true;
221*c8dee2aaSAndroid Build Coastguard Worker     }
222*c8dee2aaSAndroid Build Coastguard Worker };
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker template <typename ReadFn, typename... ExtraArgs>
asyncRescaleAndReadImpl(ReadFn Context::* asyncRead,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,const AsyncParams<SkImage> & params,ExtraArgs...extraParams)225*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadImpl(ReadFn Context::* asyncRead,
226*c8dee2aaSAndroid Build Coastguard Worker                                       SkImage::RescaleGamma rescaleGamma,
227*c8dee2aaSAndroid Build Coastguard Worker                                       SkImage::RescaleMode rescaleMode,
228*c8dee2aaSAndroid Build Coastguard Worker                                       const AsyncParams<SkImage>& params,
229*c8dee2aaSAndroid Build Coastguard Worker                                       ExtraArgs... extraParams) {
230*c8dee2aaSAndroid Build Coastguard Worker     if (!params.validate()) {
231*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
232*c8dee2aaSAndroid Build Coastguard Worker     }
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker     if (params.fSrcRect.size() == params.fDstImageInfo.dimensions()) {
235*c8dee2aaSAndroid Build Coastguard Worker         // No need to rescale so do a direct readback
236*c8dee2aaSAndroid Build Coastguard Worker         return (this->*asyncRead)(/*recorder=*/nullptr, params, extraParams...);
237*c8dee2aaSAndroid Build Coastguard Worker     }
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker     // Make a recorder to collect the rescale drawing commands and the copy commands
240*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<Recorder> recorder = this->makeInternalRecorder();
241*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> scaledImage = RescaleImage(recorder.get(),
242*c8dee2aaSAndroid Build Coastguard Worker                                               params.fSrcImage,
243*c8dee2aaSAndroid Build Coastguard Worker                                               params.fSrcRect,
244*c8dee2aaSAndroid Build Coastguard Worker                                               params.fDstImageInfo,
245*c8dee2aaSAndroid Build Coastguard Worker                                               rescaleGamma,
246*c8dee2aaSAndroid Build Coastguard Worker                                               rescaleMode);
247*c8dee2aaSAndroid Build Coastguard Worker     if (!scaledImage) {
248*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("AsyncRead failed because rescaling failed");
249*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
250*c8dee2aaSAndroid Build Coastguard Worker     }
251*c8dee2aaSAndroid Build Coastguard Worker     (this->*asyncRead)(std::move(recorder),
252*c8dee2aaSAndroid Build Coastguard Worker                        params.withNewSource(scaledImage.get(), params.fDstImageInfo.bounds()),
253*c8dee2aaSAndroid Build Coastguard Worker                        extraParams...);
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixels(const SkImage * src,const SkImageInfo & dstImageInfo,const SkIRect & srcRect,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)256*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixels(const SkImage* src,
257*c8dee2aaSAndroid Build Coastguard Worker                                         const SkImageInfo& dstImageInfo,
258*c8dee2aaSAndroid Build Coastguard Worker                                         const SkIRect& srcRect,
259*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::RescaleGamma rescaleGamma,
260*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::RescaleMode rescaleMode,
261*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::ReadPixelsCallback callback,
262*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::ReadPixelsContext callbackContext) {
263*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadImpl(&Context::asyncReadPixels,
264*c8dee2aaSAndroid Build Coastguard Worker                                   rescaleGamma, rescaleMode,
265*c8dee2aaSAndroid Build Coastguard Worker                                   {src, srcRect, dstImageInfo, callback, callbackContext});
266*c8dee2aaSAndroid Build Coastguard Worker }
267*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixels(const SkSurface * src,const SkImageInfo & dstImageInfo,const SkIRect & srcRect,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)268*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixels(const SkSurface* src,
269*c8dee2aaSAndroid Build Coastguard Worker                                         const SkImageInfo& dstImageInfo,
270*c8dee2aaSAndroid Build Coastguard Worker                                         const SkIRect& srcRect,
271*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::RescaleGamma rescaleGamma,
272*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::RescaleMode rescaleMode,
273*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::ReadPixelsCallback callback,
274*c8dee2aaSAndroid Build Coastguard Worker                                         SkImage::ReadPixelsContext callbackContext) {
275*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> surfaceImage = SkSurfaces::AsImage(sk_ref_sp(src));
276*c8dee2aaSAndroid Build Coastguard Worker     if (!surfaceImage) {
277*c8dee2aaSAndroid Build Coastguard Worker         // The source surface is not texturable, so the only supported readback is if there's
278*c8dee2aaSAndroid Build Coastguard Worker         // no rescaling
279*c8dee2aaSAndroid Build Coastguard Worker         if (src && asConstSB(src)->isGraphiteBacked() &&
280*c8dee2aaSAndroid Build Coastguard Worker             srcRect.size() == dstImageInfo.dimensions()) {
281*c8dee2aaSAndroid Build Coastguard Worker             TextureProxy* proxy = static_cast<const Surface*>(src)->backingTextureProxy();
282*c8dee2aaSAndroid Build Coastguard Worker             return this->asyncReadTexture(/*recorder=*/nullptr,
283*c8dee2aaSAndroid Build Coastguard Worker                                           {proxy, srcRect, dstImageInfo, callback, callbackContext},
284*c8dee2aaSAndroid Build Coastguard Worker                                           src->imageInfo().colorInfo());
285*c8dee2aaSAndroid Build Coastguard Worker         }
286*c8dee2aaSAndroid Build Coastguard Worker         // else fall through and let asyncRescaleAndReadPixels() invoke the callback when it detects
287*c8dee2aaSAndroid Build Coastguard Worker         // the null image.
288*c8dee2aaSAndroid Build Coastguard Worker     }
289*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadPixels(surfaceImage.get(),
290*c8dee2aaSAndroid Build Coastguard Worker                                     dstImageInfo,
291*c8dee2aaSAndroid Build Coastguard Worker                                     srcRect,
292*c8dee2aaSAndroid Build Coastguard Worker                                     rescaleGamma,
293*c8dee2aaSAndroid Build Coastguard Worker                                     rescaleMode,
294*c8dee2aaSAndroid Build Coastguard Worker                                     callback,
295*c8dee2aaSAndroid Build Coastguard Worker                                     callbackContext);
296*c8dee2aaSAndroid Build Coastguard Worker }
297*c8dee2aaSAndroid Build Coastguard Worker 
asyncReadPixels(std::unique_ptr<Recorder> recorder,const AsyncParams<SkImage> & params)298*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncReadPixels(std::unique_ptr<Recorder> recorder,
299*c8dee2aaSAndroid Build Coastguard Worker                               const AsyncParams<SkImage>& params) {
300*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT2("skia.gpu", TRACE_FUNC,
301*c8dee2aaSAndroid Build Coastguard Worker                  "width", params.fSrcRect.width(),
302*c8dee2aaSAndroid Build Coastguard Worker                  "height", params.fSrcRect.height());
303*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.validate());    // all paths to here are already validated
304*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.fSrcRect.size() == params.fDstImageInfo.dimensions());
305*c8dee2aaSAndroid Build Coastguard Worker 
306*c8dee2aaSAndroid Build Coastguard Worker     const Caps* caps = fSharedContext->caps();
307*c8dee2aaSAndroid Build Coastguard Worker     TextureProxyView view = AsView(params.fSrcImage);
308*c8dee2aaSAndroid Build Coastguard Worker     if (!view || !caps->supportsReadPixels(view.proxy()->textureInfo())) {
309*c8dee2aaSAndroid Build Coastguard Worker         // This is either a YUVA image (null view) or the texture can't be read directly, so
310*c8dee2aaSAndroid Build Coastguard Worker         // perform a draw into a compatible texture format and/or flatten any YUVA planes to RGBA.
311*c8dee2aaSAndroid Build Coastguard Worker         if (!recorder) {
312*c8dee2aaSAndroid Build Coastguard Worker             recorder = this->makeInternalRecorder();
313*c8dee2aaSAndroid Build Coastguard Worker         }
314*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkImage> flattened = CopyAsDraw(recorder.get(),
315*c8dee2aaSAndroid Build Coastguard Worker                                               params.fSrcImage,
316*c8dee2aaSAndroid Build Coastguard Worker                                               params.fSrcRect,
317*c8dee2aaSAndroid Build Coastguard Worker                                               params.fDstImageInfo.colorInfo(),
318*c8dee2aaSAndroid Build Coastguard Worker                                               Budgeted::kYes,
319*c8dee2aaSAndroid Build Coastguard Worker                                               Mipmapped::kNo,
320*c8dee2aaSAndroid Build Coastguard Worker                                               SkBackingFit::kApprox,
321*c8dee2aaSAndroid Build Coastguard Worker                                               "AsyncReadPixelsFallbackTexture");
322*c8dee2aaSAndroid Build Coastguard Worker         if (!flattened) {
323*c8dee2aaSAndroid Build Coastguard Worker             SKGPU_LOG_W("AsyncRead failed because copy-as-drawing into a readable format failed");
324*c8dee2aaSAndroid Build Coastguard Worker             return params.fail();
325*c8dee2aaSAndroid Build Coastguard Worker         }
326*c8dee2aaSAndroid Build Coastguard Worker         // Use the original fSrcRect and not flattened's size since it's approx-fit.
327*c8dee2aaSAndroid Build Coastguard Worker         return this->asyncReadPixels(std::move(recorder),
328*c8dee2aaSAndroid Build Coastguard Worker                                      params.withNewSource(flattened.get(),
329*c8dee2aaSAndroid Build Coastguard Worker                                      SkIRect::MakeSize(params.fSrcRect.size())));
330*c8dee2aaSAndroid Build Coastguard Worker     }
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     // Can copy directly from the image's texture
333*c8dee2aaSAndroid Build Coastguard Worker     this->asyncReadTexture(std::move(recorder), params.withNewSource(view.proxy(), params.fSrcRect),
334*c8dee2aaSAndroid Build Coastguard Worker                            params.fSrcImage->imageInfo().colorInfo());
335*c8dee2aaSAndroid Build Coastguard Worker }
336*c8dee2aaSAndroid Build Coastguard Worker 
asyncReadTexture(std::unique_ptr<Recorder> recorder,const AsyncParams<TextureProxy> & params,const SkColorInfo & srcColorInfo)337*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncReadTexture(std::unique_ptr<Recorder> recorder,
338*c8dee2aaSAndroid Build Coastguard Worker                                const AsyncParams<TextureProxy>& params,
339*c8dee2aaSAndroid Build Coastguard Worker                                const SkColorInfo& srcColorInfo) {
340*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.fSrcRect.size() == params.fDstImageInfo.dimensions());
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker     // We can get here directly from surface or testing-only read pixels, so re-validate
343*c8dee2aaSAndroid Build Coastguard Worker     if (!params.validate()) {
344*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
345*c8dee2aaSAndroid Build Coastguard Worker     }
346*c8dee2aaSAndroid Build Coastguard Worker     PixelTransferResult transferResult = this->transferPixels(recorder.get(),
347*c8dee2aaSAndroid Build Coastguard Worker                                                               params.fSrcImage,
348*c8dee2aaSAndroid Build Coastguard Worker                                                               srcColorInfo,
349*c8dee2aaSAndroid Build Coastguard Worker                                                               params.fDstImageInfo.colorInfo(),
350*c8dee2aaSAndroid Build Coastguard Worker                                                               params.fSrcRect);
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker     if (!transferResult.fTransferBuffer) {
353*c8dee2aaSAndroid Build Coastguard Worker         // TODO: try to do a synchronous readPixels instead
354*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker 
357*c8dee2aaSAndroid Build Coastguard Worker     this->finalizeAsyncReadPixels(std::move(recorder),
358*c8dee2aaSAndroid Build Coastguard Worker                                   {&transferResult, 1},
359*c8dee2aaSAndroid Build Coastguard Worker                                   params.fCallback,
360*c8dee2aaSAndroid Build Coastguard Worker                                   params.fCallbackContext);
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixelsYUV420(const SkImage * src,SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)363*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixelsYUV420(const SkImage* src,
364*c8dee2aaSAndroid Build Coastguard Worker                                               SkYUVColorSpace yuvColorSpace,
365*c8dee2aaSAndroid Build Coastguard Worker                                               sk_sp<SkColorSpace> dstColorSpace,
366*c8dee2aaSAndroid Build Coastguard Worker                                               const SkIRect& srcRect,
367*c8dee2aaSAndroid Build Coastguard Worker                                               const SkISize& dstSize,
368*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::RescaleGamma rescaleGamma,
369*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::RescaleMode rescaleMode,
370*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::ReadPixelsCallback callback,
371*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::ReadPixelsContext callbackContext) {
372*c8dee2aaSAndroid Build Coastguard Worker     // Use kOpaque alpha type to signal that we don't read back the alpha channel
373*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo dstImageInfo = SkImageInfo::Make(dstSize,
374*c8dee2aaSAndroid Build Coastguard Worker                                                  kRGBA_8888_SkColorType,
375*c8dee2aaSAndroid Build Coastguard Worker                                                  kOpaque_SkAlphaType,
376*c8dee2aaSAndroid Build Coastguard Worker                                                  std::move(dstColorSpace));
377*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadImpl(&Context::asyncReadPixelsYUV420,
378*c8dee2aaSAndroid Build Coastguard Worker                                   rescaleGamma, rescaleMode,
379*c8dee2aaSAndroid Build Coastguard Worker                                   {src, srcRect, dstImageInfo, callback, callbackContext},
380*c8dee2aaSAndroid Build Coastguard Worker                                   yuvColorSpace);
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixelsYUV420(const SkSurface * src,SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)383*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixelsYUV420(const SkSurface* src,
384*c8dee2aaSAndroid Build Coastguard Worker                                               SkYUVColorSpace yuvColorSpace,
385*c8dee2aaSAndroid Build Coastguard Worker                                               sk_sp<SkColorSpace> dstColorSpace,
386*c8dee2aaSAndroid Build Coastguard Worker                                               const SkIRect& srcRect,
387*c8dee2aaSAndroid Build Coastguard Worker                                               const SkISize& dstSize,
388*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::RescaleGamma rescaleGamma,
389*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::RescaleMode rescaleMode,
390*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::ReadPixelsCallback callback,
391*c8dee2aaSAndroid Build Coastguard Worker                                               SkImage::ReadPixelsContext callbackContext) {
392*c8dee2aaSAndroid Build Coastguard Worker     // YUV[A] readback requires the surface to be texturable since the plane conversion is performed
393*c8dee2aaSAndroid Build Coastguard Worker     // by draws. If AsImage() returns null, the image version of asyncRescaleAndReadback will
394*c8dee2aaSAndroid Build Coastguard Worker     // automatically fail.
395*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Is it worth performing an extra copy from 'surface' into a texture in order to succeed?
396*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> surfaceImage = SkSurfaces::AsImage(sk_ref_sp(src));
397*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadPixelsYUV420(surfaceImage.get(),
398*c8dee2aaSAndroid Build Coastguard Worker                                           yuvColorSpace,
399*c8dee2aaSAndroid Build Coastguard Worker                                           dstColorSpace,
400*c8dee2aaSAndroid Build Coastguard Worker                                           srcRect,
401*c8dee2aaSAndroid Build Coastguard Worker                                           dstSize,
402*c8dee2aaSAndroid Build Coastguard Worker                                           rescaleGamma,
403*c8dee2aaSAndroid Build Coastguard Worker                                           rescaleMode,
404*c8dee2aaSAndroid Build Coastguard Worker                                           callback,
405*c8dee2aaSAndroid Build Coastguard Worker                                           callbackContext);
406*c8dee2aaSAndroid Build Coastguard Worker }
407*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixelsYUVA420(const SkImage * src,SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)408*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixelsYUVA420(const SkImage* src,
409*c8dee2aaSAndroid Build Coastguard Worker                                                SkYUVColorSpace yuvColorSpace,
410*c8dee2aaSAndroid Build Coastguard Worker                                                sk_sp<SkColorSpace> dstColorSpace,
411*c8dee2aaSAndroid Build Coastguard Worker                                                const SkIRect& srcRect,
412*c8dee2aaSAndroid Build Coastguard Worker                                                const SkISize& dstSize,
413*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::RescaleGamma rescaleGamma,
414*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::RescaleMode rescaleMode,
415*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::ReadPixelsCallback callback,
416*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::ReadPixelsContext callbackContext) {
417*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo dstImageInfo = SkImageInfo::Make(dstSize,
418*c8dee2aaSAndroid Build Coastguard Worker                                                  kRGBA_8888_SkColorType,
419*c8dee2aaSAndroid Build Coastguard Worker                                                  kPremul_SkAlphaType,
420*c8dee2aaSAndroid Build Coastguard Worker                                                  std::move(dstColorSpace));
421*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadImpl(&Context::asyncReadPixelsYUV420,
422*c8dee2aaSAndroid Build Coastguard Worker                                   rescaleGamma, rescaleMode,
423*c8dee2aaSAndroid Build Coastguard Worker                                   {src, srcRect, dstImageInfo, callback, callbackContext},
424*c8dee2aaSAndroid Build Coastguard Worker                                   yuvColorSpace);
425*c8dee2aaSAndroid Build Coastguard Worker }
426*c8dee2aaSAndroid Build Coastguard Worker 
asyncRescaleAndReadPixelsYUVA420(const SkSurface * src,SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)427*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncRescaleAndReadPixelsYUVA420(const SkSurface* src,
428*c8dee2aaSAndroid Build Coastguard Worker                                                SkYUVColorSpace yuvColorSpace,
429*c8dee2aaSAndroid Build Coastguard Worker                                                sk_sp<SkColorSpace> dstColorSpace,
430*c8dee2aaSAndroid Build Coastguard Worker                                                const SkIRect& srcRect,
431*c8dee2aaSAndroid Build Coastguard Worker                                                const SkISize& dstSize,
432*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::RescaleGamma rescaleGamma,
433*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::RescaleMode rescaleMode,
434*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::ReadPixelsCallback callback,
435*c8dee2aaSAndroid Build Coastguard Worker                                                SkImage::ReadPixelsContext callbackContext) {
436*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> surfaceImage = SkSurfaces::AsImage(sk_ref_sp(src));
437*c8dee2aaSAndroid Build Coastguard Worker     this->asyncRescaleAndReadPixelsYUVA420(surfaceImage.get(),
438*c8dee2aaSAndroid Build Coastguard Worker                                            yuvColorSpace,
439*c8dee2aaSAndroid Build Coastguard Worker                                            dstColorSpace,
440*c8dee2aaSAndroid Build Coastguard Worker                                            srcRect,
441*c8dee2aaSAndroid Build Coastguard Worker                                            dstSize,
442*c8dee2aaSAndroid Build Coastguard Worker                                            rescaleGamma,
443*c8dee2aaSAndroid Build Coastguard Worker                                            rescaleMode,
444*c8dee2aaSAndroid Build Coastguard Worker                                            callback,
445*c8dee2aaSAndroid Build Coastguard Worker                                            callbackContext);
446*c8dee2aaSAndroid Build Coastguard Worker }
447*c8dee2aaSAndroid Build Coastguard Worker 
asyncReadPixelsYUV420(std::unique_ptr<Recorder> recorder,const AsyncParams<SkImage> & params,SkYUVColorSpace yuvColorSpace)448*c8dee2aaSAndroid Build Coastguard Worker void Context::asyncReadPixelsYUV420(std::unique_ptr<Recorder> recorder,
449*c8dee2aaSAndroid Build Coastguard Worker                                     const AsyncParams<SkImage>& params,
450*c8dee2aaSAndroid Build Coastguard Worker                                     SkYUVColorSpace yuvColorSpace) {
451*c8dee2aaSAndroid Build Coastguard Worker     TRACE_EVENT2("skia.gpu", TRACE_FUNC,
452*c8dee2aaSAndroid Build Coastguard Worker                  "width", params.fSrcRect.width(),
453*c8dee2aaSAndroid Build Coastguard Worker                  "height", params.fSrcRect.height());
454*c8dee2aaSAndroid Build Coastguard Worker     // This is only called by asyncRescaleAndReadImpl which already validates its parameters
455*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.validate());
456*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(params.fSrcRect.size() == params.fDstImageInfo.dimensions());
457*c8dee2aaSAndroid Build Coastguard Worker 
458*c8dee2aaSAndroid Build Coastguard Worker     // The planes are always extracted via drawing, so create the Recorder if there isn't one yet.
459*c8dee2aaSAndroid Build Coastguard Worker     if (!recorder) {
460*c8dee2aaSAndroid Build Coastguard Worker         recorder = this->makeInternalRecorder();
461*c8dee2aaSAndroid Build Coastguard Worker     }
462*c8dee2aaSAndroid Build Coastguard Worker 
463*c8dee2aaSAndroid Build Coastguard Worker     // copyPlane renders the source image into an A8 image and sets up a transfer stored in 'result'
464*c8dee2aaSAndroid Build Coastguard Worker     auto copyPlane = [&](SkImageInfo planeInfo,
465*c8dee2aaSAndroid Build Coastguard Worker                          std::string_view label,
466*c8dee2aaSAndroid Build Coastguard Worker                          float rgb2yuv[20],
467*c8dee2aaSAndroid Build Coastguard Worker                          const SkMatrix& texMatrix,
468*c8dee2aaSAndroid Build Coastguard Worker                          PixelTransferResult* result) {
469*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<Surface> dstSurface = Surface::MakeScratch(recorder.get(),
470*c8dee2aaSAndroid Build Coastguard Worker                                                          planeInfo,
471*c8dee2aaSAndroid Build Coastguard Worker                                                          std::move(label),
472*c8dee2aaSAndroid Build Coastguard Worker                                                          Budgeted::kYes,
473*c8dee2aaSAndroid Build Coastguard Worker                                                          Mipmapped::kNo,
474*c8dee2aaSAndroid Build Coastguard Worker                                                          SkBackingFit::kApprox);
475*c8dee2aaSAndroid Build Coastguard Worker         if (!dstSurface) {
476*c8dee2aaSAndroid Build Coastguard Worker             return false;
477*c8dee2aaSAndroid Build Coastguard Worker         }
478*c8dee2aaSAndroid Build Coastguard Worker 
479*c8dee2aaSAndroid Build Coastguard Worker         // Render the plane defined by rgb2yuv from srcImage into dstSurface
480*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
481*c8dee2aaSAndroid Build Coastguard Worker         const SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
482*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkShader> imgShader = params.fSrcImage->makeShader(
483*c8dee2aaSAndroid Build Coastguard Worker                 SkTileMode::kClamp, SkTileMode::kClamp, sampling, texMatrix);
484*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(std::move(imgShader));
485*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kSrc);
486*c8dee2aaSAndroid Build Coastguard Worker 
487*c8dee2aaSAndroid Build Coastguard Worker         if (rgb2yuv) {
488*c8dee2aaSAndroid Build Coastguard Worker             // NOTE: The dstSurface's color space is set to the requested RGB dstColorSpace, so
489*c8dee2aaSAndroid Build Coastguard Worker             // the rendered image is automatically converted to that RGB color space before the
490*c8dee2aaSAndroid Build Coastguard Worker             // RGB->YUV color filter is evaluated, putting the plane data into the alpha channel.
491*c8dee2aaSAndroid Build Coastguard Worker             paint.setColorFilter(SkColorFilters::Matrix(rgb2yuv));
492*c8dee2aaSAndroid Build Coastguard Worker         }
493*c8dee2aaSAndroid Build Coastguard Worker 
494*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* canvas = dstSurface->getCanvas();
495*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPaint(paint);
496*c8dee2aaSAndroid Build Coastguard Worker 
497*c8dee2aaSAndroid Build Coastguard Worker         // Manually flush the surface before transferPixels() is called to ensure the rendering
498*c8dee2aaSAndroid Build Coastguard Worker         // operations run before the CopyTextureToBuffer task.
499*c8dee2aaSAndroid Build Coastguard Worker         Flush(dstSurface);
500*c8dee2aaSAndroid Build Coastguard Worker         // Must use planeInfo.bounds() for srcRect since dstSurface is kApprox-fit.
501*c8dee2aaSAndroid Build Coastguard Worker         *result = this->transferPixels(recorder.get(),
502*c8dee2aaSAndroid Build Coastguard Worker                                        dstSurface->backingTextureProxy(),
503*c8dee2aaSAndroid Build Coastguard Worker                                        dstSurface->imageInfo().colorInfo(),
504*c8dee2aaSAndroid Build Coastguard Worker                                        planeInfo.colorInfo(),
505*c8dee2aaSAndroid Build Coastguard Worker                                        planeInfo.bounds());
506*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(result->fTransferBuffer);
507*c8dee2aaSAndroid Build Coastguard Worker     };
508*c8dee2aaSAndroid Build Coastguard Worker 
509*c8dee2aaSAndroid Build Coastguard Worker     // Set up draws and transfers. This interleaves the drawing to a plane and the copy to the
510*c8dee2aaSAndroid Build Coastguard Worker     // transfer buffer, which will allow the scratch A8 surface to be reused for each plane.
511*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
512*c8dee2aaSAndroid Build Coastguard Worker     const bool readAlpha = params.fDstImageInfo.colorInfo().alphaType() != kOpaque_SkAlphaType;
513*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo yaInfo = params.fDstImageInfo.makeColorType(kAlpha_8_SkColorType)
514*c8dee2aaSAndroid Build Coastguard Worker                                              .makeAlphaType(kPremul_SkAlphaType);
515*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo uvInfo = yaInfo.makeWH(yaInfo.width()/2, yaInfo.height()/2);
516*c8dee2aaSAndroid Build Coastguard Worker     PixelTransferResult transfers[4];
517*c8dee2aaSAndroid Build Coastguard Worker 
518*c8dee2aaSAndroid Build Coastguard Worker     float baseM[20];
519*c8dee2aaSAndroid Build Coastguard Worker     SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
520*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix texMatrix = SkMatrix::Translate(-params.fSrcRect.fLeft, -params.fSrcRect.fTop);
521*c8dee2aaSAndroid Build Coastguard Worker 
522*c8dee2aaSAndroid Build Coastguard Worker     // This matrix generates (r,g,b,a) = (0, 0, 0, y)
523*c8dee2aaSAndroid Build Coastguard Worker     float yM[20];
524*c8dee2aaSAndroid Build Coastguard Worker     std::fill_n(yM, 15, 0.f);
525*c8dee2aaSAndroid Build Coastguard Worker     std::copy_n(baseM + 0, 5, yM + 15);
526*c8dee2aaSAndroid Build Coastguard Worker     if (!copyPlane(yaInfo, "AsyncReadPixelsYPlane", yM, texMatrix, &transfers[0])) {
527*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
528*c8dee2aaSAndroid Build Coastguard Worker     }
529*c8dee2aaSAndroid Build Coastguard Worker 
530*c8dee2aaSAndroid Build Coastguard Worker     // No matrix, straight copy of alpha channel
531*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(baseM[15] == 0 &&
532*c8dee2aaSAndroid Build Coastguard Worker              baseM[16] == 0 &&
533*c8dee2aaSAndroid Build Coastguard Worker              baseM[17] == 0 &&
534*c8dee2aaSAndroid Build Coastguard Worker              baseM[18] == 1 &&
535*c8dee2aaSAndroid Build Coastguard Worker              baseM[19] == 0);
536*c8dee2aaSAndroid Build Coastguard Worker     if (readAlpha &&
537*c8dee2aaSAndroid Build Coastguard Worker         !copyPlane(yaInfo, "AsyncReadPixelsAPlane", nullptr, texMatrix, &transfers[3])) {
538*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
539*c8dee2aaSAndroid Build Coastguard Worker     }
540*c8dee2aaSAndroid Build Coastguard Worker 
541*c8dee2aaSAndroid Build Coastguard Worker     // The UV planes are at half resolution compared to Y and A in 4:2:0
542*c8dee2aaSAndroid Build Coastguard Worker     texMatrix.postScale(0.5f, 0.5f);
543*c8dee2aaSAndroid Build Coastguard Worker 
544*c8dee2aaSAndroid Build Coastguard Worker     // This matrix generates (r,g,b,a) = (0, 0, 0, u)
545*c8dee2aaSAndroid Build Coastguard Worker     float uM[20];
546*c8dee2aaSAndroid Build Coastguard Worker     std::fill_n(uM, 15, 0.f);
547*c8dee2aaSAndroid Build Coastguard Worker     std::copy_n(baseM + 5, 5, uM + 15);
548*c8dee2aaSAndroid Build Coastguard Worker     if (!copyPlane(uvInfo, "AsyncReadPixelsUPlane", uM, texMatrix, &transfers[1])) {
549*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
550*c8dee2aaSAndroid Build Coastguard Worker     }
551*c8dee2aaSAndroid Build Coastguard Worker 
552*c8dee2aaSAndroid Build Coastguard Worker     // This matrix generates (r,g,b,a) = (0, 0, 0, v)
553*c8dee2aaSAndroid Build Coastguard Worker     float vM[20];
554*c8dee2aaSAndroid Build Coastguard Worker     std::fill_n(vM, 15, 0.f);
555*c8dee2aaSAndroid Build Coastguard Worker     std::copy_n(baseM + 10, 5, vM + 15);
556*c8dee2aaSAndroid Build Coastguard Worker     if (!copyPlane(uvInfo, "AsyncReadPixelsVPlane", vM, texMatrix, &transfers[2])) {
557*c8dee2aaSAndroid Build Coastguard Worker         return params.fail();
558*c8dee2aaSAndroid Build Coastguard Worker     }
559*c8dee2aaSAndroid Build Coastguard Worker 
560*c8dee2aaSAndroid Build Coastguard Worker     this->finalizeAsyncReadPixels(std::move(recorder),
561*c8dee2aaSAndroid Build Coastguard Worker                                   {transfers, readAlpha ? 4 : 3},
562*c8dee2aaSAndroid Build Coastguard Worker                                   params.fCallback,
563*c8dee2aaSAndroid Build Coastguard Worker                                   params.fCallbackContext);
564*c8dee2aaSAndroid Build Coastguard Worker }
565*c8dee2aaSAndroid Build Coastguard Worker 
finalizeAsyncReadPixels(std::unique_ptr<Recorder> recorder,SkSpan<PixelTransferResult> transferResults,SkImage::ReadPixelsCallback callback,SkImage::ReadPixelsContext callbackContext)566*c8dee2aaSAndroid Build Coastguard Worker void Context::finalizeAsyncReadPixels(std::unique_ptr<Recorder> recorder,
567*c8dee2aaSAndroid Build Coastguard Worker                                       SkSpan<PixelTransferResult> transferResults,
568*c8dee2aaSAndroid Build Coastguard Worker                                       SkImage::ReadPixelsCallback callback,
569*c8dee2aaSAndroid Build Coastguard Worker                                       SkImage::ReadPixelsContext callbackContext) {
570*c8dee2aaSAndroid Build Coastguard Worker     // If the async readback work required a Recorder, insert the recording with all of the
571*c8dee2aaSAndroid Build Coastguard Worker     // accumulated work (which includes any copies). Otherwise, for pure copy readbacks,
572*c8dee2aaSAndroid Build Coastguard Worker     // transferPixels() already added the tasks directly to the QueueManager.
573*c8dee2aaSAndroid Build Coastguard Worker     if (recorder) {
574*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<Recording> recording = recorder->snap();
575*c8dee2aaSAndroid Build Coastguard Worker         if (!recording) {
576*c8dee2aaSAndroid Build Coastguard Worker             callback(callbackContext, nullptr);
577*c8dee2aaSAndroid Build Coastguard Worker             return;
578*c8dee2aaSAndroid Build Coastguard Worker         }
579*c8dee2aaSAndroid Build Coastguard Worker         InsertRecordingInfo recordingInfo;
580*c8dee2aaSAndroid Build Coastguard Worker         recordingInfo.fRecording = recording.get();
581*c8dee2aaSAndroid Build Coastguard Worker         if (!this->insertRecording(recordingInfo)) {
582*c8dee2aaSAndroid Build Coastguard Worker             callback(callbackContext, nullptr);
583*c8dee2aaSAndroid Build Coastguard Worker             return;
584*c8dee2aaSAndroid Build Coastguard Worker         }
585*c8dee2aaSAndroid Build Coastguard Worker     }
586*c8dee2aaSAndroid Build Coastguard Worker 
587*c8dee2aaSAndroid Build Coastguard Worker     // Set up FinishContext and add transfer commands to queue
588*c8dee2aaSAndroid Build Coastguard Worker     struct AsyncReadFinishContext {
589*c8dee2aaSAndroid Build Coastguard Worker         SkImage::ReadPixelsCallback* fClientCallback;
590*c8dee2aaSAndroid Build Coastguard Worker         SkImage::ReadPixelsContext fClientContext;
591*c8dee2aaSAndroid Build Coastguard Worker         ClientMappedBufferManager* fMappedBufferManager;
592*c8dee2aaSAndroid Build Coastguard Worker         std::array<PixelTransferResult, 4> fTransferResults;
593*c8dee2aaSAndroid Build Coastguard Worker     };
594*c8dee2aaSAndroid Build Coastguard Worker 
595*c8dee2aaSAndroid Build Coastguard Worker     auto finishContext = std::make_unique<AsyncReadFinishContext>();
596*c8dee2aaSAndroid Build Coastguard Worker     finishContext->fClientCallback      = callback;
597*c8dee2aaSAndroid Build Coastguard Worker     finishContext->fClientContext       = callbackContext;
598*c8dee2aaSAndroid Build Coastguard Worker     finishContext->fMappedBufferManager = fMappedBufferManager.get();
599*c8dee2aaSAndroid Build Coastguard Worker 
600*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(transferResults.size() <= std::size(finishContext->fTransferResults));
601*c8dee2aaSAndroid Build Coastguard Worker     skia_private::STArray<4, sk_sp<Buffer>> buffersToAsyncMap;
602*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < transferResults.size(); ++i) {
603*c8dee2aaSAndroid Build Coastguard Worker         finishContext->fTransferResults[i] = std::move(transferResults[i]);
604*c8dee2aaSAndroid Build Coastguard Worker         if (fSharedContext->caps()->bufferMapsAreAsync()) {
605*c8dee2aaSAndroid Build Coastguard Worker             buffersToAsyncMap.push_back(finishContext->fTransferResults[i].fTransferBuffer);
606*c8dee2aaSAndroid Build Coastguard Worker         }
607*c8dee2aaSAndroid Build Coastguard Worker     }
608*c8dee2aaSAndroid Build Coastguard Worker 
609*c8dee2aaSAndroid Build Coastguard Worker     InsertFinishInfo info;
610*c8dee2aaSAndroid Build Coastguard Worker     info.fFinishedContext = finishContext.release();
611*c8dee2aaSAndroid Build Coastguard Worker     info.fFinishedProc = [](GpuFinishedContext c, CallbackResult status) {
612*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<const AsyncReadFinishContext> context(
613*c8dee2aaSAndroid Build Coastguard Worker                 reinterpret_cast<const AsyncReadFinishContext*>(c));
614*c8dee2aaSAndroid Build Coastguard Worker         using AsyncReadResult = skgpu::TAsyncReadResult<Buffer, ContextID, PixelTransferResult>;
615*c8dee2aaSAndroid Build Coastguard Worker 
616*c8dee2aaSAndroid Build Coastguard Worker         ClientMappedBufferManager* manager = context->fMappedBufferManager;
617*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<AsyncReadResult> result;
618*c8dee2aaSAndroid Build Coastguard Worker         if (status == CallbackResult::kSuccess) {
619*c8dee2aaSAndroid Build Coastguard Worker             result = std::make_unique<AsyncReadResult>(manager->ownerID());
620*c8dee2aaSAndroid Build Coastguard Worker         }
621*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& r : context->fTransferResults) {
622*c8dee2aaSAndroid Build Coastguard Worker             if (!r.fTransferBuffer) {
623*c8dee2aaSAndroid Build Coastguard Worker                 break;
624*c8dee2aaSAndroid Build Coastguard Worker             }
625*c8dee2aaSAndroid Build Coastguard Worker             if (result && !result->addTransferResult(r, r.fSize, r.fRowBytes, manager)) {
626*c8dee2aaSAndroid Build Coastguard Worker                 result.reset();
627*c8dee2aaSAndroid Build Coastguard Worker             }
628*c8dee2aaSAndroid Build Coastguard Worker             // If we didn't get this buffer into the mapped buffer manager then make sure it gets
629*c8dee2aaSAndroid Build Coastguard Worker             // unmapped if it has a pending or completed async map.
630*c8dee2aaSAndroid Build Coastguard Worker             if (!result && r.fTransferBuffer->isUnmappable()) {
631*c8dee2aaSAndroid Build Coastguard Worker                 r.fTransferBuffer->unmap();
632*c8dee2aaSAndroid Build Coastguard Worker             }
633*c8dee2aaSAndroid Build Coastguard Worker         }
634*c8dee2aaSAndroid Build Coastguard Worker         (*context->fClientCallback)(context->fClientContext, std::move(result));
635*c8dee2aaSAndroid Build Coastguard Worker     };
636*c8dee2aaSAndroid Build Coastguard Worker 
637*c8dee2aaSAndroid Build Coastguard Worker     // If addFinishInfo() fails, it invokes the finish callback automatically, which handles all the
638*c8dee2aaSAndroid Build Coastguard Worker     // required clean up for us, just log an error message. The buffers will never be mapped and
639*c8dee2aaSAndroid Build Coastguard Worker     // thus don't need an unmap.
640*c8dee2aaSAndroid Build Coastguard Worker     if (!fQueueManager->addFinishInfo(info, fResourceProvider.get(), buffersToAsyncMap)) {
641*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_E("Failed to register finish callbacks for asyncReadPixels.");
642*c8dee2aaSAndroid Build Coastguard Worker         return;
643*c8dee2aaSAndroid Build Coastguard Worker     }
644*c8dee2aaSAndroid Build Coastguard Worker }
645*c8dee2aaSAndroid Build Coastguard Worker 
transferPixels(Recorder * recorder,const TextureProxy * srcProxy,const SkColorInfo & srcColorInfo,const SkColorInfo & dstColorInfo,const SkIRect & srcRect)646*c8dee2aaSAndroid Build Coastguard Worker Context::PixelTransferResult Context::transferPixels(Recorder* recorder,
647*c8dee2aaSAndroid Build Coastguard Worker                                                      const TextureProxy* srcProxy,
648*c8dee2aaSAndroid Build Coastguard Worker                                                      const SkColorInfo& srcColorInfo,
649*c8dee2aaSAndroid Build Coastguard Worker                                                      const SkColorInfo& dstColorInfo,
650*c8dee2aaSAndroid Build Coastguard Worker                                                      const SkIRect& srcRect) {
651*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkIRect::MakeSize(srcProxy->dimensions()).contains(srcRect));
652*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkColorInfoIsValid(dstColorInfo));
653*c8dee2aaSAndroid Build Coastguard Worker 
654*c8dee2aaSAndroid Build Coastguard Worker     const Caps* caps = fSharedContext->caps();
655*c8dee2aaSAndroid Build Coastguard Worker     if (!srcProxy || !caps->supportsReadPixels(srcProxy->textureInfo())) {
656*c8dee2aaSAndroid Build Coastguard Worker         return {};
657*c8dee2aaSAndroid Build Coastguard Worker     }
658*c8dee2aaSAndroid Build Coastguard Worker 
659*c8dee2aaSAndroid Build Coastguard Worker     const SkColorType srcColorType = srcColorInfo.colorType();
660*c8dee2aaSAndroid Build Coastguard Worker     SkColorType supportedColorType;
661*c8dee2aaSAndroid Build Coastguard Worker     bool isRGB888Format;
662*c8dee2aaSAndroid Build Coastguard Worker     std::tie(supportedColorType, isRGB888Format) =
663*c8dee2aaSAndroid Build Coastguard Worker             caps->supportedReadPixelsColorType(srcColorType,
664*c8dee2aaSAndroid Build Coastguard Worker                                                srcProxy->textureInfo(),
665*c8dee2aaSAndroid Build Coastguard Worker                                                dstColorInfo.colorType());
666*c8dee2aaSAndroid Build Coastguard Worker     if (supportedColorType == kUnknown_SkColorType) {
667*c8dee2aaSAndroid Build Coastguard Worker         return {};
668*c8dee2aaSAndroid Build Coastguard Worker     }
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker     // Fail if read color type does not have all of dstCT's color channels and those missing color
671*c8dee2aaSAndroid Build Coastguard Worker     // channels are in the src.
672*c8dee2aaSAndroid Build Coastguard Worker     uint32_t dstChannels = SkColorTypeChannelFlags(dstColorInfo.colorType());
673*c8dee2aaSAndroid Build Coastguard Worker     uint32_t legalReadChannels = SkColorTypeChannelFlags(supportedColorType);
674*c8dee2aaSAndroid Build Coastguard Worker     uint32_t srcChannels = SkColorTypeChannelFlags(srcColorType);
675*c8dee2aaSAndroid Build Coastguard Worker     if ((~legalReadChannels & dstChannels) & srcChannels) {
676*c8dee2aaSAndroid Build Coastguard Worker         return {};
677*c8dee2aaSAndroid Build Coastguard Worker     }
678*c8dee2aaSAndroid Build Coastguard Worker 
679*c8dee2aaSAndroid Build Coastguard Worker     int bpp = isRGB888Format ? 3 : SkColorTypeBytesPerPixel(supportedColorType);
680*c8dee2aaSAndroid Build Coastguard Worker     size_t rowBytes = caps->getAlignedTextureDataRowBytes(bpp * srcRect.width());
681*c8dee2aaSAndroid Build Coastguard Worker     size_t size = SkAlignTo(rowBytes * srcRect.height(), caps->requiredTransferBufferAlignment());
682*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<Buffer> buffer = fResourceProvider->findOrCreateBuffer(
683*c8dee2aaSAndroid Build Coastguard Worker             size, BufferType::kXferGpuToCpu, AccessPattern::kHostVisible, "TransferToCpu");
684*c8dee2aaSAndroid Build Coastguard Worker     if (!buffer) {
685*c8dee2aaSAndroid Build Coastguard Worker         return {};
686*c8dee2aaSAndroid Build Coastguard Worker     }
687*c8dee2aaSAndroid Build Coastguard Worker 
688*c8dee2aaSAndroid Build Coastguard Worker     // Set up copy task. Since we always use a new buffer the offset can be 0 and we don't need to
689*c8dee2aaSAndroid Build Coastguard Worker     // worry about aligning it to the required transfer buffer alignment.
690*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<CopyTextureToBufferTask> copyTask = CopyTextureToBufferTask::Make(sk_ref_sp(srcProxy),
691*c8dee2aaSAndroid Build Coastguard Worker                                                                             srcRect,
692*c8dee2aaSAndroid Build Coastguard Worker                                                                             buffer,
693*c8dee2aaSAndroid Build Coastguard Worker                                                                             /*bufferOffset=*/0,
694*c8dee2aaSAndroid Build Coastguard Worker                                                                             rowBytes);
695*c8dee2aaSAndroid Build Coastguard Worker     const bool addTasksDirectly = !SkToBool(recorder);
696*c8dee2aaSAndroid Build Coastguard Worker     Protected contextIsProtected = fSharedContext->isProtected();
697*c8dee2aaSAndroid Build Coastguard Worker     if (!copyTask || (addTasksDirectly && !fQueueManager->addTask(copyTask.get(),
698*c8dee2aaSAndroid Build Coastguard Worker                                                                   this,
699*c8dee2aaSAndroid Build Coastguard Worker                                                                   contextIsProtected))) {
700*c8dee2aaSAndroid Build Coastguard Worker         return {};
701*c8dee2aaSAndroid Build Coastguard Worker     } else if (!addTasksDirectly) {
702*c8dee2aaSAndroid Build Coastguard Worker         // Add the task to the Recorder instead of the QueueManager if that's been required for
703*c8dee2aaSAndroid Build Coastguard Worker         // collecting tasks to prepare the copied textures.
704*c8dee2aaSAndroid Build Coastguard Worker         recorder->priv().add(std::move(copyTask));
705*c8dee2aaSAndroid Build Coastguard Worker     }
706*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SynchronizeToCpuTask> syncTask = SynchronizeToCpuTask::Make(buffer);
707*c8dee2aaSAndroid Build Coastguard Worker     if (!syncTask || (addTasksDirectly && !fQueueManager->addTask(syncTask.get(),
708*c8dee2aaSAndroid Build Coastguard Worker                                                                   this,
709*c8dee2aaSAndroid Build Coastguard Worker                                                                   contextIsProtected))) {
710*c8dee2aaSAndroid Build Coastguard Worker         return {};
711*c8dee2aaSAndroid Build Coastguard Worker     } else if (!addTasksDirectly) {
712*c8dee2aaSAndroid Build Coastguard Worker         recorder->priv().add(std::move(syncTask));
713*c8dee2aaSAndroid Build Coastguard Worker     }
714*c8dee2aaSAndroid Build Coastguard Worker 
715*c8dee2aaSAndroid Build Coastguard Worker     PixelTransferResult result;
716*c8dee2aaSAndroid Build Coastguard Worker     result.fTransferBuffer = std::move(buffer);
717*c8dee2aaSAndroid Build Coastguard Worker     result.fSize = srcRect.size();
718*c8dee2aaSAndroid Build Coastguard Worker     // srcColorInfo describes the texture; readColorInfo describes the result of the copy-to-buffer,
719*c8dee2aaSAndroid Build Coastguard Worker     // which may be different; dstColorInfo is what we have to transform it into when invoking the
720*c8dee2aaSAndroid Build Coastguard Worker     // async callbacks.
721*c8dee2aaSAndroid Build Coastguard Worker     SkColorInfo readColorInfo = srcColorInfo.makeColorType(supportedColorType);
722*c8dee2aaSAndroid Build Coastguard Worker     if (readColorInfo != dstColorInfo || isRGB888Format) {
723*c8dee2aaSAndroid Build Coastguard Worker         SkISize dims = srcRect.size();
724*c8dee2aaSAndroid Build Coastguard Worker         SkImageInfo srcInfo = SkImageInfo::Make(dims, readColorInfo);
725*c8dee2aaSAndroid Build Coastguard Worker         SkImageInfo dstInfo = SkImageInfo::Make(dims, dstColorInfo);
726*c8dee2aaSAndroid Build Coastguard Worker         result.fRowBytes = dstInfo.minRowBytes();
727*c8dee2aaSAndroid Build Coastguard Worker         result.fPixelConverter = [dstInfo, srcInfo, rowBytes, isRGB888Format](
728*c8dee2aaSAndroid Build Coastguard Worker                 void* dst, const void* src) {
729*c8dee2aaSAndroid Build Coastguard Worker             SkAutoPixmapStorage temp;
730*c8dee2aaSAndroid Build Coastguard Worker             size_t srcRowBytes = rowBytes;
731*c8dee2aaSAndroid Build Coastguard Worker             if (isRGB888Format) {
732*c8dee2aaSAndroid Build Coastguard Worker                 temp.alloc(srcInfo);
733*c8dee2aaSAndroid Build Coastguard Worker                 size_t tRowBytes = temp.rowBytes();
734*c8dee2aaSAndroid Build Coastguard Worker                 auto* sRow = reinterpret_cast<const char*>(src);
735*c8dee2aaSAndroid Build Coastguard Worker                 auto* tRow = reinterpret_cast<char*>(temp.writable_addr());
736*c8dee2aaSAndroid Build Coastguard Worker                 for (int y = 0; y < srcInfo.height(); ++y, sRow += srcRowBytes, tRow += tRowBytes) {
737*c8dee2aaSAndroid Build Coastguard Worker                     for (int x = 0; x < srcInfo.width(); ++x) {
738*c8dee2aaSAndroid Build Coastguard Worker                         auto s = sRow + x*3;
739*c8dee2aaSAndroid Build Coastguard Worker                         auto t = tRow + x*sizeof(uint32_t);
740*c8dee2aaSAndroid Build Coastguard Worker                         memcpy(t, s, 3);
741*c8dee2aaSAndroid Build Coastguard Worker                         t[3] = static_cast<char>(0xFF);
742*c8dee2aaSAndroid Build Coastguard Worker                     }
743*c8dee2aaSAndroid Build Coastguard Worker                 }
744*c8dee2aaSAndroid Build Coastguard Worker                 src = temp.addr();
745*c8dee2aaSAndroid Build Coastguard Worker                 srcRowBytes = tRowBytes;
746*c8dee2aaSAndroid Build Coastguard Worker             }
747*c8dee2aaSAndroid Build Coastguard Worker             SkAssertResult(SkConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
748*c8dee2aaSAndroid Build Coastguard Worker                                            srcInfo, src, srcRowBytes));
749*c8dee2aaSAndroid Build Coastguard Worker         };
750*c8dee2aaSAndroid Build Coastguard Worker     } else {
751*c8dee2aaSAndroid Build Coastguard Worker         result.fRowBytes = rowBytes;
752*c8dee2aaSAndroid Build Coastguard Worker     }
753*c8dee2aaSAndroid Build Coastguard Worker 
754*c8dee2aaSAndroid Build Coastguard Worker     return result;
755*c8dee2aaSAndroid Build Coastguard Worker }
756*c8dee2aaSAndroid Build Coastguard Worker 
checkForFinishedWork(SyncToCpu syncToCpu)757*c8dee2aaSAndroid Build Coastguard Worker void Context::checkForFinishedWork(SyncToCpu syncToCpu) {
758*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
759*c8dee2aaSAndroid Build Coastguard Worker 
760*c8dee2aaSAndroid Build Coastguard Worker     fQueueManager->checkForFinishedWork(syncToCpu);
761*c8dee2aaSAndroid Build Coastguard Worker     fMappedBufferManager->process();
762*c8dee2aaSAndroid Build Coastguard Worker }
763*c8dee2aaSAndroid Build Coastguard Worker 
checkAsyncWorkCompletion()764*c8dee2aaSAndroid Build Coastguard Worker void Context::checkAsyncWorkCompletion() {
765*c8dee2aaSAndroid Build Coastguard Worker     this->checkForFinishedWork(SyncToCpu::kNo);
766*c8dee2aaSAndroid Build Coastguard Worker }
767*c8dee2aaSAndroid Build Coastguard Worker 
deleteBackendTexture(const BackendTexture & texture)768*c8dee2aaSAndroid Build Coastguard Worker void Context::deleteBackendTexture(const BackendTexture& texture) {
769*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
770*c8dee2aaSAndroid Build Coastguard Worker 
771*c8dee2aaSAndroid Build Coastguard Worker     if (!texture.isValid() || texture.backend() != this->backend()) {
772*c8dee2aaSAndroid Build Coastguard Worker         return;
773*c8dee2aaSAndroid Build Coastguard Worker     }
774*c8dee2aaSAndroid Build Coastguard Worker     fResourceProvider->deleteBackendTexture(texture);
775*c8dee2aaSAndroid Build Coastguard Worker }
776*c8dee2aaSAndroid Build Coastguard Worker 
freeGpuResources()777*c8dee2aaSAndroid Build Coastguard Worker void Context::freeGpuResources() {
778*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
779*c8dee2aaSAndroid Build Coastguard Worker 
780*c8dee2aaSAndroid Build Coastguard Worker     this->checkAsyncWorkCompletion();
781*c8dee2aaSAndroid Build Coastguard Worker 
782*c8dee2aaSAndroid Build Coastguard Worker     fResourceProvider->freeGpuResources();
783*c8dee2aaSAndroid Build Coastguard Worker }
784*c8dee2aaSAndroid Build Coastguard Worker 
performDeferredCleanup(std::chrono::milliseconds msNotUsed)785*c8dee2aaSAndroid Build Coastguard Worker void Context::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
786*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
787*c8dee2aaSAndroid Build Coastguard Worker 
788*c8dee2aaSAndroid Build Coastguard Worker     this->checkAsyncWorkCompletion();
789*c8dee2aaSAndroid Build Coastguard Worker 
790*c8dee2aaSAndroid Build Coastguard Worker     auto purgeTime = skgpu::StdSteadyClock::now() - msNotUsed;
791*c8dee2aaSAndroid Build Coastguard Worker     fResourceProvider->purgeResourcesNotUsedSince(purgeTime);
792*c8dee2aaSAndroid Build Coastguard Worker }
793*c8dee2aaSAndroid Build Coastguard Worker 
currentBudgetedBytes() const794*c8dee2aaSAndroid Build Coastguard Worker size_t Context::currentBudgetedBytes() const {
795*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
796*c8dee2aaSAndroid Build Coastguard Worker     return fResourceProvider->getResourceCacheCurrentBudgetedBytes();
797*c8dee2aaSAndroid Build Coastguard Worker }
798*c8dee2aaSAndroid Build Coastguard Worker 
currentPurgeableBytes() const799*c8dee2aaSAndroid Build Coastguard Worker size_t Context::currentPurgeableBytes() const {
800*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
801*c8dee2aaSAndroid Build Coastguard Worker     return fResourceProvider->getResourceCacheCurrentPurgeableBytes();
802*c8dee2aaSAndroid Build Coastguard Worker }
803*c8dee2aaSAndroid Build Coastguard Worker 
maxBudgetedBytes() const804*c8dee2aaSAndroid Build Coastguard Worker size_t Context::maxBudgetedBytes() const {
805*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
806*c8dee2aaSAndroid Build Coastguard Worker     return fResourceProvider->getResourceCacheLimit();
807*c8dee2aaSAndroid Build Coastguard Worker }
808*c8dee2aaSAndroid Build Coastguard Worker 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const809*c8dee2aaSAndroid Build Coastguard Worker void Context::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
810*c8dee2aaSAndroid Build Coastguard Worker     ASSERT_SINGLE_OWNER
811*c8dee2aaSAndroid Build Coastguard Worker     fResourceProvider->dumpMemoryStatistics(traceMemoryDump);
812*c8dee2aaSAndroid Build Coastguard Worker     // TODO: What is the graphite equivalent for the text blob cache and how do we print out its
813*c8dee2aaSAndroid Build Coastguard Worker     // used bytes here (see Ganesh implementation).
814*c8dee2aaSAndroid Build Coastguard Worker }
815*c8dee2aaSAndroid Build Coastguard Worker 
isDeviceLost() const816*c8dee2aaSAndroid Build Coastguard Worker bool Context::isDeviceLost() const {
817*c8dee2aaSAndroid Build Coastguard Worker     return fSharedContext->isDeviceLost();
818*c8dee2aaSAndroid Build Coastguard Worker }
819*c8dee2aaSAndroid Build Coastguard Worker 
maxTextureSize() const820*c8dee2aaSAndroid Build Coastguard Worker int Context::maxTextureSize() const {
821*c8dee2aaSAndroid Build Coastguard Worker     return fSharedContext->caps()->maxTextureSize();
822*c8dee2aaSAndroid Build Coastguard Worker }
823*c8dee2aaSAndroid Build Coastguard Worker 
supportsProtectedContent() const824*c8dee2aaSAndroid Build Coastguard Worker bool Context::supportsProtectedContent() const {
825*c8dee2aaSAndroid Build Coastguard Worker     return fSharedContext->isProtected() == Protected::kYes;
826*c8dee2aaSAndroid Build Coastguard Worker }
827*c8dee2aaSAndroid Build Coastguard Worker 
supportedGpuStats() const828*c8dee2aaSAndroid Build Coastguard Worker GpuStatsFlags Context::supportedGpuStats() const {
829*c8dee2aaSAndroid Build Coastguard Worker     return fSharedContext->caps()->supportedGpuStats();
830*c8dee2aaSAndroid Build Coastguard Worker }
831*c8dee2aaSAndroid Build Coastguard Worker 
832*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////
833*c8dee2aaSAndroid Build Coastguard Worker 
834*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
deregisterRecorder(const Recorder * recorder)835*c8dee2aaSAndroid Build Coastguard Worker void Context::deregisterRecorder(const Recorder* recorder) {
836*c8dee2aaSAndroid Build Coastguard Worker     SkAutoMutexExclusive lock(fTestingLock);
837*c8dee2aaSAndroid Build Coastguard Worker     for (auto it = fTrackedRecorders.begin();
838*c8dee2aaSAndroid Build Coastguard Worker          it != fTrackedRecorders.end();
839*c8dee2aaSAndroid Build Coastguard Worker          it++) {
840*c8dee2aaSAndroid Build Coastguard Worker         if (*it == recorder) {
841*c8dee2aaSAndroid Build Coastguard Worker             fTrackedRecorders.erase(it);
842*c8dee2aaSAndroid Build Coastguard Worker             return;
843*c8dee2aaSAndroid Build Coastguard Worker         }
844*c8dee2aaSAndroid Build Coastguard Worker     }
845*c8dee2aaSAndroid Build Coastguard Worker }
846*c8dee2aaSAndroid Build Coastguard Worker 
readPixels(const SkPixmap & pm,const TextureProxy * textureProxy,const SkImageInfo & srcImageInfo,int srcX,int srcY)847*c8dee2aaSAndroid Build Coastguard Worker bool ContextPriv::readPixels(const SkPixmap& pm,
848*c8dee2aaSAndroid Build Coastguard Worker                              const TextureProxy* textureProxy,
849*c8dee2aaSAndroid Build Coastguard Worker                              const SkImageInfo& srcImageInfo,
850*c8dee2aaSAndroid Build Coastguard Worker                              int srcX, int srcY) {
851*c8dee2aaSAndroid Build Coastguard Worker     auto rect = SkIRect::MakeXYWH(srcX, srcY, pm.width(), pm.height());
852*c8dee2aaSAndroid Build Coastguard Worker     struct AsyncContext {
853*c8dee2aaSAndroid Build Coastguard Worker         bool fCalled = false;
854*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<const SkImage::AsyncReadResult> fResult;
855*c8dee2aaSAndroid Build Coastguard Worker     } asyncContext;
856*c8dee2aaSAndroid Build Coastguard Worker 
857*c8dee2aaSAndroid Build Coastguard Worker     auto asyncCallback = [](void* c, std::unique_ptr<const SkImage::AsyncReadResult> out) {
858*c8dee2aaSAndroid Build Coastguard Worker         auto context = static_cast<AsyncContext*>(c);
859*c8dee2aaSAndroid Build Coastguard Worker         context->fResult = std::move(out);
860*c8dee2aaSAndroid Build Coastguard Worker         context->fCalled = true;
861*c8dee2aaSAndroid Build Coastguard Worker     };
862*c8dee2aaSAndroid Build Coastguard Worker 
863*c8dee2aaSAndroid Build Coastguard Worker     const SkColorInfo& srcColorInfo = srcImageInfo.colorInfo();
864*c8dee2aaSAndroid Build Coastguard Worker 
865*c8dee2aaSAndroid Build Coastguard Worker     // This is roughly equivalent to the logic taken in asyncRescaleAndRead(SkSurface) to either
866*c8dee2aaSAndroid Build Coastguard Worker     // try the image-based readback (with copy-as-draw fallbacks) or read the texture directly
867*c8dee2aaSAndroid Build Coastguard Worker     // if it supports reading.
868*c8dee2aaSAndroid Build Coastguard Worker     if (!fContext->fSharedContext->caps()->supportsReadPixels(textureProxy->textureInfo())) {
869*c8dee2aaSAndroid Build Coastguard Worker         // Since this is a synchronous testing-only API, callers should have flushed any pending
870*c8dee2aaSAndroid Build Coastguard Worker         // work that modifies this texture proxy already. This means we don't have to worry about
871*c8dee2aaSAndroid Build Coastguard Worker         // re-wrapping the proxy in a new Image (that wouldn't tbe connected to any Device, etc.).
872*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkImage> image{new Image(TextureProxyView(sk_ref_sp(textureProxy)), srcColorInfo)};
873*c8dee2aaSAndroid Build Coastguard Worker         Context::AsyncParams<SkImage> params {image.get(), rect, pm.info(),
874*c8dee2aaSAndroid Build Coastguard Worker                                               asyncCallback, &asyncContext};
875*c8dee2aaSAndroid Build Coastguard Worker         if (!params.validate()) {
876*c8dee2aaSAndroid Build Coastguard Worker             params.fail();
877*c8dee2aaSAndroid Build Coastguard Worker         } else {
878*c8dee2aaSAndroid Build Coastguard Worker             fContext->asyncReadPixels(/*recorder=*/nullptr, params);
879*c8dee2aaSAndroid Build Coastguard Worker         }
880*c8dee2aaSAndroid Build Coastguard Worker     } else {
881*c8dee2aaSAndroid Build Coastguard Worker         fContext->asyncReadTexture(/*recorder=*/nullptr,
882*c8dee2aaSAndroid Build Coastguard Worker                                    {textureProxy, rect, pm.info(), asyncCallback, &asyncContext},
883*c8dee2aaSAndroid Build Coastguard Worker                                    srcImageInfo.colorInfo());
884*c8dee2aaSAndroid Build Coastguard Worker     }
885*c8dee2aaSAndroid Build Coastguard Worker 
886*c8dee2aaSAndroid Build Coastguard Worker     if (fContext->fSharedContext->caps()->allowCpuSync()) {
887*c8dee2aaSAndroid Build Coastguard Worker         fContext->submit(SyncToCpu::kYes);
888*c8dee2aaSAndroid Build Coastguard Worker     } else {
889*c8dee2aaSAndroid Build Coastguard Worker         fContext->submit(SyncToCpu::kNo);
890*c8dee2aaSAndroid Build Coastguard Worker         if (fContext->fSharedContext->backend() == BackendApi::kDawn) {
891*c8dee2aaSAndroid Build Coastguard Worker             while (!asyncContext.fCalled) {
892*c8dee2aaSAndroid Build Coastguard Worker                 fContext->fSharedContext->deviceTick(fContext);
893*c8dee2aaSAndroid Build Coastguard Worker             }
894*c8dee2aaSAndroid Build Coastguard Worker         } else {
895*c8dee2aaSAndroid Build Coastguard Worker             SK_ABORT("Only Dawn supports non-syncing contexts.");
896*c8dee2aaSAndroid Build Coastguard Worker         }
897*c8dee2aaSAndroid Build Coastguard Worker     }
898*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(asyncContext.fCalled);
899*c8dee2aaSAndroid Build Coastguard Worker     if (!asyncContext.fResult) {
900*c8dee2aaSAndroid Build Coastguard Worker         return false;
901*c8dee2aaSAndroid Build Coastguard Worker     }
902*c8dee2aaSAndroid Build Coastguard Worker     SkRectMemcpy(pm.writable_addr(), pm.rowBytes(), asyncContext.fResult->data(0),
903*c8dee2aaSAndroid Build Coastguard Worker                  asyncContext.fResult->rowBytes(0), pm.info().minRowBytes(),
904*c8dee2aaSAndroid Build Coastguard Worker                  pm.height());
905*c8dee2aaSAndroid Build Coastguard Worker     return true;
906*c8dee2aaSAndroid Build Coastguard Worker }
907*c8dee2aaSAndroid Build Coastguard Worker 
supportsPathRendererStrategy(PathRendererStrategy strategy)908*c8dee2aaSAndroid Build Coastguard Worker bool ContextPriv::supportsPathRendererStrategy(PathRendererStrategy strategy) {
909*c8dee2aaSAndroid Build Coastguard Worker     AtlasProvider::PathAtlasFlagsBitMask pathAtlasFlags =
910*c8dee2aaSAndroid Build Coastguard Worker             AtlasProvider::QueryPathAtlasSupport(this->caps());
911*c8dee2aaSAndroid Build Coastguard Worker     switch (strategy) {
912*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kDefault:
913*c8dee2aaSAndroid Build Coastguard Worker             return true;
914*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kComputeAnalyticAA:
915*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kComputeMSAA16:
916*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kComputeMSAA8:
917*c8dee2aaSAndroid Build Coastguard Worker             return SkToBool(pathAtlasFlags & AtlasProvider::PathAtlasFlags::kCompute);
918*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kRasterAA:
919*c8dee2aaSAndroid Build Coastguard Worker             return SkToBool(pathAtlasFlags & AtlasProvider::PathAtlasFlags::kRaster);
920*c8dee2aaSAndroid Build Coastguard Worker         case PathRendererStrategy::kTessellation:
921*c8dee2aaSAndroid Build Coastguard Worker             return true;
922*c8dee2aaSAndroid Build Coastguard Worker     }
923*c8dee2aaSAndroid Build Coastguard Worker 
924*c8dee2aaSAndroid Build Coastguard Worker     return false;
925*c8dee2aaSAndroid Build Coastguard Worker }
926*c8dee2aaSAndroid Build Coastguard Worker 
927*c8dee2aaSAndroid Build Coastguard Worker #endif // GPU_TEST_UTILS
928*c8dee2aaSAndroid Build Coastguard Worker 
929*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////
930*c8dee2aaSAndroid Build Coastguard Worker 
MakeContext(sk_sp<SharedContext> sharedContext,std::unique_ptr<QueueManager> queueManager,const ContextOptions & options)931*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Context> ContextCtorAccessor::MakeContext(
932*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SharedContext> sharedContext,
933*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<QueueManager> queueManager,
934*c8dee2aaSAndroid Build Coastguard Worker         const ContextOptions& options) {
935*c8dee2aaSAndroid Build Coastguard Worker     auto context = std::unique_ptr<Context>(new Context(std::move(sharedContext),
936*c8dee2aaSAndroid Build Coastguard Worker                                                         std::move(queueManager),
937*c8dee2aaSAndroid Build Coastguard Worker                                                         options));
938*c8dee2aaSAndroid Build Coastguard Worker     if (context && context->finishInitialization()) {
939*c8dee2aaSAndroid Build Coastguard Worker         return context;
940*c8dee2aaSAndroid Build Coastguard Worker     } else {
941*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
942*c8dee2aaSAndroid Build Coastguard Worker     }
943*c8dee2aaSAndroid Build Coastguard Worker }
944*c8dee2aaSAndroid Build Coastguard Worker 
945*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
946