Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrSurfaceProxy.cpp
Go to the documentation of this file.
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
9
16#include "src/gpu/Swizzle.h"
31
32#include <memory>
33
34#ifdef SK_DEBUG
37
38static 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
47static bool is_valid_non_lazy(SkISize dimensions) {
48 return dimensions.fWidth > 0 && dimensions.fHeight > 0;
49}
50#endif
51
53 bool releaseCallback,
55 : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {}
58
59// Deferred version
62 SkBackingFit fit,
63 skgpu::Budgeted budgeted,
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
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
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
125
127 int sampleCnt,
128 GrRenderable renderable,
129 skgpu::Mipmapped mipmapped) const {
130 SkASSERT(mipmapped == skgpu::Mipmapped::kNo || fFit == SkBackingFit::kExact);
131 SkASSERT(!this->isLazy());
133
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
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
178
179 SkDEBUGCODE(this->validateSurface(surface.get());)
180
181 fTarget = std::move(surface);
182
183#ifdef SK_DEBUG
184 if (this->asRenderTargetProxy()) {
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
199 int sampleCnt,
200 GrRenderable renderable,
201 skgpu::Mipmapped mipmapped,
202 const skgpu::UniqueKey* uniqueKey) {
203 SkASSERT(!this->isLazy());
204 if (fTarget) {
205 if (uniqueKey && uniqueKey->isValid()) {
206 SkASSERT(fTarget->getUniqueKey().isValid() && fTarget->getUniqueKey() == *uniqueKey);
207 }
208 return true;
209 }
210
211 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, sampleCnt, renderable,
212 mipmapped);
213 if (!surface) {
214 return false;
215 }
216
217 // If there was an invalidation message pending for this key, we might have just processed it,
218 // causing the key (stored on this proxy) to become invalid.
219 if (uniqueKey && uniqueKey->isValid()) {
220 resourceProvider->assignUniqueKeyToResource(*uniqueKey, surface.get());
221 }
222
223 this->assign(std::move(surface));
224
225 return true;
226}
227
229 SkASSERT(this->isInstantiated());
230 fTarget = nullptr;
231}
232
234 SkASSERT(!this->isFullyLazy());
235 GrRenderable renderable = GrRenderable::kNo;
236 int sampleCount = 1;
237 if (const auto* rtp = this->asRenderTargetProxy()) {
238 renderable = GrRenderable::kYes;
239 sampleCount = rtp->numSamples();
240 }
241
242 const GrTextureProxy* tp = this->asTextureProxy();
243 skgpu::Mipmapped mipmapped = skgpu::Mipmapped::kNo;
244 if (tp) {
245 mipmapped = tp->mipmapped();
246 }
247
249 renderable, sampleCount, mipmapped, fIsProtected, key);
250}
251
253 SkASSERT(!this->isFullyLazy());
254 if (fTarget) {
255 return fTarget->dimensions();
256 }
257
258 if (SkBackingFit::kExact == fFit) {
259 return fDimensions;
260 }
261 return skgpu::GetApproxSize(fDimensions);
262}
263
265 SkASSERT(!this->isFullyLazy());
266 return fFit == SkBackingFit::kExact ||
267 fDimensions == skgpu::GetApproxSize(fDimensions);
268}
269
271 return caps->isFormatCompressed(this->backendFormat());
272}
273
274#ifdef SK_DEBUG
275void GrSurfaceProxy::validate(GrContext_Base* context) const {
276 if (fTarget) {
277 SkASSERT(fTarget->getContext()->priv().matches(context));
278 }
279}
280#endif
281
284 GrSurfaceOrigin origin,
285 skgpu::Mipmapped mipmapped,
286 SkIRect srcRect,
287 SkBackingFit fit,
288 skgpu::Budgeted budgeted,
289 std::string_view label,
290 RectsMustMatch rectsMustMatch,
291 sk_sp<GrRenderTask>* outTask) {
292 SkASSERT(!src->isFullyLazy());
293 int width;
294 int height;
295
296 SkIPoint dstPoint;
297 if (rectsMustMatch == RectsMustMatch::kYes) {
298 width = src->width();
299 height = src->height();
300 dstPoint = {srcRect.fLeft, srcRect.fTop};
301 } else {
302 width = srcRect.width();
303 height = srcRect.height();
304 dstPoint = {0, 0};
305 }
306
307 if (!srcRect.intersect(SkIRect::MakeSize(src->dimensions()))) {
308 return {};
309 }
310 auto format = src->backendFormat().makeTexture2D();
311 SkASSERT(format.isValid());
312
313 if (src->backendFormat().textureType() != GrTextureType::kExternal) {
315 auto dstContext = rContext->priv().makeSC(info,
316 format,
317 label,
318 fit,
319 origin,
320 GrRenderable::kNo,
321 1,
322 mipmapped,
323 src->isProtected(),
324 budgeted);
325 sk_sp<GrRenderTask> copyTask;
326 if (dstContext && (copyTask = dstContext->copy(src, srcRect, dstPoint))) {
327 if (outTask) {
328 *outTask = std::move(copyTask);
329 }
330 return dstContext->asSurfaceProxyRef();
331 }
332 }
333 if (src->asTextureProxy()) {
334 auto dstContext = rContext->priv().makeSFC(kUnknown_SkAlphaType,
335 nullptr,
336 {width, height},
337 fit,
338 format,
339 1,
340 mipmapped,
341 src->isProtected(),
344 origin,
345 budgeted,
346 label);
347 GrSurfaceProxyView view(std::move(src), origin, skgpu::Swizzle::RGBA());
348 if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
349 if (outTask) {
350 *outTask = dstContext->refRenderTask();
351 }
352 return dstContext->asSurfaceProxyRef();
353 }
354 }
355 // Can't use backend copies or draws.
356 return nullptr;
357}
358
361 GrSurfaceOrigin origin,
362 skgpu::Mipmapped mipmapped,
363 SkBackingFit fit,
364 skgpu::Budgeted budgeted,
365 std::string_view label,
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 label,
378 outTask);
379}
380
381#if defined(GR_TEST_UTILS)
382int32_t GrSurfaceProxy::testingOnly_getBackingRefCnt() const {
383 if (fTarget) {
384 return fTarget->testingOnly_getRefCnt();
385 }
386
387 return -1; // no backing GrSurface
388}
389
390GrInternalSurfaceFlags GrSurfaceProxy::testingOnly_getFlags() const {
391 return fSurfaceFlags;
392}
393
394SkString GrSurfaceProxy::dump() const {
395 SkString tmp;
396
397 tmp.appendf("proxyID: %u - surfaceID: %u",
398 this->uniqueID().asUInt(),
399 this->peekSurface() ? this->peekSurface()->uniqueID().asUInt()
400 : -1);
401 return tmp;
402}
403
404#endif
405
407 SkASSERT(!fProxy->isFullyLazy());
408 if (this->isExact()) {
409 return;
410 }
411
412 // The kApprox case. Setting the proxy's width & height to the backing-store width & height
413 // could have side-effects going forward, since we're obliterating the area of interest
414 // information. This is only used by SkSpecialImage when it's determined that sampling will
415 // not access beyond the safe known region (the current value of fProxy->fDimensions). If
416 // the proxy is instantiated, update the proxy's dimensions to match. Otherwise update them
417 // to the backing-store dimensions.
418 SkASSERT(SkBackingFit::kApprox == fProxy->fFit);
419 fProxy->fDimensions = fProxy->fTarget ? fProxy->fTarget->dimensions()
420 : fProxy->backingStoreDimensions();
421 fProxy->fFit = SkBackingFit::kExact;
422}
423
425 SkASSERT(fProxy->isLazy());
426
428 if (const auto& uniqueKey = fProxy->getUniqueKey(); uniqueKey.isValid()) {
429 // First try to reattach to a cached version if the proxy is uniquely keyed
430 surface = resourceProvider->findByUniqueKey<GrSurface>(uniqueKey);
431 }
432
433 bool syncKey = true;
434 bool releaseCallback = false;
435 if (!surface) {
436 auto result = fProxy->fLazyInstantiateCallback(resourceProvider, fProxy->callbackDesc());
437 surface = std::move(result.fSurface);
439 releaseCallback = surface && result.fReleaseCallback;
440 }
441 if (!surface) {
442 fProxy->fDimensions.setEmpty();
443 return false;
444 }
445
446 if (fProxy->isFullyLazy()) {
447 // This was a fully lazy proxy. We need to fill in the width & height. For partially
448 // lazy proxies we must preserve the original width & height since that indicates
449 // the content area.
450 fProxy->fDimensions = surface->dimensions();
451 }
452
453 SkASSERT(fProxy->width() <= surface->width());
454 SkASSERT(fProxy->height() <= surface->height());
455
456 if (GrTextureProxy* texProxy = fProxy->asTextureProxy()) {
457 texProxy->setTargetKeySync(syncKey);
458 if (syncKey) {
459 const skgpu::UniqueKey& key = texProxy->getUniqueKey();
460 if (key.isValid()) {
461 if (!surface->asTexture()->getUniqueKey().isValid()) {
462 // If 'surface' is newly created, attach the unique key
463 resourceProvider->assignUniqueKeyToResource(key, surface.get());
464 } else {
465 // otherwise we had better have reattached to a cached version
466 SkASSERT(surface->asTexture()->getUniqueKey() == key);
467 }
468 } else {
469 SkASSERT(!surface->getUniqueKey().isValid());
470 }
471 }
472 }
473
474 this->assign(std::move(surface));
475 if (releaseCallback) {
476 fProxy->fLazyInstantiateCallback = nullptr;
477 }
478
479 return true;
480}
481
482#ifdef SK_DEBUG
483void GrSurfaceProxy::validateSurface(const GrSurface* surface) {
484 SkASSERTF(surface->backendFormat() == fFormat, "%s != %s",
485 surface->backendFormat().toStr().c_str(), fFormat.toStr().c_str());
486
487 this->onValidateSurface(surface);
488}
489#endif
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
GrInternalSurfaceFlags
GrBudgetedType
Definition GrTypesPriv.h:99
GrSurfaceOrigin
Definition GrTypes.h:147
@ kUnknown_SkAlphaType
uninitialized
Definition SkAlphaType.h:27
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition SkAssert.h:117
SkBackingFit
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
@ kNo
Don't pre-clip the geometry before applying the (perspective) matrix.
bool isValid() const
GrTextureType textureType() const
bool matches(GrContext_Base *candidate) const
bool isFormatCompressed(const GrBackendFormat &format) const
Definition GrCaps.cpp:457
GrDirectContextPriv priv()
size_t gpuMemorySize() const
const GrDirectContext * getContext() const
const skgpu::UniqueKey & getUniqueKey() const
std::unique_ptr< skgpu::ganesh::SurfaceContext > makeSC(GrSurfaceProxyView readView, const GrColorInfo &)
std::unique_ptr< skgpu::ganesh::SurfaceFillContext > makeSFC(GrImageInfo, std::string_view label, SkBackingFit=SkBackingFit::kExact, int sampleCount=1, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Protected=skgpu::Protected::kNo, GrSurfaceOrigin=kTopLeft_GrSurfaceOrigin, skgpu::Budgeted=skgpu::Budgeted::kYes)
GrRecordingContextPriv priv()
std::enable_if< std::is_base_of< GrGpuResource, T >::value, sk_sp< T > >::type findByUniqueKey(const skgpu::UniqueKey &key)
sk_sp< GrTexture > createApproxTexture(SkISize dimensions, const GrBackendFormat &format, GrTextureType textureType, skgpu::Renderable renderable, int renderTargetSampleCnt, skgpu::Protected isProtected, std::string_view label)
void assignUniqueKeyToResource(const skgpu::UniqueKey &, GrGpuResource *)
sk_sp< GrTexture > createTexture(SkISize dimensions, const GrBackendFormat &format, GrTextureType textureType, skgpu::Renderable renderable, int renderTargetSampleCnt, skgpu::Mipmapped mipmapped, skgpu::Budgeted budgeted, skgpu::Protected isProtected, std::string_view label)
bool doLazyInstantiation(GrResourceProvider *)
void assign(sk_sp< GrSurface > surface)
SkISize backingStoreDimensions() const
virtual const skgpu::UniqueKey & getUniqueKey() const
GrProtected isProtected() const
virtual GrRenderTargetProxy * asRenderTargetProxy()
const GrBackendFormat & backendFormat() const
virtual ~GrSurfaceProxy()
bool instantiateImpl(GrResourceProvider *resourceProvider, int sampleCnt, GrRenderable, skgpu::Mipmapped, const skgpu::UniqueKey *)
bool isDDLTarget() const
bool isLazy() const
bool isFormatCompressed(const GrCaps *) const
bool isFullyLazy() const
int width() const
static sk_sp< GrSurfaceProxy > Copy(GrRecordingContext *, sk_sp< GrSurfaceProxy > src, GrSurfaceOrigin, skgpu::Mipmapped, SkIRect srcRect, SkBackingFit, skgpu::Budgeted, std::string_view label, RectsMustMatch=RectsMustMatch::kNo, sk_sp< GrRenderTask > *outTask=nullptr)
virtual LazySurfaceDesc callbackDesc() const =0
SkISize dimensions() const
GrSurfaceProxy(const GrBackendFormat &, SkISize, SkBackingFit, skgpu::Budgeted, GrProtected, GrInternalSurfaceFlags, UseAllocator, std::string_view label)
void computeScratchKey(const GrCaps &, skgpu::ScratchKey *) const
std::function< LazyCallbackResult(GrResourceProvider *, const LazySurfaceDesc &)> LazyInstantiateCallback
virtual GrTextureProxy * asTextureProxy()
GrSurface * peekSurface() const
bool canSkipResourceAllocator() const
bool isInstantiated() const
bool isFunctionallyExact() const
void assign(sk_sp< GrSurface > surface)
int height() const
sk_sp< GrSurface > createSurfaceImpl(GrResourceProvider *, int sampleCnt, GrRenderable, skgpu::Mipmapped) const
sk_sp< GrSurface > fTarget
GrInternalSurfaceFlags fSurfaceFlags
UniqueID uniqueID() const
SkISize dimensions() const
Definition GrSurface.h:27
virtual GrRenderTarget * asRenderTarget()
Definition GrSurface.h:65
skgpu::Mipmapped mipmapped() const
static void ComputeScratchKey(const GrCaps &caps, const GrBackendFormat &format, SkISize dimensions, GrRenderable, int sampleCnt, skgpu::Mipmapped, GrProtected, skgpu::ScratchKey *key)
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:550
bool isValid() const
Definition ResourceKey.h:55
static constexpr Swizzle RGBA()
Definition Swizzle.h:66
VkSurfaceKHR surface
Definition main.cc:49
FlutterSemanticsFlag flags
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
uint32_t uint32_t * format
SkISize GetApproxSize(SkISize size)
Budgeted
Definition GpuTypes.h:35
Renderable
Definition GpuTypes.h:69
Mipmapped
Definition GpuTypes.h:53
Protected
Definition GpuTypes.h:61
Definition ref_ptr.h:256
bool intersect(const SkIRect &r)
Definition SkRect.h:513
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
static constexpr SkIRect MakeSize(const SkISize &size)
Definition SkRect.h:66
constexpr int32_t width() const
Definition SkRect.h:158
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
int32_t fHeight
Definition SkSize.h:18
void setEmpty()
Definition SkSize.h:34
int32_t fWidth
Definition SkSize.h:17