Add SkMatrix::cheapEqualTo, use in Gr code

Review URL: http://codereview.appspot.com/5865057/



git-svn-id: http://skia.googlecode.com/svn/trunk@3488 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-03-26 15:24:27 +00:00
Родитель 22f42b71fc
Коммит 8fe84b53a6
4 изменённых файлов: 91 добавлений и 16 удалений

Просмотреть файл

@ -483,20 +483,28 @@ public:
*/ */
bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
#ifdef SK_SCALAR_IS_FIXED /** Efficient comparison of two matrices. It distinguishes between zero and
friend bool operator==(const SkMatrix& a, const SkMatrix& b) { * negative zero. It will return false when the sign of zero values is the
return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0; * only difference between the two matrices. It considers NaN values to be
* equal to themselves. So a matrix full of NaNs is "cheap equal" to
* another matrix full of NaNs iff the NaN values are bitwise identical
* while according to strict the strict == test a matrix with a NaN value
* is equal to nothing, including itself.
*/
bool cheapEqualTo(const SkMatrix& m) const {
return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
} }
friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { #ifdef SK_SCALAR_IS_FIXED
return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0; friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
return a->cheapEquals(b);
} }
#else #else
friend bool operator==(const SkMatrix& a, const SkMatrix& b); friend bool operator==(const SkMatrix& a, const SkMatrix& b);
#endif
friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
return !(a == b); return !(a == b);
} }
#endif
enum { enum {
// flatten/unflatten will never return a value larger than this // flatten/unflatten will never return a value larger than this

Просмотреть файл

@ -85,8 +85,8 @@ struct GrDrawState {
// are tightly packed // are tightly packed
GrAssert(kMemsetSize + sizeof(fColor) + sizeof(fCoverage) + GrAssert(kMemsetSize + sizeof(fColor) + sizeof(fCoverage) +
sizeof(fFirstCoverageStage) + sizeof(fColorFilterMode) + sizeof(fFirstCoverageStage) + sizeof(fColorFilterMode) +
sizeof(fSrcBlend) + sizeof(fDstBlend) + sizeof(GrMatrix) == sizeof(fSrcBlend) + sizeof(fDstBlend) ==
reinterpret_cast<uintptr_t>(&fEdgeAANumEdges) - reinterpret_cast<uintptr_t>(&fViewMatrix) -
reinterpret_cast<uintptr_t>(this)); reinterpret_cast<uintptr_t>(this));
fEdgeAANumEdges = 0; fEdgeAANumEdges = 0;
@ -740,7 +740,13 @@ struct GrDrawState {
// Most stages are usually not used, so conditionals here // Most stages are usually not used, so conditionals here
// reduce the expected number of bytes touched by 50%. // reduce the expected number of bytes touched by 50%.
bool operator ==(const GrDrawState& s) const { bool operator ==(const GrDrawState& s) const {
if (memcmp(this, &s, this->leadingBytes())) return false; if (memcmp(this, &s, this->leadingBytes())) {
return false;
}
if (!s.fViewMatrix.cheapEqualTo(fViewMatrix)) {
return false;
}
for (int i = 0; i < kNumStages; i++) { for (int i = 0; i < kNumStages; i++) {
if (fTextures[i] && if (fTextures[i] &&
@ -766,6 +772,8 @@ struct GrDrawState {
GrDrawState& operator =(const GrDrawState& s) { GrDrawState& operator =(const GrDrawState& s) {
memcpy(this, &s, this->leadingBytes()); memcpy(this, &s, this->leadingBytes());
fViewMatrix = s.fViewMatrix;
for (int i = 0; i < kNumStages; i++) { for (int i = 0; i < kNumStages; i++) {
if (s.fTextures[i]) { if (s.fTextures[i]) {
memcpy(&this->fSamplerStates[i], &s.fSamplerStates[i], memcpy(&this->fSamplerStates[i], &s.fSamplerStates[i],
@ -799,9 +807,10 @@ private:
SkXfermode::Mode fColorFilterMode; SkXfermode::Mode fColorFilterMode;
GrBlendCoeff fSrcBlend; GrBlendCoeff fSrcBlend;
GrBlendCoeff fDstBlend; GrBlendCoeff fDstBlend;
GrMatrix fViewMatrix;
// @} // @}
GrMatrix fViewMatrix;
// @{ Data for GrTesselatedPathRenderer // @{ Data for GrTesselatedPathRenderer
// TODO: currently ignored in copying & comparison for performance. // TODO: currently ignored in copying & comparison for performance.
// Must be considered if GrTesselatedPathRenderer is being used. // Must be considered if GrTesselatedPathRenderer is being used.
@ -820,7 +829,7 @@ private:
// TODO: ignores GrTesselatedPathRenderer data structures. We don't // TODO: ignores GrTesselatedPathRenderer data structures. We don't
// have a compile-time flag that lets us know if it's being used, and // have a compile-time flag that lets us know if it's being used, and
// checking at runtime seems to cost 5% performance. // checking at runtime seems to cost 5% performance.
return (size_t) ((unsigned char*)&fEdgeAANumEdges - return (size_t) ((unsigned char*)&fViewMatrix -
(unsigned char*)&fBlendConstant); (unsigned char*)&fBlendConstant);
} }

Просмотреть файл

@ -409,7 +409,7 @@ void GrGpuGLShaders::onResetContext() {
void GrGpuGLShaders::flushViewMatrix() { void GrGpuGLShaders::flushViewMatrix() {
const GrMatrix& vm = this->getDrawState().getViewMatrix(); const GrMatrix& vm = this->getDrawState().getViewMatrix();
if (GrGpuGLShaders::getHWViewMatrix() != vm) { if (!GrGpuGLShaders::getHWViewMatrix().cheapEqualTo(vm)) {
const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
GrAssert(NULL != rt); GrAssert(NULL != rt);
@ -492,11 +492,13 @@ void GrGpuGLShaders::flushTextureMatrix(int s) {
const GrGLTexture* texture = const GrGLTexture* texture =
static_cast<const GrGLTexture*>(drawState.getTexture(s)); static_cast<const GrGLTexture*>(drawState.getTexture(s));
if (NULL != texture) { if (NULL != texture) {
const GrMatrix& hwMatrix = this->getHWSamplerMatrix(s);
const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix();
if (GrGLProgram::kUnusedUniform != uni && if (GrGLProgram::kUnusedUniform != uni &&
(((1 << s) & fDirtyFlags.fTextureChangedMask) || (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
this->getHWSamplerMatrix(s) != drawState.getSampler(s).getMatrix())) { !hwMatrix.cheapEqualTo(samplerMatrix))) {
GrMatrix m = drawState.getSampler(s).getMatrix(); GrMatrix m = samplerMatrix;
GrSamplerState::SampleMode mode = GrSamplerState::SampleMode mode =
drawState.getSampler(s).getSampleMode(); drawState.getSampler(s).getSampleMode();
AdjustTextureMatrix(texture, mode, &m); AdjustTextureMatrix(texture, mode, &m);

Просмотреть файл

@ -32,6 +32,49 @@ static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
return true; return true;
} }
static bool are_equal(skiatest::Reporter* reporter,
const SkMatrix& a,
const SkMatrix& b) {
bool equal = a == b;
bool cheapEqual = a.cheapEqualTo(b);
if (equal != cheapEqual) {
#if SK_SCALAR_IS_FLOAT
if (equal) {
bool foundZeroSignDiff = false;
for (int i = 0; i < 9; ++i) {
float aVal = a.get(i);
float bVal = b.get(i);
int aValI = *reinterpret_cast<int*>(&aVal);
int bValI = *reinterpret_cast<int*>(&bVal);
if (0 == aVal && 0 == bVal && aValI != bValI) {
foundZeroSignDiff = true;
} else {
REPORTER_ASSERT(reporter, aVal == bVal && aValI == aValI);
}
}
REPORTER_ASSERT(reporter, foundZeroSignDiff);
} else {
bool foundNaN = false;
for (int i = 0; i < 9; ++i) {
float aVal = a.get(i);
float bVal = b.get(i);
int aValI = *reinterpret_cast<int*>(&aVal);
int bValI = *reinterpret_cast<int*>(&bVal);
if (sk_float_isnan(aVal) && aValI == bValI) {
foundNaN = true;
} else {
REPORTER_ASSERT(reporter, aVal == bVal && aValI == bValI);
}
}
REPORTER_ASSERT(reporter, foundNaN);
}
#else
REPORTER_ASSERT(reporter, false);
#endif
}
return equal;
}
static bool is_identity(const SkMatrix& m) { static bool is_identity(const SkMatrix& m) {
SkMatrix identity; SkMatrix identity;
identity.reset(); identity.reset();
@ -49,7 +92,7 @@ static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
SkMatrix m2; SkMatrix m2;
uint32_t size3 = m2.unflatten(buffer); uint32_t size3 = m2.unflatten(buffer);
REPORTER_ASSERT(reporter, size1 == size2); REPORTER_ASSERT(reporter, size1 == size2);
REPORTER_ASSERT(reporter, m == m2); REPORTER_ASSERT(reporter, are_equal(reporter, m, m2));
char buffer2[SkMatrix::kMaxFlattenSize + 100]; char buffer2[SkMatrix::kMaxFlattenSize + 100];
size3 = m2.flatten(buffer2); size3 = m2.flatten(buffer2);
@ -237,6 +280,19 @@ void TestMatrix(skiatest::Reporter* reporter) {
mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2)); mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
REPORTER_ASSERT(reporter, !mat.asAffine(affine)); REPORTER_ASSERT(reporter, !mat.asAffine(affine));
SkMatrix mat2;
mat2.reset();
mat.reset();
SkScalar zero = 0;
mat.set(SkMatrix::kMSkewX, -zero);
REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));
mat2.reset();
mat.reset();
mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
test_matrix_max_stretch(reporter); test_matrix_max_stretch(reporter);
} }