|  | /* | 
|  | * Copyright 2021 Google LLC | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "src/gpu/graphite/TextureProxy.h" | 
|  |  | 
|  | #include "include/gpu/graphite/Recorder.h" | 
|  | #include "src/core/SkMipmap.h" | 
|  | #include "src/gpu/graphite/Caps.h" | 
|  | #include "src/gpu/graphite/RecorderPriv.h" | 
|  | #include "src/gpu/graphite/ResourceProvider.h" | 
|  | #include "src/gpu/graphite/ScratchResourceManager.h" | 
|  | #include "src/gpu/graphite/Texture.h" | 
|  | #include "src/gpu/graphite/TextureUtils.h" | 
|  |  | 
|  | namespace skgpu::graphite { | 
|  |  | 
|  | TextureProxy::TextureProxy(SkISize dimensions, | 
|  | const TextureInfo& info, | 
|  | std::string_view label, | 
|  | skgpu::Budgeted budgeted) | 
|  | : fDimensions(dimensions) | 
|  | , fInfo(info) | 
|  | , fLabel(label) | 
|  | , fBudgeted(budgeted) | 
|  | , fVolatile(Volatile::kNo) { | 
|  | SkASSERT(fInfo.isValid()); | 
|  | } | 
|  |  | 
|  | TextureProxy::TextureProxy(sk_sp<Texture> texture) | 
|  | : fDimensions(texture->dimensions()) | 
|  | , fInfo(texture->textureInfo()) | 
|  | , fLabel(texture->getLabel()) | 
|  | , fBudgeted(texture->budgeted()) | 
|  | , fVolatile(Volatile::kNo) | 
|  | , fTexture(std::move(texture)) { | 
|  | SkASSERT(fInfo.isValid()); | 
|  | } | 
|  |  | 
|  | TextureProxy::TextureProxy(SkISize dimensions, | 
|  | const TextureInfo& textureInfo, | 
|  | skgpu::Budgeted budgeted, | 
|  | Volatile isVolatile, | 
|  | LazyInstantiateCallback&& callback) | 
|  | : fDimensions(dimensions) | 
|  | , fInfo(textureInfo) | 
|  | , fBudgeted(budgeted) | 
|  | , fVolatile(isVolatile) | 
|  | , fLazyInstantiateCallback(std::move(callback)) { | 
|  | SkASSERT(fInfo.isValid()); | 
|  | SkASSERT(fLazyInstantiateCallback); | 
|  | } | 
|  |  | 
|  | TextureProxy::~TextureProxy() {} | 
|  |  | 
|  | SkISize TextureProxy::dimensions() const { | 
|  | SkASSERT(!this->isFullyLazy() || this->isInstantiated()); | 
|  | return this->isInstantiated() ? fTexture->dimensions() : fDimensions; | 
|  | } | 
|  |  | 
|  | bool TextureProxy::isLazy() const { | 
|  | return SkToBool(fLazyInstantiateCallback); | 
|  | } | 
|  |  | 
|  | bool TextureProxy::isFullyLazy() const { | 
|  | bool result = fDimensions.width() < 0; | 
|  | SkASSERT(result == (fDimensions.height() < 0)); | 
|  | SkASSERT(!result || this->isLazy()); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool TextureProxy::isVolatile() const { | 
|  | SkASSERT(fVolatile == Volatile::kNo || SkToBool(fLazyInstantiateCallback)); | 
|  |  | 
|  | return fVolatile == Volatile::kYes; | 
|  | } | 
|  |  | 
|  | size_t TextureProxy::uninstantiatedGpuMemorySize() const { | 
|  | return ComputeSize(fDimensions, fInfo); | 
|  | } | 
|  |  | 
|  | bool TextureProxy::instantiate(ResourceProvider* resourceProvider) { | 
|  | SkASSERT(!this->isLazy()); | 
|  |  | 
|  | if (fTexture) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // TODO(389908374): Once all tasks use the ScratchResourceManager, this can be updated to just | 
|  | // finding and creating a non-shareable AND non-budgeted texture. | 
|  | fTexture = resourceProvider->findOrCreateNonShareableTexture( | 
|  | fDimensions, fInfo, fLabel, fBudgeted); | 
|  | if (!fTexture) { | 
|  | return false; | 
|  | } | 
|  | SkDEBUGCODE(this->validateTexture(fTexture.get())); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool TextureProxy::lazyInstantiate(ResourceProvider* resourceProvider) { | 
|  | SkASSERT(this->isLazy()); | 
|  |  | 
|  | if (fTexture) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | fTexture = fLazyInstantiateCallback(resourceProvider); | 
|  | if (!fTexture) { | 
|  | return false; | 
|  | } | 
|  | SkDEBUGCODE(this->validateTexture(fTexture.get())); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool TextureProxy::InstantiateIfNotLazy(ResourceProvider* resourceProvider, | 
|  | TextureProxy* textureProxy) { | 
|  | if (textureProxy->isLazy()) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return textureProxy->instantiate(resourceProvider); | 
|  | } | 
|  |  | 
|  | bool TextureProxy::InstantiateIfNotLazy(ScratchResourceManager* scratchManager, | 
|  | TextureProxy* textureProxy) { | 
|  | if (textureProxy->isLazy() || textureProxy->isInstantiated()) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | textureProxy->fTexture = scratchManager->getScratchTexture(textureProxy->dimensions(), | 
|  | textureProxy->textureInfo(), | 
|  | textureProxy->fLabel); | 
|  | if (!textureProxy->fTexture) { | 
|  | return false; | 
|  | } | 
|  | SkDEBUGCODE(textureProxy->validateTexture(textureProxy->fTexture.get())); | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  | void TextureProxy::deinstantiate() { | 
|  | SkASSERT(fVolatile == Volatile::kYes && SkToBool(fLazyInstantiateCallback)); | 
|  |  | 
|  | fTexture.reset(); | 
|  | } | 
|  |  | 
|  | sk_sp<Texture> TextureProxy::refTexture() const { | 
|  | return fTexture; | 
|  | } | 
|  |  | 
|  | const Texture* TextureProxy::texture() const { | 
|  | return fTexture.get(); | 
|  | } | 
|  |  | 
|  | sk_sp<TextureProxy> TextureProxy::Make(const Caps* caps, | 
|  | ResourceProvider* resourceProvider, | 
|  | SkISize dimensions, | 
|  | const TextureInfo& textureInfo, | 
|  | std::string_view label, | 
|  | skgpu::Budgeted budgeted) { | 
|  | if (dimensions.width() < 1 || dimensions.height() < 1 || | 
|  | dimensions.width() > caps->maxTextureSize() || | 
|  | dimensions.height() > caps->maxTextureSize() || | 
|  | !textureInfo.isValid()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | sk_sp<TextureProxy> proxy{new TextureProxy(dimensions, | 
|  | textureInfo, | 
|  | std::move(label), | 
|  | budgeted)}; | 
|  | if (budgeted == Budgeted::kNo) { | 
|  | // Instantiate immediately to avoid races later on if the client starts to use the wrapping | 
|  | // object on multiple threads. | 
|  | if (!proxy->instantiate(resourceProvider)) { | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  | return proxy; | 
|  | } | 
|  |  | 
|  | sk_sp<TextureProxy> TextureProxy::MakeLazy(const Caps* caps, | 
|  | SkISize dimensions, | 
|  | const TextureInfo& textureInfo, | 
|  | skgpu::Budgeted budgeted, | 
|  | Volatile isVolatile, | 
|  | LazyInstantiateCallback&& callback) { | 
|  | SkASSERT(textureInfo.isValid()); | 
|  | if (dimensions.width() < 1 || dimensions.height() < 1 || | 
|  | dimensions.width() > caps->maxTextureSize() || | 
|  | dimensions.height() > caps->maxTextureSize()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return sk_sp<TextureProxy>(new TextureProxy(dimensions, | 
|  | textureInfo, | 
|  | budgeted, | 
|  | isVolatile, | 
|  | std::move(callback))); | 
|  | } | 
|  |  | 
|  | sk_sp<TextureProxy> TextureProxy::MakeFullyLazy(const TextureInfo& textureInfo, | 
|  | skgpu::Budgeted budgeted, | 
|  | Volatile isVolatile, | 
|  | LazyInstantiateCallback&& callback) { | 
|  | SkASSERT(textureInfo.isValid()); | 
|  |  | 
|  | return sk_sp<TextureProxy>(new TextureProxy(SkISize::Make(-1, -1), | 
|  | textureInfo, | 
|  | budgeted, | 
|  | isVolatile, | 
|  | std::move(callback))); | 
|  | } | 
|  |  | 
|  | sk_sp<TextureProxy> TextureProxy::Wrap(sk_sp<Texture> texture) { | 
|  | return sk_sp<TextureProxy>(new TextureProxy(std::move(texture))); | 
|  | } | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  | void TextureProxy::validateTexture(const Texture* texture) { | 
|  | SkASSERT(this->isFullyLazy() || fDimensions == texture->dimensions()); | 
|  | SkASSERTF(fInfo.canBeFulfilledBy(texture->textureInfo()), | 
|  | "proxy->fInfo[%s] incompatible with texture->fInfo[%s]", | 
|  | fInfo.toString().c_str(), | 
|  | texture->textureInfo().toString().c_str()); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | } // namespace skgpu::graphite |