Implement morphology as a custom effect
Review URL: http://codereview.appspot.com/6250073/ git-svn-id: http://skia.googlecode.com/svn/trunk@4102 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
0d10280190
commit
b505a128ef
@ -274,8 +274,11 @@
|
||||
'../src/gpu/GrVertexBuffer.h',
|
||||
'../src/gpu/gr_unittests.cpp',
|
||||
|
||||
'../src/gpu/effects/Gr1DKernelEffect.h',
|
||||
'../src/gpu/effects/GrConvolutionEffect.cpp',
|
||||
'../src/gpu/effects/GrConvolutionEffect.h',
|
||||
'../src/gpu/effects/GrMorphologyEffect.cpp',
|
||||
'../src/gpu/effects/GrMorphologyEffect.h',
|
||||
|
||||
'../src/gpu/gl/GrGLCaps.cpp',
|
||||
'../src/gpu/gl/GrGLCaps.h',
|
||||
|
@ -616,6 +616,14 @@ public:
|
||||
const SkRect& rect,
|
||||
float sigmaX, float sigmaY);
|
||||
|
||||
/**
|
||||
* This enum is used with the function below, applyMorphology.
|
||||
*/
|
||||
enum MorphologyType {
|
||||
kErode_MorphologyType,
|
||||
kDilate_MorphologyType,
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies a 2D morphology to a given texture.
|
||||
* @param srcTexture The source texture to be blurred.
|
||||
@ -632,7 +640,7 @@ public:
|
||||
GrTexture* applyMorphology(GrTexture* srcTexture,
|
||||
const GrRect& rect,
|
||||
GrTexture* temp1, GrTexture* temp2,
|
||||
GrSamplerState::Filter filter,
|
||||
MorphologyType type,
|
||||
SkISize radius);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
For equivalence (that they will generate the same
|
||||
shader, but perhaps have different uniforms), check equality
|
||||
of the stageKey produced by the GrProgramStageFactory. */
|
||||
virtual bool isEqual(const GrCustomStage *) const = 0;
|
||||
virtual bool isEqual(const GrCustomStage&) const = 0;
|
||||
|
||||
/** Human-meaningful string to identify this effect; may be embedded
|
||||
in generated shader code. */
|
||||
|
@ -26,9 +26,9 @@ public:
|
||||
kProgramStageKeyBits = 10,
|
||||
};
|
||||
|
||||
virtual StageKey glStageKey(const GrCustomStage* stage) const = 0;
|
||||
virtual StageKey glStageKey(const GrCustomStage& stage) const = 0;
|
||||
virtual GrGLProgramStage* createGLInstance(
|
||||
const GrCustomStage* stage) const = 0;
|
||||
const GrCustomStage& stage) const = 0;
|
||||
|
||||
bool operator ==(const GrProgramStageFactory& b) const {
|
||||
return fStageClassID == b.fStageClassID;
|
||||
@ -79,7 +79,7 @@ public:
|
||||
id identifies the GrCustomShader subclass. The remainder is based
|
||||
on the aspects of the GrCustomStage object's configuration that affect
|
||||
GLSL code generation. */
|
||||
virtual StageKey glStageKey(const GrCustomStage* stage) const SK_OVERRIDE {
|
||||
virtual StageKey glStageKey(const GrCustomStage& stage) const SK_OVERRIDE {
|
||||
GrAssert(kIllegalStageClassID != fStageClassID);
|
||||
StageKey stageID = GLProgramStage::GenKey(stage);
|
||||
#if GR_DEBUG
|
||||
@ -94,7 +94,7 @@ public:
|
||||
for the given GrCustomStage; caller is responsible for deleting
|
||||
the object. */
|
||||
virtual GLProgramStage* createGLInstance(
|
||||
const GrCustomStage* stage) const SK_OVERRIDE {
|
||||
const GrCustomStage& stage) const SK_OVERRIDE {
|
||||
return new GLProgramStage(*this, stage);
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
#include "GrMatrix.h"
|
||||
#include "GrTypes.h"
|
||||
|
||||
#define MAX_KERNEL_WIDTH 25
|
||||
|
||||
class GrSamplerState {
|
||||
public:
|
||||
enum Filter {
|
||||
@ -36,18 +34,6 @@ public:
|
||||
* on shader backends.
|
||||
*/
|
||||
k4x4Downsample_Filter,
|
||||
/**
|
||||
* Apply a separable convolution kernel.
|
||||
*/
|
||||
kConvolution_Filter,
|
||||
/**
|
||||
* Apply a dilate filter (max over a 1D radius).
|
||||
*/
|
||||
kDilate_Filter,
|
||||
/**
|
||||
* Apply an erode filter (min over a 1D radius).
|
||||
*/
|
||||
kErode_Filter,
|
||||
|
||||
kDefault_Filter = kNearest_Filter
|
||||
};
|
||||
@ -95,17 +81,6 @@ public:
|
||||
kDefault_WrapMode = kClamp_WrapMode
|
||||
};
|
||||
|
||||
/**
|
||||
* For the filters which perform more than one texture sample (convolution,
|
||||
* erode, dilate), this determines the direction in which the texture
|
||||
* coordinates will be incremented.
|
||||
*/
|
||||
enum FilterDirection {
|
||||
kX_FilterDirection,
|
||||
kY_FilterDirection,
|
||||
|
||||
kDefault_FilterDirection = kX_FilterDirection,
|
||||
};
|
||||
/**
|
||||
* Default sampler state is set to clamp, use normal sampling mode, be
|
||||
* unfiltered, and use identity matrix.
|
||||
@ -135,7 +110,7 @@ public:
|
||||
(fCustomStage && s.fCustomStage &&
|
||||
(fCustomStage->getFactory() ==
|
||||
s.fCustomStage->getFactory()) &&
|
||||
fCustomStage->isEqual(s.fCustomStage)));
|
||||
fCustomStage->isEqual(*s.fCustomStage)));
|
||||
}
|
||||
bool operator !=(const GrSamplerState& s) const { return !(*this == s); }
|
||||
|
||||
@ -143,7 +118,6 @@ public:
|
||||
// memcpy() breaks refcounting
|
||||
fWrapX = s.fWrapX;
|
||||
fWrapY = s.fWrapY;
|
||||
fFilterDirection = s.fFilterDirection;
|
||||
fSampleMode = s.fSampleMode;
|
||||
fFilter = s.fFilter;
|
||||
fMatrix = s.fMatrix;
|
||||
@ -154,11 +128,6 @@ public:
|
||||
fRadial2Radius0 = s.fRadial2Radius0;
|
||||
fRadial2PosRoot = s.fRadial2PosRoot;
|
||||
|
||||
fKernelWidth = s.fKernelWidth;
|
||||
if (kConvolution_Filter == fFilter) {
|
||||
memcpy(fKernel, s.fKernel, MAX_KERNEL_WIDTH * sizeof(float));
|
||||
}
|
||||
|
||||
fCustomStage = s.fCustomStage;
|
||||
SkSafeRef(fCustomStage);
|
||||
|
||||
@ -167,16 +136,12 @@ public:
|
||||
|
||||
WrapMode getWrapX() const { return fWrapX; }
|
||||
WrapMode getWrapY() const { return fWrapY; }
|
||||
FilterDirection getFilterDirection() const { return fFilterDirection; }
|
||||
SampleMode getSampleMode() const { return fSampleMode; }
|
||||
const GrMatrix& getMatrix() const { return fMatrix; }
|
||||
const GrRect& getTextureDomain() const { return fTextureDomain; }
|
||||
bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
|
||||
Filter getFilter() const { return fFilter; }
|
||||
int getKernelWidth() const { return fKernelWidth; }
|
||||
const float* getKernel() const { return fKernel; }
|
||||
bool swapsRAndB() const { return fSwapRAndB; }
|
||||
|
||||
bool isGradient() const {
|
||||
return kRadial_SampleMode == fSampleMode ||
|
||||
kRadial2_SampleMode == fSampleMode ||
|
||||
@ -186,7 +151,6 @@ public:
|
||||
void setWrapX(WrapMode mode) { fWrapX = mode; }
|
||||
void setWrapY(WrapMode mode) { fWrapY = mode; }
|
||||
void setSampleMode(SampleMode mode) { fSampleMode = mode; }
|
||||
void setFilterDirection(FilterDirection mode) { fFilterDirection = mode; }
|
||||
|
||||
/**
|
||||
* Access the sampler's matrix. See SampleMode for explanation of
|
||||
@ -227,30 +191,24 @@ public:
|
||||
|
||||
void reset(WrapMode wrapXAndY,
|
||||
Filter filter,
|
||||
FilterDirection direction,
|
||||
const GrMatrix& matrix) {
|
||||
fWrapX = wrapXAndY;
|
||||
fWrapY = wrapXAndY;
|
||||
fSampleMode = kDefault_SampleMode;
|
||||
fFilter = filter;
|
||||
fFilterDirection = direction;
|
||||
fMatrix = matrix;
|
||||
fTextureDomain.setEmpty();
|
||||
fSwapRAndB = false;
|
||||
GrSafeSetNull(fCustomStage);
|
||||
}
|
||||
void reset(WrapMode wrapXAndY, Filter filter, const GrMatrix& matrix) {
|
||||
this->reset(wrapXAndY, filter, kDefault_FilterDirection, matrix);
|
||||
}
|
||||
void reset(WrapMode wrapXAndY,
|
||||
Filter filter) {
|
||||
this->reset(wrapXAndY, filter, kDefault_FilterDirection, GrMatrix::I());
|
||||
void reset(WrapMode wrapXAndY, Filter filter) {
|
||||
this->reset(wrapXAndY, filter, GrMatrix::I());
|
||||
}
|
||||
void reset(const GrMatrix& matrix) {
|
||||
this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, matrix);
|
||||
this->reset(kDefault_WrapMode, kDefault_Filter, matrix);
|
||||
}
|
||||
void reset() {
|
||||
this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, GrMatrix::I());
|
||||
this->reset(kDefault_WrapMode, kDefault_Filter, GrMatrix::I());
|
||||
}
|
||||
|
||||
GrScalar getRadial2CenterX1() const { return fRadial2CenterX1; }
|
||||
@ -273,19 +231,6 @@ public:
|
||||
fRadial2PosRoot = posRoot;
|
||||
}
|
||||
|
||||
void setConvolutionParams(int kernelWidth, const float* kernel) {
|
||||
GrAssert(kernelWidth >= 0 && kernelWidth <= MAX_KERNEL_WIDTH);
|
||||
fKernelWidth = kernelWidth;
|
||||
if (NULL != kernel) {
|
||||
memcpy(fKernel, kernel, kernelWidth * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
void setMorphologyRadius(int radius) {
|
||||
GrAssert(radius >= 0 && radius <= MAX_KERNEL_WIDTH);
|
||||
fKernelWidth = radius;
|
||||
}
|
||||
|
||||
void setCustomStage(GrCustomStage* stage) {
|
||||
GrSafeAssign(fCustomStage, stage);
|
||||
}
|
||||
@ -294,7 +239,6 @@ public:
|
||||
private:
|
||||
WrapMode fWrapX : 8;
|
||||
WrapMode fWrapY : 8;
|
||||
FilterDirection fFilterDirection : 8;
|
||||
SampleMode fSampleMode : 8;
|
||||
Filter fFilter : 8;
|
||||
GrMatrix fMatrix;
|
||||
@ -306,10 +250,6 @@ private:
|
||||
GrScalar fRadial2Radius0;
|
||||
SkBool8 fRadial2PosRoot;
|
||||
|
||||
// These are undefined unless fFilter == kConvolution_Filter
|
||||
uint8_t fKernelWidth;
|
||||
float fKernel[MAX_KERNEL_WIDTH];
|
||||
|
||||
GrCustomStage* fCustomStage;
|
||||
};
|
||||
|
||||
|
@ -9,9 +9,11 @@
|
||||
|
||||
#include "GrContext.h"
|
||||
|
||||
#include "effects/GrMorphologyEffect.h"
|
||||
#include "effects/GrConvolutionEffect.h"
|
||||
|
||||
#include "GrBufferAllocPool.h"
|
||||
#include "GrClipIterator.h"
|
||||
#include "effects/GrConvolutionEffect.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrIndexBuffer.h"
|
||||
#include "GrInOrderDrawBuffer.h"
|
||||
@ -242,23 +244,6 @@ 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 = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
|
||||
rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
|
||||
@ -266,15 +251,14 @@ void scale_rect(SkRect* rect, float xScale, float yScale) {
|
||||
rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
|
||||
}
|
||||
|
||||
float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
|
||||
int *kernelWidth) {
|
||||
float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
|
||||
*scaleFactor = 1;
|
||||
while (sigma > MAX_BLUR_SIGMA) {
|
||||
*scaleFactor *= 2;
|
||||
sigma *= 0.5f;
|
||||
}
|
||||
*halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
|
||||
*kernelWidth = *halfWidth * 2 + 1;
|
||||
*radius = static_cast<int>(ceilf(sigma * 3.0f));
|
||||
GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
|
||||
return sigma;
|
||||
}
|
||||
|
||||
@ -282,10 +266,8 @@ void apply_morphology(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
int radius,
|
||||
GrSamplerState::Filter filter,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
GrAssert(filter == GrSamplerState::kErode_Filter ||
|
||||
filter == GrSamplerState::kDilate_Filter);
|
||||
GrContext::MorphologyType morphType,
|
||||
Gr1DKernelEffect::Direction direction) {
|
||||
|
||||
GrRenderTarget* target = gpu->drawState()->getRenderTarget();
|
||||
GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
|
||||
@ -293,31 +275,31 @@ void apply_morphology(GrGpu* gpu,
|
||||
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->sampler(0)->reset(sampleM);
|
||||
SkAutoTUnref<GrCustomStage> morph(
|
||||
new GrMorphologyEffect(direction, radius, morphType));
|
||||
drawState->sampler(0)->setCustomStage(morph);
|
||||
drawState->setTexture(0, texture);
|
||||
gpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
}
|
||||
|
||||
void convolve(GrGpu* gpu,
|
||||
void convolve_gaussian(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
const SkRect& rect,
|
||||
const float* kernel,
|
||||
int kernelWidth,
|
||||
GrSamplerState::FilterDirection direction) {
|
||||
float sigma,
|
||||
int radius,
|
||||
Gr1DKernelEffect::Direction direction) {
|
||||
GrRenderTarget* target = gpu->drawState()->getRenderTarget();
|
||||
GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
|
||||
GrDrawState* drawState = gpu->drawState();
|
||||
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)->setCustomStage(
|
||||
new GrConvolutionEffect(direction, kernelWidth, kernel));
|
||||
drawState->sampler(0)->reset(sampleM);
|
||||
SkAutoTUnref<GrConvolutionEffect> conv(new
|
||||
GrConvolutionEffect(direction, radius));
|
||||
conv->setGaussianKernel(sigma);
|
||||
drawState->sampler(0)->setCustomStage(conv);
|
||||
drawState->setTexture(0, texture);
|
||||
gpu->drawSimpleRect(rect, NULL, 1 << 0);
|
||||
}
|
||||
@ -2085,10 +2067,10 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
|
||||
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);
|
||||
int scaleFactorX, radiusX;
|
||||
int scaleFactorY, radiusY;
|
||||
sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
|
||||
sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
|
||||
|
||||
SkRect srcRect(rect);
|
||||
scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
||||
@ -2138,21 +2120,17 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
|
||||
srcRect.roundOut(&srcIRect);
|
||||
|
||||
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
|
||||
// Clear out a radius to the right of the srcRect to prevent the
|
||||
// X convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
|
||||
halfWidthX, srcIRect.height());
|
||||
radiusX, srcIRect.height());
|
||||
this->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
convolve_gaussian(fGpu, srcTexture, srcRect, sigmaX, radiusX,
|
||||
Gr1DKernelEffect::kX_Direction);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) {
|
||||
dstTexture = temp2->texture();
|
||||
@ -2160,21 +2138,17 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
|
||||
}
|
||||
|
||||
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
|
||||
// Clear out a radius below the srcRect to prevent the Y
|
||||
// convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
|
||||
srcIRect.width(), halfWidthY);
|
||||
srcIRect.width(), radiusY);
|
||||
this->clear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
this->setRenderTarget(dstTexture->asRenderTarget());
|
||||
convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
convolve_gaussian(fGpu, srcTexture, srcRect, sigmaY, radiusY,
|
||||
Gr1DKernelEffect::kY_Direction);
|
||||
SkTSwap(srcTexture, dstTexture);
|
||||
if (temp2 && dstTexture == origTexture) {
|
||||
dstTexture = temp2->texture();
|
||||
@ -2210,7 +2184,7 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
|
||||
GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
|
||||
const GrRect& rect,
|
||||
GrTexture* temp1, GrTexture* temp2,
|
||||
GrSamplerState::Filter filter,
|
||||
MorphologyType morphType,
|
||||
SkISize radius) {
|
||||
ASSERT_OWNED_RESOURCE(srcTexture);
|
||||
GrRenderTarget* oldRenderTarget = this->getRenderTarget();
|
||||
@ -2220,8 +2194,8 @@ GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
|
||||
SkIntToScalar(srcTexture->height())));
|
||||
if (radius.fWidth > 0) {
|
||||
this->setRenderTarget(temp1->asRenderTarget());
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
|
||||
GrSamplerState::kX_FilterDirection);
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fWidth, morphType,
|
||||
Gr1DKernelEffect::kX_Direction);
|
||||
SkIRect clearRect = SkIRect::MakeXYWH(
|
||||
SkScalarFloorToInt(rect.fLeft),
|
||||
SkScalarFloorToInt(rect.fBottom),
|
||||
@ -2232,8 +2206,8 @@ GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
|
||||
}
|
||||
if (radius.fHeight > 0) {
|
||||
this->setRenderTarget(temp2->asRenderTarget());
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
|
||||
GrSamplerState::kY_FilterDirection);
|
||||
apply_morphology(fGpu, srcTexture, rect, radius.fHeight, morphType,
|
||||
Gr1DKernelEffect::kY_Direction);
|
||||
srcTexture = temp2;
|
||||
}
|
||||
this->setRenderTarget(oldRenderTarget);
|
||||
|
@ -1451,14 +1451,14 @@ static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
|
||||
GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
|
||||
texture = context->applyMorphology(texture, rect,
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kDilate_Filter,
|
||||
GrContext::kDilate_MorphologyType,
|
||||
radius);
|
||||
texture->ref();
|
||||
} else if (filter->asAnErode(&radius)) {
|
||||
GrAutoScratchTexture temp1(context, desc), temp2(context, desc);
|
||||
texture = context->applyMorphology(texture, rect,
|
||||
temp1.texture(), temp2.texture(),
|
||||
GrSamplerState::kErode_Filter,
|
||||
GrContext::kErode_MorphologyType,
|
||||
radius);
|
||||
texture->ref();
|
||||
}
|
||||
|
50
src/gpu/effects/Gr1DKernelEffect.h
Normal file
50
src/gpu/effects/Gr1DKernelEffect.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef Gr1DKernelEffect_DEFINED
|
||||
#define Gr1DKernelEffect_DEFINED
|
||||
|
||||
#include "GrCustomStage.h"
|
||||
|
||||
/**
|
||||
* Base class for 1D kernel effects. The kernel operates either in X or Y and
|
||||
* has a pixel radius. The kernel is specified in the src texture's space
|
||||
* and the kernel center is pinned to a texel's center. The radius specifies
|
||||
* the number of texels on either side of the center texel in X or Y that are
|
||||
* read. Since the center pixel is also read, the total width is one larger than
|
||||
* two times the radius.
|
||||
*/
|
||||
class Gr1DKernelEffect : public GrCustomStage {
|
||||
|
||||
public:
|
||||
enum Direction {
|
||||
kX_Direction,
|
||||
kY_Direction,
|
||||
};
|
||||
|
||||
Gr1DKernelEffect(Direction direction,
|
||||
int radius)
|
||||
: fDirection(direction)
|
||||
, fRadius(radius) {}
|
||||
|
||||
virtual ~Gr1DKernelEffect() {};
|
||||
|
||||
static int WidthFromRadius(int radius) { return 2 * radius + 1; }
|
||||
|
||||
int radius() const { return fRadius; }
|
||||
int width() const { return WidthFromRadius(fRadius); }
|
||||
Direction direction() const { return fDirection; }
|
||||
|
||||
private:
|
||||
|
||||
Direction fDirection;
|
||||
int fRadius;
|
||||
|
||||
typedef GrCustomStage INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -11,14 +11,11 @@
|
||||
#include "gl/GrGLTexture.h"
|
||||
#include "GrProgramStageFactory.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GrGLConvolutionEffect : public GrGLProgramStage {
|
||||
|
||||
public:
|
||||
|
||||
GrGLConvolutionEffect(const GrProgramStageFactory& factory,
|
||||
const GrCustomStage* stage);
|
||||
const GrCustomStage& stage);
|
||||
|
||||
virtual void setupVariables(GrGLShaderBuilder* state,
|
||||
int stage) SK_OVERRIDE;
|
||||
virtual void emitVS(GrGLShaderBuilder* state,
|
||||
@ -27,38 +24,38 @@ public:
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const char* samplerName) SK_OVERRIDE;
|
||||
|
||||
virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
|
||||
|
||||
virtual void setData(const GrGLInterface*,
|
||||
const GrGLTexture&,
|
||||
GrCustomStage*,
|
||||
const GrCustomStage&,
|
||||
int stageNum) SK_OVERRIDE;
|
||||
|
||||
static inline StageKey GenKey(const GrCustomStage* s);
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int fKernelWidth;
|
||||
const GrGLShaderVar* fKernelVar;
|
||||
const GrGLShaderVar* fImageIncrementVar;
|
||||
|
||||
GrGLint fKernelLocation;
|
||||
GrGLint fImageIncrementLocation;
|
||||
static inline StageKey GenKey(const GrCustomStage&);
|
||||
|
||||
private:
|
||||
int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
|
||||
|
||||
int fRadius;
|
||||
const GrGLShaderVar* fKernelVar;
|
||||
GrGLint fKernelLocation;
|
||||
const GrGLShaderVar* fImageIncrementVar;
|
||||
GrGLint fImageIncrementLocation;
|
||||
|
||||
typedef GrGLProgramStage INHERITED;
|
||||
};
|
||||
|
||||
GrGLConvolutionEffect::GrGLConvolutionEffect(
|
||||
const GrProgramStageFactory& factory,
|
||||
const GrCustomStage* data)
|
||||
GrGLConvolutionEffect::GrGLConvolutionEffect(const GrProgramStageFactory& factory,
|
||||
const GrCustomStage& stage)
|
||||
: GrGLProgramStage(factory)
|
||||
, fKernelVar(NULL)
|
||||
, fImageIncrementVar(NULL)
|
||||
, fKernelLocation(0)
|
||||
, fImageIncrementVar(NULL)
|
||||
, fImageIncrementLocation(0) {
|
||||
fKernelWidth = static_cast<const GrConvolutionEffect*>(data)->width();
|
||||
const GrConvolutionEffect& c =
|
||||
static_cast<const GrConvolutionEffect&>(stage);
|
||||
fRadius = c.radius();
|
||||
}
|
||||
|
||||
void GrGLConvolutionEffect::setupVariables(GrGLShaderBuilder* state,
|
||||
@ -68,7 +65,7 @@ void GrGLConvolutionEffect::setupVariables(GrGLShaderBuilder* state,
|
||||
kVec2f_GrSLType, "uImageIncrement", stage);
|
||||
fKernelVar = &state->addUniform(
|
||||
GrGLShaderBuilder::kFragment_VariableLifetime,
|
||||
kFloat_GrSLType, "uKernel", stage, fKernelWidth);
|
||||
kFloat_GrSLType, "uKernel", stage, this->width());
|
||||
|
||||
fImageIncrementLocation = kUseUniform;
|
||||
fKernelLocation = kUseUniform;
|
||||
@ -77,11 +74,9 @@ void GrGLConvolutionEffect::setupVariables(GrGLShaderBuilder* state,
|
||||
void GrGLConvolutionEffect::emitVS(GrGLShaderBuilder* state,
|
||||
const char* vertexCoords) {
|
||||
GrStringBuilder* code = &state->fVSCode;
|
||||
float scale = (fKernelWidth - 1) * 0.5f;
|
||||
code->appendf("\t\t%s -= vec2(%g, %g) * %s;\n",
|
||||
vertexCoords, scale, scale,
|
||||
code->appendf("\t\t%s -= vec2(%d, %d) * %s;\n",
|
||||
vertexCoords, fRadius, fRadius,
|
||||
fImageIncrementVar->getName().c_str());
|
||||
|
||||
}
|
||||
|
||||
void GrGLConvolutionEffect::emitFS(GrGLShaderBuilder* state,
|
||||
@ -92,100 +87,110 @@ void GrGLConvolutionEffect::emitFS(GrGLShaderBuilder* state,
|
||||
const char* texFunc = "texture2D";
|
||||
bool complexCoord = false;
|
||||
|
||||
GrStringBuilder modulate;
|
||||
if (NULL != inputColor) {
|
||||
modulate.printf(" * %s", inputColor);
|
||||
}
|
||||
state->fFSCode.appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
|
||||
|
||||
code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
|
||||
code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
|
||||
|
||||
// Creates the string "kernel[i]" with workarounds for
|
||||
// possible driver bugs
|
||||
GrStringBuilder kernelIndex;
|
||||
fKernelVar->appendArrayAccess("i", &kernelIndex);
|
||||
|
||||
code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
|
||||
code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
|
||||
code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n",
|
||||
fKernelWidth);
|
||||
|
||||
code->appendf("\t\t\tsum += ");
|
||||
state->fFSCode.appendf("\t\t\tsum += ");
|
||||
state->emitTextureLookup(samplerName, "coord");
|
||||
code->appendf(" * %s;\n", kernelIndex.c_str());
|
||||
state->fFSCode.appendf(" * %s;\n", kernelIndex.c_str());
|
||||
|
||||
code->appendf("\t\t\tcoord += %s;\n",
|
||||
fImageIncrementVar->getName().c_str());
|
||||
code->appendf("\t\t}\n");
|
||||
code->appendf("\t\t%s = sum%s;\n", outputColor, modulate.c_str());
|
||||
|
||||
state->fFSCode.appendf("\t\t%s = sum%s;\n",
|
||||
outputColor,
|
||||
state->fModulate.c_str());
|
||||
}
|
||||
|
||||
void GrGLConvolutionEffect::initUniforms(const GrGLInterface* gl,
|
||||
int programID) {
|
||||
GR_GL_CALL_RET(gl, fKernelLocation,
|
||||
GetUniformLocation(programID, fKernelVar->getName().c_str()));
|
||||
GR_GL_CALL_RET(gl, fImageIncrementLocation,
|
||||
GetUniformLocation(programID,
|
||||
fImageIncrementVar->getName().c_str()));
|
||||
GR_GL_CALL_RET(gl, fKernelLocation,
|
||||
GetUniformLocation(programID, fKernelVar->getName().c_str()));
|
||||
}
|
||||
|
||||
void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
|
||||
const GrGLTexture& texture,
|
||||
GrCustomStage* data,
|
||||
const GrCustomStage& data,
|
||||
int stageNum) {
|
||||
const GrConvolutionEffect* conv =
|
||||
static_cast<const GrConvolutionEffect*>(data);
|
||||
// the code we generated was for a specific kernel width
|
||||
GrAssert(conv->width() == fKernelWidth);
|
||||
GR_GL_CALL(gl, Uniform1fv(fKernelLocation,
|
||||
fKernelWidth,
|
||||
conv->kernel()));
|
||||
const GrConvolutionEffect& conv =
|
||||
static_cast<const GrConvolutionEffect&>(data);
|
||||
// the code we generated was for a specific kernel radius
|
||||
GrAssert(conv.radius() == fRadius);
|
||||
float imageIncrement[2] = { 0 };
|
||||
switch (conv->direction()) {
|
||||
case GrSamplerState::kX_FilterDirection:
|
||||
switch (conv.direction()) {
|
||||
case Gr1DKernelEffect::kX_Direction:
|
||||
imageIncrement[0] = 1.0f / texture.width();
|
||||
break;
|
||||
case GrSamplerState::kY_FilterDirection:
|
||||
imageIncrement[1] = 1.0f / texture.width();
|
||||
case Gr1DKernelEffect::kY_Direction:
|
||||
imageIncrement[1] = 1.0f / texture.height();
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unknown filter direction.");
|
||||
}
|
||||
GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
|
||||
|
||||
GR_GL_CALL(gl, Uniform1fv(fKernelLocation, this->width(), conv.kernel()));
|
||||
}
|
||||
|
||||
GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
|
||||
const GrCustomStage* s) {
|
||||
return static_cast<const GrConvolutionEffect*>(s)->width();
|
||||
const GrCustomStage& s) {
|
||||
return static_cast<const GrConvolutionEffect&>(s).radius();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrConvolutionEffect::GrConvolutionEffect(
|
||||
GrSamplerState::FilterDirection direction,
|
||||
unsigned int kernelWidth,
|
||||
GrConvolutionEffect::GrConvolutionEffect(Direction direction,
|
||||
int radius,
|
||||
const float* kernel)
|
||||
: fDirection (direction)
|
||||
, fKernelWidth (kernelWidth) {
|
||||
GrAssert(kernelWidth <= MAX_KERNEL_WIDTH);
|
||||
for (unsigned int i = 0; i < kernelWidth; i++) {
|
||||
: Gr1DKernelEffect(direction, radius) {
|
||||
GrAssert(radius <= kMaxKernelRadius);
|
||||
int width = this->width();
|
||||
if (NULL != kernel) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
fKernel[i] = kernel[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrConvolutionEffect::~GrConvolutionEffect() {
|
||||
|
||||
}
|
||||
|
||||
const GrProgramStageFactory& GrConvolutionEffect::getFactory() const {
|
||||
return GrTProgramStageFactory<GrConvolutionEffect>::getInstance();
|
||||
}
|
||||
|
||||
bool GrConvolutionEffect::isEqual(const GrCustomStage * sBase) const {
|
||||
const GrConvolutionEffect* s =
|
||||
static_cast<const GrConvolutionEffect*>(sBase);
|
||||
|
||||
return (fKernelWidth == s->fKernelWidth &&
|
||||
fDirection == s->fDirection &&
|
||||
0 == memcmp(fKernel, s->fKernel, fKernelWidth * sizeof(float)));
|
||||
bool GrConvolutionEffect::isEqual(const GrCustomStage& sBase) const {
|
||||
const GrConvolutionEffect& s =
|
||||
static_cast<const GrConvolutionEffect&>(sBase);
|
||||
return (this->radius() == s.radius() &&
|
||||
this->direction() == s.direction() &&
|
||||
0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GrConvolutionEffect::setGaussianKernel(float sigma) {
|
||||
int width = this->width();
|
||||
float sum = 0.0f;
|
||||
float denom = 1.0f / (2.0f * sigma * sigma);
|
||||
for (int i = 0; i < width; ++i) {
|
||||
float x = static_cast<float>(i - this->radius());
|
||||
// Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
|
||||
// is dropped here, since we renormalize the kernel below.
|
||||
fKernel[i] = sk_float_exp(- x * x * denom);
|
||||
sum += fKernel[i];
|
||||
}
|
||||
// Normalize the kernel
|
||||
float scale = 1.0f / sum;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
fKernel[i] *= scale;
|
||||
}
|
||||
}
|
||||
|
@ -8,40 +8,58 @@
|
||||
#ifndef GrConvolutionEffect_DEFINED
|
||||
#define GrConvolutionEffect_DEFINED
|
||||
|
||||
#include "GrCustomStage.h"
|
||||
#include "GrSamplerState.h" // for MAX_KENEL_WIDTH, FilterDirection
|
||||
#include "Gr1DKernelEffect.h"
|
||||
|
||||
class GrGLConvolutionEffect;
|
||||
|
||||
class GrConvolutionEffect : public GrCustomStage {
|
||||
/**
|
||||
* A convolution effect. The kernel is specified as an array of 2 * half-width
|
||||
* + 1 weights. Each texel is multiplied by it's weight and summed to determine
|
||||
* the output color. The output color is modulated by the input color.
|
||||
*/
|
||||
class GrConvolutionEffect : public Gr1DKernelEffect {
|
||||
|
||||
public:
|
||||
|
||||
GrConvolutionEffect(GrSamplerState::FilterDirection direction,
|
||||
unsigned int kernelWidth, const float* kernel);
|
||||
GrConvolutionEffect(Direction, int halfWidth, const float* kernel = NULL);
|
||||
virtual ~GrConvolutionEffect();
|
||||
|
||||
unsigned int width() const { return fKernelWidth; }
|
||||
void setKernel(const float* kernel) {
|
||||
memcpy(fKernel, kernel, this->width());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set the kernel to a Gaussian. Replaces the existing kernel.
|
||||
*/
|
||||
void setGaussianKernel(float sigma);
|
||||
|
||||
const float* kernel() const { return fKernel; }
|
||||
GrSamplerState::FilterDirection direction() const { return fDirection; }
|
||||
|
||||
static const char* Name() { return "Convolution"; }
|
||||
|
||||
typedef GrGLConvolutionEffect GLProgramStage;
|
||||
|
||||
virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
|
||||
virtual bool isEqual(const GrCustomStage *) const SK_OVERRIDE;
|
||||
virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
|
||||
|
||||
enum {
|
||||
// This was decided based on the min allowed value for the max texture
|
||||
// samples per fragment program run in DX9SM2 (32). A sigma param of 4.0
|
||||
// on a blur filter gives a kernel width of 25 while a sigma of 5.0
|
||||
// would exceed a 32 wide kernel.
|
||||
kMaxKernelRadius = 12,
|
||||
// With a C++11 we could have a constexpr version of WidthFromRadius()
|
||||
// and not have to duplicate this calculation.
|
||||
kMaxKernelWidth = 2 * kMaxKernelRadius + 1,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
GrSamplerState::FilterDirection fDirection;
|
||||
unsigned int fKernelWidth;
|
||||
float fKernel[MAX_KERNEL_WIDTH];
|
||||
|
||||
float fKernel[kMaxKernelWidth];
|
||||
|
||||
private:
|
||||
|
||||
typedef GrCustomStage INHERITED;
|
||||
typedef Gr1DKernelEffect INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
169
src/gpu/effects/GrMorphologyEffect.cpp
Normal file
169
src/gpu/effects/GrMorphologyEffect.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrMorphologyEffect.h"
|
||||
#include "gl/GrGLProgramStage.h"
|
||||
#include "gl/GrGLSL.h"
|
||||
#include "gl/GrGLTexture.h"
|
||||
#include "GrProgramStageFactory.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GrGLMorphologyEffect : public GrGLProgramStage {
|
||||
public:
|
||||
GrGLMorphologyEffect (const GrProgramStageFactory& factory,
|
||||
const GrCustomStage& stage);
|
||||
|
||||
virtual void setupVariables(GrGLShaderBuilder* state,
|
||||
int stage) SK_OVERRIDE;
|
||||
virtual void emitVS(GrGLShaderBuilder* state,
|
||||
const char* vertexCoords) SK_OVERRIDE;
|
||||
virtual void emitFS(GrGLShaderBuilder* state,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const char* samplerName) SK_OVERRIDE;
|
||||
|
||||
static inline StageKey GenKey(const GrCustomStage& s);
|
||||
|
||||
virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
|
||||
virtual void setData(const GrGLInterface*,
|
||||
const GrGLTexture&,
|
||||
const GrCustomStage&,
|
||||
int stageNum) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
|
||||
|
||||
int fRadius;
|
||||
GrMorphologyEffect::MorphologyType fType;
|
||||
const GrGLShaderVar* fImageIncrementVar;
|
||||
GrGLint fImageIncrementLocation;
|
||||
|
||||
typedef GrGLProgramStage INHERITED;
|
||||
};
|
||||
|
||||
GrGLMorphologyEffect ::GrGLMorphologyEffect(const GrProgramStageFactory& factory,
|
||||
const GrCustomStage& stage)
|
||||
: GrGLProgramStage(factory)
|
||||
, fImageIncrementVar(NULL)
|
||||
, fImageIncrementLocation(0) {
|
||||
const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(stage);
|
||||
fRadius = m.radius();
|
||||
fType = m.type();
|
||||
}
|
||||
|
||||
void GrGLMorphologyEffect::setupVariables(GrGLShaderBuilder* state, int stage) {
|
||||
fImageIncrementVar = &state->addUniform(
|
||||
GrGLShaderBuilder::kBoth_VariableLifetime,
|
||||
kVec2f_GrSLType, "uImageIncrement", stage);
|
||||
}
|
||||
|
||||
void GrGLMorphologyEffect::emitVS(GrGLShaderBuilder* state,
|
||||
const char* vertexCoords) {
|
||||
GrStringBuilder* code = &state->fVSCode;
|
||||
code->appendf("\t\t%s -= vec2(%d, %d) * %s;\n",
|
||||
vertexCoords, fRadius, fRadius,
|
||||
fImageIncrementVar->getName().c_str());
|
||||
}
|
||||
|
||||
void GrGLMorphologyEffect::initUniforms(const GrGLInterface* gl,
|
||||
int programID) {
|
||||
GR_GL_CALL_RET(gl, fImageIncrementLocation,
|
||||
GetUniformLocation(programID,
|
||||
fImageIncrementVar->getName().c_str()));
|
||||
}
|
||||
|
||||
void GrGLMorphologyEffect ::emitFS(GrGLShaderBuilder* state,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const char* samplerName) {
|
||||
GrStringBuilder* code = &state->fFSCode;
|
||||
const char* texFunc = "texture2D";
|
||||
bool complexCoord = false;
|
||||
|
||||
const char* func;
|
||||
switch (fType) {
|
||||
case GrContext::kErode_MorphologyType:
|
||||
state->fFSCode.appendf("\t\tvec4 value = vec4(1, 1, 1, 1);\n");
|
||||
func = "min";
|
||||
break;
|
||||
case GrContext::kDilate_MorphologyType:
|
||||
state->fFSCode.appendf("\t\tvec4 value = vec4(0, 0, 0, 0);\n");
|
||||
func = "max";
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unexpected type");
|
||||
break;
|
||||
}
|
||||
|
||||
code->appendf("\t\tvec2 coord = %s;\n", state->fSampleCoords.c_str());
|
||||
code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
|
||||
state->fFSCode.appendf("\t\t\tvalue = %s(value, ", func);
|
||||
state->emitTextureLookup(samplerName, "coord");
|
||||
state->fFSCode.appendf(");\n");
|
||||
code->appendf("\t\t\tcoord += %s;\n",
|
||||
fImageIncrementVar->getName().c_str());
|
||||
code->appendf("\t\t}\n");
|
||||
|
||||
state->fFSCode.appendf("\t\t%s = value%s;\n",
|
||||
outputColor,
|
||||
state->fModulate.c_str());
|
||||
}
|
||||
|
||||
GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(
|
||||
const GrCustomStage& s) {
|
||||
const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(s);
|
||||
StageKey key = static_cast<StageKey>(m.radius());
|
||||
key |= (m.type() << 8);
|
||||
return key;
|
||||
}
|
||||
|
||||
void GrGLMorphologyEffect ::setData(const GrGLInterface* gl,
|
||||
const GrGLTexture& texture,
|
||||
const GrCustomStage& data,
|
||||
int stageNum) {
|
||||
const Gr1DKernelEffect& kern =
|
||||
static_cast<const Gr1DKernelEffect&>(data);
|
||||
// the code we generated was for a specific kernel radius
|
||||
GrAssert(kern.radius() == fRadius);
|
||||
float imageIncrement[2] = { 0 };
|
||||
switch (kern.direction()) {
|
||||
case Gr1DKernelEffect::kX_Direction:
|
||||
imageIncrement[0] = 1.0f / texture.width();
|
||||
break;
|
||||
case Gr1DKernelEffect::kY_Direction:
|
||||
imageIncrement[1] = 1.0f / texture.height();
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unknown filter direction.");
|
||||
}
|
||||
GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrMorphologyEffect::GrMorphologyEffect(Direction direction,
|
||||
int radius,
|
||||
MorphologyType type)
|
||||
: Gr1DKernelEffect(direction, radius)
|
||||
, fType(type) {
|
||||
}
|
||||
|
||||
GrMorphologyEffect::~GrMorphologyEffect() {
|
||||
}
|
||||
|
||||
const GrProgramStageFactory& GrMorphologyEffect::getFactory() const {
|
||||
return GrTProgramStageFactory<GrMorphologyEffect>::getInstance();
|
||||
}
|
||||
|
||||
bool GrMorphologyEffect::isEqual(const GrCustomStage& sBase) const {
|
||||
const GrMorphologyEffect& s =
|
||||
static_cast<const GrMorphologyEffect&>(sBase);
|
||||
return (this->radius() == s.radius() &&
|
||||
this->direction() == s.direction() &&
|
||||
this->type() == s.type());
|
||||
}
|
48
src/gpu/effects/GrMorphologyEffect.h
Normal file
48
src/gpu/effects/GrMorphologyEffect.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrMorphologyEffect_DEFINED
|
||||
#define GrMorphologyEffect_DEFINED
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "Gr1DKernelEffect.h"
|
||||
|
||||
class GrGLMorphologyEffect;
|
||||
|
||||
/**
|
||||
* Morphology effects. Depending upon the type of morphology, either the
|
||||
* component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
|
||||
* kernel is selected as the new color. The new color is modulated by the input
|
||||
* color.
|
||||
*/
|
||||
class GrMorphologyEffect : public Gr1DKernelEffect {
|
||||
|
||||
public:
|
||||
|
||||
typedef GrContext::MorphologyType MorphologyType;
|
||||
|
||||
GrMorphologyEffect(Direction, int radius, MorphologyType);
|
||||
virtual ~GrMorphologyEffect();
|
||||
|
||||
MorphologyType type() const { return fType; }
|
||||
|
||||
static const char* Name() { return "Morphology"; }
|
||||
|
||||
typedef GrGLMorphologyEffect GLProgramStage;
|
||||
|
||||
virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
|
||||
virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
MorphologyType fType;
|
||||
|
||||
private:
|
||||
|
||||
typedef Gr1DKernelEffect INHERITED;
|
||||
};
|
||||
#endif
|
@ -95,18 +95,6 @@ inline void radial2_param_name(int stage, GrStringBuilder* s) {
|
||||
s->appendS32(stage);
|
||||
}
|
||||
|
||||
inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
|
||||
*k = "uKernel";
|
||||
k->appendS32(stage);
|
||||
*i = "uImageIncrement";
|
||||
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);
|
||||
@ -629,7 +617,7 @@ bool GrGLProgram::genProgram(const GrGLContextInfo& gl,
|
||||
const GrProgramStageFactory& factory =
|
||||
customStages[s]->getFactory();
|
||||
programData->fCustomStage[s] =
|
||||
factory.createGLInstance(customStages[s]);
|
||||
factory.createGLInstance(*customStages[s]);
|
||||
}
|
||||
this->genStageCode(gl,
|
||||
s,
|
||||
@ -752,7 +740,7 @@ bool GrGLProgram::genProgram(const GrGLContextInfo& gl,
|
||||
const GrProgramStageFactory& factory =
|
||||
customStages[s]->getFactory();
|
||||
programData->fCustomStage[s] =
|
||||
factory.createGLInstance(customStages[s]);
|
||||
factory.createGLInstance(*customStages[s]);
|
||||
}
|
||||
this->genStageCode(gl, s,
|
||||
fProgramDesc.fStages[s],
|
||||
@ -1186,21 +1174,6 @@ void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl,
|
||||
GrAssert(kUnusedUniform != locations.fTexDomUni);
|
||||
}
|
||||
|
||||
GrStringBuilder kernelName, imageIncrementName;
|
||||
convolve_param_names(s, &kernelName, &imageIncrementName);
|
||||
if (kUseUniform == locations.fKernelUni) {
|
||||
GL_CALL_RET(locations.fKernelUni,
|
||||
GetUniformLocation(progID, kernelName.c_str()));
|
||||
GrAssert(kUnusedUniform != locations.fKernelUni);
|
||||
}
|
||||
|
||||
if (kUseUniform == locations.fImageIncrementUni) {
|
||||
GL_CALL_RET(locations.fImageIncrementUni,
|
||||
GetUniformLocation(progID,
|
||||
imageIncrementName.c_str()));
|
||||
GrAssert(kUnusedUniform != locations.fImageIncrementUni);
|
||||
}
|
||||
|
||||
if (NULL != programData->fCustomStage[s]) {
|
||||
programData->fCustomStage[s]->
|
||||
initUniforms(gl.interface(), progID);
|
||||
@ -1411,65 +1384,6 @@ void gen2x2FS(int stageNum,
|
||||
|
||||
}
|
||||
|
||||
void genMorphologyVS(int stageNum,
|
||||
const StageDesc& desc,
|
||||
GrGLShaderBuilder* segments,
|
||||
GrGLProgram::StageUniLocations* locations,
|
||||
const char** imageIncrementName,
|
||||
const char* varyingVSName) {
|
||||
|
||||
GrStringBuilder iiName;
|
||||
image_increment_param_name(stageNum, &iiName);
|
||||
const GrGLShaderVar* imgInc =
|
||||
&segments->addUniform(
|
||||
GrGLShaderBuilder::kBoth_VariableLifetime, kVec2f_GrSLType,
|
||||
iiName.c_str());
|
||||
*imageIncrementName = imgInc->getName().c_str();
|
||||
|
||||
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,
|
||||
GrGLShaderBuilder* segments,
|
||||
const char* samplerName,
|
||||
const char* imageIncrementName,
|
||||
const char* fsOutColor,
|
||||
GrStringBuilder& texFunc) {
|
||||
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(),
|
||||
segments->fSampleCoords.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(),
|
||||
segments->fSwizzle.c_str());
|
||||
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(), segments->fModulate.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GrGLProgram::genStageCode(const GrGLContextInfo& gl,
|
||||
@ -1562,12 +1476,6 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl,
|
||||
|
||||
GrGLShaderVar* kernel = NULL;
|
||||
const char* imageIncrementName = NULL;
|
||||
if (StageDesc::kDilate_FetchMode == desc.fFetchMode ||
|
||||
StageDesc::kErode_FetchMode == desc.fFetchMode) {
|
||||
genMorphologyVS(stageNum, desc, segments, locations,
|
||||
&imageIncrementName, varyingVSName);
|
||||
}
|
||||
|
||||
if (NULL != customStage) {
|
||||
segments->fVSCode.appendf("\t{ // stage %d %s\n",
|
||||
stageNum, customStage->name());
|
||||
@ -1677,15 +1585,6 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl,
|
||||
gen2x2FS(stageNum, segments, locations,
|
||||
samplerName.c_str(), texelSizeName, fsOutColor, texFunc);
|
||||
break;
|
||||
case StageDesc::kConvolution_FetchMode:
|
||||
GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
|
||||
break;
|
||||
case StageDesc::kDilate_FetchMode:
|
||||
case StageDesc::kErode_FetchMode:
|
||||
GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
|
||||
genMorphologyFS(stageNum, desc, segments,
|
||||
samplerName.c_str(), imageIncrementName, fsOutColor, texFunc);
|
||||
break;
|
||||
default:
|
||||
if (desc.fInConfigFlags & kMulByAlphaMask) {
|
||||
// only one of the mul by alpha flags should be set
|
||||
|
@ -106,13 +106,10 @@ public:
|
||||
kCustomTextureDomain_OptFlagBit = 1 << 2,
|
||||
kIsEnabled_OptFlagBit = 1 << 7
|
||||
};
|
||||
// Convolution is obsolete; left in for testing only
|
||||
|
||||
enum FetchMode {
|
||||
kSingle_FetchMode,
|
||||
k2x2_FetchMode,
|
||||
kConvolution_FetchMode,
|
||||
kErode_FetchMode,
|
||||
kDilate_FetchMode,
|
||||
|
||||
kFetchModeCnt,
|
||||
};
|
||||
@ -179,7 +176,6 @@ public:
|
||||
uint8_t fInConfigFlags; // bitfield of InConfigFlags values
|
||||
uint8_t fFetchMode; // casts to enum FetchMode
|
||||
uint8_t fCoordMapping; // casts to enum CoordMapping
|
||||
uint8_t fKernelWidth;
|
||||
|
||||
/** Non-zero if user-supplied code will write the stage's
|
||||
contribution to the fragment shader. */
|
||||
@ -268,16 +264,12 @@ public:
|
||||
GrGLint fSamplerUni;
|
||||
GrGLint fRadial2Uni;
|
||||
GrGLint fTexDomUni;
|
||||
GrGLint fKernelUni;
|
||||
GrGLint fImageIncrementUni;
|
||||
void reset() {
|
||||
fTextureMatrixUni = kUnusedUniform;
|
||||
fNormalizedTexelSizeUni = kUnusedUniform;
|
||||
fSamplerUni = kUnusedUniform;
|
||||
fRadial2Uni = kUnusedUniform;
|
||||
fTexDomUni = kUnusedUniform;
|
||||
fKernelUni = kUnusedUniform;
|
||||
fImageIncrementUni = kUnusedUniform;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,9 +27,7 @@ void GrGLProgramStage::initUniforms(const GrGLInterface*, int progID) {
|
||||
|
||||
void GrGLProgramStage::setData(const GrGLInterface*,
|
||||
const GrGLTexture&,
|
||||
GrCustomStage*,
|
||||
const GrCustomStage&,
|
||||
int stageNum) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,12 @@ class GrGLTexture;
|
||||
class GrGLProgramStage {
|
||||
|
||||
public:
|
||||
typedef GrCustomStage::StageKey StageKey ;
|
||||
typedef GrCustomStage::StageKey StageKey;
|
||||
enum {
|
||||
// the number of bits in StageKey available to GenKey
|
||||
kProgramStageKeyBits = GrProgramStageFactory::kProgramStageKeyBits,
|
||||
};
|
||||
|
||||
// TODO: redundant with GrGLProgram.cpp
|
||||
enum {
|
||||
kUnusedUniform = -1,
|
||||
@ -79,7 +84,7 @@ public:
|
||||
created in emit*(). */
|
||||
virtual void setData(const GrGLInterface* gl,
|
||||
const GrGLTexture& texture,
|
||||
GrCustomStage* stage,
|
||||
const GrCustomStage& stage,
|
||||
int stageNum);
|
||||
|
||||
const char* name() const { return fFactory.name(); }
|
||||
|
@ -2102,9 +2102,6 @@ unsigned gr_to_gl_filter(GrSamplerState::Filter filter) {
|
||||
case GrSamplerState::k4x4Downsample_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");
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
#include "GrGpuGL.h"
|
||||
|
||||
#include "GrBinHashKey.h"
|
||||
#include "effects/GrConvolutionEffect.h"
|
||||
#include "effects/GrMorphologyEffect.h"
|
||||
|
||||
#include "GrBinHashKey.h"
|
||||
#include "GrCustomStage.h"
|
||||
#include "GrGLProgramStage.h"
|
||||
#include "GrGLSL.h"
|
||||
@ -176,6 +178,75 @@ bool random_bool(GrRandom* r) {
|
||||
return r->nextF() > .5f;
|
||||
}
|
||||
|
||||
typedef GrGLProgram::StageDesc StageDesc;
|
||||
// TODO: Effects should be able to register themselves for inclusion in the
|
||||
// randomly generated shaders. They should be able to configure themselves
|
||||
// randomly.
|
||||
GrCustomStage* create_random_effect(StageDesc* stageDesc,
|
||||
GrRandom* random) {
|
||||
enum EffectType {
|
||||
kConvolution_EffectType,
|
||||
kErode_EffectType,
|
||||
kDilate_EffectType,
|
||||
|
||||
kEffectCount
|
||||
};
|
||||
|
||||
// TODO: Remove this when generator doesn't apply this non-custom-stage
|
||||
// notion to custom stages automatically.
|
||||
static const uint32_t kMulByAlphaMask =
|
||||
StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
|
||||
StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
|
||||
|
||||
static const Gr1DKernelEffect::Direction gKernelDirections[] = {
|
||||
Gr1DKernelEffect::kX_Direction,
|
||||
Gr1DKernelEffect::kY_Direction
|
||||
};
|
||||
|
||||
// TODO: When matrices are property of the custom-stage then remove the
|
||||
// no-persp flag code below.
|
||||
int effect = random_int(random, kEffectCount);
|
||||
switch (effect) {
|
||||
case kConvolution_EffectType: {
|
||||
int direction = random_int(random, 2);
|
||||
int kernelRadius = random_int(random, 1, 4);
|
||||
float kernel[GrConvolutionEffect::kMaxKernelWidth];
|
||||
for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
|
||||
kernel[i] = random->nextF();
|
||||
}
|
||||
// does not work with perspective or mul-by-alpha-mask
|
||||
stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
|
||||
stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
|
||||
return new GrConvolutionEffect(gKernelDirections[direction],
|
||||
kernelRadius,
|
||||
kernel);
|
||||
}
|
||||
case kErode_EffectType: {
|
||||
int direction = random_int(random, 2);
|
||||
int kernelRadius = random_int(random, 1, 4);
|
||||
// does not work with perspective or mul-by-alpha-mask
|
||||
stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
|
||||
stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
|
||||
return new GrMorphologyEffect(gKernelDirections[direction],
|
||||
kernelRadius,
|
||||
GrContext::kErode_MorphologyType);
|
||||
}
|
||||
case kDilate_EffectType: {
|
||||
int direction = random_int(random, 2);
|
||||
int kernelRadius = random_int(random, 1, 4);
|
||||
// does not work with perspective or mul-by-alpha-mask
|
||||
stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
|
||||
stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
|
||||
return new GrMorphologyEffect(gKernelDirections[direction],
|
||||
kernelRadius,
|
||||
GrContext::kDilate_MorphologyType);
|
||||
}
|
||||
default:
|
||||
GrCrash("Unexpected custom effect type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GrGpuGL::programUnitTest() {
|
||||
@ -250,7 +321,7 @@ bool GrGpuGL::programUnitTest() {
|
||||
pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
|
||||
}
|
||||
|
||||
GrCustomStage* customStages[GrDrawState::kNumStages];
|
||||
SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
|
||||
|
||||
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
|
||||
// enable the stage?
|
||||
@ -270,56 +341,34 @@ bool GrGpuGL::programUnitTest() {
|
||||
StageDesc& stage = pdesc.fStages[s];
|
||||
|
||||
stage.fCustomStageKey = 0;
|
||||
customStages[s] = NULL;
|
||||
|
||||
stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
|
||||
stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
|
||||
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 ||
|
||||
stage.fFetchMode == StageDesc::kDilate_FetchMode ||
|
||||
stage.fFetchMode == StageDesc::kErode_FetchMode) {
|
||||
stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
|
||||
}
|
||||
stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
|
||||
static const uint32_t kMulByAlphaMask =
|
||||
StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
|
||||
StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
|
||||
|
||||
switch (stage.fFetchMode) {
|
||||
case StageDesc::kSingle_FetchMode:
|
||||
stage.fKernelWidth = 0;
|
||||
break;
|
||||
case StageDesc::kConvolution_FetchMode:
|
||||
case StageDesc::kDilate_FetchMode:
|
||||
case StageDesc::kErode_FetchMode:
|
||||
stage.fKernelWidth = random_int(&random, 2, 8);
|
||||
if (StageDesc::k2x2_FetchMode == stage.fFetchMode) {
|
||||
stage.fInConfigFlags &= ~kMulByAlphaMask;
|
||||
break;
|
||||
case StageDesc::k2x2_FetchMode:
|
||||
stage.fKernelWidth = 0;
|
||||
stage.fInConfigFlags &= ~kMulByAlphaMask;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: is there a more elegant way to express this?
|
||||
if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
|
||||
int direction = random_int(&random, 2);
|
||||
float kernel[MAX_KERNEL_WIDTH];
|
||||
for (int i = 0; i < stage.fKernelWidth; i++) {
|
||||
kernel[i] = random.nextF();
|
||||
}
|
||||
customStages[s] = new GrConvolutionEffect(
|
||||
(GrSamplerState::FilterDirection)direction,
|
||||
stage.fKernelWidth, kernel);
|
||||
bool useCustomEffect = random_bool(&random);
|
||||
if (useCustomEffect) {
|
||||
customStages[s].reset(create_random_effect(&stage, &random));
|
||||
if (NULL != customStages[s]) {
|
||||
stage.fCustomStageKey =
|
||||
customStages[s]->getFactory().glStageKey(customStages[s]);
|
||||
customStages[s]->getFactory().glStageKey(*customStages[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
CachedData cachedData;
|
||||
if (!program.genProgram(this->glContextInfo(), customStages,
|
||||
&cachedData)) {
|
||||
GR_STATIC_ASSERT(sizeof(customStages) ==
|
||||
GrDrawState::kNumStages * sizeof(GrCustomStage*));
|
||||
GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
|
||||
if (!program.genProgram(this->glContextInfo(), stages, &cachedData)) {
|
||||
return false;
|
||||
}
|
||||
DeleteProgram(this->glInterface(), &cachedData);
|
||||
@ -469,32 +518,6 @@ void GrGpuGL::flushRadial2(int s) {
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuGL::flushConvolution(int s) {
|
||||
const GrSamplerState& sampler = this->getDrawState().getSampler(s);
|
||||
int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
|
||||
if (GrGLProgram::kUnusedUniform != kernelUni) {
|
||||
GL_CALL(Uniform1fv(kernelUni, sampler.getKernelWidth(),
|
||||
sampler.getKernel()));
|
||||
}
|
||||
int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
|
||||
if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuGL::flushTexelSize(int s) {
|
||||
const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
|
||||
if (GrGLProgram::kUnusedUniform != uni) {
|
||||
@ -692,8 +715,6 @@ bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
|
||||
|
||||
this->flushRadial2(s);
|
||||
|
||||
this->flushConvolution(s);
|
||||
|
||||
this->flushTexelSize(s);
|
||||
|
||||
this->flushTextureDomain(s);
|
||||
@ -706,7 +727,7 @@ bool GrGpuGL::flushGraphicsState(GrPrimitiveType type) {
|
||||
this->getDrawState().getTexture(s));
|
||||
fProgramData->fCustomStage[s]->setData(
|
||||
this->glInterface(), *texture,
|
||||
sampler.getCustomStage(), s);
|
||||
*sampler.getCustomStage(), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -875,7 +896,7 @@ void setup_custom_stage(GrGLProgram::ProgramDesc::StageDesc* stage,
|
||||
GrCustomStage* customStage = sampler.getCustomStage();
|
||||
if (customStage) {
|
||||
const GrProgramStageFactory& factory = customStage->getFactory();
|
||||
stage->fCustomStageKey = factory.glStageKey(customStage);
|
||||
stage->fCustomStageKey = factory.glStageKey(*customStage);
|
||||
customStages[index] = customStage;
|
||||
} else {
|
||||
stage->fCustomStageKey = 0;
|
||||
@ -1027,16 +1048,6 @@ void GrGpuGL::buildProgram(GrPrimitiveType type,
|
||||
case GrSamplerState::k4x4Downsample_Filter:
|
||||
stage.fFetchMode = StageDesc::k2x2_FetchMode;
|
||||
break;
|
||||
// performs fKernelWidth texture2D()s
|
||||
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;
|
||||
@ -1083,13 +1094,6 @@ void GrGpuGL::buildProgram(GrPrimitiveType type,
|
||||
}
|
||||
}
|
||||
|
||||
if (sampler.getFilter() == GrSamplerState::kDilate_Filter ||
|
||||
sampler.getFilter() == GrSamplerState::kErode_Filter) {
|
||||
stage.fKernelWidth = sampler.getKernelWidth();
|
||||
} else {
|
||||
stage.fKernelWidth = 0;
|
||||
}
|
||||
|
||||
setup_custom_stage(&stage, sampler, customStages,
|
||||
&fCurrentProgram, s);
|
||||
|
||||
@ -1098,7 +1102,6 @@ void GrGpuGL::buildProgram(GrPrimitiveType type,
|
||||
stage.fCoordMapping = (StageDesc::CoordMapping) 0;
|
||||
stage.fInConfigFlags = 0;
|
||||
stage.fFetchMode = (StageDesc::FetchMode) 0;
|
||||
stage.fKernelWidth = 0;
|
||||
stage.fCustomStageKey = 0;
|
||||
customStages[s] = NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user