| /* | |
| * Copyright 2023 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/ganesh/image/SkImage_RasterPinnable.h" | |
| #include "include/android/SkImageAndroid.h" | |
| #include "include/core/SkBitmap.h" | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/gpu/GpuTypes.h" | |
| #include "include/gpu/ganesh/GrRecordingContext.h" | |
| #include "src/core/SkImageInfoPriv.h" | |
| #include "src/gpu/ganesh/GrRecordingContextPriv.h" | |
| #include "src/gpu/ganesh/GrSurfaceProxyView.h" | |
| #include "src/gpu/ganesh/SkGr.h" | |
| #include "src/gpu/ganesh/image/GrImageUtils.h" | |
| #include "src/gpu/ganesh/image/GrMippedBitmap.h" | |
| #include "src/image/SkImage_Base.h" | |
| #include <memory> | |
| #include <tuple> | |
| std::tuple<GrSurfaceProxyView, GrColorType> SkImage_RasterPinnable::asView( | |
| GrRecordingContext* rContext, | |
| skgpu::Mipmapped mipmapped, | |
| GrImageTexGenPolicy policy) const { | |
| if (fPinnedData) { | |
| // We ignore the mipmap request here. If the pinned view isn't mipmapped then we will | |
| // fallback to bilinear. The pin API is used by Android Framework which does not expose | |
| // mipmapping. Moreover, we're moving towards requiring that images be made with mip levels | |
| // if mipmapping is desired (skbug.com/40041743) | |
| mipmapped = skgpu::Mipmapped::kNo; | |
| if (policy != GrImageTexGenPolicy::kDraw) { | |
| return {skgpu::ganesh::CopyView( | |
| rContext, | |
| fPinnedData->fPinnedView, | |
| mipmapped, | |
| policy, | |
| /*label=*/"TextureForPinnableRasterImageWithPolicyNotEqualKDraw"), | |
| fPinnedData->fPinnedColorType}; | |
| } | |
| return {fPinnedData->fPinnedView, fPinnedData->fPinnedColorType}; | |
| } | |
| return skgpu::ganesh::RasterAsView(rContext, this, mipmapped, policy); | |
| } | |
| namespace SkImages { | |
| sk_sp<SkImage> PinnableRasterFromBitmap(const SkBitmap& bm) { | |
| if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) { | |
| return nullptr; | |
| } | |
| return sk_make_sp<SkImage_RasterPinnable>(bm); | |
| } | |
| } // namespace SkImages | |
| namespace skgpu::ganesh { | |
| bool PinAsTexture(GrRecordingContext* rContext, SkImage* img) { | |
| auto ib = as_IB(img); | |
| if (ib->type() == SkImage_Base::Type::kLazyTexture) { | |
| return true; | |
| } | |
| if (ib->type() != SkImage_Base::Type::kRasterPinnable) { | |
| // Cannot pin images which are not of subclass SkImage_RasterPinnable | |
| return false; | |
| } | |
| auto raster = static_cast<SkImage_RasterPinnable*>(ib); | |
| if (!raster->fPinnedData) { | |
| auto data = std::make_unique<PinnedData>(); | |
| std::tie(data->fPinnedView, data->fPinnedColorType) = | |
| GrMakeCachedBitmapProxyView(rContext, | |
| GrMippedBitmap(raster->bitmap(), raster->refMips()), | |
| /*label=*/"ganesh_PinAsTexture", | |
| skgpu::Mipmapped::kNo); | |
| if (!data->fPinnedView) { | |
| return false; | |
| } | |
| data->fPinnedUniqueID = raster->bitmap().getGenerationID(); | |
| data->fPinnedContextID = rContext->priv().contextID(); | |
| raster->fPinnedData.swap(data); | |
| } else { | |
| SkASSERT(raster->fPinnedData->fPinnedCount > 0); | |
| SkASSERT(raster->fPinnedData->fPinnedUniqueID != 0); | |
| if (rContext->priv().contextID() != raster->fPinnedData->fPinnedContextID) { | |
| return false; | |
| } | |
| } | |
| // Note: we only increment if the texture was successfully pinned | |
| raster->fPinnedData->fPinnedCount++; | |
| return true; | |
| } | |
| void UnpinTexture(GrRecordingContext*, SkImage* img) { | |
| auto ib = as_IB(img); | |
| if (ib->type() != SkImage_Base::Type::kRasterPinnable) { | |
| // Cannot pin images which are not of subclass SkImage_RasterPinnable | |
| return; | |
| } | |
| auto raster = static_cast<SkImage_RasterPinnable*>(ib); | |
| if (!raster->fPinnedData) { | |
| SkASSERT(false); | |
| return; | |
| } | |
| SkASSERT(raster->fPinnedData->fPinnedCount > 0); | |
| SkASSERT(raster->fPinnedData->fPinnedUniqueID != 0); | |
| // It would be good to check rContext->priv().contextID() != fPinnedContextID | |
| // but Android used to (maybe still does) call Unpin with a freed context ptr | |
| raster->fPinnedData->fPinnedCount--; | |
| if (raster->fPinnedData->fPinnedCount <= 0) { | |
| raster->fPinnedData.reset(nullptr); | |
| } | |
| } | |
| } // namespace skgpu::ganesh |