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