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