| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkRRectsGaussianEdgeShader.h" | 8 #include "SkRRectsGaussianEdgeShader.h" |
| 9 #include "SkReadBuffer.h" | 9 #include "SkReadBuffer.h" |
| 10 #include "SkWriteBuffer.h" | 10 #include "SkWriteBuffer.h" |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 this->setWillReadFragmentPosition(); | 97 this->setWillReadFragmentPosition(); |
| 98 | 98 |
| 99 fFirstMode = ComputeMode(fFirst); | 99 fFirstMode = ComputeMode(fFirst); |
| 100 fSecondMode = ComputeMode(fSecond); | 100 fSecondMode = ComputeMode(fSecond); |
| 101 } | 101 } |
| 102 | 102 |
| 103 class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { | 103 class GLSLRRectsGaussianEdgeFP : public GrGLSLFragmentProcessor { |
| 104 public: | 104 public: |
| 105 GLSLRRectsGaussianEdgeFP() { } | 105 GLSLRRectsGaussianEdgeFP() { } |
| 106 | 106 |
| 107 // This method emits code so that, for each shape, the distance from the
edge is returned |
| 108 // in 'outputName' clamped to 0..1 with positive distance being towards
the center of the |
| 109 // shape. The distance will have been normalized by the radius. |
| 107 void emitModeCode(Mode mode, | 110 void emitModeCode(Mode mode, |
| 108 GrGLSLFPFragmentBuilder* fragBuilder, | 111 GrGLSLFPFragmentBuilder* fragBuilder, |
| 109 const char* posName, | 112 const char* posName, |
| 110 const char* sizesName, | 113 const char* sizesName, |
| 111 const char* radiiName, | 114 const char* radiiName, |
| 115 const char* padRadName, |
| 112 const char* outputName, | 116 const char* outputName, |
| 113 const char indices[2]) { // how to access the params
for the 2 rrects | 117 const char indices[2]) { // how to access the params
for the 2 rrects |
| 114 | 118 |
| 115 // positive distance is towards the center of the circle | 119 // positive distance is towards the center of the circle |
| 116 fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;", | 120 fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;", |
| 117 fragBuilder->fragmentPosition(), | 121 fragBuilder->fragmentPosition(), posName, i
ndices); |
| 118 posName, indices); | |
| 119 | 122 |
| 120 switch (mode) { | 123 switch (mode) { |
| 121 case kCircle_Mode: | 124 case kCircle_Mode: |
| 122 fragBuilder->codeAppendf("%s = %s.%c - length(delta);", | 125 fragBuilder->codeAppendf("%s = clamp((%s.%c - length(delta))/%s.
y, 0.0, 1.0);", |
| 123 outputName, | 126 outputName, sizesName, indices[0], padR
adName); |
| 124 sizesName, indices[0]); | |
| 125 break; | 127 break; |
| 126 case kRect_Mode: | 128 case kRect_Mode: |
| 127 fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);", | 129 fragBuilder->codeAppendf( |
| 128 sizesName, indices[0]); | 130 "vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s.
y, 0.0, 1.0)," |
| 129 fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);", | 131 "1.0 - clamp((%s.%c - abs(delta.y))/%s.
y, 0.0, 1.0));", |
| 130 sizesName, indices[1]); | 132 sizesName, indices[0], padRadName, |
| 131 fragBuilder->codeAppendf("%s = min(xDist, yDist);", outputName); | 133 sizesName, indices[1], padRadName); |
| 134 fragBuilder->codeAppendf("%s = 1.0 - length(rectDist);", outputN
ame); |
| 132 break; | 135 break; |
| 133 case kSimpleCircular_Mode: | 136 case kSimpleCircular_Mode: |
| 134 // For the circular round rect we first compute the distance | 137 // For the circular round rect we first compute the distance |
| 135 // to the rect. Then we compute a multiplier that is 1 if the | 138 // to the rect. Then we compute a multiplier that is 1 if the |
| 136 // point is in one of the circular corners. We then compute the | 139 // point is in one of the circular corners. We then compute the |
| 137 // distance from the corner and then use the multiplier to mask | 140 // distance from the corner and then use the multiplier to mask |
| 138 // between the two distances. | 141 // between the two distances. |
| 139 fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);", | 142 fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta
.x))/%s.y," |
| 140 sizesName, indices[0]); | 143 " 0.0, 1.0);", |
| 141 fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);", | 144 sizesName, indices[0], padRadName); |
| 142 sizesName, indices[1]); | 145 fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta
.y))/%s.y," |
| 146 "0.0, 1.0);", |
| 147 sizesName, indices[1], padRadName); |
| 143 fragBuilder->codeAppend("float rectDist = min(xDist, yDist);"); | 148 fragBuilder->codeAppend("float rectDist = min(xDist, yDist);"); |
| 144 | 149 |
| 145 fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;", | 150 fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;", |
| 146 sizesName, indices, | 151 sizesName, indices, radiiName, indices)
; |
| 147 radiiName, indices); | |
| 148 fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCente
r.x," | 152 fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCente
r.x," |
| 149 "abs(delta.y) - cornerCente
r.y);"); | 153 "abs(delta.y) - cornerCente
r.y);"); |
| 150 fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", | 154 fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiN
ame, indices[0]); |
| 151 radiiName, indices[0]); | 155 fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiN
ame, indices[1]); |
| 152 fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", | |
| 153 radiiName, indices[1]); | |
| 154 fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);")
; | 156 fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);")
; |
| 155 fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist
);"); | 157 fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist
);"); |
| 156 | 158 |
| 157 fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices); | 159 fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices); |
| 158 | 160 |
| 159 fragBuilder->codeAppendf("cornerDist = 2.0 * %s.%c - length(delt
a);", | 161 fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - leng
th(delta))/%s.y," |
| 160 radiiName, indices[0]); | 162 "0.0, 1.0);", |
| 163 radiiName, indices[0], padRadName); |
| 161 | 164 |
| 162 fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +" | 165 fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +" |
| 163 "((1.0-multiplier) * rectDist);", | 166 "((1.0-multiplier) * rectDist);", |
| 164 outputName); | 167 outputName); |
| 165 break; | 168 break; |
| 166 } | 169 } |
| 167 } | 170 } |
| 168 | 171 |
| 169 void emitCode(EmitArgs& args) override { | 172 void emitCode(EmitArgs& args) override { |
| 170 const RRectsGaussianEdgeFP& fp = args.fFp.cast<RRectsGaussianEdgeFP>
(); | 173 const RRectsGaussianEdgeFP& fp = args.fFp.cast<RRectsGaussianEdgeFP>
(); |
| 171 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; | 174 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
| 172 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | 175 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
| 173 | 176 |
| 174 const char* positionsUniName = nullptr; | 177 const char* positionsUniName = nullptr; |
| 175 fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 178 fPositionsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| 176 kVec4f_GrSLType, kDefault
_GrSLPrecision, | 179 kVec4f_GrSLType, kDefault
_GrSLPrecision, |
| 177 "Positions", &positionsUn
iName); | 180 "Positions", &positionsUn
iName); |
| 178 const char* sizesUniName = nullptr; | 181 const char* sizesUniName = nullptr; |
| 179 fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 182 fSizesUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| 180 kVec4f_GrSLType, kDefault_GrS
LPrecision, | 183 kVec4f_GrSLType, kDefault_GrS
LPrecision, |
| 181 "Sizes", &sizesUniName); | 184 "Sizes", &sizesUniName); |
| 182 const char* radiiUniName = nullptr; | 185 const char* radiiUniName = nullptr; |
| 183 fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 186 if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimp
leCircular_Mode) { |
| 184 kVec4f_GrSLType, kDefault_GrS
LPrecision, | 187 fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| 185 "Radii", &radiiUniName); | 188 kVec4f_GrSLType, kDefault
_GrSLPrecision, |
| 189 "Radii", &radiiUniName); |
| 190 } |
| 186 const char* padRadUniName = nullptr; | 191 const char* padRadUniName = nullptr; |
| 187 fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 192 fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| 188 kVec2f_GrSLType, kDefault_Gr
SLPrecision, | 193 kVec2f_GrSLType, kDefault_Gr
SLPrecision, |
| 189 "PadRad", &padRadUniName); | 194 "PadRad", &padRadUniName); |
| 190 | 195 |
| 191 fragBuilder->codeAppend("float firstDist;"); | 196 fragBuilder->codeAppend("float firstDist;"); |
| 192 fragBuilder->codeAppend("{"); | 197 fragBuilder->codeAppend("{"); |
| 193 this->emitModeCode(fp.firstMode(), fragBuilder, | 198 this->emitModeCode(fp.firstMode(), fragBuilder, |
| 194 positionsUniName, sizesUniName, radiiUniName, "fi
rstDist", "xy"); | 199 positionsUniName, sizesUniName, radiiUniName, |
| 200 padRadUniName, "firstDist", "xy"); |
| 195 fragBuilder->codeAppend("}"); | 201 fragBuilder->codeAppend("}"); |
| 196 | 202 |
| 197 fragBuilder->codeAppend("float secondDist;"); | 203 fragBuilder->codeAppend("float secondDist;"); |
| 198 fragBuilder->codeAppend("{"); | 204 fragBuilder->codeAppend("{"); |
| 199 this->emitModeCode(fp.secondMode(), fragBuilder, | 205 this->emitModeCode(fp.secondMode(), fragBuilder, |
| 200 positionsUniName, sizesUniName, radiiUniName, "se
condDist", "zw"); | 206 positionsUniName, sizesUniName, radiiUniName, |
| 207 padRadUniName, "secondDist", "zw"); |
| 201 fragBuilder->codeAppend("}"); | 208 fragBuilder->codeAppend("}"); |
| 202 | 209 |
| 203 // Here use the sign of the distance to the two round rects to mask
off the different | 210 fragBuilder->codeAppendf("float dist = %s.y * firstDist * secondDist
;", |
| 204 // cases. | 211 padRadUniName); |
| 205 fragBuilder->codeAppend("float in1 = step(0.0f, firstDist);"); | |
| 206 fragBuilder->codeAppend("float in2 = step(0.0f, secondDist);"); | |
| 207 fragBuilder->codeAppend("float dist = " | |
| 208 "in1*in2 * min(firstDis
t, secondDist);" | |
| 209 "in1*(1.0-in2) * firstDist +" | |
| 210 "(1.0-in1)*in2 * secondDist;"
); | |
| 211 | 212 |
| 212 // Finally use the distance to apply the Gaussian edge | 213 // Finally use the distance to apply the Gaussian edge |
| 214 // TODO: we undo the multiply by the radius here - we should just sk
ip both |
| 213 fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%
s.y, 0.0, 1.0);", | 215 fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%
s.y, 0.0, 1.0);", |
| 214 padRadUniName, padRadUniName); | 216 padRadUniName, padRadUniName); |
| 215 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.01
8;"); | 217 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.01
8;"); |
| 216 fragBuilder->codeAppendf("%s = vec4(%s.rgb, factor);", | 218 fragBuilder->codeAppendf("%s = vec4(%s.rgb, factor);", |
| 217 args.fOutputColor, args.fInputColor); | 219 args.fOutputColor, args.fInputColor); |
| 218 } | 220 } |
| 219 | 221 |
| 220 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, | 222 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, |
| 221 GrProcessorKeyBuilder* b) { | 223 GrProcessorKeyBuilder* b) { |
| 222 const RRectsGaussianEdgeFP& fp = proc.cast<RRectsGaussianEdgeFP>(); | 224 const RRectsGaussianEdgeFP& fp = proc.cast<RRectsGaussianEdgeFP>(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 236 first.getBounds().centerY(), | 238 first.getBounds().centerY(), |
| 237 second.getBounds().centerX(), | 239 second.getBounds().centerX(), |
| 238 second.getBounds().centerY()); | 240 second.getBounds().centerY()); |
| 239 | 241 |
| 240 pdman.set4f(fSizesUni, | 242 pdman.set4f(fSizesUni, |
| 241 0.5f * first.rect().width(), | 243 0.5f * first.rect().width(), |
| 242 0.5f * first.rect().height(), | 244 0.5f * first.rect().height(), |
| 243 0.5f * second.rect().width(), | 245 0.5f * second.rect().width(), |
| 244 0.5f * second.rect().height()); | 246 0.5f * second.rect().height()); |
| 245 | 247 |
| 246 // This is a bit of overkill since fX should equal fY for both round
rects but it | 248 if (edgeFP.firstMode() == kSimpleCircular_Mode || |
| 247 // makes the shader code simpler. | 249 edgeFP.secondMode() == kSimpleCircular_Mode) { |
| 248 pdman.set4f(fRadiiUni, | 250 // This is a bit of overkill since fX should equal fY for both r
ound rects but it |
| 249 0.5f * first.getSimpleRadii().fX, | 251 // makes the shader code simpler. |
| 250 0.5f * first.getSimpleRadii().fY, | 252 pdman.set4f(fRadiiUni, |
| 251 0.5f * second.getSimpleRadii().fX, | 253 0.5f * first.getSimpleRadii().fX, |
| 252 0.5f * second.getSimpleRadii().fY); | 254 0.5f * first.getSimpleRadii().fY, |
| 255 0.5f * second.getSimpleRadii().fX, |
| 256 0.5f * second.getSimpleRadii().fY); |
| 257 } |
| 253 | 258 |
| 254 pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius()); | 259 pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius()); |
| 255 } | 260 } |
| 256 | 261 |
| 257 private: | 262 private: |
| 258 // The centers of the two round rects (x1, y1, x2, y2) | 263 // The centers of the two round rects (x1, y1, x2, y2) |
| 259 GrGLSLProgramDataManager::UniformHandle fPositionsUni; | 264 GrGLSLProgramDataManager::UniformHandle fPositionsUni; |
| 260 | 265 |
| 261 // The half widths and half heights of the two round rects (w1/2, h1/2,
w2/2, h2/2) | 266 // The half widths and half heights of the two round rects (w1/2, h1/2,
w2/2, h2/2) |
| 262 // For circles we still upload both width & height to simplify things | 267 // For circles we still upload both width & height to simplify things |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 return sk_make_sp<SkRRectsGaussianEdgeShaderImpl>(first, second, radius, pad
); | 431 return sk_make_sp<SkRRectsGaussianEdgeShaderImpl>(first, second, radius, pad
); |
| 427 } | 432 } |
| 428 | 433 |
| 429 /////////////////////////////////////////////////////////////////////////////// | 434 /////////////////////////////////////////////////////////////////////////////// |
| 430 | 435 |
| 431 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeShader) | 436 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkRRectsGaussianEdgeShader) |
| 432 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeShaderImpl) | 437 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRRectsGaussianEdgeShaderImpl) |
| 433 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 438 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
| 434 | 439 |
| 435 /////////////////////////////////////////////////////////////////////////////// | 440 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |