1 /* 2 * Copyright 2012 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 SkSurface_DEFINED 9 #define SkSurface_DEFINED 10 11 #include "SkRefCnt.h" 12 #include "SkImage.h" 13 #include "SkSurfaceProps.h" 14 15 class SkCanvas; 16 class SkPaint; 17 class GrBackendRenderTarget; 18 class GrBackendSemaphore; 19 class GrContext; 20 class GrRenderTarget; 21 22 /** 23 * SkSurface is responsible for managing the pixels that a canvas draws into. The pixels can be 24 * allocated either in CPU memory (a Raster surface) or on the GPU (a RenderTarget surface). 25 * 26 * SkSurface takes care of allocating a SkCanvas that will draw into the surface. Call 27 * surface->getCanvas() to use that canvas (but don't delete it, it is owned by the surface). 28 * 29 * SkSurface always has non-zero dimensions. If there is a request for a new surface, and either 30 * of the requested dimensions are zero, then NULL will be returned. 31 */ 32 class SK_API SkSurface : public SkRefCnt { 33 public: 34 /** 35 * Create a new surface, using the specified pixels/rowbytes as its 36 * backend. 37 * 38 * If the requested surface cannot be created, or the request is not a 39 * supported configuration, NULL will be returned. 40 * 41 * Callers are responsible for initialiazing the surface pixels. 42 */ 43 static sk_sp<SkSurface> MakeRasterDirect(const SkImageInfo&, void* pixels, size_t rowBytes, 44 const SkSurfaceProps* = nullptr); 45 46 /** 47 * The same as NewRasterDirect, but also accepts a call-back routine, which is invoked 48 * when the surface is deleted, and is passed the pixel memory and the specified context. 49 */ 50 static sk_sp<SkSurface> MakeRasterDirectReleaseProc(const SkImageInfo&, void* pixels, size_t rowBytes, 51 void (*releaseProc)(void* pixels, void* context), 52 void* context, const SkSurfaceProps* = nullptr); 53 54 /** 55 * Return a new surface, with the memory for the pixels automatically allocated and 56 * zero-initialized, but respecting the specified rowBytes. If rowBytes==0, then a default 57 * value will be chosen. If a non-zero rowBytes is specified, then any images snapped off of 58 * this surface (via makeImageSnapshot()) are guaranteed to have the same rowBytes. 59 * 60 * If the requested surface cannot be created, or the request is not a 61 * supported configuration, NULL will be returned. 62 */ 63 static sk_sp<SkSurface> MakeRaster(const SkImageInfo&, size_t rowBytes, const SkSurfaceProps*); 64 65 /** 66 * Allocate a new surface, automatically computing the rowBytes. 67 */ 68 static sk_sp<SkSurface> MakeRaster(const SkImageInfo& info, 69 const SkSurfaceProps* props = nullptr) { 70 return MakeRaster(info, 0, props); 71 } 72 73 /** 74 * Helper version of NewRaster. It creates a SkImageInfo with the 75 * specified width and height, and populates the rest of info to match 76 * pixels in SkPMColor format. 77 */ 78 static sk_sp<SkSurface> MakeRasterN32Premul(int width, int height, 79 const SkSurfaceProps* props = nullptr) { 80 return MakeRaster(SkImageInfo::MakeN32Premul(width, height), props); 81 } 82 83 /** 84 * Used to wrap a pre-existing backend 3D API texture as a SkSurface. The kRenderTarget flag 85 * must be set on GrBackendTextureDesc for this to succeed. Skia will not assume ownership 86 * of the texture and the client must ensure the texture is valid for the lifetime of the 87 * SkSurface. 88 */ 89 static sk_sp<SkSurface> MakeFromBackendTexture(GrContext*, const GrBackendTextureDesc&, 90 sk_sp<SkColorSpace>, const SkSurfaceProps*); 91 92 /** 93 * Used to wrap a pre-existing backend 3D API texture as a SkSurface. Skia will not assume 94 * ownership of the texture and the client must ensure the texture is valid for the lifetime 95 * of the SkSurface. If sampleCnt > 0, then we will create an intermediate mssa surface which 96 * we will use for rendering. We then resolve into the passed in texture. 97 */ 98 static sk_sp<SkSurface> MakeFromBackendTexture(GrContext*, const GrBackendTexture&, 99 GrSurfaceOrigin origin, int sampleCnt, 100 sk_sp<SkColorSpace>, const SkSurfaceProps*); 101 102 /** 103 * Used to wrap a pre-existing 3D API rendering target as a SkSurface. Skia will not assume 104 * ownership of the render target and the client must ensure the render target is valid for the 105 * lifetime of the SkSurface. 106 */ 107 static sk_sp<SkSurface> MakeFromBackendRenderTarget(GrContext*, 108 const GrBackendRenderTargetDesc&, 109 sk_sp<SkColorSpace>, 110 const SkSurfaceProps*); 111 112 static sk_sp<SkSurface> MakeFromBackendRenderTarget(GrContext*, 113 const GrBackendRenderTarget&, 114 GrSurfaceOrigin origin, 115 sk_sp<SkColorSpace>, 116 const SkSurfaceProps*); 117 118 /** 119 * Used to wrap a pre-existing 3D API texture as a SkSurface. Skia will treat the texture as 120 * a rendering target only, but unlike NewFromBackendRenderTarget, Skia will manage and own 121 * the associated render target objects (but not the provided texture). The kRenderTarget flag 122 * must be set on GrBackendTextureDesc for this to succeed. Skia will not assume ownership 123 * of the texture and the client must ensure the texture is valid for the lifetime of the 124 * SkSurface. 125 */ 126 static sk_sp<SkSurface> MakeFromBackendTextureAsRenderTarget( 127 GrContext*, const GrBackendTextureDesc&, sk_sp<SkColorSpace>, const SkSurfaceProps*); 128 129 static sk_sp<SkSurface> MakeFromBackendTextureAsRenderTarget(GrContext*, 130 const GrBackendTexture&, 131 GrSurfaceOrigin origin, 132 int sampleCnt, 133 sk_sp<SkColorSpace>, 134 const SkSurfaceProps*); 135 136 /** 137 * Legacy versions of the above factories, without color space support. These create "legacy" 138 * surfaces that operate without gamma correction or color management. 139 */ MakeFromBackendTexture(GrContext * ctx,const GrBackendTextureDesc & desc,const SkSurfaceProps * props)140 static sk_sp<SkSurface> MakeFromBackendTexture(GrContext* ctx, const GrBackendTextureDesc& desc, 141 const SkSurfaceProps* props) { 142 return MakeFromBackendTexture(ctx, desc, nullptr, props); 143 } 144 MakeFromBackendRenderTarget(GrContext * ctx,const GrBackendRenderTargetDesc & desc,const SkSurfaceProps * props)145 static sk_sp<SkSurface> MakeFromBackendRenderTarget(GrContext* ctx, 146 const GrBackendRenderTargetDesc& desc, 147 const SkSurfaceProps* props) { 148 return MakeFromBackendRenderTarget(ctx, desc, nullptr, props); 149 } 150 MakeFromBackendTextureAsRenderTarget(GrContext * ctx,const GrBackendTextureDesc & desc,const SkSurfaceProps * props)151 static sk_sp<SkSurface> MakeFromBackendTextureAsRenderTarget( 152 GrContext* ctx, const GrBackendTextureDesc& desc, const SkSurfaceProps* props) { 153 return MakeFromBackendTextureAsRenderTarget(ctx, desc, nullptr, props); 154 } 155 156 157 /** 158 * Return a new surface whose contents will be drawn to an offscreen 159 * render target, allocated by the surface. 160 */ 161 static sk_sp<SkSurface> MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, 162 int sampleCount, GrSurfaceOrigin, 163 const SkSurfaceProps*); 164 MakeRenderTarget(GrContext * context,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,const SkSurfaceProps * props)165 static sk_sp<SkSurface> MakeRenderTarget(GrContext* context, SkBudgeted budgeted, 166 const SkImageInfo& info, int sampleCount, 167 const SkSurfaceProps* props) { 168 return MakeRenderTarget(context, budgeted, info, sampleCount, 169 kBottomLeft_GrSurfaceOrigin, props); 170 } 171 MakeRenderTarget(GrContext * gr,SkBudgeted b,const SkImageInfo & info)172 static sk_sp<SkSurface> MakeRenderTarget(GrContext* gr, SkBudgeted b, const SkImageInfo& info) { 173 if (!info.width() || !info.height()) { 174 return nullptr; 175 } 176 return MakeRenderTarget(gr, b, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr); 177 } 178 179 /** 180 * Returns a surface that stores no pixels. It can be drawn to via its canvas, but that 181 * canvas does not draw anything. Calling makeImageSnapshot() will return nullptr. 182 */ 183 static sk_sp<SkSurface> MakeNull(int width, int height); 184 width()185 int width() const { return fWidth; } height()186 int height() const { return fHeight; } 187 188 /** 189 * Returns a unique non-zero, unique value identifying the content of this 190 * surface. Each time the content is changed changed, either by drawing 191 * into this surface, or explicitly calling notifyContentChanged()) this 192 * method will return a new value. 193 * 194 * If this surface is empty (i.e. has a zero-dimention), this will return 195 * 0. 196 */ 197 uint32_t generationID(); 198 199 /** 200 * Modes that can be passed to notifyContentWillChange 201 */ 202 enum ContentChangeMode { 203 /** 204 * Use this mode if it is known that the upcoming content changes will 205 * clear or overwrite prior contents, thus making them discardable. 206 */ 207 kDiscard_ContentChangeMode, 208 /** 209 * Use this mode if prior surface contents need to be preserved or 210 * if in doubt. 211 */ 212 kRetain_ContentChangeMode, 213 }; 214 215 /** 216 * Call this if the contents are about to change. This will (lazily) force a new 217 * value to be returned from generationID() when it is called next. 218 * 219 * CAN WE DEPRECATE THIS? 220 */ 221 void notifyContentWillChange(ContentChangeMode mode); 222 223 enum BackendHandleAccess { 224 kFlushRead_BackendHandleAccess, //!< caller may read from the backend object 225 kFlushWrite_BackendHandleAccess, //!< caller may write to the backend object 226 kDiscardWrite_BackendHandleAccess, //!< caller must over-write the entire backend object 227 }; 228 229 /* 230 * These are legacy aliases which will be removed soon 231 */ 232 static const BackendHandleAccess kFlushRead_TextureHandleAccess = 233 kFlushRead_BackendHandleAccess; 234 static const BackendHandleAccess kFlushWrite_TextureHandleAccess = 235 kFlushWrite_BackendHandleAccess; 236 static const BackendHandleAccess kDiscardWrite_TextureHandleAccess = 237 kDiscardWrite_BackendHandleAccess; 238 239 240 /** 241 * Retrieves the backend API handle of the texture used by this surface, or 0 if the surface 242 * is not backed by a GPU texture. 243 * 244 * The returned texture-handle is only valid until the next draw-call into the surface, 245 * or the surface is deleted. 246 */ 247 GrBackendObject getTextureHandle(BackendHandleAccess); 248 249 /** 250 * Retrieves the backend API handle of the RenderTarget backing this surface. Callers must 251 * ensure this function returns 'true' or else the GrBackendObject will be invalid 252 * 253 * In OpenGL this will return the FramebufferObject ID. 254 */ 255 bool getRenderTargetHandle(GrBackendObject*, BackendHandleAccess); 256 257 /** 258 * Return a canvas that will draw into this surface. This will always 259 * return the same canvas for a given surface, and is manged/owned by the 260 * surface. It should not be used when its parent surface has gone out of 261 * scope. 262 */ 263 SkCanvas* getCanvas(); 264 265 /** 266 * Return a new surface that is "compatible" with this one, in that it will 267 * efficiently be able to be drawn into this surface. Typical calling 268 * pattern: 269 * 270 * SkSurface* A = SkSurface::New...(); 271 * SkCanvas* canvasA = surfaceA->newCanvas(); 272 * ... 273 * SkSurface* surfaceB = surfaceA->newSurface(...); 274 * SkCanvas* canvasB = surfaceB->newCanvas(); 275 * ... // draw using canvasB 276 * canvasA->drawSurface(surfaceB); // <--- this will always be optimal! 277 */ 278 sk_sp<SkSurface> makeSurface(const SkImageInfo&); 279 280 /** 281 * Returns an image of the current state of the surface pixels up to this 282 * point. Subsequent changes to the surface (by drawing into its canvas) 283 * will not be reflected in this image. For the GPU-backend, the budgeting 284 * decision for the snapped image will match that of the surface. 285 */ 286 sk_sp<SkImage> makeImageSnapshot(); 287 288 /** 289 * Though the caller could get a snapshot image explicitly, and draw that, 290 * it seems that directly drawing a surface into another canvas might be 291 * a common pattern, and that we could possibly be more efficient, since 292 * we'd know that the "snapshot" need only live until we've handed it off 293 * to the canvas. 294 */ 295 void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); 296 297 /** 298 * If the surface has direct access to its pixels (i.e. they are in local 299 * RAM) return true, and if not null, set the pixmap parameter to point to the information 300 * about the surface's pixels. The pixel address in the pixmap is only valid while 301 * the surface object is in scope, and no API call is made on the surface 302 * or its canvas. 303 * 304 * On failure, returns false and the pixmap parameter is ignored. 305 */ 306 bool peekPixels(SkPixmap*); 307 308 /** 309 * Copy the pixels from the surface into the specified buffer (pixels + rowBytes), 310 * converting them into the requested format (dstInfo). The surface pixels are read 311 * starting at the specified (srcX,srcY) location. 312 * 313 * The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle 314 * 315 * srcR.setXYWH(srcX, srcY, dstInfo.width(), dstInfo.height()); 316 * 317 * srcR is intersected with the bounds of the base-layer. If this intersection is not empty, 318 * then we have two sets of pixels (of equal size). Replace the dst pixels with the 319 * corresponding src pixels, performing any colortype/alphatype transformations needed 320 * (in the case where the src and dst have different colortypes or alphatypes). 321 * 322 * This call can fail, returning false, for several reasons: 323 * - If srcR does not intersect the surface bounds. 324 * - If the requested colortype/alphatype cannot be converted from the surface's types. 325 */ 326 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 327 int srcX, int srcY); 328 props()329 const SkSurfaceProps& props() const { return fProps; } 330 331 /** 332 * Issue any pending surface IO to the current backend 3D API and resolve any surface MSAA. 333 * 334 * The flush calls below are the new preferred way to flush calls to a surface, and this call 335 * will eventually be removed. 336 */ 337 void prepareForExternalIO(); 338 339 /** 340 * Issue any pending surface IO to the current backend 3D API 341 */ 342 void flush(); 343 344 /** 345 * Issue any pending surface IO to the current backend 3D API. After issuing all commands, we 346 * will issue numSemaphore semaphores for the gpu to signal. We will then fill in the array 347 * signalSemaphores with the info on the semaphores we submitted. The client is reposonsible for 348 * allocating enough space in signalSemaphores to handle numSemaphores of GrBackendSemaphores. 349 * The client will also take ownership of the returned underlying backend semaphores. 350 * 351 * If this call returns false, the GPU backend will not have created or added any semaphores to 352 * signal. Thus the array of semaphores will remain uninitialized. However, we will still flush 353 * any pending surface IO. 354 */ 355 bool flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores); 356 357 /** 358 * Inserts a list of GPU semaphores that the current backend 3D API must wait on before 359 * executing any more commands on the GPU for this surface. Skia will take ownership of the 360 * underlying semaphores and delete them once they have been signaled and waited on. 361 * 362 * If this call returns false, then the GPU backend will not wait on any passed in semaphores, 363 * and the client will still own the semaphores. 364 */ 365 bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores); 366 367 protected: 368 SkSurface(int width, int height, const SkSurfaceProps*); 369 SkSurface(const SkImageInfo&, const SkSurfaceProps*); 370 371 // called by subclass if their contents have changed dirtyGenerationID()372 void dirtyGenerationID() { 373 fGenerationID = 0; 374 } 375 376 private: 377 const SkSurfaceProps fProps; 378 const int fWidth; 379 const int fHeight; 380 uint32_t fGenerationID; 381 382 typedef SkRefCnt INHERITED; 383 }; 384 385 #endif 386