Skip to content

Commit

Permalink
Remove xfermode support from legacy shader blitter
Browse files Browse the repository at this point in the history
Change-Id: I0f7e96af54d0e1d5b08b0d58b61c85e2db3bac36
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/667578
Reviewed-by: Kevin Lubick <[email protected]>
Commit-Queue: Brian Osman <[email protected]>
  • Loading branch information
brianosman authored and SkCQ committed Apr 24, 2023
1 parent 22e3776 commit 258dd61
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 194 deletions.
45 changes: 12 additions & 33 deletions src/core/SkBlitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,29 +661,15 @@ bool SkBlitter::UseLegacyBlitter(const SkPixmap& device,
return false;
}

#if !defined(SK_USE_LEGACY_XFERMODE_SHADER_BLITTERS)
if (!paint.isSrcOver()) {
return false;
}
#endif

const SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
const auto mode = paint.asBlendMode();

// The legacy blitters cannot handle any of these complex features (anymore).
// The legacy blitters cannot handle any of these "complex" features (anymore).
if (device.alphaType() == kUnpremul_SkAlphaType ||
!mode ||
mode.value() > SkBlendMode::kLastCoeffMode ||
!paint.isSrcOver() ||
(mf && mf->getFormat() == SkMask::k3D_Format)) {
return false;
}

// All the real legacy fast paths are for shaders and SrcOver.
// Choosing SkRasterPipelineBlitter will also let us to hit its single-color memset path.
if (!paint.getShader() && mode != SkBlendMode::kSrcOver) {
return false;
}

auto cs = device.colorSpace();
// We check (indirectly via makeContext()) later on if the shader can handle the colorspace
// in legacy mode, so here we just focus on if a single color needs raster-pipeline.
Expand Down Expand Up @@ -791,8 +777,8 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device,
// Everything but legacy kN32_SkColorType should already be handled.
SkASSERT(device.colorType() == kN32_SkColorType);

// And we should either have a shader, be blending with SrcOver, or both.
SkASSERT(paint->getShader() || paint->asBlendMode() == SkBlendMode::kSrcOver);
// And we should be blending with SrcOver
SkASSERT(paint->asBlendMode() == SkBlendMode::kSrcOver);

// Legacy blitters keep their shader state on a shader context.
SkShaderBase::Context* shaderContext = nullptr;
Expand All @@ -807,21 +793,14 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device,
}
}

switch (device.colorType()) {
case kN32_SkColorType:
if (shaderContext) {
return alloc->make<SkARGB32_Shader_Blitter>(device, *paint, shaderContext);
} else if (paint->getColor() == SK_ColorBLACK) {
return alloc->make<SkARGB32_Black_Blitter>(device, *paint);
} else if (paint->getAlpha() == 0xFF) {
return alloc->make<SkARGB32_Opaque_Blitter>(device, *paint);
} else {
return alloc->make<SkARGB32_Blitter>(device, *paint);
}

default:
SkASSERT(false);
return alloc->make<SkNullBlitter>();
if (shaderContext) {
return alloc->make<SkARGB32_Shader_Blitter>(device, *paint, shaderContext);
} else if (paint->getColor() == SK_ColorBLACK) {
return alloc->make<SkARGB32_Black_Blitter>(device, *paint);
} else if (paint->getAlpha() == 0xFF) {
return alloc->make<SkARGB32_Opaque_Blitter>(device, *paint);
} else {
return alloc->make<SkARGB32_Blitter>(device, *paint);
}
}

Expand Down
211 changes: 51 additions & 160 deletions src/core/SkBlitter_ARGB32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "src/base/SkVx.h"
#include "src/core/SkCoreBlitters.h"
#include "src/core/SkOpts.h"
#include "src/core/SkXfermodePriv.h"

static inline int upscale_31_to_32(int value) {
SkASSERT((unsigned)value <= 31);
Expand Down Expand Up @@ -950,24 +949,13 @@ void SkARGB32_Black_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {

///////////////////////////////////////////////////////////////////////////////

// Special version of SkBlitRow::Factory32 that knows we're in kSrc_Mode,
// instead of kSrcOver_Mode
static void blend_srcmode(SkPMColor* SK_RESTRICT device,
const SkPMColor* SK_RESTRICT span,
int count, U8CPU aa) {
int aa256 = SkAlpha255To256(aa);
for (int i = 0; i < count; ++i) {
device[i] = SkFourByteInterp256(span[i], device[i], aa256);
}
}

SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device,
const SkPaint& paint, SkShaderBase::Context* shaderContext)
: INHERITED(device, paint, shaderContext)
{
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));

fXfermode = SkXfermode::Peek(paint.getBlendMode_or(SkBlendMode::kSrcOver));
SkASSERT(paint.isSrcOver());

int flags = 0;
if (!(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
Expand All @@ -978,18 +966,8 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device,
// we call this on the output from the shader + alpha from the aa buffer
fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32);

fShadeDirectlyIntoDevice = false;
if (fXfermode == nullptr) {
if (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag) {
fShadeDirectlyIntoDevice = true;
}
} else {
if (SkBlendMode::kSrc == paint.asBlendMode()) {
fShadeDirectlyIntoDevice = true;
fProc32Blend = blend_srcmode;
}
}

fShadeDirectlyIntoDevice =
SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);
fConstInY = SkToBool(shaderContext->getFlags() & SkShaderBase::kConstInY32_Flag);
}

Expand All @@ -1007,11 +985,7 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
} else {
SkPMColor* span = fBuffer;
fShaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xfer32(device, span, width, nullptr);
} else {
fProc32(device, span, width, 255);
}
fProc32(device, span, width, 255);
}
}

Expand All @@ -1035,21 +1009,12 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
}
} else {
shaderContext->shadeSpan(x, y, span, width);
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
xfer->xfer32(device, span, width, nullptr);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
} else {
SkBlitRow::Proc32 proc = fProc32;
do {
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
SkBlitRow::Proc32 proc = fProc32;
do {
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
return;
}
Expand All @@ -1061,23 +1026,13 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
} else {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
shaderContext->shadeSpan(x, y, span, width);
xfer->xfer32(device, span, width, nullptr);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
} else {
SkBlitRow::Proc32 proc = fProc32;
do {
shaderContext->shadeSpan(x, y, span, width);
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
SkBlitRow::Proc32 proc = fProc32;
do {
shaderContext->shadeSpan(x, y, span, width);
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
}

Expand All @@ -1087,32 +1042,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
uint32_t* device = fDevice.writable_addr32(x, y);
auto* shaderContext = fShaderContext;

if (fXfermode && !fShadeDirectlyIntoDevice) {
for (;;) {
SkXfermode* xfer = fXfermode;

int count = *runs;
if (count <= 0)
break;
int aa = *antialias;
if (aa) {
shaderContext->shadeSpan(x, y, span, count);
if (aa == 255) {
xfer->xfer32(device, span, count, nullptr);
} else {
// count is almost always 1
for (int i = count - 1; i >= 0; --i) {
xfer->xfer32(&device[i], &span[i], 1, antialias);
}
}
}
device += count;
runs += count;
antialias += count;
x += count;
}
} else if (fShadeDirectlyIntoDevice ||
(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
if (fShadeDirectlyIntoDevice || (shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag)) {
for (;;) {
int count = *runs;
if (count <= 0) {
Expand Down Expand Up @@ -1280,31 +1210,23 @@ static void blend_row_LCD16_opaque(SkPMColor* dst, const void* vmask, const SkPM
}

void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
// we only handle kA8 with an xfermode
if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) {
this->INHERITED::blitMask(mask, clip);
return;
}

SkASSERT(mask.fBounds.contains(clip));

void (*blend_row)(SkPMColor*, const void* mask, const SkPMColor*, int) = nullptr;

if (!fXfermode) {
bool opaque = (fShaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);

if (mask.fFormat == SkMask::kA8_Format && opaque) {
blend_row = blend_row_A8_opaque;
} else if (mask.fFormat == SkMask::kA8_Format) {
blend_row = blend_row_A8;
} else if (mask.fFormat == SkMask::kLCD16_Format && opaque) {
blend_row = blend_row_LCD16_opaque;
} else if (mask.fFormat == SkMask::kLCD16_Format) {
blend_row = blend_row_lcd16;
} else {
this->INHERITED::blitMask(mask, clip);
return;
}
bool opaque = (fShaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);

if (mask.fFormat == SkMask::kA8_Format && opaque) {
blend_row = blend_row_A8_opaque;
} else if (mask.fFormat == SkMask::kA8_Format) {
blend_row = blend_row_A8;
} else if (mask.fFormat == SkMask::kLCD16_Format && opaque) {
blend_row = blend_row_LCD16_opaque;
} else if (mask.fFormat == SkMask::kLCD16_Format) {
blend_row = blend_row_lcd16;
} else {
this->INHERITED::blitMask(mask, clip);
return;
}

const int x = clip.fLeft;
Expand All @@ -1318,27 +1240,14 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
const size_t maskRB = mask.fRowBytes;

SkPMColor* span = fBuffer;

if (fXfermode) {
SkASSERT(SkMask::kA8_Format == mask.fFormat);
SkXfermode* xfer = fXfermode;
do {
fShaderContext->shadeSpan(x, y, span, width);
xfer->xfer32(reinterpret_cast<SkPMColor*>(dstRow), span, width, maskRow);
dstRow += dstRB;
maskRow += maskRB;
y += 1;
} while (--height > 0);
} else {
SkASSERT(blend_row);
do {
fShaderContext->shadeSpan(x, y, span, width);
blend_row(reinterpret_cast<SkPMColor*>(dstRow), maskRow, span, width);
dstRow += dstRB;
maskRow += maskRB;
y += 1;
} while (--height > 0);
}
SkASSERT(blend_row);
do {
fShaderContext->shadeSpan(x, y, span, width);
blend_row(reinterpret_cast<SkPMColor*>(dstRow), maskRow, span, width);
dstRow += dstRB;
maskRow += maskRB;
y += 1;
} while (--height > 0);
}

void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
Expand All @@ -1364,19 +1273,11 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} while (--height > 0);
}
} else {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
xfer->xfer32(device, &c, 1, &alpha);
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
} else {
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
proc(device, &c, 1, alpha);
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
proc(device, &c, 1, alpha);
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
return;
}
Expand All @@ -1399,22 +1300,12 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
}
} else {
SkPMColor* span = fBuffer;
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
fShaderContext->shadeSpan(x, y, span, 1);
xfer->xfer32(device, span, 1, &alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
} else {
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
fShaderContext->shadeSpan(x, y, span, 1);
proc(device, span, 1, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
fShaderContext->shadeSpan(x, y, span, 1);
proc(device, span, 1, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
}
}
1 change: 0 additions & 1 deletion src/core/SkCoreBlitters.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ class SkARGB32_Shader_Blitter : public SkShaderBlitter {
void blitMask(const SkMask&, const SkIRect&) override;

private:
SkXfermode* fXfermode;
SkPMColor* fBuffer;
SkBlitRow::Proc32 fProc32;
SkBlitRow::Proc32 fProc32Blend;
Expand Down

0 comments on commit 258dd61

Please sign in to comment.