OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkTextureCompressor_Blitter_DEFINED | 8 #ifndef SkTextureCompressor_Blitter_DEFINED |
9 #define SkTextureCompressor_Blitter_DEFINED | 9 #define SkTextureCompressor_Blitter_DEFINED |
10 | 10 |
11 #include "SkTypes.h" | 11 #include "SkTypes.h" |
12 #include "SkBlitter.h" | 12 #include "SkBlitter.h" |
13 | 13 |
14 namespace SkTextureCompressor { | 14 namespace SkTextureCompressor { |
15 | 15 |
16 // The function used to compress an A8 block. This function is expected to be | |
17 // used as a template argument to SkCompressedAlphaBlitter. The layout of the | |
18 // block is also expected to be in column-major order. | |
19 typedef void (*CompressA8Proc)(uint8_t* dst, const uint8_t block[]); | |
20 | |
21 // This class implements a blitter that blits directly into a buffer that will | 16 // This class implements a blitter that blits directly into a buffer that will |
22 // be used as an compressed alpha texture. We compute this buffer by | 17 // be used as an compressed alpha texture. We compute this buffer by |
23 // buffering scan lines and then outputting them all at once. The number of | 18 // buffering scan lines and then outputting them all at once. The number of |
24 // scan lines buffered is controlled by kBlockSize | 19 // scan lines buffered is controlled by kBlockSize |
25 template<int BlockDim, int EncodedBlockSize, CompressA8Proc CompressionProc> | 20 // |
| 21 // The CompressorType is a struct with a bunch of static methods that provides |
| 22 // the specialized compression functionality of the blitter. A complete Compress
orType |
| 23 // will implement the following static functions; |
| 24 // |
| 25 // struct CompressorType { |
| 26 // // The function used to compress an A8 block. The layout of the |
| 27 // // block is also expected to be in column-major order. |
| 28 // static void CompressA8Vertical(uint8_t* dst, const uint8_t block[]); |
| 29 // |
| 30 // // The function used to compress an A8 block. The layout of the |
| 31 // // block is also expected to be in row-major order. |
| 32 // static void CompressA8Horizontal(uint8_t* dst, const uint8_t block[]); |
| 33 // |
| 34 // // The function used to update an already compressed block. This will |
| 35 // // most likely be implementation dependent. |
| 36 // static void UpdateBlock(uint8_t* dst, const uint8_t* src); |
| 37 // }; |
| 38 // |
| 39 template<int BlockDim, int EncodedBlockSize, typename CompressorType> |
26 class SkTCompressedAlphaBlitter : public SkBlitter { | 40 class SkTCompressedAlphaBlitter : public SkBlitter { |
27 public: | 41 public: |
28 SkTCompressedAlphaBlitter(int width, int height, void *compressedBuffer) | 42 SkTCompressedAlphaBlitter(int width, int height, void *compressedBuffer) |
29 // 0x7FFE is one minus the largest positive 16-bit int. We use it for | 43 // 0x7FFE is one minus the largest positive 16-bit int. We use it for |
30 // debugging to make sure that we're properly setting the nextX distance | 44 // debugging to make sure that we're properly setting the nextX distance |
31 // in flushRuns(). | 45 // in flushRuns(). |
32 : kLongestRun(0x7FFE), kZeroAlpha(0) | 46 : kLongestRun(0x7FFE), kZeroAlpha(0) |
33 , fNextRun(0) | 47 , fNextRun(0) |
34 , fWidth(width) | 48 , fWidth(width) |
35 , fHeight(height) | 49 , fHeight(height) |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 | 346 |
333 // Do we need to populate the rest of the block? | 347 // Do we need to populate the rest of the block? |
334 if ((finalX - (BlockDim*(curX / BlockDim))) >= BlockDim) { | 348 if ((finalX - (BlockDim*(curX / BlockDim))) >= BlockDim) { |
335 const int col = curX % BlockDim; | 349 const int col = curX % BlockDim; |
336 const int colsLeft = BlockDim - col; | 350 const int colsLeft = BlockDim - col; |
337 SkASSERT(curX + colsLeft <= finalX); | 351 SkASSERT(curX + colsLeft <= finalX); |
338 | 352 |
339 this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); | 353 this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); |
340 | 354 |
341 // Write this block | 355 // Write this block |
342 CompressionProc(outPtr, reinterpret_cast<uint8_t*>(block)); | 356 CompressorType::CompressA8Vertical(outPtr, reinterpret_cast<uint
8_t*>(block)); |
343 outPtr += EncodedBlockSize; | 357 outPtr += EncodedBlockSize; |
344 curX += colsLeft; | 358 curX += colsLeft; |
345 } | 359 } |
346 | 360 |
347 // If we can advance even further, then just keep memsetting the blo
ck | 361 // If we can advance even further, then just keep memsetting the blo
ck |
348 if ((finalX - curX) >= BlockDim) { | 362 if ((finalX - curX) >= BlockDim) { |
349 SkASSERT((curX % BlockDim) == 0); | 363 SkASSERT((curX % BlockDim) == 0); |
350 | 364 |
351 const int col = 0; | 365 const int col = 0; |
352 const int colsLeft = BlockDim; | 366 const int colsLeft = BlockDim; |
353 | 367 |
354 this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); | 368 this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); |
355 | 369 |
356 // While we can keep advancing, just keep writing the block. | 370 // While we can keep advancing, just keep writing the block. |
357 uint8_t lastBlock[EncodedBlockSize]; | 371 uint8_t lastBlock[EncodedBlockSize]; |
358 CompressionProc(lastBlock, reinterpret_cast<uint8_t*>(block)); | 372 CompressorType::CompressA8Vertical(lastBlock, reinterpret_cast<u
int8_t*>(block)); |
359 while((finalX - curX) >= BlockDim) { | 373 while((finalX - curX) >= BlockDim) { |
360 memcpy(outPtr, lastBlock, EncodedBlockSize); | 374 memcpy(outPtr, lastBlock, EncodedBlockSize); |
361 outPtr += EncodedBlockSize; | 375 outPtr += EncodedBlockSize; |
362 curX += BlockDim; | 376 curX += BlockDim; |
363 } | 377 } |
364 } | 378 } |
365 | 379 |
366 // If we haven't advanced within the block then do so. | 380 // If we haven't advanced within the block then do so. |
367 if (curX < finalX) { | 381 if (curX < finalX) { |
368 const int col = curX % BlockDim; | 382 const int col = curX % BlockDim; |
(...skipping 17 matching lines...) Expand all Loading... |
386 } | 400 } |
387 | 401 |
388 finalX = 0xFFFFF; | 402 finalX = 0xFFFFF; |
389 for (int i = 0; i < BlockDim; ++i) { | 403 for (int i = 0; i < BlockDim; ++i) { |
390 finalX = SkMin32(nextX[i], finalX); | 404 finalX = SkMin32(nextX[i], finalX); |
391 } | 405 } |
392 } | 406 } |
393 | 407 |
394 // If we didn't land on a block boundary, output the block... | 408 // If we didn't land on a block boundary, output the block... |
395 if ((curX % BlockDim) > 1) { | 409 if ((curX % BlockDim) > 1) { |
396 CompressionProc(outPtr, reinterpret_cast<uint8_t*>(block)); | 410 CompressorType::CompressA8Vertical(outPtr, reinterpret_cast<uint8_t*
>(block)); |
397 } | 411 } |
398 | 412 |
399 fNextRun = 0; | 413 fNextRun = 0; |
400 } | 414 } |
401 }; | 415 }; |
402 | 416 |
403 } // namespace SkTextureCompressor | 417 } // namespace SkTextureCompressor |
404 | 418 |
405 #endif // SkTextureCompressor_Blitter_DEFINED | 419 #endif // SkTextureCompressor_Blitter_DEFINED |
OLD | NEW |