Flutter Engine
The Flutter Engine
ReadWritePixelsGraphiteTest.cpp
Go to the documentation of this file.
1/*
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
30#include "tests/Test.h"
31#include "tests/TestUtils.h"
32#include "tools/ToolUtils.h"
36
38
39static 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;
58 case kBGR_101010x_XR_SkColorType: return 10;
59 case kRGBA_10x6_SkColorType: return 10;
60 case kBGRA_10101010_XR_SkColorType: return 10;
61 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 }
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;
90 case kBGR_101010x_XR_SkColorType: return 0;
91 case kRGBA_10x6_SkColorType: return 10;
92 case kBGRA_10101010_XR_SkColorType: return 10;
93 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 }
101}
102
103namespace {
104std::vector<SkIRect> make_long_rect_array(int w, int h) {
105 return {
106 // entire thing
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
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.
174template <typename T> using GraphiteSrcFactory = T(skgpu::graphite::Recorder*, SkPixmap&);
175
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
186static SkAutoPixmapStorage make_ref_data(const SkImageInfo& info, bool forceOpaque) {
188 if (info.alphaType() == kUnknown_SkAlphaType) {
189 result.alloc(info.makeAlphaType(kUnpremul_SkAlphaType));
190 } else {
191 result.alloc(info);
192 }
194 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};
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,
214 0x60FFFFFF,
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>
231 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,
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)) {
273 } else if (readCT == kUnknown_SkColorType) {
275 } else if (readAT == kUnknown_SkAlphaType) {
277 } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
279 } else if (result == Result::kFail) {
280 // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
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(),
287 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
288 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 =
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);
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(),
336 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
337 diffs[0], diffs[1], diffs[2], diffs[3]);
338 });
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());
348 SkPixmap unpremulSrc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
349 srcPixels.addr(),
350 srcPixels.rowBytes());
351
352 unpremulSrc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
353 } 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) {
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(),
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 = {};
404 for (int sat = 0; sat <= kLastEnum_SkAlphaType; ++sat) {
405 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,
414 srcAT,
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 &&
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
441 std::unique_ptr<skgpu::graphite::Recorder> recorder = context->makeRecorder();
442
443 auto src = srcFactory(recorder.get(), srcPixels);
444 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);
459 // 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 ||
462 readCT == kBGR_101010x_XR_SkColorType ||
464 readCT == kBGR_101010x_SkColorType) {
465 continue;
466 }
467 for (const sk_sp<SkColorSpace>& readCS :
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 }
485 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);
492 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
523 reporter,
524 context,
525 testContext,
526 true,
528 using Image = sk_sp<SkImage>;
530 using TextureInfo = skgpu::graphite::TextureInfo;
531
532 auto reader = std::function<GraphiteReadSrcFn<Image>>([context, testContext](
533 const Image& image,
534 const SkIPoint& offset,
535 const SkPixmap& pixels) {
536 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(),
545 if (!context->priv().caps()->isRenderable(texInfo)) {
546 return Result::kExcusedFailure;
547 }
548
549 context->asyncRescaleAndReadPixels(image.get(),
550 pixels.info(),
551 rect,
555 &asyncContext);
556 if (!asyncContext.fCalled) {
557 context->submit();
558 }
559 while (!asyncContext.fCalled) {
560 testContext->tick();
561 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}) {
577 auto factory = std::function<GraphiteSrcFactory<Image>>([&](
579 const SkPixmap& src) {
580 Image image = sk_gpu_test::MakeBackendTextureImage(recorder,
581 src,
583 renderable,
586
587 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
589 recordingInfo.fRecording = recording.get();
590 context->insertRecording(recordingInfo);
591
592 return image;
593 });
594 auto label = SkStringPrintf("Renderable: %d", (int)renderable);
595 graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, label);
596 }
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}
602
604 reporter,
605 context,
606 testContext,
607 true,
610
611 auto reader = std::function<GraphiteReadSrcFn<Surface>>([context, testContext](
612 const Surface& surface,
613 const SkIPoint& offset,
614 const SkPixmap& pixels) {
615 AsyncContext asyncContext;
616 auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
617
618 context->asyncRescaleAndReadPixels(surface.get(),
619 pixels.info(),
620 rect,
624 &asyncContext);
625 if (!asyncContext.fCalled) {
626 context->submit();
627 }
628 while (!asyncContext.fCalled) {
629 testContext->tick();
630 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
645 auto factory = std::function<GraphiteSrcFactory<Surface>>(
646 [&](skgpu::graphite::Recorder* recorder, const SkPixmap& src) {
648 src.info(),
650 /*surfaceProps=*/nullptr);
651 if (surface) {
652 surface->writePixels(src, 0, 0);
653
654 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
656 recordingInfo.fRecording = recording.get();
657 context->insertRecording(recordingInfo);
658 }
659
660 return surface;
661 });
662 graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, {});
663
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}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
reporter
Definition: FontMgrTest.cpp:39
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
kUnpremul_SkAlphaType
std::vector< SkIRect > make_short_rect_array(int w, int h)
std::vector< SkIRect > make_long_rect_array(int w, int h)
static SkAutoPixmapStorage make_ref_data(const SkImageInfo &info, bool forceOpaque)
static constexpr int alpha_channel_bits(SkColorType ct)
static void async_callback(void *c, std::unique_ptr< const SkImage::AsyncReadResult > result)
static constexpr int min_rgb_channel_bits(SkColorType ct)
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixelsGraphite, reporter, context, testContext, true, CtsEnforcement::kNextRelease)
static void graphite_read_pixels_test_driver(skiatest::Reporter *reporter, skgpu::graphite::Context *context, const GraphiteReadPixelTestRules &rules, const std::function< GraphiteSrcFactory< T > > &srcFactory, const std::function< GraphiteReadSrcFn< T > > &read, SkString label)
SkAlphaType
Definition: SkAlphaType.h:26
@ kUnknown_SkAlphaType
uninitialized
Definition: SkAlphaType.h:27
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kLastEnum_SkAlphaType
last valid value
Definition: SkAlphaType.h:31
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kPlus
r = min(s + d, 1)
@ kDstIn
r = d * sa
SkColorType
Definition: SkColorType.h:19
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition: SkColorType.h:50
@ kRGBA_10x6_SkColorType
pixel with 10 used bits (most significant) followed by 6 unused
Definition: SkColorType.h:33
@ kR8_unorm_SkColorType
Definition: SkColorType.h:54
@ kBGR_101010x_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word
Definition: SkColorType.h:30
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kR8G8_unorm_SkColorType
pixel with a uint8_t for red and green
Definition: SkColorType.h:43
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kA16_unorm_SkColorType
pixel with a little endian uint16_t for alpha
Definition: SkColorType.h:48
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGB_101010x_SkColorType
pixel with 10 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:29
@ kLastEnum_SkColorType
last valid value
Definition: SkColorType.h:56
@ kSRGBA_8888_SkColorType
Definition: SkColorType.h:53
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kBGRA_10101010_XR_SkColorType
pixel with 10 bits each for blue, green, red, alpha; in 64-bit word, extended range
Definition: SkColorType.h:32
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
@ kBGRA_1010102_SkColorType
10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:28
@ kA16_float_SkColorType
pixel with a half float for alpha
Definition: SkColorType.h:45
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
@ kRGBA_1010102_SkColorType
10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:27
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
@ kR16G16_unorm_SkColorType
pixel with a little endian uint16_t for red and green
Definition: SkColorType.h:49
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition: SkColorType.h:36
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
@ kR16G16_float_SkColorType
pixel with a half float for red and green
Definition: SkColorType.h:46
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
@ kGray_SkColorChannelFlag
Definition: SkColor.h:243
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
static bool read(SkStream *stream, void *buffer, size_t amount)
static uint32_t SkColorTypeChannelFlags(SkColorType ct)
static bool SkColorTypeIsAlphaOnly(SkColorType ct)
SK_API int SkColorTypeBytesPerPixel(SkColorType ct)
Definition: SkImageInfo.cpp:16
SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct)
Definition: SkImageInfo.cpp:48
static void SkRectMemcpy(void *dst, size_t dstRB, const void *src, size_t srcRB, size_t trimRowBytes, int rowCount)
Definition: SkRectMemcpy.h:16
LoopControlFlowInfo fResult
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
bool ComparePixels(const GrCPixmap &a, const GrCPixmap &b, const float tolRGBA[4], std::function< ComparePixmapsErrorReporter > &error)
Definition: TestUtils.cpp:142
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
constexpr int kH
constexpr int kW
void alloc(const SkImageInfo &)
static bool Equals(const SkColorSpace *, const SkColorSpace *)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeSRGBLinear()
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
SkColorType colorType() const
Definition: SkImage.cpp:152
size_t rowBytes() const
Definition: SkPixmap.h:145
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes) const
Definition: SkPixmap.h:592
const SkImageInfo & info() const
Definition: SkPixmap.h:135
size_t computeByteSize() const
Definition: SkPixmap.h:231
void * writable_addr() const
Definition: SkPixmap.h:483
const void * addr() const
Definition: SkPixmap.h:153
void reset()
Definition: SkPixmap.cpp:32
bool extractSubset(SkPixmap *subset, const SkIRect &area) const
Definition: SkPixmap.cpp:65
bool isEmpty() const
Definition: SkString.h:130
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
T * get() const
Definition: SkRefCnt.h:303
std::unique_ptr< Recorder > makeRecorder(const RecorderOptions &={})
Definition: Context.cpp:132
const Paint & paint
Definition: color_source.cc:38
@ kSuccess
Definition: embedder.h:73
VkSurfaceKHR surface
Definition: main.cc:49
float SkScalar
Definition: extension.cpp:12
glong glong end
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float sat(float r, float g, float b)
Definition: hsl.cpp:51
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
SK_API sk_sp< SkSurface > WrapPixels(const SkImageInfo &imageInfo, void *pixels, size_t rowBytes, const SkSurfaceProps *surfaceProps=nullptr)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
const char * colortype_name(SkColorType ct)
Definition: ToolUtils.cpp:65
const char * alphatype_name(SkAlphaType at)
Definition: ToolUtils.cpp:55
CanvasImage Image
Definition: dart_ui.cc:55
Renderable
Definition: GpuTypes.h:69
Mipmapped
Definition: GpuTypes.h:53
SkScalar w
SkScalar h
#define T
Definition: precompiler.cc:65
SeparatedVector2 offset
Definition: SkRect.h:32
constexpr int32_t x() const
Definition: SkRect.h:141
constexpr int32_t y() const
Definition: SkRect.h:148
bool intersect(const SkIRect &r)
Definition: SkRect.h:513
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition: SkRect.h:535
constexpr int32_t top() const
Definition: SkRect.h:120
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
constexpr SkISize size() const
Definition: SkRect.h:172
constexpr int32_t bottom() const
Definition: SkRect.h:134
constexpr int32_t right() const
Definition: SkRect.h:127
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const
Definition: SkRect.h:300
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
constexpr int32_t left() const
Definition: SkRect.h:113
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466
SkImageInfo makeDimensions(SkISize newSize) const
Definition: SkImageInfo.h:454
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)