Make pixel comparison utility in ReadPixelsTest shareable

Also make it support GrColorType

Change-Id: I2aecb82dd1b8e3bc942549f2023ff5cae9deb4f3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/227403
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2019-07-15 12:30:44 -04:00 committed by Skia Commit-Bot
parent acf98df7a1
commit 85aeccfb9d
3 changed files with 98 additions and 40 deletions

View File

@ -19,6 +19,7 @@
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/SkGr.h"
#include "tests/Test.h"
#include "tests/TestUtils.h"
#include "tools/gpu/GrContextFactory.h"
#include "tools/gpu/ProxyUtils.h"
@ -619,45 +620,6 @@ DEF_TEST(ReadPixels_ValidConversion, reporter) {
}
}
namespace {
using ComparePixmapsErrorReporter = void(int x, int y, const float diffs[4]);
} // anonymous namespace
static void compare_pixmaps(const SkPixmap& a, const SkPixmap& b, const float tol[4],
std::function<ComparePixmapsErrorReporter>& error) {
if (a.width() != b.width() || a.height() != b.height()) {
static constexpr float kDummyDiffs[4] = {};
error(-1, -1, kDummyDiffs);
return;
}
SkAutoPixmapStorage afloat;
SkAutoPixmapStorage bfloat;
afloat.alloc(a.info().makeColorType(kRGBA_F32_SkColorType));
bfloat.alloc(b.info().makeColorType(kRGBA_F32_SkColorType));
SkConvertPixels(afloat.info(), afloat.writable_addr(), afloat.rowBytes(), a.info(), a.addr(),
a.rowBytes());
SkConvertPixels(bfloat.info(), bfloat.writable_addr(), bfloat.rowBytes(), b.info(), b.addr(),
b.rowBytes());
for (int y = 0; y < a.height(); ++y) {
for (int x = 0; x < a.width(); ++x) {
const float* rgbaA = static_cast<const float*>(afloat.addr(x, y));
const float* rgbaB = static_cast<const float*>(bfloat.addr(x, y));
float diffs[4];
bool bad = false;
for (int i = 0; i < 4; ++i) {
diffs[i] = rgbaB[i] - rgbaA[i];
if (std::abs(diffs[i]) > tol[i]) {
bad = true;
}
}
if (bad) {
error(x, y, diffs);
return;
}
}
}
}
static int min_rgb_channel_bits(SkColorType ct) {
switch (ct) {
case kUnknown_SkColorType: return 0;
@ -781,6 +743,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
const float tols[4] = {tol, tol, tol, 0};
auto error = std::function<ComparePixmapsErrorReporter>(
[&](int x, int y, const float diffs[4]) {
SkASSERT(x >= 0 && y >= 0);
ERRORF(reporter,
"Surf Color Type: %d, Read CT: %d, Rect [%d, %d, %d, %d]"
", origin: %d, CS conversion: %d\n"
@ -789,7 +752,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
rect.fBottom, origin, (bool)readCS, x, y, diffs[0],
diffs[1], diffs[2], diffs[3]);
});
compare_pixmaps(ref, result, tols, error);
compare_pixels(ref, result, tols, error);
}
}
}

View File

@ -172,6 +172,70 @@ bool bitmap_to_base64_data_uri(const SkBitmap& bitmap, SkString* dst) {
return true;
}
bool compare_pixels(const GrPixelInfo& infoA, const char* a, size_t rowBytesA,
const GrPixelInfo& infoB, const char* b, size_t rowBytesB,
const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
if (infoA.width() != infoB.width() || infoA.height() != infoB.height()) {
static constexpr float kDummyDiffs[4] = {};
error(-1, -1, kDummyDiffs);
return false;
}
SkAlphaType floatAlphaType = infoA.alphaType();
// If one is premul and the other is unpremul we do the comparison in premul space.
if ((infoA.alphaType() == kPremul_SkAlphaType ||
infoB.alphaType() == kPremul_SkAlphaType) &&
(infoA.alphaType() == kUnpremul_SkAlphaType ||
infoB.alphaType() == kUnpremul_SkAlphaType)) {
floatAlphaType = kPremul_SkAlphaType;
}
sk_sp<SkColorSpace> floatCS;
if (SkColorSpace::Equals(infoA.colorSpace(), infoB.colorSpace())) {
floatCS = infoA.refColorSpace();
} else {
floatCS = SkColorSpace::MakeSRGBLinear();
}
GrPixelInfo floatInfo(GrColorType::kRGBA_F32, floatAlphaType, std::move(floatCS),
infoA.width(), infoA.height());
size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
size_t floatRowBytes = floatBpp * infoA.width();
std::unique_ptr<char[]> floatA(new char[floatRowBytes * infoA.height()]);
std::unique_ptr<char[]> floatB(new char[floatRowBytes * infoA.height()]);
SkAssertResult(GrConvertPixels(floatInfo, floatA.get(), floatRowBytes, infoA, a, rowBytesA));
SkAssertResult(GrConvertPixels(floatInfo, floatB.get(), floatRowBytes, infoB, b, rowBytesB));
auto at = [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
};
for (int y = 0; y < infoA.height(); ++y) {
for (int x = 0; x < infoA.width(); ++x) {
const float* rgbaA = at(floatA.get(), x, y);
const float* rgbaB = at(floatB.get(), x, y);
float diffs[4];
bool bad = false;
for (int i = 0; i < 4; ++i) {
diffs[i] = rgbaB[i] - rgbaA[i];
if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
bad = true;
}
}
if (bad) {
error(x, y, diffs);
return false;
}
}
}
return true;
}
bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
std::function<ComparePixmapsErrorReporter>& error) {
return compare_pixels(a.info(), static_cast<const char*>(a.addr()), a.rowBytes(),
b.info(), static_cast<const char*>(b.addr()), b.rowBytes(),
tolRGBA, error);
}
#include "src/utils/SkCharToGlyphCache.h"
static SkGlyphID hash_to_glyph(uint32_t value) {

View File

@ -6,6 +6,7 @@
*/
#include "include/core/SkBitmap.h"
#include "src/gpu/GrDataUtils.h"
#include "tests/Test.h"
class GrSurfaceContext;
@ -44,3 +45,33 @@ bool does_full_buffer_contain_correct_color(const GrColor* srcBuffer, const GrCo
// Encodes the bitmap into a data:/image/png;base64,... url suitable to view in a browser after
// printing to a log. If false is returned, dst holds an error message instead of a URI.
bool bitmap_to_base64_data_uri(const SkBitmap& bitmap, SkString* dst);
/** Used by compare_pixels. */
using ComparePixmapsErrorReporter = void(int x, int y, const float diffs[4]);
/**
* Compares pixels pointed to by 'a' with 'infoA' and rowBytesA to pixels pointed to by 'b' with
* 'infoB' and 'rowBytesB'.
*
* If the infos have different dimensions error is called with negative coordinate values and
* zero diffs and no comparisons are made.
*
* Before comparison pixels are converted to a common color type, alpha type, and color space.
* The color type is always 32 bit float. The alpha type is premul if one of 'infoA' and 'infoB' is
* premul and the other is unpremul. The color space is linear sRGB if 'infoA' and 'infoB' have
* different colorspaces, otherwise their common color space is used.
*
* 'tolRGBA' expresses the allowed difference between pixels in the comparison space per channel. If
* pixel components differ more than by 'tolRGBA' in absolute value in any channel then 'error' is
* called with the coordinate and difference in the comparison space (B - A).
*
* The function quits after a single error is reported and returns false if 'error' was called and
* true otherwise.
*/
bool compare_pixels(const GrPixelInfo& infoA, const char* a, size_t rowBytesA,
const GrPixelInfo& infoB, const char* b, size_t rowBytesB,
const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error);
/** Convenience version of above that takes SkPixmap inputs. */
bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
std::function<ComparePixmapsErrorReporter>& error);