1 /*
2 * Copyright 2023 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/ganesh/image/SkImage_RasterPinnable.h"
9
10 #include "include/android/SkImageAndroid.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkTypes.h"
16 #include "include/gpu/GpuTypes.h"
17 #include "include/gpu/ganesh/GrRecordingContext.h"
18 #include "src/core/SkImageInfoPriv.h"
19 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
20 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
21 #include "src/gpu/ganesh/SkGr.h"
22 #include "src/gpu/ganesh/image/GrImageUtils.h"
23 #include "src/image/SkImage_Base.h"
24
25 #include <memory>
26 #include <tuple>
27
asView(GrRecordingContext * rContext,skgpu::Mipmapped mipmapped,GrImageTexGenPolicy policy) const28 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_RasterPinnable::asView(
29 GrRecordingContext* rContext,
30 skgpu::Mipmapped mipmapped,
31 GrImageTexGenPolicy policy) const {
32 if (fPinnedData) {
33 // We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
34 // fallback to bilinear. The pin API is used by Android Framework which does not expose
35 // mipmapping. Moreover, we're moving towards requiring that images be made with mip levels
36 // if mipmapping is desired (skbug.com/10411)
37 mipmapped = skgpu::Mipmapped::kNo;
38 if (policy != GrImageTexGenPolicy::kDraw) {
39 return {skgpu::ganesh::CopyView(
40 rContext,
41 fPinnedData->fPinnedView,
42 mipmapped,
43 policy,
44 /*label=*/"TextureForPinnableRasterImageWithPolicyNotEqualKDraw"),
45 fPinnedData->fPinnedColorType};
46 }
47 return {fPinnedData->fPinnedView, fPinnedData->fPinnedColorType};
48 }
49 return skgpu::ganesh::RasterAsView(rContext, this, mipmapped, policy);
50 }
51
52 namespace SkImages {
53
PinnableRasterFromBitmap(const SkBitmap & bm)54 sk_sp<SkImage> PinnableRasterFromBitmap(const SkBitmap& bm) {
55 if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
56 return nullptr;
57 }
58
59 return sk_make_sp<SkImage_RasterPinnable>(bm);
60 }
61
62 } // namespace SkImages
63
64 namespace skgpu::ganesh {
65
PinAsTexture(GrRecordingContext * rContext,SkImage * img)66 bool PinAsTexture(GrRecordingContext* rContext, SkImage* img) {
67 auto ib = as_IB(img);
68 if (ib->type() != SkImage_Base::Type::kRasterPinnable) {
69 // Cannot pin images which are not of subclass SkImage_RasterPinnable
70 return false;
71 }
72 auto raster = static_cast<SkImage_RasterPinnable*>(ib);
73 if (!raster->fPinnedData) {
74 auto data = std::make_unique<PinnedData>();
75 std::tie(data->fPinnedView, data->fPinnedColorType) =
76 GrMakeCachedBitmapProxyView(rContext,
77 raster->bitmap(),
78 /*label=*/"ganesh_PinAsTexture",
79 skgpu::Mipmapped::kNo);
80 if (!data->fPinnedView) {
81 return false;
82 }
83 data->fPinnedUniqueID = raster->bitmap().getGenerationID();
84 data->fPinnedContextID = rContext->priv().contextID();
85 raster->fPinnedData.swap(data);
86 } else {
87 SkASSERT(raster->fPinnedData->fPinnedCount > 0);
88 SkASSERT(raster->fPinnedData->fPinnedUniqueID != 0);
89 if (rContext->priv().contextID() != raster->fPinnedData->fPinnedContextID) {
90 return false;
91 }
92 }
93 // Note: we only increment if the texture was successfully pinned
94 raster->fPinnedData->fPinnedCount++;
95 return true;
96 }
97
UnpinTexture(GrRecordingContext *,SkImage * img)98 void UnpinTexture(GrRecordingContext*, SkImage* img) {
99 auto ib = as_IB(img);
100 if (ib->type() != SkImage_Base::Type::kRasterPinnable) {
101 // Cannot pin images which are not of subclass SkImage_RasterPinnable
102 return;
103 }
104 auto raster = static_cast<SkImage_RasterPinnable*>(ib);
105 if (!raster->fPinnedData) {
106 SkASSERT(false);
107 return;
108 }
109
110 SkASSERT(raster->fPinnedData->fPinnedCount > 0);
111 SkASSERT(raster->fPinnedData->fPinnedUniqueID != 0);
112 // It would be good to check rContext->priv().contextID() != fPinnedContextID
113 // but Android used to (maybe still does) call Unpin with a freed context ptr
114
115 raster->fPinnedData->fPinnedCount--;
116 if (raster->fPinnedData->fPinnedCount <= 0) {
117 raster->fPinnedData.reset(nullptr);
118 }
119 }
120
121 } // namespace skgpu::ganesh
122