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