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