diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-26 15:24:27 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-26 15:24:27 +0000 |
commit | 8fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75 (patch) | |
tree | a9d6c08b4dd8e9bd00308ccf4dd7d0fcec549c21 | |
parent | 22f42b71fc7f120e995b6e90e9fca8584438192c (diff) |
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
-rw-r--r-- | include/core/SkMatrix.h | 22 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 19 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGLShaders.cpp | 8 | ||||
-rw-r--r-- | tests/MatrixTest.cpp | 58 |
4 files changed, 91 insertions, 16 deletions
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index df3275ec4b..3c3d105805 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -483,20 +483,28 @@ public: */ bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; -#ifdef SK_SCALAR_IS_FIXED - friend bool operator==(const SkMatrix& a, const SkMatrix& b) { - return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0; + /** Efficient comparison of two matrices. It distinguishes between zero and + * negative zero. It will return false when the sign of zero values is the + * 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) { - return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0; +#ifdef SK_SCALAR_IS_FIXED + friend bool operator==(const SkMatrix& a, const SkMatrix& b) { + return a->cheapEquals(b); } #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) { return !(a == b); } -#endif enum { // flatten/unflatten will never return a value larger than this diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index c0ff42fc69..92ee2cbaad 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -85,8 +85,8 @@ struct GrDrawState { // are tightly packed GrAssert(kMemsetSize + sizeof(fColor) + sizeof(fCoverage) + sizeof(fFirstCoverageStage) + sizeof(fColorFilterMode) + - sizeof(fSrcBlend) + sizeof(fDstBlend) + sizeof(GrMatrix) == - reinterpret_cast<uintptr_t>(&fEdgeAANumEdges) - + sizeof(fSrcBlend) + sizeof(fDstBlend) == + reinterpret_cast<uintptr_t>(&fViewMatrix) - reinterpret_cast<uintptr_t>(this)); fEdgeAANumEdges = 0; @@ -740,7 +740,13 @@ struct GrDrawState { // Most stages are usually not used, so conditionals here // reduce the expected number of bytes touched by 50%. 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++) { if (fTextures[i] && @@ -766,6 +772,8 @@ struct GrDrawState { GrDrawState& operator =(const GrDrawState& s) { memcpy(this, &s, this->leadingBytes()); + fViewMatrix = s.fViewMatrix; + for (int i = 0; i < kNumStages; i++) { if (s.fTextures[i]) { memcpy(&this->fSamplerStates[i], &s.fSamplerStates[i], @@ -799,9 +807,10 @@ private: SkXfermode::Mode fColorFilterMode; GrBlendCoeff fSrcBlend; GrBlendCoeff fDstBlend; - GrMatrix fViewMatrix; // @} + GrMatrix fViewMatrix; + // @{ Data for GrTesselatedPathRenderer // TODO: currently ignored in copying & comparison for performance. // Must be considered if GrTesselatedPathRenderer is being used. @@ -820,7 +829,7 @@ private: // TODO: ignores GrTesselatedPathRenderer data structures. We don't // have a compile-time flag that lets us know if it's being used, and // checking at runtime seems to cost 5% performance. - return (size_t) ((unsigned char*)&fEdgeAANumEdges - + return (size_t) ((unsigned char*)&fViewMatrix - (unsigned char*)&fBlendConstant); } diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp index cb156f7ae4..ec2d4e2fc8 100644 --- a/src/gpu/gl/GrGpuGLShaders.cpp +++ b/src/gpu/gl/GrGpuGLShaders.cpp @@ -409,7 +409,7 @@ void GrGpuGLShaders::onResetContext() { void GrGpuGLShaders::flushViewMatrix() { const GrMatrix& vm = this->getDrawState().getViewMatrix(); - if (GrGpuGLShaders::getHWViewMatrix() != vm) { + if (!GrGpuGLShaders::getHWViewMatrix().cheapEqualTo(vm)) { const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); GrAssert(NULL != rt); @@ -492,11 +492,13 @@ void GrGpuGLShaders::flushTextureMatrix(int s) { const GrGLTexture* texture = static_cast<const GrGLTexture*>(drawState.getTexture(s)); if (NULL != texture) { + const GrMatrix& hwMatrix = this->getHWSamplerMatrix(s); + const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix(); if (GrGLProgram::kUnusedUniform != uni && (((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 = drawState.getSampler(s).getSampleMode(); AdjustTextureMatrix(texture, mode, &m); diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp index c9a696c548..316e670df3 100644 --- a/tests/MatrixTest.cpp +++ b/tests/MatrixTest.cpp @@ -32,6 +32,49 @@ static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) { 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) { SkMatrix identity; identity.reset(); @@ -49,7 +92,7 @@ static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) { SkMatrix m2; uint32_t size3 = m2.unflatten(buffer); REPORTER_ASSERT(reporter, size1 == size2); - REPORTER_ASSERT(reporter, m == m2); + REPORTER_ASSERT(reporter, are_equal(reporter, m, m2)); char buffer2[SkMatrix::kMaxFlattenSize + 100]; size3 = m2.flatten(buffer2); @@ -237,6 +280,19 @@ void TestMatrix(skiatest::Reporter* reporter) { mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2)); 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); } |