| 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/GrMatrixConvolutionEffect.h" | 14 #include "effects/GrMatrixConvolutionEffect.h" |
| 15 #include "GrContext.h" | 15 #include "GrContext.h" |
| 16 #include "GrCaps.h" | 16 #include "GrCaps.h" |
| 17 #include "GrDrawContext.h" | 17 #include "GrDrawContext.h" |
| 18 #endif | |
| 19 | |
| 20 namespace SkGpuBlurUtils { | |
| 21 | |
| 22 #if SK_SUPPORT_GPU | |
| 23 | 18 |
| 24 #define MAX_BLUR_SIGMA 4.0f | 19 #define MAX_BLUR_SIGMA 4.0f |
| 25 | 20 |
| 26 static void scale_rect(SkRect* rect, float xScale, float yScale) { | 21 static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) { |
| 27 rect->fLeft = SkScalarMul(rect->fLeft, xScale); | 22 rect->fLeft = SkScalarFloorToInt(SkScalarMul(rect->fLeft, xScale)); |
| 28 rect->fTop = SkScalarMul(rect->fTop, yScale); | 23 rect->fTop = SkScalarFloorToInt(SkScalarMul(rect->fTop, yScale)); |
| 29 rect->fRight = SkScalarMul(rect->fRight, xScale); | 24 rect->fRight = SkScalarCeilToInt(SkScalarMul(rect->fRight, xScale)); |
| 30 rect->fBottom = SkScalarMul(rect->fBottom, yScale); | 25 rect->fBottom = SkScalarCeilToInt(SkScalarMul(rect->fBottom, yScale)); |
| 26 } |
| 27 |
| 28 static void scale_irect(SkIRect* rect, int xScale, int yScale) { |
| 29 rect->fLeft *= xScale; |
| 30 rect->fTop *= yScale; |
| 31 rect->fRight *= xScale; |
| 32 rect->fBottom *= yScale; |
| 33 } |
| 34 |
| 35 #ifdef SK_DEBUG |
| 36 static inline int is_even(int x) { return !(x & 1); } |
| 37 #endif |
| 38 |
| 39 static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) { |
| 40 if (xAxis) { |
| 41 SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight)); |
| 42 rect->fLeft /= 2; |
| 43 rect->fRight /= 2; |
| 44 } |
| 45 if (yAxis) { |
| 46 SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom)); |
| 47 rect->fTop /= 2; |
| 48 rect->fBottom /= 2; |
| 49 } |
| 31 } | 50 } |
| 32 | 51 |
| 33 static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int
*radius) { | 52 static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int
*radius) { |
| 34 *scaleFactor = 1; | 53 *scaleFactor = 1; |
| 35 while (sigma > MAX_BLUR_SIGMA) { | 54 while (sigma > MAX_BLUR_SIGMA) { |
| 36 *scaleFactor *= 2; | 55 *scaleFactor *= 2; |
| 37 sigma *= 0.5f; | 56 sigma *= 0.5f; |
| 38 if (*scaleFactor > maxTextureSize) { | 57 if (*scaleFactor > maxTextureSize) { |
| 39 *scaleFactor = maxTextureSize; | 58 *scaleFactor = maxTextureSize; |
| 40 sigma = MAX_BLUR_SIGMA; | 59 sigma = MAX_BLUR_SIGMA; |
| 41 } | 60 } |
| 42 } | 61 } |
| 43 *radius = static_cast<int>(ceilf(sigma * 3.0f)); | 62 *radius = static_cast<int>(ceilf(sigma * 3.0f)); |
| 44 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); | 63 SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); |
| 45 return sigma; | 64 return sigma; |
| 46 } | 65 } |
| 47 | 66 |
| 48 static void convolve_gaussian_1d(GrDrawContext* drawContext, | 67 static void convolve_gaussian_1d(GrDrawContext* drawContext, |
| 49 const GrClip& clip, | 68 const GrClip& clip, |
| 50 const SkRect& dstRect, | 69 const SkIRect& dstRect, |
| 51 const SkPoint& srcOffset, | 70 const SkIPoint& srcOffset, |
| 52 GrTexture* texture, | 71 GrTexture* texture, |
| 53 Gr1DKernelEffect::Direction direction, | 72 Gr1DKernelEffect::Direction direction, |
| 54 int radius, | 73 int radius, |
| 55 float sigma, | 74 float sigma, |
| 56 bool useBounds, | 75 bool useBounds, |
| 57 float bounds[2]) { | 76 float bounds[2]) { |
| 58 GrPaint paint; | 77 GrPaint paint; |
| 59 paint.setGammaCorrect(drawContext->isGammaCorrect()); | 78 paint.setGammaCorrect(drawContext->isGammaCorrect()); |
| 60 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian( | 79 SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian( |
| 61 texture, direction, radius, sigma, useBounds, bounds)); | 80 texture, direction, radius, sigma, useBounds, bounds)); |
| 62 paint.addColorFragmentProcessor(conv); | 81 paint.addColorFragmentProcessor(conv); |
| 63 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); | 82 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); |
| 64 SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y()); | 83 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), |
| 65 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, lo
calMatrix); | 84 -SkIntToScalar(srcOffset.y())); |
| 85 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), |
| 86 SkRect::Make(dstRect), localMatrix); |
| 66 } | 87 } |
| 67 | 88 |
| 68 static void convolve_gaussian_2d(GrDrawContext* drawContext, | 89 static void convolve_gaussian_2d(GrDrawContext* drawContext, |
| 69 const GrClip& clip, | 90 const GrClip& clip, |
| 70 const SkRect& dstRect, | 91 const SkIRect& dstRect, |
| 71 const SkPoint& srcOffset, | 92 const SkIPoint& srcOffset, |
| 72 GrTexture* texture, | 93 GrTexture* texture, |
| 73 int radiusX, | 94 int radiusX, |
| 74 int radiusY, | 95 int radiusY, |
| 75 SkScalar sigmaX, | 96 SkScalar sigmaX, |
| 76 SkScalar sigmaY, | 97 SkScalar sigmaY, |
| 77 const SkRect* srcBounds) { | 98 const SkIRect* srcBounds) { |
| 78 SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y()); | 99 SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), |
| 100 -SkIntToScalar(srcOffset.y())); |
| 79 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); | 101 SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); |
| 80 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); | 102 SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); |
| 81 GrPaint paint; | 103 GrPaint paint; |
| 82 paint.setGammaCorrect(drawContext->isGammaCorrect()); | 104 paint.setGammaCorrect(drawContext->isGammaCorrect()); |
| 83 SkIRect bounds; | 105 SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect(); |
| 84 if (srcBounds) { | |
| 85 srcBounds->roundOut(&bounds); | |
| 86 } else { | |
| 87 bounds.setEmpty(); | |
| 88 } | |
| 89 | 106 |
| 90 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaus
sian( | 107 SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaus
sian( |
| 91 texture, bounds, size, 1.0, 0.0, kernelOffset, | 108 texture, bounds, size, 1.0, 0.0, kernelOffset, |
| 92 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_
Mode, | 109 srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_
Mode, |
| 93 true, sigmaX, sigmaY)); | 110 true, sigmaX, sigmaY)); |
| 94 paint.addColorFragmentProcessor(conv); | 111 paint.addColorFragmentProcessor(conv); |
| 95 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); | 112 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); |
| 96 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, lo
calMatrix); | 113 drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), |
| 114 SkRect::Make(dstRect), localMatrix); |
| 97 } | 115 } |
| 98 | 116 |
| 99 static void convolve_gaussian(GrDrawContext* drawContext, | 117 static void convolve_gaussian(GrDrawContext* drawContext, |
| 100 const GrClip& clip, | 118 const GrClip& clip, |
| 101 const SkRect& srcRect, | 119 const SkIRect& srcRect, |
| 102 GrTexture* texture, | 120 GrTexture* texture, |
| 103 Gr1DKernelEffect::Direction direction, | 121 Gr1DKernelEffect::Direction direction, |
| 104 int radius, | 122 int radius, |
| 105 float sigma, | 123 float sigma, |
| 106 const SkRect* srcBounds, | 124 const SkIRect* srcBounds, |
| 107 const SkPoint& srcOffset) { | 125 const SkIPoint& srcOffset) { |
| 108 float bounds[2] = { 0.0f, 1.0f }; | 126 float bounds[2] = { 0.0f, 1.0f }; |
| 109 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); | 127 SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); |
| 110 if (!srcBounds) { | 128 if (!srcBounds) { |
| 111 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, | 129 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, |
| 112 direction, radius, sigma, false, bounds); | 130 direction, radius, sigma, false, bounds); |
| 113 return; | 131 return; |
| 114 } | 132 } |
| 115 SkRect midRect = *srcBounds, leftRect, rightRect; | 133 SkIRect midRect = *srcBounds, leftRect, rightRect; |
| 116 midRect.offset(srcOffset); | 134 midRect.offset(srcOffset); |
| 117 SkIRect topRect, bottomRect; | 135 SkIRect topRect, bottomRect; |
| 118 SkScalar rad = SkIntToScalar(radius); | |
| 119 if (direction == Gr1DKernelEffect::kX_Direction) { | 136 if (direction == Gr1DKernelEffect::kX_Direction) { |
| 120 bounds[0] = SkScalarToFloat(srcBounds->left()) / texture->width(); | 137 bounds[0] = SkIntToFloat(srcBounds->left()) / texture->width(); |
| 121 bounds[1] = SkScalarToFloat(srcBounds->right()) / texture->width(); | 138 bounds[1] = SkIntToFloat(srcBounds->right()) / texture->width(); |
| 122 SkRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()).roundOut(&topRect
); | 139 topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()); |
| 123 SkRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom()) | 140 bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dst
Rect.bottom()); |
| 124 .roundOut(&bottomRect); | 141 midRect.inset(radius, 0); |
| 125 midRect.inset(rad, 0); | 142 leftRect = SkIRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.b
ottom()); |
| 126 leftRect = SkRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bo
ttom()); | |
| 127 rightRect = | 143 rightRect = |
| 128 SkRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), mi
dRect.bottom()); | 144 SkIRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), m
idRect.bottom()); |
| 129 dstRect.fTop = midRect.top(); | 145 dstRect.fTop = midRect.top(); |
| 130 dstRect.fBottom = midRect.bottom(); | 146 dstRect.fBottom = midRect.bottom(); |
| 131 } else { | 147 } else { |
| 132 bounds[0] = SkScalarToFloat(srcBounds->top()) / texture->height(); | 148 bounds[0] = SkIntToFloat(srcBounds->top()) / texture->height(); |
| 133 bounds[1] = SkScalarToFloat(srcBounds->bottom()) / texture->height(); | 149 bounds[1] = SkIntToFloat(srcBounds->bottom()) / texture->height(); |
| 134 SkRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()).roundOut(&topRe
ct); | 150 topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()); |
| 135 SkRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom()) | 151 bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstR
ect.bottom()); |
| 136 .roundOut(&bottomRect);; | 152 midRect.inset(0, radius); |
| 137 midRect.inset(0, rad); | 153 leftRect = SkIRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect
.top()); |
| 138 leftRect = SkRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.
top()); | |
| 139 rightRect = | 154 rightRect = |
| 140 SkRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(),
dstRect.height()); | 155 SkIRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(),
dstRect.height()); |
| 141 dstRect.fLeft = midRect.left(); | 156 dstRect.fLeft = midRect.left(); |
| 142 dstRect.fRight = midRect.right(); | 157 dstRect.fRight = midRect.right(); |
| 143 } | 158 } |
| 144 if (!topRect.isEmpty()) { | 159 if (!topRect.isEmpty()) { |
| 145 drawContext->clear(&topRect, 0, false); | 160 drawContext->clear(&topRect, 0, false); |
| 146 } | 161 } |
| 147 | 162 |
| 148 if (!bottomRect.isEmpty()) { | 163 if (!bottomRect.isEmpty()) { |
| 149 drawContext->clear(&bottomRect, 0, false); | 164 drawContext->clear(&bottomRect, 0, false); |
| 150 } | 165 } |
| 151 if (midRect.isEmpty()) { | 166 if (midRect.isEmpty()) { |
| 152 // Blur radius covers srcBounds; use bounds over entire draw | 167 // Blur radius covers srcBounds; use bounds over entire draw |
| 153 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, | 168 convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, |
| 154 direction, radius, sigma, true, bounds); | 169 direction, radius, sigma, true, bounds); |
| 155 } else { | 170 } else { |
| 156 // Draw right and left margins with bounds; middle without. | 171 // Draw right and left margins with bounds; middle without. |
| 157 convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture, | 172 convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture, |
| 158 direction, radius, sigma, true, bounds); | 173 direction, radius, sigma, true, bounds); |
| 159 convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture, | 174 convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture, |
| 160 direction, radius, sigma, true, bounds); | 175 direction, radius, sigma, true, bounds); |
| 161 convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture, | 176 convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture, |
| 162 direction, radius, sigma, false, bounds); | 177 direction, radius, sigma, false, bounds); |
| 163 } | 178 } |
| 164 } | 179 } |
| 165 | 180 |
| 181 namespace SkGpuBlurUtils { |
| 182 |
| 166 sk_sp<GrDrawContext> GaussianBlur(GrContext* context, | 183 sk_sp<GrDrawContext> GaussianBlur(GrContext* context, |
| 167 GrTexture* srcTexture, | 184 GrTexture* srcTexture, |
| 168 bool gammaCorrect, | 185 bool gammaCorrect, |
| 169 const SkRect& dstBounds, | 186 const SkIRect& dstBounds, |
| 170 const SkRect* srcBounds, | 187 const SkIRect* srcBounds, |
| 171 float sigmaX, | 188 float sigmaX, |
| 172 float sigmaY) { | 189 float sigmaY) { |
| 173 SkASSERT(context); | 190 SkASSERT(context); |
| 174 SkIRect clearRect; | 191 SkIRect clearRect; |
| 175 int scaleFactorX, radiusX; | 192 int scaleFactorX, radiusX; |
| 176 int scaleFactorY, radiusY; | 193 int scaleFactorY, radiusY; |
| 177 int maxTextureSize = context->caps()->maxTextureSize(); | 194 int maxTextureSize = context->caps()->maxTextureSize(); |
| 178 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); | 195 sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); |
| 179 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); | 196 sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); |
| 197 SkASSERT(sigmaX || sigmaY); |
| 180 | 198 |
| 181 SkPoint srcOffset = SkPoint::Make(-dstBounds.x(), -dstBounds.y()); | 199 SkIPoint srcOffset = SkIPoint::Make(-dstBounds.x(), -dstBounds.y()); |
| 182 SkRect localDstBounds = SkRect::MakeWH(dstBounds.width(), dstBounds.height()
); | 200 SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height
()); |
| 183 SkRect localSrcBounds; | 201 SkIRect localSrcBounds; |
| 184 SkRect srcRect; | 202 SkIRect srcRect; |
| 185 if (srcBounds) { | 203 if (srcBounds) { |
| 186 srcRect = localSrcBounds = *srcBounds; | 204 srcRect = localSrcBounds = *srcBounds; |
| 187 srcRect.offset(srcOffset); | 205 srcRect.offset(srcOffset); |
| 188 srcBounds = &localSrcBounds; | 206 srcBounds = &localSrcBounds; |
| 189 } else { | 207 } else { |
| 190 srcRect = localDstBounds; | 208 srcRect = localDstBounds; |
| 191 } | 209 } |
| 192 | 210 |
| 193 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); | 211 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); |
| 194 srcRect.roundOut(&srcRect); | 212 scale_irect(&srcRect, scaleFactorX, scaleFactorY); |
| 195 scale_rect(&srcRect, static_cast<float>(scaleFactorX), | |
| 196 static_cast<float>(scaleFactorY)); | |
| 197 | 213 |
| 198 // setup new clip | 214 // setup new clip |
| 199 GrClip clip(localDstBounds); | 215 GrClip clip(localDstBounds); |
| 200 | 216 |
| 201 SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || | 217 SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || |
| 202 kRGBA_8888_GrPixelConfig == srcTexture->config() || | 218 kRGBA_8888_GrPixelConfig == srcTexture->config() || |
| 203 kSRGBA_8888_GrPixelConfig == srcTexture->config() || | 219 kSRGBA_8888_GrPixelConfig == srcTexture->config() || |
| 204 kSBGRA_8888_GrPixelConfig == srcTexture->config() || | 220 kSBGRA_8888_GrPixelConfig == srcTexture->config() || |
| 205 kAlpha_8_GrPixelConfig == srcTexture->config()); | 221 kAlpha_8_GrPixelConfig == srcTexture->config()); |
| 206 | 222 |
| 207 const int width = SkScalarFloorToInt(dstBounds.width()); | 223 const int width = dstBounds.width(); |
| 208 const int height = SkScalarFloorToInt(dstBounds.height()); | 224 const int height = dstBounds.height(); |
| 209 const GrPixelConfig config = srcTexture->config(); | 225 const GrPixelConfig config = srcTexture->config(); |
| 210 | 226 |
| 211 const SkSurfaceProps props(gammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag
: 0, | 227 const SkSurfaceProps props(gammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag
: 0, |
| 212 SkSurfaceProps::kLegacyFontHost_InitType); | 228 SkSurfaceProps::kLegacyFontHost_InitType); |
| 213 | 229 |
| 214 sk_sp<GrDrawContext> dstDrawContext(context->newDrawContext(SkBackingFit::kA
pprox, | 230 sk_sp<GrDrawContext> dstDrawContext(context->newDrawContext(SkBackingFit::kA
pprox, |
| 215 width, height, c
onfig, | 231 width, height, c
onfig, |
| 216 0, kDefault_GrSu
rfaceOrigin, | 232 0, kDefault_GrSu
rfaceOrigin, |
| 217 &props)); | 233 &props)); |
| 218 if (!dstDrawContext) { | 234 if (!dstDrawContext) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 235 sk_sp<GrDrawContext> tmpDrawContext(context->newDrawContext(SkBackingFit::kA
pprox, | 251 sk_sp<GrDrawContext> tmpDrawContext(context->newDrawContext(SkBackingFit::kA
pprox, |
| 236 width, height, c
onfig, | 252 width, height, c
onfig, |
| 237 0, kDefault_GrSu
rfaceOrigin, | 253 0, kDefault_GrSu
rfaceOrigin, |
| 238 &props)); | 254 &props)); |
| 239 if (!tmpDrawContext) { | 255 if (!tmpDrawContext) { |
| 240 return nullptr; | 256 return nullptr; |
| 241 } | 257 } |
| 242 | 258 |
| 243 sk_sp<GrDrawContext> srcDrawContext; | 259 sk_sp<GrDrawContext> srcDrawContext; |
| 244 | 260 |
| 261 SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); |
| 262 |
| 245 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { | 263 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { |
| 246 GrPaint paint; | 264 GrPaint paint; |
| 247 paint.setGammaCorrect(gammaCorrect); | 265 paint.setGammaCorrect(gammaCorrect); |
| 248 SkMatrix matrix; | 266 SkMatrix matrix; |
| 249 matrix.setIDiv(srcTexture->width(), srcTexture->height()); | 267 matrix.setIDiv(srcTexture->width(), srcTexture->height()); |
| 250 SkRect dstRect(srcRect); | 268 SkIRect dstRect(srcRect); |
| 251 if (srcBounds && i == 1) { | 269 if (srcBounds && i == 1) { |
| 252 SkRect domain; | 270 SkRect domain; |
| 253 matrix.mapRect(&domain, *srcBounds); | 271 matrix.mapRect(&domain, SkRect::Make(*srcBounds)); |
| 254 domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width(
) : 0.0f, | 272 domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width(
) : 0.0f, |
| 255 (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height
() : 0.0f); | 273 (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height
() : 0.0f); |
| 256 sk_sp<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create( | 274 sk_sp<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create( |
| 257 srcTexture, | 275 srcTexture, |
| 258 matrix, | 276 matrix, |
| 259 domain, | 277 domain, |
| 260 GrTextureDomain::kDecal_
Mode, | 278 GrTextureDomain::kDecal_
Mode, |
| 261 GrTextureParams::kBilerp
_FilterMode)); | 279 GrTextureParams::kBilerp
_FilterMode)); |
| 262 paint.addColorFragmentProcessor(fp.get()); | 280 paint.addColorFragmentProcessor(fp.get()); |
| 263 srcRect.offset(-srcOffset); | 281 srcRect.offset(-srcOffset); |
| 264 srcOffset.set(0, 0); | 282 srcOffset.set(0, 0); |
| 265 } else { | 283 } else { |
| 266 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k
Bilerp_FilterMode); | 284 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k
Bilerp_FilterMode); |
| 267 paint.addColorTextureProcessor(srcTexture, matrix, params); | 285 paint.addColorTextureProcessor(srcTexture, matrix, params); |
| 268 } | 286 } |
| 269 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); | 287 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); |
| 270 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, | 288 shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); |
| 271 i < scaleFactorY ? 0.5f : 1.0f); | |
| 272 | 289 |
| 273 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcR
ect); | 290 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), |
| 291 SkRect::Make(dstRect), SkRect::Make(srcRe
ct)); |
| 274 | 292 |
| 275 srcDrawContext = dstDrawContext; | 293 srcDrawContext = dstDrawContext; |
| 276 srcRect = dstRect; | 294 srcRect = dstRect; |
| 277 srcTexture = srcDrawContext->asTexture().release(); | 295 srcTexture = srcDrawContext->asTexture().release(); |
| 278 SkTSwap(dstDrawContext, tmpDrawContext); | 296 SkTSwap(dstDrawContext, tmpDrawContext); |
| 279 localSrcBounds = srcRect; | 297 localSrcBounds = srcRect; |
| 280 } | 298 } |
| 281 | 299 |
| 282 srcRect = localDstBounds; | 300 srcRect = localDstBounds; |
| 283 | 301 scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); |
| 284 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); | |
| 285 srcRect.roundOut(&srcRect); | |
| 286 SkIRect srcIRect = srcRect.roundOut(); | |
| 287 if (sigmaX > 0.0f) { | 302 if (sigmaX > 0.0f) { |
| 288 if (scaleFactorX > 1) { | 303 if (scaleFactorX > 1) { |
| 289 SkASSERT(srcDrawContext); | 304 SkASSERT(srcDrawContext); |
| 290 | 305 |
| 291 // Clear out a radius to the right of the srcRect to prevent the | 306 // Clear out a radius to the right of the srcRect to prevent the |
| 292 // X convolution from reading garbage. | 307 // X convolution from reading garbage. |
| 293 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, | 308 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, |
| 294 radiusX, srcIRect.height()); | 309 radiusX, srcRect.height()); |
| 295 srcDrawContext->clear(&clearRect, 0x0, false); | 310 srcDrawContext->clear(&clearRect, 0x0, false); |
| 296 } | 311 } |
| 297 | 312 |
| 298 convolve_gaussian(dstDrawContext.get(), clip, srcRect, | 313 convolve_gaussian(dstDrawContext.get(), clip, srcRect, |
| 299 srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, s
igmaX, | 314 srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, s
igmaX, |
| 300 srcBounds, srcOffset); | 315 srcBounds, srcOffset); |
| 301 srcDrawContext = dstDrawContext; | 316 srcDrawContext = dstDrawContext; |
| 302 srcTexture = srcDrawContext->asTexture().release(); | 317 srcTexture = srcDrawContext->asTexture().release(); |
| 303 srcRect.offsetTo(0, 0); | 318 srcRect.offsetTo(0, 0); |
| 304 SkTSwap(dstDrawContext, tmpDrawContext); | 319 SkTSwap(dstDrawContext, tmpDrawContext); |
| 305 localSrcBounds = srcRect; | 320 localSrcBounds = srcRect; |
| 306 srcOffset.set(0, 0); | 321 srcOffset.set(0, 0); |
| 307 } | 322 } |
| 308 | 323 |
| 309 if (sigmaY > 0.0f) { | 324 if (sigmaY > 0.0f) { |
| 310 if (scaleFactorY > 1 || sigmaX > 0.0f) { | 325 if (scaleFactorY > 1 || sigmaX > 0.0f) { |
| 311 SkASSERT(srcDrawContext); | 326 SkASSERT(srcDrawContext); |
| 312 | 327 |
| 313 // Clear out a radius below the srcRect to prevent the Y | 328 // Clear out a radius below the srcRect to prevent the Y |
| 314 // convolution from reading garbage. | 329 // convolution from reading garbage. |
| 315 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, | 330 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, |
| 316 srcIRect.width(), radiusY); | 331 srcRect.width(), radiusY); |
| 317 srcDrawContext->clear(&clearRect, 0x0, false); | 332 srcDrawContext->clear(&clearRect, 0x0, false); |
| 318 } | 333 } |
| 319 | 334 |
| 320 convolve_gaussian(dstDrawContext.get(), clip, srcRect, | 335 convolve_gaussian(dstDrawContext.get(), clip, srcRect, |
| 321 srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, s
igmaY, | 336 srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, s
igmaY, |
| 322 srcBounds, srcOffset); | 337 srcBounds, srcOffset); |
| 323 | 338 |
| 324 srcDrawContext = dstDrawContext; | 339 srcDrawContext = dstDrawContext; |
| 325 srcRect.offsetTo(0, 0); | 340 srcRect.offsetTo(0, 0); |
| 326 SkTSwap(dstDrawContext, tmpDrawContext); | 341 SkTSwap(dstDrawContext, tmpDrawContext); |
| 327 } | 342 } |
| 328 | 343 |
| 329 SkASSERT(srcDrawContext); | 344 SkASSERT(srcDrawContext); |
| 330 srcTexture = nullptr; // we don't use this from here on out | 345 srcTexture = nullptr; // we don't use this from here on out |
| 331 srcIRect = srcRect.roundOut(); | |
| 332 | 346 |
| 333 if (scaleFactorX > 1 || scaleFactorY > 1) { | 347 if (scaleFactorX > 1 || scaleFactorY > 1) { |
| 334 // Clear one pixel to the right and below, to accommodate bilinear upsam
pling. | 348 // Clear one pixel to the right and below, to accommodate bilinear upsam
pling. |
| 335 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect
.width() + 1, 1); | 349 clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.wi
dth() + 1, 1); |
| 336 srcDrawContext->clear(&clearRect, 0x0, false); | 350 srcDrawContext->clear(&clearRect, 0x0, false); |
| 337 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1, srcIRec
t.height()); | 351 clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.h
eight()); |
| 338 srcDrawContext->clear(&clearRect, 0x0, false); | 352 srcDrawContext->clear(&clearRect, 0x0, false); |
| 339 | 353 |
| 340 SkMatrix matrix; | 354 SkMatrix matrix; |
| 341 matrix.setIDiv(srcDrawContext->width(), srcDrawContext->height()); | 355 matrix.setIDiv(srcDrawContext->width(), srcDrawContext->height()); |
| 342 | 356 |
| 343 GrPaint paint; | 357 GrPaint paint; |
| 344 paint.setGammaCorrect(gammaCorrect); | 358 paint.setGammaCorrect(gammaCorrect); |
| 345 // FIXME: this should be mitchell, not bilinear. | 359 // FIXME: this should be mitchell, not bilinear. |
| 346 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile
rp_FilterMode); | 360 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile
rp_FilterMode); |
| 347 paint.addColorTextureProcessor(srcDrawContext->asTexture().release(), ma
trix, params); | 361 paint.addColorTextureProcessor(srcDrawContext->asTexture().release(), ma
trix, params); |
| 348 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); | 362 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); |
| 349 | 363 |
| 350 SkRect dstRect(srcRect); | 364 SkIRect dstRect(srcRect); |
| 351 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); | 365 scale_irect(&dstRect, scaleFactorX, scaleFactorY); |
| 352 | 366 |
| 353 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcR
ect); | 367 dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), |
| 368 SkRect::Make(dstRect), SkRect::Make(srcRe
ct)); |
| 354 | 369 |
| 355 srcDrawContext = dstDrawContext; | 370 srcDrawContext = dstDrawContext; |
| 356 srcRect = dstRect; | 371 srcRect = dstRect; |
| 357 SkTSwap(dstDrawContext, tmpDrawContext); | 372 SkTSwap(dstDrawContext, tmpDrawContext); |
| 358 } | 373 } |
| 359 | 374 |
| 360 return srcDrawContext; | 375 return srcDrawContext; |
| 361 } | 376 } |
| 377 |
| 378 } |
| 379 |
| 362 #endif | 380 #endif |
| 363 | 381 |
| 364 } | |
| OLD | NEW |