• 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/ganesh/GrRecordingContext.h"
15 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
16 #include "include/gpu/vk/GrVulkanTrackerInterface.h"
17 #endif
18 #include "src/gpu/SkBackingFit.h"
19 #include "src/gpu/Swizzle.h"
20 #include "src/gpu/ganesh/GrCaps.h"
21 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
22 #include "src/gpu/ganesh/GrImageInfo.h"
23 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
24 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
25 #include "src/gpu/ganesh/GrRenderTask.h"
26 #include "src/gpu/ganesh/GrResourceProvider.h"
27 #include "src/gpu/ganesh/GrSurface.h"
28 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
29 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
30 #include "src/gpu/ganesh/GrTexture.h"
31 #include "src/gpu/ganesh/GrTextureProxy.h"
32 #include "src/gpu/ganesh/SurfaceContext.h"
33 #include "src/gpu/ganesh/SurfaceFillContext.h"
34 #ifdef SKIA_OHOS
35 #include "src/gpu/ganesh/GrPerfMonitorReporter.h"
36 #endif
37 
38 #include <memory>
39 
40 #ifdef SK_DEBUG
41 #include "include/gpu/ganesh/GrDirectContext.h"
42 #include "src/gpu/ganesh/GrDirectContextPriv.h"
43 
is_valid_lazy(const SkISize & dimensions,SkBackingFit fit)44 static bool is_valid_lazy(const SkISize& dimensions, SkBackingFit fit) {
45     // A "fully" lazy proxy's width and height are not known until instantiation time.
46     // So fully lazy proxies are created with width and height < 0. Regular lazy proxies must be
47     // created with positive widths and heights. The width and height are set to 0 only after a
48     // failed instantiation. The former must be "approximate" fit while the latter can be either.
49     return ((dimensions.fWidth < 0 && dimensions.fHeight < 0 && SkBackingFit::kApprox == fit) ||
50             (dimensions.fWidth > 0 && dimensions.fHeight > 0));
51 }
52 
is_valid_non_lazy(SkISize dimensions)53 static bool is_valid_non_lazy(SkISize dimensions) {
54     return dimensions.fWidth > 0 && dimensions.fHeight > 0;
55 }
56 #endif
57 
58 // emulator mock
59 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
60 #ifndef SK_VULKAN
61 namespace ParallelDebug {
IsVkImageDfxEnabled()62 bool IsVkImageDfxEnabled() { return false; }
RecordNodeId(uint64_t nodeId)63 void RecordNodeId(uint64_t nodeId) {}
GetNodeId()64 uint64_t GetNodeId() { return 0; }
65 }
66 #endif
67 #endif
68 
LazyCallbackResult(sk_sp<GrSurface> surf,bool releaseCallback,LazyInstantiationKeyMode mode)69 GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult(sk_sp<GrSurface> surf,
70                                                        bool releaseCallback,
71                                                        LazyInstantiationKeyMode mode)
72         : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {}
LazyCallbackResult(sk_sp<GrTexture> tex)73 GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult(sk_sp<GrTexture> tex)
74         : LazyCallbackResult(sk_sp<GrSurface>(std::move(tex))) {}
75 
76 // Deferred version
GrSurfaceProxy(const GrBackendFormat & format,SkISize dimensions,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator,std::string_view label)77 GrSurfaceProxy::GrSurfaceProxy(const GrBackendFormat& format,
78                                SkISize dimensions,
79                                SkBackingFit fit,
80                                skgpu::Budgeted budgeted,
81                                GrProtected isProtected,
82                                GrInternalSurfaceFlags surfaceFlags,
83                                UseAllocator useAllocator,
84                                std::string_view label)
85         : fSurfaceFlags(surfaceFlags)
86         , fFormat(format)
87         , fDimensions(dimensions)
88         , fFit(fit)
89         , fBudgeted(budgeted)
90         , fUseAllocator(useAllocator)
91 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
92         , fNodeId(ParallelDebug::GetNodeId())
93 #endif
94         , fIsProtected(isProtected)
95         , fLabel(label) {
96     SkASSERT(fFormat.isValid());
97     SkASSERT(is_valid_non_lazy(dimensions));
98 }
99 
100 // 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)101 GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback,
102                                const GrBackendFormat& format,
103                                SkISize dimensions,
104                                SkBackingFit fit,
105                                skgpu::Budgeted budgeted,
106                                GrProtected isProtected,
107                                GrInternalSurfaceFlags surfaceFlags,
108                                UseAllocator useAllocator,
109                                std::string_view label)
110         : fSurfaceFlags(surfaceFlags)
111         , fFormat(format)
112         , fDimensions(dimensions)
113         , fFit(fit)
114         , fBudgeted(budgeted)
115         , fUseAllocator(useAllocator)
116         , fLazyInstantiateCallback(std::move(callback))
117 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
118         , fNodeId(ParallelDebug::GetNodeId())
119 #endif
120         , fIsProtected(isProtected)
121         , fLabel(label) {
122     SkASSERT(fFormat.isValid());
123     SkASSERT(fLazyInstantiateCallback);
124     SkASSERT(is_valid_lazy(dimensions, fit));
125 }
126 
127 // Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface,SkBackingFit fit,UseAllocator useAllocator)128 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface,
129                                SkBackingFit fit,
130                                UseAllocator useAllocator)
131         : fTarget(std::move(surface))
132         , fSurfaceFlags(fTarget->flags())
133         , fFormat(fTarget->backendFormat())
134         , fDimensions(fTarget->dimensions())
135         , fFit(fit)
136         , fBudgeted(fTarget->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted
137                             ? skgpu::Budgeted::kYes
138                             : skgpu::Budgeted::kNo)
139         , fUseAllocator(useAllocator)
140         , fUniqueID(fTarget->uniqueID())  // Note: converting from unique resource ID to a proxy ID!
141 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
142         , fNodeId(ParallelDebug::GetNodeId())
143 #endif
144         , fIsProtected(fTarget->isProtected() ? GrProtected::kYes : GrProtected::kNo)
145         , fLabel(fTarget->getLabel()) {
146     SkASSERT(fFormat.isValid());
147 }
148 
~GrSurfaceProxy()149 GrSurfaceProxy::~GrSurfaceProxy() {
150 }
151 
152 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
153 struct NodeIdHelper {
NodeIdHelperNodeIdHelper154     explicit inline NodeIdHelper(uint64_t nodeId): initNodeId_(ParallelDebug::GetNodeId())
155     {
156         ParallelDebug::RecordNodeId(nodeId);
157     }
~NodeIdHelperNodeIdHelper158     inline ~NodeIdHelper()
159     {
160         ParallelDebug::RecordNodeId(initNodeId_);
161     }
162     uint64_t initNodeId_;
163 };
164 #endif
165 
createSurfaceImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,skgpu::Mipmapped mipmapped) const166 sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider,
167                                                    int sampleCnt,
168                                                    GrRenderable renderable,
169                                                    skgpu::Mipmapped mipmapped) const {
170 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
171     NodeIdHelper helper(fNodeId);
172 #endif
173     SkASSERT(mipmapped == skgpu::Mipmapped::kNo || fFit == SkBackingFit::kExact);
174     SkASSERT(!this->isLazy());
175     SkASSERT(!fTarget);
176 #ifdef SKIA_OHOS
177     int64_t currentTime = GrPerfMonitorReporter::getCurrentTime();
178 #endif
179     sk_sp<GrSurface> surface;
180     if (SkBackingFit::kApprox == fFit) {
181         surface = resourceProvider->createApproxTexture(fDimensions,
182                                                         fFormat,
183                                                         fFormat.textureType(),
184                                                         renderable,
185                                                         sampleCnt,
186                                                         fIsProtected,
187                                                         fLabel);
188     } else {
189         surface = resourceProvider->createTexture(fDimensions,
190                                                   fFormat,
191                                                   fFormat.textureType(),
192                                                   renderable,
193                                                   sampleCnt,
194                                                   mipmapped,
195                                                   fBudgeted,
196                                                   fIsProtected,
197                                                   fLabel);
198     }
199     if (!surface) {
200         return nullptr;
201     }
202 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
203     if (ParallelDebug::IsVkImageDfxEnabled()) {
204         surface->updateNodeId(fNodeId);
205     }
206 #endif
207 
208     if (fGrProxyTag.isGrTagValid()) {
209         surface->setResourceTag(fGrProxyTag);
210 #ifdef SKIA_OHOS
211         int64_t allocTime = GrPerfMonitorReporter::getCurrentTime() - currentTime;
212         GrPerfMonitorReporter::GetInstance().recordTextureNode(fGrProxyTag.fName, allocTime);
213         GrPerfMonitorReporter::GetInstance().recordTexturePerfEvent(fGrProxyTag.fName,
214             fGrProxyTag.fPid, static_cast<int32_t>(resourceProvider->getMaxResourceBytes()),
215             static_cast<int32_t>(resourceProvider->getBudgetedResourceBytes()), allocTime);
216 #endif
217     }
218 
219     return surface;
220 }
221 
canSkipResourceAllocator() const222 bool GrSurfaceProxy::canSkipResourceAllocator() const {
223     if (fUseAllocator == UseAllocator::kNo) {
224         // Usually an atlas or onFlush proxy
225         return true;
226     }
227 
228     auto peek = this->peekSurface();
229     if (!peek) {
230         return false;
231     }
232     // If this resource is already allocated and not recyclable then the resource allocator does
233     // not need to do anything with it.
234     return !peek->resourcePriv().getScratchKey().isValid();
235 }
236 
assign(sk_sp<GrSurface> surface)237 void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
238     SkASSERT(!fTarget && surface);
239 
240     SkDEBUGCODE(this->validateSurface(surface.get());)
241 
242     fTarget = std::move(surface);
243 
244 #ifdef SK_DEBUG
245     if (this->asRenderTargetProxy()) {
246         SkASSERT(fTarget->asRenderTarget());
247     }
248 
249     // In order to give DDL users some flexibility in the destination of there DDLs,
250     // a DDL's target proxy can be more conservative (and thus require less memory)
251     // than the actual GrSurface used to fulfill it.
252     if (!this->isDDLTarget() && kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
253         // TODO(11373): Can this check be exact?
254         SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
255     }
256 #endif
257 }
258 
instantiateImpl(GrResourceProvider * resourceProvider,int sampleCnt,GrRenderable renderable,skgpu::Mipmapped mipmapped,const skgpu::UniqueKey * uniqueKey)259 bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider,
260                                      int sampleCnt,
261                                      GrRenderable renderable,
262                                      skgpu::Mipmapped mipmapped,
263                                      const skgpu::UniqueKey* uniqueKey) {
264     SkASSERT(!this->isLazy());
265     if (fTarget) {
266         if (uniqueKey && uniqueKey->isValid()) {
267             SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey);
268         }
269         return true;
270     }
271 
272     sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, renderable,
273                                                        mipmapped);
274     if (!surface) {
275         return false;
276     }
277 
278     // If there was an invalidation message pending for this key, we might have just processed it,
279     // causing the key (stored on this proxy) to become invalid.
280     if (uniqueKey && uniqueKey->isValid()) {
281         resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
282     }
283 
284     this->assign(std::move(surface));
285 
286     return true;
287 }
288 
deinstantiate()289 void GrSurfaceProxy::deinstantiate() {
290     SkASSERT(this->isInstantiated());
291     fTarget = nullptr;
292 }
293 
computeScratchKey(const GrCaps & caps,skgpu::ScratchKey * key) const294 void GrSurfaceProxy::computeScratchKey(const GrCaps& caps, skgpu::ScratchKey* key) const {
295     SkASSERT(!this->isFullyLazy());
296     GrRenderable renderable = GrRenderable::kNo;
297     int sampleCount = 1;
298     if (const auto* rtp = this->asRenderTargetProxy()) {
299         renderable = GrRenderable::kYes;
300         sampleCount = rtp->numSamples();
301     }
302 
303     const GrTextureProxy* tp = this->asTextureProxy();
304     skgpu::Mipmapped mipmapped = skgpu::Mipmapped::kNo;
305     if (tp) {
306         mipmapped = tp->mipmapped();
307     }
308 
309     GrTexture::ComputeScratchKey(caps, this->backendFormat(), this->backingStoreDimensions(),
310                                  renderable, sampleCount, mipmapped, fIsProtected, key);
311 }
312 
backingStoreDimensions() const313 SkISize GrSurfaceProxy::backingStoreDimensions() const {
314     SkASSERT(!this->isFullyLazy());
315     if (fTarget) {
316         return fTarget->dimensions();
317     }
318 
319     if (SkBackingFit::kExact == fFit) {
320         return fDimensions;
321     }
322     return skgpu::GetApproxSize(fDimensions);
323 }
324 
isFunctionallyExact() const325 bool GrSurfaceProxy::isFunctionallyExact() const {
326     SkASSERT(!this->isFullyLazy());
327     return fFit == SkBackingFit::kExact ||
328            fDimensions == skgpu::GetApproxSize(fDimensions);
329 }
330 
isFormatCompressed(const GrCaps * caps) const331 bool GrSurfaceProxy::isFormatCompressed(const GrCaps* caps) const {
332     return caps->isFormatCompressed(this->backendFormat());
333 }
334 
335 #ifdef SK_DEBUG
validate(GrContext_Base * context) const336 void GrSurfaceProxy::validate(GrContext_Base* context) const {
337     if (fTarget) {
338         SkASSERT(fTarget->getContext()->priv().matches(context));
339     }
340 }
341 #endif
342 
Copy(GrRecordingContext * rContext,sk_sp<GrSurfaceProxy> src,GrSurfaceOrigin origin,skgpu::Mipmapped mipmapped,SkIRect srcRect,SkBackingFit fit,skgpu::Budgeted budgeted,std::string_view label,RectsMustMatch rectsMustMatch,sk_sp<GrRenderTask> * outTask)343 sk_sp<GrSurfaceProxy> GrSurfaceProxy::Copy(GrRecordingContext* rContext,
344                                            sk_sp<GrSurfaceProxy> src,
345                                            GrSurfaceOrigin origin,
346                                            skgpu::Mipmapped mipmapped,
347                                            SkIRect srcRect,
348                                            SkBackingFit fit,
349                                            skgpu::Budgeted budgeted,
350                                            std::string_view label,
351                                            RectsMustMatch rectsMustMatch,
352                                            sk_sp<GrRenderTask>* outTask) {
353     SkASSERT(!src->isFullyLazy());
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::MakeSize(src->dimensions()))) {
369         return {};
370     }
371     auto format = src->backendFormat().makeTexture2D();
372     SkASSERT(format.isValid());
373 
374     if (src->backendFormat().textureType() != GrTextureType::kExternal) {
375         GrImageInfo info(GrColorType::kUnknown, kUnknown_SkAlphaType, nullptr, {width, height});
376         auto dstContext = rContext->priv().makeSC(info,
377                                                   format,
378                                                   label,
379                                                   fit,
380                                                   origin,
381                                                   GrRenderable::kNo,
382                                                   1,
383                                                   mipmapped,
384                                                   src->isProtected(),
385                                                   budgeted);
386         sk_sp<GrRenderTask> copyTask;
387         if (dstContext && (copyTask = dstContext->copy(src, srcRect, dstPoint))) {
388             if (outTask) {
389                 *outTask = std::move(copyTask);
390             }
391             return dstContext->asSurfaceProxyRef();
392         }
393     }
394     if (src->asTextureProxy()) {
395         auto dstContext = rContext->priv().makeSFC(kUnknown_SkAlphaType,
396                                                    nullptr,
397                                                    {width, height},
398                                                    fit,
399                                                    format,
400                                                    1,
401                                                    mipmapped,
402                                                    src->isProtected(),
403                                                    skgpu::Swizzle::RGBA(),
404                                                    skgpu::Swizzle::RGBA(),
405                                                    origin,
406                                                    budgeted,
407                                                    label);
408         GrSurfaceProxyView view(std::move(src), origin, skgpu::Swizzle::RGBA());
409         if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
410             if (outTask) {
411                 *outTask = dstContext->refRenderTask();
412             }
413             return dstContext->asSurfaceProxyRef();
414         }
415     }
416     // Can't use backend copies or draws.
417     return nullptr;
418 }
419 
Copy(GrRecordingContext * context,sk_sp<GrSurfaceProxy> src,GrSurfaceOrigin origin,skgpu::Mipmapped mipmapped,SkBackingFit fit,skgpu::Budgeted budgeted,std::string_view label,sk_sp<GrRenderTask> * outTask)420 sk_sp<GrSurfaceProxy> GrSurfaceProxy::Copy(GrRecordingContext* context,
421                                            sk_sp<GrSurfaceProxy> src,
422                                            GrSurfaceOrigin origin,
423                                            skgpu::Mipmapped mipmapped,
424                                            SkBackingFit fit,
425                                            skgpu::Budgeted budgeted,
426                                            std::string_view label,
427                                            sk_sp<GrRenderTask>* outTask) {
428     SkASSERT(!src->isFullyLazy());
429     auto rect = SkIRect::MakeSize(src->dimensions());
430     return Copy(context,
431                 std::move(src),
432                 origin,
433                 mipmapped,
434                 rect,
435                 fit,
436                 budgeted,
437                 label,
438                 RectsMustMatch::kNo,
439                 outTask);
440 }
441 
442 #if defined(GPU_TEST_UTILS)
testingOnly_getBackingRefCnt() const443 int32_t GrSurfaceProxy::testingOnly_getBackingRefCnt() const {
444     if (fTarget) {
445         return fTarget->testingOnly_getRefCnt();
446     }
447 
448     return -1; // no backing GrSurface
449 }
450 
testingOnly_getFlags() const451 GrInternalSurfaceFlags GrSurfaceProxy::testingOnly_getFlags() const {
452     return fSurfaceFlags;
453 }
454 
dump() const455 SkString GrSurfaceProxy::dump() const {
456     SkString tmp;
457 
458     tmp.appendf("proxyID: %u - surfaceID: %u",
459                 this->uniqueID().asUInt(),
460                 this->peekSurface() ? this->peekSurface()->uniqueID().asUInt()
461                                     : -1);
462     return tmp;
463 }
464 
465 #endif
466 
exactify()467 void GrSurfaceProxyPriv::exactify() {
468     SkASSERT(!fProxy->isFullyLazy());
469     if (this->isExact()) {
470         return;
471     }
472 
473     // The kApprox case. Setting the proxy's width & height to the backing-store width & height
474     // could have side-effects going forward, since we're obliterating the area of interest
475     // information. This is only used by SkSpecialImage when it's determined that sampling will
476     // not access beyond the safe known region (the current value of fProxy->fDimensions). If
477     // the proxy is instantiated, update the proxy's dimensions to match. Otherwise update them
478     // to the backing-store dimensions.
479     SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
480     fProxy->fDimensions = fProxy->fTarget ? fProxy->fTarget->dimensions()
481                                           : fProxy->backingStoreDimensions();
482     fProxy->fFit = SkBackingFit::kExact;
483 }
484 
doLazyInstantiation(GrResourceProvider * resourceProvider)485 bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
486     SkASSERT(fProxy->isLazy());
487 
488     sk_sp<GrSurface> surface;
489     if (const auto& uniqueKey = fProxy->getUniqueKey(); uniqueKey.isValid()) {
490         // First try to reattach to a cached version if the proxy is uniquely keyed
491         surface = resourceProvider->findByUniqueKey<GrSurface>(uniqueKey);
492     }
493 
494     bool syncKey = true;
495     bool releaseCallback = false;
496     if (!surface) {
497 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
498         NodeIdHelper helper(fNodeId);
499 #endif
500         auto result = fProxy->fLazyInstantiateCallback(resourceProvider, fProxy->callbackDesc());
501         surface = std::move(result.fSurface);
502         syncKey = result.fKeyMode == GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
503         releaseCallback = surface && result.fReleaseCallback;
504     }
505     if (!surface) {
506         fProxy->fDimensions.setEmpty();
507         return false;
508     }
509 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
510     if (ParallelDebug::IsVkImageDfxEnabled()) {
511         surface->updateNodeId(fNodeId);
512     }
513 #endif
514 
515     if (fProxy->isFullyLazy()) {
516         // This was a fully lazy proxy. We need to fill in the width & height. For partially
517         // lazy proxies we must preserve the original width & height since that indicates
518         // the content area.
519         fProxy->fDimensions = surface->dimensions();
520     }
521 
522     SkASSERT(fProxy->width() <= surface->width());
523     SkASSERT(fProxy->height() <= surface->height());
524 
525     if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
526         texProxy->setTargetKeySync(syncKey);
527         if (syncKey) {
528             const skgpu::UniqueKey& key = texProxy->getUniqueKey();
529             if (key.isValid()) {
530                 if (!surface->asTexture()->getUniqueKey().isValid()) {
531                     // If 'surface' is newly created, attach the unique key
532                     resourceProvider->assignUniqueKeyToResource(key, surface.get());
533                 } else {
534                     // otherwise we had better have reattached to a cached version
535                     SkASSERT(surface->asTexture()->getUniqueKey() == key);
536                 }
537             } else {
538                 SkASSERT(!surface->getUniqueKey().isValid());
539             }
540         }
541     }
542 
543     this->assign(std::move(surface));
544     if (releaseCallback) {
545         fProxy->fLazyInstantiateCallback = nullptr;
546     }
547 
548     return true;
549 }
550 
551 #ifdef SK_DEBUG
validateSurface(const GrSurface * surface)552 void GrSurfaceProxy::validateSurface(const GrSurface* surface) {
553     SkASSERTF(surface->backendFormat() == fFormat, "%s != %s",
554               surface->backendFormat().toStr().c_str(), fFormat.toStr().c_str());
555 
556     this->onValidateSurface(surface);
557 }
558 #endif
559