krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 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 "GrDitherEffect.h" |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 9 | #include "GrFragmentProcessor.h" |
egdaniel | 605dd0f | 2014-11-12 08:35:25 -0800 | [diff] [blame] | 10 | #include "GrInvariantOutput.h" |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 11 | #include "SkRect.h" |
wangyix | 6af0c93 | 2015-07-22 10:21:17 -0700 | [diff] [blame] | 12 | #include "gl/GrGLFragmentProcessor.h" |
egdaniel | 2d721d3 | 2015-11-11 13:06:05 -0800 | [diff] [blame^] | 13 | #include "glsl/GrGLSLFragmentShaderBuilder.h" |
| 14 | #include "glsl/GrGLSLProgramBuilder.h" |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 15 | |
| 16 | ////////////////////////////////////////////////////////////////////////////// |
| 17 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 18 | class DitherEffect : public GrFragmentProcessor { |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 19 | public: |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 20 | static GrFragmentProcessor* Create() { |
bsalomon | 0214173 | 2015-10-21 06:57:30 -0700 | [diff] [blame] | 21 | return new DitherEffect; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 22 | } |
| 23 | |
| 24 | virtual ~DitherEffect() {}; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 25 | |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 26 | const char* name() const override { return "Dither"; } |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 27 | |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 28 | private: |
| 29 | DitherEffect() { |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 30 | this->initClassID<DitherEffect>(); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 31 | this->setWillReadFragmentPosition(); |
| 32 | } |
| 33 | |
wangyix | b1daa86 | 2015-08-18 11:29:31 -0700 | [diff] [blame] | 34 | GrGLFragmentProcessor* onCreateGLInstance() const override; |
| 35 | |
wangyix | 4b3050b | 2015-08-04 07:59:37 -0700 | [diff] [blame] | 36 | void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; |
| 37 | |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 38 | // All dither effects are equal |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 39 | bool onIsEqual(const GrFragmentProcessor&) const override { return true; } |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 40 | |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 41 | void onComputeInvariantOutput(GrInvariantOutput* inout) const override; |
egdaniel | 1a8ecdf | 2014-10-03 06:24:12 -0700 | [diff] [blame] | 42 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 43 | GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 44 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 45 | typedef GrFragmentProcessor INHERITED; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 46 | }; |
| 47 | |
egdaniel | 605dd0f | 2014-11-12 08:35:25 -0800 | [diff] [blame] | 48 | void DitherEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { |
| 49 | inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 50 | } |
| 51 | |
| 52 | ////////////////////////////////////////////////////////////////////////////// |
| 53 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 54 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(DitherEffect); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 55 | |
bsalomon | c21b09e | 2015-08-28 18:46:56 -0700 | [diff] [blame] | 56 | const GrFragmentProcessor* DitherEffect::TestCreate(GrProcessorTestData*) { |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 57 | return DitherEffect::Create(); |
| 58 | } |
| 59 | |
| 60 | ////////////////////////////////////////////////////////////////////////////// |
| 61 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 62 | class GLDitherEffect : public GrGLFragmentProcessor { |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 63 | public: |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 64 | GLDitherEffect(const GrProcessor&); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 65 | |
wangyix | 7c157a9 | 2015-07-22 15:08:53 -0700 | [diff] [blame] | 66 | virtual void emitCode(EmitArgs& args) override; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 67 | |
| 68 | private: |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 69 | typedef GrGLFragmentProcessor INHERITED; |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 70 | }; |
| 71 | |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 72 | GLDitherEffect::GLDitherEffect(const GrProcessor&) { |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 73 | } |
| 74 | |
wangyix | 7c157a9 | 2015-07-22 15:08:53 -0700 | [diff] [blame] | 75 | void GLDitherEffect::emitCode(EmitArgs& args) { |
egdaniel | 2d721d3 | 2015-11-11 13:06:05 -0800 | [diff] [blame^] | 76 | GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 77 | // Generate a random number based on the fragment position. For this |
| 78 | // random number generator, we use the "GLSL rand" function |
| 79 | // that seems to be floating around on the internet. It works under |
| 80 | // the assumption that sin(<big number>) oscillates with high frequency |
| 81 | // and sampling it will generate "randomness". Since we're using this |
| 82 | // for rendering and not cryptography it should be OK. |
| 83 | |
| 84 | // For each channel c, add the random offset to the pixel to either bump |
| 85 | // it up or let it remain constant during quantization. |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 86 | fsBuilder->codeAppendf("\t\tfloat r = " |
bsalomon | 2290000 | 2014-06-24 11:16:52 -0700 | [diff] [blame] | 87 | "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n", |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 88 | fsBuilder->fragmentPosition()); |
| 89 | fsBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n", |
wangyix | 7c157a9 | 2015-07-22 15:08:53 -0700 | [diff] [blame] | 90 | args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str()); |
krajcevski | f461a8f | 2014-06-19 14:14:06 -0700 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | ////////////////////////////////////////////////////////////////////////////// |
| 94 | |
wangyix | 4b3050b | 2015-08-04 07:59:37 -0700 | [diff] [blame] | 95 | void DitherEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, |
egdaniel | 2d721d3 | 2015-11-11 13:06:05 -0800 | [diff] [blame^] | 96 | GrProcessorKeyBuilder* b) const { |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 97 | GLDitherEffect::GenKey(*this, caps, b); |
| 98 | } |
| 99 | |
wangyix | b1daa86 | 2015-08-18 11:29:31 -0700 | [diff] [blame] | 100 | GrGLFragmentProcessor* DitherEffect::onCreateGLInstance() const { |
halcanary | 385fe4d | 2015-08-26 13:07:48 -0700 | [diff] [blame] | 101 | return new GLDitherEffect(*this); |
joshualitt | eb2a676 | 2014-12-04 11:35:33 -0800 | [diff] [blame] | 102 | } |
| 103 | |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 104 | GrFragmentProcessor* GrDitherEffect::Create() { return DitherEffect::Create(); } |