OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkGpuBlurUtils.h" | 8 #include "SkGpuBlurUtils.h" |
9 | 9 |
10 #include "SkRect.h" | 10 #include "SkRect.h" |
11 | 11 |
12 #if SK_SUPPORT_GPU | 12 #if SK_SUPPORT_GPU |
13 #include "effects/GrConvolutionEffect.h" | 13 #include "effects/GrConvolutionEffect.h" |
| 14 #include "effects/GrTextureDomainEffect.h" |
14 #include "GrContext.h" | 15 #include "GrContext.h" |
15 #endif | 16 #endif |
16 | 17 |
17 namespace SkGpuBlurUtils { | 18 namespace SkGpuBlurUtils { |
18 | 19 |
19 #if SK_SUPPORT_GPU | 20 #if SK_SUPPORT_GPU |
20 | 21 |
21 #define MAX_BLUR_SIGMA 4.0f | 22 #define MAX_BLUR_SIGMA 4.0f |
22 | 23 |
23 static void scale_rect(SkRect* rect, float xScale, float yScale) { | 24 static void scale_rect(SkRect* rect, float xScale, float yScale) { |
24 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); | 25 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); |
25 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); | 26 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); |
26 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); | 27 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); |
27 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); | 28 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); |
28 } | 29 } |
29 | 30 |
30 static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { | 31 static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { |
31 *scaleFactor = 1; | 32 *scaleFactor = 1; |
32 while (sigma > MAX_BLUR_SIGMA) { | 33 while (sigma > MAX_BLUR_SIGMA) { |
33 *scaleFactor *= 2; | 34 *scaleFactor *= 2; |
34 sigma *= 0.5f; | 35 sigma *= 0.5f; |
35 } | 36 } |
36 *radius = static_cast<int>(ceilf(sigma * 3.0f)); | 37 *radius = static_cast<int>(ceilf(sigma * 3.0f)); |
37 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); | 38 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); |
38 return sigma; | 39 return sigma; |
39 } | 40 } |
40 | 41 |
41 static void convolve_gaussian(GrContext* context, | 42 static void convolve_gaussian(GrContext* context, |
42 GrTexture* texture, | 43 GrTexture* texture, |
43 const SkRect& rect, | 44 const SkRect& srcRect, |
| 45 const SkRect& dstRect, |
| 46 bool cropToSrcRect, |
44 float sigma, | 47 float sigma, |
45 int radius, | 48 int radius, |
46 Gr1DKernelEffect::Direction direction) { | 49 Gr1DKernelEffect::Direction direction) { |
47 GrPaint paint; | 50 GrPaint paint; |
| 51 paint.reset(); |
| 52 float cropRect[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; |
| 53 if (cropToSrcRect) { |
| 54 if (direction == Gr1DKernelEffect::kX_Direction) { |
| 55 cropRect[0] = SkScalarToFloat(srcRect.left()) / texture->width(); |
| 56 cropRect[1] = SkScalarToFloat(srcRect.right()) / texture->width(); |
| 57 } else { |
| 58 cropRect[2] = SkScalarToFloat(srcRect.top()) / texture->height(); |
| 59 cropRect[3] = SkScalarToFloat(srcRect.bottom()) / texture->height(); |
| 60 } |
| 61 } |
48 | 62 |
49 SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, | 63 SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, |
50 direction
, | 64 direction
, |
51 radius, | 65 radius, |
52 sigma)); | 66 sigma, |
| 67 cropToSrc
Rect, |
| 68 cropRect)
); |
53 paint.addColorEffect(conv); | 69 paint.addColorEffect(conv); |
54 context->drawRect(paint, rect); | 70 context->drawRectToRect(paint, dstRect, srcRect); |
55 } | 71 } |
56 | 72 |
57 GrTexture* GaussianBlur(GrContext* context, | 73 GrTexture* GaussianBlur(GrContext* context, |
58 GrTexture* srcTexture, | 74 GrTexture* srcTexture, |
59 bool canClobberSrc, | 75 bool canClobberSrc, |
60 const SkRect& rect, | 76 const SkRect& rect, |
| 77 bool cropToRect, |
61 float sigmaX, | 78 float sigmaX, |
62 float sigmaY) { | 79 float sigmaY) { |
63 GrAssert(NULL != context); | 80 GrAssert(NULL != context); |
64 | 81 |
65 GrContext::AutoRenderTarget art(context); | 82 GrContext::AutoRenderTarget art(context); |
66 | 83 |
67 GrContext::AutoMatrix am; | 84 GrContext::AutoMatrix am; |
68 am.setIdentity(context); | 85 am.setIdentity(context); |
69 | 86 |
70 SkIRect clearRect; | 87 SkIRect clearRect; |
71 int scaleFactorX, radiusX; | 88 int scaleFactorX, radiusX; |
72 int scaleFactorY, radiusY; | 89 int scaleFactorY, radiusY; |
73 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); | 90 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); |
74 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); | 91 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); |
75 | 92 |
76 SkRect srcRect(rect); | 93 SkRect srcRect(rect); |
77 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); | 94 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); |
78 srcRect.roundOut(); | 95 srcRect.roundOut(); |
79 scale_rect(&srcRect, static_cast<float>(scaleFactorX), | 96 scale_rect(&srcRect, static_cast<float>(scaleFactorX), |
80 static_cast<float>(scaleFactorY)); | 97 static_cast<float>(scaleFactorY)); |
81 | 98 |
82 GrContext::AutoClip acs(context, srcRect); | 99 GrContext::AutoClip acs(context, SkRect::MakeWH(srcRect.width(), srcRect.hei
ght())); |
83 | 100 |
84 GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || | 101 GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || |
85 kRGBA_8888_GrPixelConfig == srcTexture->config() || | 102 kRGBA_8888_GrPixelConfig == srcTexture->config() || |
86 kAlpha_8_GrPixelConfig == srcTexture->config()); | 103 kAlpha_8_GrPixelConfig == srcTexture->config()); |
87 | 104 |
88 GrTextureDesc desc; | 105 GrTextureDesc desc; |
89 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | 106 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
90 desc.fWidth = SkScalarFloorToInt(srcRect.width()); | 107 desc.fWidth = SkScalarFloorToInt(srcRect.width()); |
91 desc.fHeight = SkScalarFloorToInt(srcRect.height()); | 108 desc.fHeight = SkScalarFloorToInt(srcRect.height()); |
92 desc.fConfig = srcTexture->config(); | 109 desc.fConfig = srcTexture->config(); |
93 | 110 |
94 GrAutoScratchTexture temp1, temp2; | 111 GrAutoScratchTexture temp1, temp2; |
95 GrTexture* dstTexture = temp1.set(context, desc); | 112 GrTexture* dstTexture = temp1.set(context, desc); |
96 GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, des
c); | 113 GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, des
c); |
97 if (NULL == dstTexture || NULL == tempTexture) { | 114 if (NULL == dstTexture || NULL == tempTexture) { |
98 return NULL; | 115 return NULL; |
99 } | 116 } |
100 | 117 |
101 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { | 118 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { |
102 GrPaint paint; | 119 GrPaint paint; |
103 SkMatrix matrix; | 120 SkMatrix matrix; |
104 matrix.setIDiv(srcTexture->width(), srcTexture->height()); | 121 matrix.setIDiv(srcTexture->width(), srcTexture->height()); |
105 context->setRenderTarget(dstTexture->asRenderTarget()); | 122 context->setRenderTarget(dstTexture->asRenderTarget()); |
106 SkRect dstRect(srcRect); | 123 SkRect dstRect(srcRect); |
| 124 if (cropToRect && i == 1) { |
| 125 dstRect.offset(-dstRect.fLeft, -dstRect.fTop); |
| 126 SkRect domain; |
| 127 matrix.mapRect(&domain, rect); |
| 128 domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width()
: 0.0f, |
| 129 i < scaleFactorY ? SK_ScalarHalf / srcTexture->height()
: 0.0f); |
| 130 SkAutoTUnref<GrEffectRef> effect(GrTextureDomainEffect::Create( |
| 131 srcTexture, |
| 132 matrix, |
| 133 domain, |
| 134 GrTextureDomainEffect::kDecal_WrapMode, |
| 135 true)); |
| 136 paint.addColorEffect(effect); |
| 137 } else { |
| 138 GrTextureParams params(SkShader::kClamp_TileMode, true); |
| 139 paint.addColorTextureEffect(srcTexture, matrix, params); |
| 140 } |
107 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, | 141 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, |
108 i < scaleFactorY ? 0.5f : 1.0f); | 142 i < scaleFactorY ? 0.5f : 1.0f); |
109 GrTextureParams params(SkShader::kClamp_TileMode, true); | |
110 paint.addColorTextureEffect(srcTexture, matrix, params); | |
111 context->drawRectToRect(paint, dstRect, srcRect); | 143 context->drawRectToRect(paint, dstRect, srcRect); |
112 srcRect = dstRect; | 144 srcRect = dstRect; |
113 srcTexture = dstTexture; | 145 srcTexture = dstTexture; |
114 SkTSwap(dstTexture, tempTexture); | 146 SkTSwap(dstTexture, tempTexture); |
115 } | 147 } |
116 | 148 |
117 SkIRect srcIRect; | 149 SkIRect srcIRect; |
118 srcRect.roundOut(&srcIRect); | 150 srcRect.roundOut(&srcIRect); |
119 | 151 |
120 if (sigmaX > 0.0f) { | 152 if (sigmaX > 0.0f) { |
121 if (scaleFactorX > 1) { | 153 if (scaleFactorX > 1) { |
122 // Clear out a radius to the right of the srcRect to prevent the | 154 // Clear out a radius to the right of the srcRect to prevent the |
123 // X convolution from reading garbage. | 155 // X convolution from reading garbage. |
124 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 156 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
125 radiusX, srcIRect.height()); | 157 radiusX, srcIRect.height()); |
126 context->clear(&clearRect, 0x0); | 158 context->clear(&clearRect, 0x0); |
127 } | 159 } |
128 context->setRenderTarget(dstTexture->asRenderTarget()); | 160 context->setRenderTarget(dstTexture->asRenderTarget()); |
129 convolve_gaussian(context, srcTexture, srcRect, sigmaX, radiusX, | 161 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
130 Gr1DKernelEffect::kX_Direction); | 162 convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, |
| 163 sigmaX, radiusX, Gr1DKernelEffect::kX_Direction); |
131 srcTexture = dstTexture; | 164 srcTexture = dstTexture; |
| 165 srcRect = dstRect; |
132 SkTSwap(dstTexture, tempTexture); | 166 SkTSwap(dstTexture, tempTexture); |
133 } | 167 } |
134 | 168 |
135 if (sigmaY > 0.0f) { | 169 if (sigmaY > 0.0f) { |
136 if (scaleFactorY > 1 || sigmaX > 0.0f) { | 170 if (scaleFactorY > 1 || sigmaX > 0.0f) { |
137 // Clear out a radius below the srcRect to prevent the Y | 171 // Clear out a radius below the srcRect to prevent the Y |
138 // convolution from reading garbage. | 172 // convolution from reading garbage. |
139 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 173 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
140 srcIRect.width(), radiusY); | 174 srcIRect.width(), radiusY); |
141 context->clear(&clearRect, 0x0); | 175 context->clear(&clearRect, 0x0); |
142 } | 176 } |
143 | 177 |
144 context->setRenderTarget(dstTexture->asRenderTarget()); | 178 context->setRenderTarget(dstTexture->asRenderTarget()); |
145 convolve_gaussian(context, srcTexture, srcRect, sigmaY, radiusY, | 179 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
146 Gr1DKernelEffect::kY_Direction); | 180 convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, |
| 181 sigmaY, radiusY, Gr1DKernelEffect::kY_Direction); |
147 srcTexture = dstTexture; | 182 srcTexture = dstTexture; |
| 183 srcRect = dstRect; |
148 SkTSwap(dstTexture, tempTexture); | 184 SkTSwap(dstTexture, tempTexture); |
149 } | 185 } |
150 | 186 |
151 if (scaleFactorX > 1 || scaleFactorY > 1) { | 187 if (scaleFactorX > 1 || scaleFactorY > 1) { |
152 // Clear one pixel to the right and below, to accommodate bilinear | 188 // Clear one pixel to the right and below, to accommodate bilinear |
153 // upsampling. | 189 // upsampling. |
154 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 190 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, |
155 srcIRect.width() + 1, 1); | 191 srcIRect.width() + 1, 1); |
156 context->clear(&clearRect, 0x0); | 192 context->clear(&clearRect, 0x0); |
157 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 193 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, |
(...skipping 20 matching lines...) Expand all Loading... |
178 } else if (srcTexture == temp2.texture()) { | 214 } else if (srcTexture == temp2.texture()) { |
179 return temp2.detach(); | 215 return temp2.detach(); |
180 } else { | 216 } else { |
181 srcTexture->ref(); | 217 srcTexture->ref(); |
182 return srcTexture; | 218 return srcTexture; |
183 } | 219 } |
184 } | 220 } |
185 #endif | 221 #endif |
186 | 222 |
187 } | 223 } |
OLD | NEW |