1/*
2 * Copyright 2017 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 SkDeferredDisplayListRecorder_DEFINED
9#define SkDeferredDisplayListRecorder_DEFINED
10
11#include "include/core/SkDeferredDisplayList.h"
12#include "include/core/SkImageInfo.h"
13#include "include/core/SkRefCnt.h"
14#include "include/core/SkSurfaceCharacterization.h"
15#include "include/core/SkTypes.h"
16
17class GrBackendFormat;
18class GrBackendTexture;
19class GrContext;
20class SkCanvas;
21class SkImage;
22class SkPromiseImageTexture;
23class SkSurface;
24struct SkYUVAIndex;
25struct SkYUVASizeInfo;
26
27/*
28 * This class is intended to be used as:
29 * Get an SkSurfaceCharacterization representing the intended gpu-backed destination SkSurface
30 * Create one of these (an SkDDLMaker) on the stack
31 * Get the canvas and render into it
32 * Snap off and hold on to an SkDeferredDisplayList
33 * Once your app actually needs the pixels, call SkSurface::draw(SkDeferredDisplayList*)
34 *
35 * This class never accesses the GPU but performs all the cpu work it can. It
36 * is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side
37 * work in parallel ahead of time).
38 */
39class SK_API SkDeferredDisplayListRecorder {
40public:
41 SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&);
42 ~SkDeferredDisplayListRecorder();
43
44 const SkSurfaceCharacterization& characterization() const {
45 return fCharacterization;
46 }
47
48 // The backing canvas will become invalid (and this entry point will return
49 // null) once 'detach' is called.
50 // Note: ownership of the SkCanvas is not transferred via this call.
51 SkCanvas* getCanvas();
52
53 std::unique_ptr<SkDeferredDisplayList> detach();
54
55 using PromiseImageTextureContext = void*;
56 using PromiseImageTextureFulfillProc =
57 sk_sp<SkPromiseImageTexture> (*)(PromiseImageTextureContext);
58 using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext);
59 using PromiseImageTextureDoneProc = void (*)(PromiseImageTextureContext);
60
61 enum class PromiseImageApiVersion { kLegacy, kNew };
62
63 /**
64 Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The
65 difference is that the caller need not have created the texture nor populated it with the
66 image pixel data. Moreover, the SkImage may be created on a thread as the creation of the
67 image does not require access to the backend API or GrContext. Instead of passing a
68 GrBackendTexture the client supplies a description of the texture consisting of
69 GrBackendFormat, width, height, and GrMipMapped state. The resulting SkImage can be drawn
70 to a SkDeferredDisplayListRecorder or directly to a GPU-backed SkSurface.
71
72 When the actual texture is required to perform a backend API draw, textureFulfillProc will
73 be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match
74 those set during the SkImage creation, and it must refer to a valid existing texture in the
75 backend API context/device, and be populated with the image pixel data. The texture contents
76 cannot be modified until textureReleaseProc is called. The texture cannot be deleted until
77 textureDoneProc is called.
78
79 When all the following are true:
80 * the promise SkImage is deleted,
81 * any SkDeferredDisplayLists that recorded draws referencing the image are deleted,
82 * and all draws referencing the texture have been flushed (via GrContext::flush or
83 SkSurface::flush)
84 the textureReleaseProc is called. When the following additional constraint is met
85 * the texture is safe to delete in the underlying API
86 the textureDoneProc is called. For some APIs (e.g. GL) the two states are equivalent.
87 However, for others (e.g. Vulkan) they are not as it is not legal to delete a texture until
88 the GPU work referencing it has completed.
89
90 There is at most one call to each of textureFulfillProc, textureReleaseProc, and
91 textureDoneProc. textureDoneProc is always called even if image creation fails or if the
92 image is never fulfilled (e.g. it is never drawn or all draws are clipped out). If
93 textureFulfillProc is called then textureReleaseProc will always be called even if
94 textureFulfillProc failed.
95
96 If 'version' is set to kLegacy then the textureReleaseProc call is delayed until the
97 conditions for textureDoneProc are met and then they are both called.
98
99 This call is only valid if the SkDeferredDisplayListRecorder is backed by a GPU context.
100
101 @param backendFormat format of promised gpu texture
102 @param width width of promised gpu texture
103 @param height height of promised gpu texture
104 @param mipMapped mip mapped state of promised gpu texture
105 @param colorSpace range of colors; may be nullptr
106 @param textureFulfillProc function called to get actual gpu texture
107 @param textureReleaseProc function called when texture can be released
108 @param textureDoneProc function called when we will no longer call textureFulfillProc
109 @param textureContext state passed to textureFulfillProc and textureReleaseProc
110 @param version controls when textureReleaseProc is called
111 @return created SkImage, or nullptr
112 */
113 sk_sp<SkImage> makePromiseTexture(
114 const GrBackendFormat& backendFormat,
115 int width,
116 int height,
117 GrMipMapped mipMapped,
118 GrSurfaceOrigin origin,
119 SkColorType colorType,
120 SkAlphaType alphaType,
121 sk_sp<SkColorSpace> colorSpace,
122 PromiseImageTextureFulfillProc textureFulfillProc,
123 PromiseImageTextureReleaseProc textureReleaseProc,
124 PromiseImageTextureDoneProc textureDoneProc,
125 PromiseImageTextureContext textureContext,
126 PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
127
128 /**
129 This entry point operates like 'makePromiseTexture' but it is used to construct a SkImage
130 from YUV[A] data. The source data may be planar (i.e. spread across multiple textures). In
131 the extreme Y, U, V, and A are all in different planes and thus the image is specified by
132 four textures. 'yuvaIndices' specifies the mapping from texture color channels to Y, U, V,
133 and possibly A components. It therefore indicates how many unique textures compose the full
134 image. Separate textureFulfillProc, textureReleaseProc, and textureDoneProc calls are made
135 for each texture and each texture has its own PromiseImageTextureContext. 'yuvFormats',
136 'yuvaSizes', and 'textureContexts' have one entry for each of the up to four textures, as
137 indicated by 'yuvaIndices'.
138 */
139 sk_sp<SkImage> makeYUVAPromiseTexture(
140 SkYUVColorSpace yuvColorSpace,
141 const GrBackendFormat yuvaFormats[],
142 const SkISize yuvaSizes[],
143 const SkYUVAIndex yuvaIndices[4],
144 int imageWidth,
145 int imageHeight,
146 GrSurfaceOrigin imageOrigin,
147 sk_sp<SkColorSpace> imageColorSpace,
148 PromiseImageTextureFulfillProc textureFulfillProc,
149 PromiseImageTextureReleaseProc textureReleaseProc,
150 PromiseImageTextureDoneProc textureDoneProc,
151 PromiseImageTextureContext textureContexts[],
152 PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
153
154private:
155 bool init();
156
157 const SkSurfaceCharacterization fCharacterization;
158
159#if SK_SUPPORT_GPU
160 sk_sp<GrContext> fContext;
161 sk_sp<SkDeferredDisplayList::LazyProxyData> fLazyProxyData;
162 sk_sp<SkSurface> fSurface;
163#endif
164};
165
166#endif
167