@@ -381,53 +381,151 @@ bool SkImage_GpuBase::RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* re
381381 return true ;
382382}
383383
384- // ///////////////////////////////////////////////////////////////////////////////////////////////
385- sk_sp<GrTexture> SkPromiseImageHelper::getTexture (GrResourceProvider* resourceProvider,
386- GrPixelConfig config) {
387- // Releases the promise helper if there are no outstanding hard refs. This means that we
388- // don't have any ReleaseProcs waiting to be called so we will need to do a fulfill.
389- if (fReleaseHelper && fReleaseHelper ->weak_expired ()) {
390- this ->resetReleaseHelper ();
391- }
392-
393- sk_sp<GrTexture> tex;
394- if (!fReleaseHelper ) {
395- fFulfillProc (fContext , &fBackendTex );
396- fBackendTex .fConfig = config;
397- if (!fBackendTex .isValid ()) {
398- // Even though the GrBackendTexture is not valid, we must call the release
399- // proc to keep our contract of always calling Fulfill and Release in pairs.
400- fReleaseProc (fContext );
401- return sk_sp<GrTexture>();
384+ sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy (
385+ GrContext* context, int width, int height, GrSurfaceOrigin origin, GrPixelConfig config,
386+ GrBackendFormat backendFormat, GrMipMapped mipMapped,
387+ SkImage_GpuBase::TextureFulfillProc fulfillProc,
388+ SkImage_GpuBase::TextureReleaseProc releaseProc, SkImage_GpuBase::PromiseDoneProc doneProc,
389+ SkImage_GpuBase::TextureContext textureContext) {
390+ SkASSERT (context);
391+ SkASSERT (width > 0 && height > 0 );
392+ SkASSERT (doneProc);
393+
394+ if (!fulfillProc || !releaseProc) {
395+ doneProc (textureContext);
396+ return nullptr ;
397+ }
398+
399+ if (mipMapped == GrMipMapped::kYes &&
400+ GrTextureTypeHasRestrictedSampling (backendFormat.textureType ())) {
401+ // It is invalid to have a GL_TEXTURE_EXTERNAL or GL_TEXTURE_RECTANGLE and have mips as
402+ // well.
403+ doneProc (textureContext);
404+ return nullptr ;
405+ }
406+
407+ /* *
408+ * This helper class manages the ref counting for the the ReleaseProc and DoneProc for promise
409+ * images. It holds a weak ref on the ReleaseProc (hard refs are owned by GrTextures). The weak
410+ * ref allows us to reuse an outstanding ReleaseProc (because we dropped our GrTexture but the
411+ * GrTexture isn't done on the GPU) without needing to call FulfillProc again. It also holds a
412+ * hard ref on the DoneProc. The idea is that after every flush we may call the ReleaseProc so
413+ * that the client can free up their GPU memory if they want to. The life time of the DoneProc
414+ * matches that of any outstanding ReleaseProc as well as the PromiseLazyInstantiateCallback.
415+ * Thus we won't call the DoneProc until all ReleaseProcs are finished and we are finished with
416+ * the PromiseImageHelper (i.e. won't call FulfillProc again).
417+ */
418+ class PromiseLazyInstantiateCallback {
419+ public:
420+ PromiseLazyInstantiateCallback (SkImage_GpuBase::TextureFulfillProc fulfillProc,
421+ SkImage_GpuBase::TextureReleaseProc releaseProc,
422+ SkImage_GpuBase::PromiseDoneProc doneProc,
423+ SkImage_GpuBase::TextureContext context,
424+ GrPixelConfig config)
425+ : fFulfillProc (fulfillProc)
426+ , fReleaseProc (releaseProc)
427+ , fContext (context)
428+ , fConfig (config) {
429+ fDoneHelper .reset (new GrReleaseProcHelper (doneProc, context));
430+ }
431+
432+ sk_sp<GrSurface> operator ()(GrResourceProvider* resourceProvider) {
433+ if (!resourceProvider) {
434+ this ->reset ();
435+ return sk_sp<GrTexture>();
436+ }
437+
438+ // Releases the promise helper if there are no outstanding hard refs. This means that we
439+ // don't have any ReleaseProcs waiting to be called so we will need to do a fulfill.
440+ if (fReleaseHelper && fReleaseHelper ->weak_expired ()) {
441+ this ->resetReleaseHelper ();
442+ }
443+
444+ sk_sp<GrTexture> tex;
445+ if (!fReleaseHelper ) {
446+ fFulfillProc (fContext , &fBackendTex );
447+ fBackendTex .fConfig = fConfig ;
448+ if (!fBackendTex .isValid ()) {
449+ // Even though the GrBackendTexture is not valid, we must call the release
450+ // proc to keep our contract of always calling Fulfill and Release in pairs.
451+ fReleaseProc (fContext );
452+ return sk_sp<GrTexture>();
453+ }
454+
455+ tex = resourceProvider->wrapBackendTexture (fBackendTex , kBorrow_GrWrapOwnership ,
456+ kRead_GrIOType );
457+ if (!tex) {
458+ // Even though the GrBackendTexture is not valid, we must call the release
459+ // proc to keep our contract of always calling Fulfill and Release in pairs.
460+ fReleaseProc (fContext );
461+ return sk_sp<GrTexture>();
462+ }
463+ fReleaseHelper =
464+ new SkPromiseReleaseProcHelper (fReleaseProc , fContext , fDoneHelper );
465+ // Take a weak ref
466+ fReleaseHelper ->weak_ref ();
467+ } else {
468+ SkASSERT (fBackendTex .isValid ());
469+ tex = resourceProvider->wrapBackendTexture (fBackendTex , kBorrow_GrWrapOwnership ,
470+ kRead_GrIOType );
471+ if (!tex) {
472+ // We weren't able to make a texture here, but since we are in this branch
473+ // of the calls (promiseHelper.fReleaseHelper is valid) there is already a
474+ // texture out there which will call the release proc so we don't need to
475+ // call it here.
476+ return sk_sp<GrTexture>();
477+ }
478+
479+ SkAssertResult (fReleaseHelper ->try_ref ());
480+ }
481+ SkASSERT (tex);
482+ // Pass the hard ref off to the texture
483+ tex->setRelease (sk_sp<GrReleaseProcHelper>(fReleaseHelper ));
484+ return std::move (tex);
402485 }
403486
404- tex = resourceProvider->wrapBackendTexture (fBackendTex , kBorrow_GrWrapOwnership ,
405- kRead_GrIOType );
406- if (!tex) {
407- // Even though the GrBackendTexture is not valid, we must call the release
408- // proc to keep our contract of always calling Fulfill and Release in pairs.
409- fReleaseProc (fContext );
410- return sk_sp<GrTexture>();
487+ private:
488+ void reset () {
489+ this ->resetReleaseHelper ();
490+ fDoneHelper .reset ();
411491 }
412- fReleaseHelper = new SkPromiseReleaseProcHelper (fReleaseProc , fContext , fDoneHelper );
413- // Take a weak ref
414- fReleaseHelper ->weak_ref ();
415- } else {
416- SkASSERT (fBackendTex .isValid ());
417- tex = resourceProvider->wrapBackendTexture (fBackendTex , kBorrow_GrWrapOwnership ,
418- kRead_GrIOType );
419- if (!tex) {
420- // We weren't able to make a texture here, but since we are in this branch
421- // of the calls (promiseHelper.fReleaseHelper is valid) there is already a
422- // texture out there which will call the release proc so we don't need to
423- // call it here.
424- return sk_sp<GrTexture>();
492+
493+ // Weak unrefs fReleaseHelper and sets it to null
494+ void resetReleaseHelper () {
495+ if (fReleaseHelper ) {
496+ fReleaseHelper ->weak_unref ();
497+ fReleaseHelper = nullptr ;
498+ }
425499 }
426500
427- SkAssertResult (fReleaseHelper ->try_ref ());
428- }
429- SkASSERT (tex);
430- // Pass the hard ref off to the texture
431- tex->setRelease (sk_sp<GrReleaseProcHelper>(fReleaseHelper ));
432- return tex;
501+ SkImage_GpuBase::TextureFulfillProc fFulfillProc ;
502+ SkImage_GpuBase::TextureReleaseProc fReleaseProc ;
503+ SkImage_GpuBase::TextureContext fContext ;
504+
505+ GrPixelConfig fConfig ;
506+ // We cache the GrBackendTexture so that if we deleted the GrTexture but the the release
507+ // proc has yet not been called (this can happen on Vulkan), then we can create a new
508+ // texture without needing to call the fulfill proc again.
509+ GrBackendTexture fBackendTex ;
510+ // The fReleaseHelper is used to track a weak ref on the release proc. This helps us make
511+ // sure we are always pairing fulfill and release proc calls correctly.
512+ SkPromiseReleaseProcHelper* fReleaseHelper = nullptr ;
513+ // We don't want to call the fDoneHelper until we are done with the PromiseImageHelper and
514+ // all ReleaseHelpers are finished. Thus we hold a hard ref here and we will pass a hard ref
515+ // to each fReleaseHelper we make.
516+ sk_sp<GrReleaseProcHelper> fDoneHelper ;
517+ } callback (fulfillProc, releaseProc, doneProc, textureContext, config);
518+
519+ GrProxyProvider* proxyProvider = context->contextPriv ().proxyProvider ();
520+
521+ GrSurfaceDesc desc;
522+ desc.fWidth = width;
523+ desc.fHeight = height;
524+ desc.fConfig = config;
525+
526+ // We pass kReadOnly here since we should treat content of the client's texture as immutable.
527+ return proxyProvider->createLazyProxy (std::move (callback), backendFormat, desc, origin,
528+ mipMapped, GrInternalSurfaceFlags::kReadOnly ,
529+ SkBackingFit::kExact , SkBudgeted::kNo ,
530+ GrSurfaceProxy::LazyInstantiationType::kDeinstantiate );
433531}
0 commit comments