xref: /aosp_15_r20/external/skia/src/gpu/graphite/Surface_Graphite.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
makeImageCopy(const SkIRect * subset,Mipmapped mipmapped) const68 sk_sp<Image> Surface::makeImageCopy(const SkIRect* subset, Mipmapped mipmapped) const {
69     if (this->hasCachedImage()) {
70         SKGPU_LOG_W("Intermingling makeImageSnapshot and asImage calls may produce "
71                     "unexpected results. Please use either the old _or_ new API.");
72     }
73 
74     SkIRect srcRect = subset ? *subset : SkIRect::MakeSize(this->imageInfo().dimensions());
75     // NOTE: Must copy through fDevice and not fImageView if the surface's texture is not sampleable
76     return fDevice->makeImageCopy(srcRect, Budgeted::kNo, mipmapped, SkBackingFit::kExact);
77 }
78 
onWritePixels(const SkPixmap & pixmap,int x,int y)79 void Surface::onWritePixels(const SkPixmap& pixmap, int x, int y) {
80     fDevice->writePixels(pixmap, x, y);
81 }
82 
onCopyOnWrite(ContentChangeMode)83 bool Surface::onCopyOnWrite(ContentChangeMode) { return true; }
84 
onAsyncRescaleAndReadPixels(const SkImageInfo & info,SkIRect srcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)85 void Surface::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
86                                           SkIRect srcRect,
87                                           RescaleGamma rescaleGamma,
88                                           RescaleMode rescaleMode,
89                                           ReadPixelsCallback callback,
90                                           ReadPixelsContext context) {
91     // Not supported for Graphite. Use Context::asyncRescaleAndReadPixels instead.
92     callback(context, nullptr);
93 }
94 
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,bool readAlpha,sk_sp<SkColorSpace> dstColorSpace,SkIRect srcRect,SkISize dstSize,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context)95 void Surface::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
96                                                 bool readAlpha,
97                                                 sk_sp<SkColorSpace> dstColorSpace,
98                                                 SkIRect srcRect,
99                                                 SkISize dstSize,
100                                                 RescaleGamma rescaleGamma,
101                                                 RescaleMode rescaleMode,
102                                                 ReadPixelsCallback callback,
103                                                 ReadPixelsContext context) {
104     // Not supported for Graphite. Use Context::asyncRescaleAndReadPixelsYUV420 instead.
105     callback(context, nullptr);
106 }
107 
onCapabilities()108 sk_sp<const SkCapabilities> Surface::onCapabilities() {
109     return fDevice->recorder()->priv().caps()->capabilities();
110 }
111 
backingTextureProxy() const112 TextureProxy* Surface::backingTextureProxy() const { return fDevice->target(); }
113 
Make(Recorder * recorder,const SkImageInfo & info,std::string_view label,Budgeted budgeted,Mipmapped mipmapped,SkBackingFit backingFit,const SkSurfaceProps * props,LoadOp initialLoadOp,bool registerWithRecorder)114 sk_sp<Surface> Surface::Make(Recorder* recorder,
115                              const SkImageInfo& info,
116                              std::string_view label,
117                              Budgeted budgeted,
118                              Mipmapped mipmapped,
119                              SkBackingFit backingFit,
120                              const SkSurfaceProps* props,
121                              LoadOp initialLoadOp,
122                              bool registerWithRecorder) {
123     sk_sp<Device> device = Device::Make(recorder,
124                                         info,
125                                         budgeted,
126                                         mipmapped,
127                                         backingFit,
128                                         SkSurfacePropsCopyOrDefault(props),
129                                         initialLoadOp,
130                                         std::move(label),
131                                         registerWithRecorder);
132     if (!device) {
133         return nullptr;
134     }
135     // A non-budgeted surface should be fully instantiated before we return it
136     // to the client.
137     SkASSERT(budgeted == Budgeted::kYes || device->target()->isInstantiated());
138     return sk_make_sp<Surface>(std::move(device));
139 }
140 
Flush(sk_sp<SkSurface> surface)141 void Flush(sk_sp<SkSurface> surface) {
142     return Flush(surface.get());
143 }
144 
Flush(SkSurface * surface)145 void Flush(SkSurface* surface) {
146     if (!surface) {
147         return;
148     }
149     auto sb = asSB(surface);
150     if (!sb->isGraphiteBacked()) {
151         return;
152     }
153     auto gs = static_cast<Surface*>(surface);
154     gs->fDevice->flushPendingWorkToRecorder();
155 }
156 
157 } // namespace skgpu::graphite
158 
159 using namespace skgpu::graphite;
160 
161 namespace {
162 
validate_backend_texture(const Caps * caps,const BackendTexture & texture,const SkColorInfo & info)163 bool validate_backend_texture(const Caps* caps,
164                               const BackendTexture& texture,
165                               const SkColorInfo& info) {
166     if (!texture.isValid() ||
167         texture.dimensions().width() <= 0 ||
168         texture.dimensions().height() <= 0) {
169         return false;
170     }
171 
172     if (!SkColorInfoIsValid(info)) {
173         return false;
174     }
175 
176     if (!caps->isRenderable(texture.info())) {
177         return false;
178     }
179 
180     return caps->areColorTypeAndTextureInfoCompatible(info.colorType(), texture.info());
181 }
182 
183 } // anonymous namespace
184 
185 namespace SkSurfaces {
AsImage(sk_sp<const SkSurface> surface)186 sk_sp<SkImage> AsImage(sk_sp<const SkSurface> surface) {
187     if (!surface) {
188         return nullptr;
189     }
190     auto sb = asConstSB(surface.get());
191     if (!sb->isGraphiteBacked()) {
192         return nullptr;
193     }
194     auto gs = static_cast<const Surface*>(surface.get());
195     return gs->asImage();
196 }
197 
AsImageCopy(sk_sp<const SkSurface> surface,const SkIRect * subset,skgpu::Mipmapped mipmapped)198 sk_sp<SkImage> AsImageCopy(sk_sp<const SkSurface> surface,
199                            const SkIRect* subset,
200                            skgpu::Mipmapped mipmapped) {
201     if (!surface) {
202         return nullptr;
203     }
204     auto sb = asConstSB(surface.get());
205     if (!sb->isGraphiteBacked()) {
206         return nullptr;
207     }
208     auto gs = static_cast<const Surface*>(surface.get());
209     return gs->makeImageCopy(subset, mipmapped);
210 }
211 
RenderTarget(Recorder * recorder,const SkImageInfo & info,skgpu::Mipmapped mipmapped,const SkSurfaceProps * props,std::string_view label)212 sk_sp<SkSurface> RenderTarget(Recorder* recorder,
213                               const SkImageInfo& info,
214                               skgpu::Mipmapped mipmapped,
215                               const SkSurfaceProps* props,
216                               std::string_view label) {
217     if (label.empty()) {
218         label = "SkSurfaceRenderTarget";
219     }
220     // The client is getting the ref on this surface so it must be unbudgeted.
221     return skgpu::graphite::Surface::Make(recorder, info, std::move(label), skgpu::Budgeted::kNo,
222                                           mipmapped, SkBackingFit::kExact, props);
223 }
224 
WrapBackendTexture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,sk_sp<SkColorSpace> cs,const SkSurfaceProps * props,TextureReleaseProc releaseP,ReleaseContext releaseC,std::string_view label)225 sk_sp<SkSurface> WrapBackendTexture(Recorder* recorder,
226                                     const BackendTexture& backendTex,
227                                     SkColorType ct,
228                                     sk_sp<SkColorSpace> cs,
229                                     const SkSurfaceProps* props,
230                                     TextureReleaseProc releaseP,
231                                     ReleaseContext releaseC,
232                                     std::string_view label) {
233     auto releaseHelper = skgpu::RefCntedCallback::Make(releaseP, releaseC);
234 
235     if (!recorder) {
236         return nullptr;
237     }
238 
239     const Caps* caps = recorder->priv().caps();
240 
241     SkColorInfo info(ct, kPremul_SkAlphaType, std::move(cs));
242 
243     if (!validate_backend_texture(caps, backendTex, info)) {
244         SKGPU_LOG_E("validate_backend_texture failed: backendTex.info = %s; colorType = %d",
245                     backendTex.info().toString().c_str(),
246                     info.colorType());
247         return nullptr;
248     }
249 
250     if (label.empty()) {
251         label = "SkSurfaceWrappedTexture";
252     }
253 
254     sk_sp<Texture> texture =
255             recorder->priv().resourceProvider()->createWrappedTexture(backendTex, std::move(label));
256     if (!texture) {
257         return nullptr;
258     }
259     texture->setReleaseCallback(std::move(releaseHelper));
260 
261     sk_sp<TextureProxy> proxy = TextureProxy::Wrap(std::move(texture));
262     SkISize deviceSize = proxy->dimensions();
263     // Use kLoad for this device to preserve the existing contents of the wrapped backend texture.
264     sk_sp<Device> device = Device::Make(recorder,
265                                         std::move(proxy),
266                                         deviceSize,
267                                         info,
268                                         SkSurfacePropsCopyOrDefault(props),
269                                         LoadOp::kLoad);
270     return device ? sk_make_sp<Surface>(std::move(device)) : nullptr;
271 }
272 
273 }  // namespace SkSurfaces
274