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