Fixed color bleeding issue when drawing a sub region of a bitmap with filtering enabled.
Problem was resolved by adding the notion of a custom texture domain in generated shaders, when necessary.
git-svn-id: http://skia.googlecode.com/svn/trunk@1337 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 518b4ee..efee91e 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -19,6 +19,8 @@
#include "GrGpuVertex.h"
#include "GrTexture.h"
+namespace {
+
// recursive helper for creating mask with all the tex coord bits set for
// one stage
template <int N>
@@ -26,16 +28,16 @@
return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) |
stage_mask_recur<N+1>(stage);
}
-template<> // linux build doesn't like static on specializations
+template<>
int stage_mask_recur<GrDrawTarget::kNumStages>(int) { return 0; }
// mask of all tex coord indices for one stage
-static int stage_tex_coord_mask(int stage) {
+int stage_tex_coord_mask(int stage) {
return stage_mask_recur<0>(stage);
}
// mask of all bits relevant to one stage
-static int stage_mask(int stage) {
+int stage_mask(int stage) {
return stage_tex_coord_mask(stage) |
GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(stage);
}
@@ -47,11 +49,11 @@
return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) |
tex_coord_mask_recur<N+1>(texCoordIdx);
}
-template<> // linux build doesn't like static on specializations
+template<>
int tex_coord_mask_recur<GrDrawTarget::kMaxTexCoords>(int) { return 0; }
// mask of all bits relevant to one texture coordinate index
-static int tex_coord_idx_mask(int texCoordIdx) {
+int tex_coord_idx_mask(int texCoordIdx) {
return tex_coord_mask_recur<0>(texCoordIdx);
}
@@ -66,6 +68,8 @@
return true;
}
+} //unnamed namespace
+
size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
GrAssert(check_layout(vertexLayout));
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 5d2d8b3..ab327d0 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -120,6 +120,11 @@
s->appendS32(stage);
}
+static void tex_domain_name(int stage, GrStringBuilder* s) {
+ *s = "uTexDom";
+ s->appendS32(stage);
+}
+
GrGLProgram::GrGLProgram() {
for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
fStageEffects[stage] = NULL;
@@ -650,6 +655,15 @@
radial2ParamName.c_str()));
GrAssert(kUnusedUniform != locations.fRadial2Uni);
}
+
+ if (kUseUniform == locations.fTexDomUni) {
+ GrStringBuilder texDomName;
+ tex_domain_name(s, &texDomName);
+ locations.fTexDomUni = GR_GL(GetUniformLocation(
+ progID,
+ texDomName.c_str()));
+ GrAssert(kUnusedUniform != locations.fTexDomUni);
+ }
}
}
GR_GL(UseProgram(progID));
@@ -869,6 +883,24 @@
modulate.printf(" * %s", fsInColor);
}
+ if (desc.fOptFlags &
+ ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
+ GrStringBuilder texDomainName;
+ tex_domain_name(stageNum, &texDomainName);
+ segments->fFSUnis.appendf("uniform %s %s;\n",
+ float_vector_type(4),
+ texDomainName.c_str());
+ GrStringBuilder coordVar("clampCoord");
+ segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
+ float_vector_type(coordDims),
+ coordVar.c_str(),
+ sampleCoords.c_str(),
+ texDomainName.c_str(),
+ texDomainName.c_str());
+ sampleCoords = coordVar;
+ locations->fTexDomUni = kUseUniform;
+ }
+
if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
locations->fNormalizedTexelSizeUni = kUseUniform;
if (complexCoord) {
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index 1611ca2..74078e3 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -70,14 +70,6 @@
*/
void doGLPost() const;
- /**
- * Configures the GrGLProgram based on the state of a GrDrawTarget
- * object. This is the fast and light initialization. Retrieves all the
- * state that is required for performing the heavy init (i.e. genProgram),
- * or for retrieving heavy init results from cache.
- */
- void buildFromTarget(const GrDrawTarget* target);
-
static int PositionAttributeIdx() { return 0; }
static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
@@ -114,8 +106,9 @@
struct StageDesc {
enum OptFlagBits {
- kNoPerspective_OptFlagBit = 0x1,
- kIdentityMatrix_OptFlagBit = 0x2
+ kNoPerspective_OptFlagBit = 1 << 0,
+ kIdentityMatrix_OptFlagBit = 1 << 1,
+ kCustomTextureDomain_OptFlagBit = 1 << 2
};
unsigned fOptFlags;
@@ -153,11 +146,13 @@
GrGLint fNormalizedTexelSizeUni;
GrGLint fSamplerUni;
GrGLint fRadial2Uni;
+ GrGLint fTexDomUni;
void reset() {
fTextureMatrixUni = kUnusedUniform;
fNormalizedTexelSizeUni = kUnusedUniform;
fSamplerUni = kUnusedUniform;
fRadial2Uni = kUnusedUniform;
+ fTexDomUni = kUnusedUniform;
}
};
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index fcfc120..125b820 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -309,8 +309,39 @@
}
}
+void GrGpuGLShaders::flushTextureDomain(int s) {
+ const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
+ if (GrGLProgram::kUnusedUniform != uni) {
+ const GrRect &texDom =
+ fCurrDrawState.fSamplerStates[s].getTextureDomain();
+
+ float values[4] = {
+ GrScalarToFloat(texDom.left()),
+ GrScalarToFloat(texDom.top()),
+ GrScalarToFloat(texDom.right()),
+ GrScalarToFloat(texDom.bottom())
+ };
+
+ GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
+ GrGLTexture::Orientation orientation = texture->orientation();
+
+ // vertical flip if necessary
+ if (GrGLTexture::kBottomUp_Orientation == orientation) {
+ values[1] = 1.0f - values[1];
+ values[3] = 1.0f - values[3];
+ }
+
+ values[0] *= SkScalarToFloat(texture->contentScaleX());
+ values[2] *= SkScalarToFloat(texture->contentScaleX());
+ values[1] *= SkScalarToFloat(texture->contentScaleY());
+ values[3] *= SkScalarToFloat(texture->contentScaleY());
+
+ GR_GL(Uniform4fv(uni, 1, values));
+ }
+}
+
void GrGpuGLShaders::flushTextureMatrix(int s) {
- const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
+ const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
if (NULL != texture) {
if (GrGLProgram::kUnusedUniform != uni &&
@@ -516,6 +547,8 @@
this->flushRadial2(s);
this->flushTexelSize(s);
+
+ this->flushTextureDomain(s);
}
this->flushEdgeAAData();
resetDirtyFlags();
@@ -702,6 +735,16 @@
break;
}
+ if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
+ GrAssert(GrSamplerState::kClamp_WrapMode ==
+ fCurrDrawState.fSamplerStates[s].getWrapX() &&
+ GrSamplerState::kClamp_WrapMode ==
+ fCurrDrawState.fSamplerStates[s].getWrapY());
+ stage.fOptFlags |=
+ GrGLProgram::ProgramDesc::StageDesc::
+ kCustomTextureDomain_OptFlagBit;
+ }
+
if (GrPixelConfigIsAlphaOnly(texture->config())) {
stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
} else {
@@ -725,4 +768,3 @@
}
-
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index bb3024f..9392d1c 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -51,6 +51,9 @@
// sets the texture matrix uniform for currently bound program
void flushTextureMatrix(int stage);
+ // sets the texture domain uniform for currently bound program
+ void flushTextureDomain(int stage);
+
// sets the color specified by GrDrawTarget::setColor()
void flushColor();