skrpb: evaluate color filters for constant shaders once.
The simplest thing to do here is just run shader+color filter pipeline at construction time to create a new constant color shader (replacing the paint color). This reduces a pipeline like: - constant_color (paint color) - matrix_4x5 - clamp_a - load_d_foo, xfermode, lerp, store_foo to - constant_color (paint color -> matrix_4x5 -> clamp_a) - load_d_foo, xfermode, lerp, store_foo To implement this all, we add a new store_f32 stage that writes SkPM4f, and finally get around to implementing Sk8f::Store4() (store while reinterlacing). Sk4f::Store4() already exists for both SSE and NEON. Next step: reduce simple constant_color -> store pipelines (src mode, full coverage) into non-pipeline memsets. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2480823002 Review-Url: https://codereview.chromium.org/2480823002
This commit is contained in:
parent
d8db392be9
commit
a4a4488a4c
@ -56,7 +56,7 @@
|
||||
|
||||
#define SK_RASTER_PIPELINE_STAGES(M) \
|
||||
M(swap_src_dst) M(clamp_0) M(clamp_a) M(unpremul) M(premul) \
|
||||
M(constant_color) \
|
||||
M(constant_color) M(store_f32) \
|
||||
M(load_s_565) M(load_d_565) M(store_565) \
|
||||
M(load_s_srgb) M(load_d_srgb) M(store_srgb) \
|
||||
M(load_s_f16) M(load_d_f16) M(store_f16) \
|
||||
|
@ -20,12 +20,8 @@ class SkRasterPipelineBlitter : public SkBlitter {
|
||||
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)
|
||||
{}
|
||||
@ -45,9 +41,9 @@ private:
|
||||
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,
|
||||
@ -84,53 +80,70 @@ static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipelin
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint32_t paintColor = paint.getColor();
|
||||
bool shaderIsOpaque = (paintColor >> 24) == 0xff;
|
||||
|
||||
SkRasterPipeline shader, colorFilter;
|
||||
if (auto s = paint.getShader()) {
|
||||
shaderIsOpaque = s->isOpaque();
|
||||
}
|
||||
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);
|
||||
|
||||
*pipeline = SkRasterPipeline();
|
||||
pipeline->append(SkRasterPipeline::constant_color, paintColor);
|
||||
|
||||
is_opaque = paintColor->a() == 1.0f;
|
||||
}
|
||||
|
||||
SkColor4f color;
|
||||
if (dst.info().colorSpace()) {
|
||||
color = SkColor4f::FromColor(paintColor);
|
||||
} else {
|
||||
swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
|
||||
if (is_opaque && *blend == SkBlendMode::kSrcOver) {
|
||||
*blend = SkBlendMode::kSrc;
|
||||
}
|
||||
|
||||
auto blitter = alloc->createT<SkRasterPipelineBlitter>(dst, shader, blend, color.premul());
|
||||
|
||||
if (!paint.getShader()) {
|
||||
blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor);
|
||||
}
|
||||
blitter->fShader.extend(colorFilter);
|
||||
|
||||
return blitter;
|
||||
}
|
||||
|
||||
|
@ -544,6 +544,14 @@ public:
|
||||
__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:
|
||||
@ -560,6 +568,29 @@ 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); }
|
||||
|
@ -23,9 +23,9 @@ namespace {
|
||||
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;
|
||||
@ -379,6 +379,24 @@ STAGE(store_f16, false) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user