Expand the compressed_textures GM
This CL adds testing for some edge cases in compressed texture handling Bug: skia:9680 Change-Id: I4915f46bca9e2fb5c827a51152f28dc1e9d22942 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/266201 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
0f4cb09320
commit
162e04b9a9
@ -53,7 +53,7 @@ static SkPoint gen_pt(float angle, const SkVector& scale) {
|
||||
static SkPath make_gear(SkISize dimensions, int numTeeth) {
|
||||
SkVector outerRad{ dimensions.fWidth / 2.0f, dimensions.fHeight / 2.0f };
|
||||
SkVector innerRad{ dimensions.fWidth / 2.5f, dimensions.fHeight / 2.5f };
|
||||
const float kAnglePerTooth = SK_ScalarPI / numTeeth;
|
||||
const float kAnglePerTooth = 2.0f * SK_ScalarPI / (3 * numTeeth);
|
||||
|
||||
float angle = 0.0f;
|
||||
|
||||
@ -62,11 +62,11 @@ static SkPath make_gear(SkISize dimensions, int numTeeth) {
|
||||
|
||||
tmp.moveTo(gen_pt(angle, outerRad));
|
||||
|
||||
for (int i = 0; i < numTeeth; ++i, angle += 2*kAnglePerTooth) {
|
||||
for (int i = 0; i < numTeeth; ++i, angle += 3*kAnglePerTooth) {
|
||||
tmp.lineTo(gen_pt(angle+kAnglePerTooth, outerRad));
|
||||
tmp.lineTo(gen_pt(angle+kAnglePerTooth, innerRad));
|
||||
tmp.lineTo(gen_pt(angle+2*kAnglePerTooth, innerRad));
|
||||
tmp.lineTo(gen_pt(angle+2*kAnglePerTooth, outerRad));
|
||||
tmp.lineTo(gen_pt(angle+(1.5f*kAnglePerTooth), innerRad));
|
||||
tmp.lineTo(gen_pt(angle+(2.5f*kAnglePerTooth), innerRad));
|
||||
tmp.lineTo(gen_pt(angle+(3.0f*kAnglePerTooth), outerRad));
|
||||
}
|
||||
|
||||
tmp.close();
|
||||
@ -164,32 +164,59 @@ static sk_sp<SkData> make_compressed_data(SkISize dimensions,
|
||||
// RGBA8 | | kBC1_RGBA8_UNORM |
|
||||
// --------------------------------------
|
||||
//
|
||||
// The nonPowerOfTwo and nonMultipleOfFour cases exercise some compression edge cases.
|
||||
class CompressedTexturesGM : public skiagm::GM {
|
||||
public:
|
||||
CompressedTexturesGM() {
|
||||
enum class Type {
|
||||
kNormal,
|
||||
kNonPowerOfTwo,
|
||||
kNonMultipleOfFour
|
||||
};
|
||||
|
||||
CompressedTexturesGM(Type type) : fType(type) {
|
||||
this->setBGColor(0xFFCCCCCC);
|
||||
|
||||
switch (fType) {
|
||||
case Type::kNonPowerOfTwo:
|
||||
// These dimensions force the top two mip levels to be 1x3 and 1x1
|
||||
fImgDimensions.set(20, 60);
|
||||
break;
|
||||
case Type::kNonMultipleOfFour:
|
||||
// These dimensions force the top three mip levels to be 1x7, 1x3 and 1x1
|
||||
fImgDimensions.set(13, 61); // prime numbers - just bc
|
||||
break;
|
||||
default:
|
||||
fImgDimensions.set(kBaseTexWidth, kBaseTexHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
SkString onShortName() override {
|
||||
return SkString("compressed_textures");
|
||||
SkString name("compressed_textures");
|
||||
|
||||
if (fType == Type::kNonPowerOfTwo) {
|
||||
name.append("_npot");
|
||||
} else if (fType == Type::kNonMultipleOfFour) {
|
||||
name.append("_nmof");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
return SkISize::Make(2*kCellWidth + 3*kPad, 2*kTexHeight + 3*kPad);
|
||||
return SkISize::Make(2*kCellWidth + 3*kPad, 2*kBaseTexHeight + 3*kPad);
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
fOpaqueETC2Data = make_compressed_data({ kTexWidth, kTexHeight },
|
||||
kRGB_565_SkColorType, true,
|
||||
fOpaqueETC2Data = make_compressed_data(fImgDimensions, kRGB_565_SkColorType, true,
|
||||
SkImage::CompressionType::kETC2_RGB8_UNORM);
|
||||
|
||||
fOpaqueBC1Data = make_compressed_data({ kTexWidth, kTexHeight },
|
||||
kRGBA_8888_SkColorType, true,
|
||||
fOpaqueBC1Data = make_compressed_data(fImgDimensions, kRGBA_8888_SkColorType, true,
|
||||
SkImage::CompressionType::kBC1_RGB8_UNORM);
|
||||
|
||||
fTransparentBC1Data = make_compressed_data({ kTexWidth, kTexHeight },
|
||||
kRGBA_8888_SkColorType, false,
|
||||
fTransparentBC1Data = make_compressed_data(fImgDimensions, kRGBA_8888_SkColorType, false,
|
||||
SkImage::CompressionType::kBC1_RGBA8_UNORM);
|
||||
}
|
||||
|
||||
@ -204,7 +231,7 @@ protected:
|
||||
|
||||
this->drawCell(context, canvas, fTransparentBC1Data,
|
||||
SkImage::CompressionType::kBC1_RGBA8_UNORM,
|
||||
{ 2*kPad + kCellWidth, 2*kPad + kTexHeight });
|
||||
{ 2*kPad + kCellWidth, 2*kPad + kBaseTexHeight });
|
||||
}
|
||||
|
||||
private:
|
||||
@ -213,19 +240,23 @@ private:
|
||||
|
||||
sk_sp<SkImage> image;
|
||||
if (context) {
|
||||
image = SkImage::MakeFromCompressed(context, std::move(data), kTexWidth, kTexHeight,
|
||||
image = SkImage::MakeFromCompressed(context, std::move(data),
|
||||
fImgDimensions.width(),
|
||||
fImgDimensions.height(),
|
||||
compression, GrMipMapped::kYes);
|
||||
} else {
|
||||
image = SkImage::MakeRasterFromCompressed(std::move(data), kTexWidth, kTexHeight,
|
||||
image = SkImage::MakeRasterFromCompressed(std::move(data),
|
||||
fImgDimensions.width(),
|
||||
fImgDimensions.height(),
|
||||
compression);
|
||||
}
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkISize dimensions{ kTexWidth, kTexHeight };
|
||||
|
||||
int numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
|
||||
SkISize levelDimensions = fImgDimensions;
|
||||
int numMipLevels = SkMipMap::ComputeLevelCount(levelDimensions.width(),
|
||||
levelDimensions.height()) + 1;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setFilterQuality(kHigh_SkFilterQuality); // to force mipmapping
|
||||
@ -245,25 +276,28 @@ private:
|
||||
|
||||
for (int i = 0; i < numMipLevels; ++i) {
|
||||
SkRect r = SkRect::MakeXYWH(offset.fX, offset.fY,
|
||||
dimensions.width(), dimensions.height());
|
||||
levelDimensions.width(), levelDimensions.height());
|
||||
|
||||
canvas->drawImageRect(image, r, &paint);
|
||||
|
||||
if (i == 0) {
|
||||
offset.fX += dimensions.width();
|
||||
offset.fX += levelDimensions.width()+1;
|
||||
} else {
|
||||
offset.fY += dimensions.height();
|
||||
offset.fY += levelDimensions.height()+1;
|
||||
}
|
||||
|
||||
dimensions = {SkTMax(1, dimensions.width()/2), SkTMax(1, dimensions.height()/2)};
|
||||
levelDimensions = {SkTMax(1, levelDimensions.width()/2),
|
||||
SkTMax(1, levelDimensions.height()/2)};
|
||||
}
|
||||
}
|
||||
|
||||
static const int kPad = 8;
|
||||
static const int kTexWidth = 64;
|
||||
static const int kCellWidth = 1.5f * kTexWidth;
|
||||
static const int kTexHeight = 64;
|
||||
static const int kBaseTexWidth = 64;
|
||||
static const int kCellWidth = 1.5f * kBaseTexWidth;
|
||||
static const int kBaseTexHeight = 64;
|
||||
|
||||
Type fType;
|
||||
SkISize fImgDimensions;
|
||||
sk_sp<SkData> fOpaqueETC2Data;
|
||||
sk_sp<SkData> fOpaqueBC1Data;
|
||||
sk_sp<SkData> fTransparentBC1Data;
|
||||
@ -273,6 +307,8 @@ private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM(return new CompressedTexturesGM;)
|
||||
DEF_GM(return new CompressedTexturesGM(CompressedTexturesGM::Type::kNormal);)
|
||||
DEF_GM(return new CompressedTexturesGM(CompressedTexturesGM::Type::kNonPowerOfTwo);)
|
||||
DEF_GM(return new CompressedTexturesGM(CompressedTexturesGM::Type::kNonMultipleOfFour);)
|
||||
|
||||
#endif
|
||||
|
@ -76,10 +76,15 @@ static bool decompress_bc1(SkISize dimensions, const uint8_t* srcData,
|
||||
int shift = 0;
|
||||
int offsetX = 4 * x, offsetY = 4 * y;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
for (int j = 0; j < 4; ++j, shift += 2) {
|
||||
if (offsetX + j >= dst->width() || offsetY + i >= dst->height()) {
|
||||
// This can happen for the topmost levels of a mipmap and for
|
||||
// non-multiple of 4 textures
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = (curBlock->fIndices >> shift) & 0x3;
|
||||
*dst->getAddr32(offsetX + j, offsetY + i) = colors[index];
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,25 +106,13 @@ static void create_etc1_block(SkColor col, ETC1Block* block) {
|
||||
block->fLow = SkBSwap32(low);
|
||||
}
|
||||
|
||||
static int num_ETC1_blocks_w(int w) {
|
||||
if (w < 4) {
|
||||
w = 1;
|
||||
} else {
|
||||
SkASSERT((w & 3) == 0);
|
||||
w >>= 2;
|
||||
}
|
||||
return w;
|
||||
static int num_4x4_blocks(int size) {
|
||||
return ((size + 3) & ~3) >> 2;
|
||||
}
|
||||
|
||||
static int num_ETC1_blocks(int w, int h) {
|
||||
w = num_ETC1_blocks_w(w);
|
||||
|
||||
if (h < 4) {
|
||||
h = 1;
|
||||
} else {
|
||||
SkASSERT((h & 3) == 0);
|
||||
h >>= 2;
|
||||
}
|
||||
w = num_4x4_blocks(w);
|
||||
h = num_4x4_blocks(h);
|
||||
|
||||
return w * h;
|
||||
}
|
||||
@ -165,7 +153,7 @@ size_t GrCompressedRowBytes(SkImage::CompressionType type, int width) {
|
||||
case SkImage::CompressionType::kETC2_RGB8_UNORM:
|
||||
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
||||
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
|
||||
int numBlocksWidth = num_ETC1_blocks_w(width);
|
||||
int numBlocksWidth = num_4x4_blocks(width);
|
||||
|
||||
static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
|
||||
return numBlocksWidth * sizeof(ETC1Block);
|
||||
@ -181,8 +169,8 @@ SkISize GrCompressedDimensions(SkImage::CompressionType type, SkISize baseDimens
|
||||
case SkImage::CompressionType::kETC2_RGB8_UNORM:
|
||||
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
||||
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
|
||||
int numBlocksWidth = num_ETC1_blocks_w(baseDimensions.width());
|
||||
int numBlocksHeight = num_ETC1_blocks_w(baseDimensions.height());
|
||||
int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
|
||||
int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
|
||||
|
||||
// Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
|
||||
return { 4 * numBlocksWidth, 4 * numBlocksHeight };
|
||||
@ -231,18 +219,19 @@ void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dst
|
||||
// black -> fColor0, otherColor -> fColor1
|
||||
create_BC1_block(SK_ColorBLACK, otherColor, &block);
|
||||
|
||||
int numXBlocks = num_ETC1_blocks_w(pixmap.width());
|
||||
int numYBlocks = num_ETC1_blocks_w(pixmap.height());
|
||||
int numXBlocks = num_4x4_blocks(pixmap.width());
|
||||
int numYBlocks = num_4x4_blocks(pixmap.height());
|
||||
|
||||
for (int y = 0; y < numYBlocks; ++y) {
|
||||
for (int x = 0; x < numXBlocks; ++x) {
|
||||
int shift = 0;
|
||||
int offsetX = 4 * x, offsetY = 4 * y;
|
||||
block.fIndices = 0; // init all the pixels to color0
|
||||
block.fIndices = 0; // init all the pixels to color0 (i.e., opaque black)
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
for (int j = 0; j < 4; ++j, shift += 2) {
|
||||
if (offsetX + j >= pixmap.width() || offsetY + i >= pixmap.height()) {
|
||||
// This can happen for the topmost levels of a mipmap
|
||||
// This can happen for the topmost levels of a mipmap and for
|
||||
// non-multiple of 4 textures
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -253,7 +242,6 @@ void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dst
|
||||
} else if (tmp != SK_ColorBLACK) {
|
||||
block.fIndices |= 1 << shift; // color1
|
||||
}
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +297,7 @@ sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
|
||||
SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
|
||||
: kPremul_SkAlphaType;
|
||||
|
||||
SkImageInfo ii = SkImageInfo::Make({ width, height }, kRGBA_8888_SkColorType, at);
|
||||
SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
|
||||
|
||||
if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
|
||||
return nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user