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 "SkArenaAlloc.h"
9 #include "SkOverdrawColorFilter.h"
10 #include "SkRasterPipeline.h"
11 #include "SkReadBuffer.h"
12 
13 #if SK_SUPPORT_GPU
14 #include "effects/GrSkSLFP.h"
15 
16 GR_FP_SRC_STRING SKSL_OVERDRAW_SRC = R"(
17 layout(ctype=SkPMColor) in uniform half4 color0;
18 layout(ctype=SkPMColor) in uniform half4 color1;
19 layout(ctype=SkPMColor) in uniform half4 color2;
20 layout(ctype=SkPMColor) in uniform half4 color3;
21 layout(ctype=SkPMColor) in uniform half4 color4;
22 layout(ctype=SkPMColor) in uniform half4 color5;
23 
24 void main(int x, int y, inout half4 color) {
25     half alpha = 255.0 * color.a;
26     if (alpha < 0.5) {
27         color = color0;
28     } else if (alpha < 1.5) {
29         color = color1;
30     } else if (alpha < 2.5) {
31         color = color2;
32     } else if (alpha < 3.5) {
33         color = color3;
34     } else if (alpha < 4.5) {
35         color = color4;
36     } else {
37         color = color5;
38     }
39 }
40 )";
41 #endif
42 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dstCS,SkArenaAlloc * alloc,bool shader_is_opaque) const43 void SkOverdrawColorFilter::onAppendStages(SkRasterPipeline* p,
44                                            SkColorSpace* dstCS,
45                                            SkArenaAlloc* alloc,
46                                            bool shader_is_opaque) const {
47     struct Ctx : public SkRasterPipeline_CallbackCtx {
48         const SkPMColor* colors;
49     };
50     // TODO: do we care about transforming to dstCS?
51     auto ctx = alloc->make<Ctx>();
52     ctx->colors = fColors;
53     ctx->fn = [](SkRasterPipeline_CallbackCtx* arg, int active_pixels) {
54         auto ctx = (Ctx*)arg;
55         auto pixels = (SkPMColor4f*)ctx->rgba;
56         for (int i = 0; i < active_pixels; i++) {
57             uint8_t alpha = (int)(pixels[i].fA * 255);
58             if (alpha >= kNumColors) {
59                 alpha = kNumColors - 1;
60             }
61             pixels[i] = SkPMColor4f::FromPMColor(ctx->colors[alpha]);
62         }
63     };
64     p->append(SkRasterPipeline::callback, ctx);
65 }
66 
flatten(SkWriteBuffer & buffer) const67 void SkOverdrawColorFilter::flatten(SkWriteBuffer& buffer) const {
68     buffer.writeByteArray(fColors, kNumColors * sizeof(SkPMColor));
69 }
70 
CreateProc(SkReadBuffer & buffer)71 sk_sp<SkFlattenable> SkOverdrawColorFilter::CreateProc(SkReadBuffer& buffer) {
72     SkPMColor colors[kNumColors];
73     size_t size = buffer.getArrayCount();
74     if (!buffer.validate(size == sizeof(colors))) {
75         return nullptr;
76     }
77     if (!buffer.readByteArray(colors, sizeof(colors))) {
78         return nullptr;
79     }
80 
81     return SkOverdrawColorFilter::Make(colors);
82 }
83 
RegisterFlattenables()84 void SkOverdrawColorFilter::RegisterFlattenables() {
85     SK_REGISTER_FLATTENABLE(SkOverdrawColorFilter);
86 }
87 #if SK_SUPPORT_GPU
88 
asFragmentProcessor(GrContext * context,const GrColorSpaceInfo &) const89 std::unique_ptr<GrFragmentProcessor> SkOverdrawColorFilter::asFragmentProcessor(
90         GrContext* context, const GrColorSpaceInfo&) const {
91     static int overdrawIndex = GrSkSLFP::NewIndex();
92     return GrSkSLFP::Make(context, overdrawIndex, "Overdraw", SKSL_OVERDRAW_SRC, fColors,
93                           sizeof(fColors));
94 }
95 
96 #endif
97