Do not use GrBicubic effect when downscaling. Also, don't use glTexStorage as it interferes with deleyed mipmap generation.
R=robertphillips@google.com Author: bsalomon@google.com Review URL: https://codereview.chromium.org/105353002 git-svn-id: http://skia.googlecode.com/svn/trunk@12576 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
c9c0b1e90e
commit
cea9abb001
@ -573,6 +573,14 @@ public:
|
|||||||
SkDEVCODE(void dump() const;)
|
SkDEVCODE(void dump() const;)
|
||||||
SkDEVCODE(void toString(SkString*) const;)
|
SkDEVCODE(void toString(SkString*) const;)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the minimum stretching factor of the matrix. If the matrix has
|
||||||
|
* perspective -1 is returned.
|
||||||
|
*
|
||||||
|
* @return minumum strecthing factor
|
||||||
|
*/
|
||||||
|
SkScalar getMinStretch() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the maximum stretching factor of the matrix. If the matrix has
|
* Calculates the maximum stretching factor of the matrix. If the matrix has
|
||||||
* perspective -1 is returned.
|
* perspective -1 is returned.
|
||||||
|
@ -358,13 +358,12 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
|
|||||||
SkMatrix matrix;
|
SkMatrix matrix;
|
||||||
matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
|
matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
|
||||||
|
|
||||||
if (this->hasLocalMatrix()) {
|
SkMatrix inverse;
|
||||||
SkMatrix inverse;
|
if (!this->getLocalMatrix().invert(&inverse)) {
|
||||||
if (!this->getLocalMatrix().invert(&inverse)) {
|
return NULL;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
matrix.preConcat(inverse);
|
|
||||||
}
|
}
|
||||||
|
matrix.preConcat(inverse);
|
||||||
|
|
||||||
SkShader::TileMode tm[] = {
|
SkShader::TileMode tm[] = {
|
||||||
(TileMode)fState.fTileModeX,
|
(TileMode)fState.fTileModeX,
|
||||||
(TileMode)fState.fTileModeY,
|
(TileMode)fState.fTileModeY,
|
||||||
@ -384,9 +383,21 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
|
|||||||
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
|
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
|
||||||
break;
|
break;
|
||||||
case SkPaint::kHigh_FilterLevel:
|
case SkPaint::kHigh_FilterLevel:
|
||||||
// fall back to no filtering here; we will install another
|
// Minification can look bad with the bicubic effect. This is an overly aggressive
|
||||||
// shader that will do the HQ filtering.
|
// check for MIP fallbacks. It doesn't consider the fact that minification in the local
|
||||||
textureFilterMode = GrTextureParams::kNone_FilterMode;
|
// matrix could be offset by the view matrix and vice versa. We also don't know whether
|
||||||
|
// the draw has explicit local coords (e.g. drawVertices) where the scale factor is
|
||||||
|
// unknown and varies.
|
||||||
|
if (context->getMatrix().getMinStretch() >= SK_Scalar1 &&
|
||||||
|
this->getLocalMatrix().getMaxStretch() <= SK_Scalar1) {
|
||||||
|
// fall back to no filtering here; we will install another
|
||||||
|
// shader that will do the HQ filtering.
|
||||||
|
textureFilterMode = GrTextureParams::kNone_FilterMode;
|
||||||
|
} else {
|
||||||
|
// Fall back to mip-mapping.
|
||||||
|
paintFilterLevel = SkPaint::kMedium_FilterLevel;
|
||||||
|
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SkErrorInternals::SetError( kInvalidPaint_SkError,
|
SkErrorInternals::SetError( kInvalidPaint_SkError,
|
||||||
|
@ -1857,45 +1857,71 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkScalar SkMatrix::getMaxStretch() const {
|
enum MinOrMax {
|
||||||
TypeMask mask = this->getType();
|
kMin_MinOrMax,
|
||||||
|
kMax_MinOrMax
|
||||||
|
};
|
||||||
|
|
||||||
if (this->hasPerspective()) {
|
template <MinOrMax MIN_OR_MAX> SkScalar get_stretch_factor(SkMatrix::TypeMask typeMask,
|
||||||
|
const SkScalar m[9]) {
|
||||||
|
if (typeMask & SkMatrix::kPerspective_Mask) {
|
||||||
return -SK_Scalar1;
|
return -SK_Scalar1;
|
||||||
}
|
}
|
||||||
if (this->isIdentity()) {
|
if (SkMatrix::kIdentity_Mask == typeMask) {
|
||||||
return SK_Scalar1;
|
return SK_Scalar1;
|
||||||
}
|
}
|
||||||
if (!(mask & kAffine_Mask)) {
|
if (!(typeMask & SkMatrix::kAffine_Mask)) {
|
||||||
return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
|
if (kMin_MinOrMax == MIN_OR_MAX) {
|
||||||
SkScalarAbs(fMat[kMScaleY]));
|
return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
|
||||||
|
SkScalarAbs(m[SkMatrix::kMScaleY]));
|
||||||
|
} else {
|
||||||
|
return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
|
||||||
|
SkScalarAbs(m[SkMatrix::kMScaleY]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ignore the translation part of the matrix, just look at 2x2 portion.
|
// ignore the translation part of the matrix, just look at 2x2 portion.
|
||||||
// compute singular values, take largest abs value.
|
// compute singular values, take largest or smallest abs value.
|
||||||
// [a b; b c] = A^T*A
|
// [a b; b c] = A^T*A
|
||||||
SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
|
SkScalar a = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX]) +
|
||||||
SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
|
SkScalarMul(m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
|
||||||
SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
|
SkScalar b = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX]) +
|
||||||
SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
|
SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
|
||||||
SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
|
SkScalar c = SkScalarMul(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX]) +
|
||||||
SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
|
SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
|
||||||
// eigenvalues of A^T*A are the squared singular values of A.
|
// eigenvalues of A^T*A are the squared singular values of A.
|
||||||
// characteristic equation is det((A^T*A) - l*I) = 0
|
// characteristic equation is det((A^T*A) - l*I) = 0
|
||||||
// l^2 - (a + c)l + (ac-b^2)
|
// l^2 - (a + c)l + (ac-b^2)
|
||||||
// solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
|
// solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
|
||||||
// and roots are guaraunteed to be pos and real).
|
// and roots are guaranteed to be pos and real).
|
||||||
SkScalar largerRoot;
|
SkScalar chosenRoot;
|
||||||
SkScalar bSqd = SkScalarMul(b,b);
|
SkScalar bSqd = SkScalarMul(b,b);
|
||||||
// if upper left 2x2 is orthogonal save some math
|
// if upper left 2x2 is orthogonal save some math
|
||||||
if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
|
if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
|
||||||
largerRoot = SkMaxScalar(a, c);
|
if (kMin_MinOrMax == MIN_OR_MAX) {
|
||||||
|
chosenRoot = SkMinScalar(a, c);
|
||||||
|
} else {
|
||||||
|
chosenRoot = SkMaxScalar(a, c);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SkScalar aminusc = a - c;
|
SkScalar aminusc = a - c;
|
||||||
SkScalar apluscdiv2 = SkScalarHalf(a + c);
|
SkScalar apluscdiv2 = SkScalarHalf(a + c);
|
||||||
SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
|
SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
|
||||||
largerRoot = apluscdiv2 + x;
|
if (kMin_MinOrMax == MIN_OR_MAX) {
|
||||||
|
chosenRoot = apluscdiv2 - x;
|
||||||
|
} else {
|
||||||
|
chosenRoot = apluscdiv2 + x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return SkScalarSqrt(largerRoot);
|
SkASSERT(chosenRoot >= 0);
|
||||||
|
return SkScalarSqrt(chosenRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
SkScalar SkMatrix::getMinStretch() const {
|
||||||
|
return get_stretch_factor<kMin_MinOrMax>(this->getType(), fMat);
|
||||||
|
}
|
||||||
|
|
||||||
|
SkScalar SkMatrix::getMaxStretch() const {
|
||||||
|
return get_stretch_factor<kMax_MinOrMax>(this->getType(), fMat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_identity_matrix(SkMatrix* identity) {
|
static void reset_identity_matrix(SkMatrix* identity) {
|
||||||
|
@ -1194,8 +1194,10 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
|
|||||||
tileFilterPad = 1;
|
tileFilterPad = 1;
|
||||||
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
|
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
|
||||||
break;
|
break;
|
||||||
case SkPaint::kHigh_FilterLevel:
|
case SkPaint::kHigh_FilterLevel: {
|
||||||
if (flags & SkCanvas::kBleed_DrawBitmapRectFlag) {
|
// Minification can look bad with the bicubic effect.
|
||||||
|
if (fContext->getMatrix().getMinStretch() >= SK_Scalar1 &&
|
||||||
|
(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
|
||||||
// We will install an effect that does the filtering in the shader.
|
// We will install an effect that does the filtering in the shader.
|
||||||
textureFilterMode = GrTextureParams::kNone_FilterMode;
|
textureFilterMode = GrTextureParams::kNone_FilterMode;
|
||||||
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
||||||
@ -1207,6 +1209,7 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
|
|||||||
tileFilterPad = 1;
|
tileFilterPad = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
SkErrorInternals::SetError( kInvalidPaint_SkError,
|
SkErrorInternals::SetError( kInvalidPaint_SkError,
|
||||||
"Sorry, I don't understand the filtering "
|
"Sorry, I don't understand the filtering "
|
||||||
|
@ -552,7 +552,12 @@ bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
|
|||||||
SkAutoSMalloc<128 * 128> tempStorage;
|
SkAutoSMalloc<128 * 128> tempStorage;
|
||||||
|
|
||||||
// paletted textures cannot be partially updated
|
// paletted textures cannot be partially updated
|
||||||
bool useTexStorage = isNewTexture &&
|
// We currently lazily create MIPMAPs when the we see a draw with
|
||||||
|
// GrTextureParams::kMipMap_FilterMode. Using texture storage requires that the
|
||||||
|
// MIP levels are all created when the texture is created. So for now we don't use
|
||||||
|
// texture storage.
|
||||||
|
bool useTexStorage = false &&
|
||||||
|
isNewTexture &&
|
||||||
desc.fConfig != kIndex_8_GrPixelConfig &&
|
desc.fConfig != kIndex_8_GrPixelConfig &&
|
||||||
this->glCaps().texStorageSupport();
|
this->glCaps().texStorageSupport();
|
||||||
|
|
||||||
@ -638,8 +643,7 @@ bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
|
|||||||
desc.fWidth == width && desc.fHeight == height) {
|
desc.fWidth == width && desc.fHeight == height) {
|
||||||
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
||||||
if (useTexStorage) {
|
if (useTexStorage) {
|
||||||
// We never resize or change formats of textures. We don't use
|
// We never resize or change formats of textures.
|
||||||
// mipmaps currently.
|
|
||||||
GL_ALLOC_CALL(this->glInterface(),
|
GL_ALLOC_CALL(this->glInterface(),
|
||||||
TexStorage2D(GR_GL_TEXTURE_2D,
|
TexStorage2D(GR_GL_TEXTURE_2D,
|
||||||
1, // levels
|
1, // levels
|
||||||
|
@ -130,36 +130,43 @@ static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
|
|||||||
REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
|
REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_matrix_max_stretch(skiatest::Reporter* reporter) {
|
static void test_matrix_min_max_stretch(skiatest::Reporter* reporter) {
|
||||||
SkMatrix identity;
|
SkMatrix identity;
|
||||||
identity.reset();
|
identity.reset();
|
||||||
|
REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
|
REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix scale;
|
SkMatrix scale;
|
||||||
scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
|
scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
|
||||||
|
REPORTER_ASSERT(reporter, SK_Scalar1 * 2 == scale.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
|
REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix rot90Scale;
|
SkMatrix rot90Scale;
|
||||||
rot90Scale.setRotate(90 * SK_Scalar1);
|
rot90Scale.setRotate(90 * SK_Scalar1);
|
||||||
rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
|
rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
|
||||||
|
REPORTER_ASSERT(reporter, SK_Scalar1 / 4 == rot90Scale.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
|
REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix rotate;
|
SkMatrix rotate;
|
||||||
rotate.setRotate(128 * SK_Scalar1);
|
rotate.setRotate(128 * SK_Scalar1);
|
||||||
REPORTER_ASSERT(reporter, SkScalarAbs(SK_Scalar1 - rotate.getMaxStretch()) <= SK_ScalarNearlyZero);
|
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMinStretch() ,SK_ScalarNearlyZero));
|
||||||
|
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SK_Scalar1, rotate.getMaxStretch(), SK_ScalarNearlyZero));
|
||||||
|
|
||||||
SkMatrix translate;
|
SkMatrix translate;
|
||||||
translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
|
translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
|
||||||
|
REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
|
REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix perspX;
|
SkMatrix perspX;
|
||||||
perspX.reset();
|
perspX.reset();
|
||||||
perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
|
perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
|
||||||
|
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
|
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix perspY;
|
SkMatrix perspY;
|
||||||
perspY.reset();
|
perspY.reset();
|
||||||
perspY.setPerspX(SkScalarToPersp(-SK_Scalar1 / 500));
|
perspY.setPerspY(SkScalarToPersp(-SK_Scalar1 / 500));
|
||||||
|
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMinStretch());
|
||||||
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
|
REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
|
||||||
|
|
||||||
SkMatrix baseMats[] = {scale, rot90Scale, rotate,
|
SkMatrix baseMats[] = {scale, rot90Scale, rotate,
|
||||||
@ -178,25 +185,22 @@ static void test_matrix_max_stretch(skiatest::Reporter* reporter) {
|
|||||||
int x = rand.nextU() % SK_ARRAY_COUNT(mats);
|
int x = rand.nextU() % SK_ARRAY_COUNT(mats);
|
||||||
mat.postConcat(mats[x]);
|
mat.postConcat(mats[x]);
|
||||||
}
|
}
|
||||||
SkScalar stretch = mat.getMaxStretch();
|
|
||||||
|
|
||||||
if ((stretch < 0) != mat.hasPerspective()) {
|
SkScalar minStretch = mat.getMinStretch();
|
||||||
stretch = mat.getMaxStretch();
|
SkScalar maxStretch = mat.getMaxStretch();
|
||||||
}
|
REPORTER_ASSERT(reporter, (minStretch < 0) == (maxStretch < 0));
|
||||||
|
REPORTER_ASSERT(reporter, (maxStretch < 0) == mat.hasPerspective());
|
||||||
REPORTER_ASSERT(reporter, (stretch < 0) == mat.hasPerspective());
|
|
||||||
|
|
||||||
if (mat.hasPerspective()) {
|
if (mat.hasPerspective()) {
|
||||||
m -= 1; // try another non-persp matrix
|
m -= 1; // try another non-persp matrix
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test a bunch of vectors. None should be scaled by more than stretch
|
// test a bunch of vectors. All should be scaled by between minStretch and maxStretch
|
||||||
// (modulo some error) and we should find a vector that is scaled by
|
// (modulo some error) and we should find a vector that is scaled by almost each.
|
||||||
// almost stretch.
|
static const SkScalar gVectorStretchTol = (105 * SK_Scalar1) / 100;
|
||||||
static const SkScalar gStretchTol = (105 * SK_Scalar1) / 100;
|
static const SkScalar gClosestStretchTol = (97 * SK_Scalar1) / 100;
|
||||||
static const SkScalar gMaxStretchTol = (97 * SK_Scalar1) / 100;
|
SkScalar max = 0, min = SK_ScalarMax;
|
||||||
SkScalar max = 0;
|
|
||||||
SkVector vectors[1000];
|
SkVector vectors[1000];
|
||||||
for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
|
for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
|
||||||
vectors[i].fX = rand.nextSScalar1();
|
vectors[i].fX = rand.nextSScalar1();
|
||||||
@ -209,12 +213,17 @@ static void test_matrix_max_stretch(skiatest::Reporter* reporter) {
|
|||||||
mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
|
mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
|
||||||
for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
|
for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
|
||||||
SkScalar d = vectors[i].length();
|
SkScalar d = vectors[i].length();
|
||||||
REPORTER_ASSERT(reporter, SkScalarDiv(d, stretch) < gStretchTol);
|
REPORTER_ASSERT(reporter, SkScalarDiv(d, maxStretch) < gVectorStretchTol);
|
||||||
|
REPORTER_ASSERT(reporter, SkScalarDiv(minStretch, d) < gVectorStretchTol);
|
||||||
if (max < d) {
|
if (max < d) {
|
||||||
max = d;
|
max = d;
|
||||||
}
|
}
|
||||||
|
if (min > d) {
|
||||||
|
min = d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
REPORTER_ASSERT(reporter, SkScalarDiv(max, stretch) >= gMaxStretchTol);
|
REPORTER_ASSERT(reporter, SkScalarDiv(max, maxStretch) >= gClosestStretchTol);
|
||||||
|
REPORTER_ASSERT(reporter, SkScalarDiv(minStretch, min) >= gClosestStretchTol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +806,7 @@ static void TestMatrix(skiatest::Reporter* reporter) {
|
|||||||
REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
|
REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
test_matrix_max_stretch(reporter);
|
test_matrix_min_max_stretch(reporter);
|
||||||
test_matrix_is_similarity(reporter);
|
test_matrix_is_similarity(reporter);
|
||||||
test_matrix_recttorect(reporter);
|
test_matrix_recttorect(reporter);
|
||||||
test_matrix_decomposition(reporter);
|
test_matrix_decomposition(reporter);
|
||||||
|
Loading…
Reference in New Issue
Block a user