Use texture for shadow falloff
Bug: b/142333639
Change-Id: I5c5bf4da0e2bb5f1b4233681dee305cf381c3e2a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/250096
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/effects/GrShadowGeoProc.cpp b/src/gpu/effects/GrShadowGeoProc.cpp
index 5af096c..0b8ebdc 100644
--- a/src/gpu/effects/GrShadowGeoProc.cpp
+++ b/src/gpu/effects/GrShadowGeoProc.cpp
@@ -43,12 +43,11 @@
args.fFPCoordTransformHandler);
fragBuilder->codeAppend("half d = length(shadowParams.xy);");
- fragBuilder->codeAppend("half distance = shadowParams.z * (1.0 - d);");
-
- fragBuilder->codeAppend("half factor = 1.0 - clamp(distance, 0.0, 1.0);");
- fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
- fragBuilder->codeAppendf("%s = half4(factor);",
- args.fOutputCoverage);
+ fragBuilder->codeAppend("float2 uv = float2(shadowParams.z * (1.0 - d), 0.5);");
+ fragBuilder->codeAppend("half factor = ");
+ fragBuilder->appendTextureLookup(args.fTexSamplers[0], "uv", kFloat2_GrSLType);
+ fragBuilder->codeAppend(".a;");
+ fragBuilder->codeAppendf("%s = half4(factor);", args.fOutputCoverage);
}
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
@@ -62,11 +61,17 @@
///////////////////////////////////////////////////////////////////////////////
-GrRRectShadowGeoProc::GrRRectShadowGeoProc() : INHERITED(kGrRRectShadowGeoProc_ClassID) {
+GrRRectShadowGeoProc::GrRRectShadowGeoProc(const GrTextureProxy* lut)
+ : INHERITED(kGrRRectShadowGeoProc_ClassID) {
fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
fInShadowParams = {"inShadowParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType};
this->setVertexAttributes(&fInPosition, 3);
+
+ SkASSERT(lut);
+ fLUTTextureSampler.reset(GrSamplerState::ClampBilerp(), lut->backendFormat(),
+ lut->textureSwizzle());
+ this->setTextureSamplerCnt(1);
}
GrGLSLPrimitiveProcessor* GrRRectShadowGeoProc::createGLSLInstance(const GrShaderCaps&) const {
@@ -79,6 +84,6 @@
#if GR_TEST_UTILS
sk_sp<GrGeometryProcessor> GrRRectShadowGeoProc::TestCreate(GrProcessorTestData* d) {
- return GrRRectShadowGeoProc::Make();
+ return GrRRectShadowGeoProc::Make(d->textureProxy(GrProcessorUnitTest::kAlphaTextureIdx).get());
}
#endif
diff --git a/src/gpu/effects/GrShadowGeoProc.h b/src/gpu/effects/GrShadowGeoProc.h
index b821a6a..1fb04a4 100644
--- a/src/gpu/effects/GrShadowGeoProc.h
+++ b/src/gpu/effects/GrShadowGeoProc.h
@@ -19,8 +19,8 @@
*/
class GrRRectShadowGeoProc : public GrGeometryProcessor {
public:
- static sk_sp<GrGeometryProcessor> Make() {
- return sk_sp<GrGeometryProcessor>(new GrRRectShadowGeoProc());
+ static sk_sp<GrGeometryProcessor> Make(const GrTextureProxy* lut) {
+ return sk_sp<GrGeometryProcessor>(new GrRRectShadowGeoProc(lut));
}
const char* name() const override { return "RRectShadow"; }
@@ -35,9 +35,12 @@
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
private:
- GrRRectShadowGeoProc();
+ GrRRectShadowGeoProc(const GrTextureProxy* lut);
+
+ const TextureSampler& onTextureSampler(int i) const override { return fLUTTextureSampler; }
GrColor fColor;
+ TextureSampler fLUTTextureSampler;
Attribute fInPosition;
Attribute fInColor;
diff --git a/src/gpu/ops/GrShadowRRectOp.cpp b/src/gpu/ops/GrShadowRRectOp.cpp
index 546933b..9ae467d 100644
--- a/src/gpu/ops/GrShadowRRectOp.cpp
+++ b/src/gpu/ops/GrShadowRRectOp.cpp
@@ -12,6 +12,7 @@
#include "src/gpu/GrDrawOpTest.h"
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/effects/GrShadowGeoProc.h"
@@ -189,8 +190,10 @@
// An insetWidth > 1/2 rect width or height indicates a simple fill.
ShadowCircularRRectOp(GrColor color, const SkRect& devRect,
- float devRadius, bool isCircle, float blurRadius, float insetWidth)
- : INHERITED(ClassID()) {
+ float devRadius, bool isCircle, float blurRadius, float insetWidth,
+ sk_sp<GrTextureProxy> falloffProxy)
+ : INHERITED(ClassID())
+ , fFalloffProxy(falloffProxy) {
SkRect bounds = devRect;
SkASSERT(insetWidth > 0);
SkScalar innerRadius = 0.0f;
@@ -536,7 +539,7 @@
void onPrepareDraws(Target* target) override {
// Setup geometry processor
- sk_sp<GrGeometryProcessor> gp = GrRRectShadowGeoProc::Make();
+ sk_sp<GrGeometryProcessor> gp = GrRRectShadowGeoProc::Make(fFalloffProxy.get());
int instanceCount = fGeoData.count();
SkASSERT(sizeof(CircleVertex) == gp->vertexStride());
@@ -587,11 +590,14 @@
}
}
+ auto fixedDynamicState = target->makeFixedDynamicState(1);
+ fixedDynamicState->fPrimitiveProcessorTextures[0] = fFalloffProxy.get();
+
GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
mesh->setIndexed(std::move(indexBuffer), fIndexCount, firstIndex, 0, fVertCount - 1,
GrPrimitiveRestart::kNo);
mesh->setVertexData(std::move(vertexBuffer), firstVertex);
- target->recordDraw(std::move(gp), mesh);
+ target->recordDraw(std::move(gp), mesh, 1, fixedDynamicState, nullptr);
}
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
@@ -607,9 +613,14 @@
return CombineResult::kMerged;
}
+ void visitProxies(const VisitProxyFunc& func) const override {
+ func(fFalloffProxy.get(), GrMipMapped(false));
+ }
+
SkSTArray<1, Geometry, true> fGeoData;
int fVertCount;
int fIndexCount;
+ sk_sp<GrTextureProxy> fFalloffProxy;
typedef GrMeshDrawOp INHERITED;
};
@@ -619,6 +630,49 @@
///////////////////////////////////////////////////////////////////////////////
namespace GrShadowRRectOp {
+
+static sk_sp<GrTextureProxy> create_falloff_texture(GrProxyProvider* proxyProvider) {
+ static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+ GrUniqueKey key;
+ GrUniqueKey::Builder builder(&key, kDomain, 0, "Shadow Gaussian Falloff");
+ builder.finish();
+
+ sk_sp<GrTextureProxy> falloffTexture = proxyProvider->findOrCreateProxyByUniqueKey(
+ key, GrColorType::kAlpha_8, kTopLeft_GrSurfaceOrigin);
+ if (!falloffTexture) {
+ static const int kWidth = 128;
+ static const size_t kRowBytes = kWidth*GrColorTypeBytesPerPixel(GrColorType::kAlpha_8);
+ SkImageInfo ii = SkImageInfo::MakeA8(kWidth, 1);
+
+ sk_sp<SkData> data = SkData::MakeUninitialized(kRowBytes);
+ if (!data) {
+ return nullptr;
+ }
+ unsigned char* values = (unsigned char*) data->writable_data();
+ for (int i = 0; i < 128; ++i) {
+ SkScalar d = SK_Scalar1 - i/SkIntToScalar(127);
+ values[i] = SkScalarRoundToInt((SkScalarExp(-4*d*d) - 0.018f)*255);
+ }
+
+ sk_sp<SkImage> img = SkImage::MakeRasterData(ii, std::move(data), kRowBytes);
+ if (!img) {
+ return nullptr;
+ }
+
+ falloffTexture = proxyProvider->createTextureProxy(std::move(img), 1, SkBudgeted::kYes,
+ SkBackingFit::kExact);
+ if (!falloffTexture) {
+ return nullptr;
+ }
+
+ SkASSERT(falloffTexture->origin() == kTopLeft_GrSurfaceOrigin);
+ proxyProvider->assignUniqueKeyToProxy(key, falloffTexture.get());
+ }
+
+ return falloffTexture;
+}
+
+
std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
GrColor color,
const SkMatrix& viewMatrix,
@@ -628,6 +682,11 @@
// Shadow rrect ops only handle simple circular rrects.
SkASSERT(viewMatrix.isSimilarity() && SkRRectPriv::EqualRadii(rrect));
+ sk_sp<GrTextureProxy> falloffTexture = create_falloff_texture(context->priv().proxyProvider());
+ if (!falloffTexture) {
+ return nullptr;
+ }
+
// Do any matrix crunching before we reset the draw state for device coords.
const SkRect& rrectBounds = rrect.getBounds();
SkRect bounds;
@@ -649,7 +708,8 @@
scaledRadius,
rrect.isOval(),
blurWidth,
- scaledInsetWidth);
+ scaledInsetWidth,
+ std::move(falloffTexture));
}
}