зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
22f42b71fc
Коммит
8fe84b53a6
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче