public:
static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*);
- SkRasterPipelineBlitter(SkPixmap dst,
- SkRasterPipeline shader,
- SkBlendMode blend,
- SkPM4f paintColor)
+ SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkPM4f paintColor)
: fDst(dst)
- , fShader(shader)
, fBlend(blend)
, fPaintColor(paintColor)
{}
void maybe_clamp (SkRasterPipeline*) const;
SkPixmap fDst;
- SkRasterPipeline fShader;
SkBlendMode fBlend;
SkPM4f fPaintColor;
+ SkRasterPipeline fShader;
// These functions are compiled lazily when first used.
std::function<void(size_t, size_t)> fBlitH = nullptr,
return !effect || effect->appendStages(pipeline);
}
+static SkPM4f paint_color(const SkPixmap& dst, const SkPaint& paint) {
+ auto paintColor = paint.getColor();
+ SkColor4f color;
+ if (dst.info().colorSpace()) {
+ color = SkColor4f::FromColor(paintColor);
+ // TODO: transform from sRGB to dst gamut.
+ } else {
+ swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
+ }
+ return color.premul();
+}
SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
const SkPaint& paint,
SkTBlitterAllocator* alloc) {
- if (!supported(dst.info())) {
+ auto blitter = alloc->createT<SkRasterPipelineBlitter>(dst,
+ paint.getBlendMode(),
+ paint_color(dst, paint));
+ 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()) || shader || !SkBlendMode_AppendStages(*blend)) {
+ alloc->freeLast();
return nullptr;
}
- if (paint.getShader()) {
- return nullptr; // TODO: need to work out how shaders and their contexts work
- }
- SkBlendMode blend = paint.getBlendMode();
- if (!SkBlendMode_AppendStages(blend)) {
- return nullptr; // TODO
- }
- uint32_t paintColor = paint.getColor();
- bool shaderIsOpaque = (paintColor >> 24) == 0xff;
-
- SkRasterPipeline shader, colorFilter;
- if (auto s = paint.getShader()) {
- shaderIsOpaque = s->isOpaque();
+ bool is_opaque, is_constant;
+ if (shader) {
+ is_opaque = shader->isOpaque();
+ is_constant = false; // TODO: shader->isConstant()
+ // TODO: append shader stages, of course!
+ } else {
+ is_opaque = paintColor->a() == 1.0f;
+ is_constant = true;
+ pipeline->append(SkRasterPipeline::constant_color, paintColor);
}
- if (auto cf = paint.getColorFilter()) {
- if (!cf->appendStages(&colorFilter, shaderIsOpaque)) {
+
+ if (colorFilter) {
+ if (!colorFilter->appendStages(pipeline, is_opaque)) {
+ alloc->freeLast();
return nullptr;
}
- shaderIsOpaque = shaderIsOpaque && (cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
+ is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
}
- if (shaderIsOpaque && blend == SkBlendMode::kSrcOver) {
- blend = SkBlendMode::kSrc;
- }
+ if (is_constant) {
+ pipeline->append(SkRasterPipeline::store_f32, &paintColor);
+ pipeline->compile()(0,1);
- SkColor4f color;
- if (dst.info().colorSpace()) {
- color = SkColor4f::FromColor(paintColor);
- } else {
- swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
- }
+ *pipeline = SkRasterPipeline();
+ pipeline->append(SkRasterPipeline::constant_color, paintColor);
- auto blitter = alloc->createT<SkRasterPipelineBlitter>(dst, shader, blend, color.premul());
+ is_opaque = paintColor->a() == 1.0f;
+ }
- if (!paint.getShader()) {
- blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor);
+ if (is_opaque && *blend == SkBlendMode::kSrcOver) {
+ *blend = SkBlendMode::kSrc;
}
- blitter->fShader.extend(colorFilter);
return blitter;
}
__m256i fVec;
};
+ // _mm256_unpack{lo,hi}_pd() auto-casting to and from __m256d.
+ AI static __m256 unpacklo_pd(__m256 x, __m256 y) {
+ return _mm256_castpd_ps(_mm256_unpacklo_pd(_mm256_castps_pd(x), _mm256_castps_pd(y)));
+ }
+ AI static __m256 unpackhi_pd(__m256 x, __m256 y) {
+ return _mm256_castpd_ps(_mm256_unpackhi_pd(_mm256_castps_pd(x), _mm256_castps_pd(y)));
+ }
+
template <>
class SkNx<8, float> {
public:
AI static SkNx Load(const void* ptr) { return _mm256_loadu_ps((const float*)ptr); }
AI void store(void* ptr) const { _mm256_storeu_ps((float*)ptr, fVec); }
+ AI static void Store4(void* ptr,
+ const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) {
+ __m256 rg0145 = _mm256_unpacklo_ps(r.fVec, g.fVec), // r0 g0 r1 g1 | r4 g4 r5 g5
+ rg2367 = _mm256_unpackhi_ps(r.fVec, g.fVec), // r2 ... | r6 ...
+ ba0145 = _mm256_unpacklo_ps(b.fVec, a.fVec), // b0 a0 b1 a1 | b4 a4 b5 a5
+ ba2367 = _mm256_unpackhi_ps(b.fVec, a.fVec); // b2 ... | b6 ...
+
+ __m256 _04 = unpacklo_pd(rg0145, ba0145), // r0 g0 b0 a0 | r4 g4 b4 a4
+ _15 = unpackhi_pd(rg0145, ba0145), // r1 ... | r5 ...
+ _26 = unpacklo_pd(rg2367, ba2367), // r2 ... | r6 ...
+ _37 = unpackhi_pd(rg2367, ba2367); // r3 ... | r7 ...
+
+ __m256 _01 = _mm256_permute2f128_ps(_04, _15, 16), // 16 == 010 000 == lo, lo
+ _23 = _mm256_permute2f128_ps(_26, _37, 16),
+ _45 = _mm256_permute2f128_ps(_04, _15, 25), // 25 == 011 001 == hi, hi
+ _67 = _mm256_permute2f128_ps(_26, _37, 25);
+
+ _mm256_storeu_ps((float*)ptr + 0*8, _01);
+ _mm256_storeu_ps((float*)ptr + 1*8, _23);
+ _mm256_storeu_ps((float*)ptr + 2*8, _45);
+ _mm256_storeu_ps((float*)ptr + 3*8, _67);
+ }
+
AI SkNx operator+(const SkNx& o) const { return _mm256_add_ps(fVec, o.fVec); }
AI SkNx operator-(const SkNx& o) const { return _mm256_sub_ps(fVec, o.fVec); }
AI SkNx operator*(const SkNx& o) const { return _mm256_mul_ps(fVec, o.fVec); }
static constexpr int N = 4;
#endif
-using SkNf = SkNx<N, float>;
-using SkNi = SkNx<N, int>;
-using SkNh = SkNx<N, uint16_t>;
+ using SkNf = SkNx<N, float>;
+ using SkNi = SkNx<N, int>;
+ using SkNh = SkNx<N, uint16_t>;
struct BodyStage;
struct TailStage;
}
}
+STAGE(store_f32, false) {
+ auto ptr = *(SkPM4f**)ctx + x;
+
+ SkPM4f buf[8];
+ SkNf::Store4(kIsTail ? buf : ptr, r,g,b,a);
+ if (kIsTail) {
+ switch (tail & (N-1)) {
+ case 7: ptr[6] = buf[6];
+ case 6: ptr[5] = buf[5];
+ case 5: ptr[4] = buf[4];
+ case 4: ptr[3] = buf[3];
+ case 3: ptr[2] = buf[2];
+ case 2: ptr[1] = buf[1];
+ }
+ ptr[0] = buf[0];
+ }
+}
+
// Load 8-bit SkPMColor-order sRGB.
STAGE(load_d_srgb, true) {