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