blob: 5860cf22792ba4f6953b96ff841f2884512efaca [file] [log] [blame]
reed@google.com889b09e2012-07-27 21:10:42 +00001/*
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"
reed4a8126e2014-09-22 07:29:03 -070013#include "SkSurfaceProps.h"
reed@google.com889b09e2012-07-27 21:10:42 +000014
15class SkCanvas;
16class SkPaint;
reed@google.com5d4ba882012-07-31 15:45:27 +000017class GrContext;
18class GrRenderTarget;
reed@google.com889b09e2012-07-27 21:10:42 +000019
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.
reedb2497c22014-12-31 12:31:43 -080027 *
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.
reed@google.com889b09e2012-07-27 21:10:42 +000030 */
junov@chromium.org96447be2013-04-18 13:28:19 +000031class SK_API SkSurface : public SkRefCnt {
reed@google.com889b09e2012-07-27 21:10:42 +000032public:
33 /**
bsalomonafe30052015-01-16 07:32:33 -080034 * Indicates whether a new surface or image should count against a cache budget. Currently this
35 * is only used by the GPU backend (sw-raster surfaces and images are never counted against the
36 * resource cache budget.)
37 */
38 enum Budgeted {
39 /** The surface or image does not count against the cache budget. */
40 kNo_Budgeted,
41 /** The surface or image counts against the cache budget. */
42 kYes_Budgeted
43 };
44
45 /**
reed@google.com889b09e2012-07-27 21:10:42 +000046 * Create a new surface, using the specified pixels/rowbytes as its
47 * backend.
48 *
49 * If the requested surface cannot be created, or the request is not a
50 * supported configuration, NULL will be returned.
51 */
reed4a8126e2014-09-22 07:29:03 -070052 static SkSurface* NewRasterDirect(const SkImageInfo&, void* pixels, size_t rowBytes,
53 const SkSurfaceProps* = NULL);
reed@google.com889b09e2012-07-27 21:10:42 +000054
55 /**
reed982542d2014-06-27 06:48:14 -070056 * The same as NewRasterDirect, but also accepts a call-back routine, which is invoked
57 * when the surface is deleted, and is passed the pixel memory and the specified context.
58 */
59 static SkSurface* NewRasterDirectReleaseProc(const SkImageInfo&, void* pixels, size_t rowBytes,
60 void (*releaseProc)(void* pixels, void* context),
reed4a8126e2014-09-22 07:29:03 -070061 void* context, const SkSurfaceProps* = NULL);
reed982542d2014-06-27 06:48:14 -070062
63 /**
reed@google.com889b09e2012-07-27 21:10:42 +000064 * Return a new surface, with the memory for the pixels automatically
65 * allocated.
66 *
67 * If the requested surface cannot be created, or the request is not a
68 * supported configuration, NULL will be returned.
69 */
reed4a8126e2014-09-22 07:29:03 -070070 static SkSurface* NewRaster(const SkImageInfo&, const SkSurfaceProps* = NULL);
reed@google.com889b09e2012-07-27 21:10:42 +000071
72 /**
reed@google.com2bd8b812013-11-01 13:46:54 +000073 * Helper version of NewRaster. It creates a SkImageInfo with the
reed@google.com636d87a2013-09-17 20:03:43 +000074 * specified width and height, and populates the rest of info to match
75 * pixels in SkPMColor format.
76 */
reed3054be12014-12-10 07:24:28 -080077 static SkSurface* NewRasterN32Premul(int width, int height, const SkSurfaceProps* props = NULL) {
78 return NewRaster(SkImageInfo::MakeN32Premul(width, height), props);
79 }
reed@google.com636d87a2013-09-17 20:03:43 +000080
81 /**
reed29c857d2014-09-21 10:25:07 -070082 * Return a new surface using the specified render target.
reed29c857d2014-09-21 10:25:07 -070083 */
reed4a8126e2014-09-22 07:29:03 -070084 static SkSurface* NewRenderTargetDirect(GrRenderTarget*, const SkSurfaceProps*);
mtklein2766c002015-06-26 11:45:03 -070085
reed4a8126e2014-09-22 07:29:03 -070086 static SkSurface* NewRenderTargetDirect(GrRenderTarget* target) {
87 return NewRenderTargetDirect(target, NULL);
88 }
bsalomone4579ad2015-04-08 08:38:40 -070089
90 /**
bsalomond3e259a2015-06-30 12:04:40 -070091 * Used to wrap a pre-existing backend 3D API texture as a SkSurface. The kRenderTarget flag
92 * must be set on GrBackendTextureDesc for this to succeed. Skia will not assume ownership
93 * of the texture and the client must ensure the texture is valid for the lifetime of the
94 * SkSurface.
bsalomone4579ad2015-04-08 08:38:40 -070095 */
bsalomond3e259a2015-06-30 12:04:40 -070096 static SkSurface* NewFromBackendTexture(GrContext*, const GrBackendTextureDesc&,
97 const SkSurfaceProps*);
98 // Legacy alias
99 static SkSurface* NewWrappedRenderTarget(GrContext* ctx, const GrBackendTextureDesc& desc,
100 const SkSurfaceProps* props) {
101 return NewFromBackendTexture(ctx, desc, props);
102 }
103
104
105 /**
106 * Used to wrap a pre-existing 3D API rendering target as a SkSurface. Skia will not assume
107 * ownership of the render target and the client must ensure the render target is valid for the
108 * lifetime of the SkSurface.
109 */
110 static SkSurface* NewFromBackendRenderTarget(GrContext*, const GrBackendRenderTargetDesc&,
111 const SkSurfaceProps*);
mtklein2766c002015-06-26 11:45:03 -0700112
reed29c857d2014-09-21 10:25:07 -0700113 /**
114 * Return a new surface whose contents will be drawn to an offscreen
115 * render target, allocated by the surface.
116 */
bsalomonafe30052015-01-16 07:32:33 -0800117 static SkSurface* NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&, int sampleCount,
reed4a8126e2014-09-22 07:29:03 -0700118 const SkSurfaceProps* = NULL);
119
bsalomonafe30052015-01-16 07:32:33 -0800120 static SkSurface* NewRenderTarget(GrContext* gr, Budgeted b, const SkImageInfo& info) {
121 return NewRenderTarget(gr, b, info, 0, NULL);
reed4a8126e2014-09-22 07:29:03 -0700122 }
reed29c857d2014-09-21 10:25:07 -0700123
reed@google.com889b09e2012-07-27 21:10:42 +0000124 int width() const { return fWidth; }
125 int height() const { return fHeight; }
126
127 /**
128 * Returns a unique non-zero, unique value identifying the content of this
129 * surface. Each time the content is changed changed, either by drawing
130 * into this surface, or explicitly calling notifyContentChanged()) this
131 * method will return a new value.
132 *
133 * If this surface is empty (i.e. has a zero-dimention), this will return
134 * 0.
135 */
reed@google.com97af1a62012-08-28 12:19:02 +0000136 uint32_t generationID();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000137
reed@google.com889b09e2012-07-27 21:10:42 +0000138 /**
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000139 * Modes that can be passed to notifyContentWillChange
140 */
141 enum ContentChangeMode {
skia.committer@gmail.come36a1682013-04-23 07:01:29 +0000142 /**
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000143 * Use this mode if it is known that the upcoming content changes will
144 * clear or overwrite prior contents, thus making them discardable.
145 */
146 kDiscard_ContentChangeMode,
skia.committer@gmail.come36a1682013-04-23 07:01:29 +0000147 /**
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000148 * Use this mode if prior surface contents need to be preserved or
149 * if in doubt.
150 */
151 kRetain_ContentChangeMode,
152 };
153
154 /**
155 * Call this if the contents are about to change. This will (lazily) force a new
reed@google.com889b09e2012-07-27 21:10:42 +0000156 * value to be returned from generationID() when it is called next.
reedfa5e68e2015-06-29 07:37:01 -0700157 *
158 * CAN WE DEPRECATE THIS?
reed@google.com889b09e2012-07-27 21:10:42 +0000159 */
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000160 void notifyContentWillChange(ContentChangeMode mode);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000161
reedfa5e68e2015-06-29 07:37:01 -0700162 enum TextureHandleAccess {
163 kFlushRead_TextureHandleAccess, //!< caller may read from the texture
164 kFlushWrite_TextureHandleAccess, //!< caller may write to the texture
165 kDiscardWrite_TextureHandleAccess, //!< caller must over-write the entire texture
166 };
167 /**
168 * Retrieves the backend API handle of the texture used by this surface, or 0 if the surface
169 * is not backed by a GPU texture.
170 *
171 * The returned texture-handle is only valid until the next draw-call into the surface,
172 * or the surface is deleted.
173 */
174 GrBackendObject getTextureHandle(TextureHandleAccess);
175
reed@google.com889b09e2012-07-27 21:10:42 +0000176 /**
reed@google.com9ea5a3b2012-07-30 21:03:46 +0000177 * Return a canvas that will draw into this surface. This will always
178 * return the same canvas for a given surface, and is manged/owned by the
179 * surface. It should not be used when its parent surface has gone out of
180 * scope.
reed@google.com889b09e2012-07-27 21:10:42 +0000181 */
reed@google.com9ea5a3b2012-07-30 21:03:46 +0000182 SkCanvas* getCanvas();
reed@google.com889b09e2012-07-27 21:10:42 +0000183
184 /**
185 * Return a new surface that is "compatible" with this one, in that it will
186 * efficiently be able to be drawn into this surface. Typical calling
187 * pattern:
188 *
189 * SkSurface* A = SkSurface::New...();
190 * SkCanvas* canvasA = surfaceA->newCanvas();
191 * ...
192 * SkSurface* surfaceB = surfaceA->newSurface(...);
193 * SkCanvas* canvasB = surfaceB->newCanvas();
194 * ... // draw using canvasB
195 * canvasA->drawSurface(surfaceB); // <--- this will always be optimal!
196 */
reed@google.com2bd8b812013-11-01 13:46:54 +0000197 SkSurface* newSurface(const SkImageInfo&);
reed@google.com889b09e2012-07-27 21:10:42 +0000198
199 /**
200 * Returns an image of the current state of the surface pixels up to this
201 * point. Subsequent changes to the surface (by drawing into its canvas)
bsalomoneaaaf0b2015-01-23 08:08:04 -0800202 * will not be reflected in this image. If a copy must be made the Budgeted
203 * parameter controls whether it counts against the resource budget
204 * (currently for the gpu backend only).
reed@google.com889b09e2012-07-27 21:10:42 +0000205 */
bsalomoneaaaf0b2015-01-23 08:08:04 -0800206 SkImage* newImageSnapshot(Budgeted = kYes_Budgeted);
reed@google.com889b09e2012-07-27 21:10:42 +0000207
208 /**
bsalomoneaaaf0b2015-01-23 08:08:04 -0800209 * Though the caller could get a snapshot image explicitly, and draw that,
reed@google.com889b09e2012-07-27 21:10:42 +0000210 * it seems that directly drawing a surface into another canvas might be
211 * a common pattern, and that we could possibly be more efficient, since
212 * we'd know that the "snapshot" need only live until we've handed it off
213 * to the canvas.
214 */
215 void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*);
216
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000217 /**
218 * If the surface has direct access to its pixels (i.e. they are in local
219 * RAM) return the const-address of those pixels, and if not null, return
220 * the ImageInfo and rowBytes. The returned address is only valid while
221 * the surface object is in scope, and no API call is made on the surface
222 * or its canvas.
223 *
224 * On failure, returns NULL and the info and rowBytes parameters are
225 * ignored.
226 */
227 const void* peekPixels(SkImageInfo* info, size_t* rowBytes);
228
reed7543aa22014-12-09 14:39:44 -0800229 /**
230 * Copy the pixels from the surface into the specified buffer (pixels + rowBytes),
reed96472de2014-12-10 09:53:42 -0800231 * converting them into the requested format (dstInfo). The surface pixels are read
232 * starting at the specified (srcX,srcY) location.
reed7543aa22014-12-09 14:39:44 -0800233 *
234 * The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle
235 *
236 * srcR.setXYWH(srcX, srcY, dstInfo.width(), dstInfo.height());
237 *
238 * srcR is intersected with the bounds of the base-layer. If this intersection is not empty,
239 * then we have two sets of pixels (of equal size). Replace the dst pixels with the
240 * corresponding src pixels, performing any colortype/alphatype transformations needed
241 * (in the case where the src and dst have different colortypes or alphatypes).
242 *
243 * This call can fail, returning false, for several reasons:
244 * - If srcR does not intersect the surface bounds.
reed96472de2014-12-10 09:53:42 -0800245 * - If the requested colortype/alphatype cannot be converted from the surface's types.
reed7543aa22014-12-09 14:39:44 -0800246 */
247 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
248 int srcX, int srcY);
249
reed4a8126e2014-09-22 07:29:03 -0700250 const SkSurfaceProps& props() const { return fProps; }
251
reed@google.com889b09e2012-07-27 21:10:42 +0000252protected:
reed4a8126e2014-09-22 07:29:03 -0700253 SkSurface(int width, int height, const SkSurfaceProps*);
254 SkSurface(const SkImageInfo&, const SkSurfaceProps*);
reed@google.com889b09e2012-07-27 21:10:42 +0000255
reed@google.com97af1a62012-08-28 12:19:02 +0000256 // called by subclass if their contents have changed
257 void dirtyGenerationID() {
258 fGenerationID = 0;
259 }
260
reed@google.com889b09e2012-07-27 21:10:42 +0000261private:
reed4a8126e2014-09-22 07:29:03 -0700262 const SkSurfaceProps fProps;
263 const int fWidth;
264 const int fHeight;
265 uint32_t fGenerationID;
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000266
reed@google.com7edfb492012-08-28 12:48:35 +0000267 typedef SkRefCnt INHERITED;
reed@google.com889b09e2012-07-27 21:10:42 +0000268};
269
270#endif