• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrDirectContext_DEFINED
9 #define GrDirectContext_DEFINED
10 
11 #include "include/gpu/GrRecordingContext.h"
12 
13 #include "include/gpu/GrBackendSurface.h"
14 
15 // We shouldn't need this but currently Android is relying on this being include transitively.
16 #include "include/core/SkUnPreMultiply.h"
17 
18 class GrAtlasManager;
19 class GrBackendSemaphore;
20 class GrClientMappedBufferManager;
21 class GrDirectContextPriv;
22 class GrContextThreadSafeProxy;
23 struct GrD3DBackendContext;
24 class GrFragmentProcessor;
25 class GrGpu;
26 struct GrGLInterface;
27 struct GrMtlBackendContext;
28 struct GrMockOptions;
29 class GrPath;
30 class GrResourceCache;
31 class GrResourceProvider;
32 class GrSurfaceProxy;
33 class GrTextureProxy;
34 struct GrVkBackendContext;
35 
36 class SkImage;
37 class SkString;
38 class SkSurfaceCharacterization;
39 class SkSurfaceProps;
40 class SkTaskGroup;
41 class SkTraceMemoryDump;
42 
43 namespace skgpu {
44 class Swizzle;
45 #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
46 namespace v1 { class SmallPathAtlasMgr; }
47 #endif
48 }
49 
50 namespace sktext::gpu {
51 class StrikeCache;
52 }
53 
54 class SK_API GrDirectContext : public GrRecordingContext {
55 public:
56 #ifdef SK_GL
57     /**
58      * Creates a GrDirectContext for a backend context. If no GrGLInterface is provided then the
59      * result of GrGLMakeNativeInterface() is used if it succeeds.
60      */
61     static sk_sp<GrDirectContext> MakeGL(sk_sp<const GrGLInterface>, const GrContextOptions&);
62     static sk_sp<GrDirectContext> MakeGL(sk_sp<const GrGLInterface>);
63     static sk_sp<GrDirectContext> MakeGL(const GrContextOptions&);
64     static sk_sp<GrDirectContext> MakeGL();
65 #endif
66 
67 #ifdef SK_VULKAN
68     /**
69      * The Vulkan context (VkQueue, VkDevice, VkInstance) must be kept alive until the returned
70      * GrDirectContext is destroyed. This also means that any objects created with this
71      * GrDirectContext (e.g. SkSurfaces, SkImages, etc.) must also be released as they may hold
72      * refs on the GrDirectContext. Once all these objects and the GrDirectContext are released,
73      * then it is safe to delete the vulkan objects.
74      */
75     static sk_sp<GrDirectContext> MakeVulkan(const GrVkBackendContext&, const GrContextOptions&);
76     static sk_sp<GrDirectContext> MakeVulkan(const GrVkBackendContext&);
77 #endif
78 
79 #ifdef SK_METAL
80     /**
81      * Makes a GrDirectContext which uses Metal as the backend. The GrMtlBackendContext contains a
82      * MTLDevice and MTLCommandQueue which should be used by the backend. These objects must
83      * have their own ref which will be released when the GrMtlBackendContext is destroyed.
84      * Ganesh will take its own ref on the objects which will be released when the GrDirectContext
85      * is destroyed.
86      */
87     static sk_sp<GrDirectContext> MakeMetal(const GrMtlBackendContext&, const GrContextOptions&);
88     static sk_sp<GrDirectContext> MakeMetal(const GrMtlBackendContext&);
89     /**
90      * Deprecated.
91      *
92      * Makes a GrDirectContext which uses Metal as the backend. The device parameter is an
93      * MTLDevice and queue is an MTLCommandQueue which should be used by the backend. These objects
94      * must have a ref on them that can be transferred to Ganesh, which will release the ref
95      * when the GrDirectContext is destroyed.
96      */
97     static sk_sp<GrDirectContext> MakeMetal(void* device, void* queue, const GrContextOptions&);
98     static sk_sp<GrDirectContext> MakeMetal(void* device, void* queue);
99 #endif
100 
101 #ifdef SK_DIRECT3D
102     /**
103      * Makes a GrDirectContext which uses Direct3D as the backend. The Direct3D context
104      * must be kept alive until the returned GrDirectContext is first destroyed or abandoned.
105      */
106     static sk_sp<GrDirectContext> MakeDirect3D(const GrD3DBackendContext&, const GrContextOptions&);
107     static sk_sp<GrDirectContext> MakeDirect3D(const GrD3DBackendContext&);
108 #endif
109 
110 #ifdef SK_DAWN
111     static sk_sp<GrDirectContext> MakeDawn(const wgpu::Device&,
112                                            const GrContextOptions&);
113     static sk_sp<GrDirectContext> MakeDawn(const wgpu::Device&);
114 #endif
115 
116     static sk_sp<GrDirectContext> MakeMock(const GrMockOptions*, const GrContextOptions&);
117     static sk_sp<GrDirectContext> MakeMock(const GrMockOptions*);
118 
119     ~GrDirectContext() override;
120 
121     /**
122      * The context normally assumes that no outsider is setting state
123      * within the underlying 3D API's context/device/whatever. This call informs
124      * the context that the state was modified and it should resend. Shouldn't
125      * be called frequently for good performance.
126      * The flag bits, state, is dependent on which backend is used by the
127      * context, either GL or D3D (possible in future).
128      */
129     void resetContext(uint32_t state = kAll_GrBackendState);
130 
131     /**
132      * If the backend is GrBackendApi::kOpenGL, then all texture unit/target combinations for which
133      * the context has modified the bound texture will have texture id 0 bound. This does not
134      * flush the context. Calling resetContext() does not change the set that will be bound
135      * to texture id 0 on the next call to resetGLTextureBindings(). After this is called
136      * all unit/target combinations are considered to have unmodified bindings until the context
137      * subsequently modifies them (meaning if this is called twice in a row with no intervening
138      * context usage then the second call is a no-op.)
139      */
140     void resetGLTextureBindings();
141 
142     /**
143      * Abandons all GPU resources and assumes the underlying backend 3D API context is no longer
144      * usable. Call this if you have lost the associated GPU context, and thus internal texture,
145      * buffer, etc. references/IDs are now invalid. Calling this ensures that the destructors of the
146      * context and any of its created resource objects will not make backend 3D API calls. Content
147      * rendered but not previously flushed may be lost. After this function is called all subsequent
148      * calls on the context will fail or be no-ops.
149      *
150      * The typical use case for this function is that the underlying 3D context was lost and further
151      * API calls may crash.
152      *
153      * This call is not valid to be made inside ReleaseProcs passed into SkSurface or SkImages. The
154      * call will simply fail (and assert in debug) if it is called while inside a ReleaseProc.
155      *
156      * For Vulkan, even if the device becomes lost, the VkQueue, VkDevice, or VkInstance used to
157      * create the context must be kept alive even after abandoning the context. Those objects must
158      * live for the lifetime of the context object itself. The reason for this is so that
159      * we can continue to delete any outstanding GrBackendTextures/RenderTargets which must be
160      * cleaned up even in a device lost state.
161      */
162     void abandonContext() override;
163 
164     /**
165      * Returns true if the context was abandoned or if the if the backend specific context has
166      * gotten into an unrecoverarble, lost state (e.g. in Vulkan backend if we've gotten a
167      * VK_ERROR_DEVICE_LOST). If the backend context is lost, this call will also abandon this
168      * context.
169      */
170     bool abandoned() override;
171 
172     // TODO: Remove this from public after migrating Chrome.
173     sk_sp<GrContextThreadSafeProxy> threadSafeProxy();
174 
175     /**
176      * Checks if the underlying 3D API reported an out-of-memory error. If this returns true it is
177      * reset and will return false until another out-of-memory error is reported by the 3D API. If
178      * the context is abandoned then this will report false.
179      *
180      * Currently this is implemented for:
181      *
182      * OpenGL [ES] - Note that client calls to glGetError() may swallow GL_OUT_OF_MEMORY errors and
183      * therefore hide the error from Skia. Also, it is not advised to use this in combination with
184      * enabling GrContextOptions::fSkipGLErrorChecks. That option may prevent the context from ever
185      * checking the GL context for OOM.
186      *
187      * Vulkan - Reports true if VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY has
188      * occurred.
189      */
190     bool oomed();
191 
192     /**
193      * This is similar to abandonContext() however the underlying 3D context is not yet lost and
194      * the context will cleanup all allocated resources before returning. After returning it will
195      * assume that the underlying context may no longer be valid.
196      *
197      * The typical use case for this function is that the client is going to destroy the 3D context
198      * but can't guarantee that context will be destroyed first (perhaps because it may be ref'ed
199      * elsewhere by either the client or Skia objects).
200      *
201      * For Vulkan, even if the device becomes lost, the VkQueue, VkDevice, or VkInstance used to
202      * create the context must be alive before calling releaseResourcesAndAbandonContext.
203      */
204     void releaseResourcesAndAbandonContext();
205 
206     ///////////////////////////////////////////////////////////////////////////
207     // Resource Cache
208 
209     /** DEPRECATED
210      *  Return the current GPU resource cache limits.
211      *
212      *  @param maxResources If non-null, will be set to -1.
213      *  @param maxResourceBytes If non-null, returns maximum number of bytes of
214      *                          video memory that can be held in the cache.
215      */
216     void getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const;
217 
218     /**
219      *  Return the current GPU resource cache limit in bytes.
220      */
221     size_t getResourceCacheLimit() const;
222 
223     /**
224      *  Gets the current GPU resource cache usage.
225      *
226      *  @param resourceCount If non-null, returns the number of resources that are held in the
227      *                       cache.
228      *  @param maxResourceBytes If non-null, returns the total number of bytes of video memory held
229      *                          in the cache.
230      */
231     void getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const;
232 
233     /**
234      *  Gets the number of bytes in the cache consumed by purgeable (e.g. unlocked) resources.
235      */
236     size_t getResourceCachePurgeableBytes() const;
237 
238     /** DEPRECATED
239      *  Specify the GPU resource cache limits. If the current cache exceeds the maxResourceBytes
240      *  limit, it will be purged (LRU) to keep the cache within the limit.
241      *
242      *  @param maxResources Unused.
243      *  @param maxResourceBytes The maximum number of bytes of video memory
244      *                          that can be held in the cache.
245      */
246     void setResourceCacheLimits(int maxResources, size_t maxResourceBytes);
247 
248     /**
249      *  Specify the GPU resource cache limit. If the cache currently exceeds this limit,
250      *  it will be purged (LRU) to keep the cache within the limit.
251      *
252      *  @param maxResourceBytes The maximum number of bytes of video memory
253      *                          that can be held in the cache.
254      */
255     void setResourceCacheLimit(size_t maxResourceBytes);
256 
257     /**
258      * Frees GPU created by the context. Can be called to reduce GPU memory
259      * pressure.
260      */
261     void freeGpuResources();
262 
263     /**
264      * Purge GPU resources that haven't been used in the past 'msNotUsed' milliseconds or are
265      * otherwise marked for deletion, regardless of whether the context is under budget.
266      *
267      * If 'scratchResourcesOnly' is true all unlocked scratch resources older than 'msNotUsed' will
268      * be purged but the unlocked resources with persistent data will remain. If
269      * 'scratchResourcesOnly' is false then all unlocked resources older than 'msNotUsed' will be
270      * purged.
271      *
272      * @param msNotUsed              Only unlocked resources not used in these last milliseconds
273      *                               will be cleaned up.
274      * @param scratchResourcesOnly   If true only unlocked scratch resources will be purged.
275      */
276     void performDeferredCleanup(std::chrono::milliseconds msNotUsed,
277                                 bool scratchResourcesOnly=false);
278 
279     // Temporary compatibility API for Android.
purgeResourcesNotUsedInMs(std::chrono::milliseconds msNotUsed)280     void purgeResourcesNotUsedInMs(std::chrono::milliseconds msNotUsed) {
281         this->performDeferredCleanup(msNotUsed);
282     }
283 
284     /**
285      * Purge unlocked resources from the cache until the the provided byte count has been reached
286      * or we have purged all unlocked resources. The default policy is to purge in LRU order, but
287      * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other
288      * resource types.
289      *
290      * @param maxBytesToPurge the desired number of bytes to be purged.
291      * @param preferScratchResources If true scratch resources will be purged prior to other
292      *                               resource types.
293      */
294     void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources);
295 
296     /**
297      * This entry point is intended for instances where an app has been backgrounded or
298      * suspended.
299      * If 'scratchResourcesOnly' is true all unlocked scratch resources will be purged but the
300      * unlocked resources with persistent data will remain. If 'scratchResourcesOnly' is false
301      * then all unlocked resources will be purged.
302      * In either case, after the unlocked resources are purged a separate pass will be made to
303      * ensure that resource usage is under budget (i.e., even if 'scratchResourcesOnly' is true
304      * some resources with persistent data may be purged to be under budget).
305      *
306      * @param scratchResourcesOnly   If true only unlocked scratch resources will be purged prior
307      *                               enforcing the budget requirements.
308      */
309     void purgeUnlockedResources(bool scratchResourcesOnly);
310 
311     /**
312      * Gets the maximum supported texture size.
313      */
314     using GrRecordingContext::maxTextureSize;
315 
316     /**
317      * Gets the maximum supported render target size.
318      */
319     using GrRecordingContext::maxRenderTargetSize;
320 
321     /**
322      * Can a SkImage be created with the given color type.
323      */
324     using GrRecordingContext::colorTypeSupportedAsImage;
325 
326     /**
327      * Can a SkSurface be created with the given color type. To check whether MSAA is supported
328      * use maxSurfaceSampleCountForColorType().
329      */
330     using GrRecordingContext::colorTypeSupportedAsSurface;
331 
332     /**
333      * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA
334      * rendering is supported for the color type. 0 is returned if rendering to this color type
335      * is not supported at all.
336      */
337     using GrRecordingContext::maxSurfaceSampleCountForColorType;
338 
339     ///////////////////////////////////////////////////////////////////////////
340     // Misc.
341 
342     /**
343      * Inserts a list of GPU semaphores that the current GPU-backed API must wait on before
344      * executing any more commands on the GPU. If this call returns false, then the GPU back-end
345      * will not wait on any passed in semaphores, and the client will still own the semaphores,
346      * regardless of the value of deleteSemaphoresAfterWait.
347      *
348      * If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case
349      * it is the client's responsibility to not destroy or attempt to reuse the semaphores until it
350      * knows that Skia has finished waiting on them. This can be done by using finishedProcs on
351      * flush calls.
352      */
353     bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores,
354               bool deleteSemaphoresAfterWait = true);
355 
356     /**
357      * Call to ensure all drawing to the context has been flushed and submitted to the underlying 3D
358      * API. This is equivalent to calling GrContext::flush with a default GrFlushInfo followed by
359      * GrContext::submit(syncCpu).
360      */
361     void flushAndSubmit(bool syncCpu = false) {
362         this->flush(GrFlushInfo());
363         this->submit(syncCpu);
364     }
365 
366     /**
367      * Call to ensure all drawing to the context has been flushed to underlying 3D API specific
368      * objects. A call to `submit` is always required to ensure work is actually sent to
369      * the gpu. Some specific API details:
370      *     GL: Commands are actually sent to the driver, but glFlush is never called. Thus some
371      *         sync objects from the flush will not be valid until a submission occurs.
372      *
373      *     Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command
374      *         buffer or encoder objects. However, these objects are not sent to the gpu until a
375      *         submission occurs.
376      *
377      * If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be
378      * submitted to the gpu during the next submit call (it is possible Skia failed to create a
379      * subset of the semaphores). The client should not wait on these semaphores until after submit
380      * has been called, and must keep them alive until then. If this call returns
381      * GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on
382      * the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in with
383      * the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the
384      * client is still responsible for deleting any initialized semaphores.
385      * Regardleess of semaphore submission the context will still be flushed. It should be
386      * emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not
387      * happen. It simply means there were no semaphores submitted to the GPU. A caller should only
388      * take this as a failure if they passed in semaphores to be submitted.
389      */
390     GrSemaphoresSubmitted flush(const GrFlushInfo& info);
391 
flush()392     void flush() { this->flush({}); }
393 
394     /**
395      * Submit outstanding work to the gpu from all previously un-submitted flushes. The return
396      * value of the submit will indicate whether or not the submission to the GPU was successful.
397      *
398      * If the call returns true, all previously passed in semaphores in flush calls will have been
399      * submitted to the GPU and they can safely be waited on. The caller should wait on those
400      * semaphores or perform some other global synchronization before deleting the semaphores.
401      *
402      * If it returns false, then those same semaphores will not have been submitted and we will not
403      * try to submit them again. The caller is free to delete the semaphores at any time.
404      *
405      * If the syncCpu flag is true this function will return once the gpu has finished with all
406      * submitted work.
407      */
408     bool submit(bool syncCpu = false);
409 
410     /**
411      * Checks whether any asynchronous work is complete and if so calls related callbacks.
412      */
413     void checkAsyncWorkCompletion();
414 
415     /** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */
416     // Chrome is using this!
417     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
418 
419     bool supportsDistanceFieldText() const;
420 
421     void storeVkPipelineCacheData();
422 
423     /**
424      * Retrieve the default GrBackendFormat for a given SkColorType and renderability.
425      * It is guaranteed that this backend format will be the one used by the following
426      * SkColorType and SkSurfaceCharacterization-based createBackendTexture methods.
427      *
428      * The caller should check that the returned format is valid.
429      */
430     using GrRecordingContext::defaultBackendFormat;
431 
432     /**
433      * The explicitly allocated backend texture API allows clients to use Skia to create backend
434      * objects outside of Skia proper (i.e., Skia's caching system will not know about them.)
435      *
436      * It is the client's responsibility to delete all these objects (using deleteBackendTexture)
437      * before deleting the context used to create them. If the backend is Vulkan, the textures must
438      * be deleted before abandoning the context as well. Additionally, clients should only delete
439      * these objects on the thread for which that context is active.
440      *
441      * The client is responsible for ensuring synchronization between different uses
442      * of the backend object (i.e., wrapping it in a surface, rendering to it, deleting the
443      * surface, rewrapping it in a image and drawing the image will require explicit
444      * synchronization on the client's part).
445      */
446 
447      /**
448       * If possible, create an uninitialized backend texture. The client should ensure that the
449       * returned backend texture is valid.
450       * For the Vulkan backend the layout of the created VkImage will be:
451       *      VK_IMAGE_LAYOUT_UNDEFINED.
452       */
453     GrBackendTexture createBackendTexture(int width,
454                                           int height,
455                                           const GrBackendFormat&,
456                                           GrMipmapped,
457                                           GrRenderable,
458                                           GrProtected = GrProtected::kNo,
459                                           std::string_view label = {});
460 
461      /**
462       * If possible, create an uninitialized backend texture. The client should ensure that the
463       * returned backend texture is valid.
464       * If successful, the created backend texture will be compatible with the provided
465       * SkColorType.
466       * For the Vulkan backend the layout of the created VkImage will be:
467       *      VK_IMAGE_LAYOUT_UNDEFINED.
468       */
469      GrBackendTexture createBackendTexture(int width, int height,
470                                            SkColorType,
471                                            GrMipmapped,
472                                            GrRenderable,
473                                            GrProtected = GrProtected::kNo,
474                                            std::string_view label = {});
475 
476      /**
477       * If possible, create a backend texture initialized to a particular color. The client should
478       * ensure that the returned backend texture is valid. The client can pass in a finishedProc
479       * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The
480       * client is required to call `submit` to send the upload work to the gpu. The
481       * finishedProc will always get called even if we failed to create the GrBackendTexture.
482       * For the Vulkan backend the layout of the created VkImage will be:
483       *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
484       */
485      GrBackendTexture createBackendTexture(int width, int height,
486                                            const GrBackendFormat&,
487                                            const SkColor4f& color,
488                                            GrMipmapped,
489                                            GrRenderable,
490                                            GrProtected = GrProtected::kNo,
491                                            GrGpuFinishedProc finishedProc = nullptr,
492                                            GrGpuFinishedContext finishedContext = nullptr,
493                                            std::string_view label = {});
494 
495      /**
496       * If possible, create a backend texture initialized to a particular color. The client should
497       * ensure that the returned backend texture is valid. The client can pass in a finishedProc
498       * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The
499       * client is required to call `submit` to send the upload work to the gpu. The
500       * finishedProc will always get called even if we failed to create the GrBackendTexture.
501       * If successful, the created backend texture will be compatible with the provided
502       * SkColorType.
503       * For the Vulkan backend the layout of the created VkImage will be:
504       *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
505       */
506      GrBackendTexture createBackendTexture(int width, int height,
507                                            SkColorType,
508                                            const SkColor4f& color,
509                                            GrMipmapped,
510                                            GrRenderable,
511                                            GrProtected = GrProtected::kNo,
512                                            GrGpuFinishedProc finishedProc = nullptr,
513                                            GrGpuFinishedContext finishedContext = nullptr,
514                                            std::string_view label = {});
515 
516      /**
517       * If possible, create a backend texture initialized with the provided pixmap data. The client
518       * should ensure that the returned backend texture is valid. The client can pass in a
519       * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
520       * deleted. The client is required to call `submit` to send the upload work to the gpu.
521       * The finishedProc will always get called even if we failed to create the GrBackendTexture.
522       * If successful, the created backend texture will be compatible with the provided
523       * pixmap(s). Compatible, in this case, means that the backend format will be the result
524       * of calling defaultBackendFormat on the base pixmap's colortype. The src data can be deleted
525       * when this call returns.
526       * If numLevels is 1 a non-mipmapped texture will result. If a mipmapped texture is desired
527       * the data for all the mipmap levels must be provided. In the mipmapped case all the
528       * colortypes of the provided pixmaps must be the same. Additionally, all the miplevels
529       * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount). The
530       * GrSurfaceOrigin controls whether the pixmap data is vertically flipped in the texture.
531       * Note: the pixmap's alphatypes and colorspaces are ignored.
532       * For the Vulkan backend the layout of the created VkImage will be:
533       *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
534       */
535      GrBackendTexture createBackendTexture(const SkPixmap srcData[],
536                                            int numLevels,
537                                            GrSurfaceOrigin,
538                                            GrRenderable,
539                                            GrProtected,
540                                            GrGpuFinishedProc finishedProc = nullptr,
541                                            GrGpuFinishedContext finishedContext = nullptr,
542                                            std::string_view label = {});
543 
544     /**
545      * Convenience version createBackendTexture() that takes just a base level pixmap.
546      */
547      GrBackendTexture createBackendTexture(const SkPixmap& srcData,
548                                            GrSurfaceOrigin textureOrigin,
549                                            GrRenderable renderable,
550                                            GrProtected isProtected,
551                                            GrGpuFinishedProc finishedProc = nullptr,
552                                            GrGpuFinishedContext finishedContext = nullptr,
553                                            std::string_view label = {}) {
554          return this->createBackendTexture(&srcData, 1, textureOrigin, renderable, isProtected,
555                                            finishedProc, finishedContext, label);
556      }
557 
558     // Deprecated versions that do not take origin and assume top-left.
559     GrBackendTexture createBackendTexture(const SkPixmap srcData[],
560                                           int numLevels,
561                                           GrRenderable renderable,
562                                           GrProtected isProtected,
563                                           GrGpuFinishedProc finishedProc = nullptr,
564                                           GrGpuFinishedContext finishedContext = nullptr,
565                                           std::string_view label = {}) {
566         return this->createBackendTexture(srcData,
567                                           numLevels,
568                                           kTopLeft_GrSurfaceOrigin,
569                                           renderable,
570                                           isProtected,
571                                           finishedProc,
572                                           finishedContext,
573                                           label);
574     }
575     GrBackendTexture createBackendTexture(const SkPixmap& srcData,
576                                           GrRenderable renderable,
577                                           GrProtected isProtected,
578                                           GrGpuFinishedProc finishedProc = nullptr,
579                                           GrGpuFinishedContext finishedContext = nullptr,
580                                           std::string_view label = {}) {
581         return this->createBackendTexture(&srcData,
582                                           1,
583                                           renderable,
584                                           isProtected,
585                                           finishedProc,
586                                           finishedContext,
587                                           label);
588     }
589 
590     /**
591      * If possible, updates a backend texture to be filled to a particular color. The client should
592      * check the return value to see if the update was successful. The client can pass in a
593      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
594      * deleted. The client is required to call `submit` to send the upload work to the gpu.
595      * The finishedProc will always get called even if we failed to update the GrBackendTexture.
596      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
597      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
598      */
599     bool updateBackendTexture(const GrBackendTexture&,
600                               const SkColor4f& color,
601                               GrGpuFinishedProc finishedProc,
602                               GrGpuFinishedContext finishedContext);
603 
604     /**
605      * If possible, updates a backend texture to be filled to a particular color. The data in
606      * GrBackendTexture and passed in color is interpreted with respect to the passed in
607      * SkColorType. The client should check the return value to see if the update was successful.
608      * The client can pass in a finishedProc to be notified when the data has been uploaded by the
609      * gpu and the texture can be deleted. The client is required to call `submit` to send
610      * the upload work to the gpu. The finishedProc will always get called even if we failed to
611      * update the GrBackendTexture.
612      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
613      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
614      */
615     bool updateBackendTexture(const GrBackendTexture&,
616                               SkColorType skColorType,
617                               const SkColor4f& color,
618                               GrGpuFinishedProc finishedProc,
619                               GrGpuFinishedContext finishedContext);
620 
621     /**
622      * If possible, updates a backend texture filled with the provided pixmap data. The client
623      * should check the return value to see if the update was successful. The client can pass in a
624      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
625      * deleted. The client is required to call `submit` to send the upload work to the gpu.
626      * The finishedProc will always get called even if we failed to create the GrBackendTexture.
627      * The backend texture must be compatible with the provided pixmap(s). Compatible, in this case,
628      * means that the backend format is compatible with the base pixmap's colortype. The src data
629      * can be deleted when this call returns.
630      * If the backend texture is mip mapped, the data for all the mipmap levels must be provided.
631      * In the mipmapped case all the colortypes of the provided pixmaps must be the same.
632      * Additionally, all the miplevels must be sized correctly (please see
633      * SkMipmap::ComputeLevelSize and ComputeLevelCount). The GrSurfaceOrigin controls whether the
634      * pixmap data is vertically flipped in the texture.
635      * Note: the pixmap's alphatypes and colorspaces are ignored.
636      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
637      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
638      */
639     bool updateBackendTexture(const GrBackendTexture&,
640                               const SkPixmap srcData[],
641                               int numLevels,
642                               GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin,
643                               GrGpuFinishedProc finishedProc = nullptr,
644                               GrGpuFinishedContext finishedContext = nullptr);
645 
646     /**
647      * Convenience version of updateBackendTexture that takes just a base level pixmap.
648      */
649     bool updateBackendTexture(const GrBackendTexture& texture,
650                               const SkPixmap& srcData,
651                               GrSurfaceOrigin textureOrigin = kTopLeft_GrSurfaceOrigin,
652                               GrGpuFinishedProc finishedProc = nullptr,
653                               GrGpuFinishedContext finishedContext = nullptr) {
654         return this->updateBackendTexture(texture,
655                                           &srcData,
656                                           1,
657                                           textureOrigin,
658                                           finishedProc,
659                                           finishedContext);
660     }
661 
662     // Deprecated version that does not take origin and assumes top-left.
updateBackendTexture(const GrBackendTexture & texture,const SkPixmap srcData[],int numLevels,GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)663     bool updateBackendTexture(const GrBackendTexture& texture,
664                              const SkPixmap srcData[],
665                              int numLevels,
666                              GrGpuFinishedProc finishedProc,
667                              GrGpuFinishedContext finishedContext) {
668         return this->updateBackendTexture(texture,
669                                           srcData,
670                                           numLevels,
671                                           kTopLeft_GrSurfaceOrigin,
672                                           finishedProc,
673                                           finishedContext);
674     }
675 
676     /**
677      * Retrieve the GrBackendFormat for a given SkImage::CompressionType. This is
678      * guaranteed to match the backend format used by the following
679      * createCompressedBackendTexture methods that take a CompressionType.
680      *
681      * The caller should check that the returned format is valid.
682      */
683     using GrRecordingContext::compressedBackendFormat;
684 
685     /**
686      *If possible, create a compressed backend texture initialized to a particular color. The
687      * client should ensure that the returned backend texture is valid. The client can pass in a
688      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
689      * deleted. The client is required to call `submit` to send the upload work to the gpu.
690      * The finishedProc will always get called even if we failed to create the GrBackendTexture.
691      * For the Vulkan backend the layout of the created VkImage will be:
692      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
693      */
694     GrBackendTexture createCompressedBackendTexture(int width, int height,
695                                                     const GrBackendFormat&,
696                                                     const SkColor4f& color,
697                                                     GrMipmapped,
698                                                     GrProtected = GrProtected::kNo,
699                                                     GrGpuFinishedProc finishedProc = nullptr,
700                                                     GrGpuFinishedContext finishedContext = nullptr);
701 
702     GrBackendTexture createCompressedBackendTexture(int width, int height,
703                                                     SkImage::CompressionType,
704                                                     const SkColor4f& color,
705                                                     GrMipmapped,
706                                                     GrProtected = GrProtected::kNo,
707                                                     GrGpuFinishedProc finishedProc = nullptr,
708                                                     GrGpuFinishedContext finishedContext = nullptr);
709 
710     /**
711      * If possible, create a backend texture initialized with the provided raw data. The client
712      * should ensure that the returned backend texture is valid. The client can pass in a
713      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
714      * deleted. The client is required to call `submit` to send the upload work to the gpu.
715      * The finishedProc will always get called even if we failed to create the GrBackendTexture
716      * If numLevels is 1 a non-mipmapped texture will result. If a mipmapped texture is desired
717      * the data for all the mipmap levels must be provided. Additionally, all the miplevels
718      * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount).
719      * For the Vulkan backend the layout of the created VkImage will be:
720      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
721      */
722     GrBackendTexture createCompressedBackendTexture(int width, int height,
723                                                     const GrBackendFormat&,
724                                                     const void* data, size_t dataSize,
725                                                     GrMipmapped,
726                                                     GrProtected = GrProtected::kNo,
727                                                     GrGpuFinishedProc finishedProc = nullptr,
728                                                     GrGpuFinishedContext finishedContext = nullptr);
729 
730     GrBackendTexture createCompressedBackendTexture(int width, int height,
731                                                     SkImage::CompressionType,
732                                                     const void* data, size_t dataSize,
733                                                     GrMipmapped,
734                                                     GrProtected = GrProtected::kNo,
735                                                     GrGpuFinishedProc finishedProc = nullptr,
736                                                     GrGpuFinishedContext finishedContext = nullptr);
737 
738     /**
739      * If possible, updates a backend texture filled with the provided color. If the texture is
740      * mipmapped, all levels of the mip chain will be updated to have the supplied color. The client
741      * should check the return value to see if the update was successful. The client can pass in a
742      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
743      * deleted. The client is required to call `submit` to send the upload work to the gpu.
744      * The finishedProc will always get called even if we failed to create the GrBackendTexture.
745      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
746      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
747      */
748     bool updateCompressedBackendTexture(const GrBackendTexture&,
749                                         const SkColor4f& color,
750                                         GrGpuFinishedProc finishedProc,
751                                         GrGpuFinishedContext finishedContext);
752 
753     /**
754      * If possible, updates a backend texture filled with the provided raw data. The client
755      * should check the return value to see if the update was successful. The client can pass in a
756      * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
757      * deleted. The client is required to call `submit` to send the upload work to the gpu.
758      * The finishedProc will always get called even if we failed to create the GrBackendTexture.
759      * If a mipmapped texture is passed in, the data for all the mipmap levels must be provided.
760      * Additionally, all the miplevels must be sized correctly (please see
761      * SkMipMap::ComputeLevelSize and ComputeLevelCount).
762      * For the Vulkan backend after a successful update the layout of the created VkImage will be:
763      *      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
764      */
765     bool updateCompressedBackendTexture(const GrBackendTexture&,
766                                         const void* data,
767                                         size_t dataSize,
768                                         GrGpuFinishedProc finishedProc,
769                                         GrGpuFinishedContext finishedContext);
770 
771     /**
772      * Updates the state of the GrBackendTexture/RenderTarget to have the passed in
773      * skgpu::MutableTextureState. All objects that wrap the backend surface (i.e. SkSurfaces and
774      * SkImages) will also be aware of this state change. This call does not submit the state change
775      * to the gpu, but requires the client to call `submit` to send it to the GPU. The work
776      * for this call is ordered linearly with all other calls that require GrContext::submit to be
777      * called (e.g updateBackendTexture and flush). If finishedProc is not null then it will be
778      * called with finishedContext after the state transition is known to have occurred on the GPU.
779      *
780      * See skgpu::MutableTextureState to see what state can be set via this call.
781      *
782      * If the backend API is Vulkan, the caller can set the skgpu::MutableTextureState's
783      * VkImageLayout to VK_IMAGE_LAYOUT_UNDEFINED or queueFamilyIndex to VK_QUEUE_FAMILY_IGNORED to
784      * tell Skia to not change those respective states.
785      *
786      * If previousState is not null and this returns true, then Skia will have filled in
787      * previousState to have the values of the state before this call.
788      */
789     bool setBackendTextureState(const GrBackendTexture&,
790                                 const skgpu::MutableTextureState&,
791                                 skgpu::MutableTextureState* previousState = nullptr,
792                                 GrGpuFinishedProc finishedProc = nullptr,
793                                 GrGpuFinishedContext finishedContext = nullptr);
794     bool setBackendRenderTargetState(const GrBackendRenderTarget&,
795                                      const skgpu::MutableTextureState&,
796                                      skgpu::MutableTextureState* previousState = nullptr,
797                                      GrGpuFinishedProc finishedProc = nullptr,
798                                      GrGpuFinishedContext finishedContext = nullptr);
799 
800     void deleteBackendTexture(GrBackendTexture);
801 
802     // This interface allows clients to pre-compile shaders and populate the runtime program cache.
803     // The key and data blobs should be the ones passed to the PersistentCache, in SkSL format.
804     //
805     // Steps to use this API:
806     //
807     // 1) Create a GrDirectContext as normal, but set fPersistentCache on GrContextOptions to
808     //    something that will save the cached shader blobs. Set fShaderCacheStrategy to kSkSL. This
809     //    will ensure that the blobs are SkSL, and are suitable for pre-compilation.
810     // 2) Run your application, and save all of the key/data pairs that are fed to the cache.
811     //
812     // 3) Switch over to shipping your application. Include the key/data pairs from above.
813     // 4) At startup (or any convenient time), call precompileShader for each key/data pair.
814     //    This will compile the SkSL to create a GL program, and populate the runtime cache.
815     //
816     // This is only guaranteed to work if the context/device used in step #2 are created in the
817     // same way as the one used in step #4, and the same GrContextOptions are specified.
818     // Using cached shader blobs on a different device or driver are undefined.
819     bool precompileShader(const SkData& key, const SkData& data);
820 
821 #ifdef SK_ENABLE_DUMP_GPU
822     /** Returns a string with detailed information about the context & GPU, in JSON format. */
823     SkString dump() const;
824 #endif
825 
826     class DirectContextID {
827     public:
828         static GrDirectContext::DirectContextID Next();
829 
DirectContextID()830         DirectContextID() : fID(SK_InvalidUniqueID) {}
831 
832         bool operator==(const DirectContextID& that) const { return fID == that.fID; }
833         bool operator!=(const DirectContextID& that) const { return !(*this == that); }
834 
makeInvalid()835         void makeInvalid() { fID = SK_InvalidUniqueID; }
isValid()836         bool isValid() const { return fID != SK_InvalidUniqueID; }
837 
838     private:
DirectContextID(uint32_t id)839         constexpr DirectContextID(uint32_t id) : fID(id) {}
840         uint32_t fID;
841     };
842 
directContextID()843     DirectContextID directContextID() const { return fDirectContextID; }
844 
845     // Provides access to functions that aren't part of the public API.
846     GrDirectContextPriv priv();
847     const GrDirectContextPriv priv() const;  // NOLINT(readability-const-return-type)
848 
849 protected:
850     GrDirectContext(GrBackendApi backend, const GrContextOptions& options);
851 
852     bool init() override;
853 
onGetAtlasManager()854     GrAtlasManager* onGetAtlasManager() { return fAtlasManager.get(); }
855 #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
856     skgpu::v1::SmallPathAtlasMgr* onGetSmallPathAtlasMgr();
857 #endif
858 
asDirectContext()859     GrDirectContext* asDirectContext() override { return this; }
860 
861 private:
862     // This call will make sure out work on the GPU is finished and will execute any outstanding
863     // asynchronous work (e.g. calling finished procs, freeing resources, etc.) related to the
864     // outstanding work on the gpu. The main use currently for this function is when tearing down or
865     // abandoning the context.
866     //
867     // When we finish up work on the GPU it could trigger callbacks to the client. In the case we
868     // are abandoning the context we don't want the client to be able to use the GrDirectContext to
869     // issue more commands during the callback. Thus before calling this function we set the
870     // GrDirectContext's state to be abandoned. However, we need to be able to get by the abaonded
871     // check in the call to know that it is safe to execute this. The shouldExecuteWhileAbandoned
872     // bool is used for this signal.
873     void syncAllOutstandingGpuWork(bool shouldExecuteWhileAbandoned);
874 
875     // This delete callback needs to be the first thing on the GrDirectContext so that it is the
876     // last thing destroyed. The callback may signal the client to clean up things that may need
877     // to survive the lifetime of some of the other objects on the GrDirectCotnext. So make sure
878     // we don't call it until all else has been destroyed.
879     class DeleteCallbackHelper {
880     public:
DeleteCallbackHelper(GrDirectContextDestroyedContext context,GrDirectContextDestroyedProc proc)881         DeleteCallbackHelper(GrDirectContextDestroyedContext context,
882                              GrDirectContextDestroyedProc proc)
883                 : fContext(context), fProc(proc) {}
884 
~DeleteCallbackHelper()885         ~DeleteCallbackHelper() {
886             if (fProc) {
887                 fProc(fContext);
888             }
889         }
890 
891     private:
892         GrDirectContextDestroyedContext fContext;
893         GrDirectContextDestroyedProc fProc;
894     };
895     std::unique_ptr<DeleteCallbackHelper> fDeleteCallbackHelper;
896 
897     const DirectContextID                   fDirectContextID;
898     // fTaskGroup must appear before anything that uses it (e.g. fGpu), so that it is destroyed
899     // after all of its users. Clients of fTaskGroup will generally want to ensure that they call
900     // wait() on it as they are being destroyed, to avoid the possibility of pending tasks being
901     // invoked after objects they depend upon have already been destroyed.
902     std::unique_ptr<SkTaskGroup>              fTaskGroup;
903     std::unique_ptr<sktext::gpu::StrikeCache> fStrikeCache;
904     sk_sp<GrGpu>                              fGpu;
905     std::unique_ptr<GrResourceCache>          fResourceCache;
906     std::unique_ptr<GrResourceProvider>       fResourceProvider;
907 
908     // This is incremented before we start calling ReleaseProcs from GrSurfaces and decremented
909     // after. A ReleaseProc may trigger code causing another resource to get freed so we to track
910     // the count to know if we in a ReleaseProc at any level. When this is set to a value greated
911     // than zero we will not allow abandonContext calls to be made on the context.
912     int                                     fInsideReleaseProcCnt = 0;
913 
914     bool                                    fDidTestPMConversions;
915     // true if the PM/UPM conversion succeeded; false otherwise
916     bool                                    fPMUPMConversionsRoundTrip;
917 
918     GrContextOptions::PersistentCache*      fPersistentCache;
919 
920     std::unique_ptr<GrClientMappedBufferManager> fMappedBufferManager;
921     std::unique_ptr<GrAtlasManager> fAtlasManager;
922 
923 #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
924     std::unique_ptr<skgpu::v1::SmallPathAtlasMgr> fSmallPathAtlasMgr;
925 #endif
926 
927     friend class GrDirectContextPriv;
928 
929     using INHERITED = GrRecordingContext;
930 };
931 
932 
933 #endif
934