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/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));
}
}