GrCircleBlurFragmentProcessor uses GrTextureEffect for profile texture
Bug: skia:10139 Change-Id: If539b6ad3a55c157fa5761abeaf13b318047839e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/296731 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
588b32c04e
commit
77628ce0e4
@ -7,9 +7,13 @@
|
||||
|
||||
in fragmentProcessor? inputFP;
|
||||
in half4 circleRect;
|
||||
in half textureRadius;
|
||||
in half solidRadius;
|
||||
in uniform sampler2D blurProfileSampler;
|
||||
in half textureRadius;
|
||||
in fragmentProcessor blurProfile;
|
||||
|
||||
@header {
|
||||
#include "src/gpu/effects/GrTextureEffect.h"
|
||||
};
|
||||
|
||||
// The data is formatted as:
|
||||
// x, y - the center of the circle
|
||||
@ -191,13 +195,14 @@ uniform half4 circleData;
|
||||
profile[profileWidth - 1] = 0;
|
||||
}
|
||||
|
||||
static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context,
|
||||
static std::unique_ptr<GrFragmentProcessor> create_profile_effect(GrRecordingContext* context,
|
||||
const SkRect& circle,
|
||||
float sigma,
|
||||
float* solidRadius, float* textureRadius) {
|
||||
float* solidRadius,
|
||||
float* textureRadius) {
|
||||
float circleR = circle.width() / 2.0f;
|
||||
if (circleR < SK_ScalarNearlyZero) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
// Profile textures are cached by the ratio of sigma to circle radius and by the size of the
|
||||
// profile texture (binned by powers of 2).
|
||||
@ -227,6 +232,12 @@ uniform half4 circleData;
|
||||
*textureRadius = circleR + 3 * sigma;
|
||||
}
|
||||
|
||||
static constexpr int kProfileTextureWidth = 512;
|
||||
// This would be kProfileTextureWidth/textureRadius if it weren't for the fact that we do
|
||||
// the calculation of the profile coord in a coord space that has already been scaled by
|
||||
// 1 / textureRadius. This is done to avoid overflow in length().
|
||||
SkMatrix texM = SkMatrix::Scale(kProfileTextureWidth, 1.f);
|
||||
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey key;
|
||||
GrUniqueKey::Builder builder(&key, kDomain, 1, "1-D Circular Blur");
|
||||
@ -237,14 +248,14 @@ uniform half4 circleData;
|
||||
if (sk_sp<GrTextureProxy> blurProfile = proxyProvider->findOrCreateProxyByUniqueKey(key)) {
|
||||
GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(blurProfile->backendFormat(),
|
||||
GrColorType::kAlpha_8);
|
||||
return {std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle};
|
||||
GrSurfaceProxyView profileView{std::move(blurProfile), kTopLeft_GrSurfaceOrigin,
|
||||
swizzle};
|
||||
return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM);
|
||||
}
|
||||
|
||||
static constexpr int kProfileTextureWidth = 512;
|
||||
|
||||
SkBitmap bm;
|
||||
if (!bm.tryAllocPixels(SkImageInfo::MakeA8(kProfileTextureWidth, 1))) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (useHalfPlaneApprox) {
|
||||
@ -259,12 +270,12 @@ uniform half4 circleData;
|
||||
bm.setImmutable();
|
||||
|
||||
GrBitmapTextureMaker maker(context, bm, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
|
||||
auto blurView = maker.view(GrMipMapped::kNo);
|
||||
if (!blurView) {
|
||||
return {};
|
||||
auto profileView = maker.view(GrMipMapped::kNo);
|
||||
if (!profileView) {
|
||||
return nullptr;
|
||||
}
|
||||
proxyProvider->assignUniqueKeyToProxy(key, blurView.asTextureProxy());
|
||||
return blurView;
|
||||
proxyProvider->assignUniqueKeyToProxy(key, profileView.asTextureProxy());
|
||||
return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make(
|
||||
@ -272,28 +283,28 @@ uniform half4 circleData;
|
||||
const SkRect& circle, float sigma) {
|
||||
float solidRadius;
|
||||
float textureRadius;
|
||||
GrSurfaceProxyView profile = create_profile_texture(context, circle, sigma,
|
||||
std::unique_ptr<GrFragmentProcessor> profile = create_profile_effect(context, circle, sigma,
|
||||
&solidRadius, &textureRadius);
|
||||
if (!profile) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(
|
||||
std::move(inputFP), circle, textureRadius, solidRadius, std::move(profile)));
|
||||
std::move(inputFP), circle, solidRadius, textureRadius, std::move(profile)));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// We just want to compute "(length(vec) - circleData.z + 0.5) * circleData.w" but need to
|
||||
// rearrange for precision.
|
||||
// rearrange to avoid passing large values to length() that would overflow.
|
||||
half2 vec = half2((sk_FragCoord.xy - circleData.xy) * circleData.w);
|
||||
half dist = length(vec) + (0.5 - circleData.z) * circleData.w;
|
||||
half4 inputColor = sample(inputFP, sk_InColor);
|
||||
sk_OutColor = inputColor * sample(blurProfileSampler, half2(dist, 0.5)).a;
|
||||
sk_OutColor = inputColor * sample(blurProfile, half2(dist, 0.5)).a;
|
||||
}
|
||||
|
||||
@test(testData) {
|
||||
SkScalar wh = testData->fRandom->nextRangeScalar(100.f, 1000.f);
|
||||
SkScalar sigma = testData->fRandom->nextRangeF(1.f,10.f);
|
||||
SkScalar sigma = testData->fRandom->nextRangeF(1.f, 10.f);
|
||||
SkRect circle = SkRect::MakeWH(wh, wh);
|
||||
return GrCircleBlurFragmentProcessor::Make(/*inputFP=*/nullptr, testData->context(),
|
||||
circle, sigma);
|
||||
|
@ -177,14 +177,14 @@ static void create_half_plane_profile(uint8_t* profile, int profileWidth) {
|
||||
profile[profileWidth - 1] = 0;
|
||||
}
|
||||
|
||||
static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context,
|
||||
const SkRect& circle,
|
||||
float sigma,
|
||||
float* solidRadius,
|
||||
float* textureRadius) {
|
||||
static std::unique_ptr<GrFragmentProcessor> create_profile_effect(GrRecordingContext* context,
|
||||
const SkRect& circle,
|
||||
float sigma,
|
||||
float* solidRadius,
|
||||
float* textureRadius) {
|
||||
float circleR = circle.width() / 2.0f;
|
||||
if (circleR < SK_ScalarNearlyZero) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
// Profile textures are cached by the ratio of sigma to circle radius and by the size of the
|
||||
// profile texture (binned by powers of 2).
|
||||
@ -214,6 +214,12 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context,
|
||||
*textureRadius = circleR + 3 * sigma;
|
||||
}
|
||||
|
||||
static constexpr int kProfileTextureWidth = 512;
|
||||
// This would be kProfileTextureWidth/textureRadius if it weren't for the fact that we do
|
||||
// the calculation of the profile coord in a coord space that has already been scaled by
|
||||
// 1 / textureRadius. This is done to avoid overflow in length().
|
||||
SkMatrix texM = SkMatrix::Scale(kProfileTextureWidth, 1.f);
|
||||
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey key;
|
||||
GrUniqueKey::Builder builder(&key, kDomain, 1, "1-D Circular Blur");
|
||||
@ -224,14 +230,13 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context,
|
||||
if (sk_sp<GrTextureProxy> blurProfile = proxyProvider->findOrCreateProxyByUniqueKey(key)) {
|
||||
GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(blurProfile->backendFormat(),
|
||||
GrColorType::kAlpha_8);
|
||||
return {std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle};
|
||||
GrSurfaceProxyView profileView{std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle};
|
||||
return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM);
|
||||
}
|
||||
|
||||
static constexpr int kProfileTextureWidth = 512;
|
||||
|
||||
SkBitmap bm;
|
||||
if (!bm.tryAllocPixels(SkImageInfo::MakeA8(kProfileTextureWidth, 1))) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (useHalfPlaneApprox) {
|
||||
@ -246,12 +251,12 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context,
|
||||
bm.setImmutable();
|
||||
|
||||
GrBitmapTextureMaker maker(context, bm, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
|
||||
auto blurView = maker.view(GrMipMapped::kNo);
|
||||
if (!blurView) {
|
||||
return {};
|
||||
auto profileView = maker.view(GrMipMapped::kNo);
|
||||
if (!profileView) {
|
||||
return nullptr;
|
||||
}
|
||||
proxyProvider->assignUniqueKeyToProxy(key, blurView.asTextureProxy());
|
||||
return blurView;
|
||||
proxyProvider->assignUniqueKeyToProxy(key, profileView.asTextureProxy());
|
||||
return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make(
|
||||
@ -261,13 +266,13 @@ std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make(
|
||||
float sigma) {
|
||||
float solidRadius;
|
||||
float textureRadius;
|
||||
GrSurfaceProxyView profile =
|
||||
create_profile_texture(context, circle, sigma, &solidRadius, &textureRadius);
|
||||
std::unique_ptr<GrFragmentProcessor> profile =
|
||||
create_profile_effect(context, circle, sigma, &solidRadius, &textureRadius);
|
||||
if (!profile) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(
|
||||
std::move(inputFP), circle, textureRadius, solidRadius, std::move(profile)));
|
||||
std::move(inputFP), circle, solidRadius, textureRadius, std::move(profile)));
|
||||
}
|
||||
#include "src/gpu/GrTexture.h"
|
||||
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
|
||||
@ -285,35 +290,32 @@ public:
|
||||
(void)_outer;
|
||||
auto circleRect = _outer.circleRect;
|
||||
(void)circleRect;
|
||||
auto textureRadius = _outer.textureRadius;
|
||||
(void)textureRadius;
|
||||
auto solidRadius = _outer.solidRadius;
|
||||
(void)solidRadius;
|
||||
auto textureRadius = _outer.textureRadius;
|
||||
(void)textureRadius;
|
||||
circleDataVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
|
||||
kHalf4_GrSLType, "circleData");
|
||||
fragBuilder->codeAppendf(
|
||||
"half2 vec = half2((sk_FragCoord.xy - float2(%s.xy)) * float(%s.w));\nhalf dist = "
|
||||
"length(vec) + (0.5 - %s.z) * %s.w;",
|
||||
";\nhalf2 vec = half2((sk_FragCoord.xy - float2(%s.xy)) * float(%s.w));\nhalf dist "
|
||||
"= length(vec) + (0.5 - %s.z) * %s.w;",
|
||||
args.fUniformHandler->getUniformCStr(circleDataVar),
|
||||
args.fUniformHandler->getUniformCStr(circleDataVar),
|
||||
args.fUniformHandler->getUniformCStr(circleDataVar),
|
||||
args.fUniformHandler->getUniformCStr(circleDataVar));
|
||||
SkString _input13170 = SkStringPrintf("%s", args.fInputColor);
|
||||
SkString _sample13170;
|
||||
SkString _input13945 = SkStringPrintf("%s", args.fInputColor);
|
||||
SkString _sample13945;
|
||||
if (_outer.inputFP_index >= 0) {
|
||||
_sample13170 = this->invokeChild(_outer.inputFP_index, _input13170.c_str(), args);
|
||||
_sample13945 = this->invokeChild(_outer.inputFP_index, _input13945.c_str(), args);
|
||||
} else {
|
||||
_sample13170 = _input13170;
|
||||
_sample13945 = _input13945;
|
||||
}
|
||||
fragBuilder->codeAppendf(
|
||||
"\nhalf4 inputColor = %s;\n%s = inputColor * sample(%s, float2(half2(dist, "
|
||||
"0.5))).%s.w;\n",
|
||||
_sample13170.c_str(), args.fOutputColor,
|
||||
fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]),
|
||||
fragBuilder->getProgramBuilder()
|
||||
->samplerSwizzle(args.fTexSamplers[0])
|
||||
.asString()
|
||||
.c_str());
|
||||
fragBuilder->codeAppendf("\nhalf4 inputColor = %s;", _sample13945.c_str());
|
||||
SkString _sample14005;
|
||||
SkString _coords14005("float2(half2(dist, 0.5))");
|
||||
_sample14005 = this->invokeChild(_outer.blurProfile_index, args, _coords14005.c_str());
|
||||
fragBuilder->codeAppendf("\n%s = inputColor * %s.w;\n", args.fOutputColor,
|
||||
_sample14005.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -322,13 +324,10 @@ private:
|
||||
const GrCircleBlurFragmentProcessor& _outer = _proc.cast<GrCircleBlurFragmentProcessor>();
|
||||
auto circleRect = _outer.circleRect;
|
||||
(void)circleRect;
|
||||
auto textureRadius = _outer.textureRadius;
|
||||
(void)textureRadius;
|
||||
auto solidRadius = _outer.solidRadius;
|
||||
(void)solidRadius;
|
||||
const GrSurfaceProxyView& blurProfileSamplerView = _outer.textureSampler(0).view();
|
||||
GrTexture& blurProfileSampler = *blurProfileSamplerView.proxy()->peekTexture();
|
||||
(void)blurProfileSampler;
|
||||
auto textureRadius = _outer.textureRadius;
|
||||
(void)textureRadius;
|
||||
UniformHandle& circleData = circleDataVar;
|
||||
(void)circleData;
|
||||
|
||||
@ -346,30 +345,27 @@ bool GrCircleBlurFragmentProcessor::onIsEqual(const GrFragmentProcessor& other)
|
||||
const GrCircleBlurFragmentProcessor& that = other.cast<GrCircleBlurFragmentProcessor>();
|
||||
(void)that;
|
||||
if (circleRect != that.circleRect) return false;
|
||||
if (textureRadius != that.textureRadius) return false;
|
||||
if (solidRadius != that.solidRadius) return false;
|
||||
if (blurProfileSampler != that.blurProfileSampler) return false;
|
||||
if (textureRadius != that.textureRadius) return false;
|
||||
return true;
|
||||
}
|
||||
GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(
|
||||
const GrCircleBlurFragmentProcessor& src)
|
||||
: INHERITED(kGrCircleBlurFragmentProcessor_ClassID, src.optimizationFlags())
|
||||
, circleRect(src.circleRect)
|
||||
, textureRadius(src.textureRadius)
|
||||
, solidRadius(src.solidRadius)
|
||||
, blurProfileSampler(src.blurProfileSampler) {
|
||||
, textureRadius(src.textureRadius) {
|
||||
if (src.inputFP_index >= 0) {
|
||||
inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index));
|
||||
}
|
||||
this->setTextureSamplerCnt(1);
|
||||
{
|
||||
blurProfile_index =
|
||||
this->cloneAndRegisterChildProcessor(src.childProcessor(src.blurProfile_index));
|
||||
}
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::clone() const {
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(*this));
|
||||
}
|
||||
const GrFragmentProcessor::TextureSampler& GrCircleBlurFragmentProcessor::onTextureSampler(
|
||||
int index) const {
|
||||
return IthTextureSampler(index, blurProfileSampler);
|
||||
}
|
||||
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor);
|
||||
#if GR_TEST_UTILS
|
||||
std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "include/core/SkM44.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
|
||||
#include "src/gpu/effects/GrTextureEffect.h"
|
||||
|
||||
#include "src/gpu/GrCoordTransform.h"
|
||||
#include "src/gpu/GrFragmentProcessor.h"
|
||||
|
||||
@ -28,33 +30,33 @@ public:
|
||||
const char* name() const override { return "CircleBlurFragmentProcessor"; }
|
||||
int inputFP_index = -1;
|
||||
SkRect circleRect;
|
||||
float textureRadius;
|
||||
float solidRadius;
|
||||
TextureSampler blurProfileSampler;
|
||||
float textureRadius;
|
||||
int blurProfile_index = -1;
|
||||
|
||||
private:
|
||||
GrCircleBlurFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
|
||||
SkRect circleRect,
|
||||
float textureRadius,
|
||||
float solidRadius,
|
||||
GrSurfaceProxyView blurProfileSampler)
|
||||
float textureRadius,
|
||||
std::unique_ptr<GrFragmentProcessor> blurProfile)
|
||||
: INHERITED(kGrCircleBlurFragmentProcessor_ClassID,
|
||||
(OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get())
|
||||
: kAll_OptimizationFlags) &
|
||||
kCompatibleWithCoverageAsAlpha_OptimizationFlag)
|
||||
, circleRect(circleRect)
|
||||
, textureRadius(textureRadius)
|
||||
, solidRadius(solidRadius)
|
||||
, blurProfileSampler(std::move(blurProfileSampler)) {
|
||||
, textureRadius(textureRadius) {
|
||||
if (inputFP) {
|
||||
inputFP_index = this->registerChildProcessor(std::move(inputFP));
|
||||
}
|
||||
this->setTextureSamplerCnt(1);
|
||||
SkASSERT(blurProfile);
|
||||
blurProfile->setSampledWithExplicitCoords();
|
||||
blurProfile_index = this->registerChildProcessor(std::move(blurProfile));
|
||||
}
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
|
||||
bool onIsEqual(const GrFragmentProcessor&) const override;
|
||||
const TextureSampler& onTextureSampler(int) const override;
|
||||
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user