diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp index 46a822ef40..169bb9f74b 100644 --- a/src/core/SkRasterPipelineBlitter.cpp +++ b/src/core/SkRasterPipelineBlitter.cpp @@ -41,6 +41,9 @@ public: // blits using something like a SkRasterPipeline::runFew() method. private: + void append_load_d(SkRasterPipeline*, const void*) const; + void append_store (SkRasterPipeline*, void*) const; + SkPixmap fDst; SkRasterPipeline fShader, fColorFilter, fXfermode; SkPM4f fPaintColor; @@ -124,21 +127,27 @@ static void SK_VECTORCALL lerp_a8_1(SkRasterPipeline::Stage* st, size_t x, st->next(x, r,g,b,a, dr,dg,db,da); } -static void upscale_lcd16(const Sk4h& lcd16, Sk4f* r, Sk4f* g, Sk4f* b) { - Sk4i _32_bit = SkNx_cast(lcd16); +static void from_565(const Sk4h& _565, Sk4f* r, Sk4f* g, Sk4f* b) { + Sk4i _32_bit = SkNx_cast(_565); *r = SkNx_cast(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE); *g = SkNx_cast(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE); *b = SkNx_cast(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE); } +static Sk4h to_565(const Sk4f& r, const Sk4f& g, const Sk4f& b) { + return SkNx_cast( Sk4f_round(r * SK_R16_MASK) << SK_R16_SHIFT + | Sk4f_round(g * SK_G16_MASK) << SK_G16_SHIFT + | Sk4f_round(b * SK_B16_MASK) << SK_B16_SHIFT); +} + // s' = d(1-c) + sc, 4 pixels at a time for 565 coverage. static void SK_VECTORCALL lerp_lcd16(SkRasterPipeline::Stage* st, size_t x, Sk4f r, Sk4f g, Sk4f b, Sk4f a, Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { auto ptr = st->ctx() + x; Sk4f cr, cg, cb; - upscale_lcd16(Sk4h::Load(ptr), &cr, &cg, &cb); + from_565(Sk4h::Load(ptr), &cr, &cg, &cb); r = lerp(dr, r, cr); g = lerp(dg, g, cg); @@ -153,7 +162,7 @@ static void SK_VECTORCALL lerp_lcd16_1(SkRasterPipeline::Stage* st, size_t x, Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { auto ptr = st->ctx() + x; Sk4f cr, cg, cb; - upscale_lcd16({*ptr,0,0,0}, &cr, &cg, &cb); + from_565({*ptr,0,0,0}, &cr, &cg, &cb); r = lerp(dr, r, cr); g = lerp(dg, g, cg); @@ -162,6 +171,44 @@ static void SK_VECTORCALL lerp_lcd16_1(SkRasterPipeline::Stage* st, size_t x, st->next(x, r,g,b,a, dr,dg,db,da); } +// Load 4 565 dst pixels. +static void SK_VECTORCALL load_d_565(SkRasterPipeline::Stage* st, size_t x, + Sk4f r, Sk4f g, Sk4f b, Sk4f a, + Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { + auto ptr = st->ctx() + x; + + from_565(Sk4h::Load(ptr), &dr,&dg,&db); + da = 1.0f; + st->next(x, r,g,b,a, dr,dg,db,da); +} + +// Load 1 565 dst pixel. +static void SK_VECTORCALL load_d_565_1(SkRasterPipeline::Stage* st, size_t x, + Sk4f r, Sk4f g, Sk4f b, Sk4f a, + Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { + auto ptr = st->ctx() + x; + + from_565({*ptr,0,0,0}, &dr,&dg,&db); + da = 1.0f; + st->next(x, r,g,b,a, dr,dg,db,da); +} + +// Store 4 565 pixels. +static void SK_VECTORCALL store_565(SkRasterPipeline::Stage* st, size_t x, + Sk4f r, Sk4f g, Sk4f b, Sk4f a, + Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { + auto ptr = st->ctx() + x; + to_565(r,g,b).store(ptr); +} + +// Store 1 565 pixel. +static void SK_VECTORCALL store_565_1(SkRasterPipeline::Stage* st, size_t x, + Sk4f r, Sk4f g, Sk4f b, Sk4f a, + Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { + auto ptr = st->ctx() + x; + *ptr = to_565(r,g,b)[0]; +} + // Load 4 8-bit sRGB pixels from SkPMColor order to RGBA. static void SK_VECTORCALL load_d_srgb(SkRasterPipeline::Stage* st, size_t x, Sk4f r, Sk4f g, Sk4f b, Sk4f a, @@ -222,6 +269,14 @@ static void SK_VECTORCALL store_srgb_1(SkRasterPipeline::Stage* st, size_t x, *dst = Sk4f_toS32(swizzle_rb_if_bgra({ r[0], g[0], b[0], a[0] })); } +static bool supported(const SkImageInfo& info) { + // TODO: f16, more? + switch (info.colorType()) { + case kN32_SkColorType: return info.gammaCloseToSRGB(); + case kRGB_565_SkColorType: return true; + default: return false; + } +} template static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) { @@ -232,8 +287,8 @@ static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipelin SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, const SkPaint& paint, SkTBlitterAllocator* alloc) { - if (!dst.info().gammaCloseToSRGB()) { - return nullptr; // TODO: f16, etc. + if (!supported(dst.info())) { + return nullptr; } if (paint.getShader()) { return nullptr; // TODO: need to work out how shaders and their contexts work @@ -245,10 +300,19 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, return nullptr; } + uint32_t paintColor = paint.getColor(); + + SkColor4f color; + if (dst.info().colorSpace()) { + color = SkColor4f::FromColor(paintColor); + } else { + swizzle_rb(SkNx_cast(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color); + } + auto blitter = alloc->createT( dst, shader, colorFilter, xfermode, - SkColor4f::FromColor(paint.getColor()).premul()); + color.premul()); if (!paint.getShader()) { blitter->fShader.append(constant_color, &blitter->fPaintColor); @@ -260,15 +324,47 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, return blitter; } +void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const { + SkASSERT(supported(fDst.info())); + + switch (fDst.info().colorType()) { + case kN32_SkColorType: + if (fDst.info().gammaCloseToSRGB()) { + p->append(load_d_srgb, load_d_srgb_1, dst); + } + break; + case kRGB_565_SkColorType: + p->append(load_d_565, load_d_565_1, dst); + break; + default: break; + } +} + +void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const { + SkASSERT(supported(fDst.info())); + + switch (fDst.info().colorType()) { + case kN32_SkColorType: + if (fDst.info().gammaCloseToSRGB()) { + p->append(store_srgb, store_srgb_1, dst); + } + break; + case kRGB_565_SkColorType: + p->append(store_565, store_565_1, dst); + break; + default: break; + } +} + void SkRasterPipelineBlitter::blitH(int x, int y, int w) { auto dst = fDst.writable_addr(0,y); SkRasterPipeline p; p.extend(fShader); p.extend(fColorFilter); - p.append(load_d_srgb, load_d_srgb_1, dst); + this->append_load_d(&p, dst); p.extend(fXfermode); - p.append(store_srgb, store_srgb_1, dst); + this->append_store(&p, dst); p.run(x, w); } @@ -280,10 +376,10 @@ void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const SkRasterPipeline p; p.extend(fShader); p.extend(fColorFilter); - p.append(load_d_srgb, load_d_srgb_1, dst); + this->append_load_d(&p, dst); p.extend(fXfermode); p.append(lerp_constant_float, &coverage); - p.append(store_srgb, store_srgb_1, dst); + this->append_store(&p, dst); for (int16_t run = *runs; run > 0; run = *runs) { coverage = *aa * (1/255.0f); @@ -308,7 +404,7 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) SkRasterPipeline p; p.extend(fShader); p.extend(fColorFilter); - p.append(load_d_srgb, load_d_srgb_1, dst); + this->append_load_d(&p, dst); p.extend(fXfermode); switch (mask.fFormat) { case SkMask::kA8_Format: @@ -319,7 +415,7 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) break; default: break; } - p.append(store_srgb, store_srgb_1, dst); + this->append_store(&p, dst); p.run(x, clip.width()); }