SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, const SkPaint& paint, const SkMatrix& ctm, SkArenaAlloc* alloc) { auto blitter = alloc->make<SkRasterPipelineBlitter>( dst, paint.getBlendMode(), SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace())); SkBlendMode* blend = &blitter->fBlend; SkPM4f* paintColor = &blitter->fPaintColor; SkRasterPipeline* pipeline = &blitter->fShader; SkShader* shader = paint.getShader(); SkColorFilter* colorFilter = paint.getColorFilter(); // TODO: all temporary if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) { return nullptr; } bool is_opaque = paintColor->a() == 1.0f, is_constant = true; if (shader) { pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY); if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) { return nullptr; } if (!is_opaque) { pipeline->append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]); } is_opaque = is_opaque && shader->isOpaque(); is_constant = shader->isConstant(); } else { pipeline->append(SkRasterPipeline::constant_color, paintColor); } if (colorFilter) { if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) { return nullptr; } is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); } if (is_constant) { pipeline->append(SkRasterPipeline::store_f32, &paintColor); pipeline->run(0,1); *pipeline = SkRasterPipeline(); pipeline->append(SkRasterPipeline::constant_color, paintColor); is_opaque = paintColor->a() == 1.0f; } if (is_opaque && *blend == SkBlendMode::kSrcOver) { *blend = SkBlendMode::kSrc; } if (is_constant && *blend == SkBlendMode::kSrc) { SkRasterPipeline p; p.extend(*pipeline); blitter->fDstPtr = &blitter->fMemsetColor; blitter->append_store(&p); p.run(0,1); blitter->fCanMemsetInBlitH = true; } return blitter; }
bool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, int count, SkAlphaType alphaType) const { SkRasterPipeline pipeline; switch (srcFormat) { case kBGRA_8888_ColorFormat: pipeline.append(SkRasterPipeline::load_8888, &src); pipeline.append(SkRasterPipeline::swap_rb); break; case kRGBA_8888_ColorFormat: pipeline.append(SkRasterPipeline::load_8888, &src); break; case kRGBA_U16_BE_ColorFormat: pipeline.append(SkRasterPipeline::load_u16_be, &src); break; case kRGB_U16_BE_ColorFormat: pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src); break; default: SkCSXformPrintf("F16/F32 sources must be linear.\n"); return false; } pipeline.extend(fElementsPipeline); if (kPremul_SkAlphaType == alphaType) { pipeline.append(SkRasterPipeline::premul); } switch (dstFormat) { case kBGRA_8888_ColorFormat: pipeline.append(SkRasterPipeline::swap_rb); pipeline.append(SkRasterPipeline::store_8888, &dst); break; case kRGBA_8888_ColorFormat: pipeline.append(SkRasterPipeline::store_8888, &dst); break; case kRGBA_F16_ColorFormat: if (!fLinearDstGamma) { return false; } pipeline.append(SkRasterPipeline::store_f16, &dst); break; case kRGBA_F32_ColorFormat: if (!fLinearDstGamma) { return false; } pipeline.append(SkRasterPipeline::store_f32, &dst); break; case kBGR_565_ColorFormat: if (kOpaque_SkAlphaType != alphaType) { return false; } pipeline.append(SkRasterPipeline::store_565, &dst); break; default: return false; } pipeline.run(0,count); return true; }
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END bool SkImageShader::onAppendStages(const StageRec& rec) const { SkRasterPipeline* p = rec.fPipeline; SkArenaAlloc* alloc = rec.fAlloc; SkMatrix matrix; if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &matrix)) { return false; } auto quality = rec.fPaint.getFilterQuality(); SkBitmapProvider provider(fImage.get(), rec.fDstCS); SkDefaultBitmapController controller; std::unique_ptr<SkBitmapController::State> state { controller.requestBitmap(provider, matrix, quality) }; if (!state) { return false; } const SkPixmap& pm = state->pixmap(); matrix = state->invMatrix(); quality = state->quality(); auto info = pm.info(); // When the matrix is just an integer translate, bilerp == nearest neighbor. if (quality == kLow_SkFilterQuality && matrix.getType() <= SkMatrix::kTranslate_Mask && matrix.getTranslateX() == (int)matrix.getTranslateX() && matrix.getTranslateY() == (int)matrix.getTranslateY()) { quality = kNone_SkFilterQuality; } // See skia:4649 and the GM image_scale_aligned. if (quality == kNone_SkFilterQuality) { if (matrix.getScaleX() >= 0) { matrix.setTranslateX(nextafterf(matrix.getTranslateX(), floorf(matrix.getTranslateX()))); } if (matrix.getScaleY() >= 0) { matrix.setTranslateY(nextafterf(matrix.getTranslateY(), floorf(matrix.getTranslateY()))); } } p->append(SkRasterPipeline::seed_shader); struct MiscCtx { std::unique_ptr<SkBitmapController::State> state; SkColor4f paint_color; }; auto misc = alloc->make<MiscCtx>(); misc->state = std::move(state); // Extend lifetime to match the pipeline's. misc->paint_color = SkColor4f_from_SkColor(rec.fPaint.getColor(), rec.fDstCS); p->append_matrix(alloc, matrix); auto gather = alloc->make<SkJumper_GatherCtx>(); gather->pixels = pm.addr(); gather->stride = pm.rowBytesAsPixels(); gather->width = pm.width(); gather->height = pm.height(); auto limit_x = alloc->make<SkJumper_TileCtx>(), limit_y = alloc->make<SkJumper_TileCtx>(); limit_x->scale = pm.width(); limit_x->invScale = 1.0f / pm.width(); limit_y->scale = pm.height(); limit_y->invScale = 1.0f / pm.height(); bool is_srgb = rec.fDstCS && (!info.colorSpace() || info.gammaCloseToSRGB()); SkJumper_DecalTileCtx* decal_ctx = nullptr; bool decal_x_and_y = fTileModeX == kDecal_TileMode && fTileModeY == kDecal_TileMode; if (fTileModeX == kDecal_TileMode || fTileModeY == kDecal_TileMode) { decal_ctx = alloc->make<SkJumper_DecalTileCtx>(); decal_ctx->limit_x = limit_x->scale; decal_ctx->limit_y = limit_y->scale; } auto append_tiling_and_gather = [&] { if (decal_x_and_y) { p->append(SkRasterPipeline::decal_x_and_y, decal_ctx); } else { switch (fTileModeX) { case kClamp_TileMode: /* The gather_xxx stage will clamp for us. */ break; case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit_x); break; case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit_x); break; case kDecal_TileMode: p->append(SkRasterPipeline::decal_x, decal_ctx); break; } switch (fTileModeY) { case kClamp_TileMode: /* The gather_xxx stage will clamp for us. */ break; case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, limit_y); break; case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, limit_y); break; case kDecal_TileMode: p->append(SkRasterPipeline::decal_y, decal_ctx); break; } } void* ctx = gather; switch (info.colorType()) { case kAlpha_8_SkColorType: p->append(SkRasterPipeline::gather_a8, ctx); break; case kGray_8_SkColorType: p->append(SkRasterPipeline::gather_g8, ctx); break; case kRGB_565_SkColorType: p->append(SkRasterPipeline::gather_565, ctx); break; case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, ctx); break; case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_bgra, ctx); break; case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx); break; case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::gather_1010102, ctx); break; case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::gather_f16, ctx); break; case kRGB_888x_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx); p->append(SkRasterPipeline::force_opaque ); break; case kRGB_101010x_SkColorType: p->append(SkRasterPipeline::gather_1010102, ctx); p->append(SkRasterPipeline::force_opaque ); break; default: SkASSERT(false); } if (decal_ctx) { p->append(SkRasterPipeline::check_decal_mask, decal_ctx); } if (is_srgb) { p->append(SkRasterPipeline::from_srgb); } }; auto append_misc = [&] { if (info.colorType() == kAlpha_8_SkColorType) { p->append(SkRasterPipeline::set_rgb, &misc->paint_color); } if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) { p->append(SkRasterPipeline::premul); } if (quality > kLow_SkFilterQuality) { // Bicubic filtering naturally produces out of range values on both sides. p->append(SkRasterPipeline::clamp_0); p->append(fClampAsIfUnpremul ? SkRasterPipeline::clamp_1 : SkRasterPipeline::clamp_a); } append_gamut_transform(p, alloc, info.colorSpace(), rec.fDstCS, fClampAsIfUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType); return true; }; // We've got a fast path for 8888 bilinear clamp/clamp non-color-managed sampling. auto ct = info.colorType(); if (true && (ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType) && quality == kLow_SkFilterQuality && fTileModeX == SkShader::kClamp_TileMode && fTileModeY == SkShader::kClamp_TileMode && !is_srgb) { p->append(SkRasterPipeline::bilerp_clamp_8888, gather); if (ct == kBGRA_8888_SkColorType) { p->append(SkRasterPipeline::swap_rb); } return append_misc(); } SkJumper_SamplerCtx* sampler = nullptr; if (quality != kNone_SkFilterQuality) { sampler = alloc->make<SkJumper_SamplerCtx>(); } auto sample = [&](SkRasterPipeline::StockStage setup_x, SkRasterPipeline::StockStage setup_y) { p->append(setup_x, sampler); p->append(setup_y, sampler); append_tiling_and_gather(); p->append(SkRasterPipeline::accumulate, sampler); }; if (quality == kNone_SkFilterQuality) { append_tiling_and_gather(); } else if (quality == kLow_SkFilterQuality) { p->append(SkRasterPipeline::save_xy, sampler); sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny); sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny); sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py); sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py); p->append(SkRasterPipeline::move_dst_src); } else { p->append(SkRasterPipeline::save_xy, sampler); sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y); sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y); sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y); sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y); sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y); sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y); sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y); sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y); sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y); sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y); sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y); sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y); sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y); sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y); sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y); sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y); p->append(SkRasterPipeline::move_dst_src); } return append_misc(); }