This CL's base is the CL that sets up the distance vector field req. exposure: https://codereview.chromium.org/2114993002/
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2151653002 Review-Url: https://codereview.chromium.org/2151653002
This commit is contained in:
parent
b8d1aac87a
commit
1b9e2fb494
@ -19,12 +19,20 @@
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "SkGr.h"
|
||||
|
||||
/** \class NormalBevelFP
|
||||
*
|
||||
* Fragment processor for the SkNormalBevelSource.
|
||||
*
|
||||
* @param bevelType type of the bevel
|
||||
* @param bevelWidth width of the bevel in device space
|
||||
* @param bevelHeight height of the bevel in device space
|
||||
*/
|
||||
class NormalBevelFP : public GrFragmentProcessor {
|
||||
public:
|
||||
NormalBevelFP(SkNormalSource::BevelType type, SkScalar width, SkScalar height)
|
||||
: fType(type)
|
||||
, fWidth(width)
|
||||
, fHeight(height) {
|
||||
NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight)
|
||||
: fBevelType(bevelType)
|
||||
, fBevelWidth(bevelWidth)
|
||||
, fBevelHeight(bevelHeight) {
|
||||
this->initClassID<NormalBevelFP>();
|
||||
|
||||
fUsesDistanceVectorField = true;
|
||||
@ -39,23 +47,68 @@ public:
|
||||
|
||||
void onEmitCode(EmitArgs& args) override {
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
const NormalBevelFP& fp = args.fFp.cast<NormalBevelFP>();
|
||||
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
|
||||
|
||||
const char* widthUniName = nullptr;
|
||||
fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision, "Width", &widthUniName);
|
||||
// Determining necessary uniforms and initializing them
|
||||
bool needWidth = true;
|
||||
bool needHeight = (fp.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
|
||||
fp.fBevelType == SkNormalSource::BevelType::kRoundedIn);
|
||||
bool needNormalized = (fp.fBevelType == SkNormalSource::BevelType::kLinear);
|
||||
|
||||
const char *widthUniName = nullptr;
|
||||
if (needWidth) {
|
||||
fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision, "Width",
|
||||
&widthUniName);
|
||||
}
|
||||
|
||||
const char* heightUniName = nullptr;
|
||||
fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision, "Height", &heightUniName);
|
||||
if (needHeight) {
|
||||
fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision, "Height",
|
||||
&heightUniName);
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 1.0, 0.0);", args.fOutputColor);
|
||||
const char* normalizedWidthUniName = nullptr;
|
||||
const char* normalizedHeightUniName = nullptr;
|
||||
if (needNormalized) {
|
||||
fNormalizedWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision,
|
||||
"NormalizedWidth",
|
||||
&normalizedWidthUniName);
|
||||
fNormalizedHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kFloat_GrSLType,
|
||||
kDefault_GrSLPrecision,
|
||||
"NormalizedHeight",
|
||||
&normalizedHeightUniName);
|
||||
}
|
||||
|
||||
// Here we are splitting the distance vector into length and normalized direction
|
||||
// TODO: Output these values from the geometry processor frag code instead of the vector
|
||||
fragBuilder->codeAppendf("float dv_length = length(%s);",
|
||||
fragBuilder->distanceVectorName());
|
||||
fragBuilder->codeAppendf("vec2 dv_norm = normalize(%s);",
|
||||
fragBuilder->distanceVectorName());
|
||||
|
||||
// Asserting presence of necessary uniforms
|
||||
SkASSERT(widthUniName);
|
||||
|
||||
fragBuilder->codeAppend( "vec3 normal;");
|
||||
fragBuilder->codeAppendf("if (dv_length >= %s) {", widthUniName);
|
||||
fragBuilder->codeAppend( " normal = vec3(0.0, 0.0, 1.0);");
|
||||
fragBuilder->codeAppend( "} else {");
|
||||
this->emitMath(fragBuilder, fp.fBevelType, widthUniName, heightUniName,
|
||||
normalizedWidthUniName, normalizedHeightUniName);
|
||||
fragBuilder->codeAppend( "}");
|
||||
fragBuilder->codeAppendf("%s = vec4(normal, 0.0);", args.fOutputColor);
|
||||
}
|
||||
|
||||
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const NormalBevelFP& fp = proc.cast<NormalBevelFP>();
|
||||
b->add32(static_cast<int>(fp.fType));
|
||||
b->add32(static_cast<int>(fp.fBevelType));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -63,13 +116,92 @@ public:
|
||||
const GrProcessor& proc) override {
|
||||
const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
|
||||
|
||||
if (fPrevWidth != normalBevelFP.fWidth) {
|
||||
pdman.set1f(fWidthUni, normalBevelFP.fWidth);
|
||||
fPrevWidth = normalBevelFP.fWidth;
|
||||
// Updating uniform if bevel type requires it and data has changed
|
||||
|
||||
bool needWidth = true;
|
||||
bool needHeight = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
|
||||
normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedIn);
|
||||
bool needNormalized = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kLinear);
|
||||
|
||||
bool dirtyWidth = (fPrevWidth != normalBevelFP.fBevelWidth);
|
||||
bool dirtyHeight = (fPrevHeight != normalBevelFP.fBevelHeight);
|
||||
bool dirtyNormalized = (dirtyHeight || dirtyWidth);
|
||||
|
||||
|
||||
if (needWidth && dirtyWidth) {
|
||||
pdman.set1f(fWidthUni, normalBevelFP.fBevelWidth);
|
||||
fPrevWidth = normalBevelFP.fBevelWidth;
|
||||
}
|
||||
if (fPrevHeight != normalBevelFP.fHeight) {
|
||||
pdman.set1f(fHeightUni, normalBevelFP.fHeight);
|
||||
fPrevHeight = normalBevelFP.fHeight;
|
||||
if (needHeight && dirtyHeight) {
|
||||
pdman.set1f(fHeightUni, normalBevelFP.fBevelHeight);
|
||||
fPrevHeight = normalBevelFP.fBevelHeight;
|
||||
}
|
||||
if (needNormalized && dirtyNormalized) {
|
||||
SkScalar height = normalBevelFP.fBevelHeight;
|
||||
SkScalar width = normalBevelFP.fBevelWidth;
|
||||
|
||||
SkScalar length = SkScalarSqrt(SkScalarSquare(height) + SkScalarSquare(width));
|
||||
pdman.set1f(fNormalizedHeightUni, height/length);
|
||||
pdman.set1f(fNormalizedWidthUni, width/length);
|
||||
}
|
||||
}
|
||||
|
||||
// This method emits the code that calculates the normal orthgonal to the simulated beveled
|
||||
// surface. In the comments inside the function, the math involved is described. For this
|
||||
// purpose, the d-axis is defined to be the axis co-linear to the distance vector, where the
|
||||
// origin is the end of the bevel inside the shape.
|
||||
void emitMath(GrGLSLFPFragmentBuilder* fb, SkNormalSource::BevelType type,
|
||||
const char* width, const char* height, const char* normalizedWidth,
|
||||
const char* normalizedHeight) {
|
||||
switch (type) {
|
||||
case SkNormalSource::BevelType::kLinear:
|
||||
// Asserting presence of necessary uniforms
|
||||
SkASSERT(normalizedHeight);
|
||||
SkASSERT(normalizedWidth);
|
||||
|
||||
// Because the slope of the bevel is -height/width, the vector
|
||||
// normalized(vec2(height, width)) is the d- and z-components of the normal
|
||||
// vector that is orthogonal to the linear bevel. Multiplying the d-component
|
||||
// to the normalized distance vector splits it into x- and y-components.
|
||||
fb->codeAppendf("normal = vec3(%s * dv_norm, %s);",
|
||||
normalizedHeight, normalizedWidth);
|
||||
break;
|
||||
case SkNormalSource::BevelType::kRoundedOut:
|
||||
// Fall through
|
||||
case SkNormalSource::BevelType::kRoundedIn:
|
||||
// Asserting presence of necessary uniforms
|
||||
SkASSERT(height);
|
||||
SkASSERT(width);
|
||||
|
||||
// Setting the current position in the d-axis to the distance from the end of
|
||||
// the bevel as opposed to the beginning if the bevel is rounded in, essentially
|
||||
// flipping the bevel calculations.
|
||||
if ( type == SkNormalSource::BevelType::kRoundedIn ) {
|
||||
fb->codeAppendf("float currentPos_d = %s - dv_length;", width);
|
||||
} else if (type == SkNormalSource::BevelType::kRoundedOut) {
|
||||
fb->codeAppendf("float currentPos_d = dv_length;");
|
||||
}
|
||||
|
||||
fb->codeAppendf("float rootDOverW = sqrt(currentPos_d/%s);", width);
|
||||
|
||||
// Calculating the d- and z-components of the normal, where 'd' is the axis
|
||||
// co-linear to the distance vector. Equation was derived from the formula for
|
||||
// a bezier curve by solving the parametric equation for d(t) and z(t), then
|
||||
// with those, calculate d'(t), z'(t) and t(d), and from these, d'(d) and z'(d).
|
||||
// z'(d)/d'(d) results in the slope of the bevel at d, so we construct an
|
||||
// orthogonal vector of slope -d'(d)/z'(d) and length 1.
|
||||
fb->codeAppendf("vec2 unnormalizedNormal_dz = vec2(%s*(1.0-rootDOverW), "
|
||||
"%s*rootDOverW);",
|
||||
height, width);
|
||||
fb->codeAppendf("vec2 normal_dz = normalize(unnormalizedNormal_dz);");
|
||||
|
||||
// Multiplying the d-component to the normalized distance vector splits it into
|
||||
// x- and y-components.
|
||||
fb->codeAppendf("normal = vec3(normal_dz.x*dv_norm, normal_dz.y);");
|
||||
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("Invalid bevel type passed to emitMath");
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,6 +211,11 @@ public:
|
||||
|
||||
SkScalar fPrevHeight;
|
||||
GrGLSLProgramDataManager::UniformHandle fHeightUni;
|
||||
|
||||
// width / length(<width,height>)
|
||||
GrGLSLProgramDataManager::UniformHandle fNormalizedWidthUni;
|
||||
// height / length(<width,height>)
|
||||
GrGLSLProgramDataManager::UniformHandle fNormalizedHeightUni;
|
||||
};
|
||||
|
||||
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
|
||||
@ -96,20 +233,23 @@ private:
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
||||
const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
|
||||
return fType == normalBevelFP.fType &&
|
||||
fWidth == normalBevelFP.fWidth &&
|
||||
fHeight == normalBevelFP.fHeight;
|
||||
return fBevelType == normalBevelFP.fBevelType &&
|
||||
fBevelWidth == normalBevelFP.fBevelWidth &&
|
||||
fBevelHeight == normalBevelFP.fBevelHeight;
|
||||
}
|
||||
|
||||
SkNormalSource::BevelType fType;
|
||||
SkScalar fWidth;
|
||||
SkScalar fHeight;
|
||||
SkNormalSource::BevelType fBevelType;
|
||||
SkScalar fBevelWidth;
|
||||
SkScalar fBevelHeight;
|
||||
};
|
||||
|
||||
sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
|
||||
const SkShader::AsFPArgs&) const {
|
||||
const SkShader::AsFPArgs& args) const {
|
||||
|
||||
return sk_make_sp<NormalBevelFP>(fType, fWidth, fHeight);
|
||||
SkScalar maxScale = args.fViewMatrix->getMaxScale();
|
||||
|
||||
// Providing device-space width and height
|
||||
return sk_make_sp<NormalBevelFP>(fType, maxScale * fWidth, maxScale * fHeight);
|
||||
}
|
||||
|
||||
#endif // SK_SUPPORT_GPU
|
||||
|
Loading…
Reference in New Issue
Block a user