GrRRectBlurEffect.fp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright 2018 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. in float sigma;
  8. layout(ctype=SkRect) in float4 rect;
  9. in uniform half cornerRadius;
  10. in uniform sampler2D ninePatchSampler;
  11. layout(ctype=SkRect) uniform float4 proxyRect;
  12. uniform half blurRadius;
  13. @header {
  14. #include "include/effects/SkBlurMaskFilter.h"
  15. #include "include/gpu/GrContext.h"
  16. #include "include/private/GrRecordingContext.h"
  17. #include "src/core/SkBlurPriv.h"
  18. #include "src/core/SkGpuBlurUtils.h"
  19. #include "src/core/SkRRectPriv.h"
  20. #include "src/gpu/GrCaps.h"
  21. #include "src/gpu/GrClip.h"
  22. #include "src/gpu/GrPaint.h"
  23. #include "src/gpu/GrProxyProvider.h"
  24. #include "src/gpu/GrRecordingContextPriv.h"
  25. #include "src/gpu/GrRenderTargetContext.h"
  26. #include "src/gpu/GrStyle.h"
  27. }
  28. @class {
  29. static sk_sp<GrTextureProxy> find_or_create_rrect_blur_mask(GrRecordingContext* context,
  30. const SkRRect& rrectToDraw,
  31. const SkISize& size,
  32. float xformedSigma) {
  33. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  34. GrUniqueKey key;
  35. GrUniqueKey::Builder builder(&key, kDomain, 9, "RoundRect Blur Mask");
  36. builder[0] = SkScalarCeilToInt(xformedSigma-1/6.0f);
  37. int index = 1;
  38. for (auto c : { SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner,
  39. SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner }) {
  40. SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) &&
  41. SkScalarIsInt(rrectToDraw.radii(c).fY));
  42. builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX);
  43. builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY);
  44. }
  45. builder.finish();
  46. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  47. sk_sp<GrTextureProxy> mask(proxyProvider->findOrCreateProxyByUniqueKey(
  48. key, kBottomLeft_GrSurfaceOrigin));
  49. if (!mask) {
  50. // TODO: this could be approx but the texture coords will need to be updated
  51. sk_sp<GrRenderTargetContext> rtc(
  52. context->priv().makeDeferredRenderTargetContextWithFallback(
  53. SkBackingFit::kExact, size.fWidth,
  54. size.fHeight, GrColorType::kAlpha_8, nullptr));
  55. if (!rtc) {
  56. return nullptr;
  57. }
  58. GrPaint paint;
  59. rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
  60. GrRenderTargetContext::CanClearFullscreen::kYes);
  61. rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw,
  62. GrStyle::SimpleFill());
  63. sk_sp<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
  64. if (!srcProxy) {
  65. return nullptr;
  66. }
  67. sk_sp<GrRenderTargetContext> rtc2(
  68. SkGpuBlurUtils::GaussianBlur(context,
  69. std::move(srcProxy),
  70. SkIPoint::Make(0, 0),
  71. nullptr,
  72. SkIRect::MakeWH(size.fWidth, size.fHeight),
  73. SkIRect::EmptyIRect(),
  74. xformedSigma,
  75. xformedSigma,
  76. GrTextureDomain::kIgnore_Mode,
  77. kPremul_SkAlphaType,
  78. SkBackingFit::kExact));
  79. if (!rtc2) {
  80. return nullptr;
  81. }
  82. mask = rtc2->asTextureProxyRef();
  83. if (!mask) {
  84. return nullptr;
  85. }
  86. SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin);
  87. proxyProvider->assignUniqueKeyToProxy(key, mask.get());
  88. }
  89. return mask;
  90. }
  91. }
  92. @optimizationFlags {
  93. kCompatibleWithCoverageAsAlpha_OptimizationFlag
  94. }
  95. @make {
  96. static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context,
  97. float sigma,
  98. float xformedSigma,
  99. const SkRRect& srcRRect,
  100. const SkRRect& devRRect);
  101. }
  102. @cpp {
  103. std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* context,
  104. float sigma,
  105. float xformedSigma,
  106. const SkRRect& srcRRect,
  107. const SkRRect& devRRect) {
  108. SkASSERT(!SkRRectPriv::IsCircle(devRRect) && !devRRect.isRect()); // Should've been caught up-stream
  109. // TODO: loosen this up
  110. if (!SkRRectPriv::IsSimpleCircular(devRRect)) {
  111. return nullptr;
  112. }
  113. // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
  114. // sufficiently small relative to both the size of the corner radius and the
  115. // width (and height) of the rrect.
  116. SkRRect rrectToDraw;
  117. SkISize size;
  118. SkScalar ignored[kSkBlurRRectMaxDivisions];
  119. int ignoredSize;
  120. uint32_t ignored32;
  121. bool ninePatchable = SkComputeBlurredRRectParams(srcRRect, devRRect,
  122. SkRect::MakeEmpty(),
  123. sigma, xformedSigma,
  124. &rrectToDraw, &size,
  125. ignored, ignored,
  126. ignored, ignored,
  127. &ignoredSize, &ignoredSize,
  128. &ignored32);
  129. if (!ninePatchable) {
  130. return nullptr;
  131. }
  132. sk_sp<GrTextureProxy> mask(find_or_create_rrect_blur_mask(context, rrectToDraw,
  133. size, xformedSigma));
  134. if (!mask) {
  135. return nullptr;
  136. }
  137. return std::unique_ptr<GrFragmentProcessor>(
  138. new GrRRectBlurEffect(xformedSigma, devRRect.getBounds(),
  139. SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(mask)));
  140. }
  141. }
  142. @test(d) {
  143. SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
  144. SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
  145. SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
  146. SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
  147. SkRRect rrect;
  148. rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
  149. return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect);
  150. }
  151. void main() {
  152. // warp the fragment position to the appropriate part of the 9patch blur texture
  153. half2 rectCenter = half2((proxyRect.xy + proxyRect.zw) / 2.0);
  154. half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.xy);
  155. half threshold = cornerRadius + 2.0 * blurRadius;
  156. half2 middle = half2(proxyRect.zw - proxyRect.xy - 2.0 * threshold);
  157. if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x + threshold)) {
  158. translatedFragPos.x = threshold;
  159. } else if (translatedFragPos.x >= (middle.x + threshold)) {
  160. translatedFragPos.x -= middle.x - 1.0;
  161. }
  162. if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {
  163. translatedFragPos.y = threshold;
  164. } else if (translatedFragPos.y >= (middle.y + threshold)) {
  165. translatedFragPos.y -= middle.y - 1.0;
  166. }
  167. half2 proxyDims = half2(2.0 * threshold + 1.0);
  168. half2 texCoord = translatedFragPos / proxyDims;
  169. sk_OutColor = sk_InColor * texture(ninePatchSampler, texCoord);
  170. }
  171. @setData(pdman) {
  172. float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f);
  173. pdman.set1f(blurRadius, blurRadiusValue);
  174. SkRect outset = rect;
  175. outset.outset(blurRadiusValue, blurRadiusValue);
  176. pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom);
  177. }