blob: 7baa17b0551f8bc5432385dfe663ce0bda913f7b [file] [log] [blame]
caryclark@google.comcd4421d2012-03-01 19:16:31 +00001#include "EdgeWalker_Test.h"
2#include "Intersection_Tests.h"
3#include "SkBitmap.h"
4#include "SkCanvas.h"
5#include "SkPaint.h"
caryclark@google.com59823f72012-08-09 18:17:47 +00006#include "SkStream.h"
7
caryclark@google.comfb173422012-04-10 18:28:55 +00008#include <algorithm>
caryclark@google.com59823f72012-08-09 18:17:47 +00009#include <assert.h>
10#include <errno.h>
11#include <pthread.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/sysctl.h>
caryclark@google.comcd4421d2012-03-01 19:16:31 +000015
caryclark@google.com78e17132012-04-17 11:40:34 +000016#undef SkASSERT
17#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
18
caryclark@google.com59823f72012-08-09 18:17:47 +000019static const char marker[] =
20 "</div>\n"
21 "\n"
22 "<script type=\"text/javascript\">\n"
23 "\n"
24 "var testDivs = [\n";
25#if 0
26static const char filename[] = "../../experimental/Intersection/debugXX.txt";
27#else
28static const char filename[] = "/flash/debug/XX.txt";
29#endif
30
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000031static bool gShowPath = false;
caryclark@google.com198e0542012-03-30 18:47:02 +000032static bool gComparePaths = true;
caryclark@google.coma3f05fa2012-06-01 17:44:28 +000033//static bool gDrawLastAsciiPaths = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000034static bool gDrawAllAsciiPaths = false;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000035static bool gShowAsciiPaths = false;
caryclark@google.com59823f72012-08-09 18:17:47 +000036static bool gComparePathsAssert = false;
37static bool gPathStrAssert = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000038
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000039void showPath(const SkPath& path, const char* str) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000040 SkDebugf("%s\n", !str ? "original:" : str);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000041 SkPath::Iter iter(path, true);
42 uint8_t verb;
43 SkPoint pts[4];
44 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
45 switch (verb) {
46 case SkPath::kMove_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000047 SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000048 continue;
49 case SkPath::kLine_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000050 SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000051 break;
52 case SkPath::kQuad_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000053 SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000054 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
55 break;
56 case SkPath::kCubic_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000057 SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000058 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
59 pts[3].fX, pts[3].fY);
60 break;
61 case SkPath::kClose_Verb:
62 SkDebugf("path.close();\n");
63 continue;
64 default:
65 SkDEBUGFAIL("bad verb");
66 return;
67 }
68 }
69}
70
caryclark@google.com198e0542012-03-30 18:47:02 +000071static int pathsDrawTheSame(const SkPath& one, const SkPath& two,
72 SkBitmap& bits, SkCanvas* c) {
73 SkCanvas* canvasPtr = c;
74 if (!c) {
75 canvasPtr = new SkCanvas(bits);
76 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +000077 const SkRect& bounds1 = one.getBounds();
78 const SkRect& bounds2 = two.getBounds();
79 SkRect larger = bounds1;
80 larger.join(bounds2);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000081 int bitWidth = SkScalarCeil(larger.width()) + 2;
82 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com198e0542012-03-30 18:47:02 +000083 if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +000084 if (bits.width() >= 200 && false) {
caryclark@google.com198e0542012-03-30 18:47:02 +000085 SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight);
86 }
87 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
88 bits.allocPixels();
89 canvasPtr->setBitmapDevice(bits);
90 }
91 SkCanvas& canvas = *canvasPtr;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000092 canvas.drawColor(SK_ColorWHITE);
93 SkPaint paint;
94 canvas.save();
95 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
96 canvas.drawPath(one, paint);
97 canvas.restore();
98 canvas.save();
99 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
100 canvas.drawPath(two, paint);
101 canvas.restore();
caryclark@google.com198e0542012-03-30 18:47:02 +0000102 int errors = 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000103 for (int y = 0; y < bitHeight; ++y) {
104 uint32_t* addr1 = bits.getAddr32(0, y);
105 uint32_t* addr2 = bits.getAddr32(bitWidth, y);
106 for (int x = 0; x < bitWidth; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000107 errors += addr1[x] != addr2[x];
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000108 }
109 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000110 if (!c) {
111 delete canvasPtr;
112 }
113 return errors;
114}
115
caryclark@google.com752b60e2012-03-22 21:11:17 +0000116bool drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000117 bool drawPaths) {
118 if (!drawPaths) {
caryclark@google.com752b60e2012-03-22 21:11:17 +0000119 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000120 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000121 if (gShowAsciiPaths) {
122 showPath(one, "one:");
123 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000124 }
125 const SkRect& bounds1 = one.getBounds();
126 const SkRect& bounds2 = two.getBounds();
127 SkRect larger = bounds1;
128 larger.join(bounds2);
129 SkBitmap bits;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000130 char out[256];
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000131 int bitWidth = SkScalarCeil(larger.width()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000132 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
133 return false;
134 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000135 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000136 if (bitHeight >= (int) sizeof(out)) {
137 return false;
138 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000139 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
140 bits.allocPixels();
141 SkCanvas canvas(bits);
142 canvas.drawColor(SK_ColorWHITE);
143 SkPaint paint;
144 canvas.save();
145 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
146 canvas.drawPath(one, paint);
147 canvas.restore();
148 canvas.save();
caryclark@google.comfb173422012-04-10 18:28:55 +0000149 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000150 canvas.drawPath(two, paint);
151 canvas.restore();
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000152 for (int y = 0; y < bitHeight; ++y) {
153 uint32_t* addr1 = bits.getAddr32(0, y);
154 int x;
155 char* outPtr = out;
156 for (x = 0; x < bitWidth; ++x) {
157 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
158 }
159 *outPtr++ = '|';
160 for (x = bitWidth; x < bitWidth * 2; ++x) {
161 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
162 }
163 *outPtr++ = '\0';
164 SkDebugf("%s\n", out);
165 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000166 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000167}
168
caryclark@google.com198e0542012-03-30 18:47:02 +0000169static int scaledDrawTheSame(const SkPath& one, const SkPath& two,
caryclark@google.coma3f05fa2012-06-01 17:44:28 +0000170 SkScalar a, SkScalar b, bool drawPaths, SkBitmap& bitmap,
171 SkCanvas* canvas) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000172 SkMatrix scale;
173 scale.reset();
caryclark@google.com752b60e2012-03-22 21:11:17 +0000174 float aScale = 1.21f;
175 float bScale = 1.11f;
176 scale.preScale(a * aScale, b * bScale);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000177 SkPath scaledOne, scaledTwo;
178 one.transform(scale, &scaledOne);
179 two.transform(scale, &scaledTwo);
caryclark@google.com198e0542012-03-30 18:47:02 +0000180 int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas);
181 if (errors == 0) {
182 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000183 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000184 while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
185 scale.reset();
186 aScale *= 0.5f;
187 bScale *= 0.5f;
188 scale.preScale(a * aScale, b * bScale);
189 one.transform(scale, &scaledOne);
190 two.transform(scale, &scaledTwo);
191 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000192 return errors;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000193}
194
caryclark@google.com78e17132012-04-17 11:40:34 +0000195static int max = 0;
196
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000197int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
caryclark@google.com198e0542012-03-30 18:47:02 +0000198 SkCanvas* canvas) {
199 int errors = pathsDrawTheSame(one, two, bitmap, canvas);
200 if (errors == 0) {
201 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000202 }
203 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
204 for (int x = 9; x <= 33; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000205 errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths,
206 bitmap, canvas);
207 if (errors == 0) {
208 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000209 }
210 }
211 if (!gDrawAllAsciiPaths) {
caryclark@google.comfb173422012-04-10 18:28:55 +0000212 const SkRect& bounds1 = one.getBounds();
213 const SkRect& bounds2 = two.getBounds();
214 SkRect larger = bounds1;
215 larger.join(bounds2);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000216 SkScalar xScale = std::max(32.0f / larger.width(), 1.0f);
217 SkScalar yScale = std::max(24.0f / larger.height(), 1.0f);
caryclark@google.comfb173422012-04-10 18:28:55 +0000218 errors = scaledDrawTheSame(one, two, xScale, yScale, false, bitmap, canvas);
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000219 if (errors > 5) {
caryclark@google.com59823f72012-08-09 18:17:47 +0000220 SkDebugf("\n");
caryclark@google.comfb173422012-04-10 18:28:55 +0000221 scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas);
caryclark@google.com198e0542012-03-30 18:47:02 +0000222 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000223 }
caryclark@google.com59823f72012-08-09 18:17:47 +0000224 const int MAX_ERRORS = 20;
225 if (errors > max && errors <= MAX_ERRORS) {
226 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
caryclark@google.com78e17132012-04-17 11:40:34 +0000227 max = errors;
228 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000229 if (errors > MAX_ERRORS && gComparePathsAssert) {
caryclark@google.com59823f72012-08-09 18:17:47 +0000230 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000231 showPath(one);
232 showPath(two, "simplified:");
233 SkASSERT(0);
234 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000235 return errors > MAX_ERRORS ? errors : 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000236}
237
238// doesn't work yet
239void comparePathsTiny(const SkPath& one, const SkPath& two) {
240 const SkRect& bounds1 = one.getBounds();
241 const SkRect& bounds2 = two.getBounds();
242 SkRect larger = bounds1;
243 larger.join(bounds2);
244 SkBitmap bits;
245 int bitWidth = SkScalarCeil(larger.width()) + 2;
246 int bitHeight = SkScalarCeil(larger.height()) + 2;
247 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
248 bits.allocPixels();
249 SkCanvas canvas(bits);
250 canvas.drawColor(SK_ColorWHITE);
251 SkPaint paint;
252 canvas.save();
253 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
254 canvas.drawPath(one, paint);
255 canvas.restore();
256 canvas.save();
257 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
258 canvas.drawPath(two, paint);
259 canvas.restore();
260 for (int y = 0; y < bitHeight; ++y) {
261 uint8_t* addr1 = bits.getAddr1(0, y);
262 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
263 for (int x = 0; x < bits.rowBytes(); ++x) {
264 SkASSERT(addr1[x] == addr2[x]);
265 }
266 }
267}
268
caryclark@google.com198e0542012-03-30 18:47:02 +0000269bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap,
270 SkCanvas* canvas) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000271 if (gShowPath) {
272 showPath(path);
273 }
274 simplify(path, fill, out);
caryclark@google.com752b60e2012-03-22 21:11:17 +0000275 if (!gComparePaths) {
276 return true;
277 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000278 return comparePaths(path, out, bitmap, canvas) == 0;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000279}
caryclark@google.com78e17132012-04-17 11:40:34 +0000280
caryclark@google.com59823f72012-08-09 18:17:47 +0000281bool testSimplifyx(const SkPath& path, SkPath& out, State4& state,
282 const char* pathStr) {
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000283 if (gShowPath) {
284 showPath(path);
285 }
286 simplifyx(path, out);
287 if (!gComparePaths) {
288 return true;
289 }
caryclark@google.com59823f72012-08-09 18:17:47 +0000290 int result = comparePaths(path, out, state.bitmap, state.canvas);
291 if (result && gPathStrAssert) {
292 char temp[8192];
293 bzero(temp, sizeof(temp));
294 SkMemoryWStream stream(temp, sizeof(temp));
295 outputToStream(state, pathStr, stream);
296 SkDebugf(temp);
297 SkASSERT(0);
298 }
299 return result == 0;
caryclark@google.com8dcf1142012-07-02 20:27:02 +0000300}
301
302bool testSimplifyx(const SkPath& path) {
303 if (false) {
304 showPath(path);
305 }
306 SkPath out;
307 simplifyx(path, out);
308 if (false) {
309 return true;
310 }
311 SkBitmap bitmap;
312 return comparePaths(path, out, bitmap, 0) == 0;
313}
314
caryclark@google.com59823f72012-08-09 18:17:47 +0000315const int maxThreadsAllocated = 64;
316static int maxThreads = 1;
317static int threadIndex;
318State4 threadState[maxThreadsAllocated];
319static int testNumber;
320static const char* testName;
321static bool debugThreads = false;
322
323State4* State4::queue = NULL;
324pthread_mutex_t State4::addQueue = PTHREAD_MUTEX_INITIALIZER;
325pthread_cond_t State4::checkQueue = PTHREAD_COND_INITIALIZER;
326
caryclark@google.com78e17132012-04-17 11:40:34 +0000327State4::State4() {
328 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100);
329 bitmap.allocPixels();
330 canvas = new SkCanvas(bitmap);
331}
332
caryclark@google.com59823f72012-08-09 18:17:47 +0000333void createThread(State4* statePtr, void* (*testFun)(void* )) {
334 int threadError = pthread_create(&statePtr->threadID, NULL, testFun,
caryclark@google.com78e17132012-04-17 11:40:34 +0000335 (void*) statePtr);
336 SkASSERT(!threadError);
337}
338
caryclark@google.com59823f72012-08-09 18:17:47 +0000339int dispatchTest4(void* (*testFun)(void* ), int a, int b, int c, int d) {
340 int testsRun = 0;
341
342 if (!gRunTestsInOneThread) {
343 State4* statePtr;
344 pthread_mutex_lock(&State4::addQueue);
345 if (threadIndex < maxThreads) {
346 statePtr = &threadState[threadIndex];
347 statePtr->testsRun = 0;
348 statePtr->a = a;
349 statePtr->b = b;
350 statePtr->c = c;
351 statePtr->d = d;
352 statePtr->done = false;
353 statePtr->index = threadIndex;
354 statePtr->last = false;
355 if (debugThreads) SkDebugf("%s %d create done=%d last=%d\n", __FUNCTION__,
356 statePtr->index, statePtr->done, statePtr->last);
357 pthread_cond_init(&statePtr->initialized, NULL);
358 ++threadIndex;
359 createThread(statePtr, testFun);
360 } else {
361 while (!State4::queue) {
362 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__);
363 pthread_cond_wait(&State4::checkQueue, &State4::addQueue);
364 }
365 statePtr = State4::queue;
366 testsRun += statePtr->testsRun;
367 statePtr->testsRun = 0;
368 statePtr->a = a;
369 statePtr->b = b;
370 statePtr->c = c;
371 statePtr->d = d;
372 statePtr->done = false;
373 State4::queue = NULL;
374 for (int index = 0; index < maxThreads; ++index) {
375 if (threadState[index].done) {
376 State4::queue = &threadState[index];
377 }
378 }
379 if (debugThreads) SkDebugf("%s %d init done=%d last=%d queued=%d\n", __FUNCTION__,
380 statePtr->index, statePtr->done, statePtr->last,
381 State4::queue ? State4::queue->index : -1);
382 pthread_cond_signal(&statePtr->initialized);
383 }
384 pthread_mutex_unlock(&State4::addQueue);
385 } else {
386 State4 state;
387 state.a = a;
388 state.b = b;
389 state.c = c;
390 state.d = d;
391 (*testFun)(&state);
392 testsRun++;
caryclark@google.com78e17132012-04-17 11:40:34 +0000393 }
caryclark@google.com59823f72012-08-09 18:17:47 +0000394 return testsRun;
395}
396
397void initializeTests(const char* test, size_t testNameSize) {
398 testName = test;
399 if (!gRunTestsInOneThread) {
400 int threads = -1;
401 size_t size = sizeof(threads);
402 sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0);
403 if (threads > 0) {
404 maxThreads = threads;
405 } else {
406 maxThreads = 8;
407 }
408 }
409 if (!gRunTestsInOneThread) {
410 SkFILEStream inFile("../../experimental/Intersection/op.htm");
411 if (inFile.isValid()) {
412 SkTDArray<char> inData;
413 inData.setCount(inFile.getLength());
414 size_t inLen = inData.count();
415 inFile.read(inData.begin(), inLen);
416 inFile.setPath(NULL);
417 char* insert = strstr(inData.begin(), marker);
418 if (insert) {
419 insert += sizeof(marker) - 1;
420 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1;
421 testNumber = atoi(numLoc) + 1;
422 }
423 }
424 }
425 for (int index = 0; index < maxThreads; ++index) {
426 State4* statePtr = &threadState[index];
427 strcpy(statePtr->filename, filename);
428 SkASSERT(statePtr->filename[sizeof(filename) - 7] == 'X');
429 SkASSERT(statePtr->filename[sizeof(filename) - 6] == 'X');
430 statePtr->filename[sizeof(filename) - 7] = '0' + index / 10;
431 statePtr->filename[sizeof(filename) - 6] = '0' + index % 10;
432 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000433 threadIndex = 0;
434}
caryclark@google.com59823f72012-08-09 18:17:47 +0000435
436void outputProgress(const State4& state, const char* pathStr) {
437 if (gRunTestsInOneThread) {
438 SkDebugf("%s\n", pathStr);
439 } else {
440 SkFILEWStream outFile(state.filename);
441 if (!outFile.isValid()) {
442 SkASSERT(0);
443 return;
444 }
445 outputToStream(state, pathStr, outFile);
446 }
447}
448
449void outputToStream(const State4& state, const char* pathStr, SkWStream& outFile) {
450 outFile.writeText("<div id=\"");
451 outFile.writeText(testName);
452 outFile.writeDecAsText(testNumber);
453 outFile.writeText("\">\n");
454 outFile.writeText(pathStr);
455 outFile.writeText("</div>\n\n");
456
457 outFile.writeText(marker);
458 outFile.writeText(" ");
459 outFile.writeText(testName);
460 outFile.writeDecAsText(testNumber);
461 outFile.writeText(",\n\n\n");
462
463 outFile.writeText("static void ");
464 outFile.writeText(testName);
465 outFile.writeDecAsText(testNumber);
466 outFile.writeText("() {\n SkPath path;\n");
467 outFile.writeText(pathStr);
468 outFile.writeText(" testSimplifyx(path);\n}\n\n");
469 outFile.writeText("static void (*firstTest)() = ");
470 outFile.writeText(testName);
471 outFile.writeDecAsText(testNumber);
472 outFile.writeText(";\n\n");
473
474 outFile.writeText("static struct {\n");
475 outFile.writeText(" void (*fun)();\n");
476 outFile.writeText(" const char* str;\n");
477 outFile.writeText("} tests[] = {\n");
478 outFile.writeText(" TEST(");
479 outFile.writeText(testName);
480 outFile.writeDecAsText(testNumber);
481 outFile.writeText("),\n");
482 outFile.flush();
483}
484
485bool runNextTestSet(State4& state) {
486 if (gRunTestsInOneThread) {
487 return false;
488 }
489 pthread_mutex_lock(&State4::addQueue);
490 state.done = true;
491 State4::queue = &state;
492 if (debugThreads) SkDebugf("%s %d checkQueue done=%d last=%d\n", __FUNCTION__, state.index,
493 state.done, state.last);
494 pthread_cond_signal(&State4::checkQueue);
495 while (state.done && !state.last) {
496 if (debugThreads) SkDebugf("%s %d done=%d last=%d\n", __FUNCTION__, state.index, state.done, state.last);
497 pthread_cond_wait(&state.initialized, &State4::addQueue);
498 }
499 pthread_mutex_unlock(&State4::addQueue);
500 return !state.last;
501}
502
503int waitForCompletion() {
504 int testsRun = 0;
505 if (!gRunTestsInOneThread) {
506 pthread_mutex_lock(&State4::addQueue);
507 int runningThreads = maxThreads;
508 int index;
509 while (runningThreads > 0) {
510 while (!State4::queue) {
511 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__);
512 pthread_cond_wait(&State4::checkQueue, &State4::addQueue);
513 }
514 while (State4::queue) {
515 --runningThreads;
516 SkDebugf("•");
517 State4::queue->last = true;
518 State4* next;
519 for (index = 0; index < maxThreads; ++index) {
520 State4& test = threadState[index];
521 if (test.done && !test.last) {
522 next = &test;
523 }
524 }
525 if (debugThreads) SkDebugf("%s %d next=%d deQueue\n", __FUNCTION__,
526 State4::queue->index, next ? next->index : -1);
527 pthread_cond_signal(&State4::queue->initialized);
528 State4::queue = next;
529 }
530 }
531 pthread_mutex_unlock(&State4::addQueue);
532 for (index = 0; index < maxThreads; ++index) {
533 pthread_join(threadState[index].threadID, NULL);
534 testsRun += threadState[index].testsRun;
535 }
536 SkDebugf("\n");
537 }
538#ifdef SK_DEBUG
539 gDebugMaxWindSum = SK_MaxS32;
540 gDebugMaxWindValue = SK_MaxS32;
541#endif
542 return testsRun;
543}