• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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 #ifndef SkSpecialImage_DEFINED
9 #define SkSpecialImage_DEFINED
10 
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkSamplingOptions.h"
14 #include "include/core/SkSurfaceProps.h"
15 #include "src/core/SkNextID.h"
16 
17 #if defined(SK_GANESH)
18 #include "include/private/gpu/ganesh/GrTypesPriv.h"
19 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
20 #endif
21 
22 class GrColorInfo;
23 class GrRecordingContext;
24 class GrTextureProxy;
25 class SkBitmap;
26 class SkCanvas;
27 class SkImage;
28 struct SkImageInfo;
29 class SkMatrix;
30 class SkPaint;
31 class SkPixmap;
32 class SkShader;
33 class SkSpecialSurface;
34 class SkSurface;
35 enum class SkTileMode;
36 
37 namespace skgpu::graphite {
38 class Recorder;
39 class TextureProxyView;
40 }
41 
42 enum {
43     kNeedNewImageUniqueID_SpecialImage = 0
44 };
45 
46 /**
47  * This is a restricted form of SkImage solely intended for internal use. It
48  * differs from SkImage in that:
49  *      - it can only be backed by raster or gpu (no generators)
50  *      - it can be backed by a GrTextureProxy larger than its nominal bounds
51  *      - it can't be drawn tiled
52  *      - it can't be drawn with MIPMAPs
53  * It is similar to SkImage in that it abstracts how the pixels are stored/represented.
54  *
55  * Note: the contents of the backing storage outside of the subset rect are undefined.
56  */
57 class SkSpecialImage : public SkRefCnt {
58 public:
59     typedef void* ReleaseContext;
60     typedef void(*RasterReleaseProc)(void* pixels, ReleaseContext);
61 
props()62     const SkSurfaceProps& props() const { return fProps; }
63 
width()64     int width() const { return fSubset.width(); }
height()65     int height() const { return fSubset.height(); }
dimensions()66     SkISize dimensions() const { return { this->width(), this->height() }; }
subset()67     const SkIRect& subset() const { return fSubset; }
68 
uniqueID()69     uint32_t uniqueID() const { return fUniqueID; }
70 
71     virtual size_t getSize() const = 0;
72 
colorInfo()73     const SkColorInfo& colorInfo() const { return fColorInfo; }
alphaType()74     SkAlphaType alphaType() const { return fColorInfo.alphaType(); }
colorType()75     SkColorType colorType() const { return fColorInfo.colorType(); }
getColorSpace()76     SkColorSpace* getColorSpace() const { return fColorInfo.colorSpace(); }
77 
78     /**
79      *  Draw this SpecialImage into the canvas, automatically taking into account the image's subset
80      */
draw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)81     void draw(SkCanvas* canvas,
82               SkScalar x, SkScalar y,
83               const SkSamplingOptions& sampling,
84               const SkPaint* paint) const {
85         return this->onDraw(canvas, x, y, sampling, paint);
86     }
draw(SkCanvas * canvas,SkScalar x,SkScalar y)87     void draw(SkCanvas* canvas, SkScalar x, SkScalar y) const {
88         this->draw(canvas, x, y, SkSamplingOptions(), nullptr);
89     }
90 
91     static sk_sp<SkSpecialImage> MakeFromImage(GrRecordingContext*,
92                                                const SkIRect& subset,
93                                                sk_sp<SkImage>,
94                                                const SkSurfaceProps&);
95     static sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset,
96                                                 const SkBitmap&,
97                                                 const SkSurfaceProps&);
98     static sk_sp<SkSpecialImage> CopyFromRaster(const SkIRect& subset,
99                                                 const SkBitmap&,
100                                                 const SkSurfaceProps&);
101 #if defined(SK_GANESH)
102     static sk_sp<SkSpecialImage> MakeDeferredFromGpu(GrRecordingContext*,
103                                                      const SkIRect& subset,
104                                                      uint32_t uniqueID,
105                                                      GrSurfaceProxyView,
106                                                      const GrColorInfo&,
107                                                      const SkSurfaceProps&);
108 #endif
109 
110 #if SK_GRAPHITE
111     static sk_sp<SkSpecialImage> MakeGraphite(skgpu::graphite::Recorder*,
112                                               const SkIRect& subset,
113                                               uint32_t uniqueID,
114                                               skgpu::graphite::TextureProxyView,
115                                               const SkColorInfo&,
116                                               const SkSurfaceProps&);
117 #endif
118 
119     /**
120      *  Create a new special surface with a backend that is compatible with this special image.
121      */
122     sk_sp<SkSpecialSurface> makeSurface(SkColorType,
123                                         const SkColorSpace*,
124                                         const SkISize& size,
125                                         SkAlphaType,
126                                         const SkSurfaceProps&) const;
127 
128     /**
129      * Create a new surface with a backend that is compatible with this special image.
130      * TODO: switch this to makeSurface once we resolved the naming issue
131      * TODO (michaelludwig) - This is only used by SkTileImageFilter, which appears should be
132      * updated to work correctly with subsets and then makeTightSurface() can go away entirely.
133      */
134     sk_sp<SkSurface> makeTightSurface(SkColorType,
135                                       const SkColorSpace*,
136                                       const SkISize& size,
137                                       SkAlphaType = kPremul_SkAlphaType) const;
138 
139     /**
140      * Extract a subset of this special image and return it as a special image.
141      * It may or may not point to the same backing memory. The input 'subset' is relative to the
142      * special image's content rect.
143      */
makeSubset(const SkIRect & subset)144     sk_sp<SkSpecialImage> makeSubset(const SkIRect& subset) const {
145         SkIRect absolute = subset.makeOffset(this->subset().topLeft());
146         return this->onMakeSubset(absolute);
147     }
148 
149     /**
150      * Create an SkImage from the contents of this special image optionally extracting a subset.
151      * It may or may not point to the same backing memory.
152      * Note: when no 'subset' parameter is specified the the entire SkSpecialImage will be
153      * returned - including whatever extra padding may have resulted from a loose fit!
154      * When the 'subset' parameter is specified the returned image will be tight even if that
155      * entails a copy! The 'subset' is relative to this special image's content rect.
156      */
157     // TODO: The only version that uses the subset is the tile image filter, and that doesn't need
158     // to if it can be rewritten to use asShader() and SkTileModes. Similarly, the only use case of
159     // asImage() w/o a subset is SkImage::makeFiltered() and that could/should return an SkShader so
160     // that users don't need to worry about correctly applying the subset, etc.
161     sk_sp<SkImage> asImage(const SkIRect* subset = nullptr) const;
162 
163     /**
164      * Create an SkShader that samples the contents of this special image, applying tile mode for
165      * any sample that falls outside its internal subset.
166      */
167     sk_sp<SkShader> asShader(SkTileMode, const SkSamplingOptions&, const SkMatrix& lm) const;
168     sk_sp<SkShader> asShader(const SkSamplingOptions& sampling) const;
169     sk_sp<SkShader> asShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const;
170 
171     /**
172      *  If the SpecialImage is backed by a gpu texture, return true.
173      */
isTextureBacked()174     bool isTextureBacked() const { return SkToBool(this->onGetContext()); }
175 
176     /**
177      * Return the GrRecordingContext if the SkSpecialImage is GrTexture-backed
178      */
getContext()179     GrRecordingContext* getContext() const { return this->onGetContext(); }
180 
181 #if defined(SK_GANESH)
182     /**
183      * Regardless of how the underlying backing data is stored, returns the contents as a
184      * GrSurfaceProxyView. The returned view's proxy represents the entire backing image, so texture
185      * coordinates must be mapped from the content rect (e.g. relative to 'subset()') to the proxy's
186      * space (offset by subset().topLeft()).
187      */
view(GrRecordingContext * context)188     GrSurfaceProxyView view(GrRecordingContext* context) const { return this->onView(context); }
189 #endif
190 
191 #if SK_GRAPHITE
192     bool isGraphiteBacked() const;
193 
194     skgpu::graphite::TextureProxyView textureProxyView() const;
195 #endif
196 
197     /**
198      *  Regardless of the underlying backing store, return the contents as an SkBitmap.
199      *  The returned bitmap represents the subset accessed by this image, thus (0,0) refers to the
200      *  top-left corner of 'subset'.
201      */
getROPixels(SkBitmap * bm)202     bool getROPixels(SkBitmap* bm) const {
203         return this->onGetROPixels(bm);
204     }
205 
206 protected:
207     SkSpecialImage(const SkIRect& subset,
208                    uint32_t uniqueID,
209                    const SkColorInfo&,
210                    const SkSurfaceProps&);
211 
212     virtual void onDraw(SkCanvas*,
213                         SkScalar x, SkScalar y,
214                         const SkSamplingOptions&,
215                         const SkPaint*) const = 0;
216 
217     virtual bool onGetROPixels(SkBitmap*) const = 0;
218 
onGetContext()219     virtual GrRecordingContext* onGetContext() const { return nullptr; }
220 
221 #if defined(SK_GANESH)
222     virtual GrSurfaceProxyView onView(GrRecordingContext*) const = 0;
223 #endif
224 
225 #if SK_GRAPHITE
226     virtual skgpu::graphite::TextureProxyView onTextureProxyView() const;
227 #endif
228 
229     // This subset is relative to the backing store's coordinate frame, it has already been mapped
230     // from the content rect by the non-virtual makeSubset().
231     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
232 
233     virtual sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType,
234                                                   const SkColorSpace* colorSpace,
235                                                   const SkISize& size,
236                                                   SkAlphaType at,
237                                                   const SkSurfaceProps&) const = 0;
238 
239     // This subset (when not null) is relative to the backing store's coordinate frame, it has
240     // already been mapped from the content rect by the non-virtual asImage().
241     virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
242 
243     virtual sk_sp<SkShader> onAsShader(SkTileMode,
244                                        const SkSamplingOptions&,
245                                        const SkMatrix&) const = 0;
246 
247     virtual sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType,
248                                                 const SkColorSpace* colorSpace,
249                                                 const SkISize& size,
250                                                 SkAlphaType at) const = 0;
251 
252 #ifdef SK_DEBUG
253     static bool RectFits(const SkIRect& rect, int width, int height);
254 #endif
255 
256 private:
257     const SkIRect        fSubset;
258     const uint32_t       fUniqueID;
259     const SkColorInfo    fColorInfo;
260     const SkSurfaceProps fProps;
261 };
262 
263 #endif // SkSpecialImage_DEFINED
264