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) {
|
static SkPath make_gear(SkISize dimensions, int numTeeth) {
|
||||||
SkVector outerRad{ dimensions.fWidth / 2.0f, dimensions.fHeight / 2.0f };
|
SkVector outerRad{ dimensions.fWidth / 2.0f, dimensions.fHeight / 2.0f };
|
||||||
SkVector innerRad{ dimensions.fWidth / 2.5f, dimensions.fHeight / 2.5f };
|
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;
|
float angle = 0.0f;
|
||||||
|
|
||||||
@ -62,11 +62,11 @@ static SkPath make_gear(SkISize dimensions, int numTeeth) {
|
|||||||
|
|
||||||
tmp.moveTo(gen_pt(angle, outerRad));
|
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, outerRad));
|
||||||
tmp.lineTo(gen_pt(angle+kAnglePerTooth, innerRad));
|
tmp.lineTo(gen_pt(angle+(1.5f*kAnglePerTooth), innerRad));
|
||||||
tmp.lineTo(gen_pt(angle+2*kAnglePerTooth, innerRad));
|
tmp.lineTo(gen_pt(angle+(2.5f*kAnglePerTooth), innerRad));
|
||||||
tmp.lineTo(gen_pt(angle+2*kAnglePerTooth, outerRad));
|
tmp.lineTo(gen_pt(angle+(3.0f*kAnglePerTooth), outerRad));
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp.close();
|
tmp.close();
|
||||||
@ -164,32 +164,59 @@ static sk_sp<SkData> make_compressed_data(SkISize dimensions,
|
|||||||
// RGBA8 | | kBC1_RGBA8_UNORM |
|
// RGBA8 | | kBC1_RGBA8_UNORM |
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
//
|
//
|
||||||
|
// The nonPowerOfTwo and nonMultipleOfFour cases exercise some compression edge cases.
|
||||||
class CompressedTexturesGM : public skiagm::GM {
|
class CompressedTexturesGM : public skiagm::GM {
|
||||||
public:
|
public:
|
||||||
CompressedTexturesGM() {
|
enum class Type {
|
||||||
|
kNormal,
|
||||||
|
kNonPowerOfTwo,
|
||||||
|
kNonMultipleOfFour
|
||||||
|
};
|
||||||
|
|
||||||
|
CompressedTexturesGM(Type type) : fType(type) {
|
||||||
this->setBGColor(0xFFCCCCCC);
|
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:
|
protected:
|
||||||
SkString onShortName() override {
|
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 {
|
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 {
|
void onOnceBeforeDraw() override {
|
||||||
fOpaqueETC2Data = make_compressed_data({ kTexWidth, kTexHeight },
|
fOpaqueETC2Data = make_compressed_data(fImgDimensions, kRGB_565_SkColorType, true,
|
||||||
kRGB_565_SkColorType, true,
|
|
||||||
SkImage::CompressionType::kETC2_RGB8_UNORM);
|
SkImage::CompressionType::kETC2_RGB8_UNORM);
|
||||||
|
|
||||||
fOpaqueBC1Data = make_compressed_data({ kTexWidth, kTexHeight },
|
fOpaqueBC1Data = make_compressed_data(fImgDimensions, kRGBA_8888_SkColorType, true,
|
||||||
kRGBA_8888_SkColorType, true,
|
|
||||||
SkImage::CompressionType::kBC1_RGB8_UNORM);
|
SkImage::CompressionType::kBC1_RGB8_UNORM);
|
||||||
|
|
||||||
fTransparentBC1Data = make_compressed_data({ kTexWidth, kTexHeight },
|
fTransparentBC1Data = make_compressed_data(fImgDimensions, kRGBA_8888_SkColorType, false,
|
||||||
kRGBA_8888_SkColorType, false,
|
|
||||||
SkImage::CompressionType::kBC1_RGBA8_UNORM);
|
SkImage::CompressionType::kBC1_RGBA8_UNORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +231,7 @@ protected:
|
|||||||
|
|
||||||
this->drawCell(context, canvas, fTransparentBC1Data,
|
this->drawCell(context, canvas, fTransparentBC1Data,
|
||||||
SkImage::CompressionType::kBC1_RGBA8_UNORM,
|
SkImage::CompressionType::kBC1_RGBA8_UNORM,
|
||||||
{ 2*kPad + kCellWidth, 2*kPad + kTexHeight });
|
{ 2*kPad + kCellWidth, 2*kPad + kBaseTexHeight });
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -213,19 +240,23 @@ private:
|
|||||||
|
|
||||||
sk_sp<SkImage> image;
|
sk_sp<SkImage> image;
|
||||||
if (context) {
|
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);
|
compression, GrMipMapped::kYes);
|
||||||
} else {
|
} else {
|
||||||
image = SkImage::MakeRasterFromCompressed(std::move(data), kTexWidth, kTexHeight,
|
image = SkImage::MakeRasterFromCompressed(std::move(data),
|
||||||
|
fImgDimensions.width(),
|
||||||
|
fImgDimensions.height(),
|
||||||
compression);
|
compression);
|
||||||
}
|
}
|
||||||
if (!image) {
|
if (!image) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkISize dimensions{ kTexWidth, kTexHeight };
|
SkISize levelDimensions = fImgDimensions;
|
||||||
|
int numMipLevels = SkMipMap::ComputeLevelCount(levelDimensions.width(),
|
||||||
int numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
|
levelDimensions.height()) + 1;
|
||||||
|
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
paint.setFilterQuality(kHigh_SkFilterQuality); // to force mipmapping
|
paint.setFilterQuality(kHigh_SkFilterQuality); // to force mipmapping
|
||||||
@ -245,25 +276,28 @@ private:
|
|||||||
|
|
||||||
for (int i = 0; i < numMipLevels; ++i) {
|
for (int i = 0; i < numMipLevels; ++i) {
|
||||||
SkRect r = SkRect::MakeXYWH(offset.fX, offset.fY,
|
SkRect r = SkRect::MakeXYWH(offset.fX, offset.fY,
|
||||||
dimensions.width(), dimensions.height());
|
levelDimensions.width(), levelDimensions.height());
|
||||||
|
|
||||||
canvas->drawImageRect(image, r, &paint);
|
canvas->drawImageRect(image, r, &paint);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
offset.fX += dimensions.width();
|
offset.fX += levelDimensions.width()+1;
|
||||||
} else {
|
} 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 kPad = 8;
|
||||||
static const int kTexWidth = 64;
|
static const int kBaseTexWidth = 64;
|
||||||
static const int kCellWidth = 1.5f * kTexWidth;
|
static const int kCellWidth = 1.5f * kBaseTexWidth;
|
||||||
static const int kTexHeight = 64;
|
static const int kBaseTexHeight = 64;
|
||||||
|
|
||||||
|
Type fType;
|
||||||
|
SkISize fImgDimensions;
|
||||||
sk_sp<SkData> fOpaqueETC2Data;
|
sk_sp<SkData> fOpaqueETC2Data;
|
||||||
sk_sp<SkData> fOpaqueBC1Data;
|
sk_sp<SkData> fOpaqueBC1Data;
|
||||||
sk_sp<SkData> fTransparentBC1Data;
|
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
|
#endif
|
||||||
|
@ -76,10 +76,15 @@ static bool decompress_bc1(SkISize dimensions, const uint8_t* srcData,
|
|||||||
int shift = 0;
|
int shift = 0;
|
||||||
int offsetX = 4 * x, offsetY = 4 * y;
|
int offsetX = 4 * x, offsetY = 4 * y;
|
||||||
for (int i = 0; i < 4; ++i) {
|
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;
|
int index = (curBlock->fIndices >> shift) & 0x3;
|
||||||
*dst->getAddr32(offsetX + j, offsetY + i) = colors[index];
|
*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);
|
block->fLow = SkBSwap32(low);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int num_ETC1_blocks_w(int w) {
|
static int num_4x4_blocks(int size) {
|
||||||
if (w < 4) {
|
return ((size + 3) & ~3) >> 2;
|
||||||
w = 1;
|
|
||||||
} else {
|
|
||||||
SkASSERT((w & 3) == 0);
|
|
||||||
w >>= 2;
|
|
||||||
}
|
|
||||||
return w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int num_ETC1_blocks(int w, int h) {
|
static int num_ETC1_blocks(int w, int h) {
|
||||||
w = num_ETC1_blocks_w(w);
|
w = num_4x4_blocks(w);
|
||||||
|
h = num_4x4_blocks(h);
|
||||||
if (h < 4) {
|
|
||||||
h = 1;
|
|
||||||
} else {
|
|
||||||
SkASSERT((h & 3) == 0);
|
|
||||||
h >>= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w * 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::kETC2_RGB8_UNORM:
|
||||||
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
||||||
case SkImage::CompressionType::kBC1_RGBA8_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));
|
static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
|
||||||
return numBlocksWidth * sizeof(ETC1Block);
|
return numBlocksWidth * sizeof(ETC1Block);
|
||||||
@ -181,8 +169,8 @@ SkISize GrCompressedDimensions(SkImage::CompressionType type, SkISize baseDimens
|
|||||||
case SkImage::CompressionType::kETC2_RGB8_UNORM:
|
case SkImage::CompressionType::kETC2_RGB8_UNORM:
|
||||||
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
case SkImage::CompressionType::kBC1_RGB8_UNORM:
|
||||||
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
|
case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
|
||||||
int numBlocksWidth = num_ETC1_blocks_w(baseDimensions.width());
|
int numBlocksWidth = num_4x4_blocks(baseDimensions.width());
|
||||||
int numBlocksHeight = num_ETC1_blocks_w(baseDimensions.height());
|
int numBlocksHeight = num_4x4_blocks(baseDimensions.height());
|
||||||
|
|
||||||
// Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
|
// Each BC1_RGB8_UNORM and ETC1 block has 16 pixels
|
||||||
return { 4 * numBlocksWidth, 4 * numBlocksHeight };
|
return { 4 * numBlocksWidth, 4 * numBlocksHeight };
|
||||||
@ -231,18 +219,19 @@ void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dst
|
|||||||
// black -> fColor0, otherColor -> fColor1
|
// black -> fColor0, otherColor -> fColor1
|
||||||
create_BC1_block(SK_ColorBLACK, otherColor, &block);
|
create_BC1_block(SK_ColorBLACK, otherColor, &block);
|
||||||
|
|
||||||
int numXBlocks = num_ETC1_blocks_w(pixmap.width());
|
int numXBlocks = num_4x4_blocks(pixmap.width());
|
||||||
int numYBlocks = num_ETC1_blocks_w(pixmap.height());
|
int numYBlocks = num_4x4_blocks(pixmap.height());
|
||||||
|
|
||||||
for (int y = 0; y < numYBlocks; ++y) {
|
for (int y = 0; y < numYBlocks; ++y) {
|
||||||
for (int x = 0; x < numXBlocks; ++x) {
|
for (int x = 0; x < numXBlocks; ++x) {
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
int offsetX = 4 * x, offsetY = 4 * y;
|
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 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()) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +242,6 @@ void GrTwoColorBC1Compress(const SkPixmap& pixmap, SkColor otherColor, char* dst
|
|||||||
} else if (tmp != SK_ColorBLACK) {
|
} else if (tmp != SK_ColorBLACK) {
|
||||||
block.fIndices |= 1 << shift; // color1
|
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
|
SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
|
||||||
: kPremul_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)) {
|
if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user