• 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/GrOpList.h"
20 #include "src/gpu/GrProxyProvider.h"
21 #include "src/gpu/GrRecordingContextPriv.h"
22 #include "src/gpu/GrStencilAttachment.h"
23 #include "src/gpu/GrSurfacePriv.h"
24 #include "src/gpu/GrTextureContext.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_fully_lazy(const GrSurfaceDesc & desc,SkBackingFit fit)32 static bool is_valid_fully_lazy(const GrSurfaceDesc& desc, SkBackingFit fit) {
33     return desc.fWidth <= 0 &&
34            desc.fHeight <= 0 &&
35            desc.fConfig != kUnknown_GrPixelConfig &&
36            SkBackingFit::kApprox == fit;
37 }
38 
is_valid_partially_lazy(const GrSurfaceDesc & desc)39 static bool is_valid_partially_lazy(const GrSurfaceDesc& desc) {
40     return ((desc.fWidth > 0 && desc.fHeight > 0) ||
41             (desc.fWidth <= 0 && desc.fHeight <= 0))  &&
42            desc.fConfig != kUnknown_GrPixelConfig;
43 }
44 
is_valid_non_lazy(const GrSurfaceDesc & desc)45 static bool is_valid_non_lazy(const GrSurfaceDesc& desc) {
46     return desc.fWidth > 0 &&
47            desc.fHeight > 0 &&
48            desc.fConfig != kUnknown_GrPixelConfig;
49 }
50 #endif
51 
52 // Lazy-callback version
GrSurfaceProxy(LazyInstantiateCallback && callback,LazyInstantiationType lazyType,const GrBackendFormat & format,const GrSurfaceDesc & desc,GrRenderable renderable,GrSurfaceOrigin origin,const GrSwizzle & textureSwizzle,SkBackingFit fit,SkBudgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags)53 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType,
54                                const GrBackendFormat& format, const GrSurfaceDesc& desc,
55                                GrRenderable renderable, GrSurfaceOrigin origin,
56                                const GrSwizzle& textureSwizzle, SkBackingFit fit,
57                                SkBudgeted budgeted, GrProtected isProtected,
58                                GrInternalSurfaceFlags surfaceFlags)
59         : fSurfaceFlags(surfaceFlags)
60         , fFormat(format)
61         , fConfig(desc.fConfig)
62         , fWidth(desc.fWidth)
63         , fHeight(desc.fHeight)
64         , fOrigin(origin)
65         , fTextureSwizzle(textureSwizzle)
66         , fFit(fit)
67         , fBudgeted(budgeted)
68         , fLazyInstantiateCallback(std::move(callback))
69         , fLazyInstantiationType(lazyType)
70         , fIsProtected(isProtected)
71         , fGpuMemorySize(kInvalidGpuMemorySize)
72         , fLastRenderTask(nullptr) {
73     SkASSERT(fFormat.isValid());
74     // NOTE: the default fUniqueID ctor pulls a value from the same pool as the GrGpuResources.
75     if (fLazyInstantiateCallback) {
76         SkASSERT(is_valid_fully_lazy(desc, fit) || is_valid_partially_lazy(desc));
77     } else {
78         SkASSERT(is_valid_non_lazy(desc));
79     }
80 
81     if (GrPixelConfigIsCompressed(desc.fConfig)) {
82         SkASSERT(renderable == GrRenderable::kNo);
83         fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
84     }
85 }
86 
87 // Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface,GrSurfaceOrigin origin,const GrSwizzle & textureSwizzle,SkBackingFit fit)88 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin,
89                                const GrSwizzle& textureSwizzle, SkBackingFit fit)
90         : fTarget(std::move(surface))
91         , fSurfaceFlags(fTarget->surfacePriv().flags())
92         , fFormat(fTarget->backendFormat())
93         , fConfig(fTarget->config())
94         , fWidth(fTarget->width())
95         , fHeight(fTarget->height())
96         , fOrigin(origin)
97         , fTextureSwizzle(textureSwizzle)
98         , fFit(fit)
99         , fBudgeted(fTarget->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted
100                             ? SkBudgeted::kYes
101                             : SkBudgeted::kNo)
102         , fUniqueID(fTarget->uniqueID())  // Note: converting from unique resource ID to a proxy ID!
103         , fIsProtected(fTarget->isProtected() ? GrProtected::kYes : GrProtected::kNo)
104         , fGpuMemorySize(kInvalidGpuMemorySize)
105         , fLastRenderTask(nullptr) {
106     SkASSERT(fFormat.isValid());
107 }
108 
~GrSurfaceProxy()109 GrSurfaceProxy::~GrSurfaceProxy() {
110     // For this to be deleted the opList that held a ref on it (if there was one) must have been
111     // deleted. Which would have cleared out this back pointer.
112     SkASSERT(!fLastRenderTask);
113 }
114 
AttachStencilIfNeeded(GrResourceProvider * resourceProvider,GrSurface * surface,int minStencilSampleCount)115 bool GrSurfaceProxyPriv::AttachStencilIfNeeded(GrResourceProvider* resourceProvider,
116                                                GrSurface* surface, int minStencilSampleCount) {
117     if (minStencilSampleCount) {
118         GrRenderTarget* rt = surface->asRenderTarget();
119         if (!rt) {
120             SkASSERT(0);
121             return false;
122         }
123 
124         if (!resourceProvider->attachStencilAttachment(rt, minStencilSampleCount)) {
125             return false;
126         }
127     }
128 
129     return true;
130 }
131 
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,int minStencilSampleCount,GrRenderable renderable,GrMipMapped mipMapped) const132 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider,
133                                                    int sampleCnt,
134                                                    int minStencilSampleCount,
135                                                    GrRenderable renderable,
136                                                    GrMipMapped mipMapped) const {
137     SkASSERT(GrSurfaceProxy::LazyState::kNot == this->lazyInstantiationState());
138     SkASSERT(!fTarget);
139     GrSurfaceDesc desc;
140     desc.fWidth = fWidth;
141     desc.fHeight = fHeight;
142     desc.fConfig = fConfig;
143 
144     // The explicit resource allocator requires that any resources it pulls out of the
145     // cache have no pending IO.
146     GrResourceProvider::Flags resourceProviderFlags = GrResourceProvider::Flags::kNoPendingIO;
147 
148     sk_sp<GrSurface> surface;
149     if (GrMipMapped::kYes == mipMapped) {
150         SkASSERT(SkBackingFit::kExact == fFit);
151 
152         // SkMipMap doesn't include the base level in the level count so we have to add 1
153         int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
154         // We should have caught the case where mipCount == 1 when making the proxy and instead
155         // created a non-mipmapped proxy.
156         SkASSERT(mipCount > 1);
157         std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]);
158 
159         // We don't want to upload any texel data
160         for (int i = 0; i < mipCount; i++) {
161             texels[i].fPixels = nullptr;
162             texels[i].fRowBytes = 0;
163         }
164         surface = resourceProvider->createTexture(desc, fFormat, renderable, sampleCnt, fBudgeted,
165                                                   fIsProtected, texels.get(), mipCount);
166 #ifdef SK_DEBUG
167         if (surface) {
168             const GrTextureProxy* thisTexProxy = this->asTextureProxy();
169             SkASSERT(thisTexProxy);
170 
171             GrTexture* texture = surface->asTexture();
172             SkASSERT(texture);
173 
174             SkASSERT(GrMipMapped::kYes == texture->texturePriv().mipMapped());
175             SkASSERT(thisTexProxy->fInitialMipMapsStatus == texture->texturePriv().mipMapsStatus());
176         }
177 #endif
178     } else {
179         if (SkBackingFit::kApprox == fFit) {
180             surface = resourceProvider->createApproxTexture(desc, fFormat, renderable, sampleCnt,
181                                                             fIsProtected, resourceProviderFlags);
182         } else {
183             surface =
184                     resourceProvider->createTexture(desc, fFormat, renderable, sampleCnt, fBudgeted,
185                                                     fIsProtected, resourceProviderFlags);
186         }
187     }
188     if (!surface) {
189         return nullptr;
190     }
191 
192     if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, surface.get(),
193                                                    minStencilSampleCount)) {
194         return nullptr;
195     }
196 
197     return surface;
198 }
199 
canSkipResourceAllocator() const200 bool GrSurfaceProxy::canSkipResourceAllocator() const {
201     if (this->ignoredByResourceAllocator()) {
202         // Usually an atlas or onFlush proxy
203         return true;
204     }
205 
206     auto peek = this->peekSurface();
207     if (!peek) {
208         return false;
209     }
210     // If this resource is already allocated and not recyclable then the resource allocator does
211     // not need to do anything with it.
212     return !peek->resourcePriv().getScratchKey().isValid();
213 }
214 
assign(sk_sp<GrSurface> surface)215 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
216     SkASSERT(!fTarget && surface);
217 
218     SkDEBUGCODE(this->validateSurface(surface.get());)
219 
220     fTarget = std::move(surface);
221 
222 #ifdef SK_DEBUG
223     if (this->asRenderTargetProxy()) {
224         SkASSERT(fTarget->asRenderTarget());
225         if (int minStencilSampleCount = this->asRenderTargetProxy()->numStencilSamples()) {
226             auto* stencil = fTarget->asRenderTarget()->renderTargetPriv().getStencilAttachment();
227             SkASSERT(stencil);
228             SkASSERT(stencil->numSamples() >= minStencilSampleCount);
229         }
230     }
231 
232     if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
233         SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
234     }
235 #endif
236 }
237 
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,int minStencilSampleCount,GrRenderable renderable,GrMipMapped mipMapped,const GrUniqueKey * uniqueKey)238 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
239                                      int minStencilSampleCount, GrRenderable renderable,
240                                      GrMipMapped mipMapped, const GrUniqueKey* uniqueKey) {
241     SkASSERT(LazyState::kNot == this->lazyInstantiationState());
242     if (fTarget) {
243         if (uniqueKey && uniqueKey->isValid()) {
244             SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey);
245         }
246         return GrSurfaceProxyPriv::AttachStencilIfNeeded(resourceProvider, fTarget.get(),
247                                                          minStencilSampleCount);
248     }
249 
250     sk_sp<GrSurface> surface = this->createSurfaceImpl(
251             resourceProvider, sampleCnt, minStencilSampleCount, renderable, mipMapped);
252     if (!surface) {
253         return false;
254     }
255 
256     // If there was an invalidation message pending for this key, we might have just processed it,
257     // causing the key (stored on this proxy) to become invalid.
258     if (uniqueKey && uniqueKey->isValid()) {
259         resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
260     }
261 
262     this->assign(std::move(surface));
263 
264     return true;
265 }
266 
deinstantiate()267 void GrSurfaceProxy::deinstantiate() {
268     SkASSERT(this->isInstantiated());
269     fTarget = nullptr;
270 }
271 
computeScratchKey(GrScratchKey * key) const272 void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const {
273     SkASSERT(LazyState::kFully != this->lazyInstantiationState());
274     GrRenderable renderable = GrRenderable::kNo;
275     int sampleCount = 1;
276     if (const auto* rtp = this->asRenderTargetProxy()) {
277         renderable = GrRenderable::kYes;
278         sampleCount = rtp->numSamples();
279     }
280 
281     const GrTextureProxy* tp = this->asTextureProxy();
282     GrMipMapped mipMapped = GrMipMapped::kNo;
283     if (tp) {
284         mipMapped = tp->mipMapped();
285     }
286 
287     int width = this->worstCaseWidth();
288     int height = this->worstCaseHeight();
289 
290     GrTexturePriv::ComputeScratchKey(this->config(), width, height, renderable, sampleCount,
291                                      mipMapped, key);
292 }
293 
setLastRenderTask(GrRenderTask * renderTask)294 void GrSurfaceProxy::setLastRenderTask(GrRenderTask* renderTask) {
295 #ifdef SK_DEBUG
296     if (fLastRenderTask) {
297         SkASSERT(fLastRenderTask->isClosed());
298     }
299 #endif
300 
301     // Un-reffed
302     fLastRenderTask = renderTask;
303 }
304 
getLastRenderTargetOpList()305 GrRenderTargetOpList* GrSurfaceProxy::getLastRenderTargetOpList() {
306     return fLastRenderTask ? fLastRenderTask->asRenderTargetOpList() : nullptr;
307 }
308 
getLastTextureOpList()309 GrTextureOpList* GrSurfaceProxy::getLastTextureOpList() {
310     return fLastRenderTask ? fLastRenderTask->asTextureOpList() : nullptr;
311 }
312 
worstCaseWidth() const313 int GrSurfaceProxy::worstCaseWidth() const {
314     SkASSERT(LazyState::kFully != this->lazyInstantiationState());
315     if (fTarget) {
316         return fTarget->width();
317     }
318 
319     if (SkBackingFit::kExact == fFit) {
320         return fWidth;
321     }
322     return GrResourceProvider::MakeApprox(fWidth);
323 }
324 
worstCaseHeight() const325 int GrSurfaceProxy::worstCaseHeight() const {
326     SkASSERT(LazyState::kFully != this->lazyInstantiationState());
327     if (fTarget) {
328         return fTarget->height();
329     }
330 
331     if (SkBackingFit::kExact == fFit) {
332         return fHeight;
333     }
334     return GrResourceProvider::MakeApprox(fHeight);
335 }
336 
337 #ifdef SK_DEBUG
validate(GrContext_Base * context) const338 void GrSurfaceProxy::validate(GrContext_Base* context) const {
339     if (fTarget) {
340         SkASSERT(fTarget->getContext() == context);
341     }
342 }
343 #endif
344 
Copy(GrRecordingContext * context,GrSurfaceProxy * src,GrMipMapped mipMapped,SkIRect srcRect,SkBackingFit fit,SkBudgeted budgeted,RectsMustMatch rectsMustMatch)345 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrRecordingContext* context,
346                                            GrSurfaceProxy* src,
347                                            GrMipMapped mipMapped,
348                                            SkIRect srcRect,
349                                            SkBackingFit fit,
350                                            SkBudgeted budgeted,
351                                            RectsMustMatch rectsMustMatch) {
352     SkASSERT(LazyState::kFully != src->lazyInstantiationState());
353     GrProtected isProtected = src->isProtected() ? GrProtected::kYes : GrProtected::kNo;
354     int width;
355     int height;
356 
357     SkIPoint dstPoint;
358     if (rectsMustMatch == RectsMustMatch::kYes) {
359         width = src->width();
360         height = src->height();
361         dstPoint = {srcRect.fLeft, srcRect.fTop};
362     } else {
363         width = srcRect.width();
364         height = srcRect.height();
365         dstPoint = {0, 0};
366     }
367 
368     if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
369         return nullptr;
370     }
371     auto colorType = GrPixelConfigToColorType(src->config());
372     if (src->backendFormat().textureType() != GrTextureType::kExternal) {
373         sk_sp<GrTextureContext> dstContext(context->priv().makeDeferredTextureContext(
374                 fit, width, height, colorType, kUnknown_SkAlphaType, nullptr, mipMapped,
375                 src->origin(), budgeted, isProtected));
376         if (!dstContext) {
377             return nullptr;
378         }
379         if (dstContext->copy(src, srcRect, dstPoint)) {
380             return dstContext->asTextureProxyRef();
381         }
382     }
383     if (src->asTextureProxy()) {
384         sk_sp<GrRenderTargetContext> dstContext = context->priv().makeDeferredRenderTargetContext(
385                 fit, width, height, colorType, nullptr, 1, mipMapped, src->origin(), nullptr,
386                 budgeted);
387 
388         if (dstContext && dstContext->blitTexture(src->asTextureProxy(), srcRect, dstPoint)) {
389             return dstContext->asTextureProxyRef();
390         }
391     }
392     // Can't use backend copies or draws.
393     return nullptr;
394 }
395 
Copy(GrRecordingContext * context,GrSurfaceProxy * src,GrMipMapped mipMapped,SkBackingFit fit,SkBudgeted budgeted)396 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrRecordingContext* context, GrSurfaceProxy* src,
397                                            GrMipMapped mipMapped, SkBackingFit fit,
398                                            SkBudgeted budgeted) {
399     SkASSERT(LazyState::kFully != src->lazyInstantiationState());
400     return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), fit,
401                 budgeted);
402 }
403 
404 #if GR_TEST_UTILS
testingOnly_getBackingRefCnt() const405 int32_t GrSurfaceProxy::testingOnly_getBackingRefCnt() const {
406     if (fTarget) {
407         return fTarget->testingOnly_getRefCnt();
408     }
409 
410     return -1; // no backing GrSurface
411 }
412 
testingOnly_getFlags() const413 GrInternalSurfaceFlags GrSurfaceProxy::testingOnly_getFlags() const {
414     return fSurfaceFlags;
415 }
416 #endif
417 
exactify(bool allocatedCaseOnly)418 void GrSurfaceProxyPriv::exactify(bool allocatedCaseOnly) {
419     SkASSERT(GrSurfaceProxy::LazyState::kFully != fProxy->lazyInstantiationState());
420     if (this->isExact()) {
421         return;
422     }
423 
424     SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
425 
426     if (fProxy->fTarget) {
427         // The kApprox but already instantiated case. Setting the proxy's width & height to
428         // the instantiated width & height could have side-effects going forward, since we're
429         // obliterating the area of interest information. This call (exactify) only used
430         // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
431         // used for additional draws.
432         fProxy->fWidth = fProxy->fTarget->width();
433         fProxy->fHeight = fProxy->fTarget->height();
434         return;
435     }
436 
437 #ifndef SK_CRIPPLE_TEXTURE_REUSE
438     // In the post-implicit-allocation world we can't convert this proxy to be exact fit
439     // at this point. With explicit allocation switching this to exact will result in a
440     // different allocation at flush time. With implicit allocation, allocation would occur
441     // at draw time (rather than flush time) so this pathway was encountered less often (if
442     // at all).
443     if (allocatedCaseOnly) {
444         return;
445     }
446 #endif
447 
448     // The kApprox uninstantiated case. Making this proxy be exact should be okay.
449     // It could mess things up if prior decisions were based on the approximate size.
450     fProxy->fFit = SkBackingFit::kExact;
451     // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
452     // already been computed we want to leave it alone so that amount will be removed when
453     // the special image goes away. If it hasn't been computed yet it might as well compute the
454     // exact amount.
455 }
456 
doLazyInstantiation(GrResourceProvider * resourceProvider)457 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
458     SkASSERT(GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState());
459 
460     sk_sp<GrSurface> surface;
461     if (fProxy->asTextureProxy() && fProxy->asTextureProxy()->getUniqueKey().isValid()) {
462         // First try to reattach to a cached version if the proxy is uniquely keyed
463         surface = resourceProvider->findByUniqueKey<GrSurface>(
464                                                         fProxy->asTextureProxy()->getUniqueKey());
465     }
466 
467     bool syncKey = true;
468     if (!surface) {
469         auto result = fProxy->fLazyInstantiateCallback(resourceProvider);
470         surface = std::move(result.fSurface);
471         syncKey = result.fKeyMode == GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
472     }
473     if (GrSurfaceProxy::LazyInstantiationType::kSingleUse == fProxy->fLazyInstantiationType) {
474         fProxy->fLazyInstantiateCallback = nullptr;
475     }
476     if (!surface) {
477         fProxy->fWidth = 0;
478         fProxy->fHeight = 0;
479         return false;
480     }
481 
482     if (fProxy->fWidth <= 0 || fProxy->fHeight <= 0) {
483         // This was a fully lazy proxy. We need to fill in the width & height. For partially
484         // lazy proxies we must preserve the original width & height since that indicates
485         // the content area.
486         SkASSERT(fProxy->fWidth <= 0 && fProxy->fHeight <= 0);
487         fProxy->fWidth = surface->width();
488         fProxy->fHeight = surface->height();
489     }
490 
491     SkASSERT(fProxy->fWidth <= surface->width());
492     SkASSERT(fProxy->fHeight <= surface->height());
493 
494     int minStencilSampleCount = (fProxy->asRenderTargetProxy())
495             ? fProxy->asRenderTargetProxy()->numSamples()
496             : 0;
497 
498     if (!GrSurfaceProxyPriv::AttachStencilIfNeeded(
499             resourceProvider, surface.get(), minStencilSampleCount)) {
500         return false;
501     }
502 
503     if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
504         texProxy->setTargetKeySync(syncKey);
505         if (syncKey) {
506             const GrUniqueKey& key = texProxy->getUniqueKey();
507             if (key.isValid()) {
508                 if (!surface->asTexture()->getUniqueKey().isValid()) {
509                     // If 'surface' is newly created, attach the unique key
510                     resourceProvider->assignUniqueKeyToResource(key, surface.get());
511                 } else {
512                     // otherwise we had better have reattached to a cached version
513                     SkASSERT(surface->asTexture()->getUniqueKey() == key);
514                 }
515             } else {
516                 SkASSERT(!surface->getUniqueKey().isValid());
517             }
518         }
519     }
520 
521     this->assign(std::move(surface));
522     return true;
523 }
524 
525 #ifdef SK_DEBUG
validateSurface(const GrSurface * surface)526 void GrSurfaceProxy::validateSurface(const GrSurface* surface) {
527     SkASSERT(surface->config() == fConfig);
528 
529     this->onValidateSurface(surface);
530 }
531 #endif
532