aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrContext.cpp104
-rw-r--r--src/gpu/GrDrawState.h8
-rw-r--r--src/gpu/GrEffect.cpp20
-rw-r--r--src/gpu/SkGpuDevice.cpp8
-rw-r--r--src/gpu/effects/GrConfigConversionEffect.cpp18
-rw-r--r--src/gpu/effects/GrConfigConversionEffect.h10
-rw-r--r--src/gpu/effects/GrSingleTextureEffect.cpp55
-rw-r--r--src/gpu/effects/GrSingleTextureEffect.h22
-rw-r--r--src/gpu/gl/GrGLEffect.cpp2
-rw-r--r--src/gpu/gl/GrGLEffect.h11
-rw-r--r--src/gpu/gl/GrGLEffectMatrix.cpp213
-rw-r--r--src/gpu/gl/GrGLEffectMatrix.h97
-rw-r--r--src/gpu/gl/GrGLProgram.cpp71
-rw-r--r--src/gpu/gl/GrGLUniformManager.cpp18
-rw-r--r--src/gpu/gl/GrGLUniformManager.h4
15 files changed, 560 insertions, 101 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index f7f6b0c0b7..2a39fad722 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1307,35 +1307,44 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
ast.set(this, desc, match);
GrTexture* texture = ast.texture();
if (texture) {
- SkAutoTUnref<GrEffect> effect;
+ GrEffectStage stage;
+ // compute a matrix to perform the draw
+ GrMatrix textureMatrix;
+ if (flipY) {
+ textureMatrix.setTranslate(SK_Scalar1 * left,
+ SK_Scalar1 * (top + height));
+ textureMatrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
+ } else {
+ textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
+ }
+ textureMatrix.postIDiv(src->width(), src->height());
+
+ bool effectInstalled = false;
if (unpremul) {
- effect.reset(this->createPMToUPMEffect(src, swapRAndB));
+ if (this->installPMToUPMEffect(src, swapRAndB, textureMatrix, &stage)) {
+ effectInstalled = true;
+ unpremul = false; // we no longer need to do this on CPU after the readback.
+ }
}
// If we failed to create a PM->UPM effect and have no other conversions to perform then
// there is no longer any point to using the scratch.
- if (NULL != effect || flipY || swapRAndB) {
- if (NULL == effect) {
- effect.reset(GrConfigConversionEffect::Create(src, swapRAndB));
- GrAssert(NULL != effect);
- } else {
- unpremul = false; // we will handle the UPM conversion in the draw
+ if (effectInstalled || flipY || swapRAndB) {
+ if (!effectInstalled) {
+ SkAssertResult(GrConfigConversionEffect::InstallEffect(
+ src,
+ swapRAndB,
+ GrConfigConversionEffect::kNone_PMConversion,
+ textureMatrix,
+ &stage));
}
swapRAndB = false; // we will handle the swap in the draw.
+ flipY = false; // we already incorporated the y flip in the matrix
GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
GrDrawState* drawState = fGpu->drawState();
+ *drawState->stage(0) = stage;
+
drawState->setRenderTarget(texture->asRenderTarget());
- GrMatrix matrix;
- if (flipY) {
- matrix.setTranslate(SK_Scalar1 * left,
- SK_Scalar1 * (top + height));
- matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
- flipY = false; // the y flip will be handled in the draw
- } else {
- matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
- }
- matrix.postIDiv(src->width(), src->height());
- drawState->stage(0)->setEffect(effect, matrix);
GrRect rect = GrRect::MakeWH(GrIntToScalar(width), GrIntToScalar(height));
fGpu->drawSimpleRect(rect, NULL);
// we want to read back from the scratch's origin
@@ -1350,7 +1359,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
readConfig, buffer, rowBytes, readUpsideDown)) {
return false;
}
- // Perform any conversions we weren't able to perfom using a scratch texture.
+ // Perform any conversions we weren't able to perform using a scratch texture.
if (unpremul || swapRAndB || flipY) {
// These are initialized to suppress a warning
SkCanvas::Config8888 srcC8888 = SkCanvas::kNative_Premul_Config8888;
@@ -1480,7 +1489,7 @@ void GrContext::writeRenderTargetPixels(GrRenderTarget* target,
return;
}
#endif
- SkAutoTUnref<GrEffect> effect;
+
bool swapRAndB = (fGpu->preferredReadPixelsConfig(config) == GrPixelConfigSwapRAndB(config));
GrPixelConfig textureConfig;
@@ -1499,15 +1508,24 @@ void GrContext::writeRenderTargetPixels(GrRenderTarget* target,
if (NULL == texture) {
return;
}
+
+ GrEffectStage stage;
+ GrMatrix textureMatrix;
+ textureMatrix.setIDiv(texture->width(), texture->height());
+
// allocate a tmp buffer and sw convert the pixels to premul
SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
+ bool effectInstalled = false;
if (kUnpremul_PixelOpsFlag & flags) {
if (kRGBA_8888_GrPixelConfig != config && kBGRA_8888_GrPixelConfig != config) {
return;
}
- effect.reset(this->createUPMToPMEffect(texture, swapRAndB));
- if (NULL == effect) {
+ effectInstalled = this->installUPMToPMEffect(texture,
+ swapRAndB,
+ textureMatrix,
+ &stage);
+ if (!effectInstalled) {
SkCanvas::Config8888 srcConfig8888, dstConfig8888;
GR_DEBUGCODE(bool success = )
grconfig_to_config8888(config, true, &srcConfig8888);
@@ -1524,9 +1542,13 @@ void GrContext::writeRenderTargetPixels(GrRenderTarget* target,
rowBytes = 4 * width;
}
}
- if (NULL == effect) {
- effect.reset(GrConfigConversionEffect::Create(texture, swapRAndB));
- GrAssert(NULL != effect);
+ if (!effectInstalled) {
+ SkAssertResult(GrConfigConversionEffect::InstallEffect(
+ texture,
+ swapRAndB,
+ GrConfigConversionEffect::kNone_PMConversion,
+ textureMatrix,
+ &stage));
}
this->writeTexturePixels(texture,
@@ -1536,15 +1558,13 @@ void GrContext::writeRenderTargetPixels(GrRenderTarget* target,
GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
GrDrawState* drawState = fGpu->drawState();
+ *drawState->stage(0) = stage;
GrMatrix matrix;
matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
drawState->setViewMatrix(matrix);
drawState->setRenderTarget(target);
- matrix.setIDiv(texture->width(), texture->height());
- drawState->stage(0)->setEffect(effect, matrix);
-
fGpu->drawSimpleRect(GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), NULL);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1726,7 +1746,10 @@ void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
}
}
-GrEffect* GrContext::createPMToUPMEffect(GrTexture* texture, bool swapRAndB) {
+bool GrContext::installPMToUPMEffect(GrTexture* texture,
+ bool swapRAndB,
+ const GrMatrix& matrix,
+ GrEffectStage* stage) {
if (!fDidTestPMConversions) {
test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
fDidTestPMConversions = true;
@@ -1734,13 +1757,17 @@ GrEffect* GrContext::createPMToUPMEffect(GrTexture* texture, bool swapRAndB) {
GrConfigConversionEffect::PMConversion pmToUPM =
static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
- return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM);
+ GrConfigConversionEffect::InstallEffect(texture, swapRAndB, pmToUPM, matrix, stage);
+ return true;
} else {
- return NULL;
+ return false;
}
}
-GrEffect* GrContext::createUPMToPMEffect(GrTexture* texture, bool swapRAndB) {
+bool GrContext::installUPMToPMEffect(GrTexture* texture,
+ bool swapRAndB,
+ const GrMatrix& matrix,
+ GrEffectStage* stage) {
if (!fDidTestPMConversions) {
test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
fDidTestPMConversions = true;
@@ -1748,9 +1775,10 @@ GrEffect* GrContext::createUPMToPMEffect(GrTexture* texture, bool swapRAndB) {
GrConfigConversionEffect::PMConversion upmToPM =
static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
- return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM);
+ GrConfigConversionEffect::InstallEffect(texture, swapRAndB, upmToPM, matrix, stage);
+ return true;
} else {
- return NULL;
+ return false;
}
}
@@ -1808,7 +1836,7 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
i < scaleFactorY ? 0.5f : 1.0f);
paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect,
- (srcTexture, true)), matrix)->unref();
+ (srcTexture, matrix, true)))->unref();
this->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
@@ -1865,8 +1893,8 @@ GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
// FIXME: This should be mitchell, not bilinear.
matrix.setIDiv(srcTexture->width(), srcTexture->height());
this->setRenderTarget(dstTexture->asRenderTarget());
- paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect,(srcTexture, true)),
- matrix)->unref();
+ paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect,(srcTexture,
+ matrix, true)))->unref();
SkRect dstRect(srcRect);
scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
this->drawRectToRect(paint, dstRect, srcRect);
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 3c6c3a371a..b53944189a 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -198,16 +198,16 @@ public:
}
void createTextureEffect(int stageIdx, GrTexture* texture, const GrMatrix& matrix) {
GrAssert(!this->getStage(stageIdx).getEffect());
- GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture));
- this->stage(stageIdx)->setEffect(effect, matrix)->unref();
+ GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix));
+ this->stage(stageIdx)->setEffect(effect)->unref();
}
void createTextureEffect(int stageIdx,
GrTexture* texture,
const GrMatrix& matrix,
const GrTextureParams& params) {
GrAssert(!this->getStage(stageIdx).getEffect());
- GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, params));
- this->stage(stageIdx)->setEffect(effect, matrix)->unref();
+ GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params));
+ this->stage(stageIdx)->setEffect(effect)->unref();
}
diff --git a/src/gpu/GrEffect.cpp b/src/gpu/GrEffect.cpp
index 09032bf0f9..d470c9cc5f 100644
--- a/src/gpu/GrEffect.cpp
+++ b/src/gpu/GrEffect.cpp
@@ -20,6 +20,26 @@ SkTArray<GrEffectTestFactory*, true>* GrEffectTestFactory::GetFactories() {
}
#endif
+namespace GrEffectUnitTest {
+const SkMatrix& TestMatrix(SkRandom* random) {
+ static SkMatrix gMatrices[5];
+ static bool gOnce;
+ if (!gOnce) {
+ gMatrices[0].reset();
+ gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
+ gMatrices[2].setRotate(SkIntToScalar(17));
+ gMatrices[3].setRotate(SkIntToScalar(185));
+ gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
+ gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf);
+ gMatrices[4].setRotate(SkIntToScalar(215));
+ gMatrices[4].set(SkMatrix::kMPersp0, SkFloatToScalar(0.00013f));
+ gMatrices[4].set(SkMatrix::kMPersp1, SkFloatToScalar(-0.000039f));
+ gOnce = true;
+ }
+ return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
+}
+}
+
class GrEffect_Globals {
public:
static GrMemoryPool* GetTLS() {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index cdccbcd049..946d54dcc8 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -608,7 +608,7 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
GrScalar sy = SkFloatToScalar(1.f / bitmap.height());
matrix.postScale(sx, sy);
}
- stage->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, params)), matrix)->unref();
+ stage->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params)))->unref();
return true;
}
@@ -875,7 +875,7 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
matrix.setIDiv(pathTexture->width(), pathTexture->height());
// Blend pathTexture over blurTexture.
context->setRenderTarget(blurTexture->asRenderTarget());
- paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (pathTexture)), matrix)->unref();
+ paint.colorStage(0)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (pathTexture, matrix)))->unref();
if (SkMaskFilter::kInner_BlurType == blurType) {
// inner: dst = dst * src
paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
@@ -906,7 +906,7 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath,
matrix.postIDiv(blurTexture->width(), blurTexture->height());
grp->coverageStage(MASK_IDX)->reset();
- grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (blurTexture)), matrix)->unref();
+ grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (blurTexture, matrix)))->unref();
context->drawRect(*grp, finalRect);
return true;
}
@@ -962,7 +962,7 @@ bool drawWithMaskFilter(GrContext* context, const SkPath& devPath,
m.setTranslate(-dstM.fBounds.fLeft*SK_Scalar1, -dstM.fBounds.fTop*SK_Scalar1);
m.postIDiv(texture->width(), texture->height());
- grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture)), m)->unref();
+ grp->coverageStage(MASK_IDX)->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, m)))->unref();
GrRect d;
d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
GrIntToScalar(dstM.fBounds.fTop),
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 086064545e..54d7285c93 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -218,21 +218,27 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
}
}
-GrEffect* GrConfigConversionEffect::Create(GrTexture* texture,
- bool swapRedAndBlue,
- PMConversion pmConversion) {
+bool GrConfigConversionEffect::InstallEffect(GrTexture* texture,
+ bool swapRedAndBlue,
+ PMConversion pmConversion,
+ const GrMatrix& matrix,
+ GrEffectStage* stage) {
if (!swapRedAndBlue && kNone_PMConversion == pmConversion) {
// If we returned a GrConfigConversionEffect that was equivalent to a GrSingleTextureEffect
// then we may pollute our texture cache with redundant shaders. So in the case that no
// conversions were requested we instead return a GrSingleTextureEffect.
- return SkNEW_ARGS(GrSingleTextureEffect, (texture));
+ stage->setEffect(SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix)), matrix)->unref();
+ return true;
} else {
if (kRGBA_8888_GrPixelConfig != texture->config() &&
kBGRA_8888_GrPixelConfig != texture->config() &&
kNone_PMConversion != pmConversion) {
// The PM conversions assume colors are 0..255
- return NULL;
+ return false;
}
- return SkNEW_ARGS(GrConfigConversionEffect, (texture, swapRedAndBlue, pmConversion));
+ stage->setEffect(SkNEW_ARGS(GrConfigConversionEffect, (texture,
+ swapRedAndBlue,
+ pmConversion)), matrix)->unref();
+ return true;
}
}
diff --git a/src/gpu/effects/GrConfigConversionEffect.h b/src/gpu/effects/GrConfigConversionEffect.h
index 7c5f03fa2b..5b531d4d58 100644
--- a/src/gpu/effects/GrConfigConversionEffect.h
+++ b/src/gpu/effects/GrConfigConversionEffect.h
@@ -33,10 +33,12 @@ public:
kPMConversionCnt
};
- // This will fail if the config is not 8888 and a PM conversion is requested.
- static GrEffect* Create(GrTexture*,
- bool swapRedAndBlue,
- PMConversion pmConversion = kNone_PMConversion);
+ // Installs an effect in the GrEffectStage to perform a config conversion.
+ static bool InstallEffect(GrTexture*,
+ bool swapRedAndBlue,
+ PMConversion pmConversion,
+ const GrMatrix& matrix,
+ GrEffectStage* stage);
static const char* Name() { return "Config Conversion"; }
typedef GrGLConfigConversionEffect GLEffect;
diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp
index 8866153962..0f3b614dd7 100644
--- a/src/gpu/effects/GrSingleTextureEffect.cpp
+++ b/src/gpu/effects/GrSingleTextureEffect.cpp
@@ -7,6 +7,7 @@
#include "effects/GrSingleTextureEffect.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
#include "gl/GrGLSL.h"
#include "gl/GrGLTexture.h"
#include "GrTBackendEffectFactory.h"
@@ -16,25 +17,43 @@ class GrGLSingleTextureEffect : public GrGLEffect {
public:
GrGLSingleTextureEffect(const GrBackendEffectFactory& factory, const GrEffect&)
: INHERITED (factory) {
+ fRequiresTextureMatrix = false;
}
virtual void emitCode(GrGLShaderBuilder* builder,
const GrEffectStage&,
- EffectKey,
+ EffectKey key,
const char* vertexCoords,
const char* outputColor,
const char* inputColor,
const TextureSamplerArray& samplers) SK_OVERRIDE {
-
+ const char* coordName;
+ GrSLType coordType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coordName);
builder->fFSCode.appendf("\t%s = ", outputColor);
- builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0]);
+ builder->appendTextureLookupAndModulate(&builder->fFSCode,
+ inputColor,
+ samplers[0],
+ coordName,
+ coordType);
builder->fFSCode.append(";\n");
}
- static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&) { return 0; }
+ static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
+ const GrSingleTextureEffect& ste =
+ static_cast<const GrSingleTextureEffect&>(*stage.getEffect());
+ return GrGLEffectMatrix::GenKey(ste.getMatrix(),
+ stage.getCoordChangeMatrix(),
+ ste.texture(0));
+ }
-private:
+ virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
+ const GrSingleTextureEffect& ste =
+ static_cast<const GrSingleTextureEffect&>(*stage.getEffect());
+ fEffectMatrix.setData(uman, ste.getMatrix(), stage.getCoordChangeMatrix(), ste.texture(0));
+ }
+private:
+ GrGLEffectMatrix fEffectMatrix;
typedef GrGLEffect INHERITED;
};
@@ -43,16 +62,39 @@ private:
GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture)
: INHERITED(1)
, fTextureAccess(texture) {
+ fMatrix.reset();
}
GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, bool bilerp)
: INHERITED(1)
, fTextureAccess(texture, bilerp) {
+ fMatrix.reset();
}
GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrTextureParams& params)
: INHERITED(1)
, fTextureAccess(texture, params) {
+ fMatrix.reset();
+}
+
+GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrMatrix& m)
+ : INHERITED(1)
+ , fTextureAccess(texture)
+ , fMatrix(m) {
+}
+
+GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const GrMatrix& m, bool bilerp)
+ : INHERITED(1)
+ , fTextureAccess(texture, bilerp)
+ , fMatrix(m) {
+}
+
+GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
+ const GrMatrix& m,
+ const GrTextureParams& params)
+ : INHERITED(1)
+ , fTextureAccess(texture, params)
+ , fMatrix(m) {
}
GrSingleTextureEffect::~GrSingleTextureEffect() {
@@ -76,5 +118,6 @@ GrEffect* GrSingleTextureEffect::TestCreate(SkRandom* random,
GrTexture* textures[]) {
int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
GrEffectUnitTest::kAlphaTextureIdx;
- return SkNEW_ARGS(GrSingleTextureEffect, (textures[texIdx]));
+ const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
+ return SkNEW_ARGS(GrSingleTextureEffect, (textures[texIdx], matrix));
}
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index 346a6f48d8..23b416d3b3 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -9,6 +9,7 @@
#define GrSingleTextureEffect_DEFINED
#include "GrEffect.h"
+#include "GrMatrix.h"
class GrGLSingleTextureEffect;
@@ -18,28 +19,37 @@ class GrGLSingleTextureEffect;
class GrSingleTextureEffect : public GrEffect {
public:
- /** Uses default texture params (unfiltered, clamp) */
- GrSingleTextureEffect(GrTexture* texture);
-
- /** Uses default tile mode (clamp) */
- GrSingleTextureEffect(GrTexture* texture, bool bilerp);
-
+ /** These three constructors assume an identity matrix */
+ GrSingleTextureEffect(GrTexture* texture); /* unfiltered, clamp mode */
+ GrSingleTextureEffect(GrTexture* texture, bool bilerp); /* clamp mode */
GrSingleTextureEffect(GrTexture* texture, const GrTextureParams&);
+ /** These three constructors take an explicit matrix */
+ GrSingleTextureEffect(GrTexture*, const GrMatrix&); /* unfiltered, clamp mode */
+ GrSingleTextureEffect(GrTexture*, const GrMatrix&, bool bilerp); /* clamp mode */
+ GrSingleTextureEffect(GrTexture*, const GrMatrix&, const GrTextureParams&);
+
virtual ~GrSingleTextureEffect();
virtual const GrTextureAccess& textureAccess(int index) const SK_OVERRIDE;
static const char* Name() { return "Single Texture"; }
+ const GrMatrix& getMatrix() const { return fMatrix; }
+
typedef GrGLSingleTextureEffect GLEffect;
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+ virtual bool isEqual(const GrEffect& effect) const SK_OVERRIDE {
+ const GrSingleTextureEffect& ste = static_cast<const GrSingleTextureEffect&>(effect);
+ return INHERITED::isEqual(effect) && fMatrix.cheapEqualTo(ste.getMatrix());
+ }
private:
GR_DECLARE_EFFECT_TEST;
GrTextureAccess fTextureAccess;
+ GrMatrix fMatrix;
typedef GrEffect INHERITED;
};
diff --git a/src/gpu/gl/GrGLEffect.cpp b/src/gpu/gl/GrGLEffect.cpp
index 0bbf1f7ccb..5e0875b71c 100644
--- a/src/gpu/gl/GrGLEffect.cpp
+++ b/src/gpu/gl/GrGLEffect.cpp
@@ -10,6 +10,8 @@
GrGLEffect::GrGLEffect(const GrBackendEffectFactory& factory)
: fFactory(factory) {
+
+ fRequiresTextureMatrix = true;
}
GrGLEffect::~GrGLEffect() {
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 30b8455a68..0fd5722cb8 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -51,7 +51,9 @@ public:
@param builder Interface used to emit code in the shaders.
@param stage The effect stage that generated this program stage.
- @param key The key that was computed by EffectKey() from the generating GrEffect.
+ @param key The key that was computed by GenKey() from the generating GrEffect.
+ Only the bits indicated by GrBackendEffectFactory::kEffectKeyBits are
+ guaranteed to match the value produced by GenKey();
@param vertexCoords A vec2 of texture coordinates in the VS, which may be altered. This will
be removed soon and stages will be responsible for computing their own
coords.
@@ -85,7 +87,14 @@ public:
static EffectKey GenTextureKey(const GrEffect&, const GrGLCaps&);
+ bool requiresTextureMatrix() const { return fRequiresTextureMatrix; }
+
+
protected:
+ // HACK: This is a temporary field that allows GrGLEffect subclasses to opt into the new
+ // shader gen where a texture matrix is not automatically inserted. It defaults to true and is
+ // set to false in a subclass to opt into the new behavior.
+ bool fRequiresTextureMatrix;
const GrBackendEffectFactory& fFactory;
};
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
new file mode 100644
index 0000000000..0db87f9773
--- /dev/null
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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 "GrGLEffectMatrix.h"
+#include "GrTexture.h"
+
+GrGLEffect::EffectKey GrGLEffectMatrix::GenKey(const SkMatrix& effectMatrix,
+ const SkMatrix& coordChangeMatrix,
+ const GrTexture* texture) {
+ SkMatrix::TypeMask type0 = effectMatrix.getType();
+ SkMatrix::TypeMask type1 = coordChangeMatrix.getType();
+
+ static const int kNonTransMask = SkMatrix::kAffine_Mask |
+ SkMatrix::kScale_Mask |
+ SkMatrix::kPerspective_Mask;
+ int combinedTypes = type0 | type1;
+
+ bool reverseY = (NULL != texture) && GrSurface::kBottomLeft_Origin == texture->origin();
+
+ if (SkMatrix::kPerspective_Mask & combinedTypes) {
+ return kGeneral_Key;
+ } else if ((kNonTransMask & combinedTypes) || reverseY) {
+ return kNoPersp_Key;
+ } else if (kTrans_Key & combinedTypes) {
+ return kTrans_Key;
+ } else {
+ GrAssert(effectMatrix.isIdentity() && coordChangeMatrix.isIdentity());
+ return kIdentity_Key;
+ }
+}
+
+GrSLType GrGLEffectMatrix::emitCode(GrGLShaderBuilder* builder,
+ EffectKey key,
+ const char* vertexCoords,
+ const char** fsCoordName,
+ const char** vsCoordName,
+ const char* suffix) {
+ GrSLType varyingType;
+ const char* uniName;
+ key &= kKeyMask;
+ switch (key) {
+ case kIdentity_Key:
+ fUniType = kVoid_GrSLType;
+ varyingType = kVec2f_GrSLType;
+ break;
+ case kTrans_Key:
+ fUniType = kVec2f_GrSLType;
+ uniName = "StageTranslate";
+ varyingType = kVec2f_GrSLType;
+ break;
+ case kNoPersp_Key:
+ fUniType = kMat33f_GrSLType;
+ uniName = "StageMatrix";
+ varyingType = kVec2f_GrSLType;
+ break;
+ case kGeneral_Key:
+ fUniType = kMat33f_GrSLType;
+ uniName = "StageMatrix";
+ varyingType = kVec3f_GrSLType;
+ break;
+ default:
+ GrCrash("Unexpected key.");
+ }
+ SkString suffixedUniName;
+ if (NULL != suffix) {
+ suffixedUniName.append(uniName);
+ suffixedUniName.append(suffix);
+ uniName = suffixedUniName.c_str();
+ }
+ if (kVoid_GrSLType != fUniType) {
+ fUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+ fUniType,
+ uniName,
+ &uniName);
+ }
+
+ const char* varyingName = "StageCoord";
+ SkString suffixedVaryingName;
+ if (NULL != suffix) {
+ suffixedVaryingName.append(varyingName);
+ suffixedVaryingName.append(suffix);
+ varyingName = suffixedVaryingName.c_str();
+ }
+ const char* vsVaryingName;
+ const char* fsVaryingName;
+ builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+
+ // varying = matrix * vertex-coords (logically)
+ switch (fUniType) {
+ case kVoid_GrSLType:
+ GrAssert(kVec2f_GrSLType == varyingType);
+ builder->fVSCode.appendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
+ break;
+ case kVec2f_GrSLType:
+ GrAssert(kVec2f_GrSLType == varyingType);
+ builder->fVSCode.appendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
+ break;
+ case kMat33f_GrSLType: {
+ GrAssert(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
+ if (kVec2f_GrSLType == varyingType) {
+ builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+ vsVaryingName, uniName, vertexCoords);
+ } else {
+ builder->fVSCode.appendf("\t%s = %s * vec3(%s, 1);\n",
+ vsVaryingName, uniName, vertexCoords);
+ }
+ break;
+ }
+ default:
+ GrCrash("Unexpected uniform type.");
+ }
+ if (NULL != vsCoordName) {
+ *vsCoordName = vsVaryingName;
+ }
+ if (NULL != fsCoordName) {
+ *fsCoordName = fsVaryingName;
+ }
+ return varyingType;
+}
+
+/**
+ * This is similar to emitCode except that it performs perspective division in the FS if the
+ * texture coordinates have a w coordinate. The fsCoordName always refers to a vec2f.
+ */
+void GrGLEffectMatrix::emitCodeMakeFSCoords2D(GrGLShaderBuilder* builder,
+ EffectKey key,
+ const char* vertexCoords,
+ const char** fsCoordName,
+ const char** vsVaryingName,
+ GrSLType* vsVaryingType,
+ const char* suffix) {
+ const char* fsVaryingName;
+
+ GrSLType varyingType = this->emitCode(builder,
+ key,
+ vertexCoords,
+ &fsVaryingName,
+ vsVaryingName,
+ suffix);
+ if (kVec3f_GrSLType == varyingType) {
+
+ const char* coordName = "coords2D";
+ SkString suffixedCoordName;
+ if (NULL != suffix) {
+ suffixedCoordName.append(coordName);
+ suffixedCoordName.append(suffix);
+ coordName = suffixedCoordName.c_str();
+ }
+ builder->fFSCode.appendf("\tvec2 %s = %s.xy / %s.z;",
+ coordName, fsVaryingName, fsVaryingName);
+ if (NULL != fsCoordName) {
+ *fsCoordName = coordName;
+ }
+ } else if(NULL != fsCoordName) {
+ *fsCoordName = fsVaryingName;
+ }
+ if (NULL != vsVaryingType) {
+ *vsVaryingType = varyingType;
+ }
+}
+
+void GrGLEffectMatrix::setData(const GrGLUniformManager& uniformManager,
+ const SkMatrix& matrix,
+ const SkMatrix& coordChangeMatrix,
+ const GrTexture* texture) {
+ GrAssert((GrGLUniformManager::kInvalidUniformHandle == fUni) ==
+ (kVoid_GrSLType == fUniType));
+ switch (fUniType) {
+ case kVoid_GrSLType:
+ GrAssert(matrix.isIdentity());
+ GrAssert(coordChangeMatrix.isIdentity());
+ GrAssert(NULL == texture || GrSurface::kTopLeft_Origin == texture->origin());
+ return;
+ case kVec2f_GrSLType: {
+ GrAssert(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType()));
+ GrAssert(NULL == texture || GrSurface::kTopLeft_Origin == texture->origin());
+ SkScalar tx = matrix[SkMatrix::kMTransX] + coordChangeMatrix[SkMatrix::kMTransX];
+ SkScalar ty = matrix[SkMatrix::kMTransY] + coordChangeMatrix[SkMatrix::kMTransY];
+ if (fPrevMatrix.get(SkMatrix::kMTransX) != tx ||
+ fPrevMatrix.get(SkMatrix::kMTransY) != ty) {
+ uniformManager.set2f(fUni, tx, ty);
+ fPrevMatrix.set(SkMatrix::kMTransX, tx);
+ fPrevMatrix.set(SkMatrix::kMTransY, ty);
+ }
+ break;
+ }
+ case kMat33f_GrSLType: {
+ SkMatrix combined;
+ combined.setConcat(matrix, coordChangeMatrix);
+ if (NULL != texture && GrSurface::kBottomLeft_Origin == texture->origin()) {
+ // combined.postScale(1,-1);
+ // combined.postTranslate(0,1);
+ combined.set(SkMatrix::kMSkewY,
+ combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
+ combined.set(SkMatrix::kMScaleY,
+ combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
+ combined.set(SkMatrix::kMTransY,
+ combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
+ }
+ if (!fPrevMatrix.cheapEqualTo(combined)) {
+ uniformManager.setSkMatrix(fUni, combined);
+ fPrevMatrix = combined;
+ }
+ break;
+ }
+ default:
+ GrCrash("Unexpected uniform type.");
+ }
+}
diff --git a/src/gpu/gl/GrGLEffectMatrix.h b/src/gpu/gl/GrGLEffectMatrix.h
new file mode 100644
index 0000000000..9e45f3ef82
--- /dev/null
+++ b/src/gpu/gl/GrGLEffectMatrix.h
@@ -0,0 +1,97 @@
+/*
+ * 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 GrGLEffectMatrix_DEFINED
+#define GrGLEffectMatrix_DEFINED
+
+#include "GrGLEffect.h"
+#include "SkMatrix.h"
+
+class GrTexture;
+class SkRandom;
+
+/**
+ * This is a helper to implement a texture matrix in a GrGLEffect.
+ */
+class GrGLEffectMatrix {
+public:
+ typedef GrGLEffect::EffectKey EffectKey;
+ /**
+ * The matrix uses kKeyBits of the effect's EffectKey. A GrGLEffect may place these bits at an
+ * arbitrary shift in its final key. However, when GrGLEffectMatrix::emitCode*() code is called
+ * the relevant bits must be in the lower kKeyBits of the key parameter.
+ */
+ enum {
+ kKeyBits = 2,
+ kKeyMask = (1 << kKeyBits) - 1,
+ };
+
+ GrGLEffectMatrix() : fUni(GrGLUniformManager::kInvalidUniformHandle) {
+ fPrevMatrix = SkMatrix::InvalidMatrix();
+ }
+
+ /**
+ * Generates the key for the portion of the code emitted by this class's emitCode() function.
+ * Pass a texture to make GrGLEffectMatrix automatically adjust for the texture's origin. Pass
+ * NULL when not using the EffectMatrix for a texture lookups, or if the GrGLEffect subclass
+ * wants to handle origin adjustments in some other manner. coordChangeMatrix is the matrix
+ * from GrEffectStage.
+ */
+ static EffectKey GenKey(const SkMatrix& effectMatrix,
+ const SkMatrix& coordChangeMatrix,
+ const GrTexture*);
+
+ /**
+ * Emits code to implement the matrix in the VS. A varying is added as an output of the VS and
+ * input to the FS. The varying may be either a vec2f or vec3f depending upon whether
+ * perspective interpolation is required or not. The names of the varying in the VS and FS are
+ * are returned as output parameters and the type of the varying is the return value. The suffix
+ * is an optional parameter that can be used to make all variables emitted by the object
+ * unique within a stage. It is only necessary if multiple GrGLEffectMatrix objects are used by
+ * a GrGLEffect.
+ */
+ GrSLType emitCode(GrGLShaderBuilder*,
+ EffectKey,
+ const char* vertexCoords,
+ const char** fsCoordName, /* optional */
+ const char** vsCoordName = NULL,
+ const char* suffix = NULL);
+
+ /**
+ * This is similar to emitCode except that it performs perspective division in the FS if the
+ * texture coordinates have a w coordinate. The fsCoordName always refers to a vec2f.
+ */
+ void emitCodeMakeFSCoords2D(GrGLShaderBuilder*,
+ EffectKey,
+ const char* vertexCoords,
+ const char** fsCoordName, /* optional */
+ const char** vsVaryingName = NULL,
+ GrSLType* vsVaryingType = NULL,
+ const char* suffix = NULL);
+ /**
+ * Call from a GrGLEffect's subclass to update the texture matrix. The matrix,
+ * coordChangeMatrix, and texture params should match those used with GenKey.
+ */
+ void setData(const GrGLUniformManager& uniformManager,
+ const SkMatrix& effectMatrix,
+ const SkMatrix& coordChangeMatrix,
+ const GrTexture*);
+
+private:
+ enum {
+ kIdentity_Key = 0,
+ kTrans_Key = 1,
+ kNoPersp_Key = 2,
+ kGeneral_Key = 3,
+ };
+
+ GrGLUniformManager::UniformHandle fUni;
+ GrSLType fUniType;
+ SkMatrix fPrevMatrix;
+};
+
+#endif \ No newline at end of file
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index cd16d9e24f..120bd1e3ad 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -909,57 +909,64 @@ GrGLEffect* GrGLProgram::GenStageCode(const GrEffectStage& stage,
/// Vertex Shader Stuff
- // decide whether we need a matrix to transform texture coords and whether the varying needs a
- // perspective coord.
- const char* matName = NULL;
- GrSLType texCoordVaryingType;
- if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
- texCoordVaryingType = kVec2f_GrSLType;
- } else {
- uniforms->fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
- kMat33f_GrSLType, "TexM", &matName);
- builder->getUniformVariable(uniforms->fTextureMatrixUni);
-
- if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
+ const char* vertexCoords;
+
+ // Has the effect not yet been updated to insert its own texture matrix if necessary.
+ if (glEffect->requiresTextureMatrix()) {
+ // Decide whether we need a matrix to transform texture coords and whether the varying needs
+ // a perspective coord.
+ const char* matName = NULL;
+ GrSLType texCoordVaryingType;
+ if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
texCoordVaryingType = kVec2f_GrSLType;
} else {
- texCoordVaryingType = kVec3f_GrSLType;
+ uniforms->fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+ kMat33f_GrSLType, "TexM", &matName);
+ builder->getUniformVariable(uniforms->fTextureMatrixUni);
+
+ if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
+ texCoordVaryingType = kVec2f_GrSLType;
+ } else {
+ texCoordVaryingType = kVec3f_GrSLType;
+ }
+ }
+ const char *varyingVSName, *varyingFSName;
+ builder->addVarying(texCoordVaryingType,
+ "Stage",
+ &varyingVSName,
+ &varyingFSName);
+ builder->setupTextureAccess(varyingFSName, texCoordVaryingType);
+
+ if (!matName) {
+ GrAssert(kVec2f_GrSLType == texCoordVaryingType);
+ builder->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord);
+ } else {
+ // varying = texMatrix * texCoord
+ builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
+ varyingVSName, matName, vsInCoord,
+ vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType)));
}
+ vertexCoords = varyingVSName;
+ } else {
+ vertexCoords = vsInCoord;
}
- const char *varyingVSName, *varyingFSName;
- builder->addVarying(texCoordVaryingType,
- "Stage",
- &varyingVSName,
- &varyingFSName);
- builder->setupTextureAccess(varyingFSName, texCoordVaryingType);
+ // setup texture samplers for gl effect
int numTextures = effect->numTextures();
SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
-
textureSamplers.push_back_n(numTextures);
-
for (int i = 0; i < numTextures; ++i) {
textureSamplers[i].init(builder, &effect->textureAccess(i));
uniforms->fSamplerUniforms.push_back(textureSamplers[i].fSamplerUniform);
}
- if (!matName) {
- GrAssert(kVec2f_GrSLType == texCoordVaryingType);
- builder->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord);
- } else {
- // varying = texMatrix * texCoord
- builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
- varyingVSName, matName, vsInCoord,
- vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType)));
- }
-
// Enclose custom code in a block to avoid namespace conflicts
builder->fVSCode.appendf("\t{ // %s\n", glEffect->name());
builder->fFSCode.appendf("\t{ // %s \n", glEffect->name());
glEffect->emitCode(builder,
stage,
desc.fEffectKey,
- varyingVSName,
+ vertexCoords,
fsOutColor,
fsInColor,
textureSamplers);
diff --git a/src/gpu/gl/GrGLUniformManager.cpp b/src/gpu/gl/GrGLUniformManager.cpp
index 684ef8c37e..7a92d25b28 100644
--- a/src/gpu/gl/GrGLUniformManager.cpp
+++ b/src/gpu/gl/GrGLUniformManager.cpp
@@ -8,6 +8,7 @@
#include "gl/GrGLShaderBuilder.h"
#include "gl/GrGLProgram.h"
#include "gl/GrGLUniformHandle.h"
+#include "SkMatrix.h"
#define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, OFFSET, COUNT) \
GrAssert(offset + arrayCount <= uni.fArrayCount || \
@@ -231,6 +232,23 @@ void GrGLUniformManager::setMatrix4fv(UniformHandle u,
}
}
+void GrGLUniformManager::setSkMatrix(UniformHandle u, const SkMatrix& matrix) const {
+ GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT);
+ GrGLfloat mt[] = {
+ matrix.get(SkMatrix::kMScaleX),
+ matrix.get(SkMatrix::kMSkewY),
+ matrix.get(SkMatrix::kMPersp0),
+ matrix.get(SkMatrix::kMSkewX),
+ matrix.get(SkMatrix::kMScaleY),
+ matrix.get(SkMatrix::kMPersp1),
+ matrix.get(SkMatrix::kMTransX),
+ matrix.get(SkMatrix::kMTransY),
+ matrix.get(SkMatrix::kMPersp2),
+ };
+ this->setMatrix3f(u, mt);
+}
+
+
void GrGLUniformManager::getUniformLocations(GrGLuint programID, const BuilderUniformArray& uniforms) {
GrAssert(uniforms.count() == fUniforms.count());
int count = fUniforms.count();
diff --git a/src/gpu/gl/GrGLUniformManager.h b/src/gpu/gl/GrGLUniformManager.h
index e9856c6ea3..8f435d3037 100644
--- a/src/gpu/gl/GrGLUniformManager.h
+++ b/src/gpu/gl/GrGLUniformManager.h
@@ -15,6 +15,7 @@
#include "SkTArray.h"
class GrGLContextInfo;
+class SkMatrix;
/** Manages a program's uniforms.
*/
@@ -47,6 +48,9 @@ public:
void setMatrix3fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const;
void setMatrix4fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const;
+ // convenience method for uploading a SkMatrix to a 3x3 matrix uniform
+ void setSkMatrix(UniformHandle, const SkMatrix&) const;
+
struct BuilderUniform {
GrGLShaderVar fVariable;
uint32_t fVisibility;