1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 Google LLC.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
9cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
10cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
11cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h"
12cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
13cb93a386Sopenharmony_ci#include "src/core/SkAutoPixmapStorage.h"
14cb93a386Sopenharmony_ci#include "src/core/SkConvertPixels.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrImageInfo.h"
17cb93a386Sopenharmony_ci#include "src/gpu/SurfaceContext.h"
18cb93a386Sopenharmony_ci#include "src/gpu/SurfaceFillContext.h"
19cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
20cb93a386Sopenharmony_ci#include "tests/Test.h"
21cb93a386Sopenharmony_ci#include "tests/TestUtils.h"
22cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
23cb93a386Sopenharmony_ci#include "tools/gpu/BackendSurfaceFactory.h"
24cb93a386Sopenharmony_ci#include "tools/gpu/BackendTextureImageFactory.h"
25cb93a386Sopenharmony_ci#include "tools/gpu/GrContextFactory.h"
26cb93a386Sopenharmony_ci#include "tools/gpu/ProxyUtils.h"
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci#include <initializer_list>
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_cistatic constexpr int min_rgb_channel_bits(SkColorType ct) {
31cb93a386Sopenharmony_ci    switch (ct) {
32cb93a386Sopenharmony_ci        case kUnknown_SkColorType:            return 0;
33cb93a386Sopenharmony_ci        case kAlpha_8_SkColorType:            return 0;
34cb93a386Sopenharmony_ci        case kA16_unorm_SkColorType:          return 0;
35cb93a386Sopenharmony_ci        case kA16_float_SkColorType:          return 0;
36cb93a386Sopenharmony_ci        case kRGB_565_SkColorType:            return 5;
37cb93a386Sopenharmony_ci        case kARGB_4444_SkColorType:          return 4;
38cb93a386Sopenharmony_ci        case kR8G8_unorm_SkColorType:         return 8;
39cb93a386Sopenharmony_ci        case kR16G16_unorm_SkColorType:       return 16;
40cb93a386Sopenharmony_ci        case kR16G16_float_SkColorType:       return 16;
41cb93a386Sopenharmony_ci        case kRGBA_8888_SkColorType:          return 8;
42cb93a386Sopenharmony_ci        case kSRGBA_8888_SkColorType:         return 8;
43cb93a386Sopenharmony_ci        case kRGB_888x_SkColorType:           return 8;
44cb93a386Sopenharmony_ci        case kBGRA_8888_SkColorType:          return 8;
45cb93a386Sopenharmony_ci        case kRGBA_1010102_SkColorType:       return 10;
46cb93a386Sopenharmony_ci        case kRGB_101010x_SkColorType:        return 10;
47cb93a386Sopenharmony_ci        case kBGRA_1010102_SkColorType:       return 10;
48cb93a386Sopenharmony_ci        case kBGR_101010x_SkColorType:        return 10;
49cb93a386Sopenharmony_ci        case kGray_8_SkColorType:             return 8;   // counting gray as "rgb"
50cb93a386Sopenharmony_ci        case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
51cb93a386Sopenharmony_ci        case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
52cb93a386Sopenharmony_ci        case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
53cb93a386Sopenharmony_ci        case kR16G16B16A16_unorm_SkColorType: return 16;
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci    SkUNREACHABLE;
56cb93a386Sopenharmony_ci}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cistatic constexpr int alpha_channel_bits(SkColorType ct) {
59cb93a386Sopenharmony_ci    switch (ct) {
60cb93a386Sopenharmony_ci        case kUnknown_SkColorType:            return 0;
61cb93a386Sopenharmony_ci        case kAlpha_8_SkColorType:            return 8;
62cb93a386Sopenharmony_ci        case kA16_unorm_SkColorType:          return 16;
63cb93a386Sopenharmony_ci        case kA16_float_SkColorType:          return 16;
64cb93a386Sopenharmony_ci        case kRGB_565_SkColorType:            return 0;
65cb93a386Sopenharmony_ci        case kARGB_4444_SkColorType:          return 4;
66cb93a386Sopenharmony_ci        case kR8G8_unorm_SkColorType:         return 0;
67cb93a386Sopenharmony_ci        case kR16G16_unorm_SkColorType:       return 0;
68cb93a386Sopenharmony_ci        case kR16G16_float_SkColorType:       return 0;
69cb93a386Sopenharmony_ci        case kRGBA_8888_SkColorType:          return 8;
70cb93a386Sopenharmony_ci        case kSRGBA_8888_SkColorType:         return 8;
71cb93a386Sopenharmony_ci        case kRGB_888x_SkColorType:           return 0;
72cb93a386Sopenharmony_ci        case kBGRA_8888_SkColorType:          return 8;
73cb93a386Sopenharmony_ci        case kRGBA_1010102_SkColorType:       return 2;
74cb93a386Sopenharmony_ci        case kRGB_101010x_SkColorType:        return 0;
75cb93a386Sopenharmony_ci        case kBGRA_1010102_SkColorType:       return 2;
76cb93a386Sopenharmony_ci        case kBGR_101010x_SkColorType:        return 0;
77cb93a386Sopenharmony_ci        case kGray_8_SkColorType:             return 0;
78cb93a386Sopenharmony_ci        case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
79cb93a386Sopenharmony_ci        case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
80cb93a386Sopenharmony_ci        case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
81cb93a386Sopenharmony_ci        case kR16G16B16A16_unorm_SkColorType: return 16;
82cb93a386Sopenharmony_ci    }
83cb93a386Sopenharmony_ci    SkUNREACHABLE;
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_cistd::vector<SkIRect> make_long_rect_array(int w, int h) {
87cb93a386Sopenharmony_ci    return {
88cb93a386Sopenharmony_ci            // entire thing
89cb93a386Sopenharmony_ci            SkIRect::MakeWH(w, h),
90cb93a386Sopenharmony_ci            // larger on all sides
91cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, w + 10, h + 10),
92cb93a386Sopenharmony_ci            // fully contained
93cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
94cb93a386Sopenharmony_ci            // outside top left
95cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, -1, -1),
96cb93a386Sopenharmony_ci            // touching top left corner
97cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, 0, 0),
98cb93a386Sopenharmony_ci            // overlapping top left corner
99cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, w/4, h/4),
100cb93a386Sopenharmony_ci            // overlapping top left and top right corners
101cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, w + 10, h/4),
102cb93a386Sopenharmony_ci            // touching entire top edge
103cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, w + 10, 0),
104cb93a386Sopenharmony_ci            // overlapping top right corner
105cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
106cb93a386Sopenharmony_ci            // contained in x, overlapping top edge
107cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(w/4, -10, 3*w/4, h/4),
108cb93a386Sopenharmony_ci            // outside top right corner
109cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(w + 1, -10, w + 10, -1),
110cb93a386Sopenharmony_ci            // touching top right corner
111cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(w, -10, w + 10, 0),
112cb93a386Sopenharmony_ci            // overlapping top left and bottom left corners
113cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, w/4, h + 10),
114cb93a386Sopenharmony_ci            // touching entire left edge
115cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, -10, 0, h + 10),
116cb93a386Sopenharmony_ci            // overlapping bottom left corner
117cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, 3*h/4, w/4, h + 10),
118cb93a386Sopenharmony_ci            // contained in y, overlapping left edge
119cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, h/4, w/4, 3*h/4),
120cb93a386Sopenharmony_ci            // outside bottom left corner
121cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, h + 1, -1, h + 10),
122cb93a386Sopenharmony_ci            // touching bottom left corner
123cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, h, 0, h + 10),
124cb93a386Sopenharmony_ci            // overlapping bottom left and bottom right corners
125cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(-10, 3*h/4, w + 10, h + 10),
126cb93a386Sopenharmony_ci            // touching entire left edge
127cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(0, h, w, h + 10),
128cb93a386Sopenharmony_ci            // overlapping bottom right corner
129cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(3*w/4, 3*h/4, w + 10, h + 10),
130cb93a386Sopenharmony_ci            // overlapping top right and bottom right corners
131cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(3*w/4, -10, w + 10, h + 10),
132cb93a386Sopenharmony_ci    };
133cb93a386Sopenharmony_ci}
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_cistd::vector<SkIRect> make_short_rect_array(int w, int h) {
136cb93a386Sopenharmony_ci    return {
137cb93a386Sopenharmony_ci            // entire thing
138cb93a386Sopenharmony_ci            SkIRect::MakeWH(w, h),
139cb93a386Sopenharmony_ci            // fully contained
140cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
141cb93a386Sopenharmony_ci            // overlapping top right corner
142cb93a386Sopenharmony_ci            SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
143cb93a386Sopenharmony_ci    };
144cb93a386Sopenharmony_ci}
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_cinamespace {
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_cistruct GpuReadPixelTestRules {
149cb93a386Sopenharmony_ci    // Test unpremul sources? We could omit this and detect that creating the source of the read
150cb93a386Sopenharmony_ci    // failed but having it lets us skip generating reference color data.
151cb93a386Sopenharmony_ci    bool fAllowUnpremulSrc = true;
152cb93a386Sopenharmony_ci    // Are reads that are overlapping but not contained by the src bounds expected to succeed?
153cb93a386Sopenharmony_ci    bool fUncontainedRectSucceeds = true;
154cb93a386Sopenharmony_ci};
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci// Makes a src populated with the pixmap. The src should get its image info (or equivalent) from
157cb93a386Sopenharmony_ci// the pixmap.
158cb93a386Sopenharmony_citemplate <typename T> using GpuSrcFactory = T(SkPixmap&);
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_cienum class Result {
161cb93a386Sopenharmony_ci    kFail,
162cb93a386Sopenharmony_ci    kSuccess,
163cb93a386Sopenharmony_ci    kExcusedFailure,
164cb93a386Sopenharmony_ci};
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci// Does a read from the T into the pixmap.
167cb93a386Sopenharmony_citemplate <typename T>
168cb93a386Sopenharmony_ciusing GpuReadSrcFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci// Makes a dst for testing writes.
171cb93a386Sopenharmony_citemplate <typename T> using GpuDstFactory = T(const SkImageInfo& ii);
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci// Does a write from the pixmap to the T.
174cb93a386Sopenharmony_citemplate <typename T>
175cb93a386Sopenharmony_ciusing GpuWriteDstFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci// To test the results of the write we do a read. This reads the entire src T. It should do a non-
178cb93a386Sopenharmony_ci// converting read (i.e. the image info of the returned pixmap matches that of the T).
179cb93a386Sopenharmony_citemplate <typename T>
180cb93a386Sopenharmony_ciusing GpuReadDstFn = SkAutoPixmapStorage(const T&);
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci}  // anonymous namespace
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ciSkPixmap make_pixmap_have_valid_alpha_type(SkPixmap pm) {
185cb93a386Sopenharmony_ci    if (pm.alphaType() == kUnknown_SkAlphaType) {
186cb93a386Sopenharmony_ci        return {pm.info().makeAlphaType(kUnpremul_SkAlphaType), pm.addr(), pm.rowBytes()};
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci    return pm;
189cb93a386Sopenharmony_ci}
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_cistatic SkAutoPixmapStorage make_ref_data(const SkImageInfo& info, bool forceOpaque) {
192cb93a386Sopenharmony_ci    SkAutoPixmapStorage result;
193cb93a386Sopenharmony_ci    result.alloc(info);
194cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRasterDirect(make_pixmap_have_valid_alpha_type(result));
195cb93a386Sopenharmony_ci    if (!surface) {
196cb93a386Sopenharmony_ci        return result;
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    SkPoint pts1[] = {{0, 0}, {float(info.width()), float(info.height())}};
200cb93a386Sopenharmony_ci    static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
201cb93a386Sopenharmony_ci    SkPaint paint;
202cb93a386Sopenharmony_ci    paint.setShader(SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkTileMode::kClamp));
203cb93a386Sopenharmony_ci    surface->getCanvas()->drawPaint(paint);
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ci    SkPoint pts2[] = {{float(info.width()), 0}, {0, float(info.height())}};
206cb93a386Sopenharmony_ci    static constexpr SkColor kColors2[] = {SK_ColorBLUE, SK_ColorBLACK};
207cb93a386Sopenharmony_ci    paint.setShader(SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkTileMode::kClamp));
208cb93a386Sopenharmony_ci    paint.setBlendMode(SkBlendMode::kPlus);
209cb93a386Sopenharmony_ci    surface->getCanvas()->drawPaint(paint);
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci    // If not opaque add some fractional alpha.
212cb93a386Sopenharmony_ci    if (info.alphaType() != kOpaque_SkAlphaType && !forceOpaque) {
213cb93a386Sopenharmony_ci        static constexpr SkColor kColors3[] = {SK_ColorWHITE,
214cb93a386Sopenharmony_ci                                               SK_ColorWHITE,
215cb93a386Sopenharmony_ci                                               0x60FFFFFF,
216cb93a386Sopenharmony_ci                                               SK_ColorWHITE,
217cb93a386Sopenharmony_ci                                               SK_ColorWHITE};
218cb93a386Sopenharmony_ci        static constexpr SkScalar kPos3[] = {0.f, 0.15f, 0.5f, 0.85f, 1.f};
219cb93a386Sopenharmony_ci        paint.setShader(SkGradientShader::MakeRadial({info.width()/2.f, info.height()/2.f},
220cb93a386Sopenharmony_ci                                                     (info.width() + info.height())/10.f,
221cb93a386Sopenharmony_ci                                                     kColors3, kPos3, 5, SkTileMode::kMirror));
222cb93a386Sopenharmony_ci        paint.setBlendMode(SkBlendMode::kDstIn);
223cb93a386Sopenharmony_ci        surface->getCanvas()->drawPaint(paint);
224cb93a386Sopenharmony_ci    }
225cb93a386Sopenharmony_ci    return result;
226cb93a386Sopenharmony_ci};
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_citemplate <typename T>
229cb93a386Sopenharmony_cistatic void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
230cb93a386Sopenharmony_ci                                        const GpuReadPixelTestRules& rules,
231cb93a386Sopenharmony_ci                                        const std::function<GpuSrcFactory<T>>& srcFactory,
232cb93a386Sopenharmony_ci                                        const std::function<GpuReadSrcFn<T>>& read,
233cb93a386Sopenharmony_ci                                        SkString label) {
234cb93a386Sopenharmony_ci    if (!label.isEmpty()) {
235cb93a386Sopenharmony_ci        // Add space for printing.
236cb93a386Sopenharmony_ci        label.append(" ");
237cb93a386Sopenharmony_ci    }
238cb93a386Sopenharmony_ci    // Separate this out just to give it some line width to breathe. Note 'srcPixels' should have
239cb93a386Sopenharmony_ci    // the same image info as src. We will do a converting readPixels() on it to get the data
240cb93a386Sopenharmony_ci    // to compare with the results of 'read'.
241cb93a386Sopenharmony_ci    auto runTest = [&](const T& src,
242cb93a386Sopenharmony_ci                       const SkPixmap& srcPixels,
243cb93a386Sopenharmony_ci                       const SkImageInfo& readInfo,
244cb93a386Sopenharmony_ci                       SkIPoint offset) {
245cb93a386Sopenharmony_ci        const bool csConversion =
246cb93a386Sopenharmony_ci                !SkColorSpace::Equals(readInfo.colorSpace(), srcPixels.info().colorSpace());
247cb93a386Sopenharmony_ci        const auto readCT = readInfo.colorType();
248cb93a386Sopenharmony_ci        const auto readAT = readInfo.alphaType();
249cb93a386Sopenharmony_ci        const auto srcCT = srcPixels.info().colorType();
250cb93a386Sopenharmony_ci        const auto srcAT = srcPixels.info().alphaType();
251cb93a386Sopenharmony_ci        const auto rect = SkIRect::MakeWH(readInfo.width(), readInfo.height()).makeOffset(offset);
252cb93a386Sopenharmony_ci        const auto surfBounds = SkIRect::MakeWH(srcPixels.width(), srcPixels.height());
253cb93a386Sopenharmony_ci        const size_t readBpp = SkColorTypeBytesPerPixel(readCT);
254cb93a386Sopenharmony_ci
255cb93a386Sopenharmony_ci        // Make the row bytes in the dst be loose for extra stress.
256cb93a386Sopenharmony_ci        const size_t dstRB = readBpp * readInfo.width() + 10 * readBpp;
257cb93a386Sopenharmony_ci        // This will make the last row tight.
258cb93a386Sopenharmony_ci        const size_t dstSize = readInfo.computeByteSize(dstRB);
259cb93a386Sopenharmony_ci        std::unique_ptr<char[]> dstData(new char[dstSize]);
260cb93a386Sopenharmony_ci        SkPixmap dstPixels(readInfo, dstData.get(), dstRB);
261cb93a386Sopenharmony_ci        // Initialize with an arbitrary value for each byte. Later we will check that only the
262cb93a386Sopenharmony_ci        // correct part of the destination gets overwritten by 'read'.
263cb93a386Sopenharmony_ci        static constexpr auto kInitialByte = static_cast<char>(0x1B);
264cb93a386Sopenharmony_ci        std::fill_n(static_cast<char*>(dstPixels.writable_addr()),
265cb93a386Sopenharmony_ci                    dstPixels.computeByteSize(),
266cb93a386Sopenharmony_ci                    kInitialByte);
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci        const Result result = read(src, offset, dstPixels);
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci        if (!SkIRect::Intersects(rect, surfBounds)) {
271cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
272cb93a386Sopenharmony_ci        } else if (readCT == kUnknown_SkColorType) {
273cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
274cb93a386Sopenharmony_ci        } else if ((readAT == kUnknown_SkAlphaType) != (srcAT == kUnknown_SkAlphaType)) {
275cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
276cb93a386Sopenharmony_ci        } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
277cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
278cb93a386Sopenharmony_ci        } else if (result == Result::kFail) {
279cb93a386Sopenharmony_ci            // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
280cb93a386Sopenharmony_ci            if (SkColorTypeToGrColorType(readCT) != GrColorType::kUnknown) {
281cb93a386Sopenharmony_ci                ERRORF(reporter,
282cb93a386Sopenharmony_ci                       "Read failed. %sSrc CT: %s, Src AT: %s Read CT: %s, Read AT: %s, "
283cb93a386Sopenharmony_ci                       "Rect [%d, %d, %d, %d], CS conversion: %d\n",
284cb93a386Sopenharmony_ci                       label.c_str(),
285cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
286cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
287cb93a386Sopenharmony_ci                       rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
288cb93a386Sopenharmony_ci            }
289cb93a386Sopenharmony_ci            return result;
290cb93a386Sopenharmony_ci        }
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci        bool guardOk = true;
293cb93a386Sopenharmony_ci        auto guardCheck = [](char x) { return x == kInitialByte; };
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci        // Considering the rect we tried to read and the surface bounds figure  out which pixels in
296cb93a386Sopenharmony_ci        // both src and dst space should actually have been read and written.
297cb93a386Sopenharmony_ci        SkIRect srcReadRect;
298cb93a386Sopenharmony_ci        if (result == Result::kSuccess && srcReadRect.intersect(surfBounds, rect)) {
299cb93a386Sopenharmony_ci            SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci            const bool lumConversion =
302cb93a386Sopenharmony_ci                    !(SkColorTypeChannelFlags(srcCT) & kGray_SkColorChannelFlag) &&
303cb93a386Sopenharmony_ci                    (SkColorTypeChannelFlags(readCT) & kGray_SkColorChannelFlag);
304cb93a386Sopenharmony_ci            // A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
305cb93a386Sopenharmony_ci            // difference. Note that sometimes read back on GPU can be lossy even when there no
306cb93a386Sopenharmony_ci            // conversion at all because GPU->CPU read may go to a lower bit depth format and then
307cb93a386Sopenharmony_ci            // be promoted back to the original type. For example, GL ES cannot read to 1010102, so
308cb93a386Sopenharmony_ci            // we go through 8888.
309cb93a386Sopenharmony_ci            float numer = (lumConversion || csConversion) ? 3.f : 2.f;
310cb93a386Sopenharmony_ci            // Allow some extra tolerance if unpremuling.
311cb93a386Sopenharmony_ci            if (srcAT == kPremul_SkAlphaType && readAT == kUnpremul_SkAlphaType) {
312cb93a386Sopenharmony_ci                numer += 1;
313cb93a386Sopenharmony_ci            }
314cb93a386Sopenharmony_ci            int rgbBits = std::min({min_rgb_channel_bits(readCT), min_rgb_channel_bits(srcCT), 8});
315cb93a386Sopenharmony_ci            float tol = numer / (1 << rgbBits);
316cb93a386Sopenharmony_ci            float alphaTol = 0;
317cb93a386Sopenharmony_ci            if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
318cb93a386Sopenharmony_ci                // Alpha can also get squashed down to 8 bits going through an intermediate
319cb93a386Sopenharmony_ci                // color format.
320cb93a386Sopenharmony_ci                const int alphaBits = std::min({alpha_channel_bits(readCT),
321cb93a386Sopenharmony_ci                                                alpha_channel_bits(srcCT),
322cb93a386Sopenharmony_ci                                                8});
323cb93a386Sopenharmony_ci                alphaTol = 2.f / (1 << alphaBits);
324cb93a386Sopenharmony_ci            }
325cb93a386Sopenharmony_ci
326cb93a386Sopenharmony_ci            const float tols[4] = {tol, tol, tol, alphaTol};
327cb93a386Sopenharmony_ci            auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
328cb93a386Sopenharmony_ci                                                                        const float diffs[4]) {
329cb93a386Sopenharmony_ci                SkASSERT(x >= 0 && y >= 0);
330cb93a386Sopenharmony_ci                ERRORF(reporter,
331cb93a386Sopenharmony_ci                       "%sSrc CT: %s, Src AT: %s, Read CT: %s, Read AT: %s, Rect [%d, %d, %d, %d]"
332cb93a386Sopenharmony_ci                       ", CS conversion: %d\n"
333cb93a386Sopenharmony_ci                       "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
334cb93a386Sopenharmony_ci                       label.c_str(),
335cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
336cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
337cb93a386Sopenharmony_ci                       rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
338cb93a386Sopenharmony_ci                       diffs[0], diffs[1], diffs[2], diffs[3]);
339cb93a386Sopenharmony_ci            });
340cb93a386Sopenharmony_ci            SkAutoPixmapStorage ref;
341cb93a386Sopenharmony_ci            SkImageInfo refInfo = readInfo.makeDimensions(dstWriteRect.size());
342cb93a386Sopenharmony_ci            ref.alloc(refInfo);
343cb93a386Sopenharmony_ci            if (readAT == kUnknown_SkAlphaType) {
344cb93a386Sopenharmony_ci                // Do a spoofed read where src and dst alpha type are both kUnpremul. This will
345cb93a386Sopenharmony_ci                // allow SkPixmap readPixels to succeed and won't do any alpha type conversion.
346cb93a386Sopenharmony_ci                SkPixmap unpremulRef(refInfo.makeAlphaType(kUnpremul_SkAlphaType),
347cb93a386Sopenharmony_ci                                     ref.addr(),
348cb93a386Sopenharmony_ci                                     ref.rowBytes());
349cb93a386Sopenharmony_ci                SkPixmap unpremulSRc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
350cb93a386Sopenharmony_ci                                     srcPixels.addr(),
351cb93a386Sopenharmony_ci                                     srcPixels.rowBytes());
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci                unpremulSRc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
354cb93a386Sopenharmony_ci            } else {
355cb93a386Sopenharmony_ci                srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
356cb93a386Sopenharmony_ci            }
357cb93a386Sopenharmony_ci            // This is the part of dstPixels that should have been updated.
358cb93a386Sopenharmony_ci            SkPixmap actual;
359cb93a386Sopenharmony_ci            SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
360cb93a386Sopenharmony_ci            ComparePixels(ref, actual, tols, error);
361cb93a386Sopenharmony_ci
362cb93a386Sopenharmony_ci            const auto* v = dstData.get();
363cb93a386Sopenharmony_ci            const auto* end = dstData.get() + dstSize;
364cb93a386Sopenharmony_ci            guardOk = std::all_of(v, v + dstWriteRect.top() * dstPixels.rowBytes(), guardCheck);
365cb93a386Sopenharmony_ci            v += dstWriteRect.top() * dstPixels.rowBytes();
366cb93a386Sopenharmony_ci            for (int y = dstWriteRect.top(); y < dstWriteRect.bottom(); ++y) {
367cb93a386Sopenharmony_ci                guardOk |= std::all_of(v, v + dstWriteRect.left() * readBpp, guardCheck);
368cb93a386Sopenharmony_ci                auto pad = v + dstWriteRect.right() * readBpp;
369cb93a386Sopenharmony_ci                auto rowEnd = std::min(end, v + dstPixels.rowBytes());
370cb93a386Sopenharmony_ci                // min protects against reading past the end of the tight last row.
371cb93a386Sopenharmony_ci                guardOk |= std::all_of(pad, rowEnd, guardCheck);
372cb93a386Sopenharmony_ci                v = rowEnd;
373cb93a386Sopenharmony_ci            }
374cb93a386Sopenharmony_ci            guardOk |= std::all_of(v, end, guardCheck);
375cb93a386Sopenharmony_ci        } else {
376cb93a386Sopenharmony_ci            guardOk = std::all_of(dstData.get(), dstData.get() + dstSize, guardCheck);
377cb93a386Sopenharmony_ci        }
378cb93a386Sopenharmony_ci        if (!guardOk) {
379cb93a386Sopenharmony_ci            ERRORF(reporter,
380cb93a386Sopenharmony_ci                   "Result pixels modified result outside read rect [%d, %d, %d, %d]. "
381cb93a386Sopenharmony_ci                   "%sSrc CT: %s, Read CT: %s, CS conversion: %d",
382cb93a386Sopenharmony_ci                   rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, label.c_str(),
383cb93a386Sopenharmony_ci                   ToolUtils::colortype_name(srcCT), ToolUtils::colortype_name(readCT),
384cb93a386Sopenharmony_ci                   csConversion);
385cb93a386Sopenharmony_ci        }
386cb93a386Sopenharmony_ci        return result;
387cb93a386Sopenharmony_ci    };
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci    static constexpr int kW = 16;
390cb93a386Sopenharmony_ci    static constexpr int kH = 16;
391cb93a386Sopenharmony_ci
392cb93a386Sopenharmony_ci    const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
393cb93a386Sopenharmony_ci    const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci    // We ensure we use the long array once per src and read color type and otherwise use the
396cb93a386Sopenharmony_ci    // short array to improve test run time.
397cb93a386Sopenharmony_ci    // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
398cb93a386Sopenharmony_ci    // equivalent. Just ensure each redundant AT is tested once with each CT (src and read).
399cb93a386Sopenharmony_ci    // Similarly, alpha-only color types behave the same for all alpha types so just test premul
400cb93a386Sopenharmony_ci    // after one iter.
401cb93a386Sopenharmony_ci    // We consider a src or read CT thoroughly tested once it has run through the long rect array
402cb93a386Sopenharmony_ci    // and full complement of alpha types with one successful read in the loop.
403cb93a386Sopenharmony_ci    std::array<bool, kLastEnum_SkColorType + 1> srcCTTestedThoroughly  = {},
404cb93a386Sopenharmony_ci                                                readCTTestedThoroughly = {};
405cb93a386Sopenharmony_ci    for (int sat = 0; sat < kLastEnum_SkAlphaType; ++sat) {
406cb93a386Sopenharmony_ci        const auto srcAT = static_cast<SkAlphaType>(sat);
407cb93a386Sopenharmony_ci        if (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc) {
408cb93a386Sopenharmony_ci            continue;
409cb93a386Sopenharmony_ci        }
410cb93a386Sopenharmony_ci        for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
411cb93a386Sopenharmony_ci            const auto srcCT = static_cast<SkColorType>(sct);
412cb93a386Sopenharmony_ci            // We always make our ref data as F32
413cb93a386Sopenharmony_ci            auto refInfo = SkImageInfo::Make(kW, kH,
414cb93a386Sopenharmony_ci                                             kRGBA_F32_SkColorType,
415cb93a386Sopenharmony_ci                                             srcAT,
416cb93a386Sopenharmony_ci                                             SkColorSpace::MakeSRGB());
417cb93a386Sopenharmony_ci            // 1010102 formats have an issue where it's easy to make a resulting
418cb93a386Sopenharmony_ci            // color where r, g, or b is greater than a. CPU/GPU differ in whether the stored color
419cb93a386Sopenharmony_ci            // channels are clipped to the alpha value. CPU clips but GPU does not.
420cb93a386Sopenharmony_ci            // Note that we only currently use srcCT for the 1010102 workaround. If we remove this
421cb93a386Sopenharmony_ci            // we can also put the ref data setup above the srcCT loop.
422cb93a386Sopenharmony_ci            bool forceOpaque = srcAT == kPremul_SkAlphaType &&
423cb93a386Sopenharmony_ci                    (srcCT == kRGBA_1010102_SkColorType || srcCT == kBGRA_1010102_SkColorType);
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ci            SkAutoPixmapStorage srcPixels = make_ref_data(refInfo, forceOpaque);
426cb93a386Sopenharmony_ci            auto src = srcFactory(srcPixels);
427cb93a386Sopenharmony_ci            if (!src) {
428cb93a386Sopenharmony_ci                continue;
429cb93a386Sopenharmony_ci            }
430cb93a386Sopenharmony_ci            if (SkColorTypeIsAlwaysOpaque(srcCT) && srcCTTestedThoroughly[srcCT] &&
431cb93a386Sopenharmony_ci                (kPremul_SkAlphaType == srcAT || kUnpremul_SkAlphaType == srcAT)) {
432cb93a386Sopenharmony_ci                continue;
433cb93a386Sopenharmony_ci            }
434cb93a386Sopenharmony_ci            if (SkColorTypeIsAlphaOnly(srcCT) && srcCTTestedThoroughly[srcCT] &&
435cb93a386Sopenharmony_ci                (kUnpremul_SkAlphaType == srcAT ||
436cb93a386Sopenharmony_ci                 kOpaque_SkAlphaType   == srcAT ||
437cb93a386Sopenharmony_ci                 kUnknown_SkAlphaType  == srcAT)) {
438cb93a386Sopenharmony_ci                continue;
439cb93a386Sopenharmony_ci            }
440cb93a386Sopenharmony_ci            for (int rct = 0; rct <= kLastEnum_SkColorType; ++rct) {
441cb93a386Sopenharmony_ci                const auto readCT = static_cast<SkColorType>(rct);
442cb93a386Sopenharmony_ci                for (const sk_sp<SkColorSpace>& readCS :
443cb93a386Sopenharmony_ci                     {SkColorSpace::MakeSRGB(), SkColorSpace::MakeSRGBLinear()}) {
444cb93a386Sopenharmony_ci                    for (int at = 0; at <= kLastEnum_SkAlphaType; ++at) {
445cb93a386Sopenharmony_ci                        const auto readAT = static_cast<SkAlphaType>(at);
446cb93a386Sopenharmony_ci                        if (srcAT != kOpaque_SkAlphaType && readAT == kOpaque_SkAlphaType) {
447cb93a386Sopenharmony_ci                            // This doesn't make sense.
448cb93a386Sopenharmony_ci                            continue;
449cb93a386Sopenharmony_ci                        }
450cb93a386Sopenharmony_ci                        if (SkColorTypeIsAlwaysOpaque(readCT) && readCTTestedThoroughly[readCT] &&
451cb93a386Sopenharmony_ci                            (kPremul_SkAlphaType == readAT || kUnpremul_SkAlphaType == readAT)) {
452cb93a386Sopenharmony_ci                            continue;
453cb93a386Sopenharmony_ci                        }
454cb93a386Sopenharmony_ci                        if (SkColorTypeIsAlphaOnly(readCT) && readCTTestedThoroughly[readCT] &&
455cb93a386Sopenharmony_ci                            (kUnpremul_SkAlphaType == readAT ||
456cb93a386Sopenharmony_ci                             kOpaque_SkAlphaType   == readAT ||
457cb93a386Sopenharmony_ci                             kUnknown_SkAlphaType  == readAT)) {
458cb93a386Sopenharmony_ci                            continue;
459cb93a386Sopenharmony_ci                        }
460cb93a386Sopenharmony_ci                        const auto& rects =
461cb93a386Sopenharmony_ci                                srcCTTestedThoroughly[sct] && readCTTestedThoroughly[rct]
462cb93a386Sopenharmony_ci                                        ? shortRectArray
463cb93a386Sopenharmony_ci                                        : longRectArray;
464cb93a386Sopenharmony_ci                        for (const auto& rect : rects) {
465cb93a386Sopenharmony_ci                            const auto readInfo = SkImageInfo::Make(rect.width(), rect.height(),
466cb93a386Sopenharmony_ci                                                                    readCT, readAT, readCS);
467cb93a386Sopenharmony_ci                            const SkIPoint offset = rect.topLeft();
468cb93a386Sopenharmony_ci                            Result r = runTest(src, srcPixels, readInfo, offset);
469cb93a386Sopenharmony_ci                            if (r == Result::kSuccess) {
470cb93a386Sopenharmony_ci                                srcCTTestedThoroughly[sct] = true;
471cb93a386Sopenharmony_ci                                readCTTestedThoroughly[rct] = true;
472cb93a386Sopenharmony_ci                            }
473cb93a386Sopenharmony_ci                        }
474cb93a386Sopenharmony_ci                    }
475cb93a386Sopenharmony_ci                }
476cb93a386Sopenharmony_ci            }
477cb93a386Sopenharmony_ci        }
478cb93a386Sopenharmony_ci    }
479cb93a386Sopenharmony_ci}
480cb93a386Sopenharmony_ci
481cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextReadPixels, reporter, ctxInfo) {
482cb93a386Sopenharmony_ci    using Surface = std::unique_ptr<skgpu::SurfaceContext>;
483cb93a386Sopenharmony_ci    GrDirectContext* direct = ctxInfo.directContext();
484cb93a386Sopenharmony_ci    auto reader = std::function<GpuReadSrcFn<Surface>>(
485cb93a386Sopenharmony_ci            [direct](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
486cb93a386Sopenharmony_ci                if (surface->readPixels(direct, pixels, offset)) {
487cb93a386Sopenharmony_ci                    return Result::kSuccess;
488cb93a386Sopenharmony_ci                } else {
489cb93a386Sopenharmony_ci                    // Reading from a non-renderable format is not guaranteed to work on GL.
490cb93a386Sopenharmony_ci                    // We'd have to be able to force a copy or draw draw to a renderable format.
491cb93a386Sopenharmony_ci                    const auto& caps = *direct->priv().caps();
492cb93a386Sopenharmony_ci                    if (direct->backend() == GrBackendApi::kOpenGL &&
493cb93a386Sopenharmony_ci                        !caps.isFormatRenderable(surface->asSurfaceProxy()->backendFormat(), 1)) {
494cb93a386Sopenharmony_ci                        return Result::kExcusedFailure;
495cb93a386Sopenharmony_ci                    }
496cb93a386Sopenharmony_ci                    return Result::kFail;
497cb93a386Sopenharmony_ci                }
498cb93a386Sopenharmony_ci            });
499cb93a386Sopenharmony_ci    GpuReadPixelTestRules rules;
500cb93a386Sopenharmony_ci    rules.fAllowUnpremulSrc = true;
501cb93a386Sopenharmony_ci    rules.fUncontainedRectSucceeds = true;
502cb93a386Sopenharmony_ci
503cb93a386Sopenharmony_ci    for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
504cb93a386Sopenharmony_ci        for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
505cb93a386Sopenharmony_ci            auto factory = std::function<GpuSrcFactory<Surface>>(
506cb93a386Sopenharmony_ci                    [direct, origin, renderable](const SkPixmap& src) {
507cb93a386Sopenharmony_ci                        auto sc = CreateSurfaceContext(
508cb93a386Sopenharmony_ci                                direct, src.info(), SkBackingFit::kExact, origin, renderable);
509cb93a386Sopenharmony_ci                        if (sc) {
510cb93a386Sopenharmony_ci                            sc->writePixels(direct, src, {0, 0});
511cb93a386Sopenharmony_ci                        }
512cb93a386Sopenharmony_ci                        return sc;
513cb93a386Sopenharmony_ci                    });
514cb93a386Sopenharmony_ci            auto label = SkStringPrintf("Renderable: %d, Origin: %d", (int)renderable, origin);
515cb93a386Sopenharmony_ci            gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
516cb93a386Sopenharmony_ci        }
517cb93a386Sopenharmony_ci    }
518cb93a386Sopenharmony_ci}
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_ALL_CONTEXTS(ReadPixels_InvalidRowBytes_Gpu, reporter, ctxInfo) {
521cb93a386Sopenharmony_ci    auto srcII = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
522cb93a386Sopenharmony_ci    auto surf = SkSurface::MakeRenderTarget(ctxInfo.directContext(), SkBudgeted::kYes, srcII);
523cb93a386Sopenharmony_ci    for (int ct = 0; ct < kLastEnum_SkColorType + 1; ++ct) {
524cb93a386Sopenharmony_ci        auto colorType = static_cast<SkColorType>(ct);
525cb93a386Sopenharmony_ci        size_t bpp = SkColorTypeBytesPerPixel(colorType);
526cb93a386Sopenharmony_ci        if (bpp <= 1) {
527cb93a386Sopenharmony_ci            continue;
528cb93a386Sopenharmony_ci        }
529cb93a386Sopenharmony_ci        auto dstII = srcII.makeColorType(colorType);
530cb93a386Sopenharmony_ci        size_t badRowBytes = (surf->width() + 1)*bpp - 1;
531cb93a386Sopenharmony_ci        auto storage = std::make_unique<char[]>(badRowBytes*surf->height());
532cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !surf->readPixels(dstII, storage.get(), badRowBytes, 0, 0));
533cb93a386Sopenharmony_ci    }
534cb93a386Sopenharmony_ci}
535cb93a386Sopenharmony_ci
536cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_ALL_CONTEXTS(WritePixels_InvalidRowBytes_Gpu, reporter, ctxInfo) {
537cb93a386Sopenharmony_ci    auto dstII = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
538cb93a386Sopenharmony_ci    auto surf = SkSurface::MakeRenderTarget(ctxInfo.directContext(), SkBudgeted::kYes, dstII);
539cb93a386Sopenharmony_ci    for (int ct = 0; ct < kLastEnum_SkColorType + 1; ++ct) {
540cb93a386Sopenharmony_ci        auto colorType = static_cast<SkColorType>(ct);
541cb93a386Sopenharmony_ci        size_t bpp = SkColorTypeBytesPerPixel(colorType);
542cb93a386Sopenharmony_ci        if (bpp <= 1) {
543cb93a386Sopenharmony_ci            continue;
544cb93a386Sopenharmony_ci        }
545cb93a386Sopenharmony_ci        auto srcII = dstII.makeColorType(colorType);
546cb93a386Sopenharmony_ci        size_t badRowBytes = (surf->width() + 1)*bpp - 1;
547cb93a386Sopenharmony_ci        auto storage = std::make_unique<char[]>(badRowBytes*surf->height());
548cb93a386Sopenharmony_ci        memset(storage.get(), 0, badRowBytes * surf->height());
549cb93a386Sopenharmony_ci        // SkSurface::writePixels doesn't report bool, SkCanvas's does.
550cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter,
551cb93a386Sopenharmony_ci                        !surf->getCanvas()->writePixels(srcII, storage.get(), badRowBytes, 0, 0));
552cb93a386Sopenharmony_ci    }
553cb93a386Sopenharmony_ci}
554cb93a386Sopenharmony_ci
555cb93a386Sopenharmony_cinamespace {
556cb93a386Sopenharmony_cistruct AsyncContext {
557cb93a386Sopenharmony_ci    bool fCalled = false;
558cb93a386Sopenharmony_ci    std::unique_ptr<const SkImage::AsyncReadResult> fResult;
559cb93a386Sopenharmony_ci};
560cb93a386Sopenharmony_ci}  // anonymous namespace
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ci// Making this a lambda in the test functions caused:
563cb93a386Sopenharmony_ci//   "error: cannot compile this forwarded non-trivially copyable parameter yet"
564cb93a386Sopenharmony_ci// on x86/Win/Clang bot, referring to 'result'.
565cb93a386Sopenharmony_cistatic void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
566cb93a386Sopenharmony_ci    auto context = static_cast<AsyncContext*>(c);
567cb93a386Sopenharmony_ci    context->fResult = std::move(result);
568cb93a386Sopenharmony_ci    context->fCalled = true;
569cb93a386Sopenharmony_ci};
570cb93a386Sopenharmony_ci
571cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixels, reporter, ctxInfo) {
572cb93a386Sopenharmony_ci    using Surface = sk_sp<SkSurface>;
573cb93a386Sopenharmony_ci    auto reader = std::function<GpuReadSrcFn<Surface>>(
574cb93a386Sopenharmony_ci            [](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
575cb93a386Sopenharmony_ci                auto direct = surface->recordingContext()->asDirectContext();
576cb93a386Sopenharmony_ci                SkASSERT(direct);
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci                AsyncContext context;
579cb93a386Sopenharmony_ci                auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ci                // Rescale quality and linearity don't matter since we're doing a non-scaling
582cb93a386Sopenharmony_ci                // readback.
583cb93a386Sopenharmony_ci                surface->asyncRescaleAndReadPixels(pixels.info(), rect,
584cb93a386Sopenharmony_ci                                                   SkImage::RescaleGamma::kSrc,
585cb93a386Sopenharmony_ci                                                   SkImage::RescaleMode::kNearest,
586cb93a386Sopenharmony_ci                                                   async_callback, &context);
587cb93a386Sopenharmony_ci                direct->submit();
588cb93a386Sopenharmony_ci                while (!context.fCalled) {
589cb93a386Sopenharmony_ci                    direct->checkAsyncWorkCompletion();
590cb93a386Sopenharmony_ci                }
591cb93a386Sopenharmony_ci                if (!context.fResult) {
592cb93a386Sopenharmony_ci                    return Result::kFail;
593cb93a386Sopenharmony_ci                }
594cb93a386Sopenharmony_ci                SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), context.fResult->data(0),
595cb93a386Sopenharmony_ci                             context.fResult->rowBytes(0), pixels.info().minRowBytes(),
596cb93a386Sopenharmony_ci                             pixels.height());
597cb93a386Sopenharmony_ci                return Result::kSuccess;
598cb93a386Sopenharmony_ci            });
599cb93a386Sopenharmony_ci    GpuReadPixelTestRules rules;
600cb93a386Sopenharmony_ci    rules.fAllowUnpremulSrc = false;
601cb93a386Sopenharmony_ci    rules.fUncontainedRectSucceeds = false;
602cb93a386Sopenharmony_ci
603cb93a386Sopenharmony_ci    for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
604cb93a386Sopenharmony_ci        auto factory = std::function<GpuSrcFactory<Surface>>(
605cb93a386Sopenharmony_ci                [context = ctxInfo.directContext(), origin](const SkPixmap& src) {
606cb93a386Sopenharmony_ci                    auto surf = SkSurface::MakeRenderTarget(context,
607cb93a386Sopenharmony_ci                                                            SkBudgeted::kYes,
608cb93a386Sopenharmony_ci                                                            src.info(),
609cb93a386Sopenharmony_ci                                                            1,
610cb93a386Sopenharmony_ci                                                            origin,
611cb93a386Sopenharmony_ci                                                            nullptr);
612cb93a386Sopenharmony_ci                    if (surf) {
613cb93a386Sopenharmony_ci                        surf->writePixels(src, 0, 0);
614cb93a386Sopenharmony_ci                    }
615cb93a386Sopenharmony_ci                    return surf;
616cb93a386Sopenharmony_ci                });
617cb93a386Sopenharmony_ci        auto label = SkStringPrintf("Origin: %d", origin);
618cb93a386Sopenharmony_ci        gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
619cb93a386Sopenharmony_ci        auto backendRTFactory = std::function<GpuSrcFactory<Surface>>(
620cb93a386Sopenharmony_ci                [context = ctxInfo.directContext(), origin](const SkPixmap& src) {
621cb93a386Sopenharmony_ci                    // Dawn backend implementation of backend render targets doesn't support
622cb93a386Sopenharmony_ci                    // reading.
623cb93a386Sopenharmony_ci                    if (context->backend() == GrBackendApi::kDawn) {
624cb93a386Sopenharmony_ci                        return Surface();
625cb93a386Sopenharmony_ci                    }
626cb93a386Sopenharmony_ci                    auto surf = sk_gpu_test::MakeBackendRenderTargetSurface(context,
627cb93a386Sopenharmony_ci                                                                            src.info(),
628cb93a386Sopenharmony_ci                                                                            origin,
629cb93a386Sopenharmony_ci                                                                            1);
630cb93a386Sopenharmony_ci                    if (surf) {
631cb93a386Sopenharmony_ci                        surf->writePixels(src, 0, 0);
632cb93a386Sopenharmony_ci                    }
633cb93a386Sopenharmony_ci                    return surf;
634cb93a386Sopenharmony_ci                });
635cb93a386Sopenharmony_ci        label = SkStringPrintf("BERT Origin: %d", origin);
636cb93a386Sopenharmony_ci        gpu_read_pixels_test_driver(reporter, rules, backendRTFactory, reader, label);
637cb93a386Sopenharmony_ci    }
638cb93a386Sopenharmony_ci}
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels, reporter, ctxInfo) {
641cb93a386Sopenharmony_ci    using Image = sk_sp<SkImage>;
642cb93a386Sopenharmony_ci    auto context = ctxInfo.directContext();
643cb93a386Sopenharmony_ci    auto reader = std::function<GpuReadSrcFn<Image>>([context](const Image& image,
644cb93a386Sopenharmony_ci                                                               const SkIPoint& offset,
645cb93a386Sopenharmony_ci                                                               const SkPixmap& pixels) {
646cb93a386Sopenharmony_ci        AsyncContext asyncContext;
647cb93a386Sopenharmony_ci        auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
648cb93a386Sopenharmony_ci        // The GPU implementation is based on rendering and will fail for non-renderable color
649cb93a386Sopenharmony_ci        // types.
650cb93a386Sopenharmony_ci        auto ct = SkColorTypeToGrColorType(image->colorType());
651cb93a386Sopenharmony_ci        auto format = context->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
652cb93a386Sopenharmony_ci        if (!context->priv().caps()->isFormatAsColorTypeRenderable(ct, format)) {
653cb93a386Sopenharmony_ci            return Result::kExcusedFailure;
654cb93a386Sopenharmony_ci        }
655cb93a386Sopenharmony_ci
656cb93a386Sopenharmony_ci        // Rescale quality and linearity don't matter since we're doing a non-scaling readback.
657cb93a386Sopenharmony_ci        image->asyncRescaleAndReadPixels(pixels.info(), rect,
658cb93a386Sopenharmony_ci                                         SkImage::RescaleGamma::kSrc,
659cb93a386Sopenharmony_ci                                         SkImage::RescaleMode::kNearest,
660cb93a386Sopenharmony_ci                                         async_callback, &asyncContext);
661cb93a386Sopenharmony_ci        context->submit();
662cb93a386Sopenharmony_ci        while (!asyncContext.fCalled) {
663cb93a386Sopenharmony_ci            context->checkAsyncWorkCompletion();
664cb93a386Sopenharmony_ci        }
665cb93a386Sopenharmony_ci        if (!asyncContext.fResult) {
666cb93a386Sopenharmony_ci            return Result::kFail;
667cb93a386Sopenharmony_ci        }
668cb93a386Sopenharmony_ci        SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
669cb93a386Sopenharmony_ci                     asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
670cb93a386Sopenharmony_ci                     pixels.height());
671cb93a386Sopenharmony_ci        return Result::kSuccess;
672cb93a386Sopenharmony_ci    });
673cb93a386Sopenharmony_ci
674cb93a386Sopenharmony_ci    GpuReadPixelTestRules rules;
675cb93a386Sopenharmony_ci    rules.fAllowUnpremulSrc = true;
676cb93a386Sopenharmony_ci    rules.fUncontainedRectSucceeds = false;
677cb93a386Sopenharmony_ci
678cb93a386Sopenharmony_ci    for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
679cb93a386Sopenharmony_ci        for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
680cb93a386Sopenharmony_ci            auto factory = std::function<GpuSrcFactory<Image>>([&](const SkPixmap& src) {
681cb93a386Sopenharmony_ci                return sk_gpu_test::MakeBackendTextureImage(ctxInfo.directContext(), src,
682cb93a386Sopenharmony_ci                                                            renderable, origin);
683cb93a386Sopenharmony_ci            });
684cb93a386Sopenharmony_ci            auto label = SkStringPrintf("Renderable: %d, Origin: %d", (int)renderable, origin);
685cb93a386Sopenharmony_ci            gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
686cb93a386Sopenharmony_ci        }
687cb93a386Sopenharmony_ci    }
688cb93a386Sopenharmony_ci}
689cb93a386Sopenharmony_ci
690cb93a386Sopenharmony_ciDEF_GPUTEST(AsyncReadPixelsContextShutdown, reporter, options) {
691cb93a386Sopenharmony_ci    const auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
692cb93a386Sopenharmony_ci                                      SkColorSpace::MakeSRGB());
693cb93a386Sopenharmony_ci    enum class ShutdownSequence {
694cb93a386Sopenharmony_ci        kFreeResult_DestroyContext,
695cb93a386Sopenharmony_ci        kDestroyContext_FreeResult,
696cb93a386Sopenharmony_ci        kFreeResult_ReleaseAndAbandon_DestroyContext,
697cb93a386Sopenharmony_ci        kFreeResult_Abandon_DestroyContext,
698cb93a386Sopenharmony_ci        kReleaseAndAbandon_FreeResult_DestroyContext,
699cb93a386Sopenharmony_ci        kAbandon_FreeResult_DestroyContext,
700cb93a386Sopenharmony_ci        kReleaseAndAbandon_DestroyContext_FreeResult,
701cb93a386Sopenharmony_ci        kAbandon_DestroyContext_FreeResult,
702cb93a386Sopenharmony_ci    };
703cb93a386Sopenharmony_ci    for (int t = 0; t < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++t) {
704cb93a386Sopenharmony_ci        auto type = static_cast<sk_gpu_test::GrContextFactory::ContextType>(t);
705cb93a386Sopenharmony_ci        for (auto sequence : {ShutdownSequence::kFreeResult_DestroyContext,
706cb93a386Sopenharmony_ci                              ShutdownSequence::kDestroyContext_FreeResult,
707cb93a386Sopenharmony_ci                              ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext,
708cb93a386Sopenharmony_ci                              ShutdownSequence::kFreeResult_Abandon_DestroyContext,
709cb93a386Sopenharmony_ci                              ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext,
710cb93a386Sopenharmony_ci                              ShutdownSequence::kAbandon_FreeResult_DestroyContext,
711cb93a386Sopenharmony_ci                              ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult,
712cb93a386Sopenharmony_ci                              ShutdownSequence::kAbandon_DestroyContext_FreeResult}) {
713cb93a386Sopenharmony_ci            // Vulkan and D3D context abandoning without resource release has issues outside of the
714cb93a386Sopenharmony_ci            // scope of this test.
715cb93a386Sopenharmony_ci            if ((type == sk_gpu_test::GrContextFactory::kVulkan_ContextType ||
716cb93a386Sopenharmony_ci                 type == sk_gpu_test::GrContextFactory::kDirect3D_ContextType) &&
717cb93a386Sopenharmony_ci                (sequence == ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext ||
718cb93a386Sopenharmony_ci                 sequence == ShutdownSequence::kFreeResult_Abandon_DestroyContext ||
719cb93a386Sopenharmony_ci                 sequence == ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext ||
720cb93a386Sopenharmony_ci                 sequence == ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult ||
721cb93a386Sopenharmony_ci                 sequence == ShutdownSequence::kAbandon_FreeResult_DestroyContext ||
722cb93a386Sopenharmony_ci                 sequence == ShutdownSequence::kAbandon_DestroyContext_FreeResult)) {
723cb93a386Sopenharmony_ci                continue;
724cb93a386Sopenharmony_ci            }
725cb93a386Sopenharmony_ci            for (bool yuv : {false, true}) {
726cb93a386Sopenharmony_ci                sk_gpu_test::GrContextFactory factory(options);
727cb93a386Sopenharmony_ci                auto direct = factory.get(type);
728cb93a386Sopenharmony_ci                if (!direct) {
729cb93a386Sopenharmony_ci                    continue;
730cb93a386Sopenharmony_ci                }
731cb93a386Sopenharmony_ci                // This test is only meaningful for contexts that support transfer buffers for
732cb93a386Sopenharmony_ci                // reads.
733cb93a386Sopenharmony_ci                if (!direct->priv().caps()->transferFromSurfaceToBufferSupport()) {
734cb93a386Sopenharmony_ci                    continue;
735cb93a386Sopenharmony_ci                }
736cb93a386Sopenharmony_ci                auto surf = SkSurface::MakeRenderTarget(direct, SkBudgeted::kYes, ii, 1, nullptr);
737cb93a386Sopenharmony_ci                if (!surf) {
738cb93a386Sopenharmony_ci                    continue;
739cb93a386Sopenharmony_ci                }
740cb93a386Sopenharmony_ci                AsyncContext cbContext;
741cb93a386Sopenharmony_ci                if (yuv) {
742cb93a386Sopenharmony_ci                    surf->asyncRescaleAndReadPixelsYUV420(
743cb93a386Sopenharmony_ci                            kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), ii.bounds(),
744cb93a386Sopenharmony_ci                            ii.dimensions(), SkImage::RescaleGamma::kSrc,
745cb93a386Sopenharmony_ci                            SkImage::RescaleMode::kNearest, &async_callback, &cbContext);
746cb93a386Sopenharmony_ci                } else {
747cb93a386Sopenharmony_ci                    surf->asyncRescaleAndReadPixels(ii, ii.bounds(), SkImage::RescaleGamma::kSrc,
748cb93a386Sopenharmony_ci                                                    SkImage::RescaleMode::kNearest, &async_callback,
749cb93a386Sopenharmony_ci                                                    &cbContext);
750cb93a386Sopenharmony_ci                }
751cb93a386Sopenharmony_ci                direct->submit();
752cb93a386Sopenharmony_ci                while (!cbContext.fCalled) {
753cb93a386Sopenharmony_ci                    direct->checkAsyncWorkCompletion();
754cb93a386Sopenharmony_ci                }
755cb93a386Sopenharmony_ci                if (!cbContext.fResult) {
756cb93a386Sopenharmony_ci                    ERRORF(reporter, "Callback failed on %s. is YUV: %d",
757cb93a386Sopenharmony_ci                           sk_gpu_test::GrContextFactory::ContextTypeName(type), yuv);
758cb93a386Sopenharmony_ci                    continue;
759cb93a386Sopenharmony_ci                }
760cb93a386Sopenharmony_ci                // For vulkan we need to release all refs to the GrDirectContext before trying to
761cb93a386Sopenharmony_ci                // destroy the test context. The surface here is holding a ref.
762cb93a386Sopenharmony_ci                surf.reset();
763cb93a386Sopenharmony_ci
764cb93a386Sopenharmony_ci                // The real test is that we don't crash, get Vulkan validation errors, etc, during
765cb93a386Sopenharmony_ci                // this shutdown sequence.
766cb93a386Sopenharmony_ci                switch (sequence) {
767cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_DestroyContext:
768cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
769cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
770cb93a386Sopenharmony_ci                        break;
771cb93a386Sopenharmony_ci                    case ShutdownSequence::kDestroyContext_FreeResult:
772cb93a386Sopenharmony_ci                        factory.destroyContexts();
773cb93a386Sopenharmony_ci                        break;
774cb93a386Sopenharmony_ci                    case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
775cb93a386Sopenharmony_ci                        factory.releaseResourcesAndAbandonContexts();
776cb93a386Sopenharmony_ci                        break;
777cb93a386Sopenharmony_ci                    case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
778cb93a386Sopenharmony_ci                        factory.abandonContexts();
779cb93a386Sopenharmony_ci                        break;
780cb93a386Sopenharmony_ci                    case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
781cb93a386Sopenharmony_ci                        factory.releaseResourcesAndAbandonContexts();
782cb93a386Sopenharmony_ci                        factory.destroyContexts();
783cb93a386Sopenharmony_ci                        break;
784cb93a386Sopenharmony_ci                    case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
785cb93a386Sopenharmony_ci                        factory.abandonContexts();
786cb93a386Sopenharmony_ci                        factory.destroyContexts();
787cb93a386Sopenharmony_ci                        break;
788cb93a386Sopenharmony_ci                }
789cb93a386Sopenharmony_ci                cbContext.fResult.reset();
790cb93a386Sopenharmony_ci                switch (sequence) {
791cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
792cb93a386Sopenharmony_ci                        factory.releaseResourcesAndAbandonContexts();
793cb93a386Sopenharmony_ci                        break;
794cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
795cb93a386Sopenharmony_ci                        factory.abandonContexts();
796cb93a386Sopenharmony_ci                        break;
797cb93a386Sopenharmony_ci                    case ShutdownSequence::kFreeResult_DestroyContext:
798cb93a386Sopenharmony_ci                    case ShutdownSequence::kDestroyContext_FreeResult:
799cb93a386Sopenharmony_ci                    case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
800cb93a386Sopenharmony_ci                    case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
801cb93a386Sopenharmony_ci                    case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
802cb93a386Sopenharmony_ci                    case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
803cb93a386Sopenharmony_ci                        break;
804cb93a386Sopenharmony_ci                }
805cb93a386Sopenharmony_ci            }
806cb93a386Sopenharmony_ci        }
807cb93a386Sopenharmony_ci    }
808cb93a386Sopenharmony_ci}
809cb93a386Sopenharmony_ci
810cb93a386Sopenharmony_citemplate <typename T>
811cb93a386Sopenharmony_cistatic void gpu_write_pixels_test_driver(skiatest::Reporter* reporter,
812cb93a386Sopenharmony_ci                                         const std::function<GpuDstFactory<T>>& dstFactory,
813cb93a386Sopenharmony_ci                                         const std::function<GpuWriteDstFn<T>>& write,
814cb93a386Sopenharmony_ci                                         const std::function<GpuReadDstFn<T>>& read) {
815cb93a386Sopenharmony_ci    // Separate this out just to give it some line width to breathe.
816cb93a386Sopenharmony_ci    auto runTest = [&](const T& dst,
817cb93a386Sopenharmony_ci                       const SkImageInfo& dstInfo,
818cb93a386Sopenharmony_ci                       const SkPixmap& srcPixels,
819cb93a386Sopenharmony_ci                       SkIPoint offset) {
820cb93a386Sopenharmony_ci        const bool csConversion =
821cb93a386Sopenharmony_ci                !SkColorSpace::Equals(dstInfo.colorSpace(), srcPixels.info().colorSpace());
822cb93a386Sopenharmony_ci        const auto writeCT = srcPixels.colorType();
823cb93a386Sopenharmony_ci        const auto writeAT = srcPixels.alphaType();
824cb93a386Sopenharmony_ci        const auto dstCT = dstInfo.colorType();
825cb93a386Sopenharmony_ci        const auto dstAT = dstInfo.alphaType();
826cb93a386Sopenharmony_ci        const auto rect = SkIRect::MakePtSize(offset, srcPixels.dimensions());
827cb93a386Sopenharmony_ci        const auto surfBounds = SkIRect::MakeSize(dstInfo.dimensions());
828cb93a386Sopenharmony_ci
829cb93a386Sopenharmony_ci        // Do an initial read before the write.
830cb93a386Sopenharmony_ci        SkAutoPixmapStorage firstReadPM = read(dst);
831cb93a386Sopenharmony_ci        if (!firstReadPM.addr()) {
832cb93a386Sopenharmony_ci            // Particularly with GLES 2 we can have formats that are unreadable with our current
833cb93a386Sopenharmony_ci            // implementation of read pixels. If the format can't be attached to a FBO we don't have
834cb93a386Sopenharmony_ci            // a code path that draws it to another readable color type/format combo and reads from
835cb93a386Sopenharmony_ci            // that.
836cb93a386Sopenharmony_ci            return Result::kExcusedFailure;
837cb93a386Sopenharmony_ci        }
838cb93a386Sopenharmony_ci
839cb93a386Sopenharmony_ci        const Result result = write(dst, offset, srcPixels);
840cb93a386Sopenharmony_ci
841cb93a386Sopenharmony_ci        if (!SkIRect::Intersects(rect, surfBounds)) {
842cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
843cb93a386Sopenharmony_ci        } else if (writeCT == kUnknown_SkColorType) {
844cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
845cb93a386Sopenharmony_ci        } else if ((writeAT == kUnknown_SkAlphaType) != (dstAT == kUnknown_SkAlphaType)) {
846cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, result != Result::kSuccess);
847cb93a386Sopenharmony_ci        } else if (result == Result::kExcusedFailure) {
848cb93a386Sopenharmony_ci            return result;
849cb93a386Sopenharmony_ci        } else if (result == Result::kFail) {
850cb93a386Sopenharmony_ci            // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
851cb93a386Sopenharmony_ci            if (SkColorTypeToGrColorType(writeCT) != GrColorType::kUnknown) {
852cb93a386Sopenharmony_ci                ERRORF(reporter,
853cb93a386Sopenharmony_ci                       "Write failed. Write CT: %s, Write AT: %s Dst CT: %s, Dst AT: %s, "
854cb93a386Sopenharmony_ci                       "Rect [%d, %d, %d, %d], CS conversion: %d\n",
855cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(writeCT), ToolUtils::alphatype_name(writeAT),
856cb93a386Sopenharmony_ci                       ToolUtils::colortype_name(dstCT), ToolUtils::alphatype_name(dstAT),
857cb93a386Sopenharmony_ci                       rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
858cb93a386Sopenharmony_ci            }
859cb93a386Sopenharmony_ci            return result;
860cb93a386Sopenharmony_ci        }
861cb93a386Sopenharmony_ci
862cb93a386Sopenharmony_ci        SkIRect checkRect;
863cb93a386Sopenharmony_ci        if (result != Result::kSuccess || !checkRect.intersect(surfBounds, rect)) {
864cb93a386Sopenharmony_ci            return result;
865cb93a386Sopenharmony_ci        }
866cb93a386Sopenharmony_ci
867cb93a386Sopenharmony_ci        // Do an initial read before the write. We'll use this to verify that areas outside the
868cb93a386Sopenharmony_ci        // write are unaffected.
869cb93a386Sopenharmony_ci        SkAutoPixmapStorage secondReadPM = read(dst);
870cb93a386Sopenharmony_ci        if (!secondReadPM.addr()) {
871cb93a386Sopenharmony_ci            // The first read succeeded so this one should, too.
872cb93a386Sopenharmony_ci            ERRORF(reporter,
873cb93a386Sopenharmony_ci                   "could not read from dst (CT: %s, AT: %s)\n",
874cb93a386Sopenharmony_ci                   ToolUtils::colortype_name(dstCT),
875cb93a386Sopenharmony_ci                   ToolUtils::alphatype_name(dstAT));
876cb93a386Sopenharmony_ci            return Result::kFail;
877cb93a386Sopenharmony_ci        }
878cb93a386Sopenharmony_ci
879cb93a386Sopenharmony_ci        // Sometimes wider types go through 8bit unorm intermediates because of API
880cb93a386Sopenharmony_ci        // restrictions.
881cb93a386Sopenharmony_ci        int rgbBits = std::min({min_rgb_channel_bits(writeCT), min_rgb_channel_bits(dstCT), 8});
882cb93a386Sopenharmony_ci        float tol = 2.f/(1 << rgbBits);
883cb93a386Sopenharmony_ci        float alphaTol = 0;
884cb93a386Sopenharmony_ci        if (writeAT != kOpaque_SkAlphaType && dstAT != kOpaque_SkAlphaType) {
885cb93a386Sopenharmony_ci            // Alpha can also get squashed down to 8 bits going through an intermediate
886cb93a386Sopenharmony_ci            // color format.
887cb93a386Sopenharmony_ci            const int alphaBits = std::min({alpha_channel_bits(writeCT),
888cb93a386Sopenharmony_ci                                            alpha_channel_bits(dstCT),
889cb93a386Sopenharmony_ci                                            8});
890cb93a386Sopenharmony_ci            alphaTol = 2.f/(1 << alphaBits);
891cb93a386Sopenharmony_ci        }
892cb93a386Sopenharmony_ci
893cb93a386Sopenharmony_ci        const float tols[4] = {tol, tol, tol, alphaTol};
894cb93a386Sopenharmony_ci        auto error = std::function<ComparePixmapsErrorReporter>([&](int x,
895cb93a386Sopenharmony_ci                                                                    int y,
896cb93a386Sopenharmony_ci                                                                    const float diffs[4]) {
897cb93a386Sopenharmony_ci            SkASSERT(x >= 0 && y >= 0);
898cb93a386Sopenharmony_ci            ERRORF(reporter,
899cb93a386Sopenharmony_ci                   "Write CT: %s, Write AT: %s, Dst CT: %s, Dst AT: %s, Rect [%d, %d, %d, %d]"
900cb93a386Sopenharmony_ci                   ", CS conversion: %d\n"
901cb93a386Sopenharmony_ci                   "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
902cb93a386Sopenharmony_ci                   ToolUtils::colortype_name(writeCT),
903cb93a386Sopenharmony_ci                   ToolUtils::alphatype_name(writeAT),
904cb93a386Sopenharmony_ci                   ToolUtils::colortype_name(dstCT),
905cb93a386Sopenharmony_ci                   ToolUtils::alphatype_name(dstAT),
906cb93a386Sopenharmony_ci                   rect.fLeft,
907cb93a386Sopenharmony_ci                   rect.fTop,
908cb93a386Sopenharmony_ci                   rect.fRight,
909cb93a386Sopenharmony_ci                   rect.fBottom,
910cb93a386Sopenharmony_ci                   csConversion,
911cb93a386Sopenharmony_ci                   x,
912cb93a386Sopenharmony_ci                   y,
913cb93a386Sopenharmony_ci                   diffs[0],
914cb93a386Sopenharmony_ci                   diffs[1],
915cb93a386Sopenharmony_ci                   diffs[2],
916cb93a386Sopenharmony_ci                   diffs[3]);
917cb93a386Sopenharmony_ci        });
918cb93a386Sopenharmony_ci
919cb93a386Sopenharmony_ci        SkAutoPixmapStorage ref;
920cb93a386Sopenharmony_ci        ref.alloc(secondReadPM.info().makeDimensions(checkRect.size()));
921cb93a386Sopenharmony_ci        // Here we use the CPU backend to do the equivalent conversion as the write we're
922cb93a386Sopenharmony_ci        // testing, using kUnpremul instead of kUnknown since CPU requires a valid alpha type.
923cb93a386Sopenharmony_ci        SkAssertResult(make_pixmap_have_valid_alpha_type(srcPixels).readPixels(
924cb93a386Sopenharmony_ci                make_pixmap_have_valid_alpha_type(ref),
925cb93a386Sopenharmony_ci                std::max(0, -offset.fX),
926cb93a386Sopenharmony_ci                std::max(0, -offset.fY)));
927cb93a386Sopenharmony_ci        // This is the part of secondReadPixels that should have been updated by the write.
928cb93a386Sopenharmony_ci        SkPixmap actual;
929cb93a386Sopenharmony_ci        SkAssertResult(secondReadPM.extractSubset(&actual, checkRect));
930cb93a386Sopenharmony_ci        ComparePixels(ref, actual, tols, error);
931cb93a386Sopenharmony_ci        // The area around written rect should be the same in the first and second read.
932cb93a386Sopenharmony_ci        SkIRect borders[]{
933cb93a386Sopenharmony_ci                {               0,                 0, secondReadPM.width(), secondReadPM.height()},
934cb93a386Sopenharmony_ci                {checkRect.fRight,                 0,      checkRect.fLeft, secondReadPM.height()},
935cb93a386Sopenharmony_ci                { checkRect.fLeft,                 0,     checkRect.fRight,        checkRect.fTop},
936cb93a386Sopenharmony_ci                { checkRect.fLeft, checkRect.fBottom,     checkRect.fRight, secondReadPM.height()}
937cb93a386Sopenharmony_ci        };
938cb93a386Sopenharmony_ci        for (const auto r : borders) {
939cb93a386Sopenharmony_ci            if (!r.isEmpty()) {
940cb93a386Sopenharmony_ci                // Make a copy because MSVC for some reason doesn't correctly capture 'r'.
941cb93a386Sopenharmony_ci                SkIPoint tl = r.topLeft();
942cb93a386Sopenharmony_ci                auto guardError = std::function<ComparePixmapsErrorReporter>(
943cb93a386Sopenharmony_ci                        [&](int x, int y, const float diffs[4]) {
944cb93a386Sopenharmony_ci                            x += tl.x();
945cb93a386Sopenharmony_ci                            y += tl.y();
946cb93a386Sopenharmony_ci                            ERRORF(reporter,
947cb93a386Sopenharmony_ci                                   "Write CT: %s, Write AT: %s, Dst CT: %s, Dst AT: %s,"
948cb93a386Sopenharmony_ci                                   "Rect [%d, %d, %d, %d], CS conversion: %d\n"
949cb93a386Sopenharmony_ci                                   "Error in guard region %d, %d. Diff in floats: (%f, %f, %f, %f)",
950cb93a386Sopenharmony_ci                                   ToolUtils::colortype_name(writeCT),
951cb93a386Sopenharmony_ci                                   ToolUtils::alphatype_name(writeAT),
952cb93a386Sopenharmony_ci                                   ToolUtils::colortype_name(dstCT),
953cb93a386Sopenharmony_ci                                   ToolUtils::alphatype_name(dstAT),
954cb93a386Sopenharmony_ci                                   rect.fLeft,
955cb93a386Sopenharmony_ci                                   rect.fTop,
956cb93a386Sopenharmony_ci                                   rect.fRight,
957cb93a386Sopenharmony_ci                                   rect.fBottom,
958cb93a386Sopenharmony_ci                                   csConversion,
959cb93a386Sopenharmony_ci                                   x,
960cb93a386Sopenharmony_ci                                   y,
961cb93a386Sopenharmony_ci                                   diffs[0],
962cb93a386Sopenharmony_ci                                   diffs[1],
963cb93a386Sopenharmony_ci                                   diffs[2],
964cb93a386Sopenharmony_ci                                   diffs[3]);
965cb93a386Sopenharmony_ci                        });
966cb93a386Sopenharmony_ci                SkPixmap a, b;
967cb93a386Sopenharmony_ci                SkAssertResult(firstReadPM.extractSubset(&a, r));
968cb93a386Sopenharmony_ci                SkAssertResult(firstReadPM.extractSubset(&b, r));
969cb93a386Sopenharmony_ci                float zeroTols[4] = {};
970cb93a386Sopenharmony_ci                ComparePixels(a, b, zeroTols, guardError);
971cb93a386Sopenharmony_ci            }
972cb93a386Sopenharmony_ci        }
973cb93a386Sopenharmony_ci        return result;
974cb93a386Sopenharmony_ci    };
975cb93a386Sopenharmony_ci
976cb93a386Sopenharmony_ci    static constexpr int kW = 16;
977cb93a386Sopenharmony_ci    static constexpr int kH = 16;
978cb93a386Sopenharmony_ci
979cb93a386Sopenharmony_ci    const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
980cb93a386Sopenharmony_ci    const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
981cb93a386Sopenharmony_ci
982cb93a386Sopenharmony_ci    // We ensure we use the long array once per src and read color type and otherwise use the
983cb93a386Sopenharmony_ci    // short array to improve test run time.
984cb93a386Sopenharmony_ci    // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
985cb93a386Sopenharmony_ci    // equivalent. Just ensure each redundant AT is tested once with each CT (dst and write).
986cb93a386Sopenharmony_ci    // Similarly, alpha-only color types behave the same for all alpha types so just test premul
987cb93a386Sopenharmony_ci    // after one iter.
988cb93a386Sopenharmony_ci    // We consider a dst or write CT thoroughly tested once it has run through the long rect array
989cb93a386Sopenharmony_ci    // and full complement of alpha types with one successful read in the loop.
990cb93a386Sopenharmony_ci    std::array<bool, kLastEnum_SkColorType + 1> dstCTTestedThoroughly   = {},
991cb93a386Sopenharmony_ci                                                writeCTTestedThoroughly = {};
992cb93a386Sopenharmony_ci    for (int dat = 0; dat < kLastEnum_SkAlphaType; ++dat) {
993cb93a386Sopenharmony_ci        const auto dstAT = static_cast<SkAlphaType>(dat);
994cb93a386Sopenharmony_ci        for (int dct = 0; dct <= kLastEnum_SkColorType; ++dct) {
995cb93a386Sopenharmony_ci            const auto dstCT = static_cast<SkColorType>(dct);
996cb93a386Sopenharmony_ci            const auto dstInfo = SkImageInfo::Make(kW, kH, dstCT, dstAT, SkColorSpace::MakeSRGB());
997cb93a386Sopenharmony_ci            auto dst = dstFactory(dstInfo);
998cb93a386Sopenharmony_ci            if (!dst) {
999cb93a386Sopenharmony_ci                continue;
1000cb93a386Sopenharmony_ci            }
1001cb93a386Sopenharmony_ci            if (SkColorTypeIsAlwaysOpaque(dstCT) && dstCTTestedThoroughly[dstCT] &&
1002cb93a386Sopenharmony_ci                (kPremul_SkAlphaType == dstAT || kUnpremul_SkAlphaType == dstAT)) {
1003cb93a386Sopenharmony_ci                continue;
1004cb93a386Sopenharmony_ci            }
1005cb93a386Sopenharmony_ci            if (SkColorTypeIsAlphaOnly(dstCT) && dstCTTestedThoroughly[dstCT] &&
1006cb93a386Sopenharmony_ci                (kUnpremul_SkAlphaType == dstAT ||
1007cb93a386Sopenharmony_ci                 kOpaque_SkAlphaType   == dstAT ||
1008cb93a386Sopenharmony_ci                 kUnknown_SkAlphaType  == dstAT)) {
1009cb93a386Sopenharmony_ci                continue;
1010cb93a386Sopenharmony_ci            }
1011cb93a386Sopenharmony_ci            for (int wct = 0; wct <= kLastEnum_SkColorType; ++wct) {
1012cb93a386Sopenharmony_ci                const auto writeCT = static_cast<SkColorType>(wct);
1013cb93a386Sopenharmony_ci                for (const sk_sp<SkColorSpace>& writeCS : {SkColorSpace::MakeSRGB(),
1014cb93a386Sopenharmony_ci                                                           SkColorSpace::MakeSRGBLinear()}) {
1015cb93a386Sopenharmony_ci                    for (int wat = 0; wat <= kLastEnum_SkAlphaType; ++wat) {
1016cb93a386Sopenharmony_ci                        const auto writeAT = static_cast<SkAlphaType>(wat);
1017cb93a386Sopenharmony_ci                        if (writeAT != kOpaque_SkAlphaType && dstAT == kOpaque_SkAlphaType) {
1018cb93a386Sopenharmony_ci                            // This doesn't make sense.
1019cb93a386Sopenharmony_ci                            continue;
1020cb93a386Sopenharmony_ci                        }
1021cb93a386Sopenharmony_ci                        if (SkColorTypeIsAlwaysOpaque(writeCT) &&
1022cb93a386Sopenharmony_ci                            writeCTTestedThoroughly[writeCT] &&
1023cb93a386Sopenharmony_ci                            (kPremul_SkAlphaType == writeAT || kUnpremul_SkAlphaType == writeAT)) {
1024cb93a386Sopenharmony_ci                            continue;
1025cb93a386Sopenharmony_ci                        }
1026cb93a386Sopenharmony_ci                        if (SkColorTypeIsAlphaOnly(writeCT) && writeCTTestedThoroughly[writeCT] &&
1027cb93a386Sopenharmony_ci                            (kUnpremul_SkAlphaType == writeAT ||
1028cb93a386Sopenharmony_ci                             kOpaque_SkAlphaType   == writeAT ||
1029cb93a386Sopenharmony_ci                             kUnknown_SkAlphaType  == writeAT)) {
1030cb93a386Sopenharmony_ci                            continue;
1031cb93a386Sopenharmony_ci                        }
1032cb93a386Sopenharmony_ci                        const auto& rects =
1033cb93a386Sopenharmony_ci                                dstCTTestedThoroughly[dct] && writeCTTestedThoroughly[wct]
1034cb93a386Sopenharmony_ci                                        ? shortRectArray
1035cb93a386Sopenharmony_ci                                        : longRectArray;
1036cb93a386Sopenharmony_ci                        for (const auto& rect : rects) {
1037cb93a386Sopenharmony_ci                            auto writeInfo = SkImageInfo::Make(rect.size(),
1038cb93a386Sopenharmony_ci                                                               writeCT,
1039cb93a386Sopenharmony_ci                                                               writeAT,
1040cb93a386Sopenharmony_ci                                                               writeCS);
1041cb93a386Sopenharmony_ci                            // CPU and GPU handle 1010102 differently. CPU clamps RGB to A, GPU
1042cb93a386Sopenharmony_ci                            // doesn't.
1043cb93a386Sopenharmony_ci                            bool forceOpaque = writeCT == kRGBA_1010102_SkColorType ||
1044cb93a386Sopenharmony_ci                                               writeCT == kBGRA_1010102_SkColorType;
1045cb93a386Sopenharmony_ci                            SkAutoPixmapStorage writePixels = make_ref_data(writeInfo, forceOpaque);
1046cb93a386Sopenharmony_ci                            const SkIPoint offset = rect.topLeft();
1047cb93a386Sopenharmony_ci                            Result r = runTest(dst, dstInfo, writePixels, offset);
1048cb93a386Sopenharmony_ci                            if (r == Result::kSuccess) {
1049cb93a386Sopenharmony_ci                                dstCTTestedThoroughly[dct] = true;
1050cb93a386Sopenharmony_ci                                writeCTTestedThoroughly[wct] = true;
1051cb93a386Sopenharmony_ci                            }
1052cb93a386Sopenharmony_ci                        }
1053cb93a386Sopenharmony_ci                    }
1054cb93a386Sopenharmony_ci                }
1055cb93a386Sopenharmony_ci            }
1056cb93a386Sopenharmony_ci        }
1057cb93a386Sopenharmony_ci    }
1058cb93a386Sopenharmony_ci}
1059cb93a386Sopenharmony_ci
1060cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels, reporter, ctxInfo) {
1061cb93a386Sopenharmony_ci    using Surface = std::unique_ptr<skgpu::SurfaceContext>;
1062cb93a386Sopenharmony_ci    GrDirectContext* direct = ctxInfo.directContext();
1063cb93a386Sopenharmony_ci    auto writer = std::function<GpuWriteDstFn<Surface>>(
1064cb93a386Sopenharmony_ci            [direct](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
1065cb93a386Sopenharmony_ci                if (surface->writePixels(direct, pixels, offset)) {
1066cb93a386Sopenharmony_ci                    return Result::kSuccess;
1067cb93a386Sopenharmony_ci                } else {
1068cb93a386Sopenharmony_ci                    return Result::kFail;
1069cb93a386Sopenharmony_ci                }
1070cb93a386Sopenharmony_ci            });
1071cb93a386Sopenharmony_ci    auto reader = std::function<GpuReadDstFn<Surface>>([direct](const Surface& s) {
1072cb93a386Sopenharmony_ci        SkAutoPixmapStorage result;
1073cb93a386Sopenharmony_ci        auto grInfo = s->imageInfo();
1074cb93a386Sopenharmony_ci        SkColorType ct = GrColorTypeToSkColorType(grInfo.colorType());
1075cb93a386Sopenharmony_ci        SkASSERT(ct != kUnknown_SkColorType);
1076cb93a386Sopenharmony_ci        auto skInfo = SkImageInfo::Make(grInfo.dimensions(), ct, grInfo.alphaType(),
1077cb93a386Sopenharmony_ci                                        grInfo.refColorSpace());
1078cb93a386Sopenharmony_ci        result.alloc(skInfo);
1079cb93a386Sopenharmony_ci        if (!s->readPixels(direct, result, {0, 0})) {
1080cb93a386Sopenharmony_ci            SkAutoPixmapStorage badResult;
1081cb93a386Sopenharmony_ci            return badResult;
1082cb93a386Sopenharmony_ci        }
1083cb93a386Sopenharmony_ci        return result;
1084cb93a386Sopenharmony_ci    });
1085cb93a386Sopenharmony_ci
1086cb93a386Sopenharmony_ci    for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
1087cb93a386Sopenharmony_ci        for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
1088cb93a386Sopenharmony_ci            auto factory = std::function<GpuDstFactory<Surface>>(
1089cb93a386Sopenharmony_ci                    [direct, origin, renderable](const SkImageInfo& info) {
1090cb93a386Sopenharmony_ci                        return CreateSurfaceContext(direct,
1091cb93a386Sopenharmony_ci                                                    info,
1092cb93a386Sopenharmony_ci                                                    SkBackingFit::kExact,
1093cb93a386Sopenharmony_ci                                                    origin,
1094cb93a386Sopenharmony_ci                                                    renderable);
1095cb93a386Sopenharmony_ci                    });
1096cb93a386Sopenharmony_ci
1097cb93a386Sopenharmony_ci            gpu_write_pixels_test_driver(reporter, factory, writer, reader);
1098cb93a386Sopenharmony_ci        }
1099cb93a386Sopenharmony_ci    }
1100cb93a386Sopenharmony_ci}
1101cb93a386Sopenharmony_ci
1102cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixelsMipped, reporter, ctxInfo) {
1103cb93a386Sopenharmony_ci    auto direct = ctxInfo.directContext();
1104cb93a386Sopenharmony_ci    if (!direct->priv().caps()->mipmapSupport()) {
1105cb93a386Sopenharmony_ci        return;
1106cb93a386Sopenharmony_ci    }
1107cb93a386Sopenharmony_ci    static constexpr int kW = 25,
1108cb93a386Sopenharmony_ci                         kH = 37;
1109cb93a386Sopenharmony_ci    SkAutoPixmapStorage refP = make_ref_data(SkImageInfo::Make({kW, kH},
1110cb93a386Sopenharmony_ci                                                               kRGBA_F32_SkColorType,
1111cb93a386Sopenharmony_ci                                                               kPremul_SkAlphaType,
1112cb93a386Sopenharmony_ci                                                               nullptr),
1113cb93a386Sopenharmony_ci                                             false);
1114cb93a386Sopenharmony_ci    SkAutoPixmapStorage refO = make_ref_data(SkImageInfo::Make({kW, kH},
1115cb93a386Sopenharmony_ci                                                               kRGBA_F32_SkColorType,
1116cb93a386Sopenharmony_ci                                                               kOpaque_SkAlphaType,
1117cb93a386Sopenharmony_ci                                                               nullptr),
1118cb93a386Sopenharmony_ci                                             true);
1119cb93a386Sopenharmony_ci
1120cb93a386Sopenharmony_ci    for (int c = 0; c < kGrColorTypeCnt; ++c) {
1121cb93a386Sopenharmony_ci        auto ct = static_cast<GrColorType>(c);
1122cb93a386Sopenharmony_ci        // Below we use rendering to read the level pixels back.
1123cb93a386Sopenharmony_ci        auto format = direct->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
1124cb93a386Sopenharmony_ci        if (!format.isValid()) {
1125cb93a386Sopenharmony_ci            continue;
1126cb93a386Sopenharmony_ci        }
1127cb93a386Sopenharmony_ci        SkAlphaType at = GrColorTypeHasAlpha(ct) ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
1128cb93a386Sopenharmony_ci        GrImageInfo info(ct, at, nullptr, kW, kH);
1129cb93a386Sopenharmony_ci        SkTArray<GrCPixmap> levels;
1130cb93a386Sopenharmony_ci        const auto& ref = at == kPremul_SkAlphaType ? refP : refO;
1131cb93a386Sopenharmony_ci        for (int w = kW, h = kH; w || h; w/=2, h/=2) {
1132cb93a386Sopenharmony_ci            auto level = GrPixmap::Allocate(info.makeWH(std::max(w, 1), std::max(h, 1)));
1133cb93a386Sopenharmony_ci            SkPixmap src;
1134cb93a386Sopenharmony_ci            SkAssertResult(ref.extractSubset(&src, SkIRect::MakeSize(level.dimensions())));
1135cb93a386Sopenharmony_ci            SkAssertResult(GrConvertPixels(level, src));
1136cb93a386Sopenharmony_ci            levels.push_back(level);
1137cb93a386Sopenharmony_ci        }
1138cb93a386Sopenharmony_ci
1139cb93a386Sopenharmony_ci        for (bool unowned : {false, true}) { // test a GrCPixmap that doesn't own its storage.
1140cb93a386Sopenharmony_ci            for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
1141cb93a386Sopenharmony_ci                for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin,
1142cb93a386Sopenharmony_ci                                               kBottomLeft_GrSurfaceOrigin}) {
1143cb93a386Sopenharmony_ci                    auto sc = CreateSurfaceContext(direct,
1144cb93a386Sopenharmony_ci                                                   info,
1145cb93a386Sopenharmony_ci                                                   SkBackingFit::kExact,
1146cb93a386Sopenharmony_ci                                                   origin,
1147cb93a386Sopenharmony_ci                                                   renderable,
1148cb93a386Sopenharmony_ci                                                   /*sample count*/ 1,
1149cb93a386Sopenharmony_ci                                                   GrMipmapped::kYes);
1150cb93a386Sopenharmony_ci                    if (!sc) {
1151cb93a386Sopenharmony_ci                        continue;
1152cb93a386Sopenharmony_ci                    }
1153cb93a386Sopenharmony_ci                    // Keeps pixels in unowned case alive until after writePixels is called but no
1154cb93a386Sopenharmony_ci                    // longer.
1155cb93a386Sopenharmony_ci                    GrPixmap keepAlive;
1156cb93a386Sopenharmony_ci                    GrCPixmap savedLevel = levels[1];
1157cb93a386Sopenharmony_ci                    if (unowned) {
1158cb93a386Sopenharmony_ci                        // Also test non-tight row bytes with the unowned pixmap, bump width by 1.
1159cb93a386Sopenharmony_ci                        int w = levels[1].width() + 1;
1160cb93a386Sopenharmony_ci                        int h = levels[1].height();
1161cb93a386Sopenharmony_ci                        keepAlive = GrPixmap::Allocate(levels[1].info().makeWH(w, h));
1162cb93a386Sopenharmony_ci                        SkPixmap src;
1163cb93a386Sopenharmony_ci                        // These pixel values will be the same as the original level 1.
1164cb93a386Sopenharmony_ci                        SkAssertResult(ref.extractSubset(&src, SkIRect::MakeWH(w, h)));
1165cb93a386Sopenharmony_ci                        SkAssertResult(GrConvertPixels(keepAlive, src));
1166cb93a386Sopenharmony_ci                        levels[1] = GrCPixmap(levels[1].info(),
1167cb93a386Sopenharmony_ci                                              keepAlive.addr(),
1168cb93a386Sopenharmony_ci                                              keepAlive.rowBytes());
1169cb93a386Sopenharmony_ci                    }
1170cb93a386Sopenharmony_ci                    // Going through intermediate textures is not supported for MIP levels (because
1171cb93a386Sopenharmony_ci                    // we don't support rendering to non-base levels). So it's hard to have any hard
1172cb93a386Sopenharmony_ci                    // rules about when we expect success.
1173cb93a386Sopenharmony_ci                    if (!sc->writePixels(direct, levels.begin(), levels.count())) {
1174cb93a386Sopenharmony_ci                        continue;
1175cb93a386Sopenharmony_ci                    }
1176cb93a386Sopenharmony_ci                    // Make sure the pixels from the unowned pixmap are released and then put the
1177cb93a386Sopenharmony_ci                    // original level back in for the comparison after the read below.
1178cb93a386Sopenharmony_ci                    keepAlive = {};
1179cb93a386Sopenharmony_ci                    levels[1] = savedLevel;
1180cb93a386Sopenharmony_ci
1181cb93a386Sopenharmony_ci                    // TODO: Update this when read pixels supports reading back levels to read
1182cb93a386Sopenharmony_ci                    // directly rather than using minimizing draws.
1183cb93a386Sopenharmony_ci                    auto dstSC = CreateSurfaceContext(direct,
1184cb93a386Sopenharmony_ci                                                      info,
1185cb93a386Sopenharmony_ci                                                      SkBackingFit::kExact,
1186cb93a386Sopenharmony_ci                                                      kBottomLeft_GrSurfaceOrigin,
1187cb93a386Sopenharmony_ci                                                      GrRenderable::kYes);
1188cb93a386Sopenharmony_ci                    SkASSERT(dstSC);
1189cb93a386Sopenharmony_ci                    GrSamplerState sampler(SkFilterMode::kNearest, SkMipmapMode::kNearest);
1190cb93a386Sopenharmony_ci                    for (int i = 1; i <= 1; ++i) {
1191cb93a386Sopenharmony_ci                        auto te = GrTextureEffect::Make(sc->readSurfaceView(),
1192cb93a386Sopenharmony_ci                                                        info.alphaType(),
1193cb93a386Sopenharmony_ci                                                        SkMatrix::I(),
1194cb93a386Sopenharmony_ci                                                        sampler,
1195cb93a386Sopenharmony_ci                                                        *direct->priv().caps());
1196cb93a386Sopenharmony_ci                        dstSC->asFillContext()->fillRectToRectWithFP(
1197cb93a386Sopenharmony_ci                                SkIRect::MakeSize(sc->dimensions()),
1198cb93a386Sopenharmony_ci                                SkIRect::MakeSize(levels[i].dimensions()),
1199cb93a386Sopenharmony_ci                                std::move(te));
1200cb93a386Sopenharmony_ci                        GrImageInfo readInfo =
1201cb93a386Sopenharmony_ci                                dstSC->imageInfo().makeDimensions(levels[i].dimensions());
1202cb93a386Sopenharmony_ci                        GrPixmap read = GrPixmap::Allocate(readInfo);
1203cb93a386Sopenharmony_ci                        if (!dstSC->readPixels(direct, read, {0, 0})) {
1204cb93a386Sopenharmony_ci                            continue;
1205cb93a386Sopenharmony_ci                        }
1206cb93a386Sopenharmony_ci
1207cb93a386Sopenharmony_ci                        auto skCT = GrColorTypeToSkColorType(info.colorType());
1208cb93a386Sopenharmony_ci                        int rgbBits = std::min(min_rgb_channel_bits(skCT), 8);
1209cb93a386Sopenharmony_ci                        float rgbTol = 2.f / ((1 << rgbBits) - 1);
1210cb93a386Sopenharmony_ci                        int alphaBits = std::min(alpha_channel_bits(skCT), 8);
1211cb93a386Sopenharmony_ci                        float alphaTol = 2.f / ((1 << alphaBits) - 1);
1212cb93a386Sopenharmony_ci                        float tol[] = {rgbTol, rgbTol, rgbTol, alphaTol};
1213cb93a386Sopenharmony_ci
1214cb93a386Sopenharmony_ci                        GrCPixmap a = levels[i];
1215cb93a386Sopenharmony_ci                        GrCPixmap b = read;
1216cb93a386Sopenharmony_ci                        // The compare code will linearize when reading the srgb data. This will
1217cb93a386Sopenharmony_ci                        // magnify differences at the high end. Rather than adjusting the tolerance
1218cb93a386Sopenharmony_ci                        // to compensate we do the comparison without going through srgb->linear.
1219cb93a386Sopenharmony_ci                        if (ct == GrColorType::kRGBA_8888_SRGB) {
1220cb93a386Sopenharmony_ci                            a = GrCPixmap(a.info().makeColorType(GrColorType::kRGBA_8888),
1221cb93a386Sopenharmony_ci                                          a.addr(),
1222cb93a386Sopenharmony_ci                                          a.rowBytes());
1223cb93a386Sopenharmony_ci                            b = GrCPixmap(b.info().makeColorType(GrColorType::kRGBA_8888),
1224cb93a386Sopenharmony_ci                                          b.addr(),
1225cb93a386Sopenharmony_ci                                          b.rowBytes());
1226cb93a386Sopenharmony_ci                        }
1227cb93a386Sopenharmony_ci
1228cb93a386Sopenharmony_ci                        auto error = std::function<ComparePixmapsErrorReporter>(
1229cb93a386Sopenharmony_ci                                [&](int x, int y, const float diffs[4]) {
1230cb93a386Sopenharmony_ci                                    SkASSERT(x >= 0 && y >= 0);
1231cb93a386Sopenharmony_ci                                    ERRORF(reporter,
1232cb93a386Sopenharmony_ci                                           "CT: %s, Level %d, Unowned: %d. "
1233cb93a386Sopenharmony_ci                                           "Error at %d, %d. Diff in floats:"
1234cb93a386Sopenharmony_ci                                           "(%f, %f, %f, %f)",
1235cb93a386Sopenharmony_ci                                           GrColorTypeToStr(info.colorType()), i, unowned, x, y,
1236cb93a386Sopenharmony_ci                                           diffs[0], diffs[1], diffs[2], diffs[3]);
1237cb93a386Sopenharmony_ci                                });
1238cb93a386Sopenharmony_ci                        ComparePixels(a, b, tol, error);
1239cb93a386Sopenharmony_ci                    }
1240cb93a386Sopenharmony_ci                }
1241cb93a386Sopenharmony_ci            }
1242cb93a386Sopenharmony_ci        }
1243cb93a386Sopenharmony_ci    }
1244cb93a386Sopenharmony_ci}
1245cb93a386Sopenharmony_ci
1246cb93a386Sopenharmony_ci// Tests a bug found in OOP-R canvas2d in Chrome. The GPU backend would incorrectly not bind
1247cb93a386Sopenharmony_ci// buffer 0 to GL_PIXEL_PACK_BUFFER before a glReadPixels() that was supposed to read into
1248cb93a386Sopenharmony_ci// client memory if a GrDirectContext::resetContext() occurred.
1249cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(GLReadPixelsUnbindPBO, reporter, ctxInfo) {
1250cb93a386Sopenharmony_ci    // Start with a async read so that we bind to GL_PIXEL_PACK_BUFFER.
1251cb93a386Sopenharmony_ci    auto info = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
1252cb93a386Sopenharmony_ci    SkAutoPixmapStorage pmap = make_ref_data(info, /*forceOpaque=*/false);
1253cb93a386Sopenharmony_ci    auto image = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
1254cb93a386Sopenharmony_ci    image = image->makeTextureImage(ctxInfo.directContext());
1255cb93a386Sopenharmony_ci    if (!image) {
1256cb93a386Sopenharmony_ci        ERRORF(reporter, "Couldn't make texture image.");
1257cb93a386Sopenharmony_ci        return;
1258cb93a386Sopenharmony_ci    }
1259cb93a386Sopenharmony_ci
1260cb93a386Sopenharmony_ci    AsyncContext asyncContext;
1261cb93a386Sopenharmony_ci    image->asyncRescaleAndReadPixels(info,
1262cb93a386Sopenharmony_ci                                     SkIRect::MakeSize(info.dimensions()),
1263cb93a386Sopenharmony_ci                                     SkImage::RescaleGamma::kSrc,
1264cb93a386Sopenharmony_ci                                     SkImage::RescaleMode::kNearest,
1265cb93a386Sopenharmony_ci                                     async_callback,
1266cb93a386Sopenharmony_ci                                     &asyncContext);
1267cb93a386Sopenharmony_ci
1268cb93a386Sopenharmony_ci    // This will force the async readback to finish.
1269cb93a386Sopenharmony_ci    ctxInfo.directContext()->flushAndSubmit(true);
1270cb93a386Sopenharmony_ci    if (!asyncContext.fCalled) {
1271cb93a386Sopenharmony_ci        ERRORF(reporter, "async_callback not called.");
1272cb93a386Sopenharmony_ci    }
1273cb93a386Sopenharmony_ci    if (!asyncContext.fResult) {
1274cb93a386Sopenharmony_ci        ERRORF(reporter, "async read failed.");
1275cb93a386Sopenharmony_ci    }
1276cb93a386Sopenharmony_ci
1277cb93a386Sopenharmony_ci    SkPixmap asyncResult(info, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0));
1278cb93a386Sopenharmony_ci
1279cb93a386Sopenharmony_ci    // Bug was that this would cause GrGLGpu to think no buffer was left bound to
1280cb93a386Sopenharmony_ci    // GL_PIXEL_PACK_BUFFER even though async transfer did leave one bound. So the sync read
1281cb93a386Sopenharmony_ci    // wouldn't bind buffer 0.
1282cb93a386Sopenharmony_ci    ctxInfo.directContext()->resetContext();
1283cb93a386Sopenharmony_ci
1284cb93a386Sopenharmony_ci    SkBitmap syncResult;
1285cb93a386Sopenharmony_ci    syncResult.allocPixels(info);
1286cb93a386Sopenharmony_ci    syncResult.eraseARGB(0xFF, 0xFF, 0xFF, 0xFF);
1287cb93a386Sopenharmony_ci
1288cb93a386Sopenharmony_ci    image->readPixels(ctxInfo.directContext(), syncResult.pixmap(), 0, 0);
1289cb93a386Sopenharmony_ci
1290cb93a386Sopenharmony_ci    float tol[4] = {};  // expect exactly same pixels, no conversions.
1291cb93a386Sopenharmony_ci    auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
1292cb93a386Sopenharmony_ci                                                                const float diffs[4]) {
1293cb93a386Sopenharmony_ci      SkASSERT(x >= 0 && y >= 0);
1294cb93a386Sopenharmony_ci      ERRORF(reporter, "Expect sync and async read to be the same. "
1295cb93a386Sopenharmony_ci             "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
1296cb93a386Sopenharmony_ci             x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
1297cb93a386Sopenharmony_ci    });
1298cb93a386Sopenharmony_ci
1299cb93a386Sopenharmony_ci    ComparePixels(syncResult.pixmap(), asyncResult, tol, error);
1300cb93a386Sopenharmony_ci}
1301