diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-11-01 15:40:47 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-11-01 15:40:47 +0000 |
commit | c3a58f345de16c185db3a20578c7ddf52bc89d38 (patch) | |
tree | 90b83991981cce5a6e19e212911122f240aa8470 /src/gpu/gl | |
parent | 66e534da8e2b3de928f7ce132da61947a73ab7cb (diff) |
Reland r6233 with fix for config conversion texture matrices.
git-svn-id: http://skia.googlecode.com/svn/trunk@6238 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/gl')
-rw-r--r-- | src/gpu/gl/GrGLEffect.cpp | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffect.h | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffectMatrix.cpp | 213 | ||||
-rw-r--r-- | src/gpu/gl/GrGLEffectMatrix.h | 97 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 71 | ||||
-rw-r--r-- | src/gpu/gl/GrGLUniformManager.cpp | 18 | ||||
-rw-r--r-- | src/gpu/gl/GrGLUniformManager.h | 4 |
7 files changed, 383 insertions, 33 deletions
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; |