/* * 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/image/SkImage_Base.h" #include #include std::tuple 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/10411) 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 PinnableRasterFromBitmap(const SkBitmap& bm) { if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) { return nullptr; } return sk_make_sp(bm); } } // namespace SkImages namespace skgpu::ganesh { bool PinAsTexture(GrRecordingContext* rContext, 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 false; } auto raster = static_cast(ib); if (!raster->fPinnedData) { auto data = std::make_unique(); std::tie(data->fPinnedView, data->fPinnedColorType) = GrMakeCachedBitmapProxyView(rContext, raster->bitmap(), /*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(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