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