Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1645)

Unified Diff: src/utils/SkTextureCompressor_R11EAC.cpp

Issue 403383003: Refactor texture compressors into separate files (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Handle improper dimensions Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/utils/SkTextureCompressor_R11EAC.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/utils/SkTextureCompressor_R11EAC.cpp
diff --git a/src/utils/SkTextureCompressor.cpp b/src/utils/SkTextureCompressor_R11EAC.cpp
similarity index 69%
copy from src/utils/SkTextureCompressor.cpp
copy to src/utils/SkTextureCompressor_R11EAC.cpp
index a593b36880e8588fe50a0eb0bfcea68afac2b320..3ce0120ec5fa29e6c4577896d1dd3d2d677b533c 100644
--- a/src/utils/SkTextureCompressor.cpp
+++ b/src/utils/SkTextureCompressor_R11EAC.cpp
@@ -7,292 +7,8 @@
#include "SkTextureCompressor.h"
-#include "SkBitmap.h"
-#include "SkData.h"
#include "SkEndian.h"
-#include "SkTextureCompression_opts.h"
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// Utility Functions
-//
-////////////////////////////////////////////////////////////////////////////////
-
-// Absolute difference between two values. More correct than SkTAbs(a - b)
-// because it works on unsigned values.
-template <typename T> inline T abs_diff(const T &a, const T &b) {
- return (a > b) ? (a - b) : (b - a);
-}
-
-static bool is_extremal(uint8_t pixel) {
- return 0 == pixel || 255 == pixel;
-}
-
-typedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]);
-
-// This function is used by both R11 EAC and LATC to compress 4x4 blocks
-// of 8-bit alpha into 64-bit values that comprise the compressed data.
-// For both formats, we need to make sure that the dimensions of the
-// src pixels are divisible by 4, and copy 4x4 blocks one at a time
-// for compression.
-static bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src,
- int width, int height, int rowBytes,
- A84x4To64BitProc proc) {
- // Make sure that our data is well-formed enough to be considered for compression
- if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) {
- return false;
- }
-
- int blocksX = width >> 2;
- int blocksY = height >> 2;
-
- uint8_t block[16];
- uint64_t* encPtr = reinterpret_cast<uint64_t*>(dst);
- for (int y = 0; y < blocksY; ++y) {
- for (int x = 0; x < blocksX; ++x) {
- // Load block
- for (int k = 0; k < 4; ++k) {
- memcpy(block + k*4, src + k*rowBytes + 4*x, 4);
- }
-
- // Compress it
- *encPtr = proc(block);
- ++encPtr;
- }
- src += 4 * rowBytes;
- }
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// LATC compressor
-//
-////////////////////////////////////////////////////////////////////////////////
-
-// LATC compressed texels down into square 4x4 blocks
-static const int kLATCPaletteSize = 8;
-static const int kLATCBlockSize = 4;
-static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize;
-
-// Generates an LATC palette. LATC constructs
-// a palette of eight colors from LUM0 and LUM1 using the algorithm:
-//
-// LUM0, if lum0 > lum1 and code(x,y) == 0
-// LUM1, if lum0 > lum1 and code(x,y) == 1
-// (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2
-// (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3
-// (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4
-// (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5
-// (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6
-// ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7
-//
-// LUM0, if lum0 <= lum1 and code(x,y) == 0
-// LUM1, if lum0 <= lum1 and code(x,y) == 1
-// (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2
-// (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3
-// (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4
-// ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5
-// 0, if lum0 <= lum1 and code(x,y) == 6
-// 255, if lum0 <= lum1 and code(x,y) == 7
-
-static void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1) {
- palette[0] = lum0;
- palette[1] = lum1;
- if (lum0 > lum1) {
- for (int i = 1; i < 7; i++) {
- palette[i+1] = ((7-i)*lum0 + i*lum1) / 7;
- }
- } else {
- for (int i = 1; i < 5; i++) {
- palette[i+1] = ((5-i)*lum0 + i*lum1) / 5;
- }
- palette[6] = 0;
- palette[7] = 255;
- }
-}
-
-// Compress a block by using the bounding box of the pixels. It is assumed that
-// there are no extremal pixels in this block otherwise we would have used
-// compressBlockBBIgnoreExtremal.
-static uint64_t compress_latc_block_bb(const uint8_t pixels[]) {
- uint8_t minVal = 255;
- uint8_t maxVal = 0;
- for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
- minVal = SkTMin(pixels[i], minVal);
- maxVal = SkTMax(pixels[i], maxVal);
- }
-
- SkASSERT(!is_extremal(minVal));
- SkASSERT(!is_extremal(maxVal));
-
- uint8_t palette[kLATCPaletteSize];
- generate_latc_palette(palette, maxVal, minVal);
-
- uint64_t indices = 0;
- for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
-
- // Find the best palette index
- uint8_t bestError = abs_diff(pixels[i], palette[0]);
- uint8_t idx = 0;
- for (int j = 1; j < kLATCPaletteSize; ++j) {
- uint8_t error = abs_diff(pixels[i], palette[j]);
- if (error < bestError) {
- bestError = error;
- idx = j;
- }
- }
-
- indices <<= 3;
- indices |= idx;
- }
-
- return
- SkEndian_SwapLE64(
- static_cast<uint64_t>(maxVal) |
- (static_cast<uint64_t>(minVal) << 8) |
- (indices << 16));
-}
-
-// Compress a block by using the bounding box of the pixels without taking into
-// account the extremal values. The generated palette will contain extremal values
-// and fewer points along the line segment to interpolate.
-static uint64_t compress_latc_block_bb_ignore_extremal(const uint8_t pixels[]) {
- uint8_t minVal = 255;
- uint8_t maxVal = 0;
- for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
- if (is_extremal(pixels[i])) {
- continue;
- }
-
- minVal = SkTMin(pixels[i], minVal);
- maxVal = SkTMax(pixels[i], maxVal);
- }
-
- SkASSERT(!is_extremal(minVal));
- SkASSERT(!is_extremal(maxVal));
-
- uint8_t palette[kLATCPaletteSize];
- generate_latc_palette(palette, minVal, maxVal);
-
- uint64_t indices = 0;
- for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
-
- // Find the best palette index
- uint8_t idx = 0;
- if (is_extremal(pixels[i])) {
- if (0xFF == pixels[i]) {
- idx = 7;
- } else if (0 == pixels[i]) {
- idx = 6;
- } else {
- SkFAIL("Pixel is extremal but not really?!");
- }
- } else {
- uint8_t bestError = abs_diff(pixels[i], palette[0]);
- for (int j = 1; j < kLATCPaletteSize - 2; ++j) {
- uint8_t error = abs_diff(pixels[i], palette[j]);
- if (error < bestError) {
- bestError = error;
- idx = j;
- }
- }
- }
-
- indices <<= 3;
- indices |= idx;
- }
-
- return
- SkEndian_SwapLE64(
- static_cast<uint64_t>(minVal) |
- (static_cast<uint64_t>(maxVal) << 8) |
- (indices << 16));
-}
-
-
-// Compress LATC block. Each 4x4 block of pixels is decompressed by LATC from two
-// values LUM0 and LUM1, and an index into the generated palette. Details of how
-// the palette is generated can be found in the comments of generatePalette above.
-//
-// We choose which palette type to use based on whether or not 'pixels' contains
-// any extremal values (0 or 255). If there are extremal values, then we use the
-// palette that has the extremal values built in. Otherwise, we use the full bounding
-// box.
-
-static uint64_t compress_latc_block(const uint8_t pixels[]) {
- // Collect unique pixels
- int nUniquePixels = 0;
- uint8_t uniquePixels[kLATCPixelsPerBlock];
- for (int i = 0; i < kLATCPixelsPerBlock; ++i) {
- bool foundPixel = false;
- for (int j = 0; j < nUniquePixels; ++j) {
- foundPixel = foundPixel || uniquePixels[j] == pixels[i];
- }
-
- if (!foundPixel) {
- uniquePixels[nUniquePixels] = pixels[i];
- ++nUniquePixels;
- }
- }
-
- // If there's only one unique pixel, then our compression is easy.
- if (1 == nUniquePixels) {
- return SkEndian_SwapLE64(pixels[0] | (pixels[0] << 8));
-
- // Similarly, if there are only two unique pixels, then our compression is
- // easy again: place the pixels in the block header, and assign the indices
- // with one or zero depending on which pixel they belong to.
- } else if (2 == nUniquePixels) {
- uint64_t outBlock = 0;
- for (int i = kLATCPixelsPerBlock - 1; i >= 0; --i) {
- int idx = 0;
- if (pixels[i] == uniquePixels[1]) {
- idx = 1;
- }
-
- outBlock <<= 3;
- outBlock |= idx;
- }
- outBlock <<= 16;
- outBlock |= (uniquePixels[0] | (uniquePixels[1] << 8));
- return SkEndian_SwapLE64(outBlock);
- }
-
- // Count non-maximal pixel values
- int nonExtremalPixels = 0;
- for (int i = 0; i < nUniquePixels; ++i) {
- if (!is_extremal(uniquePixels[i])) {
- ++nonExtremalPixels;
- }
- }
-
- // If all the pixels are nonmaximal then compute the palette using
- // the bounding box of all the pixels.
- if (nonExtremalPixels == nUniquePixels) {
- // This is really just for correctness, in all of my tests we
- // never take this step. We don't lose too much perf here because
- // most of the processing in this function is worth it for the
- // 1 == nUniquePixels optimization.
- return compress_latc_block_bb(pixels);
- } else {
- return compress_latc_block_bb_ignore_extremal(pixels);
- }
-}
-
-static inline bool compress_a8_to_latc(uint8_t* dst, const uint8_t* src,
- int width, int height, int rowBytes) {
- return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_latc_block);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// R11 EAC Compressor
-//
-////////////////////////////////////////////////////////////////////////////////
-
// #define COMPRESS_R11_EAC_SLOW 1
// #define COMPRESS_R11_EAC_FAST 1
#define COMPRESS_R11_EAC_FASTEST 1
@@ -548,9 +264,51 @@ static uint64_t compress_r11eac_block(const uint8_t block[16]) {
return compress_heterogeneous_r11eac_block(block);
}
+
+// This function is used by R11 EAC to compress 4x4 blocks
+// of 8-bit alpha into 64-bit values that comprise the compressed data.
+// We need to make sure that the dimensions of the src pixels are divisible
+// by 4, and copy 4x4 blocks one at a time for compression.
+typedef uint64_t (*A84x4To64BitProc)(const uint8_t block[]);
+
+static bool compress_4x4_a8_to_64bit(uint8_t* dst, const uint8_t* src,
+ int width, int height, int rowBytes,
+ A84x4To64BitProc proc) {
+ // Make sure that our data is well-formed enough to be considered for compression
+ if (0 == width || 0 == height || (width % 4) != 0 || (height % 4) != 0) {
+ return false;
+ }
+
+ int blocksX = width >> 2;
+ int blocksY = height >> 2;
+
+ uint8_t block[16];
+ uint64_t* encPtr = reinterpret_cast<uint64_t*>(dst);
+ for (int y = 0; y < blocksY; ++y) {
+ for (int x = 0; x < blocksX; ++x) {
+ // Load block
+ for (int k = 0; k < 4; ++k) {
+ memcpy(block + k*4, src + k*rowBytes + 4*x, 4);
+ }
+
+ // Compress it
+ *encPtr = proc(block);
+ ++encPtr;
+ }
+ src += 4 * rowBytes;
+ }
+
+ return true;
+}
#endif // (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST)
#if COMPRESS_R11_EAC_FASTEST
+template<unsigned shift>
+static inline uint64_t swap_shift(uint64_t x, uint64_t mask) {
+ const uint64_t t = (x ^ (x >> shift)) & mask;
+ return x ^ t ^ (t << shift);
+}
+
static inline uint64_t interleave6(uint64_t topRows, uint64_t bottomRows) {
// If our 3-bit block indices are laid out as:
// a b c d
@@ -584,8 +342,7 @@ static inline uint64_t interleave6(uint64_t topRows, uint64_t bottomRows) {
// x: 00 a e 00 b f 00 c g 00 d h 00 i m 00 j n 00 k o 00 l p
- uint64_t t = (x ^ (x >> 10)) & 0x3FC0003FC00000ULL;
- x = x ^ t ^ (t << 10);
+ x = swap_shift<10>(x, 0x3FC0003FC00000ULL);
// x: b f 00 00 00 a e c g i m 00 00 00 d h j n 00 k o 00 l p
@@ -593,38 +350,30 @@ static inline uint64_t interleave6(uint64_t topRows, uint64_t bottomRows) {
// x: 00 00 00 00 00 00 00 00 b f l p a e c g i m k o d h j n
- t = (x ^ (x >> 6)) & 0xFC0000ULL;
- x = x ^ t ^ (t << 6);
+ x = swap_shift<6>(x, 0xFC0000ULL);
#if defined (SK_CPU_BENDIAN)
// x: 00 00 00 00 00 00 00 00 b f l p a e i m c g k o d h j n
- t = (x ^ (x >> 36)) & 0x3FULL;
- x = x ^ t ^ (t << 36);
+ x = swap_shift<36>(x, 0x3FULL);
// x: 00 00 00 00 00 00 00 00 b f j n a e i m c g k o d h l p
- t = (x ^ (x >> 12)) & 0xFFF000000ULL;
- x = x ^ t ^ (t << 12);
-
- // x: 00 00 00 00 00 00 00 00 a e i m b f j n c g k o d h l p
- return x;
+ x = swap_shift<12>(x, 0xFFF000000ULL);
#else
// If our CPU is little endian, then the above logic will
// produce the following indices:
// x: 00 00 00 00 00 00 00 00 c g i m d h l p b f j n a e k o
- t = (x ^ (x >> 36)) & 0xFC0ULL;
- x = x ^ t ^ (t << 36);
+ x = swap_shift<36>(x, 0xFC0ULL);
// x: 00 00 00 00 00 00 00 00 a e i m d h l p b f j n c g k o
x = (x & (0xFFFULL << 36)) | ((x & 0xFFFFFFULL) << 12) | ((x >> 24) & 0xFFFULL);
+#endif
// x: 00 00 00 00 00 00 00 00 a e i m b f j n c g k o d h l p
-
return x;
-#endif
}
// This function converts an integer containing four bytes of alpha
@@ -732,6 +481,12 @@ static bool compress_a8_to_r11eac_fast(uint8_t* dst, const uint8_t* src,
}
#endif // COMPRESS_R11_EAC_FASTEST
+////////////////////////////////////////////////////////////////////////////////
+//
+// Utility functions used by the blitter
+//
+////////////////////////////////////////////////////////////////////////////////
+
// The R11 EAC format expects that indices are given in column-major order. Since
// we receive alpha values in raster order, this usually means that we have to use
// pack6 above to properly pack our indices. However, if our indices come from the
@@ -795,43 +550,16 @@ static inline uint64_t compress_block_vertical(const uint32_t alphaColumn0,
}
-static inline bool compress_a8_to_r11eac(uint8_t* dst, const uint8_t* src,
- int width, int height, int rowBytes) {
-#if (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST)
- return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_r11eac_block);
-#elif COMPRESS_R11_EAC_FASTEST
- return compress_a8_to_r11eac_fast(dst, src, width, height, rowBytes);
-#else
-#error "Must choose R11 EAC algorithm"
-#endif
-}
-
// Updates the block whose columns are stored in blockColN. curAlphai is expected
// to store, as an integer, the four alpha values that will be placed within each
// of the columns in the range [col, col+colsLeft).
-static inline void update_block_columns(
- uint32_t* blockCol1, uint32_t* blockCol2, uint32_t* blockCol3, uint32_t* blockCol4,
- const int col, const int colsLeft, const uint32_t curAlphai) {
- SkASSERT(NULL != blockCol1);
- SkASSERT(NULL != blockCol2);
- SkASSERT(NULL != blockCol3);
- SkASSERT(NULL != blockCol4);
+static inline void update_block_columns(uint32_t* block, const int col,
+ const int colsLeft, const uint32_t curAlphai) {
+ SkASSERT(NULL != block);
SkASSERT(col + colsLeft <= 4);
+
for (int i = col; i < (col + colsLeft); ++i) {
- switch(i) {
- case 0:
- *blockCol1 = curAlphai;
- break;
- case 1:
- *blockCol2 = curAlphai;
- break;
- case 2:
- *blockCol3 = curAlphai;
- break;
- case 3:
- *blockCol4 = curAlphai;
- break;
- }
+ block[i] = curAlphai;
}
}
@@ -839,78 +567,182 @@ static inline void update_block_columns(
namespace SkTextureCompressor {
-static inline size_t get_compressed_data_size(Format fmt, int width, int height) {
- switch (fmt) {
- // These formats are 64 bits per 4x4 block.
- case kR11_EAC_Format:
- case kLATC_Format:
- {
- static const int kLATCEncodedBlockSize = 8;
-
- const int blocksX = width / kLATCBlockSize;
- const int blocksY = height / kLATCBlockSize;
-
- return blocksX * blocksY * kLATCEncodedBlockSize;
- }
-
- default:
- SkFAIL("Unknown compressed format!");
- return 0;
- }
-}
+bool CompressA8ToR11EAC(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes) {
-bool CompressBufferToFormat(uint8_t* dst, const uint8_t* src, SkColorType srcColorType,
- int width, int height, int rowBytes, Format format, bool opt) {
- CompressionProc proc = NULL;
- if (opt) {
- proc = SkTextureCompressorGetPlatformProc(srcColorType, format);
- }
+#if (COMPRESS_R11_EAC_SLOW) || (COMPRESS_R11_EAC_FAST)
- if (NULL == proc) {
- switch (srcColorType) {
- case kAlpha_8_SkColorType:
- {
- switch (format) {
- case kLATC_Format:
- proc = compress_a8_to_latc;
- break;
- case kR11_EAC_Format:
- proc = compress_a8_to_r11eac;
- break;
- default:
- // Do nothing...
- break;
- }
- }
- break;
+ return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_r11eac_block);
- default:
- // Do nothing...
- break;
- }
- }
+#elif COMPRESS_R11_EAC_FASTEST
- if (NULL != proc) {
- return proc(dst, src, width, height, rowBytes);
- }
+ return compress_a8_to_r11eac_fast(dst, src, width, height, rowBytes);
- return false;
+#else
+#error "Must choose R11 EAC algorithm"
+#endif
}
-SkData *CompressBitmapToFormat(const SkBitmap &bitmap, Format format) {
- SkAutoLockPixels alp(bitmap);
-
- int compressedDataSize = get_compressed_data_size(format, bitmap.width(), bitmap.height());
- const uint8_t* src = reinterpret_cast<const uint8_t*>(bitmap.getPixels());
- uint8_t* dst = reinterpret_cast<uint8_t*>(sk_malloc_throw(compressedDataSize));
- if (CompressBufferToFormat(dst, src, bitmap.colorType(), bitmap.width(), bitmap.height(),
- bitmap.rowBytes(), format)) {
- return SkData::NewFromMalloc(dst, compressedDataSize);
+// This class implements a blitter that blits directly into a buffer that will
+// be used as an R11 EAC compressed texture. We compute this buffer by
+// buffering four scan lines and then outputting them all at once. This blitter
+// is only expected to be used with alpha masks, i.e. kAlpha8_SkColorType.
+class R11_EACBlitter : public SkBlitter {
+public:
+ R11_EACBlitter(int width, int height, void *compressedBuffer);
+ virtual ~R11_EACBlitter() { this->flushRuns(); }
+
+ // Blit a horizontal run of one or more pixels.
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE {
+ // This function is intended to be called from any standard RGB
+ // buffer, so we should never encounter it. However, if some code
+ // path does end up here, then this needs to be investigated.
+ SkFAIL("Not implemented!");
}
+
+ // Blit a horizontal run of antialiased pixels; runs[] is a *sparse*
+ // zero-terminated run-length encoding of spans of constant alpha values.
+ virtual void blitAntiH(int x, int y,
+ const SkAlpha antialias[],
+ const int16_t runs[]) SK_OVERRIDE;
+
+ // Blit a vertical run of pixels with a constant alpha value.
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
+ // This function is currently not implemented. It is not explicitly
+ // required by the contract, but if at some time a code path runs into
+ // this function (which is entirely possible), it needs to be implemented.
+ //
+ // TODO (krajcevski):
+ // This function will be most easily implemented in one of two ways:
+ // 1. Buffer each vertical column value and then construct a list
+ // of alpha values and output all of the blocks at once. This only
+ // requires a write to the compressed buffer
+ // 2. Replace the indices of each block with the proper indices based
+ // on the alpha value. This requires a read and write of the compressed
+ // buffer, but much less overhead.
+ SkFAIL("Not implemented!");
+ }
+
+ // Blit a solid rectangle one or more pixels wide.
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
+ // Analogous to blitRow, this function is intended for RGB targets
+ // and should never be called by this blitter. Any calls to this function
+ // are probably a bug and should be investigated.
+ SkFAIL("Not implemented!");
+ }
+
+ // Blit a rectangle with one alpha-blended column on the left,
+ // width (zero or more) opaque pixels, and one alpha-blended column
+ // on the right. The result will always be at least two pixels wide.
+ virtual void blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
+ // This function is currently not implemented. It is not explicitly
+ // required by the contract, but if at some time a code path runs into
+ // this function (which is entirely possible), it needs to be implemented.
+ //
+ // TODO (krajcevski):
+ // This function will be most easily implemented as follows:
+ // 1. If width/height are smaller than a block, then update the
+ // indices of the affected blocks.
+ // 2. If width/height are larger than a block, then construct a 9-patch
+ // of block encodings that represent the rectangle, and write them
+ // to the compressed buffer as necessary. Whether or not the blocks
+ // are overwritten by zeros or just their indices are updated is up
+ // to debate.
+ SkFAIL("Not implemented!");
+ }
+
+ // Blit a pattern of pixels defined by a rectangle-clipped mask;
+ // typically used for text.
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE {
+ // This function is currently not implemented. It is not explicitly
+ // required by the contract, but if at some time a code path runs into
+ // this function (which is entirely possible), it needs to be implemented.
+ //
+ // TODO (krajcevski):
+ // This function will be most easily implemented in the same way as
+ // blitAntiRect above.
+ SkFAIL("Not implemented!");
+ }
+
+ // If the blitter just sets a single value for each pixel, return the
+ // bitmap it draws into, and assign value. If not, return NULL and ignore
+ // the value parameter.
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE {
+ return NULL;
+ }
+
+ /**
+ * Compressed texture blitters only really work correctly if they get
+ * four blocks at a time. That being said, this blitter tries it's best
+ * to preserve semantics if blitAntiH doesn't get called in too many
+ * weird ways...
+ */
+ virtual int requestRowsPreserved() const { return kR11_EACBlockSz; }
+
+protected:
+ virtual void onNotifyFinished() { this->flushRuns(); }
+
+private:
+ static const int kR11_EACBlockSz = 4;
+ static const int kPixelsPerBlock = kR11_EACBlockSz * kR11_EACBlockSz;
+
+ // The longest possible run of pixels that this blitter will receive.
+ // This is initialized in the constructor to 0x7FFE, which is one less
+ // than the largest positive 16-bit integer. We make sure that it's one
+ // less for debugging purposes. We also don't make this variable static
+ // in order to make sure that we can construct a valid pointer to it.
+ const int16_t kLongestRun;
+
+ // Usually used in conjunction with kLongestRun. This is initialized to
+ // zero.
+ const SkAlpha kZeroAlpha;
+
+ // This is the information that we buffer whenever we're asked to blit
+ // a row with this blitter.
+ struct BufferedRun {
+ const SkAlpha* fAlphas;
+ const int16_t* fRuns;
+ int fX, fY;
+ } fBufferedRuns[kR11_EACBlockSz];
+
+ // The next row (0-3) that we need to blit. This value should never exceed
+ // the number of rows that we have (kR11_EACBlockSz)
+ int fNextRun;
+
+ // The width and height of the image that we're blitting
+ const int fWidth;
+ const int fHeight;
+
+ // The R11 EAC buffer that we're blitting into. It is assumed that the buffer
+ // is large enough to store a compressed image of size fWidth*fHeight.
+ uint64_t* const fBuffer;
+
+ // Various utility functions
+ int blocksWide() const { return fWidth / kR11_EACBlockSz; }
+ int blocksTall() const { return fHeight / kR11_EACBlockSz; }
+ int totalBlocks() const { return (fWidth * fHeight) / kPixelsPerBlock; }
+
+ // Returns the block index for the block containing pixel (x, y). Block
+ // indices start at zero and proceed in raster order.
+ int getBlockOffset(int x, int y) const {
+ SkASSERT(x < fWidth);
+ SkASSERT(y < fHeight);
+ const int blockCol = x / kR11_EACBlockSz;
+ const int blockRow = y / kR11_EACBlockSz;
+ return blockRow * this->blocksWide() + blockCol;
+ }
+
+ // Returns a pointer to the block containing pixel (x, y)
+ uint64_t *getBlock(int x, int y) const {
+ return fBuffer + this->getBlockOffset(x, y);
+ }
+
+ // The following function writes the buffered runs to compressed blocks.
+ // If fNextRun < 4, then we fill the runs that we haven't buffered with
+ // the constant zero buffer.
+ void flushRuns();
+};
- sk_free(dst);
- return NULL;
-}
R11_EACBlitter::R11_EACBlitter(int width, int height, void *latcBuffer)
// 0x7FFE is one minus the largest positive 16-bit int. We use it for
@@ -1027,11 +859,7 @@ void R11_EACBlitter::flushRuns() {
// end of a loop.
// Setup:
- uint32_t c1 = 0;
- uint32_t c2 = 0;
- uint32_t c3 = 0;
- uint32_t c4 = 0;
-
+ uint32_t c[4] = { 0, 0, 0, 0 };
uint32_t curAlphaColumn = 0;
SkAlpha *curAlpha = reinterpret_cast<SkAlpha*>(&curAlphaColumn);
@@ -1066,10 +894,10 @@ void R11_EACBlitter::flushRuns() {
const int colsLeft = 4 - col;
SkASSERT(curX + colsLeft <= finalX);
- update_block_columns(&c1, &c2, &c3, &c4, col, colsLeft, curAlphaColumn);
+ update_block_columns(c, col, colsLeft, curAlphaColumn);
// Write this block
- *outPtr = compress_block_vertical(c1, c2, c3, c4);
+ *outPtr = compress_block_vertical(c[0], c[1], c[2], c[3]);
++outPtr;
curX += colsLeft;
}
@@ -1081,10 +909,10 @@ void R11_EACBlitter::flushRuns() {
const int col = 0;
const int colsLeft = kR11_EACBlockSz;
- update_block_columns(&c1, &c2, &c3, &c4, col, colsLeft, curAlphaColumn);
+ update_block_columns(c, col, colsLeft, curAlphaColumn);
// While we can keep advancing, just keep writing the block.
- uint64_t lastBlock = compress_block_vertical(c1, c2, c3, c4);
+ uint64_t lastBlock = compress_block_vertical(c[0], c[1], c[2], c[3]);
while((finalX - curX) >= kR11_EACBlockSz) {
*outPtr = lastBlock;
++outPtr;
@@ -1097,7 +925,7 @@ void R11_EACBlitter::flushRuns() {
const int col = curX & 3;
const int colsLeft = finalX - curX;
- update_block_columns(&c1, &c2, &c3, &c4, col, colsLeft, curAlphaColumn);
+ update_block_columns(c, col, colsLeft, curAlphaColumn);
curX += colsLeft;
}
@@ -1123,10 +951,14 @@ void R11_EACBlitter::flushRuns() {
// If we didn't land on a block boundary, output the block...
if ((curX & 3) > 1) {
- *outPtr = compress_block_vertical(c1, c2, c3, c4);
+ *outPtr = compress_block_vertical(c[0], c[1], c[2], c[3]);
}
fNextRun = 0;
}
+SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer) {
+ return new R11_EACBlitter(width, height, outputBuffer);
+}
+
} // namespace SkTextureCompressor
« no previous file with comments | « src/utils/SkTextureCompressor_R11EAC.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698