Line data Source code
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 "GrGpuResource.h"
12 : #include "GrSurface.h"
13 :
14 : #include "SkRect.h"
15 :
16 : class GrCaps;
17 : class GrRenderTargetOpList;
18 : class GrRenderTargetProxy;
19 : class GrResourceProvider;
20 : class GrSurfaceContext;
21 : class GrSurfaceProxyPriv;
22 : class GrTextureOpList;
23 : class GrTextureProxy;
24 :
25 : //#define SK_DISABLE_DEFERRED_PROXIES 1
26 :
27 : // This class replicates the functionality GrIORef<GrSurface> but tracks the
28 : // utilitization for later resource allocation (for the deferred case) and
29 : // forwards on the utilization in the wrapped case
30 : class GrIORefProxy : public SkNoncopyable {
31 : public:
32 0 : void ref() const {
33 0 : this->validate();
34 :
35 0 : ++fRefCnt;
36 0 : if (fTarget) {
37 0 : fTarget->ref();
38 : }
39 0 : }
40 :
41 0 : void unref() const {
42 0 : this->validate();
43 :
44 0 : if (fTarget) {
45 0 : fTarget->unref();
46 : }
47 :
48 0 : if (!(--fRefCnt)) {
49 0 : delete this;
50 0 : return;
51 : }
52 :
53 0 : this->validate();
54 : }
55 :
56 0 : void validate() const {
57 : #ifdef SK_DEBUG
58 0 : SkASSERT(fRefCnt >= 1);
59 0 : SkASSERT(fPendingReads >= 0);
60 0 : SkASSERT(fPendingWrites >= 0);
61 0 : SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1);
62 :
63 0 : if (fTarget) {
64 0 : SkASSERT(!fPendingReads && !fPendingWrites);
65 : // The backing GrSurface can have more refs than the proxy if the proxy
66 : // started off wrapping an external resource (that came in with refs).
67 : // The GrSurface should never have fewer refs than the proxy however.
68 0 : SkASSERT(fTarget->fRefCnt >= fRefCnt);
69 : }
70 : #endif
71 0 : }
72 :
73 : int32_t getProxyRefCnt_TestOnly() const;
74 : int32_t getBackingRefCnt_TestOnly() const;
75 : int32_t getPendingReadCnt_TestOnly() const;
76 : int32_t getPendingWriteCnt_TestOnly() const;
77 :
78 : protected:
79 0 : GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {}
80 0 : GrIORefProxy(sk_sp<GrSurface> surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) {
81 : // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing
82 : // anything extra.
83 0 : fTarget = surface.release();
84 0 : }
85 0 : virtual ~GrIORefProxy() {
86 : // We don't unref 'fTarget' here since the 'unref' method will already
87 : // have forwarded on the unref call that got use here.
88 0 : }
89 :
90 : // This GrIORefProxy was deferred before but has just been instantiated. To
91 : // make all the reffing & unreffing work out we now need to transfer any deferred
92 : // refs & unrefs to the new GrSurface
93 0 : void transferRefs() {
94 0 : SkASSERT(fTarget);
95 :
96 0 : fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref
97 0 : fTarget->fPendingReads += fPendingReads;
98 0 : fTarget->fPendingWrites += fPendingWrites;
99 :
100 0 : fPendingReads = 0;
101 0 : fPendingWrites = 0;
102 0 : }
103 :
104 0 : bool internalHasPendingIO() const {
105 0 : if (fTarget) {
106 0 : return fTarget->internalHasPendingIO();
107 : }
108 :
109 0 : return SkToBool(fPendingWrites | fPendingReads);
110 : }
111 :
112 0 : bool internalHasPendingWrite() const {
113 0 : if (fTarget) {
114 0 : return fTarget->internalHasPendingWrite();
115 : }
116 :
117 0 : return SkToBool(fPendingWrites);
118 : }
119 :
120 : // For deferred proxies this will be null. For wrapped proxies it will point to the
121 : // wrapped resource.
122 : GrSurface* fTarget;
123 :
124 : private:
125 : // This class is used to manage conversion of refs to pending reads/writes.
126 : friend class GrGpuResourceRef;
127 : template <typename, GrIOType> friend class GrPendingIOResource;
128 :
129 : void addPendingRead() const {
130 : this->validate();
131 :
132 : if (fTarget) {
133 : fTarget->addPendingRead();
134 : return;
135 : }
136 :
137 : ++fPendingReads;
138 : }
139 :
140 : void completedRead() const {
141 : this->validate();
142 :
143 : if (fTarget) {
144 : fTarget->completedRead();
145 : return;
146 : }
147 :
148 : SkFAIL("How was the read completed if the Proxy hasn't been instantiated?");
149 : }
150 :
151 : void addPendingWrite() const {
152 : this->validate();
153 :
154 : if (fTarget) {
155 : fTarget->addPendingWrite();
156 : return;
157 : }
158 :
159 : ++fPendingWrites;
160 : }
161 :
162 : void completedWrite() const {
163 : this->validate();
164 :
165 : if (fTarget) {
166 : fTarget->completedWrite();
167 : return;
168 : }
169 :
170 : SkFAIL("How was the write completed if the Proxy hasn't been instantiated?");
171 : }
172 :
173 : mutable int32_t fRefCnt;
174 : mutable int32_t fPendingReads;
175 : mutable int32_t fPendingWrites;
176 : };
177 :
178 : class GrSurfaceProxy : public GrIORefProxy {
179 : public:
180 : static sk_sp<GrSurfaceProxy> MakeWrapped(sk_sp<GrSurface>);
181 : static sk_sp<GrTextureProxy> MakeWrapped(sk_sp<GrTexture>);
182 :
183 : static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
184 : const GrSurfaceDesc&, SkBackingFit,
185 : SkBudgeted, uint32_t flags = 0);
186 :
187 : // TODO: need to refine ownership semantics of 'srcData' if we're in completely
188 : // deferred mode
189 : static sk_sp<GrTextureProxy> MakeDeferred(GrResourceProvider*,
190 : const GrSurfaceDesc&, SkBudgeted,
191 : const void* srcData, size_t rowBytes);
192 :
193 : static sk_sp<GrSurfaceProxy> MakeWrappedBackend(GrContext*, GrBackendTextureDesc&);
194 :
195 0 : const GrSurfaceDesc& desc() const { return fDesc; }
196 :
197 0 : GrSurfaceOrigin origin() const {
198 0 : SkASSERT(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin ||
199 : kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin);
200 0 : return fDesc.fOrigin;
201 : }
202 0 : int width() const { return fDesc.fWidth; }
203 0 : int height() const { return fDesc.fHeight; }
204 0 : GrPixelConfig config() const { return fDesc.fConfig; }
205 :
206 : class UniqueID {
207 : public:
208 0 : static UniqueID InvalidID() {
209 0 : return UniqueID(uint32_t(SK_InvalidUniqueID));
210 : }
211 :
212 : // wrapped
213 0 : explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
214 : // deferred
215 0 : UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
216 :
217 0 : uint32_t asUInt() const { return fID; }
218 :
219 0 : bool operator==(const UniqueID& other) const {
220 0 : return fID == other.fID;
221 : }
222 : bool operator!=(const UniqueID& other) const {
223 : return !(*this == other);
224 : }
225 :
226 0 : void makeInvalid() { fID = SK_InvalidUniqueID; }
227 : bool isInvalid() const { return SK_InvalidUniqueID == fID; }
228 :
229 : private:
230 0 : explicit UniqueID(uint32_t id) : fID(id) {}
231 :
232 : uint32_t fID;
233 : };
234 :
235 : /*
236 : * The contract for the uniqueID is:
237 : * for wrapped resources:
238 : * the uniqueID will match that of the wrapped resource
239 : *
240 : * for deferred resources:
241 : * the uniqueID will be different from the real resource, when it is allocated
242 : * the proxy's uniqueID will not change across the instantiate call
243 : *
244 : * the uniqueIDs of the proxies and the resources draw from the same pool
245 : *
246 : * What this boils down to is that the uniqueID of a proxy can be used to consistently
247 : * track/identify a proxy but should never be used to distinguish between
248 : * resources and proxies - beware!
249 : */
250 0 : UniqueID uniqueID() const { return fUniqueID; }
251 :
252 : GrSurface* instantiate(GrResourceProvider* resourceProvider);
253 :
254 : /**
255 : * Helper that gets the width and height of the surface as a bounding rectangle.
256 : */
257 0 : SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
258 :
259 : int worstCaseWidth(const GrCaps& caps) const;
260 : int worstCaseHeight(const GrCaps& caps) const;
261 :
262 : /**
263 : * @return the texture proxy associated with the surface proxy, may be NULL.
264 : */
265 0 : virtual GrTextureProxy* asTextureProxy() { return nullptr; }
266 0 : virtual const GrTextureProxy* asTextureProxy() const { return nullptr; }
267 :
268 : /**
269 : * @return the render target proxy associated with the surface proxy, may be NULL.
270 : */
271 0 : virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; }
272 0 : virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; }
273 :
274 : /**
275 : * Does the resource count against the resource budget?
276 : */
277 0 : SkBudgeted isBudgeted() const { return fBudgeted; }
278 :
279 : void setLastOpList(GrOpList* opList);
280 0 : GrOpList* getLastOpList() { return fLastOpList; }
281 :
282 : GrRenderTargetOpList* getLastRenderTargetOpList();
283 : GrTextureOpList* getLastTextureOpList();
284 :
285 : /**
286 : * Retrieves the amount of GPU memory that will be or currently is used by this resource
287 : * in bytes. It is approximate since we aren't aware of additional padding or copies made
288 : * by the driver.
289 : *
290 : * @return the amount of GPU memory used in bytes
291 : */
292 0 : size_t gpuMemorySize() const {
293 0 : if (kInvalidGpuMemorySize == fGpuMemorySize) {
294 0 : fGpuMemorySize = this->onGpuMemorySize();
295 0 : SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
296 : }
297 0 : return fGpuMemorySize;
298 : }
299 :
300 : // Helper function that creates a temporary SurfaceContext to perform the copy
301 : // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage
302 : // to an SkImage.
303 : static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src,
304 : SkIRect srcRect, SkBudgeted);
305 :
306 : // Copy the entire 'src'
307 : // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial
308 : static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src,
309 : SkBudgeted budgeted);
310 :
311 : // Test-only entry point - should decrease in use as proxies propagate
312 : static sk_sp<GrSurfaceContext> TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
313 : GrSurfaceProxy* srcProxy);
314 :
315 : bool isWrapped_ForTesting() const;
316 :
317 : SkDEBUGCODE(void validate(GrContext*) const;)
318 :
319 : // Provides access to functions that aren't part of the public API.
320 : GrSurfaceProxyPriv priv();
321 : const GrSurfaceProxyPriv priv() const;
322 :
323 : protected:
324 : // Deferred version
325 0 : GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags)
326 0 : : fDesc(desc)
327 : , fFit(fit)
328 : , fBudgeted(budgeted)
329 : , fFlags(flags)
330 : // fMipColorMode is only valid for texturable proxies
331 : , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
332 : , fGpuMemorySize(kInvalidGpuMemorySize)
333 0 : , fLastOpList(nullptr) {
334 : // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
335 0 : }
336 :
337 : // Wrapped version
338 : GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit);
339 :
340 : virtual ~GrSurfaceProxy();
341 :
342 : friend class GrSurfaceProxyPriv;
343 :
344 : // Methods made available via GrSurfaceProxyPriv
345 0 : bool hasPendingIO() const {
346 0 : return this->internalHasPendingIO();
347 : }
348 :
349 0 : bool hasPendingWrite() const {
350 0 : return this->internalHasPendingWrite();
351 : }
352 :
353 : // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource.
354 : GrSurfaceDesc fDesc;
355 : SkBackingFit fFit; // always exact for wrapped resources
356 : mutable SkBudgeted fBudgeted; // set from the backing resource for wrapped resources
357 : // mutable bc of SkSurface/SkImage wishy-washiness
358 : const uint32_t fFlags;
359 :
360 : SkDestinationSurfaceColorMode fMipColorMode;
361 :
362 : const UniqueID fUniqueID; // set from the backing resource for wrapped resources
363 :
364 : static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
365 0 : SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
366 :
367 : private:
368 : virtual size_t onGpuMemorySize() const = 0;
369 :
370 : // This entry is lazily evaluated so, when the proxy wraps a resource, the resource
371 : // will be called but, when the proxy is deferred, it will compute the answer itself.
372 : // If the proxy computes its own answer that answer is checked (in debug mode) in
373 : // the instantiation method.
374 : mutable size_t fGpuMemorySize;
375 :
376 : // The last opList that wrote to or is currently going to write to this surface
377 : // The opList can be closed (e.g., no render target context is currently bound
378 : // to this renderTarget).
379 : // This back-pointer is required so that we can add a dependancy between
380 : // the opList used to create the current contents of this surface
381 : // and the opList of a destination surface to which this one is being drawn or copied.
382 : GrOpList* fLastOpList;
383 :
384 :
385 : typedef GrIORefProxy INHERITED;
386 : };
387 :
388 : #endif
|