| 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 |