OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "PathOpsExtendedTest.h" | 8 #include "PathOpsExtendedTest.h" |
| 9 #include "PathOpsThreadedCommon.h" |
9 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
10 #include "SkCanvas.h" | 11 #include "SkCanvas.h" |
11 #include "SkMatrix.h" | 12 #include "SkMatrix.h" |
12 #include "SkPaint.h" | 13 #include "SkPaint.h" |
13 #include "SkStream.h" | 14 #include "SkStream.h" |
14 | 15 |
15 #ifdef SK_BUILD_FOR_MAC | 16 #ifdef SK_BUILD_FOR_MAC |
16 #include <sys/sysctl.h> | 17 #include <sys/sysctl.h> |
17 #endif | 18 #endif |
18 | 19 |
19 bool gShowTestProgress = false; | |
20 bool gAllowExtendedTest = false; | |
21 | |
22 static const char marker[] = | 20 static const char marker[] = |
23 "</div>\n" | 21 "</div>\n" |
24 "\n" | 22 "\n" |
25 "<script type=\"text/javascript\">\n" | 23 "<script type=\"text/javascript\">\n" |
26 "\n" | 24 "\n" |
27 "var testDivs = [\n"; | 25 "var testDivs = [\n"; |
28 | 26 |
29 static const char* opStrs[] = { | 27 static const char* opStrs[] = { |
30 "kDifference_PathOp", | 28 "kDifference_PathOp", |
31 "kIntersect_PathOp", | 29 "kIntersect_PathOp", |
32 "kUnion_PathOp", | 30 "kUnion_PathOp", |
33 "kXor_PathOp", | 31 "kXor_PathOp", |
34 }; | 32 }; |
35 | 33 |
36 static const char* opSuffixes[] = { | 34 static const char* opSuffixes[] = { |
37 "d", | 35 "d", |
38 "i", | 36 "i", |
39 "u", | 37 "u", |
40 "x", | 38 "o", |
41 }; | 39 }; |
42 | 40 |
43 static bool gShowPath = false; | 41 static bool gShowPath = false; |
44 static bool gComparePaths = true; | 42 static bool gComparePaths = true; |
45 static bool gShowOutputProgress = false; | |
46 static bool gComparePathsAssert = true; | 43 static bool gComparePathsAssert = true; |
47 static bool gPathStrAssert = true; | 44 static bool gPathStrAssert = true; |
48 static bool gUsePhysicalFiles = false; | |
49 | 45 |
50 #if FORCE_RELEASE && !defined SK_BUILD_FOR_WIN | 46 #if FORCE_RELEASE |
51 static bool gRunTestsInOneThread = false; | 47 static bool gRunTestsInOneThread = false; |
52 #else | 48 #else |
53 static bool gRunTestsInOneThread = true; | 49 static bool gRunTestsInOneThread = true; |
54 #endif | 50 #endif |
55 | 51 |
56 static void showPathContour(SkPath::Iter& iter) { | 52 static void showPathContour(SkPath::Iter& iter) { |
57 uint8_t verb; | 53 uint8_t verb; |
58 SkPoint pts[4]; | 54 SkPoint pts[4]; |
59 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 55 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
60 switch (verb) { | 56 switch (verb) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 | 109 |
114 void showPathData(const SkPath& path) { | 110 void showPathData(const SkPath& path) { |
115 SkPath::Iter iter(path, true); | 111 SkPath::Iter iter(path, true); |
116 uint8_t verb; | 112 uint8_t verb; |
117 SkPoint pts[4]; | 113 SkPoint pts[4]; |
118 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 114 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
119 switch (verb) { | 115 switch (verb) { |
120 case SkPath::kMove_Verb: | 116 case SkPath::kMove_Verb: |
121 continue; | 117 continue; |
122 case SkPath::kLine_Verb: | 118 case SkPath::kLine_Verb: |
123 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0].
fY, pts[1].fX, pts[1].fY); | 119 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0].
fY, |
| 120 pts[1].fX, pts[1].fY); |
124 break; | 121 break; |
125 case SkPath::kQuad_Verb: | 122 case SkPath::kQuad_Verb: |
126 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", | 123 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", |
127 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2
].fY); | 124 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, p
ts[2].fY); |
128 break; | 125 break; |
129 case SkPath::kCubic_Verb: | 126 case SkPath::kCubic_Verb: |
130 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%
1.9g}},\n", | 127 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%
1.9g}},\n", |
131 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2
].fY, pts[3].fX, pts[3].fY); | 128 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, p
ts[2].fY, |
| 129 pts[3].fX, pts[3].fY); |
132 break; | 130 break; |
133 case SkPath::kClose_Verb: | 131 case SkPath::kClose_Verb: |
134 break; | 132 break; |
135 default: | 133 default: |
136 SkDEBUGFAIL("bad verb"); | 134 SkDEBUGFAIL("bad verb"); |
137 return; | 135 return; |
138 } | 136 } |
139 } | 137 } |
140 } | 138 } |
141 | 139 |
(...skipping 13 matching lines...) Expand all Loading... |
155 break; | 153 break; |
156 default: | 154 default: |
157 SkASSERT(0); | 155 SkASSERT(0); |
158 } | 156 } |
159 } | 157 } |
160 | 158 |
161 static void showPath(const SkPath& path, const char* str, const SkMatrix& scale)
{ | 159 static void showPath(const SkPath& path, const char* str, const SkMatrix& scale)
{ |
162 SkPath scaled; | 160 SkPath scaled; |
163 SkMatrix inverse; | 161 SkMatrix inverse; |
164 bool success = scale.invert(&inverse); | 162 bool success = scale.invert(&inverse); |
165 if (!success) { | 163 if (!success) { |
166 SkASSERT(0); | 164 SkASSERT(0); |
167 } | 165 } |
168 path.transform(inverse, &scaled); | 166 path.transform(inverse, &scaled); |
169 showPath(scaled, str); | 167 showPath(scaled, str); |
170 } | 168 } |
171 | 169 |
172 const int bitWidth = 64; | 170 const int bitWidth = 64; |
173 const int bitHeight = 64; | 171 const int bitHeight = 64; |
174 | 172 |
175 static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) { | 173 static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) { |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 SkDebugf("op: %s\n", opStrs[shapeOp]); | 321 SkDebugf("op: %s\n", opStrs[shapeOp]); |
324 showPath(b, "subtrahend:"); | 322 showPath(b, "subtrahend:"); |
325 // the region often isn't very helpful since it approximates curves with a l
ot of line-tos | 323 // the region often isn't very helpful since it approximates curves with a l
ot of line-tos |
326 if (0) showPath(scaledOne, "region:", scale); | 324 if (0) showPath(scaledOne, "region:", scale); |
327 showPath(two, "op result:"); | 325 showPath(two, "op result:"); |
328 drawAsciiPaths(scaledOne, scaledTwo, true); | 326 drawAsciiPaths(scaledOne, scaledTwo, true); |
329 } | 327 } |
330 | 328 |
331 static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const S
kPath& scaledOne, | 329 static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const S
kPath& scaledOne, |
332 const SkPath& two, const SkPath& scaledTwo, SkBitmap& bi
tmap, | 330 const SkPath& two, const SkPath& scaledTwo, SkBitmap& bi
tmap, |
333 const SkPath& a, const SkPath& b, const SkPathOp shapeOp
, | 331 const SkPath& a, const SkPath& b, const SkPathOp shapeOp
, |
334 const SkMatrix& scale) { | 332 const SkMatrix& scale) { |
335 int errors2x2; | 333 int errors2x2; |
336 int errors = pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2); | 334 int errors = pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2); |
337 if (errors2x2 == 0) { | 335 if (errors2x2 == 0) { |
338 return 0; | 336 return 0; |
339 } | 337 } |
340 const int MAX_ERRORS = 8; | 338 const int MAX_ERRORS = 8; |
341 if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) { | 339 if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) { |
342 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale); | 340 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale); |
343 } | 341 } |
344 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) { | 342 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) { |
345 SkDebugf("%s errors=%d\n", __FUNCTION__, errors); | 343 SkDebugf("%s errors=%d\n", __FUNCTION__, errors); |
346 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale); | 344 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale); |
347 REPORTER_ASSERT(reporter, 0); | 345 REPORTER_ASSERT(reporter, 0); |
348 } | 346 } |
349 return errors2x2 > MAX_ERRORS ? errors2x2 : 0; | 347 return errors2x2 > MAX_ERRORS ? errors2x2 : 0; |
350 } | 348 } |
351 | 349 |
352 bool testSimplify(SkPath& path, bool useXor, SkPath& out, State4& state, const c
har* pathStr) { | 350 static int testNumber; |
| 351 static const char* testName; |
| 352 |
| 353 static void writeTestName(const char* nameSuffix, SkMemoryWStream& outFile) { |
| 354 outFile.writeText(testName); |
| 355 outFile.writeDecAsText(testNumber); |
| 356 if (nameSuffix) { |
| 357 outFile.writeText(nameSuffix); |
| 358 } |
| 359 } |
| 360 |
| 361 static void outputToStream(const char* pathStr, const char* pathPrefix, const ch
ar* nameSuffix, |
| 362 const char* testFunction, bool twoPaths, SkMemoryWStream& outFile) { |
| 363 outFile.writeText("<div id=\""); |
| 364 writeTestName(nameSuffix, outFile); |
| 365 outFile.writeText("\">\n"); |
| 366 if (pathPrefix) { |
| 367 outFile.writeText(pathPrefix); |
| 368 } |
| 369 outFile.writeText(pathStr); |
| 370 outFile.writeText("</div>\n\n"); |
| 371 |
| 372 outFile.writeText(marker); |
| 373 outFile.writeText(" "); |
| 374 writeTestName(nameSuffix, outFile); |
| 375 outFile.writeText(",\n\n\n"); |
| 376 |
| 377 outFile.writeText("static void "); |
| 378 writeTestName(nameSuffix, outFile); |
| 379 outFile.writeText("() {\n SkPath path"); |
| 380 if (twoPaths) { |
| 381 outFile.writeText(", pathB"); |
| 382 } |
| 383 outFile.writeText(";\n"); |
| 384 if (pathPrefix) { |
| 385 outFile.writeText(pathPrefix); |
| 386 } |
| 387 outFile.writeText(pathStr); |
| 388 outFile.writeText(" "); |
| 389 outFile.writeText(testFunction); |
| 390 outFile.writeText("\n}\n\n"); |
| 391 outFile.writeText("static void (*firstTest)() = "); |
| 392 writeTestName(nameSuffix, outFile); |
| 393 outFile.writeText(";\n\n"); |
| 394 |
| 395 outFile.writeText("static struct {\n"); |
| 396 outFile.writeText(" void (*fun)();\n"); |
| 397 outFile.writeText(" const char* str;\n"); |
| 398 outFile.writeText("} tests[] = {\n"); |
| 399 outFile.writeText(" TEST("); |
| 400 writeTestName(nameSuffix, outFile); |
| 401 outFile.writeText("),\n"); |
| 402 outFile.flush(); |
| 403 } |
| 404 |
| 405 bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& st
ate, |
| 406 const char* pathStr) { |
353 SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWi
nding_FillType; | 407 SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWi
nding_FillType; |
354 path.setFillType(fillType); | 408 path.setFillType(fillType); |
355 if (gShowPath) { | 409 if (gShowPath) { |
356 showPath(path); | 410 showPath(path); |
357 } | 411 } |
358 Simplify(path, &out); | 412 Simplify(path, &out); |
359 if (!gComparePaths) { | 413 if (!gComparePaths) { |
360 return true; | 414 return true; |
361 } | 415 } |
362 int result = comparePaths(state.reporter, path, out, state.bitmap); | 416 int result = comparePaths(state.fReporter, path, out, *state.fBitmap); |
363 if (result && gPathStrAssert) { | 417 if (result && gPathStrAssert) { |
364 SkDebugf("addTest %s\n", state.filename); | |
365 char temp[8192]; | 418 char temp[8192]; |
366 sk_bzero(temp, sizeof(temp)); | 419 sk_bzero(temp, sizeof(temp)); |
367 SkMemoryWStream stream(temp, sizeof(temp)); | 420 SkMemoryWStream stream(temp, sizeof(temp)); |
368 const char* pathPrefix = NULL; | 421 const char* pathPrefix = NULL; |
369 const char* nameSuffix = NULL; | 422 const char* nameSuffix = NULL; |
370 if (fillType == SkPath::kEvenOdd_FillType) { | 423 if (fillType == SkPath::kEvenOdd_FillType) { |
371 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; | 424 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; |
372 nameSuffix = "x"; | 425 nameSuffix = "x"; |
373 } | 426 } |
374 const char testFunction[] = "testSimplifyx(path);"; | 427 const char testFunction[] = "testSimplifyx(path);"; |
375 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, str
eam); | 428 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, str
eam); |
376 SkDebugf(temp); | 429 SkDebugf(temp); |
377 REPORTER_ASSERT(state.reporter, 0); | 430 REPORTER_ASSERT(state.fReporter, 0); |
378 } | 431 } |
| 432 state.fReporter->bumpTestCount(); |
379 return result == 0; | 433 return result == 0; |
380 } | 434 } |
381 | 435 |
382 bool testSimplify(skiatest::Reporter* reporter, const SkPath& path) { | 436 bool testSimplify(skiatest::Reporter* reporter, const SkPath& path) { |
383 SkPath out; | 437 SkPath out; |
384 Simplify(path, &out); | 438 Simplify(path, &out); |
385 SkBitmap bitmap; | 439 SkBitmap bitmap; |
386 int result = comparePaths(reporter, path, out, bitmap); | 440 int result = comparePaths(reporter, path, out, bitmap); |
387 if (result && gPathStrAssert) { | 441 if (result && gPathStrAssert) { |
388 REPORTER_ASSERT(reporter, 0); | 442 REPORTER_ASSERT(reporter, 0); |
389 } | 443 } |
| 444 reporter->bumpTestCount(); |
390 return result == 0; | 445 return result == 0; |
391 } | 446 } |
392 | 447 |
393 bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, | 448 bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, |
394 const SkPathOp shapeOp) { | 449 const SkPathOp shapeOp) { |
395 #if FORCE_RELEASE == 0 | 450 #if FORCE_RELEASE == 0 |
396 showPathData(a); | 451 showPathData(a); |
397 showOp(shapeOp); | 452 showOp(shapeOp); |
398 showPathData(b); | 453 showPathData(b); |
399 #endif | 454 #endif |
(...skipping 21 matching lines...) Expand all Loading... |
421 scaledRgnOut.getBoundaryPath(&scaledPathOut); | 476 scaledRgnOut.getBoundaryPath(&scaledPathOut); |
422 SkBitmap bitmap; | 477 SkBitmap bitmap; |
423 SkPath scaledOut; | 478 SkPath scaledOut; |
424 scaledOut.addPath(out, scale); | 479 scaledOut.addPath(out, scale); |
425 scaledOut.setFillType(out.getFillType()); | 480 scaledOut.setFillType(out.getFillType()); |
426 int result = comparePaths(reporter, pathOut, scaledPathOut, out, scaledOut,
bitmap, a, b, | 481 int result = comparePaths(reporter, pathOut, scaledPathOut, out, scaledOut,
bitmap, a, b, |
427 shapeOp, scale); | 482 shapeOp, scale); |
428 if (result && gPathStrAssert) { | 483 if (result && gPathStrAssert) { |
429 REPORTER_ASSERT(reporter, 0); | 484 REPORTER_ASSERT(reporter, 0); |
430 } | 485 } |
| 486 reporter->bumpTestCount(); |
431 return result == 0; | 487 return result == 0; |
432 } | 488 } |
433 | 489 |
434 const int maxThreadsAllocated = 64; | 490 const int maxThreadsAllocated = 64; |
435 static int maxThreads = 1; | 491 static int maxThreads = 1; |
436 static int threadIndex; | |
437 State4 threadState[maxThreadsAllocated]; | |
438 static int testNumber; | |
439 static const char* testName; | |
440 static bool debugThreads = false; | |
441 | 492 |
442 State4* State4::queue = NULL; | 493 SK_DECLARE_STATIC_MUTEX(gQueueMutex); |
443 | 494 |
444 #if HARD_CODE_PTHREAD | 495 int initializeTests(const char* test) { |
445 pthread_mutex_t State4::addQueue = PTHREAD_MUTEX_INITIALIZER; | 496 #ifdef SK_DEBUG |
446 pthread_cond_t State4::checkQueue = PTHREAD_COND_INITIALIZER; | 497 gDebugMaxWindSum = 4; |
447 #else | 498 gDebugMaxWindValue = 4; |
448 SK_DECLARE_STATIC_MUTEX(gQueueMutex); | |
449 #endif | 499 #endif |
450 | |
451 State4::State4() { | |
452 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100); | |
453 bitmap.allocPixels(); | |
454 } | |
455 | |
456 void createThread(State4* statePtr, ThreadFunction testFun) { | |
457 #if HARD_CODE_PTHREAD | |
458 SkDEBUGCODE(int threadError =) pthread_create(&statePtr->threadID, NULL, tes
tFun, | |
459 (void*) statePtr); | |
460 SkASSERT(!threadError); | |
461 #else | |
462 statePtr->thread = new SkThread(testFun, (void*) statePtr); | |
463 statePtr->thread->start(); | |
464 #endif | |
465 } | |
466 | |
467 int dispatchTest4(ThreadFunction testFun, int a, int b, int c, int d) { | |
468 int testsRun = 0; | |
469 State4* statePtr; | |
470 if (!gRunTestsInOneThread) { | |
471 #if HARD_CODE_PTHREAD | |
472 pthread_mutex_lock(&State4::addQueue); | |
473 #else | |
474 SkAutoMutexAcquire aq(&gQueueMutex); | |
475 #endif | |
476 if (threadIndex < maxThreads) { | |
477 statePtr = &threadState[threadIndex]; | |
478 statePtr->testsRun = 0; | |
479 statePtr->a = a; | |
480 statePtr->b = b; | |
481 statePtr->c = c; | |
482 statePtr->d = d; | |
483 statePtr->done = false; | |
484 statePtr->index = threadIndex; | |
485 statePtr->last = false; | |
486 if (debugThreads) SkDebugf("%s %d create done=%d last=%d\n", __FUNCT
ION__, | |
487 statePtr->index, statePtr->done, statePtr->last); | |
488 #if HARD_CODE_PTHREAD | |
489 pthread_cond_init(&statePtr->initialized, NULL); | |
490 #else | |
491 // statePtr->thread contains fData which points to SkThread_PThreadD
ata which | |
492 // contains PThreadEvent fStarted, all of which is initialized by cr
eateThread below | |
493 #endif | |
494 ++threadIndex; | |
495 createThread(statePtr, testFun); | |
496 } else { | |
497 while (!State4::queue) { | |
498 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__); | |
499 #if HARD_CODE_PTHREAD | |
500 pthread_cond_wait(&State4::checkQueue, &State4::addQueue); | |
501 #else | |
502 // incomplete | |
503 #endif | |
504 } | |
505 statePtr = State4::queue; | |
506 testsRun += statePtr->testsRun; | |
507 statePtr->testsRun = 0; | |
508 statePtr->a = a; | |
509 statePtr->b = b; | |
510 statePtr->c = c; | |
511 statePtr->d = d; | |
512 statePtr->done = false; | |
513 State4::queue = NULL; | |
514 for (int index = 0; index < maxThreads; ++index) { | |
515 if (threadState[index].done) { | |
516 State4::queue = &threadState[index]; | |
517 } | |
518 } | |
519 if (debugThreads) SkDebugf("%s %d init done=%d last=%d queued=%d\n",
__FUNCTION__, | |
520 statePtr->index, statePtr->done, statePtr->last, | |
521 State4::queue ? State4::queue->index : -1); | |
522 #if HARD_CODE_PTHREAD | |
523 pthread_cond_signal(&statePtr->initialized); | |
524 #else | |
525 // incomplete | |
526 #endif | |
527 } | |
528 #if HARD_CODE_PTHREAD | |
529 pthread_mutex_unlock(&State4::addQueue); | |
530 #endif | |
531 } else { | |
532 statePtr = &threadState[0]; | |
533 testsRun += statePtr->testsRun; | |
534 statePtr->testsRun = 0; | |
535 statePtr->a = a; | |
536 statePtr->b = b; | |
537 statePtr->c = c; | |
538 statePtr->d = d; | |
539 statePtr->done = false; | |
540 statePtr->index = threadIndex; | |
541 statePtr->last = false; | |
542 (*testFun)(statePtr); | |
543 } | |
544 return testsRun; | |
545 } | |
546 | |
547 void initializeTests(skiatest::Reporter* reporter, const char* test, size_t test
NameSize) { | |
548 testName = test; | 500 testName = test; |
| 501 size_t testNameSize = strlen(test); |
549 if (!gRunTestsInOneThread) { | 502 if (!gRunTestsInOneThread) { |
550 int threads = -1; | 503 int threads = -1; |
551 #ifdef SK_BUILD_FOR_MAC | 504 #ifdef SK_BUILD_FOR_MAC |
552 size_t size = sizeof(threads); | 505 size_t size = sizeof(threads); |
553 sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0); | 506 sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0); |
554 #endif | 507 #endif |
555 if (threads > 0) { | 508 if (threads > 0) { |
556 maxThreads = threads; | 509 maxThreads = threads; |
557 } else { | 510 } else { |
558 maxThreads = 8; | 511 maxThreads = 16; |
559 } | 512 } |
560 } | 513 } |
561 SkFILEStream inFile("../../experimental/Intersection/op.htm"); | 514 SkFILEStream inFile("../../experimental/Intersection/op.htm"); |
562 if (inFile.isValid()) { | 515 if (inFile.isValid()) { |
563 SkTDArray<char> inData; | 516 SkTDArray<char> inData; |
564 inData.setCount(inFile.getLength()); | 517 inData.setCount(inFile.getLength()); |
565 size_t inLen = inData.count(); | 518 size_t inLen = inData.count(); |
566 inFile.read(inData.begin(), inLen); | 519 inFile.read(inData.begin(), inLen); |
567 inFile.setPath(NULL); | 520 inFile.setPath(NULL); |
568 char* insert = strstr(inData.begin(), marker); | 521 char* insert = strstr(inData.begin(), marker); |
569 if (insert) { | 522 if (insert) { |
570 insert += sizeof(marker) - 1; | 523 insert += sizeof(marker) - 1; |
571 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize -
1; | 524 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize -
1; |
572 testNumber = atoi(numLoc) + 1; | 525 testNumber = atoi(numLoc) + 1; |
573 } | 526 } |
574 } | 527 } |
575 const char* filename = "debugXX.txt"; | 528 return maxThreads; |
576 for (int index = 0; index < maxThreads; ++index) { | |
577 State4* statePtr = &threadState[index]; | |
578 statePtr->reporter = reporter; | |
579 strcpy(statePtr->filename, filename); | |
580 size_t len = strlen(filename); | |
581 SkASSERT(statePtr->filename[len - 6] == 'X'); | |
582 SkASSERT(statePtr->filename[len - 5] == 'X'); | |
583 statePtr->filename[len - 6] = '0' + index / 10; | |
584 statePtr->filename[len - 5] = '0' + index % 10; | |
585 } | |
586 threadIndex = 0; | |
587 } | 529 } |
588 | 530 |
589 void outputProgress(const State4& state, const char* pathStr, SkPath::FillType p
athFillType) { | 531 void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType pathFill
Type) { |
590 if (gRunTestsInOneThread && gShowOutputProgress) { | 532 const char testFunction[] = "testSimplify(path);"; |
591 if (pathFillType == SkPath::kEvenOdd_FillType) { | |
592 SkDebugf(" path.setFillType(SkPath::kEvenOdd_FillType);\n", pathS
tr); | |
593 } | |
594 SkDebugf("%s\n", pathStr); | |
595 } | |
596 const char testFunction[] = "testSimplifyx(path);"; | |
597 const char* pathPrefix = NULL; | 533 const char* pathPrefix = NULL; |
598 const char* nameSuffix = NULL; | 534 const char* nameSuffix = NULL; |
599 if (pathFillType == SkPath::kEvenOdd_FillType) { | 535 if (pathFillType == SkPath::kEvenOdd_FillType) { |
600 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; | 536 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; |
601 nameSuffix = "x"; | 537 nameSuffix = "x"; |
602 } | 538 } |
603 if (gUsePhysicalFiles) { | 539 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE); |
604 SkFILEWStream outFile(state.filename); | 540 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, rRamStr
eam); |
605 if (!outFile.isValid()) { | |
606 SkASSERT(0); | |
607 return; | |
608 } | |
609 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, out
File); | |
610 return; | |
611 } | |
612 state.ramStream.reset(); | |
613 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, state.r
amStream); | |
614 } | 541 } |
615 | 542 |
616 void outputProgress(const State4& state, const char* pathStr, SkPathOp op) { | 543 void outputProgress(char* ramStr, const char* pathStr, SkPathOp op) { |
617 SkString testFunc("testPathOp(path, pathB, "); | 544 const char testFunction[] = "testOp(path);"; |
618 testFunc += opStrs[op]; | 545 SkASSERT(op < sizeof(opSuffixes) / sizeof(opSuffixes[0])); |
619 testFunc += ");"; | |
620 const char* testFunction = testFunc.c_str(); | |
621 if (gRunTestsInOneThread && gShowOutputProgress) { | |
622 SkDebugf("%s\n", pathStr); | |
623 SkDebugf(" %s\n", testFunction); | |
624 } | |
625 const char* nameSuffix = opSuffixes[op]; | 546 const char* nameSuffix = opSuffixes[op]; |
626 if (gUsePhysicalFiles) { | 547 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE); |
627 SkFILEWStream outFile(state.filename); | 548 outputToStream(pathStr, NULL, nameSuffix, testFunction, true, rRamStream); |
628 if (!outFile.isValid()) { | |
629 SkASSERT(0); | |
630 return; | |
631 } | |
632 outputToStream(state, pathStr, NULL, nameSuffix, testFunction, outFile); | |
633 return; | |
634 } | |
635 state.ramStream.reset(); | |
636 outputToStream(state, pathStr, NULL, nameSuffix, testFunction, state.ramStre
am); | |
637 } | |
638 | |
639 static void writeTestName(const char* nameSuffix, SkWStream& outFile) { | |
640 outFile.writeText(testName); | |
641 outFile.writeDecAsText(testNumber); | |
642 if (nameSuffix) { | |
643 outFile.writeText(nameSuffix); | |
644 } | |
645 } | |
646 | |
647 void outputToStream(const State4& state, const char* pathStr, const char* pathPr
efix, | |
648 const char* nameSuffix, | |
649 const char* testFunction, SkWStream& outFile) { | |
650 outFile.writeText("<div id=\""); | |
651 writeTestName(nameSuffix, outFile); | |
652 outFile.writeText("\">\n"); | |
653 if (pathPrefix) { | |
654 outFile.writeText(pathPrefix); | |
655 } | |
656 outFile.writeText(pathStr); | |
657 outFile.writeText("</div>\n\n"); | |
658 | |
659 outFile.writeText(marker); | |
660 outFile.writeText(" "); | |
661 writeTestName(nameSuffix, outFile); | |
662 outFile.writeText(",\n\n\n"); | |
663 | |
664 outFile.writeText("static void "); | |
665 writeTestName(nameSuffix, outFile); | |
666 outFile.writeText("() {\n SkPath path"); | |
667 if (!pathPrefix) { | |
668 outFile.writeText(", pathB"); | |
669 } | |
670 outFile.writeText(";\n"); | |
671 if (pathPrefix) { | |
672 outFile.writeText(pathPrefix); | |
673 } | |
674 outFile.writeText(pathStr); | |
675 outFile.writeText(" "); | |
676 outFile.writeText(testFunction); | |
677 outFile.writeText("\n}\n\n"); | |
678 outFile.writeText("static void (*firstTest)() = "); | |
679 writeTestName(nameSuffix, outFile); | |
680 outFile.writeText(";\n\n"); | |
681 | |
682 outFile.writeText("static struct {\n"); | |
683 outFile.writeText(" void (*fun)();\n"); | |
684 outFile.writeText(" const char* str;\n"); | |
685 outFile.writeText("} tests[] = {\n"); | |
686 outFile.writeText(" TEST("); | |
687 writeTestName(nameSuffix, outFile); | |
688 outFile.writeText("),\n"); | |
689 outFile.flush(); | |
690 } | |
691 | |
692 bool runNextTestSet(State4& state) { | |
693 if (gRunTestsInOneThread) { | |
694 return false; | |
695 } | |
696 #if HARD_CODE_PTHREAD | |
697 pthread_mutex_lock(&State4::addQueue); | |
698 #else | |
699 SkAutoMutexAcquire aq(&gQueueMutex); | |
700 #endif | |
701 state.done = true; | |
702 State4::queue = &state; | |
703 if (debugThreads) SkDebugf("%s %d checkQueue done=%d last=%d\n", __FUNCTION_
_, state.index, | |
704 state.done, state.last); | |
705 #if HARD_CODE_PTHREAD | |
706 pthread_cond_signal(&State4::checkQueue); | |
707 #else | |
708 // incomplete | |
709 #endif | |
710 while (state.done && !state.last) { | |
711 if (debugThreads) SkDebugf("%s %d done=%d last=%d\n", __FUNCTION__, stat
e.index, state.done, state.last); | |
712 #if HARD_CODE_PTHREAD | |
713 pthread_cond_wait(&state.initialized, &State4::addQueue); | |
714 #else | |
715 // incomplete | |
716 #endif | |
717 } | |
718 #if HARD_CODE_PTHREAD | |
719 pthread_mutex_unlock(&State4::addQueue); | |
720 #endif | |
721 return !state.last; | |
722 } | |
723 | |
724 int waitForCompletion() { | |
725 int testsRun = 0; | |
726 if (!gRunTestsInOneThread) { | |
727 #if HARD_CODE_PTHREAD | |
728 pthread_mutex_lock(&State4::addQueue); | |
729 #else | |
730 SkAutoMutexAcquire aq(gQueueMutex); | |
731 #endif | |
732 int runningThreads = threadIndex; | |
733 int index; | |
734 while (runningThreads > 0) { | |
735 while (!State4::queue) { | |
736 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__); | |
737 #if HARD_CODE_PTHREAD | |
738 pthread_cond_wait(&State4::checkQueue, &State4::addQueue); | |
739 #else | |
740 // ioncomplete | |
741 #endif | |
742 } | |
743 while (State4::queue) { | |
744 --runningThreads; | |
745 #if DEBUG_SHOW_TEST_PROGRESS | |
746 SkDebugf("•"); | |
747 #endif | |
748 State4::queue->last = true; | |
749 State4* next = NULL; | |
750 for (index = 0; index < maxThreads; ++index) { | |
751 State4& test = threadState[index]; | |
752 if (test.done && !test.last) { | |
753 next = &test; | |
754 } | |
755 } | |
756 if (debugThreads) SkDebugf("%s %d next=%d deQueue\n", __FUNCTION
__, | |
757 State4::queue->index, next ? next->index : -1); | |
758 #if HARD_CODE_PTHREAD | |
759 pthread_cond_signal(&State4::queue->initialized); | |
760 #else | |
761 // incomplete | |
762 #endif | |
763 State4::queue = next; | |
764 } | |
765 } | |
766 #if HARD_CODE_PTHREAD | |
767 pthread_mutex_unlock(&State4::addQueue); | |
768 #endif | |
769 for (index = 0; index < maxThreads; ++index) { | |
770 #if HARD_CODE_PTHREAD | |
771 pthread_join(threadState[index].threadID, NULL); | |
772 #else | |
773 threadState[index].thread->join(); | |
774 delete threadState[index].thread; | |
775 #endif | |
776 testsRun += threadState[index].testsRun; | |
777 } | |
778 #if DEBUG_SHOW_TEST_PROGRESS | |
779 SkDebugf("\n"); | |
780 #endif | |
781 } | |
782 #ifdef SK_DEBUG | |
783 gDebugMaxWindSum = SK_MaxS32; | |
784 gDebugMaxWindValue = SK_MaxS32; | |
785 #endif | |
786 return testsRun; | |
787 } | 549 } |
788 | 550 |
789 void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count, | 551 void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count, |
790 void (*firstTest)(skiatest::Reporter* ), | 552 void (*firstTest)(skiatest::Reporter* ), |
791 void (*stopTest)(skiatest::Reporter* ), bool reverse) { | 553 void (*stopTest)(skiatest::Reporter* ), bool reverse) { |
792 size_t index; | 554 size_t index; |
793 if (firstTest) { | 555 if (firstTest) { |
794 index = count - 1; | 556 index = count - 1; |
795 while (index > 0 && tests[index].fun != firstTest) { | 557 while (index > 0 && tests[index].fun != firstTest) { |
796 --index; | 558 --index; |
(...skipping 16 matching lines...) Expand all Loading... |
813 } | 575 } |
814 if (tests[index].fun == stopTest) { | 576 if (tests[index].fun == stopTest) { |
815 SkDebugf("lastTest\n"); | 577 SkDebugf("lastTest\n"); |
816 } | 578 } |
817 if (index == last) { | 579 if (index == last) { |
818 break; | 580 break; |
819 } | 581 } |
820 index += reverse ? -1 : 1; | 582 index += reverse ? -1 : 1; |
821 } while (true); | 583 } while (true); |
822 } | 584 } |
OLD | NEW |