1 /*
2 * Copyright 2021 Google LLC
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 #include "src/gpu/graphite/Surface_Graphite.h"
9
10 #include "include/core/SkCapabilities.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/gpu/graphite/BackendTexture.h"
13 #include "include/gpu/graphite/Recorder.h"
14 #include "include/gpu/graphite/Surface.h"
15 #include "src/core/SkSurfacePriv.h"
16 #include "src/gpu/RefCntedCallback.h"
17 #include "src/gpu/SkBackingFit.h"
18 #include "src/gpu/graphite/Caps.h"
19 #include "src/gpu/graphite/Device.h"
20 #include "src/gpu/graphite/Image_Graphite.h"
21 #include "src/gpu/graphite/Log.h"
22 #include "src/gpu/graphite/RecorderPriv.h"
23 #include "src/gpu/graphite/ResourceProvider.h"
24 #include "src/gpu/graphite/Texture.h"
25
26 namespace skgpu::graphite {
27
Surface(sk_sp<Device> device)28 Surface::Surface(sk_sp<Device> device)
29 : SkSurface_Base(device->width(), device->height(), &device->surfaceProps())
30 , fDevice(std::move(device))
31 , fImageView(Image::WrapDevice(fDevice)) {}
32
~Surface()33 Surface::~Surface() {
34 // Mark the device immutable when the Surface is destroyed to flush any pending work to the
35 // recorder and to flag the device so that any linked image views can detach from the Device
36 // when they are next drawn.
37 fDevice->setImmutable();
38 }
39
imageInfo() const40 SkImageInfo Surface::imageInfo() const {
41 return fDevice->imageInfo();
42 }
43
onGetRecorder() const44 Recorder* Surface::onGetRecorder() const { return fDevice->recorder(); }
45
readSurfaceView() const46 TextureProxyView Surface::readSurfaceView() const {
47 return fDevice->readSurfaceView();
48 }
49
onNewCanvas()50 SkCanvas* Surface::onNewCanvas() { return new SkCanvas(fDevice); }
51
onNewSurface(const SkImageInfo & ii)52 sk_sp<SkSurface> Surface::onNewSurface(const SkImageInfo& ii) {
53 return fDevice->makeSurface(ii, this->props());
54 }
55
onNewImageSnapshot(const SkIRect * subset)56 sk_sp<SkImage> Surface::onNewImageSnapshot(const SkIRect* subset) {
57 return this->makeImageCopy(subset, fDevice->target()->mipmapped());
58 }
59
asImage() const60 sk_sp<Image> Surface::asImage() const {
61 if (this->hasCachedImage()) {
62 SKGPU_LOG_W("Intermingling makeImageSnapshot and asImage calls may produce "
63 "unexpected results. Please use either the old _or_ new API.");
64 }
65 return fImageView;
66 }
67
onMakeTemporaryImage()68 sk_sp<SkImage> Surface::onMakeTemporaryImage() {
69 if (this->hasCachedImage()) {
70 SKGPU_LOG_W("Intermingling makeImageSnapshot and makeTemporaryImage calls may produce "
71 "unexpected results. Please use either the old _or_ new API.");
72 }
73 return this->asImage();
74 }
75
makeImageCopy(const SkIRect * subset,Mipmapped mipmapped) const76 sk_sp<Image> Surface::makeImageCopy(const SkIRect* subset, Mipmapped mipmapped) const {
77 if (this->hasCachedImage()) {
78 SKGPU_LOG_W("Intermingling makeImageSnapshot and asImage calls may produce "
79 "unexpected results. Please use either the old _or_ new API.");
80 }
81
82 SkIRect srcRect = subset ? *subset : SkIRect::MakeSize(this->imageInfo().dimensions());
83 // NOTE: Must copy through fDevice and not fImageView if the surface's texture is not sampleable
84 return fDevice->makeImageCopy(srcRect, Budgeted::kNo, mipmapped, SkBackingFit::kExact);
85 }
86
onWritePixels(const SkPixmap & pixmap,int x,int y)87 void Surface::onWritePixels(const SkPixmap& pixmap, int x, int y) {
88 fDevice->writePixels(pixmap, x, y);
89 }
90
onCopyOnWrite(ContentChangeMode)91 bool Surface::onCopyOnWrite(ContentChangeMode) { return true; }
92
onAsyncRescaleAndReadPixels(const SkImageInfo & info,SkIRect srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)93 void Surface::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
94 SkIRect srcRect,
95 RescaleGamma rescaleGamma,
96 RescaleMode rescaleMode,
97 ReadPixelsCallback callback,
98 ReadPixelsContext context) {
99 // Not supported for Graphite. Use Context::asyncRescaleAndReadPixels instead.
100 callback(context, nullptr);
101 }
102
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,bool readAlpha,sk_sp<SkColorSpace> dstColorSpace,SkIRect srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)103 void Surface::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
104 bool readAlpha,
105 sk_sp<SkColorSpace> dstColorSpace,
106 SkIRect srcRect,
107 SkISize dstSize,
108 RescaleGamma rescaleGamma,
109 RescaleMode rescaleMode,
110 ReadPixelsCallback callback,
111 ReadPixelsContext context) {
112 // Not supported for Graphite. Use Context::asyncRescaleAndReadPixelsYUV420 instead.
113 callback(context, nullptr);
114 }
115
onCapabilities()116 sk_sp<const SkCapabilities> Surface::onCapabilities() {
117 return fDevice->recorder()->priv().caps()->capabilities();
118 }
119
backingTextureProxy() const120 TextureProxy* Surface::backingTextureProxy() const { return fDevice->target(); }
121
Make(Recorder * recorder,const SkImageInfo & info,std::string_view label,Budgeted budgeted,Mipmapped mipmapped,SkBackingFit backingFit,const SkSurfaceProps * props,LoadOp initialLoadOp,bool registerWithRecorder)122 sk_sp<Surface> Surface::Make(Recorder* recorder,
123 const SkImageInfo& info,
124 std::string_view label,
125 Budgeted budgeted,
126 Mipmapped mipmapped,
127 SkBackingFit backingFit,
128 const SkSurfaceProps* props,
129 LoadOp initialLoadOp,
130 bool registerWithRecorder) {
131 sk_sp<Device> device = Device::Make(recorder,
132 info,
133 budgeted,
134 mipmapped,
135 backingFit,
136 SkSurfacePropsCopyOrDefault(props),
137 initialLoadOp,
138 std::move(label),
139 registerWithRecorder);
140 if (!device) {
141 return nullptr;
142 }
143 // A non-budgeted surface should be fully instantiated before we return it
144 // to the client.
145 SkASSERT(budgeted == Budgeted::kYes || device->target()->isInstantiated());
146 return sk_make_sp<Surface>(std::move(device));
147 }
148
Flush(sk_sp<SkSurface> surface)149 void Flush(sk_sp<SkSurface> surface) {
150 return Flush(surface.get());
151 }
152
Flush(SkSurface * surface)153 void Flush(SkSurface* surface) {
154 if (!surface) {
155 return;
156 }
157 auto sb = asSB(surface);
158 if (!sb->isGraphiteBacked()) {
159 return;
160 }
161 auto gs = static_cast<Surface*>(surface);
162 gs->fDevice->flushPendingWorkToRecorder();
163 }
164
165 } // namespace skgpu::graphite
166
167 using namespace skgpu::graphite;
168
169 namespace {
170
validate_backend_texture(const Caps * caps,const BackendTexture & texture,const SkColorInfo & info)171 bool validate_backend_texture(const Caps* caps,
172 const BackendTexture& texture,
173 const SkColorInfo& info) {
174 if (!texture.isValid() ||
175 texture.dimensions().width() <= 0 ||
176 texture.dimensions().height() <= 0) {
177 return false;
178 }
179
180 if (!SkColorInfoIsValid(info)) {
181 return false;
182 }
183
184 if (!caps->isRenderable(texture.info())) {
185 return false;
186 }
187
188 return caps->areColorTypeAndTextureInfoCompatible(info.colorType(), texture.info());
189 }
190
191 } // anonymous namespace
192
193 namespace SkSurfaces {
AsImage(sk_sp<const SkSurface> surface)194 sk_sp<SkImage> AsImage(sk_sp<const SkSurface> surface) {
195 if (!surface) {
196 return nullptr;
197 }
198 auto sb = asConstSB(surface.get());
199 if (!sb->isGraphiteBacked()) {
200 return nullptr;
201 }
202 auto gs = static_cast<const Surface*>(surface.get());
203 return gs->asImage();
204 }
205
AsImageCopy(sk_sp<const SkSurface> surface,const SkIRect * subset,skgpu::Mipmapped mipmapped)206 sk_sp<SkImage> AsImageCopy(sk_sp<const SkSurface> surface,
207 const SkIRect* subset,
208 skgpu::Mipmapped mipmapped) {
209 if (!surface) {
210 return nullptr;
211 }
212 auto sb = asConstSB(surface.get());
213 if (!sb->isGraphiteBacked()) {
214 return nullptr;
215 }
216 auto gs = static_cast<const Surface*>(surface.get());
217 return gs->makeImageCopy(subset, mipmapped);
218 }
219
RenderTarget(Recorder * recorder,const SkImageInfo & info,skgpu::Mipmapped mipmapped,const SkSurfaceProps * props,std::string_view label)220 sk_sp<SkSurface> RenderTarget(Recorder* recorder,
221 const SkImageInfo& info,
222 skgpu::Mipmapped mipmapped,
223 const SkSurfaceProps* props,
224 std::string_view label) {
225 if (label.empty()) {
226 label = "SkSurfaceRenderTarget";
227 }
228 // The client is getting the ref on this surface so it must be unbudgeted.
229 return skgpu::graphite::Surface::Make(recorder, info, std::move(label), skgpu::Budgeted::kNo,
230 mipmapped, SkBackingFit::kExact, props);
231 }
232
WrapBackendTexture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,sk_sp<SkColorSpace> cs,const SkSurfaceProps * props,TextureReleaseProc releaseP,ReleaseContext releaseC,std::string_view label)233 sk_sp<SkSurface> WrapBackendTexture(Recorder* recorder,
234 const BackendTexture& backendTex,
235 SkColorType ct,
236 sk_sp<SkColorSpace> cs,
237 const SkSurfaceProps* props,
238 TextureReleaseProc releaseP,
239 ReleaseContext releaseC,
240 std::string_view label) {
241 auto releaseHelper = skgpu::RefCntedCallback::Make(releaseP, releaseC);
242
243 if (!recorder) {
244 return nullptr;
245 }
246
247 const Caps* caps = recorder->priv().caps();
248
249 SkColorInfo info(ct, kPremul_SkAlphaType, std::move(cs));
250
251 if (!validate_backend_texture(caps, backendTex, info)) {
252 SKGPU_LOG_E("validate_backend_texture failed: backendTex.info = %s; colorType = %d",
253 backendTex.info().toString().c_str(),
254 info.colorType());
255 return nullptr;
256 }
257
258 if (label.empty()) {
259 label = "SkSurfaceWrappedTexture";
260 }
261
262 sk_sp<Texture> texture =
263 recorder->priv().resourceProvider()->createWrappedTexture(backendTex, std::move(label));
264 if (!texture) {
265 return nullptr;
266 }
267 texture->setReleaseCallback(std::move(releaseHelper));
268
269 sk_sp<TextureProxy> proxy = TextureProxy::Wrap(std::move(texture));
270 SkISize deviceSize = proxy->dimensions();
271 // Use kLoad for this device to preserve the existing contents of the wrapped backend texture.
272 sk_sp<Device> device = Device::Make(recorder,
273 std::move(proxy),
274 deviceSize,
275 info,
276 SkSurfacePropsCopyOrDefault(props),
277 LoadOp::kLoad);
278 return device ? sk_make_sp<Surface>(std::move(device)) : nullptr;
279 }
280
281 } // namespace SkSurfaces
282