/src/skia/include/gpu/graphite/Context.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2021 Google LLC |
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 skgpu_graphite_Context_DEFINED |
9 | | #define skgpu_graphite_Context_DEFINED |
10 | | |
11 | | #include "include/core/SkImage.h" |
12 | | #include "include/core/SkRefCnt.h" |
13 | | #include "include/core/SkShader.h" |
14 | | #include "include/gpu/graphite/ContextOptions.h" |
15 | | #include "include/gpu/graphite/GraphiteTypes.h" |
16 | | #include "include/gpu/graphite/Recorder.h" |
17 | | #include "include/private/base/SingleOwner.h" |
18 | | |
19 | | #include <chrono> |
20 | | #include <functional> |
21 | | #include <memory> |
22 | | |
23 | | class SkColorSpace; |
24 | | class SkRuntimeEffect; |
25 | | class SkTraceMemoryDump; |
26 | | |
27 | | namespace skgpu::graphite { |
28 | | |
29 | | class BackendTexture; |
30 | | class Buffer; |
31 | | class ClientMappedBufferManager; |
32 | | class Context; |
33 | | class ContextPriv; |
34 | | class GlobalCache; |
35 | | class PaintOptions; |
36 | | class PlotUploadTracker; |
37 | | class QueueManager; |
38 | | class Recording; |
39 | | class ResourceProvider; |
40 | | class SharedContext; |
41 | | class TextureProxy; |
42 | | |
43 | | class SK_API Context final { |
44 | | public: |
45 | | Context(const Context&) = delete; |
46 | | Context(Context&&) = delete; |
47 | | Context& operator=(const Context&) = delete; |
48 | | Context& operator=(Context&&) = delete; |
49 | | |
50 | | ~Context(); |
51 | | |
52 | | BackendApi backend() const; |
53 | | |
54 | | std::unique_ptr<Recorder> makeRecorder(const RecorderOptions& = {}); |
55 | | |
56 | | bool insertRecording(const InsertRecordingInfo&); |
57 | | bool submit(SyncToCpu = SyncToCpu::kNo); |
58 | | |
59 | | /** Returns true if there is work that was submitted to the GPU that has not finished. */ |
60 | | bool hasUnfinishedGpuWork() const; |
61 | | |
62 | | /** Makes image pixel data available to caller, possibly asynchronously. It can also rescale |
63 | | the image pixels. |
64 | | |
65 | | Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is |
66 | | rescaled to the size indicated by 'dstImageInfo', is then converted to the color space, |
67 | | color type, and alpha type of 'dstImageInfo'. A 'srcRect' that is not contained by the |
68 | | bounds of the image causes failure. |
69 | | |
70 | | When the pixel data is ready the caller's ReadPixelsCallback is called with a |
71 | | AsyncReadResult containing pixel data in the requested color type, alpha type, and color |
72 | | space. The AsyncReadResult will have count() == 1. Upon failure the callback is called with |
73 | | nullptr for AsyncReadResult. The callback can be triggered, for example, with a call to |
74 | | Context::submit(SyncToCpu::kYes). |
75 | | |
76 | | The data is valid for the lifetime of AsyncReadResult with the exception that the data is |
77 | | immediately invalidated if the Graphite context is abandoned or destroyed. |
78 | | |
79 | | @param src Graphite-backed image or surface to read the data from. |
80 | | @param dstImageInfo info of the requested pixels |
81 | | @param srcRect subrectangle of image to read |
82 | | @param rescaleGamma controls whether rescaling is done in the image's gamma or whether |
83 | | the source data is transformed to a linear gamma before rescaling. |
84 | | @param rescaleMode controls the technique (and cost) of the rescaling |
85 | | @param callback function to call with result of the read |
86 | | @param context passed to callback |
87 | | */ |
88 | | void asyncRescaleAndReadPixels(const SkImage* src, |
89 | | const SkImageInfo& dstImageInfo, |
90 | | const SkIRect& srcRect, |
91 | | SkImage::RescaleGamma rescaleGamma, |
92 | | SkImage::RescaleMode rescaleMode, |
93 | | SkImage::ReadPixelsCallback callback, |
94 | | SkImage::ReadPixelsContext context); |
95 | | void asyncRescaleAndReadPixels(const SkSurface* src, |
96 | | const SkImageInfo& dstImageInfo, |
97 | | const SkIRect& srcRect, |
98 | | SkImage::RescaleGamma rescaleGamma, |
99 | | SkImage::RescaleMode rescaleMode, |
100 | | SkImage::ReadPixelsCallback callback, |
101 | | SkImage::ReadPixelsContext context); |
102 | | |
103 | | /** |
104 | | Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The |
105 | | RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three |
106 | | planes ordered y, u, v. The u and v planes are half the width and height of the resized |
107 | | rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize' |
108 | | width and height are not even. A 'srcRect' that is not contained by the bounds of the |
109 | | surface causes failure. |
110 | | |
111 | | When the pixel data is ready the caller's ReadPixelsCallback is called with a |
112 | | AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3. |
113 | | Upon failure the callback is called with nullptr for AsyncReadResult. The callback can |
114 | | be triggered, for example, with a call to Context::submit(SyncToCpu::kYes). |
115 | | |
116 | | The data is valid for the lifetime of AsyncReadResult with the exception that the data |
117 | | is immediately invalidated if the context is abandoned or destroyed. |
118 | | |
119 | | @param src Graphite-backed image or surface to read the data from. |
120 | | @param yuvColorSpace The transformation from RGB to YUV. Applied to the resized image |
121 | | after it is converted to dstColorSpace. |
122 | | @param dstColorSpace The color space to convert the resized image to, after rescaling. |
123 | | @param srcRect The portion of the surface to rescale and convert to YUV planes. |
124 | | @param dstSize The size to rescale srcRect to |
125 | | @param rescaleGamma controls whether rescaling is done in the surface's gamma or whether |
126 | | the source data is transformed to a linear gamma before rescaling. |
127 | | @param rescaleMode controls the sampling technique of the rescaling |
128 | | @param callback function to call with the planar read result |
129 | | @param context passed to callback |
130 | | */ |
131 | | void asyncRescaleAndReadPixelsYUV420(const SkImage* src, |
132 | | SkYUVColorSpace yuvColorSpace, |
133 | | sk_sp<SkColorSpace> dstColorSpace, |
134 | | const SkIRect& srcRect, |
135 | | const SkISize& dstSize, |
136 | | SkImage::RescaleGamma rescaleGamma, |
137 | | SkImage::RescaleMode rescaleMode, |
138 | | SkImage::ReadPixelsCallback callback, |
139 | | SkImage::ReadPixelsContext context); |
140 | | void asyncRescaleAndReadPixelsYUV420(const SkSurface* src, |
141 | | SkYUVColorSpace yuvColorSpace, |
142 | | sk_sp<SkColorSpace> dstColorSpace, |
143 | | const SkIRect& srcRect, |
144 | | const SkISize& dstSize, |
145 | | SkImage::RescaleGamma rescaleGamma, |
146 | | SkImage::RescaleMode rescaleMode, |
147 | | SkImage::ReadPixelsCallback callback, |
148 | | SkImage::ReadPixelsContext context); |
149 | | |
150 | | /** |
151 | | * Identical to asyncRescaleAndReadPixelsYUV420 but a fourth plane is returned in the |
152 | | * AsyncReadResult passed to 'callback'. The fourth plane contains the alpha chanel at the |
153 | | * same full resolution as the Y plane. |
154 | | */ |
155 | | void asyncRescaleAndReadPixelsYUVA420(const SkImage* src, |
156 | | SkYUVColorSpace yuvColorSpace, |
157 | | sk_sp<SkColorSpace> dstColorSpace, |
158 | | const SkIRect& srcRect, |
159 | | const SkISize& dstSize, |
160 | | SkImage::RescaleGamma rescaleGamma, |
161 | | SkImage::RescaleMode rescaleMode, |
162 | | SkImage::ReadPixelsCallback callback, |
163 | | SkImage::ReadPixelsContext context); |
164 | | void asyncRescaleAndReadPixelsYUVA420(const SkSurface* src, |
165 | | SkYUVColorSpace yuvColorSpace, |
166 | | sk_sp<SkColorSpace> dstColorSpace, |
167 | | const SkIRect& srcRect, |
168 | | const SkISize& dstSize, |
169 | | SkImage::RescaleGamma rescaleGamma, |
170 | | SkImage::RescaleMode rescaleMode, |
171 | | SkImage::ReadPixelsCallback callback, |
172 | | SkImage::ReadPixelsContext context); |
173 | | |
174 | | /** |
175 | | * Checks whether any asynchronous work is complete and if so calls related callbacks. |
176 | | */ |
177 | | void checkAsyncWorkCompletion(); |
178 | | |
179 | | /** |
180 | | * Called to delete the passed in BackendTexture. This should only be called if the |
181 | | * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder created |
182 | | * from this Context. If the BackendTexture is not valid or does not match the BackendApi of the |
183 | | * Context then nothing happens. |
184 | | * |
185 | | * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture. |
186 | | * The BackendTexture will be reset to an invalid state and should not be used again. |
187 | | */ |
188 | | void deleteBackendTexture(const BackendTexture&); |
189 | | |
190 | | /** |
191 | | * Frees GPU resources created and held by the Context. Can be called to reduce GPU memory |
192 | | * pressure. Any resources that are still in use (e.g. being used by work submitted to the GPU) |
193 | | * will not be deleted by this call. If the caller wants to make sure all resources are freed, |
194 | | * then they should first make sure to submit and wait on any outstanding work. |
195 | | */ |
196 | | void freeGpuResources(); |
197 | | |
198 | | /** |
199 | | * Purge GPU resources on the Context that haven't been used in the past 'msNotUsed' |
200 | | * milliseconds or are otherwise marked for deletion, regardless of whether the context is under |
201 | | * budget. |
202 | | */ |
203 | | void performDeferredCleanup(std::chrono::milliseconds msNotUsed); |
204 | | |
205 | | /** |
206 | | * Returns the number of bytes of the Context's gpu memory cache budget that are currently in |
207 | | * use. |
208 | | */ |
209 | | size_t currentBudgetedBytes() const; |
210 | | |
211 | | /** |
212 | | * Returns the number of bytes of the Context's resource cache that are currently purgeable. |
213 | | */ |
214 | | size_t currentPurgeableBytes() const; |
215 | | |
216 | | /** |
217 | | * Returns the size of Context's gpu memory cache budget in bytes. |
218 | | */ |
219 | | size_t maxBudgetedBytes() const; |
220 | | |
221 | | /** |
222 | | * Enumerates all cached GPU resources owned by the Context and dumps their memory to |
223 | | * traceMemoryDump. |
224 | | */ |
225 | | void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; |
226 | | |
227 | | /** |
228 | | * Returns true if the backend-specific context has gotten into an unrecoverarble, lost state |
229 | | * (e.g. if we've gotten a VK_ERROR_DEVICE_LOST in the Vulkan backend). |
230 | | */ |
231 | | bool isDeviceLost() const; |
232 | | |
233 | | /** |
234 | | * Returns the maximum texture dimension supported by the underlying backend. |
235 | | */ |
236 | | int maxTextureSize() const; |
237 | | |
238 | | /* |
239 | | * Does this context support protected content? |
240 | | */ |
241 | | bool supportsProtectedContent() const; |
242 | | |
243 | | // Provides access to functions that aren't part of the public API. |
244 | | ContextPriv priv(); |
245 | | const ContextPriv priv() const; // NOLINT(readability-const-return-type) |
246 | | |
247 | | class ContextID { |
248 | | public: |
249 | | static Context::ContextID Next(); |
250 | | |
251 | 0 | ContextID() : fID(SK_InvalidUniqueID) {} |
252 | | |
253 | 0 | bool operator==(const ContextID& that) const { return fID == that.fID; } |
254 | 0 | bool operator!=(const ContextID& that) const { return !(*this == that); } |
255 | | |
256 | 0 | void makeInvalid() { fID = SK_InvalidUniqueID; } |
257 | 0 | bool isValid() const { return fID != SK_InvalidUniqueID; } |
258 | | |
259 | | private: |
260 | 0 | constexpr ContextID(uint32_t id) : fID(id) {} |
261 | | uint32_t fID; |
262 | | }; |
263 | | |
264 | 0 | ContextID contextID() const { return fContextID; } |
265 | | |
266 | | protected: |
267 | | Context(sk_sp<SharedContext>, std::unique_ptr<QueueManager>, const ContextOptions&); |
268 | | |
269 | | private: |
270 | | friend class ContextPriv; |
271 | | friend class ContextCtorAccessor; |
272 | | |
273 | | struct PixelTransferResult { |
274 | | using ConversionFn = void(void* dst, const void* mappedBuffer); |
275 | | // If null then the transfer could not be performed. Otherwise this buffer will contain |
276 | | // the pixel data when the transfer is complete. |
277 | | sk_sp<Buffer> fTransferBuffer; |
278 | | // Size of the read. |
279 | | SkISize fSize; |
280 | | // RowBytes for transfer buffer data |
281 | | size_t fRowBytes; |
282 | | // If this is null then the transfer buffer will contain the data in the requested |
283 | | // color type. Otherwise, when the transfer is done this must be called to convert |
284 | | // from the transfer buffer's color type to the requested color type. |
285 | | std::function<ConversionFn> fPixelConverter; |
286 | | }; |
287 | | |
288 | 0 | SingleOwner* singleOwner() const { return &fSingleOwner; } |
289 | | |
290 | | // Must be called in Make() to handle one-time GPU setup operations that can possibly fail and |
291 | | // require Context::Make() to return a nullptr. |
292 | | bool finishInitialization(); |
293 | | |
294 | | void checkForFinishedWork(SyncToCpu); |
295 | | |
296 | | std::unique_ptr<Recorder> makeInternalRecorder() const; |
297 | | |
298 | | template <typename SrcPixels> struct AsyncParams; |
299 | | |
300 | | template <typename ReadFn, typename... ExtraArgs> |
301 | | void asyncRescaleAndReadImpl(ReadFn Context::* asyncRead, |
302 | | SkImage::RescaleGamma rescaleGamma, |
303 | | SkImage::RescaleMode rescaleMode, |
304 | | const AsyncParams<SkImage>&, |
305 | | ExtraArgs...); |
306 | | |
307 | | // Recorder is optional and will be used if drawing operations are required. If no Recorder is |
308 | | // provided but drawing operations are needed, a new Recorder will be created automatically. |
309 | | void asyncReadPixels(std::unique_ptr<Recorder>, const AsyncParams<SkImage>&); |
310 | | void asyncReadPixelsYUV420(std::unique_ptr<Recorder>, |
311 | | const AsyncParams<SkImage>&, |
312 | | SkYUVColorSpace); |
313 | | |
314 | | // Like asyncReadPixels() except it performs no fallbacks, and requires that the texture be |
315 | | // readable. However, the texture does not need to be sampleable. |
316 | | void asyncReadTexture(std::unique_ptr<Recorder>, |
317 | | const AsyncParams<TextureProxy>&, |
318 | | const SkColorInfo& srcColorInfo); |
319 | | |
320 | | // Inserts a texture to buffer transfer task, used by asyncReadPixels methods. If the |
321 | | // Recorder is non-null, tasks will be added to the Recorder's list; otherwise the transfer |
322 | | // tasks will be added to the queue manager directly. |
323 | | PixelTransferResult transferPixels(Recorder*, |
324 | | const TextureProxy* srcProxy, |
325 | | const SkColorInfo& srcColorInfo, |
326 | | const SkColorInfo& dstColorInfo, |
327 | | const SkIRect& srcRect); |
328 | | |
329 | | // If the recorder is non-null, it will be snapped and inserted with the assumption that the |
330 | | // copy tasks (and possibly preparatory draw tasks) have already been added to the Recording. |
331 | | void finalizeAsyncReadPixels(std::unique_ptr<Recorder>, |
332 | | SkSpan<PixelTransferResult>, |
333 | | SkImage::ReadPixelsCallback callback, |
334 | | SkImage::ReadPixelsContext callbackContext); |
335 | | |
336 | | sk_sp<SharedContext> fSharedContext; |
337 | | std::unique_ptr<ResourceProvider> fResourceProvider; |
338 | | std::unique_ptr<QueueManager> fQueueManager; |
339 | | std::unique_ptr<ClientMappedBufferManager> fMappedBufferManager; |
340 | | |
341 | | // In debug builds we guard against improper thread handling. This guard is passed to the |
342 | | // ResourceCache for the Context. |
343 | | mutable SingleOwner fSingleOwner; |
344 | | |
345 | | #if defined(GPU_TEST_UTILS) |
346 | | // In test builds a Recorder may track the Context that was used to create it. |
347 | | bool fStoreContextRefInRecorder = false; |
348 | | // If this tracking is on, to allow the client to safely delete this Context or its Recorders |
349 | | // in any order we must also track the Recorders created here. |
350 | | std::vector<Recorder*> fTrackedRecorders; |
351 | | #endif |
352 | | |
353 | | // Needed for MessageBox handling |
354 | | const ContextID fContextID; |
355 | | }; |
356 | | |
357 | | } // namespace skgpu::graphite |
358 | | |
359 | | #endif // skgpu_graphite_Context_DEFINED |