xref: /aosp_15_r20/external/skia/src/gpu/graphite/Image_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/Image_Graphite.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkSurface.h"
14 #include "include/gpu/graphite/Image.h"
15 #include "include/gpu/graphite/Recorder.h"
16 #include "include/gpu/graphite/Surface.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/Log.h"
21 #include "src/gpu/graphite/RecorderPriv.h"
22 #include "src/gpu/graphite/ResourceProvider.h"
23 #include "src/gpu/graphite/Texture.h"
24 #include "src/gpu/graphite/TextureUtils.h"
25 #include "src/gpu/graphite/task/CopyTask.h"
26 
27 #if defined(GPU_TEST_UTILS)
28 #include "include/gpu/graphite/Context.h"
29 #include "src/gpu/graphite/ContextPriv.h"
30 #endif
31 
32 namespace skgpu::graphite {
33 
34 // Graphite does not cache based on the image's unique ID so always request a new one.
Image(TextureProxyView view,const SkColorInfo & info)35 Image::Image(TextureProxyView view,
36              const SkColorInfo& info)
37     : Image_Base(SkImageInfo::Make(view.proxy()->dimensions(), info), kNeedNewImageUniqueID)
38     , fTextureProxyView(std::move(view)) {}
39 
40 Image::~Image() = default;
41 
WrapDevice(sk_sp<Device> device)42 sk_sp<Image> Image::WrapDevice(sk_sp<Device> device) {
43     TextureProxyView proxy = device->readSurfaceView();
44     if (!proxy) {
45         return nullptr;
46     }
47     // NOTE: If the device was created with an approx backing fit, its SkImageInfo reports the
48     // logical dimensions, but its proxy has the approximate fit. These larger dimensions are
49     // propagated to the SkImageInfo of this image view.
50     sk_sp<Image> image = sk_make_sp<Image>(std::move(proxy),
51                                            device->imageInfo().colorInfo());
52     image->linkDevice(std::move(device));
53     return image;
54 }
55 
Copy(Recorder * recorder,const TextureProxyView & srcView,const SkColorInfo & srcColorInfo,const SkIRect & subset,Budgeted budgeted,Mipmapped mipmapped,SkBackingFit backingFit,std::string_view label)56 sk_sp<Image> Image::Copy(Recorder* recorder,
57                          const TextureProxyView& srcView,
58                          const SkColorInfo& srcColorInfo,
59                          const SkIRect& subset,
60                          Budgeted budgeted,
61                          Mipmapped mipmapped,
62                          SkBackingFit backingFit,
63                          std::string_view label) {
64     SkASSERT(!(mipmapped == Mipmapped::kYes && backingFit == SkBackingFit::kApprox));
65     if (!srcView) {
66         return nullptr;
67     }
68 
69     SkASSERT(srcView.proxy()->isFullyLazy() ||
70              SkIRect::MakeSize(srcView.proxy()->dimensions()).contains(subset));
71 
72     if (!recorder->priv().caps()->supportsReadPixels(srcView.proxy()->textureInfo())) {
73         if (!recorder->priv().caps()->isTexturable(srcView.proxy()->textureInfo())) {
74             // The texture is not blittable nor texturable so copying cannot be done.
75             return nullptr;
76         }
77         // Copy-as-draw
78         sk_sp<Image> srcImage(new Image(srcView, srcColorInfo));
79         return CopyAsDraw(recorder, srcImage.get(), subset, srcColorInfo,
80                           budgeted, mipmapped, backingFit, std::move(label));
81     }
82 
83 
84     skgpu::graphite::TextureInfo textureInfo =
85             recorder->priv().caps()->getTextureInfoForSampledCopy(srcView.proxy()->textureInfo(),
86                                                                   mipmapped);
87 
88     sk_sp<TextureProxy> dst = TextureProxy::Make(
89             recorder->priv().caps(),
90             recorder->priv().resourceProvider(),
91             backingFit == SkBackingFit::kApprox ? GetApproxSize(subset.size()) : subset.size(),
92             textureInfo,
93             std::move(label),
94             budgeted);
95     if (!dst) {
96         return nullptr;
97     }
98 
99     auto copyTask = CopyTextureToTextureTask::Make(srcView.refProxy(), subset, dst, {0, 0});
100     if (!copyTask) {
101         return nullptr;
102     }
103 
104     recorder->priv().add(std::move(copyTask));
105 
106     if (mipmapped == Mipmapped::kYes) {
107         if (!GenerateMipmaps(recorder, dst, srcColorInfo)) {
108             SKGPU_LOG_W("Image::Copy failed to generate mipmaps");
109             return nullptr;
110         }
111     }
112 
113     return sk_sp<Image>(new Image({std::move(dst), srcView.swizzle()}, srcColorInfo));
114 }
115 
textureSize() const116 size_t Image::textureSize() const {
117     if (!fTextureProxyView.proxy()) {
118         return 0;
119     }
120 
121     if (!fTextureProxyView.proxy()->texture()) {
122         return fTextureProxyView.proxy()->uninstantiatedGpuMemorySize();
123     }
124 
125     return fTextureProxyView.proxy()->texture()->gpuMemorySize();
126 }
127 
copyImage(Recorder * recorder,const SkIRect & subset,Budgeted budgeted,Mipmapped mipmapped,SkBackingFit backingFit,std::string_view label) const128 sk_sp<Image> Image::copyImage(Recorder* recorder,
129                               const SkIRect& subset,
130                               Budgeted budgeted,
131                               Mipmapped mipmapped,
132                               SkBackingFit backingFit,
133                               std::string_view label) const {
134     this->notifyInUse(recorder, /*drawContext=*/nullptr);
135     return Image::Copy(recorder, fTextureProxyView, this->imageInfo().colorInfo(),
136                        subset, budgeted, mipmapped, backingFit, std::move(label));
137 }
138 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const139 sk_sp<SkImage> Image::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
140     sk_sp<Image> view = sk_make_sp<Image>(fTextureProxyView,
141                                           this->imageInfo().colorInfo()
142                                                            .makeColorSpace(std::move(newCS)));
143     // The new Image object shares the same texture proxy, so it should also share linked Devices
144     view->linkDevices(this);
145     return view;
146 }
147 
148 #if defined(GPU_TEST_UTILS)
readPixelsGraphite(Recorder * recorder,const SkPixmap & dst,int srcX,int srcY) const149 bool Image::readPixelsGraphite(Recorder* recorder, const SkPixmap& dst, int srcX, int srcY) const {
150     if (Context* context = recorder->priv().context()) {
151         // Add all previous commands generated to the command buffer.
152         // If the client snaps later they'll only get post-read commands in their Recording,
153         // but since they're doing a readPixels in the middle that shouldn't be unexpected.
154         std::unique_ptr<Recording> recording = recorder->snap();
155         if (!recording) {
156             return false;
157         }
158         InsertRecordingInfo info;
159         info.fRecording = recording.get();
160         if (!context->insertRecording(info)) {
161             return false;
162         }
163         return context->priv().readPixels(dst,
164                                           fTextureProxyView.proxy(),
165                                           this->imageInfo(),
166                                           srcX,
167                                           srcY);
168     }
169     return false;
170 }
171 #endif
172 
173 } // namespace skgpu::graphite
174