1/*
2 * Copyright 2016 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 GrSurfaceProxy_DEFINED
9#define GrSurfaceProxy_DEFINED
10
11#include "include/core/SkRect.h"
12#include "include/core/SkRefCnt.h"
13#include "include/core/SkSize.h"
14#include "include/core/SkString.h"
15#include "include/core/SkTypes.h"
16#include "include/gpu/GrBackendSurface.h"
17#include "include/gpu/GrTypes.h"
18#include "include/private/base/SkDebug.h"
19#include "include/private/base/SkTo.h"
20#include "include/private/gpu/ganesh/GrTypesPriv.h"
21#include "src/gpu/ResourceKey.h"
22#include "src/gpu/ganesh/GrGpuResource.h"
23#include "src/gpu/ganesh/GrSurface.h"
24
25#include <atomic>
26#include <cstddef>
27#include <cstdint>
28#include <functional>
29#include <string>
30#include <string_view>
31#include <utility>
32
33class GrCaps;
34class GrContext_Base;
35class GrRecordingContext;
36class GrRenderTarget;
37class GrRenderTargetProxy;
38class GrRenderTask;
39class GrResourceProvider;
40class GrSurfaceProxyPriv;
41class GrTexture;
42class GrTextureProxy;
43enum class SkBackingFit;
44namespace skgpu {
45enum class Budgeted : bool;
46}
47
48class GrSurfaceProxy : public SkNVRefCnt<GrSurfaceProxy> {
49public:
50 virtual ~GrSurfaceProxy();
51
52 /**
53 * Indicates "resolutions" that need to be done on a surface before its pixels can be accessed.
54 * If both types of resolve are requested, the MSAA resolve will happen first.
55 */
56 enum class ResolveFlags {
57 kNone = 0,
58 kMSAA = 1 << 0, // Blit and resolve an internal MSAA render buffer into the texture.
59 kMipMaps = 1 << 1, // Regenerate all mipmap levels.
60 };
61
62 /**
63 * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return.
64 * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls
65 * the key relationship between proxies and their targets.
66 */
67 enum class LazyInstantiationKeyMode {
68 /**
69 * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to
70 * return a GrSurface that already has a unique key unrelated to the proxy's key.
71 */
72 kUnsynced,
73 /**
74 * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface
75 * returned from the lazy instantiation callback must not have a unique key or have the same
76 * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned
77 * to the GrSurface.
78 */
79 kSynced
80 };
81
82 /**
83 * Specifies the expected properties of the GrSurface returned by a lazy instantiation
84 * callback. The dimensions will be negative in the case of a fully lazy proxy.
85 */
86 struct LazySurfaceDesc {
87 SkISize fDimensions;
88 SkBackingFit fFit;
89 GrRenderable fRenderable;
90 GrMipmapped fMipmapped;
91 int fSampleCnt;
92 const GrBackendFormat& fFormat;
93 GrTextureType fTextureType;
94 GrProtected fProtected;
95 skgpu::Budgeted fBudgeted;
96 std::string_view fLabel;
97 };
98
99 struct LazyCallbackResult {
100 LazyCallbackResult() = default;
101 LazyCallbackResult(const LazyCallbackResult&) = default;
102 LazyCallbackResult(LazyCallbackResult&& that) = default;
103 LazyCallbackResult(sk_sp<GrSurface> surf,
104 bool releaseCallback = true,
105 LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced);
106 LazyCallbackResult(sk_sp<GrTexture> tex);
107
108 LazyCallbackResult& operator=(const LazyCallbackResult&) = default;
109 LazyCallbackResult& operator=(LazyCallbackResult&&) = default;
110
111 sk_sp<GrSurface> fSurface;
112 LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced;
113 /**
114 * Should the callback be disposed of after it has returned or preserved until the proxy
115 * is freed. Only honored if fSurface is not-null. If it is null the callback is preserved.
116 */
117 bool fReleaseCallback = true;
118 };
119
120 using LazyInstantiateCallback =
121 std::function<LazyCallbackResult(GrResourceProvider*, const LazySurfaceDesc&)>;
122
123 enum class UseAllocator {
124 /**
125 * This proxy will be instantiated outside the allocator (e.g. for proxies that are
126 * instantiated in on-flush callbacks).
127 */
128 kNo = false,
129 /**
130 * GrResourceAllocator should instantiate this proxy.
131 */
132 kYes = true,
133 };
134
135 bool isLazy() const { return !this->isInstantiated() && SkToBool(x: fLazyInstantiateCallback); }
136
137 bool isFullyLazy() const {
138 bool result = fDimensions.width() < 0;
139 SkASSERT(result == (fDimensions.height() < 0));
140 SkASSERT(!result || this->isLazy());
141 return result;
142 }
143
144 SkISize dimensions() const {
145 SkASSERT(!this->isFullyLazy());
146 return fDimensions;
147 }
148 int width() const { return this->dimensions().width(); }
149 int height() const { return this->dimensions().height(); }
150
151 SkISize backingStoreDimensions() const;
152
153 /**
154 * Helper that gets the width and height of the proxy as a bounding rectangle.
155 */
156 SkRect getBoundsRect() const { return SkRect::Make(size: this->dimensions()); }
157
158 /* A perhaps faster check for this->dimensions() == this->backingStoreDimensions(). */
159 bool isFunctionallyExact() const;
160
161 /**
162 * Helper that gets the dimensions the backing GrSurface will have as a bounding rectangle.
163 */
164 SkRect backingStoreBoundsRect() const {
165 return SkRect::Make(size: this->backingStoreDimensions());
166 }
167
168 SkIRect backingStoreBoundsIRect() const {
169 return SkIRect::MakeSize(size: this->backingStoreDimensions());
170 }
171
172 const GrBackendFormat& backendFormat() const { return fFormat; }
173
174 bool isFormatCompressed(const GrCaps*) const;
175
176 class UniqueID {
177 public:
178 static UniqueID InvalidID() {
179 return UniqueID(uint32_t(SK_InvalidUniqueID));
180 }
181
182 // wrapped
183 explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
184 // deferred and lazy-callback
185 UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
186
187 uint32_t asUInt() const { return fID; }
188
189 bool operator==(const UniqueID& other) const {
190 return fID == other.fID;
191 }
192 bool operator!=(const UniqueID& other) const {
193 return !(*this == other);
194 }
195
196 void makeInvalid() { fID = SK_InvalidUniqueID; }
197 bool isInvalid() const { return SK_InvalidUniqueID == fID; }
198
199 private:
200 explicit UniqueID(uint32_t id) : fID(id) {}
201
202 uint32_t fID;
203 };
204
205 /*
206 * The contract for the uniqueID is:
207 * for wrapped resources:
208 * the uniqueID will match that of the wrapped resource
209 *
210 * for deferred resources:
211 * the uniqueID will be different from the real resource, when it is allocated
212 * the proxy's uniqueID will not change across the instantiate call
213 *
214 * the uniqueIDs of the proxies and the resources draw from the same pool
215 *
216 * What this boils down to is that the uniqueID of a proxy can be used to consistently
217 * track/identify a proxy but should never be used to distinguish between
218 * resources and proxies - beware!
219 */
220 UniqueID uniqueID() const { return fUniqueID; }
221
222 UniqueID underlyingUniqueID() const {
223 if (fTarget) {
224 return UniqueID(fTarget->uniqueID());
225 }
226
227 return fUniqueID;
228 }
229
230 virtual bool instantiate(GrResourceProvider*) = 0;
231
232 void deinstantiate();
233
234 /**
235 * Proxies that are already instantiated and whose backing surface cannot be recycled to
236 * instantiate other proxies do not need to be considered by GrResourceAllocator.
237 */
238 bool canSkipResourceAllocator() const;
239
240 /**
241 * @return the texture proxy associated with the surface proxy, may be NULL.
242 */
243 virtual GrTextureProxy* asTextureProxy() { return nullptr; }
244 virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
245
246 /**
247 * @return the render target proxy associated with the surface proxy, may be NULL.
248 */
249 virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
250 virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
251
252 /** @return The unique key for this proxy. May be invalid. */
253 virtual const skgpu::UniqueKey& getUniqueKey() const {
254 // Base class never has a valid unique key.
255 static const skgpu::UniqueKey kInvalidKey;
256 return kInvalidKey;
257 }
258
259 bool isInstantiated() const { return SkToBool(x: fTarget); }
260
261 /** Called when this task becomes a target of a GrRenderTask. */
262 void isUsedAsTaskTarget() { ++fTaskTargetCount; }
263
264 /** How many render tasks has this proxy been the target of? */
265 int getTaskTargetCount() const { return fTaskTargetCount; }
266
267 // If the proxy is already instantiated, return its backing GrTexture; if not, return null.
268 GrSurface* peekSurface() const { return fTarget.get(); }
269
270 // If this is a texture proxy and the proxy is already instantiated, return its backing
271 // GrTexture; if not, return null.
272 GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; }
273
274 // If this is a render target proxy and the proxy is already instantiated, return its backing
275 // GrRenderTarget; if not, return null.
276 GrRenderTarget* peekRenderTarget() const {
277 return fTarget ? fTarget->asRenderTarget() : nullptr;
278 }
279
280 /**
281 * Does the resource count against the resource budget?
282 */
283 skgpu::Budgeted isBudgeted() const { return fBudgeted; }
284
285 /**
286 * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write
287 * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and
288 * assignment in GrResourceAllocator.
289 */
290 bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
291 bool framebufferOnly() const {
292 return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
293 }
294
295 /**
296 * This means surface is a multisampled render target, and internally holds a non-msaa texture
297 * for resolving into. The render target resolves itself by blitting into this internal texture.
298 * (asTexture() might or might not return the internal texture, but if it does, we always
299 * resolve the render target before accessing this texture's data.)
300 */
301 bool requiresManualMSAAResolve() const {
302 return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
303 }
304
305 /**
306 * Retrieves the amount of GPU memory that will be or currently is used by this resource
307 * in bytes. It is approximate since we aren't aware of additional padding or copies made
308 * by the driver.
309 *
310 * @return the amount of GPU memory used in bytes
311 */
312 size_t gpuMemorySize() const {
313 SkASSERT(!this->isFullyLazy());
314 if (kInvalidGpuMemorySize == fGpuMemorySize) {
315 fGpuMemorySize = this->onUninstantiatedGpuMemorySize();
316 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
317 }
318 return fGpuMemorySize;
319 }
320
321 std::string_view getLabel() const { return fLabel; }
322
323 enum class RectsMustMatch : bool {
324 kNo = false,
325 kYes = true
326 };
327
328 // Helper function that creates a temporary SurfaceContext to perform the copy
329 // The copy is is not a render target and not multisampled.
330 //
331 // The intended use of this copy call is simply to copy exact pixel values from one proxy to a
332 // new one. Thus, there isn't a need for a swizzle when doing the copy. The format of the copy
333 // will be the same as the src. Therefore, the copy can be used in a view with the same swizzle
334 // as the original for use with a given color type.
335 //
336 // Optionally gets the render task that performs the copy. If it is later determined that the
337 // copy is not neccessaru then the task can be marked skippable using GrRenderTask::canSkip() and
338 // the copy will be elided.
339 static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*,
340 sk_sp<GrSurfaceProxy> src,
341 GrSurfaceOrigin,
342 GrMipmapped,
343 SkIRect srcRect,
344 SkBackingFit,
345 skgpu::Budgeted,
346 std::string_view label,
347 RectsMustMatch = RectsMustMatch::kNo,
348 sk_sp<GrRenderTask>* outTask = nullptr);
349
350 // Same as above Copy but copies the entire 'src'
351 static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*,
352 sk_sp<GrSurfaceProxy> src,
353 GrSurfaceOrigin,
354 GrMipmapped,
355 SkBackingFit,
356 skgpu::Budgeted,
357 std::string_view label,
358 sk_sp<GrRenderTask>* outTask = nullptr);
359
360#if GR_TEST_UTILS
361 int32_t testingOnly_getBackingRefCnt() const;
362 GrInternalSurfaceFlags testingOnly_getFlags() const;
363 SkString dump() const;
364#endif
365
366#ifdef SK_DEBUG
367 void validate(GrContext_Base*) const;
368 SkString getDebugName() {
369 return fDebugName.isEmpty() ? SkStringPrintf(format: "%d", this->uniqueID().asUInt()) : fDebugName;
370 }
371 void setDebugName(SkString name) { fDebugName = std::move(name); }
372#endif
373
374 // Provides access to functions that aren't part of the public API.
375 inline GrSurfaceProxyPriv priv();
376 inline const GrSurfaceProxyPriv priv() const; // NOLINT(readability-const-return-type)
377
378 bool isDDLTarget() const { return fIsDDLTarget; }
379
380 GrProtected isProtected() const { return fIsProtected; }
381
382 bool isPromiseProxy() { return fIsPromiseProxy; }
383
384protected:
385 // Deferred version - takes a new UniqueID from the shared resource/proxy pool.
386 GrSurfaceProxy(const GrBackendFormat&,
387 SkISize,
388 SkBackingFit,
389 skgpu::Budgeted,
390 GrProtected,
391 GrInternalSurfaceFlags,
392 UseAllocator,
393 std::string_view label);
394 // Lazy-callback version - takes a new UniqueID from the shared resource/proxy pool.
395 GrSurfaceProxy(LazyInstantiateCallback&&,
396 const GrBackendFormat&,
397 SkISize,
398 SkBackingFit,
399 skgpu::Budgeted,
400 GrProtected,
401 GrInternalSurfaceFlags,
402 UseAllocator,
403 std::string_view label);
404
405 // Wrapped version - shares the UniqueID of the passed surface.
406 // Takes UseAllocator because even though this is already instantiated it still can participate
407 // in allocation by having its backing resource recycled to other uninstantiated proxies or
408 // not depending on UseAllocator.
409 GrSurfaceProxy(sk_sp<GrSurface>, SkBackingFit, UseAllocator);
410
411 friend class GrSurfaceProxyPriv;
412
413 // Methods made available via GrSurfaceProxyPriv
414 bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; }
415 void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; }
416
417 void computeScratchKey(const GrCaps&, skgpu::ScratchKey*) const;
418
419 virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0;
420 void assign(sk_sp<GrSurface> surface);
421
422 sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, GrRenderable,
423 GrMipmapped) const;
424
425 // Once the dimensions of a fully-lazy proxy are decided, and before it gets instantiated, the
426 // client can use this optional method to specify the proxy's dimensions. (A proxy's dimensions
427 // can be less than the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise,
428 // the proxy's dimensions will be set to match the underlying GPU surface upon instantiation.
429 void setLazyDimensions(SkISize dimensions) {
430 SkASSERT(this->isFullyLazy());
431 SkASSERT(!dimensions.isEmpty());
432 fDimensions = dimensions;
433 }
434
435 bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, GrRenderable,
436 GrMipmapped, const skgpu::UniqueKey*);
437
438 // For deferred proxies this will be null until the proxy is instantiated.
439 // For wrapped proxies it will point to the wrapped resource.
440 sk_sp<GrSurface> fTarget;
441
442 // In many cases these flags aren't actually known until the proxy has been instantiated.
443 // However, Ganesh frequently needs to change its behavior based on these settings. For
444 // internally create proxies we will know these properties ahead of time. For wrapped
445 // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the
446 // call sites to provide the required information ahead of time. At instantiation time
447 // we verify that the assumed properties match the actual properties.
448 GrInternalSurfaceFlags fSurfaceFlags;
449
450private:
451 // For wrapped resources, 'fFormat' and 'fDimensions' will always be filled in from the
452 // wrapped resource.
453 const GrBackendFormat fFormat;
454 SkISize fDimensions;
455
456 SkBackingFit fFit; // always kApprox for lazy-callback resources
457 // always kExact for wrapped resources
458 mutable skgpu::Budgeted fBudgeted; // always kYes for lazy-callback resources
459 // set from the backing resource for wrapped resources
460 // mutable bc of SkSurface/SkImage wishy-washiness
461 // Only meaningful if fLazyInstantiateCallback is non-null.
462 UseAllocator fUseAllocator;
463
464 const UniqueID fUniqueID; // set from the backing resource for wrapped resources
465
466 LazyInstantiateCallback fLazyInstantiateCallback;
467
468 SkDEBUGCODE(void validateSurface(const GrSurface*);)
469 SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;)
470
471 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
472 SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
473
474 virtual size_t onUninstantiatedGpuMemorySize() const = 0;
475
476 virtual LazySurfaceDesc callbackDesc() const = 0;
477
478 bool fIgnoredByResourceAllocator = false;
479 bool fIsDDLTarget = false;
480 bool fIsPromiseProxy = false;
481 GrProtected fIsProtected;
482
483 int fTaskTargetCount = 0;
484
485 const std::string fLabel;
486
487 // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
488 // will be called but, when the proxy is deferred, it will compute the answer itself.
489 // If the proxy computes its own answer that answer is checked (in debug mode) in
490 // the instantiation method. The image may be shared between threads, hence atomic.
491 mutable std::atomic<size_t> fGpuMemorySize{kInvalidGpuMemorySize};
492 SkDEBUGCODE(SkString fDebugName;)
493};
494
495GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags)
496
497#endif
498

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/third_party/skia/src/gpu/ganesh/GrSurfaceProxy.h