diff options
author | Mike Reed <reed@google.com> | 2017-10-05 16:04:41 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-10-05 20:25:04 +0000 |
commit | ef8ce2858b7692c9ec9874c43656e603f304c760 (patch) | |
tree | 1b3abd8bd47acfc2e13168df79b58d82878df097 /src | |
parent | ded7aa82afa9672002fcd2a0eff09db59bfd0010 (diff) |
experiments to speed up drawing 32bit images into 565
New (legacy style) blitters only coded for shaders (and very restricted blendmodes)
Bug: skia:
See https://buganizer.corp.google.com/issues/64884885
Change-Id: Ie2546093bfe1e670a825dfd9542d252d53732c40
Reviewed-on: https://skia-review.googlesource.com/54103
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBlitter.cpp | 12 | ||||
-rw-r--r-- | src/core/SkBlitter_RGB565.cpp | 143 | ||||
-rw-r--r-- | src/core/SkBlitter_Sprite.cpp | 16 | ||||
-rw-r--r-- | src/core/SkCoreBlitters.h | 21 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter.h | 2 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter_RGB565.cpp | 179 |
6 files changed, 371 insertions, 2 deletions
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 5eb5dd80d0..6901511d4e 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -918,6 +918,11 @@ bool SkBlitter::UseRasterPipelineBlitter(const SkPixmap& device, const SkPaint& return true; } + // Added support only for shaders (and other constraints) for android + if (device.colorType() == kRGB_565_SkColorType) { + return false; + } + return device.colorType() != kN32_SkColorType; #endif } @@ -1054,6 +1059,13 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, blitter = alloc->make<SkARGB32_Blitter>(device, *paint); } break; + case kRGB_565_SkColorType: + if (shader && SkRGB565_Shader_Blitter::Supports(device, *paint)) { + blitter = alloc->make<SkRGB565_Shader_Blitter>(device, *paint, shaderContext); + } else { + blitter = SkCreateRasterPipelineBlitter(device, *paint, matrix, alloc); + } + break; default: // should have been handled via raster pipeline. diff --git a/src/core/SkBlitter_RGB565.cpp b/src/core/SkBlitter_RGB565.cpp new file mode 100644 index 0000000000..6668f84f72 --- /dev/null +++ b/src/core/SkBlitter_RGB565.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCoreBlitters.h" +#include "SkColorData.h" +#include "SkShader.h" +#include "SkUtils.h" +#include "SkXfermodePriv.h" +#include "SkBlitMask.h" +#include "SkColorData.h" + +#include "SkNx.h" + +static void D16_S32X_src(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) { + SkASSERT(coverage == 0xFF); + for (int i = 0; i < count; ++i) { + dst[i] = SkPixel32ToPixel16(src[i]); + } +} + +static void D16_S32X_src_coverage(uint16_t dst[], const SkPMColor src[], int count, + uint8_t coverage) { + switch (coverage) { + case 0: break; + case 0xFF: + for (int i = 0; i < count; ++i) { + dst[i] = SkPixel32ToPixel16(src[i]); + } + break; + default: + unsigned scale = coverage + (coverage >> 7); + for (int i = 0; i < count; ++i) { + dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]); + } + break; + } +} + +static void D16_S32A_srcover(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) { + SkASSERT(coverage == 0xFF); + for (int i = 0; i < count; ++i) { + dst[i] = SkSrcOver32To16(src[i], dst[i]); + } +} + +static void D16_S32A_srcover_coverage(uint16_t dst[], const SkPMColor src[], int count, + uint8_t coverage) { + switch (coverage) { + case 0: break; + case 0xFF: + for (int i = 0; i < count; ++i) { + dst[i] = SkSrcOver32To16(src[i], dst[i]); + } + break; + default: + unsigned scale = coverage + (coverage >> 7); + for (int i = 0; i < count; ++i) { + dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]); + } + break; + } +} + +bool SkRGB565_Shader_Blitter::Supports(const SkPixmap& device, const SkPaint& paint) { + if (device.colorType() != kRGB_565_SkColorType) { + return false; + } + if (device.colorSpace()) { + return false; + } + if (paint.getBlendMode() != SkBlendMode::kSrcOver && + paint.getBlendMode() != SkBlendMode::kSrc) { + return false; + } + if (paint.isLCDRenderText()) { + return false; + } + if (paint.isDither()) { + return false; + } + return true; +} + +SkRGB565_Shader_Blitter::SkRGB565_Shader_Blitter(const SkPixmap& device, + const SkPaint& paint, SkShaderBase::Context* shaderContext) + : INHERITED(device, paint, shaderContext) +{ + SkASSERT(shaderContext); + SkASSERT(Supports(device, paint)); + + fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); + + bool isOpaque = SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag); + + if (paint.getBlendMode() == SkBlendMode::kSrc || isOpaque) { + fBlend = D16_S32X_src; + fBlendCoverage = D16_S32X_src_coverage; + } else { // srcover + fBlend = isOpaque ? D16_S32X_src : D16_S32A_srcover; + fBlendCoverage = isOpaque ? D16_S32X_src_coverage : D16_S32A_srcover_coverage; + } +} + +SkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() { + sk_free(fBuffer); +} + +void SkRGB565_Shader_Blitter::blitH(int x, int y, int width) { + SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); + + uint16_t* device = fDevice.writable_addr16(x, y); + + SkPMColor* span = fBuffer; + fShaderContext->shadeSpan(x, y, span, width); + fBlend(device, span, width, 0xFF); +} + +void SkRGB565_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha coverage[], + const int16_t runs[]) { + SkPMColor* span = fBuffer; + uint16_t* device = fDevice.writable_addr16(x, y); + auto* shaderContext = fShaderContext; + + for (;;) { + int count = *runs; + if (count <= 0) { + break; + } + int aa = *coverage; + if (aa) { + shaderContext->shadeSpan(x, y, span, count); + fBlendCoverage(device, span, count, aa); + } + device += count; + runs += count; + coverage += count; + x += count; + } +} diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp index 3a230029ce..eddb42b25b 100644 --- a/src/core/SkBlitter_Sprite.cpp +++ b/src/core/SkBlitter_Sprite.cpp @@ -184,8 +184,20 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) { blitter = allocator->make<SkSpriteBlitter_Memcpy>(source); } - if (!blitter && !dst.colorSpace() && dst.colorType() == kN32_SkColorType) { - blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); + if (!blitter && !dst.colorSpace()) { + switch (dst.colorType()) { + case kN32_SkColorType: + blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); + break; + case kRGB_565_SkColorType: + blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator); + break; + case kAlpha_8_SkColorType: + blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator); + break; + default: + break; + } } if (!blitter) { blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator); diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 47b20176e6..9d227e9b43 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -137,6 +137,27 @@ private: typedef SkShaderBlitter INHERITED; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef void (*SkS32D16BlendProc)(uint16_t*, const SkPMColor*, int, uint8_t); + +class SkRGB565_Shader_Blitter : public SkShaderBlitter { +public: + SkRGB565_Shader_Blitter(const SkPixmap& device, const SkPaint&, SkShaderBase::Context*); + ~SkRGB565_Shader_Blitter() override; + void blitH(int x, int y, int width) override; + void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override; + + static bool Supports(const SkPixmap& device, const SkPaint&); + +private: + SkPMColor* fBuffer; + SkS32D16BlendProc fBlend; + SkS32D16BlendProc fBlendCoverage; + + typedef SkShaderBlitter INHERITED; +}; + /////////////////////////////////////////////////////////////////////////////// // Neither of these ever returns nullptr, but this first factory may return a SkNullBlitter. diff --git a/src/core/SkSpriteBlitter.h b/src/core/SkSpriteBlitter.h index 9f10dbfc70..42313677cf 100644 --- a/src/core/SkSpriteBlitter.h +++ b/src/core/SkSpriteBlitter.h @@ -33,6 +33,8 @@ public: void blitRect(int x, int y, int width, int height) override = 0; static SkSpriteBlitter* ChooseL32(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); + static SkSpriteBlitter* ChooseL565(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); + static SkSpriteBlitter* ChooseLA8(const SkPixmap& source, const SkPaint&, SkArenaAlloc*); protected: SkPixmap fDst; diff --git a/src/core/SkSpriteBlitter_RGB565.cpp b/src/core/SkSpriteBlitter_RGB565.cpp new file mode 100644 index 0000000000..8151347ceb --- /dev/null +++ b/src/core/SkSpriteBlitter_RGB565.cpp @@ -0,0 +1,179 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSpriteBlitter.h" +#include "SkArenaAlloc.h" +#include "SkBlitRow.h" +#include "SkColorFilter.h" +#include "SkColorData.h" +#include "SkTemplates.h" +#include "SkUtils.h" +#include "SkXfermodePriv.h" + +/////////////////////////////////////////////////////////////////////////////// + +static void S32_src(uint16_t dst[], const SkPMColor src[], int count) { + for (int i = 0; i < count; ++i) { + dst[i] = SkPixel32ToPixel16(src[i]); + } +} + +static void S32_srcover(uint16_t dst[], const SkPMColor src[], int count) { + for (int i = 0; i < count; ++i) { + dst[i] = SkSrcOver32To16(src[i], dst[i]); + } +} + +class Sprite_D16_S32 : public SkSpriteBlitter { +public: + Sprite_D16_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { + SkASSERT(src.colorType() == kN32_SkColorType); + SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); + + fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); + } + + void blitRect(int x, int y, int width, int height) override { + SkASSERT(width > 0 && height > 0); + uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y); + const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); + size_t dstRB = fDst.rowBytes(); + size_t srcRB = fSource.rowBytes(); + + do { + if (fUseSrcOver) { + S32_srcover(dst, src, width); + } else { + S32_src(dst, src, width); + } + + dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB); + src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); + } while (--height != 0); + } + +private: + bool fUseSrcOver; + + typedef SkSpriteBlitter INHERITED; +}; + +SkSpriteBlitter* SkSpriteBlitter::ChooseL565(const SkPixmap& source, const SkPaint& paint, + SkArenaAlloc* allocator) { + SkASSERT(allocator != nullptr); + + if (paint.getColorFilter() != nullptr) { + return nullptr; + } + if (paint.getMaskFilter() != nullptr) { + return nullptr; + } + + U8CPU alpha = paint.getAlpha(); + if (alpha != 0xFF) { + return nullptr; + } + + if (source.colorType() == kN32_SkColorType) { + switch (paint.getBlendMode()) { + case SkBlendMode::kSrc: + case SkBlendMode::kSrcOver: + return allocator->make<Sprite_D16_S32>(source, paint.getBlendMode()); + default: + break; + } + } + return nullptr; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +static unsigned div255(unsigned a, unsigned b) { + return (a * b * 257 + 127) >> 16; +} + +static void S32_src_da8(uint8_t dst[], const SkPMColor src[], int count) { + for (int i = 0; i < count; ++i) { + dst[i] = SkGetPackedA32(src[i]); + } +} + +static void S32_srcover_da8(uint8_t dst[], const SkPMColor src[], int count) { + for (int i = 0; i < count; ++i) { + SkPMColor c = src[i]; + if (c) { + unsigned a = SkGetPackedA32(c); + if (a == 0xFF) { + dst[i] = 0xFF; + } else { + dst[i] = a + div255(255 - a, dst[i]); + } + } + } +} + +class Sprite_D8_S32 : public SkSpriteBlitter { +public: + Sprite_D8_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { + SkASSERT(src.colorType() == kN32_SkColorType); + SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); + + fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); + } + + void blitRect(int x, int y, int width, int height) override { + SkASSERT(width > 0 && height > 0); + uint8_t* SK_RESTRICT dst = fDst.writable_addr8(x, y); + const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); + size_t dstRB = fDst.rowBytes(); + size_t srcRB = fSource.rowBytes(); + + do { + if (fUseSrcOver) { + S32_srcover_da8(dst, src, width); + } else { + S32_src_da8(dst, src, width); + } + + dst = (uint8_t* SK_RESTRICT)((char*)dst + dstRB); + src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); + } while (--height != 0); + } + +private: + bool fUseSrcOver; + + typedef SkSpriteBlitter INHERITED; +}; + +SkSpriteBlitter* SkSpriteBlitter::ChooseLA8(const SkPixmap& source, const SkPaint& paint, + SkArenaAlloc* allocator) { + SkASSERT(allocator != nullptr); + + if (paint.getColorFilter() != nullptr) { + return nullptr; + } + if (paint.getMaskFilter() != nullptr) { + return nullptr; + } + + U8CPU alpha = paint.getAlpha(); + if (alpha != 0xFF) { + return nullptr; + } + + if (source.colorType() == kN32_SkColorType) { + switch (paint.getBlendMode()) { + case SkBlendMode::kSrc: + case SkBlendMode::kSrcOver: + return allocator->make<Sprite_D8_S32>(source, paint.getBlendMode()); + default: + break; + } + } + return nullptr; +} |