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