| /* | |
| * 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 "include/private/SkPixelStorage.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, | |
| skgpu::Budgeted budgeted, | |
| std::string_view label) | |
| : SkPixelStorage(SkPixelStorage::Type::kTextureProxy) | |
| , fDimensions(dimensions) | |
| , fInfo(info) | |
| , fBudgeted(budgeted) | |
| , fVolatile(Volatile::kNo) | |
| , fLabel(label) { | |
| SkASSERT(fInfo.isValid()); | |
| } | |
| TextureProxy::TextureProxy(sk_sp<Texture> texture) | |
| : SkPixelStorage(SkPixelStorage::Type::kTextureProxy) | |
| , fDimensions(texture->dimensions()) | |
| , fInfo(texture->textureInfo()) | |
| , fBudgeted(texture->budgeted()) | |
| , fVolatile(Volatile::kNo) | |
| , fLabel(texture->getLabel()) | |
| , fTexture(std::move(texture)) { | |
| SkASSERT(fInfo.isValid()); | |
| } | |
| TextureProxy::TextureProxy(SkISize dimensions, | |
| const TextureInfo& textureInfo, | |
| skgpu::Budgeted budgeted, | |
| Volatile isVolatile, | |
| LazyInstantiateCallback&& callback) | |
| : SkPixelStorage(SkPixelStorage::Type::kTextureProxy) | |
| , 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(); | |
| } | |
| namespace { | |
| bool texture_info_and_size_are_valid( | |
| SkISize dimensions, const TextureInfo& textureInfo, int maxTextureSize) { | |
| return dimensions.width() >= 1 && dimensions.height() >= 1 && | |
| dimensions.width() <= maxTextureSize && dimensions.height() <= maxTextureSize && | |
| textureInfo.isValid(); | |
| } | |
| } // anonymous namespace | |
| sk_sp<TextureProxy> TextureProxy::Make(const Caps* caps, | |
| ResourceProvider* resourceProvider, | |
| SkISize dimensions, | |
| const TextureInfo& textureInfo, | |
| skgpu::Budgeted budgeted, | |
| std::string_view label) { | |
| if (!texture_info_and_size_are_valid(dimensions, textureInfo, caps->maxTextureSize())) { | |
| return nullptr; | |
| } | |
| sk_sp<TextureProxy> proxy {new TextureProxy(dimensions, textureInfo, budgeted, label)}; | |
| 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) { | |
| if (!texture_info_and_size_are_valid(dimensions, textureInfo, 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 |