1 | /* |
2 | * Copyright 2016 Google Inc. |
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 | |
8 | #include "include/core/SkUnPreMultiply.h" |
9 | #include "include/effects/SkOverdrawColorFilter.h" |
10 | #include "src/core/SkArenaAlloc.h" |
11 | #include "src/core/SkEffectPriv.h" |
12 | #include "src/core/SkRasterPipeline.h" |
13 | #include "src/core/SkReadBuffer.h" |
14 | #include "src/core/SkVM.h" |
15 | |
16 | #if SK_SUPPORT_GPU |
17 | #include "include/effects/SkRuntimeEffect.h" |
18 | #include "src/gpu/effects/GrSkSLFP.h" |
19 | |
20 | GR_FP_SRC_STRING SKSL_OVERDRAW_SRC = R"( |
21 | uniform half4 color0; |
22 | uniform half4 color1; |
23 | uniform half4 color2; |
24 | uniform half4 color3; |
25 | uniform half4 color4; |
26 | uniform half4 color5; |
27 | |
28 | void main(inout half4 color) { |
29 | half alpha = 255.0 * color.a; |
30 | if (alpha < 0.5) { |
31 | color = color0; |
32 | } else if (alpha < 1.5) { |
33 | color = color1; |
34 | } else if (alpha < 2.5) { |
35 | color = color2; |
36 | } else if (alpha < 3.5) { |
37 | color = color3; |
38 | } else if (alpha < 4.5) { |
39 | color = color4; |
40 | } else { |
41 | color = color5; |
42 | } |
43 | } |
44 | )" ; |
45 | #endif |
46 | |
47 | static void convert_to_pm4f(SkPMColor4f dst[], const SkColor src[]) { |
48 | for (int i = 0; i < SkOverdrawColorFilter::kNumColors; ++i) { |
49 | dst[i] = SkColor4f::FromColor(src[i]).premul(); |
50 | } |
51 | } |
52 | |
53 | bool SkOverdrawColorFilter::onAppendStages(const SkStageRec& rec, bool shader_is_opaque) const { |
54 | struct Ctx : public SkRasterPipeline_CallbackCtx { |
55 | SkPMColor4f colors[kNumColors]; |
56 | }; |
57 | // TODO: do we care about transforming to dstCS? |
58 | auto ctx = rec.fAlloc->make<Ctx>(); |
59 | convert_to_pm4f(ctx->colors, fColors); |
60 | |
61 | ctx->fn = [](SkRasterPipeline_CallbackCtx* arg, int active_pixels) { |
62 | auto ctx = (Ctx*)arg; |
63 | auto pixels = (SkPMColor4f*)ctx->rgba; |
64 | for (int i = 0; i < active_pixels; i++) { |
65 | uint8_t alpha = (int)(pixels[i].fA * 255); |
66 | if (alpha >= kNumColors) { |
67 | alpha = kNumColors - 1; |
68 | } |
69 | pixels[i] = ctx->colors[alpha]; |
70 | } |
71 | }; |
72 | rec.fPipeline->append(SkRasterPipeline::callback, ctx); |
73 | return true; |
74 | } |
75 | |
76 | skvm::Color SkOverdrawColorFilter::onProgram(skvm::Builder* p, skvm::Color c, |
77 | SkColorSpace* /*dstCS*/, skvm::Uniforms* uniforms, |
78 | SkArenaAlloc* alloc) const { |
79 | skvm::I32 index = min(to_unorm(8,c.a), kNumColors - 1); |
80 | c = unpack_8888(gather32(uniforms->pushPtr(fColors), index)); |
81 | std::swap(c.r, c.b); // The SkColors in fColors are BGRA, but we want RGBA |
82 | return c; |
83 | } |
84 | |
85 | void SkOverdrawColorFilter::flatten(SkWriteBuffer& buffer) const { |
86 | buffer.writeByteArray(fColors, kNumColors * sizeof(SkPMColor)); |
87 | } |
88 | |
89 | sk_sp<SkFlattenable> SkOverdrawColorFilter::CreateProc(SkReadBuffer& buffer) { |
90 | SkPMColor colors[kNumColors]; |
91 | size_t size = buffer.getArrayCount(); |
92 | if (!buffer.validate(size == sizeof(colors))) { |
93 | return nullptr; |
94 | } |
95 | if (!buffer.readByteArray(colors, sizeof(colors))) { |
96 | return nullptr; |
97 | } |
98 | |
99 | return sk_sp<SkColorFilter>(new SkOverdrawColorFilter(colors)); |
100 | } |
101 | |
102 | void SkOverdrawColorFilter::RegisterFlattenables() { |
103 | SK_REGISTER_FLATTENABLE(SkOverdrawColorFilter); |
104 | } |
105 | #if SK_SUPPORT_GPU |
106 | |
107 | #include "include/private/GrRecordingContext.h" |
108 | |
109 | std::unique_ptr<GrFragmentProcessor> SkOverdrawColorFilter::asFragmentProcessor( |
110 | GrRecordingContext* context, const GrColorInfo&) const { |
111 | static auto effect = std::get<0>(SkRuntimeEffect::Make(SkString(SKSL_OVERDRAW_SRC))); |
112 | SkASSERT(effect->inputSize() == (kNumColors * sizeof(SkPMColor4f))); |
113 | |
114 | auto inputs = SkData::MakeUninitialized(kNumColors * sizeof(SkPMColor4f)); |
115 | convert_to_pm4f(reinterpret_cast<SkPMColor4f*>(inputs->writable_data()), fColors); |
116 | |
117 | return GrSkSLFP::Make(context, effect, "Overdraw" , std::move(inputs)); |
118 | } |
119 | |
120 | #endif |
121 | |