• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/gpu/GrSurfaceProxy.h"
9 #include "src/gpu/GrSurfaceProxyPriv.h"
10 
11 #include "include/gpu/GrContext.h"
12 #include "include/private/GrRecordingContext.h"
13 #include "src/core/SkMathPriv.h"
14 #include "src/core/SkMipMap.h"
15 #include "src/gpu/GrCaps.h"
16 #include "src/gpu/GrClip.h"
17 #include "src/gpu/GrContextPriv.h"
18 #include "src/gpu/GrGpuResourcePriv.h"
19 #include "src/gpu/GrOpsTask.h"
20 #include "src/gpu/GrProxyProvider.h"
21 #include "src/gpu/GrRecordingContextPriv.h"
22 #include "src/gpu/GrRenderTargetContext.h"
23 #include "src/gpu/GrStencilAttachment.h"
24 #include "src/gpu/GrSurfacePriv.h"
25 #include "src/gpu/GrTexturePriv.h"
26 #include "src/gpu/GrTextureRenderTargetProxy.h"
27 
28 #ifdef SK_DEBUG
29 #include "src/gpu/GrRenderTarget.h"
30 #include "src/gpu/GrRenderTargetPriv.h"
31 
is_valid_lazy(const SkISize & dimensions,SkBackingFit fit)32 static bool is_valid_lazy(const SkISize& dimensions, SkBackingFit fit) {
33     // A "fully" lazy proxy's width and height are not known until instantiation time.
34     // So fully lazy proxies are created with width and height < 0. Regular lazy proxies must be
35     // created with positive widths and heights. The width and height are set to 0 only after a
36     // failed instantiation. The former must be "approximate" fit while the latter can be either.
37     return ((dimensions.fWidth < 0 && dimensions.fHeight < 0 && SkBackingFit::kApprox == fit) ||
38             (dimensions.fWidth > 0 && dimensions.fHeight > 0));
39 }
40 
is_valid_non_lazy(SkISize dimensions)41 static bool is_valid_non_lazy(SkISize dimensions) {
42     return dimensions.fWidth > 0 && dimensions.fHeight > 0;
43 }
44 #endif
45 
46 // Deferred version
GrSurfaceProxy(const GrBackendFormat & format,SkISize dimensions,GrRenderable renderable,const GrSwizzle & textureSwizzle,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator)47 GrSurfaceProxy::GrSurfaceProxy(const GrBackendFormat& format,
48                                SkISize dimensions,
49                                GrRenderable renderable,
50                                const GrSwizzle& textureSwizzle,
51                                SkBackingFit fit,
52                                SkBudgeted budgeted,
53                                GrProtected isProtected,
54                                GrInternalSurfaceFlags surfaceFlags,
55                                UseAllocator useAllocator)
56         : fSurfaceFlags(surfaceFlags)
57         , fFormat(format)
58         , fDimensions(dimensions)
59         , fTextureSwizzle(textureSwizzle)
60         , fFit(fit)
61         , fBudgeted(budgeted)
62         , fUseAllocator(useAllocator)
63         , fIsProtected(isProtected)
64         , fGpuMemorySize(kInvalidGpuMemorySize) {
65     SkASSERT(fFormat.isValid());
66     SkASSERT(is_valid_non_lazy(dimensions));
67 }
68 
69 // Lazy-callback version
GrSurfaceProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,GrRenderable renderable,const GrSwizzle & textureSwizzle,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator)70 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback,
71                                const GrBackendFormat& format,
72                                SkISize dimensions,
73                                GrRenderable renderable,
74                                const GrSwizzle& textureSwizzle,
75                                SkBackingFit fit,
76                                SkBudgeted budgeted,
77                                GrProtected isProtected,
78                                GrInternalSurfaceFlags surfaceFlags,
79                                UseAllocator useAllocator)
80         : fSurfaceFlags(surfaceFlags)
81         , fFormat(format)
82         , fDimensions(dimensions)
83         , fTextureSwizzle(textureSwizzle)
84         , fFit(fit)
85         , fBudgeted(budgeted)
86         , fUseAllocator(useAllocator)
87         , fLazyInstantiateCallback(std::move(callback))
88         , fIsProtected(isProtected)
89         , fGpuMemorySize(kInvalidGpuMemorySize) {
90     SkASSERT(fFormat.isValid());
91     SkASSERT(fLazyInstantiateCallback);
92     SkASSERT(is_valid_lazy(dimensions, fit));
93 }
94 
95 // Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface,const GrSwizzle & textureSwizzle,SkBackingFit fit,UseAllocator useAllocator)96 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface,
97                                const GrSwizzle& textureSwizzle,
98                                SkBackingFit fit,
99                                UseAllocator useAllocator)
100         : fTarget(std::move(surface))
101         , fSurfaceFlags(fTarget->surfacePriv().flags())
102         , fFormat(fTarget->backendFormat())
103         , fDimensions(fTarget->dimensions())
104         , fTextureSwizzle(textureSwizzle)
105         , fFit(fit)
106         , fBudgeted(fTarget->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted
107                             ? SkBudgeted::kYes
108                             : SkBudgeted::kNo)
109         , fUseAllocator(useAllocator)
110         , fUniqueID(fTarget->uniqueID())  // Note: converting from unique resource ID to a proxy ID!
111         , fIsProtected(fTarget->isProtected() ? GrProtected::kYes : GrProtected::kNo)
112         , fGpuMemorySize(kInvalidGpuMemorySize) {
113     SkASSERT(fFormat.isValid());
114 }
115 
~GrSurfaceProxy()116 GrSurfaceProxy::~GrSurfaceProxy() {
117     // For this to be deleted the opsTask that held a ref on it (if there was one) must have been
118     // deleted. Which would have cleared out this back pointer.
119     SkASSERT(!fLastRenderTask);
120 }
121 
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,GrMipMapped mipMapped) const122 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider,
123                                                    int sampleCnt,
124                                                    GrRenderable renderable,
125                                                    GrMipMapped mipMapped) const {
126     SkASSERT(mipMapped == GrMipMapped::kNo || fFit == SkBackingFit::kExact);
127     SkASSERT(!this->isLazy());
128     SkASSERT(!fTarget);
129 
130     sk_sp<GrSurface> surface;
131     if (SkBackingFit::kApprox == fFit) {
132         surface = resourceProvider->createApproxTexture(fDimensions, fFormat, renderable, sampleCnt,
133                                                         fIsProtected);
134     } else {
135         surface = resourceProvider->createTexture(fDimensions, fFormat, renderable, sampleCnt,
136                                                   mipMapped, fBudgeted, fIsProtected);
137     }
138     if (!surface) {
139         return nullptr;
140     }
141 
142     return surface;
143 }
144 
canSkipResourceAllocator() const145 bool GrSurfaceProxy::canSkipResourceAllocator() const {
146     if (fUseAllocator == UseAllocator::kNo) {
147         // Usually an atlas or onFlush proxy
148         return true;
149     }
150 
151     auto peek = this->peekSurface();
152     if (!peek) {
153         return false;
154     }
155     // If this resource is already allocated and not recyclable then the resource allocator does
156     // not need to do anything with it.
157     return !peek->resourcePriv().getScratchKey().isValid();
158 }
159 
assign(sk_sp<GrSurface> surface)160 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
161     SkASSERT(!fTarget && surface);
162 
163     SkDEBUGCODE(this->validateSurface(surface.get());)
164 
165     fTarget = std::move(surface);
166 
167 #ifdef SK_DEBUG
168     if (this->asRenderTargetProxy()) {
169         SkASSERT(fTarget->asRenderTarget());
170     }
171 
172     if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
173         SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
174     }
175 #endif
176 }
177 
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,GrMipMapped mipMapped,const GrUniqueKey * uniqueKey)178 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
179                                      GrRenderable renderable, GrMipMapped mipMapped,
180                                      const GrUniqueKey* uniqueKey) {
181     SkASSERT(!this->isLazy());
182     if (fTarget) {
183         if (uniqueKey && uniqueKey->isValid()) {
184             SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey);
185         }
186         return true;
187     }
188 
189     sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, renderable,
190                                                        mipMapped);
191     if (!surface) {
192         return false;
193     }
194 
195     // If there was an invalidation message pending for this key, we might have just processed it,
196     // causing the key (stored on this proxy) to become invalid.
197     if (uniqueKey && uniqueKey->isValid()) {
198         resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
199     }
200 
201     this->assign(std::move(surface));
202 
203     return true;
204 }
205 
deinstantiate()206 void GrSurfaceProxy::deinstantiate() {
207     SkASSERT(this->isInstantiated());
208     fTarget = nullptr;
209 }
210 
computeScratchKey(const GrCaps & caps,GrScratchKey * key) const211 void GrSurfaceProxy::computeScratchKey(const GrCaps& caps, GrScratchKey* key) const {
212     SkASSERT(!this->isFullyLazy());
213     GrRenderable renderable = GrRenderable::kNo;
214     int sampleCount = 1;
215     if (const auto* rtp = this->asRenderTargetProxy()) {
216         renderable = GrRenderable::kYes;
217         sampleCount = rtp->numSamples();
218     }
219 
220     const GrTextureProxy* tp = this->asTextureProxy();
221     GrMipMapped mipMapped = GrMipMapped::kNo;
222     if (tp) {
223         mipMapped = tp->mipMapped();
224     }
225 
226     GrTexturePriv::ComputeScratchKey(caps, this->backendFormat(), this->backingStoreDimensions(),
227                                      renderable, sampleCount, mipMapped, fIsProtected, key);
228 }
229 
setLastRenderTask(GrRenderTask * renderTask)230 void GrSurfaceProxy::setLastRenderTask(GrRenderTask* renderTask) {
231 #ifdef SK_DEBUG
232     if (fLastRenderTask) {
233         SkASSERT(fLastRenderTask->isClosed());
234     }
235 #endif
236 
237     // Un-reffed
238     fLastRenderTask = renderTask;
239 }
240 
getLastOpsTask()241 GrOpsTask* GrSurfaceProxy::getLastOpsTask() {
242     return fLastRenderTask ? fLastRenderTask->asOpsTask() : nullptr;
243 }
244 
backingStoreDimensions() const245 SkISize GrSurfaceProxy::backingStoreDimensions() const {
246     SkASSERT(!this->isFullyLazy());
247     if (fTarget) {
248         return fTarget->dimensions();
249     }
250 
251     if (SkBackingFit::kExact == fFit) {
252         return fDimensions;
253     }
254     return GrResourceProvider::MakeApprox(fDimensions);
255 }
256 
isFunctionallyExact() const257 bool GrSurfaceProxy::isFunctionallyExact() const {
258     SkASSERT(!this->isFullyLazy());
259     return fFit == SkBackingFit::kExact ||
260            fDimensions == GrResourceProvider::MakeApprox(fDimensions);
261 }
262 
isFormatCompressed(const GrCaps * caps) const263 bool GrSurfaceProxy::isFormatCompressed(const GrCaps* caps) const {
264     return caps->isFormatCompressed(this->backendFormat());
265 }
266 
267 #ifdef SK_DEBUG
validate(GrContext_Base * context) const268 void GrSurfaceProxy::validate(GrContext_Base* context) const {
269     if (fTarget) {
270         SkASSERT(fTarget->getContext() == context);
271     }
272 }
273 #endif
274 
Copy(GrRecordingContext * context,GrSurfaceProxy * src,GrSurfaceOrigin origin,GrColorType srcColorType,GrMipMapped mipMapped,SkIRect srcRect,SkBackingFit fit,SkBudgeted budgeted,RectsMustMatch rectsMustMatch)275 GrSurfaceProxyView GrSurfaceProxy::Copy(GrRecordingContext* context,
276                                         GrSurfaceProxy* src,
277                                         GrSurfaceOrigin origin,
278                                         GrColorType srcColorType,
279                                         GrMipMapped mipMapped,
280                                         SkIRect srcRect,
281                                         SkBackingFit fit,
282                                         SkBudgeted budgeted,
283                                         RectsMustMatch rectsMustMatch) {
284     SkASSERT(!src->isFullyLazy());
285     int width;
286     int height;
287 
288     SkIPoint dstPoint;
289     if (rectsMustMatch == RectsMustMatch::kYes) {
290         width = src->width();
291         height = src->height();
292         dstPoint = {srcRect.fLeft, srcRect.fTop};
293     } else {
294         width = srcRect.width();
295         height = srcRect.height();
296         dstPoint = {0, 0};
297     }
298 
299     if (!srcRect.intersect(SkIRect::MakeSize(src->dimensions()))) {
300         return {};
301     }
302     auto format = src->backendFormat().makeTexture2D();
303     SkASSERT(format.isValid());
304 
305     if (src->backendFormat().textureType() != GrTextureType::kExternal) {
306         auto dstContext = GrSurfaceContext::Make(context, {width, height}, format,
307                                                  GrRenderable::kNo, 1, mipMapped,
308                                                  src->isProtected(), origin, srcColorType,
309                                                  kUnknown_SkAlphaType, nullptr, fit, budgeted);
310         if (dstContext && dstContext->copy(src, origin, srcRect, dstPoint)) {
311             return dstContext->readSurfaceView();
312         }
313     }
314     if (src->asTextureProxy()) {
315         auto dstContext = GrRenderTargetContext::Make(context, srcColorType, nullptr, fit,
316                                                       {width, height}, format, 1,
317                                                       mipMapped, src->isProtected(), origin,
318                                                       budgeted, nullptr);
319         GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(src->backendFormat(),
320                                                                    srcColorType);
321         GrSurfaceProxyView view(sk_ref_sp(src), origin, swizzle);
322         if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
323             return dstContext->readSurfaceView();
324         }
325     }
326     // Can't use backend copies or draws.
327     return {};
328 }
329 
Copy(GrRecordingContext * context,GrSurfaceProxy * src,GrSurfaceOrigin origin,GrColorType srcColorType,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted)330 GrSurfaceProxyView GrSurfaceProxy::Copy(GrRecordingContext* context, GrSurfaceProxy* src,
331                                         GrSurfaceOrigin origin, GrColorType srcColorType,
332                                         GrMipMapped mipMapped, SkBackingFit fit,
333                                         SkBudgeted budgeted) {
334     SkASSERT(!src->isFullyLazy());
335     return Copy(context, src, origin, srcColorType, mipMapped, SkIRect::MakeSize(src->dimensions()),
336                 fit, budgeted);
337 }
338 
339 #if GR_TEST_UTILS
testingOnly_getBackingRefCnt() const340 int32_t GrSurfaceProxy::testingOnly_getBackingRefCnt() const {
341     if (fTarget) {
342         return fTarget->testingOnly_getRefCnt();
343     }
344 
345     return -1; // no backing GrSurface
346 }
347 
testingOnly_getFlags() const348 GrInternalSurfaceFlags GrSurfaceProxy::testingOnly_getFlags() const {
349     return fSurfaceFlags;
350 }
351 #endif
352 
exactify(bool allocatedCaseOnly)353 void GrSurfaceProxyPriv::exactify(bool allocatedCaseOnly) {
354     SkASSERT(!fProxy->isFullyLazy());
355     if (this->isExact()) {
356         return;
357     }
358 
359     SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
360 
361     if (fProxy->fTarget) {
362         // The kApprox but already instantiated case. Setting the proxy's width & height to
363         // the instantiated width & height could have side-effects going forward, since we're
364         // obliterating the area of interest information. This call (exactify) only used
365         // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
366         // used for additional draws.
367         fProxy->fDimensions = fProxy->fTarget->dimensions();
368         return;
369     }
370 
371 #ifndef SK_CRIPPLE_TEXTURE_REUSE
372     // In the post-implicit-allocation world we can't convert this proxy to be exact fit
373     // at this point. With explicit allocation switching this to exact will result in a
374     // different allocation at flush time. With implicit allocation, allocation would occur
375     // at draw time (rather than flush time) so this pathway was encountered less often (if
376     // at all).
377     if (allocatedCaseOnly) {
378         return;
379     }
380 #endif
381 
382     // The kApprox uninstantiated case. Making this proxy be exact should be okay.
383     // It could mess things up if prior decisions were based on the approximate size.
384     fProxy->fFit = SkBackingFit::kExact;
385     // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
386     // already been computed we want to leave it alone so that amount will be removed when
387     // the special image goes away. If it hasn't been computed yet it might as well compute the
388     // exact amount.
389 }
390 
doLazyInstantiation(GrResourceProvider * resourceProvider)391 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
392     SkASSERT(fProxy->isLazy());
393 
394     sk_sp<GrSurface> surface;
395     if (fProxy->asTextureProxy() && fProxy->asTextureProxy()->getUniqueKey().isValid()) {
396         // First try to reattach to a cached version if the proxy is uniquely keyed
397         surface = resourceProvider->findByUniqueKey<GrSurface>(
398                                                         fProxy->asTextureProxy()->getUniqueKey());
399     }
400 
401     bool syncKey = true;
402     bool releaseCallback = false;
403     if (!surface) {
404         auto result = fProxy->fLazyInstantiateCallback(resourceProvider);
405         surface = std::move(result.fSurface);
406         syncKey = result.fKeyMode == GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
407         releaseCallback = surface && result.fReleaseCallback;
408     }
409     if (!surface) {
410         fProxy->fDimensions.setEmpty();
411         return false;
412     }
413 
414     if (fProxy->isFullyLazy()) {
415         // This was a fully lazy proxy. We need to fill in the width & height. For partially
416         // lazy proxies we must preserve the original width & height since that indicates
417         // the content area.
418         fProxy->fDimensions = surface->dimensions();
419     }
420 
421     SkASSERT(fProxy->width() <= surface->width());
422     SkASSERT(fProxy->height() <= surface->height());
423 
424     if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
425         texProxy->setTargetKeySync(syncKey);
426         if (syncKey) {
427             const GrUniqueKey& key = texProxy->getUniqueKey();
428             if (key.isValid()) {
429                 if (!surface->asTexture()->getUniqueKey().isValid()) {
430                     // If 'surface' is newly created, attach the unique key
431                     resourceProvider->assignUniqueKeyToResource(key, surface.get());
432                 } else {
433                     // otherwise we had better have reattached to a cached version
434                     SkASSERT(surface->asTexture()->getUniqueKey() == key);
435                 }
436             } else {
437                 SkASSERT(!surface->getUniqueKey().isValid());
438             }
439         }
440     }
441 
442     this->assign(std::move(surface));
443     if (releaseCallback) {
444         fProxy->fLazyInstantiateCallback = nullptr;
445     }
446 
447     return true;
448 }
449 
450 #ifdef SK_DEBUG
validateSurface(const GrSurface * surface)451 void GrSurfaceProxy::validateSurface(const GrSurface* surface) {
452     SkASSERT(surface->backendFormat() == fFormat);
453 
454     this->onValidateSurface(surface);
455 }
456 #endif
457