• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorFilter.h"
11 #include "include/core/SkFlattenable.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkString.h"
15 #include "include/core/SkTypes.h"
16 #include "include/private/SkSLSampleUsage.h"
17 #include "src/base/SkArenaAlloc.h"
18 #include "src/core/SkColorFilterBase.h"
19 #include "src/core/SkEffectPriv.h"
20 #include "src/core/SkRasterPipeline.h"
21 #include "src/core/SkRasterPipelineOpContexts.h"
22 #include "src/core/SkRasterPipelineOpList.h"
23 #include "src/core/SkReadBuffer.h"
24 #include "src/core/SkWriteBuffer.h"
25 
26 #include <cstdint>
27 #include <memory>
28 #include <tuple>
29 #include <utility>
30 
31 #if defined(SK_GRAPHITE)
32 #include "src/gpu/graphite/Image_Graphite.h"
33 #include "src/gpu/graphite/KeyContext.h"
34 #include "src/gpu/graphite/KeyHelpers.h"
35 #include "src/gpu/graphite/PaintParamsKey.h"
36 
37 namespace skgpu::graphite {
38 class PipelineDataGatherer;
39 }
40 #endif
41 
42 #if defined(SK_GANESH)
43 #include "include/gpu/GpuTypes.h"
44 #include "include/gpu/GrTypes.h"
45 #include "src/gpu/ganesh/GrColorInfo.h"
46 #include "src/gpu/ganesh/GrFragmentProcessor.h"
47 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
48 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
49 #include "src/gpu/ganesh/SkGr.h"
50 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
51 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
52 
53 class GrRecordingContext;
54 struct GrShaderCaps;
55 namespace skgpu { class KeyBuilder; }
56 #endif
57 
58 #if GR_TEST_UTILS
59 #include "include/core/SkColorSpace.h"
60 #include "include/core/SkSurfaceProps.h"
61 #include "include/private/base/SkTo.h"
62 #include "include/private/gpu/ganesh/GrTypesPriv.h"
63 #include "src/base/SkRandom.h"
64 #include "src/gpu/ganesh/GrTestUtils.h"
65 #else
66 class SkSurfaceProps;
67 #endif
68 
69 #if defined(SK_ENABLE_SKSL)
70 #include "src/core/SkVM.h"
71 #endif
72 
73 class SkTable_ColorFilter final : public SkColorFilterBase {
74 public:
SkTable_ColorFilter(const uint8_t tableA[],const uint8_t tableR[],const uint8_t tableG[],const uint8_t tableB[])75     SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
76                         const uint8_t tableG[], const uint8_t tableB[]) {
77         fBitmap.allocPixels(SkImageInfo::MakeA8(256, 4));
78         uint8_t *a = fBitmap.getAddr8(0,0),
79                 *r = fBitmap.getAddr8(0,1),
80                 *g = fBitmap.getAddr8(0,2),
81                 *b = fBitmap.getAddr8(0,3);
82         for (int i = 0; i < 256; i++) {
83             a[i] = tableA ? tableA[i] : i;
84             r[i] = tableR ? tableR[i] : i;
85             g[i] = tableG ? tableG[i] : i;
86             b[i] = tableB ? tableB[i] : i;
87         }
88         fBitmap.setImmutable();
89     }
90 
91 #if defined(SK_GANESH)
92     GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
93                                    GrRecordingContext*, const GrColorInfo&,
94                                    const SkSurfaceProps&) const override;
95 #endif
96 
97 #if defined(SK_GRAPHITE)
98     void addToKey(const skgpu::graphite::KeyContext&,
99                   skgpu::graphite::PaintParamsKeyBuilder*,
100                   skgpu::graphite::PipelineDataGatherer*) const override;
101 #endif
102 
appendStages(const SkStageRec & rec,bool shaderIsOpaque) const103     bool appendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
104         SkRasterPipeline* p = rec.fPipeline;
105         if (!shaderIsOpaque) {
106             p->append(SkRasterPipelineOp::unpremul);
107         }
108 
109         SkRasterPipeline_TablesCtx* tables = rec.fAlloc->make<SkRasterPipeline_TablesCtx>();
110         tables->a = fBitmap.getAddr8(0, 0);
111         tables->r = fBitmap.getAddr8(0, 1);
112         tables->g = fBitmap.getAddr8(0, 2);
113         tables->b = fBitmap.getAddr8(0, 3);
114         p->append(SkRasterPipelineOp::byte_tables, tables);
115 
116         bool definitelyOpaque = shaderIsOpaque && tables->a[0xff] == 0xff;
117         if (!definitelyOpaque) {
118             p->append(SkRasterPipelineOp::premul);
119         }
120         return true;
121     }
122 
onProgram(skvm::Builder * p,skvm::Color c,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc *) const123     skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
124                           const SkColorInfo& dst,
125                           skvm::Uniforms* uniforms, SkArenaAlloc*) const override {
126 
127         auto apply_table_to_component = [&](skvm::F32 c, const uint8_t* bytePtr) -> skvm::F32 {
128             skvm::I32     index = to_unorm(8, clamp01(c));
129             skvm::Uniform table = uniforms->pushPtr(bytePtr);
130             return from_unorm(8, gather8(table, index));
131         };
132 
133         c = unpremul(c);
134         c.a = apply_table_to_component(c.a, fBitmap.getAddr8(0,0));
135         c.r = apply_table_to_component(c.r, fBitmap.getAddr8(0,1));
136         c.g = apply_table_to_component(c.g, fBitmap.getAddr8(0,2));
137         c.b = apply_table_to_component(c.b, fBitmap.getAddr8(0,3));
138         return premul(c);
139     }
140 
flatten(SkWriteBuffer & buffer) const141     void flatten(SkWriteBuffer& buffer) const override {
142         buffer.writeByteArray(fBitmap.getAddr8(0,0), 4*256);
143     }
144 
145 private:
146     friend void ::SkRegisterTableColorFilterFlattenable();
147     SK_FLATTENABLE_HOOKS(SkTable_ColorFilter)
148 
149     SkBitmap fBitmap;
150 };
151 
CreateProc(SkReadBuffer & buffer)152 sk_sp<SkFlattenable> SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
153     uint8_t argb[4*256];
154     if (buffer.readByteArray(argb, sizeof(argb))) {
155         return SkColorFilters::TableARGB(argb+0*256, argb+1*256, argb+2*256, argb+3*256);
156     }
157     return nullptr;
158 }
159 
160 #if defined(SK_GANESH)
161 
162 class ColorTableEffect : public GrFragmentProcessor {
163 public:
164     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP,
165                                                      GrRecordingContext* context,
166                                                      const SkBitmap& bitmap);
167 
~ColorTableEffect()168     ~ColorTableEffect() override {}
169 
name() const170     const char* name() const override { return "ColorTableEffect"; }
171 
clone() const172     std::unique_ptr<GrFragmentProcessor> clone() const override {
173         return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(*this));
174     }
175 
176     inline static constexpr int kTexEffectFPIndex = 0;
177     inline static constexpr int kInputFPIndex = 1;
178 
179 private:
180     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
181 
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const182     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
183 
onIsEqual(const GrFragmentProcessor &) const184     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
185 
186     ColorTableEffect(std::unique_ptr<GrFragmentProcessor> inputFP, GrSurfaceProxyView view);
187 
188     explicit ColorTableEffect(const ColorTableEffect& that);
189 
190     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
191 
192     using INHERITED = GrFragmentProcessor;
193 };
194 
ColorTableEffect(std::unique_ptr<GrFragmentProcessor> inputFP,GrSurfaceProxyView view)195 ColorTableEffect::ColorTableEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
196                                    GrSurfaceProxyView view)
197         // Not bothering with table-specific optimizations.
198         : INHERITED(kColorTableEffect_ClassID, kNone_OptimizationFlags) {
199     this->registerChild(GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType),
200                         SkSL::SampleUsage::Explicit());
201     this->registerChild(std::move(inputFP));
202 }
203 
ColorTableEffect(const ColorTableEffect & that)204 ColorTableEffect::ColorTableEffect(const ColorTableEffect& that)
205         : INHERITED(that) {}
206 
onMakeProgramImpl() const207 std::unique_ptr<GrFragmentProcessor::ProgramImpl> ColorTableEffect::onMakeProgramImpl() const {
208     class Impl : public ProgramImpl {
209     public:
210         void emitCode(EmitArgs& args) override {
211             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
212             SkString inputColor = this->invokeChild(kInputFPIndex, args);
213             SkString a = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.a, 0.5)");
214             SkString r = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.r, 1.5)");
215             SkString g = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.g, 2.5)");
216             SkString b = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.b, 3.5)");
217             fragBuilder->codeAppendf(
218                     "half4 coord = 255 * unpremul(%s) + 0.5;\n"
219                     "half4 color = half4(%s.a, %s.a, %s.a, 1);\n"
220                     "return color * %s.a;\n",
221                     inputColor.c_str(), r.c_str(), g.c_str(), b.c_str(), a.c_str());
222         }
223     };
224 
225     return std::make_unique<Impl>();
226 }
227 
Make(std::unique_ptr<GrFragmentProcessor> inputFP,GrRecordingContext * context,const SkBitmap & bitmap)228 std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(
229         std::unique_ptr<GrFragmentProcessor> inputFP,
230         GrRecordingContext* context, const SkBitmap& bitmap) {
231     SkASSERT(kPremul_SkAlphaType == bitmap.alphaType());
232     SkASSERT(bitmap.isImmutable());
233 
234     auto view = std::get<0>(GrMakeCachedBitmapProxyView(context,
235                                                         bitmap,
236                                                         /*label=*/"MakeColorTableEffect",
237                                                         GrMipmapped::kNo));
238     if (!view) {
239         return nullptr;
240     }
241 
242     return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(std::move(inputFP),
243                                                                      std::move(view)));
244 }
245 
246 ///////////////////////////////////////////////////////////////////////////////
247 
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect)248 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect)
249 
250 #if GR_TEST_UTILS
251 
252 
253 std::unique_ptr<GrFragmentProcessor> ColorTableEffect::TestCreate(GrProcessorTestData* d) {
254     int flags = 0;
255     uint8_t luts[256][4];
256     do {
257         for (int i = 0; i < 4; ++i) {
258             flags |= d->fRandom->nextBool() ? (1  << i): 0;
259         }
260     } while (!flags);
261     for (int i = 0; i < 4; ++i) {
262         if (flags & (1 << i)) {
263             for (int j = 0; j < 256; ++j) {
264                 luts[j][i] = SkToU8(d->fRandom->nextBits(8));
265             }
266         }
267     }
268     auto filter(SkColorFilters::TableARGB(
269         (flags & (1 << 0)) ? luts[0] : nullptr,
270         (flags & (1 << 1)) ? luts[1] : nullptr,
271         (flags & (1 << 2)) ? luts[2] : nullptr,
272         (flags & (1 << 3)) ? luts[3] : nullptr
273     ));
274     sk_sp<SkColorSpace> colorSpace = GrTest::TestColorSpace(d->fRandom);
275     SkSurfaceProps props; // default props for testing
276     auto [success, fp] = as_CFB(filter)->asFragmentProcessor(
277             d->inputFP(), d->context(),
278             GrColorInfo(GrColorType::kRGBA_8888, kUnknown_SkAlphaType, std::move(colorSpace)),
279             props);
280     SkASSERT(success);
281     return std::move(fp);
282 }
283 #endif
284 
asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,GrRecordingContext * context,const GrColorInfo &,const SkSurfaceProps &) const285 GrFPResult SkTable_ColorFilter::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
286                                                     GrRecordingContext* context,
287                                                     const GrColorInfo&,
288                                                     const SkSurfaceProps&) const {
289     auto cte = ColorTableEffect::Make(std::move(inputFP), context, fBitmap);
290     return cte ? GrFPSuccess(std::move(cte)) : GrFPFailure(nullptr);
291 }
292 
293 #endif // defined(SK_GANESH)
294 
295 #if defined(SK_GRAPHITE)
296 
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const297 void SkTable_ColorFilter::addToKey(const skgpu::graphite::KeyContext& keyContext,
298                                    skgpu::graphite::PaintParamsKeyBuilder* builder,
299                                    skgpu::graphite::PipelineDataGatherer* gatherer) const {
300     using namespace skgpu::graphite;
301 
302     TableColorFilterBlock::TableColorFilterData data;
303 
304     // TODO(b/239604347): remove this hack. This is just here until we determine what Graphite's
305     // Recorder-level caching story is going to be.
306     sk_sp<SkImage> image = SkImage::MakeFromBitmap(fBitmap);
307     image = image->makeTextureImage(keyContext.recorder(), { skgpu::Mipmapped::kNo });
308 
309     if (as_IB(image)->isGraphiteBacked()) {
310         skgpu::graphite::Image* grImage = static_cast<skgpu::graphite::Image*>(image.get());
311 
312         auto [view, _] = grImage->asView(keyContext.recorder(), skgpu::Mipmapped::kNo);
313         data.fTextureProxy = view.refProxy();
314     }
315 
316     TableColorFilterBlock::BeginBlock(keyContext, builder, gatherer, data);
317     builder->endBlock();
318 }
319 
320 #endif
321 
322 ///////////////////////////////////////////////////////////////////////////////
323 
Table(const uint8_t table[256])324 sk_sp<SkColorFilter> SkColorFilters::Table(const uint8_t table[256]) {
325     return sk_make_sp<SkTable_ColorFilter>(table, table, table, table);
326 }
327 
TableARGB(const uint8_t tableA[256],const uint8_t tableR[256],const uint8_t tableG[256],const uint8_t tableB[256])328 sk_sp<SkColorFilter> SkColorFilters::TableARGB(const uint8_t tableA[256],
329                                                const uint8_t tableR[256],
330                                                const uint8_t tableG[256],
331                                                const uint8_t tableB[256]) {
332     if (!tableA && !tableR && !tableG && !tableB) {
333         return nullptr;
334     }
335 
336     return sk_make_sp<SkTable_ColorFilter>(tableA, tableR, tableG, tableB);
337 }
338 
SkRegisterTableColorFilterFlattenable()339 void SkRegisterTableColorFilterFlattenable() {
340     SK_REGISTER_FLATTENABLE(SkTable_ColorFilter);
341 }
342