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