• 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/ganesh/GrSurfaceProxy.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkPoint.h"
13 #include "include/gpu/GpuTypes.h"
14 #include "include/gpu/GrRecordingContext.h"
15 #include "src/gpu/SkBackingFit.h"
16 #include "src/gpu/Swizzle.h"
17 #include "src/gpu/ganesh/GrCaps.h"
18 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
19 #include "src/gpu/ganesh/GrImageInfo.h"
20 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
21 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
22 #include "src/gpu/ganesh/GrRenderTask.h"
23 #include "src/gpu/ganesh/GrResourceProvider.h"
24 #include "src/gpu/ganesh/GrSurface.h"
25 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
26 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
27 #include "src/gpu/ganesh/GrTexture.h"
28 #include "src/gpu/ganesh/GrTextureProxy.h"
29 #include "src/gpu/ganesh/SurfaceContext.h"
30 #include "src/gpu/ganesh/SurfaceFillContext.h"
31 
32 #include <memory>
33 
34 #ifdef SK_DEBUG
35 #include "include/gpu/GrDirectContext.h"
36 #include "src/gpu/ganesh/GrDirectContextPriv.h"
37 
is_valid_lazy(const SkISize & dimensions,SkBackingFit fit)38 static bool is_valid_lazy(const SkISize& dimensions, SkBackingFit fit) {
39     // A "fully" lazy proxy's width and height are not known until instantiation time.
40     // So fully lazy proxies are created with width and height < 0. Regular lazy proxies must be
41     // created with positive widths and heights. The width and height are set to 0 only after a
42     // failed instantiation. The former must be "approximate" fit while the latter can be either.
43     return ((dimensions.fWidth < 0 && dimensions.fHeight < 0 && SkBackingFit::kApprox == fit) ||
44             (dimensions.fWidth > 0 && dimensions.fHeight > 0));
45 }
46 
is_valid_non_lazy(SkISize dimensions)47 static bool is_valid_non_lazy(SkISize dimensions) {
48     return dimensions.fWidth > 0 && dimensions.fHeight > 0;
49 }
50 #endif
51 
LazyCallbackResult(sk_sp<GrSurface> surf,bool releaseCallback,LazyInstantiationKeyMode mode)52 GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult(sk_sp<GrSurface> surf,
53                                                        bool releaseCallback,
54                                                        LazyInstantiationKeyMode mode)
55         : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {}
LazyCallbackResult(sk_sp<GrTexture> tex)56 GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult(sk_sp<GrTexture> tex)
57         : LazyCallbackResult(sk_sp<GrSurface>(std::move(tex))) {}
58 
59 // Deferred version
GrSurfaceProxy(const GrBackendFormat & format,SkISize dimensions,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator,std::string_view label)60 GrSurfaceProxy::GrSurfaceProxy(const GrBackendFormat& format,
61                                SkISize dimensions,
62                                SkBackingFit fit,
63                                skgpu::Budgeted budgeted,
64                                GrProtected isProtected,
65                                GrInternalSurfaceFlags surfaceFlags,
66                                UseAllocator useAllocator,
67                                std::string_view label)
68         : fSurfaceFlags(surfaceFlags)
69         , fFormat(format)
70         , fDimensions(dimensions)
71         , fFit(fit)
72         , fBudgeted(budgeted)
73         , fUseAllocator(useAllocator)
74         , fIsProtected(isProtected)
75         , fLabel(label) {
76     SkASSERT(fFormat.isValid());
77     SkASSERT(is_valid_non_lazy(dimensions));
78 }
79 
80 // Lazy-callback version
GrSurfaceProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator,std::string_view label)81 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback,
82                                const GrBackendFormat& format,
83                                SkISize dimensions,
84                                SkBackingFit fit,
85                                skgpu::Budgeted budgeted,
86                                GrProtected isProtected,
87                                GrInternalSurfaceFlags surfaceFlags,
88                                UseAllocator useAllocator,
89                                std::string_view label)
90         : fSurfaceFlags(surfaceFlags)
91         , fFormat(format)
92         , fDimensions(dimensions)
93         , fFit(fit)
94         , fBudgeted(budgeted)
95         , fUseAllocator(useAllocator)
96         , fLazyInstantiateCallback(std::move(callback))
97         , fIsProtected(isProtected)
98         , fLabel(label) {
99     SkASSERT(fFormat.isValid());
100     SkASSERT(fLazyInstantiateCallback);
101     SkASSERT(is_valid_lazy(dimensions, fit));
102 }
103 
104 // Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface,SkBackingFit fit,UseAllocator useAllocator)105 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface,
106                                SkBackingFit fit,
107                                UseAllocator useAllocator)
108         : fTarget(std::move(surface))
109         , fSurfaceFlags(fTarget->flags())
110         , fFormat(fTarget->backendFormat())
111         , fDimensions(fTarget->dimensions())
112         , fFit(fit)
113         , fBudgeted(fTarget->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted
114                             ? skgpu::Budgeted::kYes
115                             : skgpu::Budgeted::kNo)
116         , fUseAllocator(useAllocator)
117         , fUniqueID(fTarget->uniqueID())  // Note: converting from unique resource ID to a proxy ID!
118         , fIsProtected(fTarget->isProtected() ? GrProtected::kYes : GrProtected::kNo)
119         , fLabel(fTarget->getLabel()) {
120     SkASSERT(fFormat.isValid());
121 }
122 
~GrSurfaceProxy()123 GrSurfaceProxy::~GrSurfaceProxy() {
124 }
125 
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,GrMipmapped mipmapped) const126 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider,
127                                                    int sampleCnt,
128                                                    GrRenderable renderable,
129                                                    GrMipmapped mipmapped) const {
130     SkASSERT(mipmapped == GrMipmapped::kNo || fFit == SkBackingFit::kExact);
131     SkASSERT(!this->isLazy());
132     SkASSERT(!fTarget);
133 
134     sk_sp<GrSurface> surface;
135     if (SkBackingFit::kApprox == fFit) {
136         surface = resourceProvider->createApproxTexture(fDimensions,
137                                                         fFormat,
138                                                         fFormat.textureType(),
139                                                         renderable,
140                                                         sampleCnt,
141                                                         fIsProtected,
142                                                         fLabel);
143     } else {
144         surface = resourceProvider->createTexture(fDimensions,
145                                                   fFormat,
146                                                   fFormat.textureType(),
147                                                   renderable,
148                                                   sampleCnt,
149                                                   mipmapped,
150                                                   fBudgeted,
151                                                   fIsProtected,
152                                                   fLabel);
153     }
154     if (!surface) {
155         return nullptr;
156     }
157 
158     return surface;
159 }
160 
canSkipResourceAllocator() const161 bool GrSurfaceProxy::canSkipResourceAllocator() const {
162     if (fUseAllocator == UseAllocator::kNo) {
163         // Usually an atlas or onFlush proxy
164         return true;
165     }
166 
167     auto peek = this->peekSurface();
168     if (!peek) {
169         return false;
170     }
171     // If this resource is already allocated and not recyclable then the resource allocator does
172     // not need to do anything with it.
173     return !peek->resourcePriv().getScratchKey().isValid();
174 }
175 
assign(sk_sp<GrSurface> surface)176 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
177     SkASSERT(!fTarget && surface);
178 
179     SkDEBUGCODE(this->validateSurface(surface.get());)
180 
181     fTarget = std::move(surface);
182 
183 #ifdef SK_DEBUG
184     if (this->asRenderTargetProxy()) {
185         SkASSERT(fTarget->asRenderTarget());
186     }
187 
188     // In order to give DDL users some flexibility in the destination of there DDLs,
189     // a DDL's target proxy can be more conservative (and thus require less memory)
190     // than the actual GrSurface used to fulfill it.
191     if (!this->isDDLTarget() && kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
192         // TODO(11373): Can this check be exact?
193         SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
194     }
195 #endif
196 }
197 
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,GrMipmapped mipmapped,const skgpu::UniqueKey * uniqueKey)198 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt,
199                                      GrRenderable renderable, GrMipmapped mipmapped,
200                                      const skgpu::UniqueKey* uniqueKey) {
201     SkASSERT(!this->isLazy());
202     if (fTarget) {
203         if (uniqueKey && uniqueKey->isValid()) {
204             SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey);
205         }
206         return true;
207     }
208 
209     sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, renderable,
210                                                        mipmapped);
211     if (!surface) {
212         return false;
213     }
214 
215     // If there was an invalidation message pending for this key, we might have just processed it,
216     // causing the key (stored on this proxy) to become invalid.
217     if (uniqueKey && uniqueKey->isValid()) {
218         resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
219     }
220 
221     this->assign(std::move(surface));
222 
223     return true;
224 }
225 
deinstantiate()226 void GrSurfaceProxy::deinstantiate() {
227     SkASSERT(this->isInstantiated());
228     fTarget = nullptr;
229 }
230 
computeScratchKey(const GrCaps & caps,skgpu::ScratchKey * key) const231 void GrSurfaceProxy::computeScratchKey(const GrCaps& caps, skgpu::ScratchKey* key) const {
232     SkASSERT(!this->isFullyLazy());
233     GrRenderable renderable = GrRenderable::kNo;
234     int sampleCount = 1;
235     if (const auto* rtp = this->asRenderTargetProxy()) {
236         renderable = GrRenderable::kYes;
237         sampleCount = rtp->numSamples();
238     }
239 
240     const GrTextureProxy* tp = this->asTextureProxy();
241     GrMipmapped mipmapped = GrMipmapped::kNo;
242     if (tp) {
243         mipmapped = tp->mipmapped();
244     }
245 
246     GrTexture::ComputeScratchKey(caps, this->backendFormat(), this->backingStoreDimensions(),
247                                  renderable, sampleCount, mipmapped, fIsProtected, key);
248 }
249 
backingStoreDimensions() const250 SkISize GrSurfaceProxy::backingStoreDimensions() const {
251     SkASSERT(!this->isFullyLazy());
252     if (fTarget) {
253         return fTarget->dimensions();
254     }
255 
256     if (SkBackingFit::kExact == fFit) {
257         return fDimensions;
258     }
259     return GrResourceProvider::MakeApprox(fDimensions);
260 }
261 
isFunctionallyExact() const262 bool GrSurfaceProxy::isFunctionallyExact() const {
263     SkASSERT(!this->isFullyLazy());
264     return fFit == SkBackingFit::kExact ||
265            fDimensions == GrResourceProvider::MakeApprox(fDimensions);
266 }
267 
isFormatCompressed(const GrCaps * caps) const268 bool GrSurfaceProxy::isFormatCompressed(const GrCaps* caps) const {
269     return caps->isFormatCompressed(this->backendFormat());
270 }
271 
272 #ifdef SK_DEBUG
validate(GrContext_Base * context) const273 void GrSurfaceProxy::validate(GrContext_Base* context) const {
274     if (fTarget) {
275         SkASSERT(fTarget->getContext()->priv().matches(context));
276     }
277 }
278 #endif
279 
Copy(GrRecordingContext * rContext,sk_sp<GrSurfaceProxy> src,GrSurfaceOrigin origin,GrMipmapped mipmapped,SkIRect srcRect,SkBackingFit fit,skgpu::Budgeted budgeted,std::string_view label,RectsMustMatch rectsMustMatch,sk_sp<GrRenderTask> * outTask)280 sk_sp<GrSurfaceProxy> GrSurfaceProxy::Copy(GrRecordingContext* rContext,
281                                            sk_sp<GrSurfaceProxy> src,
282                                            GrSurfaceOrigin origin,
283                                            GrMipmapped mipmapped,
284                                            SkIRect srcRect,
285                                            SkBackingFit fit,
286                                            skgpu::Budgeted budgeted,
287                                            std::string_view label,
288                                            RectsMustMatch rectsMustMatch,
289                                            sk_sp<GrRenderTask>* outTask) {
290     SkASSERT(!src->isFullyLazy());
291     int width;
292     int height;
293 
294     SkIPoint dstPoint;
295     if (rectsMustMatch == RectsMustMatch::kYes) {
296         width = src->width();
297         height = src->height();
298         dstPoint = {srcRect.fLeft, srcRect.fTop};
299     } else {
300         width = srcRect.width();
301         height = srcRect.height();
302         dstPoint = {0, 0};
303     }
304 
305     if (!srcRect.intersect(SkIRect::MakeSize(src->dimensions()))) {
306         return {};
307     }
308     auto format = src->backendFormat().makeTexture2D();
309     SkASSERT(format.isValid());
310 
311     if (src->backendFormat().textureType() != GrTextureType::kExternal) {
312         GrImageInfo info(GrColorType::kUnknown, kUnknown_SkAlphaType, nullptr, {width, height});
313         auto dstContext = rContext->priv().makeSC(info,
314                                                   format,
315                                                   label,
316                                                   fit,
317                                                   origin,
318                                                   GrRenderable::kNo,
319                                                   1,
320                                                   mipmapped,
321                                                   src->isProtected(),
322                                                   budgeted);
323         sk_sp<GrRenderTask> copyTask;
324         if (dstContext && (copyTask = dstContext->copy(src, srcRect, dstPoint))) {
325             if (outTask) {
326                 *outTask = std::move(copyTask);
327             }
328             return dstContext->asSurfaceProxyRef();
329         }
330     }
331     if (src->asTextureProxy()) {
332         auto dstContext = rContext->priv().makeSFC(kUnknown_SkAlphaType,
333                                                    nullptr,
334                                                    {width, height},
335                                                    fit,
336                                                    format,
337                                                    1,
338                                                    mipmapped,
339                                                    src->isProtected(),
340                                                    skgpu::Swizzle::RGBA(),
341                                                    skgpu::Swizzle::RGBA(),
342                                                    origin,
343                                                    budgeted,
344                                                    label);
345         GrSurfaceProxyView view(std::move(src), origin, skgpu::Swizzle::RGBA());
346         if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
347             if (outTask) {
348                 *outTask = dstContext->refRenderTask();
349             }
350             return dstContext->asSurfaceProxyRef();
351         }
352     }
353     // Can't use backend copies or draws.
354     return nullptr;
355 }
356 
Copy(GrRecordingContext * context,sk_sp<GrSurfaceProxy> src,GrSurfaceOrigin origin,GrMipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted,std::string_view label,sk_sp<GrRenderTask> * outTask)357 sk_sp<GrSurfaceProxy> GrSurfaceProxy::Copy(GrRecordingContext* context,
358                                            sk_sp<GrSurfaceProxy> src,
359                                            GrSurfaceOrigin origin,
360                                            GrMipmapped mipmapped,
361                                            SkBackingFit fit,
362                                            skgpu::Budgeted budgeted,
363                                            std::string_view label,
364                                            sk_sp<GrRenderTask>* outTask) {
365     SkASSERT(!src->isFullyLazy());
366     auto rect = SkIRect::MakeSize(src->dimensions());
367     return Copy(context,
368                 std::move(src),
369                 origin,
370                 mipmapped,
371                 rect,
372                 fit,
373                 budgeted,
374                 label,
375                 RectsMustMatch::kNo,
376                 outTask);
377 }
378 
379 #if GR_TEST_UTILS
testingOnly_getBackingRefCnt() const380 int32_t GrSurfaceProxy::testingOnly_getBackingRefCnt() const {
381     if (fTarget) {
382         return fTarget->testingOnly_getRefCnt();
383     }
384 
385     return -1; // no backing GrSurface
386 }
387 
testingOnly_getFlags() const388 GrInternalSurfaceFlags GrSurfaceProxy::testingOnly_getFlags() const {
389     return fSurfaceFlags;
390 }
391 
dump() const392 SkString GrSurfaceProxy::dump() const {
393     SkString tmp;
394 
395     tmp.appendf("proxyID: %d - surfaceID: %d",
396                 this->uniqueID().asUInt(),
397                 this->peekSurface() ? this->peekSurface()->uniqueID().asUInt()
398                                     : -1);
399     return tmp;
400 }
401 
402 #endif
403 
exactify(bool allocatedCaseOnly)404 void GrSurfaceProxyPriv::exactify(bool allocatedCaseOnly) {
405     SkASSERT(!fProxy->isFullyLazy());
406     if (this->isExact()) {
407         return;
408     }
409 
410     SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
411 
412     if (fProxy->fTarget) {
413         // The kApprox but already instantiated case. Setting the proxy's width & height to
414         // the instantiated width & height could have side-effects going forward, since we're
415         // obliterating the area of interest information. This call (exactify) only used
416         // when converting an SkSpecialImage to an SkImage so the proxy shouldn't be
417         // used for additional draws.
418         fProxy->fDimensions = fProxy->fTarget->dimensions();
419         return;
420     }
421 
422 #ifndef SK_CRIPPLE_TEXTURE_REUSE
423     // In the post-implicit-allocation world we can't convert this proxy to be exact fit
424     // at this point. With explicit allocation switching this to exact will result in a
425     // different allocation at flush time. With implicit allocation, allocation would occur
426     // at draw time (rather than flush time) so this pathway was encountered less often (if
427     // at all).
428     if (allocatedCaseOnly) {
429         return;
430     }
431 #endif
432 
433     // The kApprox uninstantiated case. Making this proxy be exact should be okay.
434     // It could mess things up if prior decisions were based on the approximate size.
435     fProxy->fFit = SkBackingFit::kExact;
436     // If fGpuMemorySize is used when caching specialImages for the image filter DAG. If it has
437     // already been computed we want to leave it alone so that amount will be removed when
438     // the special image goes away. If it hasn't been computed yet it might as well compute the
439     // exact amount.
440 }
441 
doLazyInstantiation(GrResourceProvider * resourceProvider)442 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
443     SkASSERT(fProxy->isLazy());
444 
445     sk_sp<GrSurface> surface;
446     if (const auto& uniqueKey = fProxy->getUniqueKey(); uniqueKey.isValid()) {
447         // First try to reattach to a cached version if the proxy is uniquely keyed
448         surface = resourceProvider->findByUniqueKey<GrSurface>(uniqueKey);
449     }
450 
451     bool syncKey = true;
452     bool releaseCallback = false;
453     if (!surface) {
454         auto result = fProxy->fLazyInstantiateCallback(resourceProvider, fProxy->callbackDesc());
455         surface = std::move(result.fSurface);
456         syncKey = result.fKeyMode == GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
457         releaseCallback = surface && result.fReleaseCallback;
458     }
459     if (!surface) {
460         fProxy->fDimensions.setEmpty();
461         return false;
462     }
463 
464     if (fProxy->isFullyLazy()) {
465         // This was a fully lazy proxy. We need to fill in the width & height. For partially
466         // lazy proxies we must preserve the original width & height since that indicates
467         // the content area.
468         fProxy->fDimensions = surface->dimensions();
469     }
470 
471     SkASSERT(fProxy->width() <= surface->width());
472     SkASSERT(fProxy->height() <= surface->height());
473 
474     if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
475         texProxy->setTargetKeySync(syncKey);
476         if (syncKey) {
477             const skgpu::UniqueKey& key = texProxy->getUniqueKey();
478             if (key.isValid()) {
479                 if (!surface->asTexture()->getUniqueKey().isValid()) {
480                     // If 'surface' is newly created, attach the unique key
481                     resourceProvider->assignUniqueKeyToResource(key, surface.get());
482                 } else {
483                     // otherwise we had better have reattached to a cached version
484                     SkASSERT(surface->asTexture()->getUniqueKey() == key);
485                 }
486             } else {
487                 SkASSERT(!surface->getUniqueKey().isValid());
488             }
489         }
490     }
491 
492     this->assign(std::move(surface));
493     if (releaseCallback) {
494         fProxy->fLazyInstantiateCallback = nullptr;
495     }
496 
497     return true;
498 }
499 
500 #ifdef SK_DEBUG
validateSurface(const GrSurface * surface)501 void GrSurfaceProxy::validateSurface(const GrSurface* surface) {
502     SkASSERTF(surface->backendFormat() == fFormat, "%s != %s",
503               surface->backendFormat().toStr().c_str(), fFormat.toStr().c_str());
504 
505     this->onValidateSurface(surface);
506 }
507 #endif
508