aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar krajcevski <krajcevski@google.com>2014-08-07 08:15:14 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-07 08:15:14 -0700
commitb8ccc2f6d258a8466f79fc418e9e0a55aeaf58ce (patch)
tree1e859270a248919ef5f5562fe576958384b8abeb
parent963137b75c0a1fe91f35e9826742f36309f5e65d (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.gyp1
-rw-r--r--src/gpu/GrSWMaskHelper.cpp92
-rw-r--r--src/gpu/GrSWMaskHelper.h22
-rw-r--r--src/utils/SkTextureCompressor.cpp10
-rw-r--r--src/utils/SkTextureCompressor.h16
-rw-r--r--src/utils/SkTextureCompressor_ASTC.cpp23
-rw-r--r--src/utils/SkTextureCompressor_ASTC.h6
-rw-r--r--src/utils/SkTextureCompressor_LATC.cpp20
-rw-r--r--src/utils/SkTextureCompressor_LATC.h7
-rw-r--r--src/utils/SkTextureCompressor_R11EAC.cpp24
-rw-r--r--src/utils/SkTextureCompressor_R11EAC.h7
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);
}