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