7785dd235d
The versions of showmiplevel that take both a width and height, round the coords of draws to integers. The basic version did not do this which caused sampling bugs on adreno when using nearest neighbor at half pixel coords. Since this GM isn't testing the GPU rendering of the mips, this workaround is okay. Bug: skia:5905 Change-Id: I4080532e8c1f37d74c60089970c5d0fc83cd5373 Reviewed-on: https://skia-review.googlesource.com/18939 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
333 lines
9.8 KiB
C++
333 lines
9.8 KiB
C++
/*
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "gm.h"
|
|
#include "sk_tool_utils.h"
|
|
|
|
#include "Resources.h"
|
|
#include "SkBitmapScaler.h"
|
|
#include "SkGradientShader.h"
|
|
#include "SkTypeface.h"
|
|
#include "SkStream.h"
|
|
#include "SkPaint.h"
|
|
#include "SkMipMap.h"
|
|
#include "Resources.h"
|
|
|
|
#define SHOW_MIP_COLOR 0xFF000000
|
|
|
|
static SkBitmap make_bitmap(int w, int h) {
|
|
SkBitmap bm;
|
|
bm.allocN32Pixels(w, h);
|
|
SkCanvas canvas(bm);
|
|
canvas.clear(0xFFFFFFFF);
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(w / 16.0f);
|
|
paint.setColor(SHOW_MIP_COLOR);
|
|
canvas.drawCircle(w/2.0f, h/2.0f, w/3.0f, paint);
|
|
return bm;
|
|
}
|
|
|
|
static SkBitmap make_bitmap2(int w, int h) {
|
|
SkBitmap bm;
|
|
bm.allocN32Pixels(w, h);
|
|
SkCanvas canvas(bm);
|
|
canvas.clear(0xFFFFFFFF);
|
|
SkPaint paint;
|
|
paint.setColor(SHOW_MIP_COLOR);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
SkScalar inset = 2;
|
|
SkRect r = SkRect::MakeIWH(w, h).makeInset(0.5f, 0.5f);
|
|
while (r.width() > 4) {
|
|
canvas.drawRect(r, paint);
|
|
r.inset(inset, inset);
|
|
inset += 1;
|
|
}
|
|
return bm;
|
|
}
|
|
|
|
#include "SkNx.h"
|
|
static SkBitmap make_bitmap3(int w, int h) {
|
|
SkBitmap bm;
|
|
bm.allocN32Pixels(w, h);
|
|
SkCanvas canvas(bm);
|
|
canvas.clear(0xFFFFFFFF);
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(2.1f);
|
|
paint.setColor(SHOW_MIP_COLOR);
|
|
|
|
SkScalar s = SkIntToScalar(w);
|
|
Sk4f p(s, -s, -s, s);
|
|
Sk4f d(5);
|
|
while (p[1] < s) {
|
|
canvas.drawLine(p[0],p[1], p[2], p[3], paint);
|
|
p = p + d;
|
|
}
|
|
return bm;
|
|
}
|
|
|
|
class ShowMipLevels : public skiagm::GM {
|
|
const int fN;
|
|
SkBitmap fBM[4];
|
|
|
|
public:
|
|
static unsigned gamma(unsigned n) {
|
|
float x = n / 255.0f;
|
|
#if 0
|
|
x = sqrtf(x);
|
|
#else
|
|
if (x > 0.0031308f) {
|
|
x = 1.055f * (powf(x, (1.0f / 2.4f))) - 0.055f;
|
|
} else {
|
|
x = 12.92f * x;
|
|
}
|
|
#endif
|
|
return (int)(x * 255);
|
|
}
|
|
|
|
static void apply_gamma(const SkBitmap& bm) {
|
|
return; // below is our experiment for sRGB correction
|
|
for (int y = 0; y < bm.height(); ++y) {
|
|
for (int x = 0; x < bm.width(); ++x) {
|
|
SkPMColor c = *bm.getAddr32(x, y);
|
|
unsigned r = gamma(SkGetPackedR32(c));
|
|
unsigned g = gamma(SkGetPackedG32(c));
|
|
unsigned b = gamma(SkGetPackedB32(c));
|
|
*bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
|
|
}
|
|
}
|
|
}
|
|
|
|
ShowMipLevels(int N) : fN(N) { }
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override {
|
|
SkString str;
|
|
str.printf("showmiplevels_%d", fN);
|
|
return str;
|
|
}
|
|
|
|
SkISize onISize() override {
|
|
return { 824, 862 };
|
|
}
|
|
|
|
static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
|
|
SkBitmap bm;
|
|
sk_tool_utils::copy_to(&bm, orig.colorType(), orig);
|
|
apply_gamma(bm);
|
|
|
|
canvas->drawBitmap(bm, x, y, nullptr);
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setColor(0xFFFFCCCC);
|
|
canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
|
|
}
|
|
|
|
template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
|
|
SkScalar x = 4;
|
|
SkScalar y = 4;
|
|
|
|
SkPixmap prevPM;
|
|
baseBM.peekPixels(&prevPM);
|
|
|
|
SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
|
|
sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, colorMode, nullptr));
|
|
|
|
int index = 0;
|
|
SkMipMap::Level level;
|
|
SkScalar scale = 0.5f;
|
|
while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
|
|
SkBitmap bm = func(prevPM, level.fPixmap);
|
|
DrawAndFrame(canvas, bm, x, y);
|
|
|
|
if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
|
|
break;
|
|
}
|
|
if (index & 1) {
|
|
x += level.fPixmap.width() + 4;
|
|
} else {
|
|
y += level.fPixmap.height() + 4;
|
|
}
|
|
scale /= 2;
|
|
prevPM = level.fPixmap;
|
|
index += 1;
|
|
}
|
|
}
|
|
|
|
void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
|
|
SkBitmap bm;
|
|
bm.installPixels(curr);
|
|
return bm;
|
|
});
|
|
|
|
const SkBitmapScaler::ResizeMethod methods[] = {
|
|
SkBitmapScaler::RESIZE_BOX,
|
|
SkBitmapScaler::RESIZE_TRIANGLE,
|
|
SkBitmapScaler::RESIZE_LANCZOS3,
|
|
SkBitmapScaler::RESIZE_HAMMING,
|
|
SkBitmapScaler::RESIZE_MITCHELL,
|
|
};
|
|
|
|
SkPixmap basePM;
|
|
orig.peekPixels(&basePM);
|
|
for (auto method : methods) {
|
|
canvas->translate(orig.width()/2 + 8.0f, 0);
|
|
drawLevels(canvas, orig, [method](const SkPixmap& prev, const SkPixmap& curr) {
|
|
SkBitmap bm;
|
|
SkBitmapScaler::Resize(&bm, prev, method, curr.width(), curr.height());
|
|
return bm;
|
|
});
|
|
}
|
|
}
|
|
|
|
void onOnceBeforeDraw() override {
|
|
fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fN, fN, SK_ColorBLACK, SK_ColorWHITE, 2);
|
|
fBM[1] = make_bitmap(fN, fN);
|
|
fBM[2] = make_bitmap2(fN, fN);
|
|
fBM[3] = make_bitmap3(fN, fN);
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
canvas->translate(4, 4);
|
|
for (const auto& bm : fBM) {
|
|
this->drawSet(canvas, bm);
|
|
// round so we always produce an integral translate, so the GOLD tool won't show
|
|
// unimportant diffs if this is drawn on a GPU with different rounding rules
|
|
// since we draw the bitmaps using nearest-neighbor
|
|
canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
|
|
}
|
|
}
|
|
|
|
private:
|
|
typedef skiagm::GM INHERITED;
|
|
};
|
|
DEF_GM( return new ShowMipLevels(255); )
|
|
DEF_GM( return new ShowMipLevels(256); )
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
|
|
if (kGray_8_SkColorType == dstColorType) {
|
|
return sk_tool_utils::copy_to_g8(dst, src);
|
|
}
|
|
|
|
const SkBitmap* srcPtr = &src;
|
|
SkBitmap tmp(src);
|
|
if (kRGB_565_SkColorType == dstColorType) {
|
|
tmp.setAlphaType(kOpaque_SkAlphaType);
|
|
srcPtr = &tmp;
|
|
}
|
|
|
|
sk_tool_utils::copy_to(dst, dstColorType, *srcPtr);
|
|
}
|
|
|
|
/**
|
|
* Show mip levels that were built, for all supported colortypes
|
|
*/
|
|
class ShowMipLevels2 : public skiagm::GM {
|
|
const int fW, fH;
|
|
SkBitmap fBM[4];
|
|
|
|
public:
|
|
ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override {
|
|
SkString str;
|
|
str.printf("showmiplevels2_%dx%d", fW, fH);
|
|
return str;
|
|
}
|
|
|
|
SkISize onISize() override {
|
|
return { 824, 862 };
|
|
}
|
|
|
|
static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
|
|
canvas->drawBitmap(bm, x, y, nullptr);
|
|
SkPaint paint;
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setColor(0xFFFFCCCC);
|
|
canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
|
|
}
|
|
|
|
void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
|
|
SkScalar x = 4;
|
|
SkScalar y = 4;
|
|
|
|
SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
|
|
sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, colorMode, nullptr));
|
|
|
|
int index = 0;
|
|
SkMipMap::Level level;
|
|
SkScalar scale = 0.5f;
|
|
while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
|
|
SkBitmap bm;
|
|
bm.installPixels(level.fPixmap);
|
|
DrawAndFrame(canvas, bm, x, y);
|
|
|
|
if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
|
|
break;
|
|
}
|
|
if (index & 1) {
|
|
x += level.fPixmap.width() + 4;
|
|
} else {
|
|
y += level.fPixmap.height() + 4;
|
|
}
|
|
scale /= 2;
|
|
index += 1;
|
|
}
|
|
}
|
|
|
|
void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
|
|
const SkColorType ctypes[] = {
|
|
kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
|
|
};
|
|
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
for (auto ctype : ctypes) {
|
|
SkBitmap bm;
|
|
copy_to(&bm, ctype, orig);
|
|
drawLevels(canvas, bm);
|
|
canvas->translate(orig.width()/2 + 8.0f, 0);
|
|
}
|
|
}
|
|
|
|
void onOnceBeforeDraw() override {
|
|
fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fW, fH,
|
|
SHOW_MIP_COLOR, SK_ColorWHITE, 2);
|
|
fBM[1] = make_bitmap(fW, fH);
|
|
fBM[2] = make_bitmap2(fW, fH);
|
|
fBM[3] = make_bitmap3(fW, fH);
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
canvas->translate(4, 4);
|
|
for (const auto& bm : fBM) {
|
|
this->drawSet(canvas, bm);
|
|
// round so we always produce an integral translate, so the GOLD tool won't show
|
|
// unimportant diffs if this is drawn on a GPU with different rounding rules
|
|
// since we draw the bitmaps using nearest-neighbor
|
|
canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
|
|
}
|
|
}
|
|
|
|
private:
|
|
typedef skiagm::GM INHERITED;
|
|
};
|
|
DEF_GM( return new ShowMipLevels2(255, 255); )
|
|
DEF_GM( return new ShowMipLevels2(256, 255); )
|
|
DEF_GM( return new ShowMipLevels2(255, 256); )
|
|
DEF_GM( return new ShowMipLevels2(256, 256); )
|