Index: src/core/SkBlitter_PM4f.cpp |
diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp |
index bd8ae493dab9f2bca50d98eb07f3c02163a66d25..01fd70425423967cc835f4e93d3226af9fa4793e 100644 |
--- a/src/core/SkBlitter_PM4f.cpp |
+++ b/src/core/SkBlitter_PM4f.cpp |
@@ -11,149 +11,339 @@ |
#include "SkUtils.h" |
#include "SkXfermode.h" |
#include "SkBlitMask.h" |
+#include "SkTemplates.h" |
-////////////////////////////////////////////////////////////////////////////////////// |
- |
-SkARGB32_Shader4f_Blitter::SkARGB32_Shader4f_Blitter(const SkPixmap& device, |
- const SkPaint& paint, SkShader::Context* shaderContext) |
- : INHERITED(device, paint, shaderContext) |
-{ |
- const uint32_t shaderFlags = shaderContext->getFlags(); |
- |
- SkASSERT(shaderFlags & SkShader::kSupports4f_Flag); |
+template <typename State> class SkState_Blitter : public SkRasterBlitter { |
+ typedef SkRasterBlitter INHERITED; |
+ State fState; |
- fBuffer = (SkPM4f*)sk_malloc_throw(device.width() * (sizeof(SkPM4f))); |
+public: |
+ SkState_Blitter(const SkPixmap& device, const SkPaint& paint) |
+ : INHERITED(device) |
+ , fState(device.info(), paint, nullptr) |
+ {} |
- fState.fXfer = SkSafeRef(paint.getXfermode()); |
- fState.fFlags = 0; |
- if (shaderFlags & SkShader::kOpaqueAlpha_Flag) { |
- fState.fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag; |
+ void blitH(int x, int y, int width) override { |
+ SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); |
+ |
+ fState.fProc1(fState, State::WritableAddr(fDevice, x, y), fState.fPM4f, width, nullptr); |
} |
- if (device.info().isSRGB()) { |
- fState.fFlags |= SkXfermode::kDstIsSRGB_PM4fFlag; |
- } |
- if (fState.fXfer) { |
- fProc1 = fState.fXfer->getPM4fProc1(fState.fFlags); |
- fProcN = fState.fXfer->getPM4fProcN(fState.fFlags); |
- } else { |
- fProc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, fState.fFlags); |
- fProcN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, fState.fFlags); |
+ |
+ void blitV(int x, int y, int height, SkAlpha alpha) override { |
+ SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height()); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ size_t deviceRB = fDevice.rowBytes(); |
+ |
+ for (int i = 0; i < height; ++i) { |
+ fState.fProc1(fState, device, fState.fPM4f, 1, &alpha); |
+ device = (typename State::DstType*)((char*)device + deviceRB); |
+ } |
} |
- fConstInY = SkToBool(shaderFlags & SkShader::kConstInY32_Flag); |
-} |
+ void blitRect(int x, int y, int width, int height) override { |
+ SkASSERT(x >= 0 && y >= 0 && |
+ x + width <= fDevice.width() && y + height <= fDevice.height()); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ size_t deviceRB = fDevice.rowBytes(); |
+ |
+ do { |
+ fState.fProc1(fState, device, fState.fPM4f, width, nullptr); |
+ y += 1; |
+ device = (typename State::DstType*)((char*)device + deviceRB); |
+ } while (--height > 0); |
+ } |
-SkARGB32_Shader4f_Blitter::~SkARGB32_Shader4f_Blitter() { |
- SkSafeUnref(fState.fXfer); |
- sk_free(fBuffer); |
-} |
+ void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ |
+ for (;;) { |
+ int count = *runs; |
+ if (count <= 0) { |
+ break; |
+ } |
+ int aa = *antialias; |
+ if (aa) { |
+ if (aa == 255) { |
+ fState.fProc1(fState, device, fState.fPM4f, count, nullptr); |
+ } else { |
+ for (int i = 0; i < count; ++i) { |
+ fState.fProc1(fState, &device[i], fState.fPM4f, 1, antialias); |
+ } |
+ } |
+ } |
+ device += count; |
+ runs += count; |
+ antialias += count; |
+ x += count; |
+ } |
+ } |
-void SkARGB32_Shader4f_Blitter::blitH(int x, int y, int width) { |
- SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); |
+ void blitMask(const SkMask& mask, const SkIRect& clip) override { |
+ // we only handle kA8 |
+ if (SkMask::kA8_Format != mask.fFormat) { |
+ this->INHERITED::blitMask(mask, clip); |
+ return; |
+ } |
+ |
+ SkASSERT(mask.fBounds.contains(clip)); |
+ |
+ const int x = clip.fLeft; |
+ const int width = clip.width(); |
+ const int y = clip.fTop; |
+ const int height = clip.height(); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ const size_t dstRB = fDevice.rowBytes(); |
+ const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y); |
+ const size_t maskRB = mask.fRowBytes; |
+ |
+ for (int i = 0; i < height; ++i) { |
+ fState.fProc1(fState, device, fState.fPM4f, width, maskRow); |
+ device = (typename State::DstType*)((char*)device + dstRB); |
+ maskRow += maskRB; |
+ } |
+ } |
+}; |
- uint32_t* device = fDevice.writable_addr32(x, y); |
- fShaderContext->shadeSpan4f(x, y, fBuffer, width); |
- fProcN(fState, device, fBuffer, width, nullptr); |
-} |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
-void SkARGB32_Shader4f_Blitter::blitRect(int x, int y, int width, int height) { |
- SkASSERT(x >= 0 && y >= 0 && |
- x + width <= fDevice.width() && y + height <= fDevice.height()); |
+template <typename State> class SkState_Shader_Blitter : public SkShaderBlitter { |
+public: |
+ SkState_Shader_Blitter(const SkPixmap& device, const SkPaint& paint, |
+ SkShader::Context* shaderContext) |
+ : INHERITED(device, paint, shaderContext) |
+ , fState(device.info(), paint, shaderContext) |
+ {} |
+ |
+ void blitH(int x, int y, int width) override { |
+ SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); |
+ fState.fProcN(fState, device, fState.fBuffer, width, nullptr); |
+ } |
- uint32_t* device = fDevice.writable_addr32(x, y); |
- size_t deviceRB = fDevice.rowBytes(); |
+ void blitV(int x, int y, int height, SkAlpha alpha) override { |
+ SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height()); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ size_t deviceRB = fDevice.rowBytes(); |
+ const int bottom = y + height; |
+ |
+ if (fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1); |
+ } |
+ for (; y < bottom; ++y) { |
+ if (!fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1); |
+ } |
+ fState.fProcN(fState, device, fState.fBuffer, 1, &alpha); |
+ device = (typename State::DstType*)((char*)device + deviceRB); |
+ } |
+ } |
- if (fConstInY) { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, width); |
- do { |
- fProcN(fState, device, fBuffer, width, nullptr); |
- y += 1; |
- device = (uint32_t*)((char*)device + deviceRB); |
- } while (--height > 0); |
- } else { |
- do { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, width); |
- fProcN(fState, device, fBuffer, width, nullptr); |
- y += 1; |
- device = (uint32_t*)((char*)device + deviceRB); |
- } while (--height > 0); |
+ void blitRect(int x, int y, int width, int height) override { |
+ SkASSERT(x >= 0 && y >= 0 && |
+ x + width <= fDevice.width() && y + height <= fDevice.height()); |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ size_t deviceRB = fDevice.rowBytes(); |
+ const int bottom = y + height; |
+ |
+ if (fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); |
+ } |
+ for (; y < bottom; ++y) { |
+ if (!fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); |
+ } |
+ fState.fProcN(fState, device, fState.fBuffer, width, nullptr); |
+ device = (typename State::DstType*)((char*)device + deviceRB); |
+ } |
} |
-} |
-void SkARGB32_Shader4f_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], |
- const int16_t runs[]) { |
- uint32_t* device = fDevice.writable_addr32(x, y); |
- |
- for (;;) { |
- int count = *runs; |
- if (count <= 0) { |
- break; |
- } |
- int aa = *antialias; |
- if (aa) { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, count); |
- if (aa == 255) { |
- fProcN(fState, device, fBuffer, count, nullptr); |
- } else { |
- // count is almost always 1 |
- for (int i = count - 1; i >= 0; --i) { |
- fProcN(fState, &device[i], &fBuffer[i], 1, antialias); |
+ void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ |
+ for (;;) { |
+ int count = *runs; |
+ if (count <= 0) { |
+ break; |
+ } |
+ int aa = *antialias; |
+ if (aa) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, count); |
+ if (aa == 255) { |
+ fState.fProcN(fState, device, fState.fBuffer, count, nullptr); |
+ } else { |
+ for (int i = 0; i < count; ++i) { |
+ fState.fProcN(fState, &device[i], &fState.fBuffer[i], 1, antialias); |
+ } |
} |
} |
+ device += count; |
+ runs += count; |
+ antialias += count; |
+ x += count; |
} |
- device += count; |
- runs += count; |
- antialias += count; |
- x += count; |
} |
-} |
-void SkARGB32_Shader4f_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { |
- // we only handle kA8 |
- if (SkMask::kA8_Format != mask.fFormat) { |
- this->INHERITED::blitMask(mask, clip); |
- return; |
+ void blitMask(const SkMask& mask, const SkIRect& clip) override { |
+ // we only handle kA8 |
+ if (SkMask::kA8_Format != mask.fFormat) { |
+ this->INHERITED::blitMask(mask, clip); |
+ return; |
+ } |
+ |
+ SkASSERT(mask.fBounds.contains(clip)); |
+ |
+ const int x = clip.fLeft; |
+ const int width = clip.width(); |
+ int y = clip.fTop; |
+ |
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y); |
+ const size_t deviceRB = fDevice.rowBytes(); |
+ const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y); |
+ const size_t maskRB = mask.fRowBytes; |
+ |
+ if (fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); |
+ } |
+ for (; y < clip.fBottom; ++y) { |
+ if (!fConstInY) { |
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width); |
+ } |
+ fState.fProcN(fState, device, fState.fBuffer, width, maskRow); |
+ device = (typename State::DstType*)((char*)device + deviceRB); |
+ maskRow += maskRB; |
+ } |
} |
+ |
+private: |
+ State fState; |
- SkASSERT(mask.fBounds.contains(clip)); |
- |
- const int x = clip.fLeft; |
- const int width = clip.width(); |
- int y = clip.fTop; |
- int height = clip.height(); |
+ typedef SkShaderBlitter INHERITED; |
+}; |
- char* dstRow = (char*)fDevice.writable_addr32(x, y); |
- const size_t dstRB = fDevice.rowBytes(); |
- const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y); |
- const size_t maskRB = mask.fRowBytes; |
+////////////////////////////////////////////////////////////////////////////////////// |
- do { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, width); |
- fProcN(fState, reinterpret_cast<SkPMColor*>(dstRow), fBuffer, width, maskRow); |
- dstRow += dstRB; |
- maskRow += maskRB; |
- y += 1; |
- } while (--height > 0); |
+static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderContext) { |
+ return shaderContext ? SkToBool(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) |
+ : 0xFF == paint.getAlpha(); |
} |
-void SkARGB32_Shader4f_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { |
- SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height()); |
+struct State32 : SkXfermode::PM4fState { |
+ typedef uint32_t DstType; |
+ |
+ SkXfermode::PM4fProc1 fProc1; |
+ SkXfermode::PM4fProcN fProcN; |
+ SkPM4f fPM4f; |
+ SkPM4f* fBuffer; |
+ |
+ State32(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) { |
+ fXfer = SkSafeRef(paint.getXfermode()); |
+ fFlags = 0; |
+ if (is_opaque(paint, shaderContext)) { |
+ fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag; |
+ } |
+ if (info.isSRGB()) { |
+ fFlags |= SkXfermode::kDstIsSRGB_PM4fFlag; |
+ } |
+ if (fXfer) { |
+ fProc1 = fXfer->getPM4fProc1(fFlags); |
+ fProcN = fXfer->getPM4fProcN(fFlags); |
+ } else { |
+ fProc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, fFlags); |
+ fProcN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, fFlags); |
+ } |
- uint32_t* device = fDevice.writable_addr32(x, y); |
- size_t deviceRB = fDevice.rowBytes(); |
+ fBuffer = nullptr; |
+ if (shaderContext) { |
+ fBuffer = new SkPM4f[info.width()]; |
+ } else { |
+ fPM4f = SkColor4f::FromColor(paint.getColor()).premul(); |
+ } |
+ } |
+ |
+ ~State32() { |
+ SkSafeUnref(fXfer); |
+ delete[] fBuffer; |
+ } |
+ |
+ static DstType* WritableAddr(const SkPixmap& device, int x, int y) { |
+ return device.writable_addr32(x, y); |
+ } |
+}; |
- if (fConstInY) { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, 1); |
- do { |
- fProcN(fState, device, fBuffer, 1, &alpha); |
- device = (uint32_t*)((char*)device + deviceRB); |
- } while (--height > 0); |
+struct State64 : SkXfermode::U64State { |
+ typedef uint64_t DstType; |
+ |
+ SkXfermode::U64Proc1 fProc1; |
+ SkXfermode::U64ProcN fProcN; |
+ SkPM4f fPM4f; |
+ SkPM4f* fBuffer; |
+ |
+ State64(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) { |
+ fXfer = SkSafeRef(paint.getXfermode()); |
+ fFlags = 0; |
+ if (is_opaque(paint, shaderContext)) { |
+ fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag; |
+ } |
+ if (kRGBA_F16_SkColorType == info.colorType()) { |
+ fFlags |= SkXfermode::kDstIsFloat16_U64Flag; |
+ } |
+ |
+ SkXfermode::Mode mode; |
+ if (SkXfermode::AsMode(fXfer, &mode)) { |
+ mode = SkXfermode::kSrcOver_Mode; |
+ } |
+ fProc1 = SkXfermode::GetU64Proc1(mode, fFlags); |
+ fProcN = SkXfermode::GetU64ProcN(mode, fFlags); |
+ |
+ fBuffer = nullptr; |
+ if (shaderContext) { |
+ fBuffer = new SkPM4f[info.width()]; |
+ } else { |
+ fPM4f = SkColor4f::FromColor(paint.getColor()).premul(); |
+ } |
+ } |
+ |
+ ~State64() { |
+ SkSafeUnref(fXfer); |
+ delete[] fBuffer; |
+ } |
+ |
+ static DstType* WritableAddr(const SkPixmap& device, int x, int y) { |
+ return device.writable_addr64(x, y); |
+ } |
+}; |
+ |
+template <typename State> SkBlitter* create(const SkPixmap& device, const SkPaint& paint, |
+ SkShader::Context* shaderContext, |
+ SkTBlitterAllocator* allocator) { |
+ SkASSERT(allocator != nullptr); |
+ |
+ if (shaderContext) { |
+ return allocator->createT<SkState_Shader_Blitter<State>>(device, paint, shaderContext); |
} else { |
- do { |
- fShaderContext->shadeSpan4f(x, y, fBuffer, 1); |
- fProcN(fState, device, fBuffer, 1, &alpha); |
- y += 1; |
- device = (uint32_t*)((char*)device + deviceRB); |
- } while (--height > 0); |
+ SkColor color = paint.getColor(); |
+ if (0 == SkColorGetA(color)) { |
+ return nullptr; |
+ } |
+ return allocator->createT<SkState_Blitter<State>>(device, paint); |
} |
} |
+ |
+SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint, |
+ SkShader::Context* shaderContext, |
+ SkTBlitterAllocator* allocator) { |
+ return create<State32>(device, paint, shaderContext, allocator); |
+} |
+ |
+SkBlitter* SkBlitter_ARGB64_Create(const SkPixmap& device, const SkPaint& paint, |
+ SkShader::Context* shaderContext, |
+ SkTBlitterAllocator* allocator) { |
+ return create<State64>(device, paint, shaderContext, allocator); |
+} |