blob: d6d5cfaa69b53aa06b48c63deb579c85ac54757e [file] [log] [blame]
Jim Van Verth10314972022-10-26 10:23:16 -04001/*
2 * Copyright 2022 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 "include/core/SkAlphaType.h"
Michael Ludwigfbd683d2023-01-03 10:34:29 -05009#include "include/core/SkCanvas.h"
Jim Van Verth10314972022-10-26 10:23:16 -040010#include "include/core/SkColorSpace.h"
11#include "include/core/SkColorType.h"
12#include "include/core/SkPixmap.h"
13#include "include/core/SkSurface.h"
14#include "include/effects/SkGradientShader.h"
15#include "include/gpu/GpuTypes.h"
16#include "include/gpu/graphite/BackendTexture.h"
17#include "include/gpu/graphite/Context.h"
Kevin Lubickf95da882023-05-12 11:16:12 -040018#include "include/gpu/graphite/Image.h"
Jim Van Verth10314972022-10-26 10:23:16 -040019#include "include/gpu/graphite/Recorder.h"
20#include "include/gpu/graphite/Recording.h"
Kevin Lubick5c93acf2023-05-09 12:11:43 -040021#include "include/gpu/graphite/Surface.h"
Jim Van Verth10314972022-10-26 10:23:16 -040022#include "include/gpu/graphite/TextureInfo.h"
Kevin Lubick406dacd2023-03-23 10:15:46 -040023#include "src/base/SkRectMemcpy.h"
Jim Van Verth10314972022-10-26 10:23:16 -040024#include "src/core/SkAutoPixmapStorage.h"
Brian Osman699841c2023-01-04 10:32:03 -050025#include "src/core/SkImageInfoPriv.h"
Jim Van Verth10314972022-10-26 10:23:16 -040026#include "src/gpu/graphite/Caps.h"
27#include "src/gpu/graphite/ContextPriv.h"
28#include "src/gpu/graphite/RecorderPriv.h"
29#include "src/gpu/graphite/ResourceTypes.h"
30#include "tests/Test.h"
31#include "tests/TestUtils.h"
32#include "tools/ToolUtils.h"
Nicolette Prevost4731ccd2023-09-26 10:24:46 -040033#include "tools/gpu/BackendTextureImageFactory.h"
34#include "tools/gpu/ManagedBackendTexture.h"
Brian Salomonc759bbf2023-12-05 11:11:27 -050035#include "tools/graphite/GraphiteTestContext.h"
Jim Van Verth10314972022-10-26 10:23:16 -040036
Jim Van Verthfa628552023-02-15 10:21:50 -050037using Mipmapped = skgpu::Mipmapped;
38
Jim Van Verth10314972022-10-26 10:23:16 -040039static constexpr int min_rgb_channel_bits(SkColorType ct) {
40 switch (ct) {
41 case kUnknown_SkColorType: return 0;
42 case kAlpha_8_SkColorType: return 0;
43 case kA16_unorm_SkColorType: return 0;
44 case kA16_float_SkColorType: return 0;
45 case kRGB_565_SkColorType: return 5;
46 case kARGB_4444_SkColorType: return 4;
47 case kR8G8_unorm_SkColorType: return 8;
48 case kR16G16_unorm_SkColorType: return 16;
49 case kR16G16_float_SkColorType: return 16;
50 case kRGBA_8888_SkColorType: return 8;
51 case kSRGBA_8888_SkColorType: return 8;
52 case kRGB_888x_SkColorType: return 8;
53 case kBGRA_8888_SkColorType: return 8;
54 case kRGBA_1010102_SkColorType: return 10;
55 case kRGB_101010x_SkColorType: return 10;
56 case kBGRA_1010102_SkColorType: return 10;
57 case kBGR_101010x_SkColorType: return 10;
Aaron Clarkefe37efc2023-02-16 14:40:00 -080058 case kBGR_101010x_XR_SkColorType: return 10;
Brian Osman211d63b2023-09-01 20:39:58 +000059 case kRGBA_10x6_SkColorType: return 10;
Aaron Clarkea0bbf722024-04-08 10:48:15 -070060 case kBGRA_10101010_XR_SkColorType: return 10;
Jim Van Verth10314972022-10-26 10:23:16 -040061 case kGray_8_SkColorType: return 8; // counting gray as "rgb"
62 case kRGBA_F16Norm_SkColorType: return 10; // just counting the mantissa
63 case kRGBA_F16_SkColorType: return 10; // just counting the mantissa
64 case kRGBA_F32_SkColorType: return 23; // just counting the mantissa
65 case kR16G16B16A16_unorm_SkColorType: return 16;
66 case kR8_unorm_SkColorType: return 8;
67 }
68 SkUNREACHABLE;
69}
70
71static constexpr int alpha_channel_bits(SkColorType ct) {
72 switch (ct) {
73 case kUnknown_SkColorType: return 0;
74 case kAlpha_8_SkColorType: return 8;
75 case kA16_unorm_SkColorType: return 16;
76 case kA16_float_SkColorType: return 16;
77 case kRGB_565_SkColorType: return 0;
78 case kARGB_4444_SkColorType: return 4;
79 case kR8G8_unorm_SkColorType: return 0;
80 case kR16G16_unorm_SkColorType: return 0;
81 case kR16G16_float_SkColorType: return 0;
82 case kRGBA_8888_SkColorType: return 8;
83 case kSRGBA_8888_SkColorType: return 8;
84 case kRGB_888x_SkColorType: return 0;
85 case kBGRA_8888_SkColorType: return 8;
86 case kRGBA_1010102_SkColorType: return 2;
87 case kRGB_101010x_SkColorType: return 0;
88 case kBGRA_1010102_SkColorType: return 2;
89 case kBGR_101010x_SkColorType: return 0;
Aaron Clarkefe37efc2023-02-16 14:40:00 -080090 case kBGR_101010x_XR_SkColorType: return 0;
Brian Osman211d63b2023-09-01 20:39:58 +000091 case kRGBA_10x6_SkColorType: return 10;
Aaron Clarkea0bbf722024-04-08 10:48:15 -070092 case kBGRA_10101010_XR_SkColorType: return 10;
Jim Van Verth10314972022-10-26 10:23:16 -040093 case kGray_8_SkColorType: return 0;
94 case kRGBA_F16Norm_SkColorType: return 10; // just counting the mantissa
95 case kRGBA_F16_SkColorType: return 10; // just counting the mantissa
96 case kRGBA_F32_SkColorType: return 23; // just counting the mantissa
97 case kR16G16B16A16_unorm_SkColorType: return 16;
98 case kR8_unorm_SkColorType: return 0;
99 }
100 SkUNREACHABLE;
101}
102
103namespace {
104std::vector<SkIRect> make_long_rect_array(int w, int h) {
105 return {
106 // entire thing
107 SkIRect::MakeWH(w, h),
108 // larger on all sides
109 SkIRect::MakeLTRB(-10, -10, w + 10, h + 10),
110 // fully contained
111 SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
112 // outside top left
113 SkIRect::MakeLTRB(-10, -10, -1, -1),
114 // touching top left corner
115 SkIRect::MakeLTRB(-10, -10, 0, 0),
116 // overlapping top left corner
117 SkIRect::MakeLTRB(-10, -10, w/4, h/4),
118 // overlapping top left and top right corners
119 SkIRect::MakeLTRB(-10, -10, w + 10, h/4),
120 // touching entire top edge
121 SkIRect::MakeLTRB(-10, -10, w + 10, 0),
122 // overlapping top right corner
123 SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
124 // contained in x, overlapping top edge
125 SkIRect::MakeLTRB(w/4, -10, 3*w/4, h/4),
126 // outside top right corner
127 SkIRect::MakeLTRB(w + 1, -10, w + 10, -1),
128 // touching top right corner
129 SkIRect::MakeLTRB(w, -10, w + 10, 0),
130 // overlapping top left and bottom left corners
131 SkIRect::MakeLTRB(-10, -10, w/4, h + 10),
132 // touching entire left edge
133 SkIRect::MakeLTRB(-10, -10, 0, h + 10),
134 // overlapping bottom left corner
135 SkIRect::MakeLTRB(-10, 3*h/4, w/4, h + 10),
136 // contained in y, overlapping left edge
137 SkIRect::MakeLTRB(-10, h/4, w/4, 3*h/4),
138 // outside bottom left corner
139 SkIRect::MakeLTRB(-10, h + 1, -1, h + 10),
140 // touching bottom left corner
141 SkIRect::MakeLTRB(-10, h, 0, h + 10),
142 // overlapping bottom left and bottom right corners
143 SkIRect::MakeLTRB(-10, 3*h/4, w + 10, h + 10),
144 // touching entire left edge
145 SkIRect::MakeLTRB(0, h, w, h + 10),
146 // overlapping bottom right corner
147 SkIRect::MakeLTRB(3*w/4, 3*h/4, w + 10, h + 10),
148 // overlapping top right and bottom right corners
149 SkIRect::MakeLTRB(3*w/4, -10, w + 10, h + 10),
150 };
151}
152
153std::vector<SkIRect> make_short_rect_array(int w, int h) {
154 return {
155 // entire thing
156 SkIRect::MakeWH(w, h),
157 // fully contained
158 SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
159 // overlapping top right corner
160 SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
161 };
162}
163
164struct GraphiteReadPixelTestRules {
165 // Test unpremul sources? We could omit this and detect that creating the source of the read
166 // failed but having it lets us skip generating reference color data.
167 bool fAllowUnpremulSrc = true;
168 // Are reads that are overlapping but not contained by the src bounds expected to succeed?
169 bool fUncontainedRectSucceeds = true;
170};
171
172// Makes a src populated with the pixmap. The src should get its image info (or equivalent) from
173// the pixmap.
Robert Phillips5fa5d592023-03-23 15:08:28 -0400174template <typename T> using GraphiteSrcFactory = T(skgpu::graphite::Recorder*, SkPixmap&);
Jim Van Verth10314972022-10-26 10:23:16 -0400175
176enum class Result {
177 kFail,
178 kSuccess,
179 kExcusedFailure,
180};
181
182// Does a read from the T into the pixmap.
183template <typename T>
184using GraphiteReadSrcFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
185
Jim Van Verth10314972022-10-26 10:23:16 -0400186static SkAutoPixmapStorage make_ref_data(const SkImageInfo& info, bool forceOpaque) {
187 SkAutoPixmapStorage result;
Jim Van Verthbbbbfb12023-08-18 12:12:30 -0400188 if (info.alphaType() == kUnknown_SkAlphaType) {
189 result.alloc(info.makeAlphaType(kUnpremul_SkAlphaType));
190 } else {
191 result.alloc(info);
192 }
193 auto surface = SkSurfaces::WrapPixels(result);
Jim Van Verth10314972022-10-26 10:23:16 -0400194 if (!surface) {
195 return result;
196 }
197
198 SkPoint pts1[] = {{0, 0}, {float(info.width()), float(info.height())}};
199 static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
200 SkPaint paint;
201 paint.setShader(SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkTileMode::kClamp));
202 surface->getCanvas()->drawPaint(paint);
203
204 SkPoint pts2[] = {{float(info.width()), 0}, {0, float(info.height())}};
205 static constexpr SkColor kColors2[] = {SK_ColorBLUE, SK_ColorBLACK};
206 paint.setShader(SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkTileMode::kClamp));
207 paint.setBlendMode(SkBlendMode::kPlus);
208 surface->getCanvas()->drawPaint(paint);
209
210 // If not opaque add some fractional alpha.
211 if (info.alphaType() != kOpaque_SkAlphaType && !forceOpaque) {
212 static constexpr SkColor kColors3[] = {SK_ColorWHITE,
213 SK_ColorWHITE,
214 0x60FFFFFF,
215 SK_ColorWHITE,
216 SK_ColorWHITE};
217 static constexpr SkScalar kPos3[] = {0.f, 0.15f, 0.5f, 0.85f, 1.f};
218 paint.setShader(SkGradientShader::MakeRadial({info.width()/2.f, info.height()/2.f},
219 (info.width() + info.height())/10.f,
220 kColors3, kPos3, 5, SkTileMode::kMirror));
221 paint.setBlendMode(SkBlendMode::kDstIn);
222 surface->getCanvas()->drawPaint(paint);
223 }
224 return result;
225};
226} // anonymous namespace
227
228template <typename T>
229static void graphite_read_pixels_test_driver(skiatest::Reporter* reporter,
Robert Phillips5fa5d592023-03-23 15:08:28 -0400230 skgpu::graphite::Context* context,
Jim Van Verth10314972022-10-26 10:23:16 -0400231 const GraphiteReadPixelTestRules& rules,
232 const std::function<GraphiteSrcFactory<T>>& srcFactory,
233 const std::function<GraphiteReadSrcFn<T>>& read,
234 SkString label) {
235 if (!label.isEmpty()) {
236 // Add space for printing.
237 label.append(" ");
238 }
239 // Separate this out just to give it some line width to breathe. Note 'srcPixels' should have
240 // the same image info as src. We will do a converting readPixels() on it to get the data
241 // to compare with the results of 'read'.
242 auto runTest = [&](const T& src,
243 const SkPixmap& srcPixels,
244 const SkImageInfo& readInfo,
245 SkIPoint offset) {
246 const bool csConversion =
247 !SkColorSpace::Equals(readInfo.colorSpace(), srcPixels.info().colorSpace());
248 const auto readCT = readInfo.colorType();
249 const auto readAT = readInfo.alphaType();
250 const auto srcCT = srcPixels.info().colorType();
251 const auto srcAT = srcPixels.info().alphaType();
252 const auto rect = SkIRect::MakeWH(readInfo.width(), readInfo.height()).makeOffset(offset);
253 const auto surfBounds = SkIRect::MakeWH(srcPixels.width(), srcPixels.height());
254 const size_t readBpp = SkColorTypeBytesPerPixel(readCT);
255
256 // Make the row bytes in the dst be loose for extra stress.
257 const size_t dstRB = readBpp * readInfo.width() + 10 * readBpp;
258 // This will make the last row tight.
259 const size_t dstSize = readInfo.computeByteSize(dstRB);
260 std::unique_ptr<char[]> dstData(new char[dstSize]);
261 SkPixmap dstPixels(readInfo, dstData.get(), dstRB);
262 // Initialize with an arbitrary value for each byte. Later we will check that only the
263 // correct part of the destination gets overwritten by 'read'.
264 static constexpr auto kInitialByte = static_cast<char>(0x1B);
265 std::fill_n(static_cast<char*>(dstPixels.writable_addr()),
266 dstPixels.computeByteSize(),
267 kInitialByte);
268
269 const Result result = read(src, offset, dstPixels);
270
271 if (!SkIRect::Intersects(rect, surfBounds)) {
272 REPORTER_ASSERT(reporter, result != Result::kSuccess);
273 } else if (readCT == kUnknown_SkColorType) {
274 REPORTER_ASSERT(reporter, result != Result::kSuccess);
Jim Van Verth1272b522022-11-02 10:57:43 -0400275 } else if (readAT == kUnknown_SkAlphaType) {
Jim Van Verth10314972022-10-26 10:23:16 -0400276 REPORTER_ASSERT(reporter, result != Result::kSuccess);
277 } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
278 REPORTER_ASSERT(reporter, result != Result::kSuccess);
279 } else if (result == Result::kFail) {
280 // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
Jim Van Verthd853295b2022-11-01 15:48:15 -0400281 ERRORF(reporter,
282 "Read failed. %sSrc CT: %s, Src AT: %s Read CT: %s, Read AT: %s, "
283 "Rect [%d, %d, %d, %d], CS conversion: %d\n",
284 label.c_str(),
285 ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
286 ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
287 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
Jim Van Verth10314972022-10-26 10:23:16 -0400288 return result;
289 }
290
291 bool guardOk = true;
292 auto guardCheck = [](char x) { return x == kInitialByte; };
293
294 // Considering the rect we tried to read and the surface bounds figure out which pixels in
295 // both src and dst space should actually have been read and written.
296 SkIRect srcReadRect;
297 if (result == Result::kSuccess && srcReadRect.intersect(surfBounds, rect)) {
298 SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
299
300 const bool lumConversion =
301 !(SkColorTypeChannelFlags(srcCT) & kGray_SkColorChannelFlag) &&
302 (SkColorTypeChannelFlags(readCT) & kGray_SkColorChannelFlag);
303 // A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
304 // difference. Note that sometimes read back on GPU can be lossy even when there no
305 // conversion at all because GPU->CPU read may go to a lower bit depth format and then
306 // be promoted back to the original type. For example, GL ES cannot read to 1010102, so
307 // we go through 8888.
308 float numer = (lumConversion || csConversion) ? 3.f : 2.f;
309 // Allow some extra tolerance if unpremuling.
310 if (srcAT == kPremul_SkAlphaType && readAT == kUnpremul_SkAlphaType) {
311 numer += 1;
312 }
313 int rgbBits = std::min({min_rgb_channel_bits(readCT), min_rgb_channel_bits(srcCT), 8});
314 float tol = numer / (1 << rgbBits);
315 float alphaTol = 0;
316 if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
317 // Alpha can also get squashed down to 8 bits going through an intermediate
318 // color format.
319 const int alphaBits = std::min({alpha_channel_bits(readCT),
320 alpha_channel_bits(srcCT),
321 8});
322 alphaTol = 2.f / (1 << alphaBits);
323 }
324
325 const float tols[4] = {tol, tol, tol, alphaTol};
326 auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
327 const float diffs[4]) {
328 SkASSERT(x >= 0 && y >= 0);
329 ERRORF(reporter,
330 "%sSrc CT: %s, Src AT: %s, Read CT: %s, Read AT: %s, Rect [%d, %d, %d, %d]"
331 ", CS conversion: %d\n"
332 "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
333 label.c_str(),
334 ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
335 ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
336 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
337 diffs[0], diffs[1], diffs[2], diffs[3]);
338 });
339 SkAutoPixmapStorage ref;
340 SkImageInfo refInfo = readInfo.makeDimensions(dstWriteRect.size());
341 ref.alloc(refInfo);
342 if (readAT == kUnknown_SkAlphaType) {
343 // Do a spoofed read where src and dst alpha type are both kUnpremul. This will
344 // allow SkPixmap readPixels to succeed and won't do any alpha type conversion.
345 SkPixmap unpremulRef(refInfo.makeAlphaType(kUnpremul_SkAlphaType),
346 ref.addr(),
347 ref.rowBytes());
Jim Van Verthd853295b2022-11-01 15:48:15 -0400348 SkPixmap unpremulSrc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
Jim Van Verth10314972022-10-26 10:23:16 -0400349 srcPixels.addr(),
350 srcPixels.rowBytes());
351
Jim Van Verthd853295b2022-11-01 15:48:15 -0400352 unpremulSrc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
Jim Van Verth10314972022-10-26 10:23:16 -0400353 } else {
354 srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
355 }
356 // This is the part of dstPixels that should have been updated.
357 SkPixmap actual;
358 SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
359 ComparePixels(ref, actual, tols, error);
360
361 const auto* v = dstData.get();
362 const auto* end = dstData.get() + dstSize;
363 guardOk = std::all_of(v, v + dstWriteRect.top() * dstPixels.rowBytes(), guardCheck);
364 v += dstWriteRect.top() * dstPixels.rowBytes();
365 for (int y = dstWriteRect.top(); y < dstWriteRect.bottom(); ++y) {
366 guardOk |= std::all_of(v, v + dstWriteRect.left() * readBpp, guardCheck);
367 auto pad = v + dstWriteRect.right() * readBpp;
368 auto rowEnd = std::min(end, v + dstPixels.rowBytes());
369 // min protects against reading past the end of the tight last row.
370 guardOk |= std::all_of(pad, rowEnd, guardCheck);
371 v = rowEnd;
372 }
373 guardOk |= std::all_of(v, end, guardCheck);
374 } else {
375 guardOk = std::all_of(dstData.get(), dstData.get() + dstSize, guardCheck);
376 }
377 if (!guardOk) {
378 ERRORF(reporter,
379 "Result pixels modified result outside read rect [%d, %d, %d, %d]. "
380 "%sSrc CT: %s, Read CT: %s, CS conversion: %d",
381 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, label.c_str(),
382 ToolUtils::colortype_name(srcCT), ToolUtils::colortype_name(readCT),
383 csConversion);
384 }
385 return result;
386 };
387
388 static constexpr int kW = 16;
389 static constexpr int kH = 16;
390
391 const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
392 const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
393
394 // We ensure we use the long array once per src and read color type and otherwise use the
395 // short array to improve test run time.
396 // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
397 // equivalent. Just ensure each redundant AT is tested once with each CT (src and read).
398 // Similarly, alpha-only color types behave the same for all alpha types so just test premul
399 // after one iter.
400 // We consider a src or read CT thoroughly tested once it has run through the long rect array
401 // and full complement of alpha types with one successful read in the loop.
402 std::array<bool, kLastEnum_SkColorType + 1> srcCTTestedThoroughly = {},
403 readCTTestedThoroughly = {};
Jim Van Verthd853295b2022-11-01 15:48:15 -0400404 for (int sat = 0; sat <= kLastEnum_SkAlphaType; ++sat) {
Jim Van Verth10314972022-10-26 10:23:16 -0400405 const auto srcAT = static_cast<SkAlphaType>(sat);
406 if (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc) {
407 continue;
408 }
409 for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
410 const auto srcCT = static_cast<SkColorType>(sct);
411 // We always make our ref data as F32
412 auto refInfo = SkImageInfo::Make(kW, kH,
413 kRGBA_F32_SkColorType,
414 srcAT,
415 SkColorSpace::MakeSRGB());
416 // 1010102 formats have an issue where it's easy to make a resulting
417 // color where r, g, or b is greater than a. CPU/GPU differ in whether the stored color
418 // channels are clipped to the alpha value. CPU clips but GPU does not.
419 // Note that we only currently use srcCT for the 1010102 workaround. If we remove this
420 // we can also put the ref data setup above the srcCT loop.
421 bool forceOpaque = srcAT == kPremul_SkAlphaType &&
422 (srcCT == kRGBA_1010102_SkColorType || srcCT == kBGRA_1010102_SkColorType);
423
424 SkAutoPixmapStorage refPixels = make_ref_data(refInfo, forceOpaque);
425 // Convert the ref data to our desired src color type.
426 const auto srcInfo = SkImageInfo::Make(kW, kH, srcCT, srcAT, SkColorSpace::MakeSRGB());
427 SkAutoPixmapStorage srcPixels;
428 srcPixels.alloc(srcInfo);
429 {
430 SkPixmap readPixmap = srcPixels;
431 // Spoof the alpha type to kUnpremul so the read will succeed without doing any
432 // conversion (because we made our surface also use kUnpremul).
433 if (srcAT == kUnknown_SkAlphaType) {
434 readPixmap.reset(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
435 srcPixels.addr(),
436 srcPixels.rowBytes());
437 }
438 refPixels.readPixels(readPixmap, 0, 0);
439 }
440
Robert Phillips5fa5d592023-03-23 15:08:28 -0400441 std::unique_ptr<skgpu::graphite::Recorder> recorder = context->makeRecorder();
442
443 auto src = srcFactory(recorder.get(), srcPixels);
Jim Van Verth10314972022-10-26 10:23:16 -0400444 if (!src) {
445 continue;
446 }
447 if (SkColorTypeIsAlwaysOpaque(srcCT) && srcCTTestedThoroughly[srcCT] &&
448 (kPremul_SkAlphaType == srcAT || kUnpremul_SkAlphaType == srcAT)) {
449 continue;
450 }
451 if (SkColorTypeIsAlphaOnly(srcCT) && srcCTTestedThoroughly[srcCT] &&
452 (kUnpremul_SkAlphaType == srcAT ||
453 kOpaque_SkAlphaType == srcAT ||
454 kUnknown_SkAlphaType == srcAT)) {
455 continue;
456 }
457 for (int rct = 0; rct <= kLastEnum_SkColorType; ++rct) {
458 const auto readCT = static_cast<SkColorType>(rct);
Jim Van Verthd853295b2022-11-01 15:48:15 -0400459 // ComparePixels will end up converting these types to kUnknown
460 // because there's no corresponding GrColorType, and hence it will fail
461 if (readCT == kRGB_101010x_SkColorType ||
Aaron Clarkefe37efc2023-02-16 14:40:00 -0800462 readCT == kBGR_101010x_XR_SkColorType ||
Aaron Clarkea0bbf722024-04-08 10:48:15 -0700463 readCT == kBGRA_10101010_XR_SkColorType ||
Jim Van Verthd853295b2022-11-01 15:48:15 -0400464 readCT == kBGR_101010x_SkColorType) {
465 continue;
466 }
Jim Van Verth10314972022-10-26 10:23:16 -0400467 for (const sk_sp<SkColorSpace>& readCS :
468 {SkColorSpace::MakeSRGB(), SkColorSpace::MakeSRGBLinear()}) {
469 for (int at = 0; at <= kLastEnum_SkAlphaType; ++at) {
470 const auto readAT = static_cast<SkAlphaType>(at);
471 if (srcAT != kOpaque_SkAlphaType && readAT == kOpaque_SkAlphaType) {
472 // This doesn't make sense.
473 continue;
474 }
475 if (SkColorTypeIsAlwaysOpaque(readCT) && readCTTestedThoroughly[readCT] &&
476 (kPremul_SkAlphaType == readAT || kUnpremul_SkAlphaType == readAT)) {
477 continue;
478 }
479 if (SkColorTypeIsAlphaOnly(readCT) && readCTTestedThoroughly[readCT] &&
480 (kUnpremul_SkAlphaType == readAT ||
481 kOpaque_SkAlphaType == readAT ||
482 kUnknown_SkAlphaType == readAT)) {
483 continue;
484 }
Jim Van Verth10314972022-10-26 10:23:16 -0400485 const auto& rects =
486 srcCTTestedThoroughly[sct] && readCTTestedThoroughly[rct]
487 ? shortRectArray
488 : longRectArray;
489 for (const auto& rect : rects) {
490 const auto readInfo = SkImageInfo::Make(rect.width(), rect.height(),
491 readCT, readAT, readCS);
Jim Van Verth10314972022-10-26 10:23:16 -0400492 const SkIPoint offset = rect.topLeft();
493 Result r = runTest(src, srcPixels, readInfo, offset);
494 if (r == Result::kSuccess) {
495 srcCTTestedThoroughly[sct] = true;
496 readCTTestedThoroughly[rct] = true;
497 }
498 }
499 }
500 }
501 }
502 }
503 }
504}
505
506namespace {
507struct AsyncContext {
508 bool fCalled = false;
509 std::unique_ptr<const SkImage::AsyncReadResult> fResult;
510};
511} // anonymous namespace
512
513// Making this a lambda in the test functions caused:
514// "error: cannot compile this forwarded non-trivially copyable parameter yet"
515// on x86/Win/Clang bot, referring to 'result'.
516static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
517 auto context = static_cast<AsyncContext*>(c);
518 context->fResult = std::move(result);
519 context->fCalled = true;
520};
521
Brian Salomonc759bbf2023-12-05 11:11:27 -0500522DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixelsGraphite,
523 reporter,
524 context,
525 testContext,
526 true,
527 CtsEnforcement::kNextRelease) {
Jim Van Verth10314972022-10-26 10:23:16 -0400528 using Image = sk_sp<SkImage>;
Jim Van Verthd8d33412023-03-15 14:41:28 -0400529 using Renderable = skgpu::Renderable;
Jim Van Verth10314972022-10-26 10:23:16 -0400530 using TextureInfo = skgpu::graphite::TextureInfo;
531
Brian Salomonc759bbf2023-12-05 11:11:27 -0500532 auto reader = std::function<GraphiteReadSrcFn<Image>>([context, testContext](
533 const Image& image,
534 const SkIPoint& offset,
535 const SkPixmap& pixels) {
Jim Van Verth10314972022-10-26 10:23:16 -0400536 AsyncContext asyncContext;
537 auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
538 // The GPU implementation is based on rendering and will fail for non-renderable color
539 // types.
540 TextureInfo texInfo = context->priv().caps()->getDefaultSampledTextureInfo(
541 image->colorType(),
Jim Van Verthfa628552023-02-15 10:21:50 -0500542 Mipmapped::kNo,
Jim Van Verth10314972022-10-26 10:23:16 -0400543 skgpu::Protected::kNo,
544 Renderable::kYes);
545 if (!context->priv().caps()->isRenderable(texInfo)) {
546 return Result::kExcusedFailure;
547 }
548
Jim Van Verth6aaef9c2023-07-06 10:22:01 -0400549 context->asyncRescaleAndReadPixels(image.get(),
550 pixels.info(),
551 rect,
552 SkImage::RescaleGamma::kSrc,
553 SkImage::RescaleMode::kRepeatedLinear,
554 async_callback,
555 &asyncContext);
Jim Van Verth10314972022-10-26 10:23:16 -0400556 if (!asyncContext.fCalled) {
557 context->submit();
558 }
559 while (!asyncContext.fCalled) {
Brian Salomonc759bbf2023-12-05 11:11:27 -0500560 testContext->tick();
Jim Van Verth10314972022-10-26 10:23:16 -0400561 context->checkAsyncWorkCompletion();
562 }
563 if (!asyncContext.fResult) {
564 return Result::kFail;
565 }
566 SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
567 asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
568 pixels.height());
569 return Result::kSuccess;
570 });
571
572 GraphiteReadPixelTestRules rules;
573 rules.fAllowUnpremulSrc = true;
574 rules.fUncontainedRectSucceeds = false;
575
576 for (auto renderable : {Renderable::kNo, Renderable::kYes}) {
Robert Phillips5fa5d592023-03-23 15:08:28 -0400577 auto factory = std::function<GraphiteSrcFactory<Image>>([&](
578 skgpu::graphite::Recorder* recorder,
579 const SkPixmap& src) {
Nicolette Prevost4731ccd2023-09-26 10:24:46 -0400580 Image image = sk_gpu_test::MakeBackendTextureImage(recorder,
581 src,
582 Mipmapped::kNo,
583 renderable,
584 skgpu::Origin::kTopLeft,
585 skgpu::Protected::kNo);
Jim Van Verth10314972022-10-26 10:23:16 -0400586
587 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
588 skgpu::graphite::InsertRecordingInfo recordingInfo;
589 recordingInfo.fRecording = recording.get();
590 context->insertRecording(recordingInfo);
591
592 return image;
593 });
594 auto label = SkStringPrintf("Renderable: %d", (int)renderable);
Robert Phillips5fa5d592023-03-23 15:08:28 -0400595 graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, label);
Jim Van Verth10314972022-10-26 10:23:16 -0400596 }
597
598 // It's possible that we've created an Image using the factory, but then don't try to do
599 // readPixels on it, leaving a hanging command buffer. So we submit here to clean up.
600 context->submit();
601}
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400602
Brian Salomonc759bbf2023-12-05 11:11:27 -0500603DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixelsGraphite,
604 reporter,
605 context,
606 testContext,
607 true,
608 CtsEnforcement::kNextRelease) {
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400609 using Surface = sk_sp<SkSurface>;
610
Brian Salomonc759bbf2023-12-05 11:11:27 -0500611 auto reader = std::function<GraphiteReadSrcFn<Surface>>([context, testContext](
612 const Surface& surface,
613 const SkIPoint& offset,
614 const SkPixmap& pixels) {
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400615 AsyncContext asyncContext;
616 auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
617
Jim Van Verth6aaef9c2023-07-06 10:22:01 -0400618 context->asyncRescaleAndReadPixels(surface.get(),
619 pixels.info(),
620 rect,
621 SkImage::RescaleGamma::kSrc,
622 SkImage::RescaleMode::kRepeatedLinear,
623 async_callback,
624 &asyncContext);
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400625 if (!asyncContext.fCalled) {
626 context->submit();
627 }
628 while (!asyncContext.fCalled) {
Brian Salomonc759bbf2023-12-05 11:11:27 -0500629 testContext->tick();
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400630 context->checkAsyncWorkCompletion();
631 }
632 if (!asyncContext.fResult) {
633 return Result::kFail;
634 }
635 SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
636 asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
637 pixels.height());
638 return Result::kSuccess;
639 });
640
641 GraphiteReadPixelTestRules rules;
642 rules.fAllowUnpremulSrc = true;
643 rules.fUncontainedRectSucceeds = false;
644
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400645 auto factory = std::function<GraphiteSrcFactory<Surface>>(
646 [&](skgpu::graphite::Recorder* recorder, const SkPixmap& src) {
647 Surface surface = SkSurfaces::RenderTarget(recorder,
648 src.info(),
649 Mipmapped::kNo,
650 /*surfaceProps=*/nullptr);
651 if (surface) {
652 surface->writePixels(src, 0, 0);
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400653
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400654 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
655 skgpu::graphite::InsertRecordingInfo recordingInfo;
656 recordingInfo.fRecording = recording.get();
657 context->insertRecording(recordingInfo);
658 }
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400659
Kevin Lubick5c93acf2023-05-09 12:11:43 -0400660 return surface;
661 });
Robert Phillips5fa5d592023-03-23 15:08:28 -0400662 graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, {});
Jim Van Verth35ab5b42022-10-31 12:18:15 -0400663
664 // It's possible that we've created an Image using the factory, but then don't try to do
665 // readPixels on it, leaving a hanging command buffer. So we submit here to clean up.
666 context->submit();
667}