diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-02 21:05:45 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-02 21:05:45 +0000 |
commit | 05054f1a78a697b507580d0025db6c90423e033f (patch) | |
tree | fa00f0862980cdc712f21d2d792d59fe070ebcaa /src/gpu | |
parent | c8ccfb0fbadfdcadcc860bc648c5ac42aa9277b1 (diff) |
Erode and dilate image filter effects, CPU and GPU implementations.
Review URL: http://codereview.appspot.com/5656067/
git-svn-id: http://skia.googlecode.com/svn/trunk@3310 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 53 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 66 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 78 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGLShaders.cpp | 31 |
6 files changed, 202 insertions, 32 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 2de978f757..d6ebada82a 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -2007,31 +2007,11 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { return fGpu->getQuadIndexBuffer(); } -void GrContext::convolveInX(GrTexture* texture, - const SkRect& rect, - const float* kernel, - int kernelWidth) { - ASSERT_OWNED_RESOURCE(texture); - - float imageIncrement[2] = {1.0f / texture->width(), 0.0f}; - convolve(texture, rect, imageIncrement, kernel, kernelWidth); -} - -void GrContext::convolveInY(GrTexture* texture, - const SkRect& rect, - const float* kernel, - int kernelWidth) { - ASSERT_OWNED_RESOURCE(texture); - - float imageIncrement[2] = {0.0f, 1.0f / texture->height()}; - convolve(texture, rect, imageIncrement, kernel, kernelWidth); -} - void GrContext::convolve(GrTexture* texture, const SkRect& rect, - float imageIncrement[2], const float* kernel, - int kernelWidth) { + int kernelWidth, + GrSamplerState::FilterDirection direction) { ASSERT_OWNED_RESOURCE(texture); GrDrawTarget::AutoStateRestore asr(fGpu); @@ -2044,10 +2024,33 @@ void GrContext::convolve(GrTexture* texture, drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, GrSamplerState::kConvolution_Filter, sampleM); - drawState->sampler(0)->setConvolutionParams(kernelWidth, - kernel, - imageIncrement); + drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel); + drawState->sampler(0)->setFilterDirection(direction); + drawState->setTexture(0, texture); + fGpu->drawSimpleRect(rect, NULL, 1 << 0); +} +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); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 94ac5d2cba..af59699654 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -698,6 +698,36 @@ 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; @@ -808,7 +838,8 @@ static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture, } context->setRenderTarget(dstTexture->asRenderTarget()); - context->convolveInX(srcTexture, srcRect, kernelX, kernelWidthX); + context->convolve(srcTexture, srcRect, kernelX, kernelWidthX, + GrSamplerState::kX_FilterDirection); SkTSwap(srcTexture, dstTexture); if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); } @@ -827,7 +858,8 @@ static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture, } context->setRenderTarget(dstTexture->asRenderTarget()); - context->convolveInY(srcTexture, srcRect, kernelY, kernelWidthY); + context->convolve(srcTexture, srcRect, kernelY, kernelWidthY, + GrSamplerState::kY_FilterDirection); SkTSwap(srcTexture, dstTexture); if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); } @@ -1481,6 +1513,7 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, SkImageFilter* imageFilter = paint.getImageFilter(); SkSize blurSize; + SkISize radius; if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) { GrAutoScratchTexture temp1, temp2; GrTexture* blurTexture = gaussianBlur(fContext, @@ -1490,6 +1523,32 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, blurSize.height()); texture = blurTexture; grPaint.setTexture(kBitmapTextureIdx, texture); + } else if (NULL != imageFilter && imageFilter->asADilate(&radius)) { + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit, + w, + h, + kRGBA_8888_PM_GrPixelConfig, + {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); + grPaint.setTexture(kBitmapTextureIdx, texture); + } else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) { + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit, + w, + h, + kRGBA_8888_PM_GrPixelConfig, + {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); + grPaint.setTexture(kBitmapTextureIdx, texture); } else { grPaint.setTexture(kBitmapTextureIdx, texture); } @@ -1541,7 +1600,8 @@ bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { SkSize size; - if (!filter->asABlur(&size)) { + SkISize radius; + if (!filter->asABlur(&size) && !filter->asADilate(&radius) && !filter->asAnErode(&radius)) { return false; } SkDevice* dev = this->createCompatibleDevice(SkBitmap::kARGB_8888_Config, diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 7eecf914c0..29252131a5 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -166,6 +166,11 @@ inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i->appendS32(stage); } +inline void image_increment_param_name(int stage, GrStringBuilder* i) { + *i = "uImageIncrement"; + i->appendS32(stage); +} + inline void tex_domain_name(int stage, GrStringBuilder* s) { *s = "uTexDom"; s->appendS32(stage); @@ -1655,6 +1660,68 @@ void genConvolutionFS(int stageNum, segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor, sumVar.c_str(), modulate.c_str()); } + +void genMorphologyVS(int stageNum, + const StageDesc& desc, + ShaderCodeSegments* segments, + GrGLProgram::StageUniLocations* locations, + const char** imageIncrementName, + const char* varyingVSName) { + GrGLShaderVar* imgInc = &segments->fFSUnis.push_back(); + imgInc->setType(GrGLShaderVar::kVec2f_Type); + imgInc->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); + + image_increment_param_name(stageNum, imgInc->accessName()); + *imageIncrementName = imgInc->getName().c_str(); + + // need image increment in both VS and FS + segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true); + + locations->fImageIncrementUni = kUseUniform; + segments->fVSCode.appendf("\t%s -= vec2(%d, %d) * %s;\n", + varyingVSName, desc.fKernelWidth, + desc.fKernelWidth, *imageIncrementName); +} + +void genMorphologyFS(int stageNum, + const StageDesc& desc, + ShaderCodeSegments* segments, + const char* samplerName, + const char* swizzle, + const char* imageIncrementName, + const char* fsOutColor, + GrStringBuilder& sampleCoords, + GrStringBuilder& texFunc, + GrStringBuilder& modulate) { + GrStringBuilder valueVar("value"); + valueVar.appendS32(stageNum); + GrStringBuilder coordVar("coord"); + coordVar.appendS32(stageNum); + bool isDilate = StageDesc::kDilate_FetchMode == desc.fFetchMode; + + if (isDilate) { + segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n", + valueVar.c_str()); + } else { + segments->fFSCode.appendf("\tvec4 %s = vec4(1, 1, 1, 1);\n", + valueVar.c_str()); + } + segments->fFSCode.appendf("\tvec2 %s = %s;\n", + coordVar.c_str(), + sampleCoords.c_str()); + segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n", + desc.fKernelWidth * 2 + 1); + segments->fFSCode.appendf("\t\t%s = %s(%s, %s(%s, %s)%s);\n", + valueVar.c_str(), isDilate ? "max" : "min", + valueVar.c_str(), texFunc.c_str(), + samplerName, coordVar.c_str(), swizzle); + segments->fFSCode.appendf("\t\t%s += %s;\n", + coordVar.c_str(), + imageIncrementName); + segments->fFSCode.appendf("\t}\n"); + segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor, + valueVar.c_str(), modulate.c_str()); +} } @@ -1755,6 +1822,10 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, if (StageDesc::kConvolution_FetchMode == desc.fFetchMode) { genConvolutionVS(stageNum, desc, segments, locations, &kernel, &imageIncrementName, varyingVSName); + } else if (StageDesc::kDilate_FetchMode == desc.fFetchMode || + StageDesc::kErode_FetchMode == desc.fFetchMode) { + genMorphologyVS(stageNum, desc, segments, locations, + &imageIncrementName, varyingVSName); } /// Fragment Shader Stuff @@ -1866,6 +1937,13 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, samplerName, kernel, swizzle, imageIncrementName, fsOutColor, sampleCoords, texFunc, modulate); break; + case StageDesc::kDilate_FetchMode: + case StageDesc::kErode_FetchMode: + GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask)); + genMorphologyFS(stageNum, desc, segments, + samplerName, swizzle, imageIncrementName, fsOutColor, + sampleCoords, texFunc, modulate); + break; default: if (desc.fInConfigFlags & kMulByAlphaMask) { // only one of the mul by alpha flags should be set diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index e9030bc793..76f9c9006f 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -110,6 +110,8 @@ public: kSingle_FetchMode, k2x2_FetchMode, kConvolution_FetchMode, + kErode_FetchMode, + kDilate_FetchMode, kFetchModeCnt, }; diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index bee2017272..69880e5555 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -445,7 +445,7 @@ void GrGpuGL::onResetContext() { -GR_ScalarMax, true); *fHWDrawState.sampler(s)->matrix() = GrMatrix::InvalidMatrix(); - fHWDrawState.sampler(s)->setConvolutionParams(0, NULL, NULL); + fHWDrawState.sampler(s)->setConvolutionParams(0, NULL); } fHWBounds.fScissorRect.invalidate(); @@ -1935,6 +1935,8 @@ unsigned gr_to_gl_filter(GrSamplerState::Filter filter) { return GR_GL_LINEAR; case GrSamplerState::kNearest_Filter: case GrSamplerState::kConvolution_Filter: + case GrSamplerState::kErode_Filter: + case GrSamplerState::kDilate_Filter: return GR_GL_NEAREST; default: GrAssert(!"Unknown filter type"); diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp index a0a2df5802..db7e3a7f76 100644 --- a/src/gpu/gl/GrGpuGLShaders.cpp +++ b/src/gpu/gl/GrGpuGLShaders.cpp @@ -261,7 +261,9 @@ bool GrGpuGLShaders::programUnitTest() { stage.fCoordMapping = random_int(&random, StageDesc::kCoordMappingCnt); stage.fFetchMode = random_int(&random, StageDesc::kFetchModeCnt); // convolution shaders don't work with persp tex matrix - if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) { + if (stage.fFetchMode == StageDesc::kConvolution_FetchMode || + stage.fFetchMode == StageDesc::kDilate_FetchMode || + stage.fFetchMode == StageDesc::kErode_FetchMode) { stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit; } stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout)); @@ -273,6 +275,8 @@ bool GrGpuGLShaders::programUnitTest() { stage.fKernelWidth = 0; break; case StageDesc::kConvolution_FetchMode: + case StageDesc::kDilate_FetchMode: + case StageDesc::kErode_FetchMode: stage.fKernelWidth = random_int(&random, 2, 8); stage.fInConfigFlags &= ~kMulByAlphaMask; break; @@ -560,7 +564,20 @@ void GrGpuGLShaders::flushConvolution(int s) { } int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni; if (GrGLProgram::kUnusedUniform != imageIncrementUni) { - GL_CALL(Uniform2fv(imageIncrementUni, 1, sampler.getImageIncrement())); + const GrGLTexture* texture = + static_cast<const GrGLTexture*>(this->getDrawState().getTexture(s)); + float imageIncrement[2] = { 0 }; + switch (sampler.getFilterDirection()) { + case GrSamplerState::kX_FilterDirection: + imageIncrement[0] = 1.0f / texture->width(); + break; + case GrSamplerState::kY_FilterDirection: + imageIncrement[1] = 1.0f / texture->height(); + break; + default: + GrCrash("Unknown filter direction."); + } + GL_CALL(Uniform2fv(imageIncrementUni, 1, imageIncrement)); } } @@ -1081,6 +1098,12 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type, case GrSamplerState::kConvolution_Filter: stage.fFetchMode = StageDesc::kConvolution_FetchMode; break; + case GrSamplerState::kDilate_Filter: + stage.fFetchMode = StageDesc::kDilate_FetchMode; + break; + case GrSamplerState::kErode_Filter: + stage.fFetchMode = StageDesc::kErode_FetchMode; + break; default: GrCrash("Unexpected filter!"); break; @@ -1119,7 +1142,9 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type, } } - if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) { + if (sampler.getFilter() == GrSamplerState::kConvolution_Filter || + sampler.getFilter() == GrSamplerState::kDilate_Filter || + sampler.getFilter() == GrSamplerState::kErode_Filter) { stage.fKernelWidth = sampler.getKernelWidth(); } else { stage.fKernelWidth = 0; |