xref: /aosp_15_r20/external/skia/tests/YUVTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkCodec.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkEncodedOrigin.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixmap.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkYUVAInfo.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkYUVAPixmaps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkColorMatrix.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkJpegEncoder.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
28*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
29*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
30*c8dee2aaSAndroid Build Coastguard Worker 
codec_yuv(skiatest::Reporter * reporter,const char path[],const SkYUVAInfo * expectedInfo)31*c8dee2aaSAndroid Build Coastguard Worker static void codec_yuv(skiatest::Reporter* reporter,
32*c8dee2aaSAndroid Build Coastguard Worker                       const char path[],
33*c8dee2aaSAndroid Build Coastguard Worker                       const SkYUVAInfo* expectedInfo) {
34*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
35*c8dee2aaSAndroid Build Coastguard Worker     if (!stream) {
36*c8dee2aaSAndroid Build Coastguard Worker         return;
37*c8dee2aaSAndroid Build Coastguard Worker     }
38*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
39*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, codec);
40*c8dee2aaSAndroid Build Coastguard Worker     if (!codec) {
41*c8dee2aaSAndroid Build Coastguard Worker         return;
42*c8dee2aaSAndroid Build Coastguard Worker     }
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     // Test queryYUBAInfo()
45*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAPixmapInfo yuvaPixmapInfo;
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
48*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kNoTypes  = SkYUVAPixmapInfo::SupportedDataTypes();
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker     // SkYUVAInfo param is required to be non-null.
51*c8dee2aaSAndroid Build Coastguard Worker     bool success = codec->queryYUVAInfo(kAllTypes, nullptr);
52*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !success);
53*c8dee2aaSAndroid Build Coastguard Worker     // Fails when there is no support for YUVA planes.
54*c8dee2aaSAndroid Build Coastguard Worker     success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo);
55*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !success);
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker     success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo);
58*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success);
59*c8dee2aaSAndroid Build Coastguard Worker     if (!success) {
60*c8dee2aaSAndroid Build Coastguard Worker         return;
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo());
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker     int numPlanes = yuvaPixmapInfo.numPlanes();
65*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes);
66*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < numPlanes; ++i) {
67*c8dee2aaSAndroid Build Coastguard Worker         const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
68*c8dee2aaSAndroid Build Coastguard Worker         SkColorType planeCT = planeInfo.colorType();
69*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !planeInfo.isEmpty());
70*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType);
71*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i)));
72*c8dee2aaSAndroid Build Coastguard Worker         // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType().
73*c8dee2aaSAndroid Build Coastguard Worker         auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT);
74*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType());
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker     for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
77*c8dee2aaSAndroid Build Coastguard Worker         const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
78*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, planeInfo.dimensions().isEmpty());
79*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, planeInfo.colorType() == kUnknown_SkColorType);
80*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, yuvaPixmapInfo.rowBytes(i) == 0);
81*c8dee2aaSAndroid Build Coastguard Worker     }
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     // Allocate the memory for the YUV decode.
84*c8dee2aaSAndroid Build Coastguard Worker     auto pixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
85*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, pixmaps.isValid());
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < SkYUVAPixmaps::kMaxPlanes; ++i) {
88*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pixmaps.plane(i).info() == yuvaPixmapInfo.planeInfo(i));
89*c8dee2aaSAndroid Build Coastguard Worker     }
90*c8dee2aaSAndroid Build Coastguard Worker     for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
91*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, pixmaps.plane(i).rowBytes() == 0);
92*c8dee2aaSAndroid Build Coastguard Worker     }
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     // Test getYUVAPlanes()
95*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps));
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Jpeg_YUV_Codec,r)98*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Jpeg_YUV_Codec, r) {
99*c8dee2aaSAndroid Build Coastguard Worker     auto setExpectations = [](SkISize dims, SkYUVAInfo::Subsampling subsampling) {
100*c8dee2aaSAndroid Build Coastguard Worker         return SkYUVAInfo(dims,
101*c8dee2aaSAndroid Build Coastguard Worker                           SkYUVAInfo::PlaneConfig::kY_U_V,
102*c8dee2aaSAndroid Build Coastguard Worker                           subsampling,
103*c8dee2aaSAndroid Build Coastguard Worker                           kJPEG_Full_SkYUVColorSpace,
104*c8dee2aaSAndroid Build Coastguard Worker                           kTopLeft_SkEncodedOrigin,
105*c8dee2aaSAndroid Build Coastguard Worker                           SkYUVAInfo::Siting::kCentered,
106*c8dee2aaSAndroid Build Coastguard Worker                           SkYUVAInfo::Siting::kCentered);
107*c8dee2aaSAndroid Build Coastguard Worker     };
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::Subsampling::k420);
110*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/color_wheel.jpg", &expectations);
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker     // H2V2
113*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k420);
114*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations);
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker     // H1V1
117*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
118*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations);
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker     // H2V1
121*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k422);
122*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations);
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker     // Non-power of two dimensions
125*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({439, 154}, SkYUVAInfo::Subsampling::k420);
126*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/cropped_mandrill.jpg", &expectations);
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({8, 8}, SkYUVAInfo::Subsampling::k420);
129*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/randPixels.jpg", &expectations);
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker     // Progressive images
132*c8dee2aaSAndroid Build Coastguard Worker     expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
133*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/brickwork-texture.jpg", &expectations);
134*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations);
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker     // A CMYK encoded image should fail.
137*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/CMYK.jpg", nullptr);
138*c8dee2aaSAndroid Build Coastguard Worker     // A grayscale encoded image should fail.
139*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/grayscale.jpg", nullptr);
140*c8dee2aaSAndroid Build Coastguard Worker     // A PNG should fail.
141*c8dee2aaSAndroid Build Coastguard Worker     codec_yuv(r, "images/arrow.png", nullptr);
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker 
decode_yuva(skiatest::Reporter * r,std::unique_ptr<SkStream> stream)144*c8dee2aaSAndroid Build Coastguard Worker SkYUVAPixmaps decode_yuva(skiatest::Reporter* r, std::unique_ptr<SkStream> stream) {
145*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
146*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAPixmaps result;
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
149*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, codec);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     SkYUVAPixmapInfo yuvaPixmapInfo;
152*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo));
153*c8dee2aaSAndroid Build Coastguard Worker     result = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
154*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, result.isValid());
155*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getYUVAPlanes(result));
156*c8dee2aaSAndroid Build Coastguard Worker     return result;
157*c8dee2aaSAndroid Build Coastguard Worker }
158*c8dee2aaSAndroid Build Coastguard Worker 
verify_same(skiatest::Reporter * r,const SkYUVAPixmaps a,const SkYUVAPixmaps & b)159*c8dee2aaSAndroid Build Coastguard Worker static void verify_same(skiatest::Reporter* r, const SkYUVAPixmaps a, const SkYUVAPixmaps& b) {
160*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, a.yuvaInfo() == b.yuvaInfo());
161*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, a.numPlanes() == b.numPlanes());
162*c8dee2aaSAndroid Build Coastguard Worker     for (int plane = 0; plane < a.numPlanes(); ++plane) {
163*c8dee2aaSAndroid Build Coastguard Worker         const SkPixmap& aPlane = a.plane(plane);
164*c8dee2aaSAndroid Build Coastguard Worker         const SkPixmap& bPlane = b.plane(plane);
165*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, aPlane.computeByteSize() == bPlane.computeByteSize());
166*c8dee2aaSAndroid Build Coastguard Worker         const uint8_t* aData = reinterpret_cast<const uint8_t*>(aPlane.addr());
167*c8dee2aaSAndroid Build Coastguard Worker         const uint8_t* bData = reinterpret_cast<const uint8_t*>(bPlane.addr());
168*c8dee2aaSAndroid Build Coastguard Worker         for (int row = 0; row < aPlane.height(); ++row) {
169*c8dee2aaSAndroid Build Coastguard Worker             for (int col = 0; col < aPlane.width() * aPlane.info().bytesPerPixel(); ++col) {
170*c8dee2aaSAndroid Build Coastguard Worker                 int32_t aByte = aData[col];
171*c8dee2aaSAndroid Build Coastguard Worker                 int32_t bByte = bData[col];
172*c8dee2aaSAndroid Build Coastguard Worker                 // Allow at most one bit of difference.
173*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, std::abs(aByte - bByte) <= 1);
174*c8dee2aaSAndroid Build Coastguard Worker             }
175*c8dee2aaSAndroid Build Coastguard Worker             aData += aPlane.rowBytes();
176*c8dee2aaSAndroid Build Coastguard Worker             bData += bPlane.rowBytes();
177*c8dee2aaSAndroid Build Coastguard Worker         }
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Jpeg_YUV_Encode,r)181*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Jpeg_YUV_Encode, r) {
182*c8dee2aaSAndroid Build Coastguard Worker     const char* paths[] = {
183*c8dee2aaSAndroid Build Coastguard Worker             "images/color_wheel.jpg",
184*c8dee2aaSAndroid Build Coastguard Worker             "images/mandrill_512_q075.jpg",
185*c8dee2aaSAndroid Build Coastguard Worker             "images/mandrill_h1v1.jpg",
186*c8dee2aaSAndroid Build Coastguard Worker             "images/mandrill_h2v1.jpg",
187*c8dee2aaSAndroid Build Coastguard Worker             "images/cropped_mandrill.jpg",
188*c8dee2aaSAndroid Build Coastguard Worker             "images/randPixels.jpg",
189*c8dee2aaSAndroid Build Coastguard Worker     };
190*c8dee2aaSAndroid Build Coastguard Worker     for (const auto* path : paths) {
191*c8dee2aaSAndroid Build Coastguard Worker         SkYUVAPixmaps decoded;
192*c8dee2aaSAndroid Build Coastguard Worker         {
193*c8dee2aaSAndroid Build Coastguard Worker             std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
194*c8dee2aaSAndroid Build Coastguard Worker             decoded = decode_yuva(r, std::move(stream));
195*c8dee2aaSAndroid Build Coastguard Worker         }
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker         SkYUVAPixmaps roundtrip;
198*c8dee2aaSAndroid Build Coastguard Worker         {
199*c8dee2aaSAndroid Build Coastguard Worker             SkJpegEncoder::Options options;
200*c8dee2aaSAndroid Build Coastguard Worker             SkDynamicMemoryWStream encodeStream;
201*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, SkJpegEncoder::Encode(&encodeStream, decoded, nullptr, options));
202*c8dee2aaSAndroid Build Coastguard Worker             auto encodedData = encodeStream.detachAsData();
203*c8dee2aaSAndroid Build Coastguard Worker             roundtrip = decode_yuva(r, SkMemoryStream::Make(encodedData));
204*c8dee2aaSAndroid Build Coastguard Worker         }
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker         verify_same(r, decoded, roundtrip);
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker // Be sure that the two matrices are inverses of each other
211*c8dee2aaSAndroid Build Coastguard Worker // (i.e. rgb2yuv and yuv2rgb
DEF_TEST(YUVMath,reporter)212*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(YUVMath, reporter) {
213*c8dee2aaSAndroid Build Coastguard Worker     const SkYUVColorSpace spaces[] = {
214*c8dee2aaSAndroid Build Coastguard Worker         kJPEG_SkYUVColorSpace,
215*c8dee2aaSAndroid Build Coastguard Worker         kRec601_SkYUVColorSpace,
216*c8dee2aaSAndroid Build Coastguard Worker         kRec709_SkYUVColorSpace,
217*c8dee2aaSAndroid Build Coastguard Worker         kBT2020_SkYUVColorSpace,
218*c8dee2aaSAndroid Build Coastguard Worker         kIdentity_SkYUVColorSpace,
219*c8dee2aaSAndroid Build Coastguard Worker     };
220*c8dee2aaSAndroid Build Coastguard Worker 
221*c8dee2aaSAndroid Build Coastguard Worker     // Not sure what the theoretical precision we can hope for is, so pick a big value that
222*c8dee2aaSAndroid Build Coastguard Worker     // passes (when I think we're correct).
223*c8dee2aaSAndroid Build Coastguard Worker     const float tolerance = 1.0f/(1 << 18);
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker     for (auto cs : spaces) {
226*c8dee2aaSAndroid Build Coastguard Worker         SkColorMatrix r2ym = SkColorMatrix::RGBtoYUV(cs),
227*c8dee2aaSAndroid Build Coastguard Worker                       y2rm = SkColorMatrix::YUVtoRGB(cs);
228*c8dee2aaSAndroid Build Coastguard Worker         r2ym.postConcat(y2rm);
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker         float tmp[20];
231*c8dee2aaSAndroid Build Coastguard Worker         r2ym.getRowMajor(tmp);
232*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 20; ++i) {
233*c8dee2aaSAndroid Build Coastguard Worker             float expected = 0;
234*c8dee2aaSAndroid Build Coastguard Worker             if (i % 6 == 0) {   // diagonal
235*c8dee2aaSAndroid Build Coastguard Worker                 expected = 1;
236*c8dee2aaSAndroid Build Coastguard Worker             }
237*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, SkScalarNearlyEqual(tmp[i], expected, tolerance));
238*c8dee2aaSAndroid Build Coastguard Worker         }
239*c8dee2aaSAndroid Build Coastguard Worker     }
240*c8dee2aaSAndroid Build Coastguard Worker }
241