void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader::Context* shaderContextA = fShaderContextA; SkShader::Context* shaderContextB = fShaderContextB; SkBlendMode mode = static_cast<const SkComposeShader&>(fShader).fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); SkPMColor tmp[TMP_COLOR_COUNT]; SkXfermode* xfer = SkXfermode::Peek(mode); if (nullptr == xfer) { // implied SRC_OVER // TODO: when we have a good test-case, should use SkBlitRow::Proc32 // for these loops do { int n = count; if (n > TMP_COLOR_COUNT) { n = TMP_COLOR_COUNT; } shaderContextA->shadeSpan(x, y, result, n); shaderContextB->shadeSpan(x, y, tmp, n); if (256 == scale) { for (int i = 0; i < n; i++) { result[i] = SkPMSrcOver(tmp[i], result[i]); } } else { for (int i = 0; i < n; i++) { result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale); } } result += n; x += n; count -= n; } while (count > 0); } else { // use mode for the composition do { int n = count; if (n > TMP_COLOR_COUNT) { n = TMP_COLOR_COUNT; } shaderContextA->shadeSpan(x, y, result, n); shaderContextB->shadeSpan(x, y, tmp, n); xfer->xfer32(result, tmp, n, nullptr); if (256 != scale) { for (int i = 0; i < n; i++) { result[i] = SkAlphaMulQ(result[i], scale); } } result += n; x += n; count -= n; } while (count > 0); } }
DEF_TEST(Color4f_shader, reporter) { struct { sk_sp<SkShader> (*fFact)(); bool fSupports4f; float fTolerance; } recs[] = { { make_color_sh, true, 1.0f/255 }, // PMColor 4f gradients are interpolated in 255-multiplied values, so we need a // slightly relaxed tolerance to accommodate the cumulative precision deviation. { make_grad_sh, true, 1.001f/255 }, { make_image_sh, false, 1.0f/255 }, { make_cf_sh, true, 1.0f/255 }, }; SkPaint paint; for (const auto& rec : recs) { uint32_t storage[300]; paint.setShader(rec.fFact()); // Encourage 4f context selection. At some point we may need // to instantiate two separate contexts for optimal 4b/4f selection. const SkShader::ContextRec contextRec(paint, SkMatrix::I(), nullptr, SkShader::ContextRec::kPM4f_DstType); SkASSERT(paint.getShader()->contextSize(contextRec) <= sizeof(storage)); SkShader::Context* ctx = paint.getShader()->createContext(contextRec, storage); if (rec.fSupports4f) { const int N = 100; SkPM4f buffer4f[N]; ctx->shadeSpan4f(0, 0, buffer4f, N); SkPMColor buffer4b[N]; ctx->shadeSpan(0, 0, buffer4b, N); REPORTER_ASSERT(reporter, compare_spans(buffer4f, buffer4b, N, rec.fTolerance)); } ctx->~Context(); } }
void onDraw(int loops, SkCanvas*) override { int width = fSrcSize.fWidth; int height = fSrcSize.fHeight; SkAutoTMalloc<SkPMColor> buffer4b(width*height); uint32_t storage[kSkBlitterContextSize]; const SkShader::ContextRec rec(fPaint, fM, nullptr, SkShader::ContextRec::kPMColor_DstType); SkASSERT(fPaint.getShader()->contextSize(rec) <= sizeof(storage)); SkShader::Context* ctx = fPaint.getShader()->createContext(rec, storage); int count = 100; for (int n = 0; n < 1000*loops; n++) { ctx->shadeSpan(3, 6, buffer4b, count); } ctx->~Context(); }
void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { SkShader::Context* shaderContextA = fShaderContextA; SkShader::Context* shaderContextB = fShaderContextB; SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode; unsigned scale = SkAlpha255To256(this->getPaintAlpha()); #ifdef SK_BUILD_FOR_ANDROID scale = 256; // ugh -- maintain old bug/behavior for now #endif SkPMColor tmp[TMP_COLOR_COUNT]; if (NULL == mode) { // implied SRC_OVER // TODO: when we have a good test-case, should use SkBlitRow::Proc32 // for these loops do { int n = count; if (n > TMP_COLOR_COUNT) { n = TMP_COLOR_COUNT; } shaderContextA->shadeSpan(x, y, result, n); shaderContextB->shadeSpan(x, y, tmp, n); if (256 == scale) { for (int i = 0; i < n; i++) { result[i] = SkPMSrcOver(tmp[i], result[i]); } } else { for (int i = 0; i < n; i++) { result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]), scale); } } result += n; x += n; count -= n; } while (count > 0); } else { // use mode for the composition do { int n = count; if (n > TMP_COLOR_COUNT) { n = TMP_COLOR_COUNT; } shaderContextA->shadeSpan(x, y, result, n); shaderContextB->shadeSpan(x, y, tmp, n); mode->xfer32(result, tmp, n, NULL); if (256 != scale) { for (int i = 0; i < n; i++) { result[i] = SkAlphaMulQ(result[i], scale); } } result += n; x += n; count -= n; } while (count > 0); } }