• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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