diff options
author | krajcevski <krajcevski@google.com> | 2014-08-07 08:15:14 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-07 08:15:14 -0700 |
commit | b8ccc2f6d258a8466f79fc418e9e0a55aeaf58ce (patch) | |
tree | 1e859270a248919ef5f5562fe576958384b8abeb | |
parent | 963137b75c0a1fe91f35e9826742f36309f5e65d (diff) |
Pass compressed blitters to our mask drawing algorithm
R=robertphillips@google.com, reed@google.com
Author: krajcevski@google.com
Review URL: https://codereview.chromium.org/446103002
-rw-r--r-- | gyp/ktx.gyp | 1 | ||||
-rw-r--r-- | src/gpu/GrSWMaskHelper.cpp | 92 | ||||
-rw-r--r-- | src/gpu/GrSWMaskHelper.h | 22 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor.cpp | 10 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor.h | 16 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_ASTC.cpp | 23 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_ASTC.h | 6 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_LATC.cpp | 20 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_LATC.h | 7 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_R11EAC.cpp | 24 | ||||
-rw-r--r-- | src/utils/SkTextureCompressor_R11EAC.h | 7 |
11 files changed, 170 insertions, 58 deletions
diff --git a/gyp/ktx.gyp b/gyp/ktx.gyp index 32a5c32ce8..dda353d430 100644 --- a/gyp/ktx.gyp +++ b/gyp/ktx.gyp @@ -9,6 +9,7 @@ 'include_dirs' : [ '../third_party/ktx', '../include/gpu', + '../src/core', '../src/gpu', '../src/utils', ], diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp index 744fa1db8f..2863739161 100644 --- a/src/gpu/GrSWMaskHelper.cpp +++ b/src/gpu/GrSWMaskHelper.cpp @@ -125,13 +125,21 @@ void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegio } paint.setAntiAlias(antiAlias); + SkTBlitterAllocator allocator; + SkBlitter* blitter = NULL; + if (kBlitter_CompressionMode == fCompressionMode) { + SkASSERT(NULL != fCompressedBuffer.get()); + blitter = SkTextureCompressor::CreateBlitterForFormat( + fBM.width(), fBM.height(), fCompressedBuffer.get(), &allocator, fCompressedFormat); + } + if (SkRegion::kReplace_Op == op && 0xFF == alpha) { SkASSERT(0xFF == paint.getAlpha()); - fDraw.drawPathCoverage(path, paint); + fDraw.drawPathCoverage(path, paint, blitter); } else { paint.setXfermodeMode(op_to_mode(op)); paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); - fDraw.drawPath(path, paint); + fDraw.drawPath(path, paint, blitter); } } @@ -150,31 +158,50 @@ bool GrSWMaskHelper::init(const SkIRect& resultBounds, resultBounds.height()); #if GR_COMPRESS_ALPHA_MASK - fCompressMask = choose_compressed_fmt(fContext->getGpu()->caps(), &fCompressedFormat); -#else - fCompressMask = false; + if (choose_compressed_fmt(fContext->getGpu()->caps(), &fCompressedFormat)) { + fCompressionMode = kCompress_CompressionMode; + } #endif - // Make sure that the width is a multiple of 16 so that we can use - // specialized SIMD instructions that compress 4 blocks at a time. - int cmpWidth, cmpHeight; - if (fCompressMask) { + // Make sure that the width is a multiple of the desired block dimensions + // to allow for specialized SIMD instructions that compress multiple blocks at a time. + int cmpWidth = bounds.fRight; + int cmpHeight = bounds.fBottom; + if (kCompress_CompressionMode == fCompressionMode) { int dimX, dimY; SkTextureCompressor::GetBlockDimensions(fCompressedFormat, &dimX, &dimY); - cmpWidth = dimX * ((bounds.fRight + (dimX - 1)) / dimX); - cmpHeight = dimY * ((bounds.fBottom + (dimY - 1)) / dimY); - } else { - cmpWidth = bounds.fRight; - cmpHeight = bounds.fBottom; - } + cmpWidth = dimX * ((cmpWidth + (dimX - 1)) / dimX); + cmpHeight = dimY * ((cmpHeight + (dimY - 1)) / dimY); + + // Can we create a blitter? + if (SkTextureCompressor::ExistsBlitterForFormat(fCompressedFormat)) { + int cmpSz = SkTextureCompressor::GetCompressedDataSize( + fCompressedFormat, cmpWidth, cmpHeight); + + SkASSERT(cmpSz > 0); + SkASSERT(NULL == fCompressedBuffer.get()); + fCompressedBuffer.reset(cmpSz); + fCompressionMode = kBlitter_CompressionMode; + } + } + + // If we don't have a custom blitter, then we either need a bitmap to compress + // from or a bitmap that we're going to use as a texture. In any case, we should + // allocate the pixels for a bitmap + const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(cmpWidth, cmpHeight); + if (kBlitter_CompressionMode != fCompressionMode) { + if (!fBM.allocPixels(bmImageInfo)) { + return false; + } - if (!fBM.allocPixels(SkImageInfo::MakeA8(cmpWidth, cmpHeight))) { - return false; + sk_bzero(fBM.getPixels(), fBM.getSafeSize()); + } else { + // Otherwise, we just need to remember how big the buffer is... + fBM.setInfo(bmImageInfo); } - sk_bzero(fBM.getPixels(), fBM.getSafeSize()); - sk_bzero(&fDraw, sizeof(fDraw)); + fRasterClip.setRect(bounds); fDraw.fRC = &fRasterClip; fDraw.fClip = &fRasterClip.bwRgn(); @@ -193,7 +220,7 @@ bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) { desc.fHeight = fBM.height(); desc.fConfig = kAlpha_8_GrPixelConfig; - if (fCompressMask) { + if (kNone_CompressionMode != fCompressionMode) { #ifdef SK_DEBUG int dimX, dimY; @@ -203,12 +230,7 @@ bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) { #endif desc.fConfig = fmt_to_config(fCompressedFormat); - - // If this config isn't supported then we should fall back to A8 - if (!(fContext->getGpu()->caps()->isConfigTexturable(desc.fConfig))) { - SkDEBUGFAIL("Determining compression should be set from choose_compressed_fmt"); - desc.fConfig = kAlpha_8_GrPixelConfig; - } + SkASSERT(fContext->getGpu()->caps()->isConfigTexturable(desc.fConfig)); } texture->set(fContext, desc); @@ -253,11 +275,19 @@ void GrSWMaskHelper::toTexture(GrTexture *texture) { desc.fConfig = texture->config(); // First see if we should compress this texture before uploading. - if (fCompressMask) { - this->compressTextureData(texture, desc); - } else { - // Looks like we have to send a full A8 texture. - this->sendTextureData(texture, desc, fBM.getPixels(), fBM.rowBytes()); + switch (fCompressionMode) { + case kNone_CompressionMode: + this->sendTextureData(texture, desc, fBM.getPixels(), fBM.rowBytes()); + break; + + case kCompress_CompressionMode: + this->compressTextureData(texture, desc); + break; + + case kBlitter_CompressionMode: + SkASSERT(NULL != fCompressedBuffer.get()); + this->sendTextureData(texture, desc, fCompressedBuffer.get(), 0); + break; } } diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h index 4c06786280..ccd2df865e 100644 --- a/src/gpu/GrSWMaskHelper.h +++ b/src/gpu/GrSWMaskHelper.h @@ -42,7 +42,8 @@ class GrDrawTarget; class GrSWMaskHelper : SkNoncopyable { public: GrSWMaskHelper(GrContext* context) - : fContext(context), fCompressMask(false) { + : fContext(context) + , fCompressionMode(kNone_CompressionMode) { } // set up the internal state in preparation for draws. Since many masks @@ -94,7 +95,6 @@ public: GrDrawTarget* target, const SkIRect& rect); -protected: private: GrContext* fContext; SkMatrix fMatrix; @@ -102,12 +102,22 @@ private: SkDraw fDraw; SkRasterClip fRasterClip; - // This flag says whether or not we should compress the mask. If - // it is true, then fCompressedFormat is always valid. - bool fCompressMask; + // This enum says whether or not we should compress the mask: + // kNone_CompressionMode: compression is not supported on this device. + // kCompress_CompressionMode: compress the bitmap before it gets sent to the gpu + // kBlitter_CompressionMode: write to the bitmap using a special compressed blitter. + enum CompressionMode { + kNone_CompressionMode, + kCompress_CompressionMode, + kBlitter_CompressionMode, + } fCompressionMode; + + // This is the buffer into which we store our compressed data. This buffer is + // only allocated (non-null) if fCompressionMode is kBlitter_CompressionMode + SkAutoMalloc fCompressedBuffer; // This is the desired format within which to compress the - // texture. This value is only valid if fCompressMask is true. + // texture. This value is only valid if fCompressionMode is not kNone_CompressionMode. SkTextureCompressor::Format fCompressedFormat; // Actually sends the texture data to the GPU. This is called from diff --git a/src/utils/SkTextureCompressor.cpp b/src/utils/SkTextureCompressor.cpp index 4034615b37..4ced9a0b57 100644 --- a/src/utils/SkTextureCompressor.cpp +++ b/src/utils/SkTextureCompressor.cpp @@ -11,6 +11,7 @@ #include "SkTextureCompressor_R11EAC.h" #include "SkBitmap.h" +#include "SkBitmapProcShader.h" #include "SkData.h" #include "SkEndian.h" @@ -172,16 +173,17 @@ SkData *CompressBitmapToFormat(const SkBitmap &bitmap, Format format) { return NULL; } -SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, Format format) { +SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, + SkTBlitterAllocator *allocator, Format format) { switch(format) { case kLATC_Format: - return CreateLATCBlitter(width, height, compressedBuffer); + return CreateLATCBlitter(width, height, compressedBuffer, allocator); case kR11_EAC_Format: - return CreateR11EACBlitter(width, height, compressedBuffer); + return CreateR11EACBlitter(width, height, compressedBuffer, allocator); case kASTC_12x12_Format: - return CreateASTCBlitter(width, height, compressedBuffer); + return CreateASTCBlitter(width, height, compressedBuffer, allocator); default: return NULL; diff --git a/src/utils/SkTextureCompressor.h b/src/utils/SkTextureCompressor.h index e44e7b353d..d82bf07a1e 100644 --- a/src/utils/SkTextureCompressor.h +++ b/src/utils/SkTextureCompressor.h @@ -8,6 +8,7 @@ #ifndef SkTextureCompressor_DEFINED #define SkTextureCompressor_DEFINED +#include "SkBitmapProcShader.h" #include "SkImageInfo.h" class SkBitmap; @@ -73,11 +74,24 @@ namespace SkTextureCompressor { typedef bool (*CompressionProc)(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes); + // Returns true if there exists a blitter for the specified format. + inline bool ExistsBlitterForFormat(Format format) { + switch (format) { + case kLATC_Format: + case kR11_EAC_Format: + case kASTC_12x12_Format: + return true; + + default: + return false; + } + } + // Returns the blitter for the given compression format. Note, the blitter // is intended to be used with the proper input. I.e. if you try to blit // RGB source data into an R11 EAC texture, you're gonna have a bad time. SkBlitter* CreateBlitterForFormat(int width, int height, void* compressedBuffer, - Format format); + SkTBlitterAllocator *allocator, Format format); // Returns the desired dimensions of the block size for the given format. These dimensions // don't necessarily correspond to the specification's dimensions, since there may diff --git a/src/utils/SkTextureCompressor_ASTC.cpp b/src/utils/SkTextureCompressor_ASTC.cpp index fbae8504e5..816d2f1860 100644 --- a/src/utils/SkTextureCompressor_ASTC.cpp +++ b/src/utils/SkTextureCompressor_ASTC.cpp @@ -2011,9 +2011,26 @@ bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, return true; } -SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer) { - return new - SkTCompressedAlphaBlitter<12, 16, CompressA8ASTCBlockVertical> +SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator* allocator) { + if ((width % 12) != 0 || (height % 12) != 0) { + return NULL; + } + + // Memset the output buffer to an encoding that decodes to zero. We must do this + // in order to avoid having uninitialized values in the buffer if the blitter + // decides not to write certain scanlines (and skip entire rows of blocks). + // In the case of ASTC, if everything index is zero, then the interpolated value + // will decode to zero provided we have the right header. We use the encoding + // from recognizing all zero blocks from above. + const int nBlocks = (width * height / 144); + uint8_t *dst = reinterpret_cast<uint8_t *>(outputBuffer); + for (int i = 0; i < nBlocks; ++i) { + send_packing(&dst, SkTEndian_SwapLE64(0x0000000001FE000173ULL), 0); + } + + return allocator->createT< + SkTCompressedAlphaBlitter<12, 16, CompressA8ASTCBlockVertical>, int, int, void* > (width, height, outputBuffer); } diff --git a/src/utils/SkTextureCompressor_ASTC.h b/src/utils/SkTextureCompressor_ASTC.h index 57ba08d440..bdbe6305c6 100644 --- a/src/utils/SkTextureCompressor_ASTC.h +++ b/src/utils/SkTextureCompressor_ASTC.h @@ -8,9 +8,8 @@ #ifndef SkTextureCompressor_ASTC_DEFINED #define SkTextureCompressor_ASTC_DEFINED -#include <stdint.h> +#include "SkBitmapProcShader.h" -// Forward declare class SkBlitter; namespace SkTextureCompressor { @@ -18,7 +17,8 @@ namespace SkTextureCompressor { bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes); - SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer); + SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator *allocator); void DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height, int blockDimX, int blockDimY); diff --git a/src/utils/SkTextureCompressor_LATC.cpp b/src/utils/SkTextureCompressor_LATC.cpp index 5db0fc6c04..0b9cf17ad6 100644 --- a/src/utils/SkTextureCompressor_LATC.cpp +++ b/src/utils/SkTextureCompressor_LATC.cpp @@ -8,6 +8,7 @@ #include "SkTextureCompressor_LATC.h" #include "SkTextureCompressor_Blitter.h" +#include "SkBlitter.h" #include "SkEndian.h" // Compression options. In general, the slow version is much more accurate, but @@ -427,10 +428,23 @@ bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, i #endif } -SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer) { +SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator* allocator) { + if ((width % 4) != 0 || (height % 4) != 0) { + return NULL; + } + #if COMPRESS_LATC_FAST - return new - SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical> + // Memset the output buffer to an encoding that decodes to zero. We must do this + // in order to avoid having uninitialized values in the buffer if the blitter + // decides not to write certain scanlines (and skip entire rows of blocks). + // In the case of LATC, if everything is zero, then LUM0 and LUM1 are also zero, + // and they will only be non-zero (0xFF) if the index is 7. So bzero will do just fine. + // (8 bytes per block) * (w * h / 16 blocks) = w * h / 2 + sk_bzero(outputBuffer, width * height / 2); + + return allocator->createT< + SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical>, int, int, void* > (width, height, outputBuffer); #elif COMPRESS_LATC_SLOW // TODO (krajcevski) diff --git a/src/utils/SkTextureCompressor_LATC.h b/src/utils/SkTextureCompressor_LATC.h index 6ee2ff63e2..e41a249e2a 100644 --- a/src/utils/SkTextureCompressor_LATC.h +++ b/src/utils/SkTextureCompressor_LATC.h @@ -8,14 +8,17 @@ #ifndef SkTextureCompressor_LATC_DEFINED #define SkTextureCompressor_LATC_DEFINED -#include "SkBlitter.h" +#include "SkBitmapProcShader.h" + +class SkBlitter; namespace SkTextureCompressor { bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes); - SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer); + SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator *allocator); void DecompressLATC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width, int height); } diff --git a/src/utils/SkTextureCompressor_R11EAC.cpp b/src/utils/SkTextureCompressor_R11EAC.cpp index 7baa219a28..1d2b8e54aa 100644 --- a/src/utils/SkTextureCompressor_R11EAC.cpp +++ b/src/utils/SkTextureCompressor_R11EAC.cpp @@ -8,6 +8,7 @@ #include "SkTextureCompressor.h" #include "SkTextureCompressor_Blitter.h" +#include "SkBlitter.h" #include "SkEndian.h" // #define COMPRESS_R11_EAC_SLOW 1 @@ -608,9 +609,26 @@ bool CompressA8ToR11EAC(uint8_t* dst, const uint8_t* src, int width, int height, #endif } -SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer) { - return new - SkTCompressedAlphaBlitter<4, 8, compress_block_vertical> +SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator* allocator) { + + if ((width % 4) != 0 || (height % 4) != 0) { + return NULL; + } + + // Memset the output buffer to an encoding that decodes to zero. We must do this + // in order to avoid having uninitialized values in the buffer if the blitter + // decides not to write certain scanlines (and skip entire rows of blocks). + // In the case of R11, we use the encoding from recognizing all zero pixels from above. + const int nBlocks = (width * height / 16); // 4x4 pixel blocks. + uint64_t *dst = reinterpret_cast<uint64_t *>(outputBuffer); + for (int i = 0; i < nBlocks; ++i) { + *dst = 0x0020000000002000ULL; + ++dst; + } + + return allocator->createT< + SkTCompressedAlphaBlitter<4, 8, compress_block_vertical>, int, int, void*> (width, height, outputBuffer); } diff --git a/src/utils/SkTextureCompressor_R11EAC.h b/src/utils/SkTextureCompressor_R11EAC.h index 1dd8e395a8..6786513b67 100644 --- a/src/utils/SkTextureCompressor_R11EAC.h +++ b/src/utils/SkTextureCompressor_R11EAC.h @@ -8,14 +8,17 @@ #ifndef SkTextureCompressor_R11EAC_DEFINED #define SkTextureCompressor_R11EAC_DEFINED -#include "SkBlitter.h" +#include "SkBitmapProcShader.h" + +class SkBlitter; namespace SkTextureCompressor { bool CompressA8ToR11EAC(uint8_t* dst, const uint8_t* src, int width, int height, int rowBytes); - SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer); + SkBlitter* CreateR11EACBlitter(int width, int height, void* outputBuffer, + SkTBlitterAllocator* allocator); void DecompressR11EAC(uint8_t* dst, int dstRB, const uint8_t* src, int width, int height); } |