SkColorFilter.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * Copyright 2006 The Android Open Source Project
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkColorFilter.h"
  8. #include "include/core/SkRefCnt.h"
  9. #include "include/core/SkString.h"
  10. #include "include/core/SkUnPreMultiply.h"
  11. #include "include/private/SkNx.h"
  12. #include "include/private/SkTDArray.h"
  13. #include "src/core/SkArenaAlloc.h"
  14. #include "src/core/SkColorFilterPriv.h"
  15. #include "src/core/SkColorSpacePriv.h"
  16. #include "src/core/SkColorSpaceXformSteps.h"
  17. #include "src/core/SkRasterPipeline.h"
  18. #include "src/core/SkReadBuffer.h"
  19. #include "src/core/SkWriteBuffer.h"
  20. #if SK_SUPPORT_GPU
  21. #include "src/gpu/GrFragmentProcessor.h"
  22. #include "src/gpu/effects/generated/GrMixerEffect.h"
  23. #endif
  24. bool SkColorFilter::onAsAColorMode(SkColor*, SkBlendMode*) const {
  25. return false;
  26. }
  27. bool SkColorFilter::onAsAColorMatrix(float matrix[20]) const {
  28. return false;
  29. }
  30. #if SK_SUPPORT_GPU
  31. std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(
  32. GrRecordingContext*, const GrColorSpaceInfo&) const {
  33. return nullptr;
  34. }
  35. #endif
  36. bool SkColorFilter::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
  37. return this->onAppendStages(rec, shaderIsOpaque);
  38. }
  39. SkColor SkColorFilter::filterColor(SkColor c) const {
  40. return this->filterColor4f(SkColor4f::FromColor(c), nullptr)
  41. .toSkColor();
  42. }
  43. #include "src/core/SkRasterPipeline.h"
  44. SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c, SkColorSpace* colorSpace) const {
  45. SkPMColor4f dst, src = c.premul();
  46. // determined experimentally, seems to cover compose+colormatrix
  47. constexpr size_t kEnoughForCommonFilters = 512;
  48. SkSTArenaAlloc<kEnoughForCommonFilters> alloc;
  49. SkRasterPipeline pipeline(&alloc);
  50. pipeline.append_constant_color(&alloc, src.vec());
  51. SkPaint dummyPaint;
  52. SkStageRec rec = {
  53. &pipeline, &alloc, kRGBA_F32_SkColorType, colorSpace, dummyPaint, nullptr, SkMatrix::I()
  54. };
  55. this->onAppendStages(rec, c.fA == 1);
  56. SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
  57. pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
  58. pipeline.run(0,0, 1,1);
  59. return dst.unpremul();
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////////////////////////
  62. /*
  63. * Since colorfilters may be used on the GPU backend, and in that case we may string together
  64. * many GrFragmentProcessors, we might exceed some internal instruction/resource limit.
  65. *
  66. * Since we don't yet know *what* those limits might be when we construct the final shader,
  67. * we just set an arbitrary limit during construction. If later we find smarter ways to know what
  68. * the limnits are, we can change this constant (or remove it).
  69. */
  70. #define SK_MAX_COMPOSE_COLORFILTER_COUNT 4
  71. class SkComposeColorFilter : public SkColorFilter {
  72. public:
  73. uint32_t getFlags() const override {
  74. // Can only claim alphaunchanged support if both our proxys do.
  75. return fOuter->getFlags() & fInner->getFlags();
  76. }
  77. bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
  78. bool innerIsOpaque = shaderIsOpaque;
  79. if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) {
  80. innerIsOpaque = false;
  81. }
  82. return fInner->appendStages(rec, shaderIsOpaque) &&
  83. fOuter->appendStages(rec, innerIsOpaque);
  84. }
  85. #if SK_SUPPORT_GPU
  86. std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
  87. GrRecordingContext* context, const GrColorSpaceInfo& dstColorSpaceInfo) const override {
  88. auto innerFP = fInner->asFragmentProcessor(context, dstColorSpaceInfo);
  89. auto outerFP = fOuter->asFragmentProcessor(context, dstColorSpaceInfo);
  90. if (!innerFP || !outerFP) {
  91. return nullptr;
  92. }
  93. std::unique_ptr<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) };
  94. return GrFragmentProcessor::RunInSeries(series, 2);
  95. }
  96. #endif
  97. protected:
  98. void flatten(SkWriteBuffer& buffer) const override {
  99. buffer.writeFlattenable(fOuter.get());
  100. buffer.writeFlattenable(fInner.get());
  101. }
  102. private:
  103. SK_FLATTENABLE_HOOKS(SkComposeColorFilter)
  104. SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner,
  105. int composedFilterCount)
  106. : fOuter(std::move(outer))
  107. , fInner(std::move(inner))
  108. , fComposedFilterCount(composedFilterCount)
  109. {
  110. SkASSERT(composedFilterCount >= 2);
  111. SkASSERT(composedFilterCount <= SK_MAX_COMPOSE_COLORFILTER_COUNT);
  112. }
  113. int privateComposedFilterCount() const override {
  114. return fComposedFilterCount;
  115. }
  116. sk_sp<SkColorFilter> fOuter;
  117. sk_sp<SkColorFilter> fInner;
  118. const int fComposedFilterCount;
  119. friend class SkColorFilter;
  120. typedef SkColorFilter INHERITED;
  121. };
  122. sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) {
  123. sk_sp<SkColorFilter> outer(buffer.readColorFilter());
  124. sk_sp<SkColorFilter> inner(buffer.readColorFilter());
  125. return outer ? outer->makeComposed(std::move(inner)) : inner;
  126. }
  127. sk_sp<SkColorFilter> SkColorFilter::makeComposed(sk_sp<SkColorFilter> inner) const {
  128. if (!inner) {
  129. return sk_ref_sp(this);
  130. }
  131. int count = inner->privateComposedFilterCount() + this->privateComposedFilterCount();
  132. if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) {
  133. return nullptr;
  134. }
  135. return sk_sp<SkColorFilter>(new SkComposeColorFilter(sk_ref_sp(this), std::move(inner), count));
  136. }
  137. ///////////////////////////////////////////////////////////////////////////////////////////////////
  138. #if SK_SUPPORT_GPU
  139. #include "src/gpu/effects/GrSRGBEffect.h"
  140. #endif
  141. class SkSRGBGammaColorFilter : public SkColorFilter {
  142. public:
  143. enum class Direction {
  144. kLinearToSRGB,
  145. kSRGBToLinear,
  146. };
  147. SkSRGBGammaColorFilter(Direction dir) : fDir(dir), fSteps([&]{
  148. // We handle premul/unpremul separately, so here just always upm->upm.
  149. if (dir == Direction::kLinearToSRGB) {
  150. return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
  151. sk_srgb_singleton(), kUnpremul_SkAlphaType};
  152. } else {
  153. return SkColorSpaceXformSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType,
  154. sk_srgb_linear_singleton(), kUnpremul_SkAlphaType};
  155. }
  156. }()) {}
  157. #if SK_SUPPORT_GPU
  158. std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
  159. GrRecordingContext*, const GrColorSpaceInfo&) const override {
  160. // wish our caller would let us know if our input was opaque...
  161. GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul;
  162. switch (fDir) {
  163. case Direction::kLinearToSRGB:
  164. return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha);
  165. case Direction::kSRGBToLinear:
  166. return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha);
  167. }
  168. return nullptr;
  169. }
  170. #endif
  171. bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
  172. if (!shaderIsOpaque) {
  173. rec.fPipeline->append(SkRasterPipeline::unpremul);
  174. }
  175. // TODO: is it valuable to thread this through appendStages()?
  176. bool shaderIsNormalized = false;
  177. fSteps.apply(rec.fPipeline, shaderIsNormalized);
  178. if (!shaderIsOpaque) {
  179. rec.fPipeline->append(SkRasterPipeline::premul);
  180. }
  181. return true;
  182. }
  183. protected:
  184. void flatten(SkWriteBuffer& buffer) const override {
  185. buffer.write32(static_cast<uint32_t>(fDir));
  186. }
  187. private:
  188. SK_FLATTENABLE_HOOKS(SkSRGBGammaColorFilter)
  189. const Direction fDir;
  190. SkColorSpaceXformSteps fSteps;
  191. friend class SkColorFilter;
  192. typedef SkColorFilter INHERITED;
  193. };
  194. sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
  195. uint32_t dir = buffer.read32();
  196. if (!buffer.validate(dir <= 1)) {
  197. return nullptr;
  198. }
  199. return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
  200. }
  201. template <SkSRGBGammaColorFilter::Direction dir>
  202. sk_sp<SkColorFilter> MakeSRGBGammaCF() {
  203. static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir);
  204. return sk_ref_sp(gSingleton);
  205. }
  206. sk_sp<SkColorFilter> SkColorFilters::LinearToSRGBGamma() {
  207. return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>();
  208. }
  209. sk_sp<SkColorFilter> SkColorFilters::SRGBToLinearGamma() {
  210. return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>();
  211. }
  212. ///////////////////////////////////////////////////////////////////////////////////////////////////
  213. class SkMixerColorFilter : public SkColorFilter {
  214. public:
  215. SkMixerColorFilter(sk_sp<SkColorFilter> cf0, sk_sp<SkColorFilter> cf1, float weight)
  216. : fCF0(std::move(cf0)), fCF1(std::move(cf1)), fWeight(weight)
  217. {
  218. SkASSERT(fCF0);
  219. SkASSERT(fWeight >= 0 && fWeight <= 1);
  220. }
  221. uint32_t getFlags() const override {
  222. uint32_t f0 = fCF0->getFlags();
  223. uint32_t f1 = fCF1 ? fCF1->getFlags() : ~0U;
  224. return f0 & f1;
  225. }
  226. bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
  227. // want cf0 * (1 - w) + cf1 * w == lerp(w)
  228. // which means
  229. // dr,dg,db,da <-- cf0
  230. // r,g,b,a <-- cf1
  231. struct State {
  232. float orig_rgba[4 * SkRasterPipeline_kMaxStride];
  233. float filtered_rgba[4 * SkRasterPipeline_kMaxStride];
  234. };
  235. auto state = rec.fAlloc->make<State>();
  236. SkRasterPipeline* p = rec.fPipeline;
  237. p->append(SkRasterPipeline::store_src, state->orig_rgba);
  238. if (!fCF1) {
  239. fCF0->appendStages(rec, shaderIsOpaque);
  240. p->append(SkRasterPipeline::move_src_dst);
  241. p->append(SkRasterPipeline::load_src, state->orig_rgba);
  242. } else {
  243. fCF0->appendStages(rec, shaderIsOpaque);
  244. p->append(SkRasterPipeline::store_src, state->filtered_rgba);
  245. p->append(SkRasterPipeline::load_src, state->orig_rgba);
  246. fCF1->appendStages(rec, shaderIsOpaque);
  247. p->append(SkRasterPipeline::load_dst, state->filtered_rgba);
  248. }
  249. float* storage = rec.fAlloc->make<float>(fWeight);
  250. p->append(SkRasterPipeline::lerp_1_float, storage);
  251. return true;
  252. }
  253. #if SK_SUPPORT_GPU
  254. std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
  255. GrRecordingContext* context, const GrColorSpaceInfo& dstColorSpaceInfo) const override {
  256. return GrMixerEffect::Make(
  257. fCF0->asFragmentProcessor(context, dstColorSpaceInfo),
  258. fCF1 ? fCF1->asFragmentProcessor(context, dstColorSpaceInfo) : nullptr,
  259. fWeight);
  260. }
  261. #endif
  262. protected:
  263. void flatten(SkWriteBuffer& buffer) const override {
  264. buffer.writeFlattenable(fCF0.get());
  265. buffer.writeFlattenable(fCF1.get());
  266. buffer.writeScalar(fWeight);
  267. }
  268. private:
  269. SK_FLATTENABLE_HOOKS(SkMixerColorFilter)
  270. sk_sp<SkColorFilter> fCF0;
  271. sk_sp<SkColorFilter> fCF1;
  272. const float fWeight;
  273. friend class SkColorFilter;
  274. typedef SkColorFilter INHERITED;
  275. };
  276. sk_sp<SkFlattenable> SkMixerColorFilter::CreateProc(SkReadBuffer& buffer) {
  277. sk_sp<SkColorFilter> cf0(buffer.readColorFilter());
  278. sk_sp<SkColorFilter> cf1(buffer.readColorFilter());
  279. const float weight = buffer.readScalar();
  280. return SkColorFilters::Lerp(weight, std::move(cf0), std::move(cf1));
  281. }
  282. sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0,
  283. sk_sp<SkColorFilter> cf1) {
  284. if (!cf0 && !cf1) {
  285. return nullptr;
  286. }
  287. if (SkScalarIsNaN(weight)) {
  288. return nullptr;
  289. }
  290. if (cf0 == cf1) {
  291. return cf0; // or cf1
  292. }
  293. if (weight <= 0) {
  294. return cf0;
  295. }
  296. if (weight >= 1) {
  297. return cf1;
  298. }
  299. return sk_sp<SkColorFilter>(cf0
  300. ? new SkMixerColorFilter(std::move(cf0), std::move(cf1), weight)
  301. : new SkMixerColorFilter(std::move(cf1), nullptr, 1 - weight));
  302. }
  303. ///////////////////////////////////////////////////////////////////////////////////////////////////
  304. #include "include/private/SkMutex.h"
  305. #if SK_SUPPORT_GPU
  306. #include "include/private/GrRecordingContext.h"
  307. #include "src/gpu/effects/GrSkSLFP.h"
  308. #include "src/sksl/SkSLByteCode.h"
  309. class SkRuntimeColorFilter : public SkColorFilter {
  310. public:
  311. SkRuntimeColorFilter(int index, SkString sksl, sk_sp<SkData> inputs,
  312. void (*cpuFunction)(float[4], const void*))
  313. : fIndex(index)
  314. , fSkSL(std::move(sksl))
  315. , fInputs(std::move(inputs))
  316. , fCpuFunction(cpuFunction) {}
  317. #if SK_SUPPORT_GPU
  318. std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
  319. GrRecordingContext* context, const GrColorSpaceInfo&) const override {
  320. return GrSkSLFP::Make(context, fIndex, "Runtime Color Filter", fSkSL,
  321. fInputs ? fInputs->data() : nullptr,
  322. fInputs ? fInputs->size() : 0);
  323. }
  324. #endif
  325. bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
  326. if (fCpuFunction) {
  327. struct CpuFuncCtx : public SkRasterPipeline_CallbackCtx {
  328. SkRuntimeColorFilterFn cpuFn;
  329. const void* inputs;
  330. };
  331. auto ctx = rec.fAlloc->make<CpuFuncCtx>();
  332. ctx->inputs = fInputs->data();
  333. ctx->cpuFn = fCpuFunction;
  334. ctx->fn = [](SkRasterPipeline_CallbackCtx* arg, int active_pixels) {
  335. auto ctx = (CpuFuncCtx*)arg;
  336. for (int i = 0; i < active_pixels; i++) {
  337. ctx->cpuFn(ctx->rgba + i * 4, ctx->inputs);
  338. }
  339. };
  340. rec.fPipeline->append(SkRasterPipeline::callback, ctx);
  341. } else {
  342. auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
  343. // don't need to set ctx->paintColor
  344. ctx->inputs = fInputs->data();
  345. ctx->ninputs = fInputs->size() / 4;
  346. ctx->shaderConvention = false;
  347. SkAutoMutexExclusive ama(fByteCodeMutex);
  348. if (!fByteCode) {
  349. SkSL::Compiler c;
  350. auto prog = c.convertProgram(SkSL::Program::kPipelineStage_Kind,
  351. SkSL::String(fSkSL.c_str()),
  352. SkSL::Program::Settings());
  353. if (c.errorCount()) {
  354. SkDebugf("%s\n", c.errorText().c_str());
  355. return false;
  356. }
  357. fByteCode = c.toByteCode(*prog);
  358. }
  359. ctx->byteCode = fByteCode.get();
  360. ctx->fn = ctx->byteCode->fFunctions[0].get();
  361. rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
  362. }
  363. return true;
  364. }
  365. protected:
  366. void flatten(SkWriteBuffer& buffer) const override {
  367. // the client is responsible for ensuring that the indices match up between flattening and
  368. // unflattening; we don't have a reasonable way to enforce that at the moment
  369. buffer.writeInt(fIndex);
  370. buffer.writeString(fSkSL.c_str());
  371. if (fInputs) {
  372. buffer.writeDataAsByteArray(fInputs.get());
  373. } else {
  374. buffer.writeByteArray(nullptr, 0);
  375. }
  376. }
  377. private:
  378. SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
  379. int fIndex;
  380. SkString fSkSL;
  381. sk_sp<SkData> fInputs;
  382. SkRuntimeColorFilterFn fCpuFunction;
  383. mutable SkMutex fByteCodeMutex;
  384. mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
  385. friend class SkColorFilter;
  386. typedef SkColorFilter INHERITED;
  387. };
  388. sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
  389. int index = buffer.readInt();
  390. SkString sksl;
  391. buffer.readString(&sksl);
  392. sk_sp<SkData> inputs = buffer.readByteArrayAsData();
  393. return sk_sp<SkFlattenable>(new SkRuntimeColorFilter(index, std::move(sksl), std::move(inputs),
  394. nullptr));
  395. }
  396. SkRuntimeColorFilterFactory::SkRuntimeColorFilterFactory(SkString sksl,
  397. SkRuntimeColorFilterFn cpuFunc)
  398. : fIndex(GrSkSLFP::NewIndex())
  399. , fSkSL(std::move(sksl))
  400. , fCpuFunc(cpuFunc) {}
  401. sk_sp<SkColorFilter> SkRuntimeColorFilterFactory::make(sk_sp<SkData> inputs) {
  402. return sk_sp<SkColorFilter>(new SkRuntimeColorFilter(fIndex, fSkSL, std::move(inputs),
  403. fCpuFunc));
  404. }
  405. #endif // SK_SUPPORT_GPU
  406. ///////////////////////////////////////////////////////////////////////////////////////////////////
  407. #include "src/core/SkModeColorFilter.h"
  408. void SkColorFilter::RegisterFlattenables() {
  409. SK_REGISTER_FLATTENABLE(SkComposeColorFilter);
  410. SK_REGISTER_FLATTENABLE(SkModeColorFilter);
  411. SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter);
  412. SK_REGISTER_FLATTENABLE(SkMixerColorFilter);
  413. #if SK_SUPPORT_GPU
  414. SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
  415. #endif
  416. }