1/*
2 * Copyright 2014 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 "gl/builders/GrGLProgramBuilder.h"
9#include "GrDitherEffect.h"
10
11#include "gl/GrGLProcessor.h"
12#include "gl/GrGLSL.h"
13#include "GrTBackendProcessorFactory.h"
14
15#include "SkRect.h"
16
17//////////////////////////////////////////////////////////////////////////////
18
19class GLDitherEffect;
20
21class DitherEffect : public GrFragmentProcessor {
22public:
23    static GrFragmentProcessor* Create() {
24        GR_CREATE_STATIC_FRAGMENT_PROCESSOR(gDitherEffect, DitherEffect, ())
25        return SkRef(gDitherEffect);
26    }
27
28    virtual ~DitherEffect() {};
29    static const char* Name() { return "Dither"; }
30
31    typedef GLDitherEffect GLProcessor;
32
33    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
34
35    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
36        return GrTBackendFragmentProcessorFactory<DitherEffect>::getInstance();
37    }
38
39private:
40    DitherEffect() {
41        this->setWillReadFragmentPosition();
42    }
43
44    // All dither effects are equal
45    virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
46
47    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
48
49    typedef GrFragmentProcessor INHERITED;
50};
51
52void DitherEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
53    *validFlags = 0;
54}
55
56//////////////////////////////////////////////////////////////////////////////
57
58GR_DEFINE_FRAGMENT_PROCESSOR_TEST(DitherEffect);
59
60GrFragmentProcessor* DitherEffect::TestCreate(SkRandom*,
61                                              GrContext*,
62                                              const GrDrawTargetCaps&,
63                                              GrTexture*[]) {
64    return DitherEffect::Create();
65}
66
67//////////////////////////////////////////////////////////////////////////////
68
69class GLDitherEffect : public GrGLFragmentProcessor {
70public:
71    GLDitherEffect(const GrBackendProcessorFactory&, const GrProcessor&);
72
73    virtual void emitCode(GrGLProgramBuilder* builder,
74                          const GrFragmentProcessor& fp,
75                          const GrProcessorKey& key,
76                          const char* outputColor,
77                          const char* inputColor,
78                          const TransformedCoordsArray&,
79                          const TextureSamplerArray&) SK_OVERRIDE;
80
81private:
82    typedef GrGLFragmentProcessor INHERITED;
83};
84
85GLDitherEffect::GLDitherEffect(const GrBackendProcessorFactory& factory,
86                               const GrProcessor&)
87    : INHERITED (factory) {
88}
89
90void GLDitherEffect::emitCode(GrGLProgramBuilder* builder,
91                              const GrFragmentProcessor& fp,
92                              const GrProcessorKey& key,
93                              const char* outputColor,
94                              const char* inputColor,
95                              const TransformedCoordsArray&,
96                              const TextureSamplerArray& samplers) {
97    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
98    // Generate a random number based on the fragment position. For this
99    // random number generator, we use the "GLSL rand" function
100    // that seems to be floating around on the internet. It works under
101    // the assumption that sin(<big number>) oscillates with high frequency
102    // and sampling it will generate "randomness". Since we're using this
103    // for rendering and not cryptography it should be OK.
104
105    // For each channel c, add the random offset to the pixel to either bump
106    // it up or let it remain constant during quantization.
107    fsBuilder->codeAppendf("\t\tfloat r = "
108                           "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n",
109                           fsBuilder->fragmentPosition());
110    fsBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n",
111                           outputColor, GrGLSLExpr4(inputColor).c_str());
112}
113
114//////////////////////////////////////////////////////////////////////////////
115
116GrFragmentProcessor* GrDitherEffect::Create() { return DitherEffect::Create(); }
117