зеркало из https://github.com/mozilla/moz-skia.git
Refactor Gaussian blur and morphology from SkGpuDevice into GrContext.
Review URL: http://codereview.appspot.com/5720060/ git-svn-id: http://skia.googlecode.com/svn/trunk@3327 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
67ca522bca
Коммит
3b4dd90282
|
@ -16,6 +16,7 @@
|
|||
// remove.
|
||||
#include "GrRenderTarget.h"
|
||||
|
||||
class GrAutoScratchTexture;
|
||||
class GrDrawTarget;
|
||||
class GrFontCache;
|
||||
class GrGpu;
|
||||
|
@ -577,33 +578,42 @@ public:
|
|||
void resolveRenderTarget(GrRenderTarget* target);
|
||||
|
||||
/**
|
||||
* Applies a 1D convolution kernel in the given direction to a rectangle of
|
||||
* pixels from a given texture.
|
||||
* @param texture the texture to read from
|
||||
* @param rect the destination rectangle
|
||||
* @param kernel the convolution kernel (kernelWidth elements)
|
||||
* @param kernelWidth the width of the convolution kernel
|
||||
* @param direction the direction in which to apply the kernel
|
||||
* Applies a 2D Gaussian blur to a given texture.
|
||||
* @param srcTexture The source texture to be blurred.
|
||||
* @param temp1 A scratch texture. Must not be NULL.
|
||||
* @param temp2 A scratch texture. May be NULL, in which case
|
||||
* srcTexture is overwritten with intermediate
|
||||
* results.
|
||||
* @param rect The destination rectangle.
|
||||
* @param sigmaX The blur's standard deviation in X.
|
||||
* @param sigmaY The blur's standard deviation in Y.
|
||||
* @return the blurred texture, which may be temp1, temp2 or srcTexture.
|
||||
*/
|
||||
void convolve(GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
const float* kernel,
|
||||
int kernelWidth,
|
||||
GrSamplerState::FilterDirection direction);
|
||||
GrTexture* gaussianBlur(GrTexture* srcTexture,
|
||||
GrAutoScratchTexture* temp1,
|
||||
GrAutoScratchTexture* temp2,
|
||||
const SkRect& rect,
|
||||
float sigmaX, float sigmaY);
|
||||
|
||||
/**
|
||||
* Applies a 1D morphology in the given direction to a rectangle of
|
||||
* pixels from a given texture.
|
||||
* @param texture the texture to read from
|
||||
* @param rect the destination rectangle
|
||||
* @param radius the radius of the morphological operator
|
||||
* @param filter the filter kernel (must be kDilate or kErode)
|
||||
* @param direction the direction in which to apply the morphology
|
||||
* Applies a 2D morphology to a given texture.
|
||||
* @param srcTexture The source texture to be blurred.
|
||||
* @param rect The destination rectangle.
|
||||
* @param temp1 A scratch texture. Must not be NULL.
|
||||
* @param temp2 A scratch texture. Must not be NULL.
|
||||
* @param filter The morphology filter. Must be kDilate_Filter or
|
||||
* kErode_Filter.
|
||||
* @param radius The morphology radius in X and Y. The filter is
|
||||
* applied to a fWidth by fHeight rectangle of
|
||||
* pixels.
|
||||
* @return the morphed texture, which may be temp1, temp2 or srcTexture.
|
||||
*/
|
||||
void applyMorphology(GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
int radius,
|
||||
GrSamplerState::Filter filter,
|
||||
GrSamplerState::FilterDirection direction);
|
||||
GrTexture* applyMorphology(GrTexture* srcTexture,
|
||||
const GrRect& rect,
|
||||
GrTexture* temp1, GrTexture* temp2,
|
||||
GrSamplerState::Filter filter,
|
||||
SkISize radius);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
|
||||
|
||||
#define MAX_BLUR_SIGMA 4.0f
|
||||
|
||||
// When we're using coverage AA but the blend is incompatible (given gpu
|
||||
// limitations) should we disable AA or draw wrong?
|
||||
#define DISABLE_COVERAGE_AA_FOR_BLEND 1
|
||||
|
@ -218,6 +220,91 @@ void gen_stencil_key_values(const GrStencilBuffer* sb,
|
|||
sb->numSamples(), v);
|
||||
}
|
||||
|
||||
void build_kernel(float sigma, float* kernel, int kernelWidth) {
|
||||
int halfWidth = (kernelWidth - 1) / 2;
|
||||
float sum = 0.0f;
|
||||
float denom = 1.0f / (2.0f * sigma * sigma);
|
||||
for (int i = 0; i < kernelWidth; ++i) {
|
||||
float x = static_cast<float>(i - halfWidth);
|
||||
// Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
|
||||
// is dropped here, since we renormalize the kernel below.
|
||||
kernel[i] = sk_float_exp(- x * x * denom);
|
||||
sum += kernel[i];
|
||||
}
|
||||
// Normalize the kernel
|
||||
float scale = 1.0f / sum;
|
||||
for (int i = 0; i < kernelWidth; ++i)
|
||||
kernel[i] *= scale;
|
||||
}
|
||||
|
||||
void scale_rect(SkRect* rect, float xScale, float yScale) {
|
||||
rect->fLeft *= xScale;
|
||||
rect->fTop *= yScale;
|
||||
rect->fRight *= xScale;
|
||||
rect->fBottom *= yScale;
|
||||
}
|
||||
|
||||
float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
|
||||
int *kernelWidth) {
|
||||
*scaleFactor = 1;
|
||||
while (sigma > MAX_BLUR_SIGMA) {
|
||||
*scaleFactor *= 2;
|
||||
sigma *= 0.5f;
|
||||
}
|
||||
*halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
|
||||
*kernelWidth = *halfWidth * 2 + 1;
|
||||
return sigma;
|
||||
}
|
||||
|
||||
void apply_morphology(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
int radius,
|
||||
GrSamplerState::Filter filter,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
ASSERT_OWNED_RESOURCE(texture);
|
||||
GrAssert(filter == GrSamplerState::kErode_Filter ||
|
||||
filter == GrSamplerState::kDilate_Filter);
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(gpu);
|
||||
GrDrawState* drawState = gpu->drawState();
|
||||
GrRenderTarget* target = drawState->getRenderTarget();
|
||||
drawState->reset();
|
||||
drawState->setRenderTarget(target);
|
||||
GrMatrix sampleM;
|
||||
sampleM.setIDiv(texture->width(), texture->height());
|
||||
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
|
||||
sampleM);
|
||||
drawState->sampler(0)->setMorphologyRadius(radius);
|
||||
drawState->sampler(0)->setFilterDirection(direction);
|
||||
drawState->setTexture(0, texture);
|
||||
gpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
}
|
||||
|
||||
void convolve(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
const float* kernel,
|
||||
int kernelWidth,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
ASSERT_OWNED_RESOURCE(texture);
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(gpu);
|
||||
GrDrawState* drawState = gpu->drawState();
|
||||
GrRenderTarget* target = drawState->getRenderTarget();
|
||||
drawState->reset();
|
||||
drawState->setRenderTarget(target);
|
||||
GrMatrix sampleM;
|
||||
sampleM.setIDiv(texture->width(), texture->height());
|
||||
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
|
||||
GrSamplerState::kConvolution_Filter,
|
||||
sampleM);
|
||||
drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
|
||||
drawState->sampler(0)->setFilterDirection(direction);
|
||||
drawState->setTexture(0, texture);
|
||||
gpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GrContext::TextureCacheEntry GrContext::findAndLockTexture(
|
||||
|
@ -2005,52 +2092,151 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
|
|||
return fGpu->getQuadIndexBuffer();
|
||||
}
|
||||
|
||||
void GrContext::convolve(GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
const float* kernel,
|
||||
int kernelWidth,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
ASSERT_OWNED_RESOURCE(texture);
|
||||
GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
|
||||
GrAutoScratchTexture* temp1,
|
||||
GrAutoScratchTexture* temp2,
|
||||
const SkRect& rect,
|
||||
float sigmaX, float sigmaY) {
|
||||
GrRenderTarget* oldRenderTarget = this->getRenderTarget();
|
||||
GrClip oldClip = this->getClip();
|
||||
GrTexture* origTexture = srcTexture;
|
||||
GrAutoMatrix avm(this, GrMatrix::I());
|
||||
SkIRect clearRect;
|
||||
int scaleFactorX, halfWidthX, kernelWidthX;
|
||||
int scaleFactorY, halfWidthY, kernelWidthY;
|
||||
sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
|
||||
sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(fGpu);
|
||||
GrDrawState* drawState = fGpu->drawState();
|
||||
GrRenderTarget* target = drawState->getRenderTarget();
|
||||
drawState->reset();
|
||||
drawState->setRenderTarget(target);
|
||||
GrMatrix sampleM;
|
||||
sampleM.setIDiv(texture->width(), texture->height());
|
||||
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
|
||||
GrSamplerState::kConvolution_Filter,
|
||||
sampleM);
|
||||
drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
|
||||
drawState->sampler(0)->setFilterDirection(direction);
|
||||
drawState->setTexture(0, texture);
|
||||
fGpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
SkRect srcRect(rect);
|
||||
scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
||||
srcRect.roundOut();
|
||||
scale_rect(&srcRect, scaleFactorX, scaleFactorY);
|
||||
this->setClip(srcRect);
|
||||
|
||||
const GrTextureDesc desc = {
|
||||
kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
|
||||
srcRect.width(),
|
||||
srcRect.height(),
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
{0} // samples
|
||||
};
|
||||
|
||||
temp1->set(this, desc);
|
||||
if (temp2) temp2->set(this, desc);
|
||||
|
||||
GrTexture* dstTexture = temp1->texture();
|
||||
GrPaint paint;
|
||||
paint.reset();
|
||||
paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
|
||||
|
||||
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
|
||||
paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
|
||||
srcTexture->height());
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
SkRect dstRect(srcRect);
|
||||
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
|
||||
i < scaleFactorY ? 0.5f : 1.0f);
|
||||
paint.setTexture(0, srcTexture);
|
||||
this->drawRectToRect(paint, dstRect, srcRect);
|
||||
srcRect = dstRect;
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
// If temp2 is non-NULL, don't render back to origTexture
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (sigmaX > 0.0f) {
|
||||
SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
|
||||
float* kernelX = kernelStorageX.get();
|
||||
build_kernel(sigmaX, kernelX, kernelWidthX);
|
||||
|
||||
if (scaleFactorX > 1) {
|
||||
// Clear out a halfWidth to the right of the srcRect to prevent the
|
||||
// X convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
|
||||
this->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (sigmaY > 0.0f) {
|
||||
SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
|
||||
float* kernelY = kernelStorageY.get();
|
||||
build_kernel(sigmaY, kernelY, kernelWidthY);
|
||||
|
||||
if (scaleFactorY > 1 || sigmaX > 0.0f) {
|
||||
// Clear out a halfWidth below the srcRect to prevent the Y
|
||||
// convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
|
||||
this->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (scaleFactorX > 1 || scaleFactorY > 1) {
|
||||
// Clear one pixel to the right and below, to accommodate bilinear
|
||||
// upsampling.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
|
||||
this->clear(&clearRect, 0x0);
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fRight, srcRect.fTop, 1, srcRect.height());
|
||||
this->clear(&clearRect, 0x0);
|
||||
// FIXME: This should be mitchell, not bilinear.
|
||||
paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
|
||||
paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
|
||||
srcTexture->height());
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
paint.setTexture(0, srcTexture);
|
||||
SkRect dstRect(srcRect);
|
||||
scale_rect(&dstRect, scaleFactorX, scaleFactorY);
|
||||
this->drawRectToRect(paint, dstRect, srcRect);
|
||||
srcRect = dstRect;
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
}
|
||||
this->setRenderTarget(oldRenderTarget);
|
||||
this->setClip(oldClip);
|
||||
return srcTexture;
|
||||
}
|
||||
|
||||
void GrContext::applyMorphology(GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
int radius,
|
||||
GrSamplerState::Filter filter,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
ASSERT_OWNED_RESOURCE(texture);
|
||||
GrAssert(filter == GrSamplerState::kErode_Filter ||
|
||||
filter == GrSamplerState::kDilate_Filter);
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(fGpu);
|
||||
GrDrawState* drawState = fGpu->drawState();
|
||||
GrRenderTarget* target = drawState->getRenderTarget();
|
||||
drawState->reset();
|
||||
drawState->setRenderTarget(target);
|
||||
GrMatrix sampleM;
|
||||
sampleM.setIDiv(texture->width(), texture->height());
|
||||
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
|
||||
filter,
|
||||
sampleM);
|
||||
drawState->sampler(0)->setMorphologyRadius(radius);
|
||||
drawState->sampler(0)->setFilterDirection(direction);
|
||||
drawState->setTexture(0, texture);
|
||||
fGpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
|
||||
const GrRect& rect,
|
||||
GrTexture* temp1, GrTexture* temp2,
|
||||
GrSamplerState::Filter filter,
|
||||
SkISize radius) {
|
||||
GrRenderTarget* oldRenderTarget = this->getRenderTarget();
|
||||
GrAutoMatrix avm(this, GrMatrix::I());
|
||||
GrClip oldClip = this->getClip();
|
||||
this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
|
||||
if (radius.fWidth > 0) {
|
||||
this->setRenderTarget(temp1->asRenderTarget());
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
|
||||
rect.width(), radius.fHeight);
|
||||
this->clear(&clearRect, 0x0);
|
||||
srcTexture = temp1;
|
||||
}
|
||||
if (radius.fHeight > 0) {
|
||||
this->setRenderTarget(temp2->asRenderTarget());
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
srcTexture = temp2;
|
||||
}
|
||||
this->setRenderTarget(oldRenderTarget);
|
||||
this->setClip(oldClip);
|
||||
return srcTexture;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -719,198 +719,6 @@ static GrPathFill skToGrFillType(SkPath::FillType fillType) {
|
|||
}
|
||||
}
|
||||
|
||||
static GrTexture* applyMorphology(GrContext* context, GrTexture* texture,
|
||||
const GrRect& srcRect,
|
||||
GrTexture* temp1, GrTexture* temp2,
|
||||
GrSamplerState::Filter filter,
|
||||
SkISize radius) {
|
||||
GrRenderTarget* oldRenderTarget = context->getRenderTarget();
|
||||
GrAutoMatrix avm(context, GrMatrix::I());
|
||||
GrClip oldClip = context->getClip();
|
||||
context->setClip(GrRect::MakeWH(texture->width(), texture->height()));
|
||||
if (radius.fWidth > 0) {
|
||||
context->setRenderTarget(temp1->asRenderTarget());
|
||||
context->applyMorphology(texture, srcRect, radius.fWidth, filter,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fLeft, srcRect.fBottom,
|
||||
srcRect.width(), radius.fHeight);
|
||||
context->clear(&clearRect, 0x0);
|
||||
texture = temp1;
|
||||
}
|
||||
if (radius.fHeight > 0) {
|
||||
context->setRenderTarget(temp2->asRenderTarget());
|
||||
context->applyMorphology(texture, srcRect, radius.fHeight, filter,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
texture = temp2;
|
||||
}
|
||||
context->setRenderTarget(oldRenderTarget);
|
||||
context->setClip(oldClip);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static void buildKernel(float sigma, float* kernel, int kernelWidth) {
|
||||
int halfWidth = (kernelWidth - 1) / 2;
|
||||
float sum = 0.0f;
|
||||
float denom = 1.0f / (2.0f * sigma * sigma);
|
||||
for (int i = 0; i < kernelWidth; ++i) {
|
||||
float x = static_cast<float>(i - halfWidth);
|
||||
// Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
|
||||
// is dropped here, since we renormalize the kernel below.
|
||||
kernel[i] = sk_float_exp(- x * x * denom);
|
||||
sum += kernel[i];
|
||||
}
|
||||
// Normalize the kernel
|
||||
float scale = 1.0f / sum;
|
||||
for (int i = 0; i < kernelWidth; ++i)
|
||||
kernel[i] *= scale;
|
||||
}
|
||||
|
||||
static void scaleRect(SkRect* rect, float xScale, float yScale) {
|
||||
rect->fLeft *= xScale;
|
||||
rect->fTop *= yScale;
|
||||
rect->fRight *= xScale;
|
||||
rect->fBottom *= yScale;
|
||||
}
|
||||
|
||||
static float adjustSigma(float sigma, int *scaleFactor, int *halfWidth,
|
||||
int *kernelWidth) {
|
||||
*scaleFactor = 1;
|
||||
while (sigma > MAX_BLUR_SIGMA) {
|
||||
*scaleFactor *= 2;
|
||||
sigma *= 0.5f;
|
||||
}
|
||||
*halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
|
||||
*kernelWidth = *halfWidth * 2 + 1;
|
||||
return sigma;
|
||||
}
|
||||
|
||||
// Apply a Gaussian blur to srcTexture by sigmaX and sigmaY, within the given
|
||||
// rect.
|
||||
// temp1 and temp2 are used for allocation of intermediate textures.
|
||||
// If temp2 is non-NULL, srcTexture will be untouched, and the return
|
||||
// value will be either temp1 or temp2.
|
||||
// If temp2 is NULL, srcTexture will be overwritten with intermediate
|
||||
// results, and the return value will either be temp1 or srcTexture.
|
||||
static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture,
|
||||
GrAutoScratchTexture* temp1,
|
||||
GrAutoScratchTexture* temp2,
|
||||
const SkRect& rect,
|
||||
float sigmaX, float sigmaY) {
|
||||
|
||||
GrRenderTarget* oldRenderTarget = context->getRenderTarget();
|
||||
GrClip oldClip = context->getClip();
|
||||
GrTexture* origTexture = srcTexture;
|
||||
GrAutoMatrix avm(context, GrMatrix::I());
|
||||
SkIRect clearRect;
|
||||
int scaleFactorX, halfWidthX, kernelWidthX;
|
||||
int scaleFactorY, halfWidthY, kernelWidthY;
|
||||
sigmaX = adjustSigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
|
||||
sigmaY = adjustSigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
|
||||
|
||||
SkRect srcRect(rect);
|
||||
scaleRect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
||||
srcRect.roundOut();
|
||||
scaleRect(&srcRect, scaleFactorX, scaleFactorY);
|
||||
context->setClip(srcRect);
|
||||
|
||||
const GrTextureDesc desc = {
|
||||
kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
|
||||
srcRect.width(),
|
||||
srcRect.height(),
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
{0} // samples
|
||||
};
|
||||
|
||||
temp1->set(context, desc);
|
||||
if (temp2) temp2->set(context, desc);
|
||||
|
||||
GrTexture* dstTexture = temp1->texture();
|
||||
GrPaint paint;
|
||||
paint.reset();
|
||||
paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
|
||||
|
||||
for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
|
||||
paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
|
||||
srcTexture->height());
|
||||
context->setRenderTarget(dstTexture->asRenderTarget());
|
||||
SkRect dstRect(srcRect);
|
||||
scaleRect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
|
||||
i < scaleFactorY ? 0.5f : 1.0f);
|
||||
paint.setTexture(0, srcTexture);
|
||||
context->drawRectToRect(paint, dstRect, srcRect);
|
||||
srcRect = dstRect;
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
// If temp2 is non-NULL, don't render back to origTexture
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (sigmaX > 0.0f) {
|
||||
SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
|
||||
float* kernelX = kernelStorageX.get();
|
||||
buildKernel(sigmaX, kernelX, kernelWidthX);
|
||||
|
||||
if (scaleFactorX > 1) {
|
||||
// Clear out a halfWidth to the right of the srcRect to prevent the
|
||||
// X convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
|
||||
context->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
context->setRenderTarget(dstTexture->asRenderTarget());
|
||||
context->convolve(srcTexture, srcRect, kernelX, kernelWidthX,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (sigmaY > 0.0f) {
|
||||
SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
|
||||
float* kernelY = kernelStorageY.get();
|
||||
buildKernel(sigmaY, kernelY, kernelWidthY);
|
||||
|
||||
if (scaleFactorY > 1 || sigmaX > 0.0f) {
|
||||
// Clear out a halfWidth below the srcRect to prevent the Y
|
||||
// convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
|
||||
context->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
context->setRenderTarget(dstTexture->asRenderTarget());
|
||||
context->convolve(srcTexture, srcRect, kernelY, kernelWidthY,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
|
||||
}
|
||||
|
||||
if (scaleFactorX > 1 || scaleFactorY > 1) {
|
||||
// Clear one pixel to the right and below, to accommodate bilinear
|
||||
// upsampling.
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
|
||||
context->clear(&clearRect, 0x0);
|
||||
clearRect = SkIRect::MakeXYWH(
|
||||
srcRect.fRight, srcRect.fTop, 1, srcRect.height());
|
||||
context->clear(&clearRect, 0x0);
|
||||
// FIXME: This should be mitchell, not bilinear.
|
||||
paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
|
||||
paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
|
||||
srcTexture->height());
|
||||
context->setRenderTarget(dstTexture->asRenderTarget());
|
||||
paint.setTexture(0, srcTexture);
|
||||
SkRect dstRect(srcRect);
|
||||
scaleRect(&dstRect, scaleFactorX, scaleFactorY);
|
||||
context->drawRectToRect(paint, dstRect, srcRect);
|
||||
srcRect = dstRect;
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
}
|
||||
context->setRenderTarget(oldRenderTarget);
|
||||
context->setClip(oldClip);
|
||||
return srcTexture;
|
||||
}
|
||||
|
||||
static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
|
||||
SkMaskFilter* filter, const SkMatrix& matrix,
|
||||
const SkRegion& clip, SkBounder* bounder,
|
||||
|
@ -995,9 +803,10 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
|
|||
// If we're doing a normal blur, we can clobber the pathTexture in the
|
||||
// gaussianBlur. Otherwise, we need to save it for later compositing.
|
||||
bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType;
|
||||
GrTexture* blurTexture = gaussianBlur(context, pathTexture,
|
||||
&temp1, isNormalBlur ? NULL : &temp2,
|
||||
srcRect, sigma, sigma);
|
||||
GrTexture* blurTexture = context->gaussianBlur(pathTexture,
|
||||
&temp1,
|
||||
isNormalBlur ? NULL : &temp2,
|
||||
srcRect, sigma, sigma);
|
||||
|
||||
if (!isNormalBlur) {
|
||||
GrPaint paint;
|
||||
|
@ -1538,11 +1347,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
|||
SkISize radius;
|
||||
if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) {
|
||||
GrAutoScratchTexture temp1, temp2;
|
||||
GrTexture* blurTexture = gaussianBlur(fContext,
|
||||
texture, &temp1, &temp2,
|
||||
GrRect::MakeWH(w, h),
|
||||
blurSize.width(),
|
||||
blurSize.height());
|
||||
GrTexture* blurTexture = fContext->gaussianBlur(texture, &temp1, &temp2,
|
||||
GrRect::MakeWH(w, h),
|
||||
blurSize.width(),
|
||||
blurSize.height());
|
||||
texture = blurTexture;
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else if (NULL != imageFilter && imageFilter->asADilate(&radius)) {
|
||||
|
@ -1554,9 +1362,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
|||
{0} // samples
|
||||
};
|
||||
GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
|
||||
texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kDilate_Filter, radius);
|
||||
texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kDilate_Filter,
|
||||
radius);
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) {
|
||||
const GrTextureDesc desc = {
|
||||
|
@ -1567,9 +1376,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
|||
{0} // samples
|
||||
};
|
||||
GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc);
|
||||
texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kErode_Filter, radius);
|
||||
texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h),
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kErode_Filter,
|
||||
radius);
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
} else {
|
||||
grPaint.setTexture(kBitmapTextureIdx, texture);
|
||||
|
|
Загрузка…
Ссылка в новой задаче