Chromium Code Reviews| Index: gm/gmmain.cpp |
| =================================================================== |
| --- gm/gmmain.cpp (revision 8160) |
| +++ gm/gmmain.cpp (working copy) |
| @@ -194,6 +194,7 @@ |
| // Set default values of member variables, which tool_main() |
| // may override. |
| fUseFileHierarchy = false; |
| + fSimulatePipePlaybackFailure = false; |
| fMismatchPath = NULL; |
| } |
| @@ -261,8 +262,9 @@ |
| return; |
| } |
| - FailRec& rec = fFailedTests.push_back(make_name( |
| - name.c_str(), renderModeDescriptor)); |
| + SkString completeName = name; |
| + completeName.append(renderModeDescriptor); |
| + FailRec& rec = fFailedTests.push_back(completeName); |
| rec.fIsPixelError = |
| (kEmptyErrorBitfield != (errorType & kImageMismatch_ErrorBitmask)); |
| } |
| @@ -905,7 +907,9 @@ |
| SkGPipeWriter writer; |
| SkCanvas* pipeCanvas = writer.startRecording( |
| &pipeController, gPipeWritingFlagCombos[i].flags); |
| - invokeGM(gm, pipeCanvas, false, false); |
| + if (!this->fSimulatePipePlaybackFailure) { |
| + invokeGM(gm, pipeCanvas, false, false); |
| + } |
| complete_bitmap(&bitmap); |
| writer.endRecording(); |
| SkString string("-pipe"); |
| @@ -951,6 +955,7 @@ |
| // |
| bool fUseFileHierarchy; |
| + bool fSimulatePipePlaybackFailure; |
| const char* fMismatchPath; |
| @@ -1054,6 +1059,7 @@ |
| " [--resourcePath|-i <path>]: directory that stores image resources\n" |
| " [--nortree]: Do not exercise the R-Tree variant of SkPicture\n" |
| " [--noserialize]: do not exercise SkPicture serialization & deserialization\n" |
| +" [--simulatePipePlaybackFailure]: simulate a rendering failure in pipe mode only\n" |
| " [--tiledPipe]: Exercise tiled SkGPipe replay\n" |
| " [--notileGrid]: Do not exercise the tile grid variant of SkPicture\n" |
| " [--tileGridReplayScales <scales>]: Comma separated list of floating-point scale\n" |
| @@ -1136,6 +1142,233 @@ |
| } |
| } |
| +/** |
| + * Run this test in a number of different configs (8888, 565, PDF, |
| + * etc.), confirming that the resulting bitmaps match expectations |
| + * (which may be different for each config). |
| + */ |
| +ErrorBitfield run_multiple_configs(GMMain &gmmain, GM *gm, const SkTDArray<size_t> &configs, |
|
epoger
2013/03/14 21:18:02
patchset 2 is a refactoring-only change... it extr
|
| + GrContextFactory *grFactory, int gpuCacheSizeBytes, |
| + int gpuCacheSizeCount, const char *writePath, bool doPDF, |
| + bool doDeferred) { |
| + uint32_t gmFlags = gm->getFlags(); |
| + ErrorBitfield testErrors = kEmptyErrorBitfield; |
| + for (int i = 0; i < configs.count(); i++) { |
| + ConfigData config = gRec[configs[i]]; |
| + |
| + // Skip any tests that we don't even need to try. |
| + if ((kPDF_Backend == config.fBackend) && |
| + (!doPDF || (gmFlags & GM::kSkipPDF_Flag))) |
| + { |
| + continue; |
| + } |
| + if ((gmFlags & GM::kSkip565_Flag) && |
| + (kRaster_Backend == config.fBackend) && |
| + (SkBitmap::kRGB_565_Config == config.fConfig)) { |
| + continue; |
| + } |
| + if ((gmFlags & GM::kSkipGPU_Flag) && |
| + kGPU_Backend == config.fBackend) { |
| + continue; |
| + } |
| + |
| + // Now we know that we want to run this test and record its |
| + // success or failure. |
| + ErrorBitfield renderErrors = kEmptyErrorBitfield; |
| + GrRenderTarget* renderTarget = NULL; |
| +#if SK_SUPPORT_GPU |
| + SkAutoTUnref<GrRenderTarget> rt; |
| + AutoResetGr autogr; |
| + if ((kEmptyErrorBitfield == renderErrors) && |
| + kGPU_Backend == config.fBackend) { |
| + GrContext* gr = grFactory->get(config.fGLContextType); |
| + bool grSuccess = false; |
| + if (gr) { |
| + // create a render target to back the device |
| + GrTextureDesc desc; |
| + desc.fConfig = kSkia8888_GrPixelConfig; |
| + desc.fFlags = kRenderTarget_GrTextureFlagBit; |
| + desc.fWidth = gm->getISize().width(); |
| + desc.fHeight = gm->getISize().height(); |
| + desc.fSampleCnt = config.fSampleCnt; |
| + GrTexture* tex = gr->createUncachedTexture(desc, NULL, 0); |
| + if (tex) { |
| + rt.reset(tex->asRenderTarget()); |
| + rt.get()->ref(); |
| + tex->unref(); |
| + autogr.set(gr); |
| + renderTarget = rt.get(); |
| + grSuccess = NULL != renderTarget; |
| + } |
| + // Set the user specified cache limits if non-default. |
| + size_t bytes; |
| + int count; |
| + gr->getTextureCacheLimits(&count, &bytes); |
| + if (-1 != gpuCacheSizeBytes) { |
| + bytes = static_cast<size_t>(gpuCacheSizeBytes); |
| + } |
| + if (-1 != gpuCacheSizeCount) { |
| + count = gpuCacheSizeCount; |
| + } |
| + gr->setTextureCacheLimits(count, bytes); |
| + } |
| + if (!grSuccess) { |
| + renderErrors |= kNoGpuContext_ErrorBitmask; |
| + } |
| + } |
| +#endif |
| + |
| + SkBitmap comparisonBitmap; |
| + |
| + if (kEmptyErrorBitfield == renderErrors) { |
| + renderErrors |= gmmain.test_drawing(gm, config, writePath, |
| + GetGr(), |
| + renderTarget, |
| + &comparisonBitmap); |
| + } |
| + |
| + if (doDeferred && !renderErrors && |
| + (kGPU_Backend == config.fBackend || |
| + kRaster_Backend == config.fBackend)) { |
| + renderErrors |= gmmain.test_deferred_drawing(gm, config, |
| + comparisonBitmap, |
| + GetGr(), |
| + renderTarget); |
| + } |
| + |
| + testErrors |= renderErrors; |
| + } |
| + return testErrors; |
| +} |
| + |
| +/** |
| + * Run this test in a number of different drawing modes (pipe, |
| + * deferred, tiled, etc.), confirming that the resulting bitmaps are |
| + * *exactly* the same in all drawing modes. |
| + * |
| + * TODO(epoger): Right now, we only run the different drawing modes |
| + * with the 8888 config. Would there be value in running all those |
| + * different drawing modes in whatever configs (8888, 565, PDF) we are |
| + * testing? |
| + */ |
| +ErrorBitfield run_multiple_drawing_modes(GMMain &gmmain, GM *gm, |
| + const char *writePicturePath, bool doReplay, |
| + bool doSerialize, bool doRTree, bool doTileGrid, |
| + const SkTDArray<SkScalar> &tileGridReplayScales, |
| + bool doPipe, bool doTiledPipe) { |
| + uint32_t gmFlags = gm->getFlags(); |
| + SkBitmap comparisonBitmap; |
| + const ConfigData compareConfig = |
| + { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType, 0, |
| + kRW_ConfigFlag, "comparison" }; |
| + ErrorBitfield testErrors = gmmain.generate_image(gm, compareConfig, NULL, NULL, |
| + &comparisonBitmap, false); |
| + |
| + // run the picture centric GM steps |
| + if (!(gmFlags & GM::kSkipPicture_Flag)) { |
| + |
| + ErrorBitfield pictErrors = kEmptyErrorBitfield; |
| + |
| + //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); |
| + SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); |
| + SkAutoUnref aur(pict); |
| + |
| + if ((kEmptyErrorBitfield == testErrors) && doReplay) { |
| + SkBitmap bitmap; |
| + gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| + &bitmap); |
| + pictErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| + gm, compareConfig, "-replay", bitmap, &comparisonBitmap); |
| + } |
| + |
| + if ((kEmptyErrorBitfield == testErrors) && |
| + (kEmptyErrorBitfield == pictErrors) && |
| + doSerialize) { |
| + SkPicture* repict = gmmain.stream_to_new_picture(*pict); |
| + SkAutoUnref aurr(repict); |
| + |
| + SkBitmap bitmap; |
| + gmmain.generate_image_from_picture(gm, compareConfig, repict, |
| + &bitmap); |
| + pictErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| + gm, compareConfig, "-serialize", bitmap, &comparisonBitmap); |
| + } |
| + |
| + if (writePicturePath) { |
| + const char* pictureSuffix = "skp"; |
| + SkString path = make_filename(writePicturePath, "", |
| + gm->shortName(), |
| + pictureSuffix); |
| + SkFILEWStream stream(path.c_str()); |
| + pict->serialize(&stream); |
| + } |
| + |
| + testErrors |= pictErrors; |
| + } |
| + |
| + // TODO: add a test in which the RTree rendering results in a |
| + // different bitmap than the standard rendering. It should |
| + // show up as failed in the JSON summary, and should be listed |
| + // in the stdout also. |
| + if (!(gmFlags & GM::kSkipPicture_Flag) && doRTree) { |
| + SkPicture* pict = gmmain.generate_new_picture( |
| + gm, kRTree_BbhType, SkPicture::kUsePathBoundsForClip_RecordingFlag); |
| + SkAutoUnref aur(pict); |
| + SkBitmap bitmap; |
| + gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| + &bitmap); |
| + testErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| + gm, compareConfig, "-rtree", bitmap, &comparisonBitmap); |
| + } |
| + |
| + if (!(gmFlags & GM::kSkipPicture_Flag) && doTileGrid) { |
| + for(int scaleIndex = 0; scaleIndex < tileGridReplayScales.count(); ++scaleIndex) { |
| + SkScalar replayScale = tileGridReplayScales[scaleIndex]; |
| + if ((gmFlags & GM::kSkipScaledReplay_Flag) && replayScale != 1) |
| + continue; |
| + // We record with the reciprocal scale to obtain a replay |
| + // result that can be validated against comparisonBitmap. |
| + SkScalar recordScale = SkScalarInvert(replayScale); |
| + SkPicture* pict = gmmain.generate_new_picture( |
| + gm, kTileGrid_BbhType, SkPicture::kUsePathBoundsForClip_RecordingFlag, |
| + recordScale); |
| + SkAutoUnref aur(pict); |
| + SkBitmap bitmap; |
| + gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| + &bitmap, replayScale); |
| + SkString suffix("-tilegrid"); |
| + if (SK_Scalar1 != replayScale) { |
| + suffix += "-scale-"; |
| + suffix.appendScalar(replayScale); |
| + } |
| + testErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| + gm, compareConfig, suffix.c_str(), bitmap, |
| + &comparisonBitmap); |
| + } |
| + } |
| + |
| + // run the pipe centric GM steps |
| + if (!(gmFlags & GM::kSkipPipe_Flag)) { |
| + |
| + ErrorBitfield pipeErrors = kEmptyErrorBitfield; |
| + |
| + if ((kEmptyErrorBitfield == testErrors) && doPipe) { |
| + pipeErrors |= gmmain.test_pipe_playback(gm, compareConfig, |
| + comparisonBitmap); |
| + } |
| + |
| + if ((kEmptyErrorBitfield == testErrors) && |
| + (kEmptyErrorBitfield == pipeErrors) && |
| + doTiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { |
| + pipeErrors |= gmmain.test_tiled_pipe_playback(gm, compareConfig, |
| + comparisonBitmap); |
| + } |
| + |
| + testErrors |= pipeErrors; |
| + } |
| + return testErrors; |
| +} |
| + |
| int tool_main(int argc, char** argv); |
| int tool_main(int argc, char** argv) { |
| @@ -1180,12 +1413,9 @@ |
| int moduloRemainder = -1; |
| int moduloDivisor = -1; |
| -#if SK_SUPPORT_GPU |
| - struct { |
| - int fBytes; |
| - int fCount; |
| - } gpuCacheSize = { -1, -1 }; // -1s mean use the default |
| -#endif |
| + int gpuCacheSizeBytes = -1; |
| + int gpuCacheSizeCount = -1; |
| + // -1 means use the default |
| const char* const commandName = argv[0]; |
| char* const* stop = argv + argc; |
| @@ -1261,8 +1491,8 @@ |
| #if SK_SUPPORT_GPU |
| } else if (strcmp(*argv, "--gpuCacheSize") == 0) { |
| if (stop - argv > 2) { |
| - gpuCacheSize.fBytes = atoi(*++argv); |
| - gpuCacheSize.fCount = atoi(*++argv); |
| + gpuCacheSizeBytes = atoi(*++argv); |
| + gpuCacheSizeCount = atoi(*++argv); |
| } else { |
| gm_fprintf(stderr, "missing arg for --gpuCacheSize\n"); |
| usage(commandName); |
| @@ -1320,6 +1550,8 @@ |
| doSerialize = true; |
| } else if (strcmp(*argv, "--noserialize") == 0) { |
| doSerialize = false; |
| + } else if (strcmp(*argv, "--simulatePipePlaybackFailure") == 0) { |
| + gmmain.fSimulatePipePlaybackFailure = true; |
| } else if (strcmp(*argv, "--tiledPipe") == 0) { |
| doTiledPipe = true; |
| } else if (!strcmp(*argv, "--verbose") || !strcmp(*argv, "-v")) { |
| @@ -1465,202 +1697,12 @@ |
| size.width(), size.height()); |
| ErrorBitfield testErrors = kEmptyErrorBitfield; |
| - uint32_t gmFlags = gm->getFlags(); |
| + testErrors |= run_multiple_configs(gmmain, gm, configs, grFactory, gpuCacheSizeBytes, |
| + gpuCacheSizeCount, writePath, doPDF, doDeferred); |
| + testErrors |= run_multiple_drawing_modes(gmmain, gm, writePicturePath, doReplay, |
| + doSerialize, doRTree, doTileGrid, |
| + tileGridReplayScales, doPipe, doTiledPipe); |
| - for (int i = 0; i < configs.count(); i++) { |
| - ConfigData config = gRec[configs[i]]; |
| - |
| - // Skip any tests that we don't even need to try. |
| - if ((kPDF_Backend == config.fBackend) && |
| - (!doPDF || (gmFlags & GM::kSkipPDF_Flag))) |
| - { |
| - continue; |
| - } |
| - if ((gmFlags & GM::kSkip565_Flag) && |
| - (kRaster_Backend == config.fBackend) && |
| - (SkBitmap::kRGB_565_Config == config.fConfig)) { |
| - continue; |
| - } |
| - if ((gmFlags & GM::kSkipGPU_Flag) && |
| - kGPU_Backend == config.fBackend) { |
| - continue; |
| - } |
| - |
| - // Now we know that we want to run this test and record its |
| - // success or failure. |
| - ErrorBitfield renderErrors = kEmptyErrorBitfield; |
| - GrRenderTarget* renderTarget = NULL; |
| -#if SK_SUPPORT_GPU |
| - SkAutoTUnref<GrRenderTarget> rt; |
| - AutoResetGr autogr; |
| - if ((kEmptyErrorBitfield == renderErrors) && |
| - kGPU_Backend == config.fBackend) { |
| - GrContext* gr = grFactory->get(config.fGLContextType); |
| - bool grSuccess = false; |
| - if (gr) { |
| - // create a render target to back the device |
| - GrTextureDesc desc; |
| - desc.fConfig = kSkia8888_GrPixelConfig; |
| - desc.fFlags = kRenderTarget_GrTextureFlagBit; |
| - desc.fWidth = gm->getISize().width(); |
| - desc.fHeight = gm->getISize().height(); |
| - desc.fSampleCnt = config.fSampleCnt; |
| - GrTexture* tex = gr->createUncachedTexture(desc, NULL, 0); |
| - if (tex) { |
| - rt.reset(tex->asRenderTarget()); |
| - rt.get()->ref(); |
| - tex->unref(); |
| - autogr.set(gr); |
| - renderTarget = rt.get(); |
| - grSuccess = NULL != renderTarget; |
| - } |
| - // Set the user specified cache limits if non-default. |
| - size_t bytes; |
| - int count; |
| - gr->getTextureCacheLimits(&count, &bytes); |
| - if (-1 != gpuCacheSize.fBytes) { |
| - bytes = static_cast<size_t>(gpuCacheSize.fBytes); |
| - } |
| - if (-1 != gpuCacheSize.fCount) { |
| - count = gpuCacheSize.fCount; |
| - } |
| - gr->setTextureCacheLimits(count, bytes); |
| - } |
| - if (!grSuccess) { |
| - renderErrors |= kNoGpuContext_ErrorBitmask; |
| - } |
| - } |
| -#endif |
| - |
| - SkBitmap comparisonBitmap; |
| - |
| - if (kEmptyErrorBitfield == renderErrors) { |
| - renderErrors |= gmmain.test_drawing(gm, config, writePath, |
| - GetGr(), |
| - renderTarget, |
| - &comparisonBitmap); |
| - } |
| - |
| - if (doDeferred && !renderErrors && |
| - (kGPU_Backend == config.fBackend || |
| - kRaster_Backend == config.fBackend)) { |
| - renderErrors |= gmmain.test_deferred_drawing(gm, config, |
| - comparisonBitmap, |
| - GetGr(), |
| - renderTarget); |
| - } |
| - |
| - testErrors |= renderErrors; |
| - } |
| - |
| - SkBitmap comparisonBitmap; |
| - const ConfigData compareConfig = |
| - { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "comparison" }; |
| - testErrors |= gmmain.generate_image(gm, compareConfig, NULL, NULL, &comparisonBitmap, false); |
| - |
| - // run the picture centric GM steps |
| - if (!(gmFlags & GM::kSkipPicture_Flag)) { |
| - |
| - ErrorBitfield pictErrors = kEmptyErrorBitfield; |
| - |
| - //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); |
| - SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); |
| - SkAutoUnref aur(pict); |
| - |
| - if ((kEmptyErrorBitfield == testErrors) && doReplay) { |
| - SkBitmap bitmap; |
| - gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| - &bitmap); |
| - pictErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| - gm, compareConfig, "-replay", bitmap, &comparisonBitmap); |
| - } |
| - |
| - if ((kEmptyErrorBitfield == testErrors) && |
| - (kEmptyErrorBitfield == pictErrors) && |
| - doSerialize) { |
| - SkPicture* repict = gmmain.stream_to_new_picture(*pict); |
| - SkAutoUnref aurr(repict); |
| - |
| - SkBitmap bitmap; |
| - gmmain.generate_image_from_picture(gm, compareConfig, repict, |
| - &bitmap); |
| - pictErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| - gm, compareConfig, "-serialize", bitmap, &comparisonBitmap); |
| - } |
| - |
| - if (writePicturePath) { |
| - const char* pictureSuffix = "skp"; |
| - SkString path = make_filename(writePicturePath, "", |
| - gm->shortName(), |
| - pictureSuffix); |
| - SkFILEWStream stream(path.c_str()); |
| - pict->serialize(&stream); |
| - } |
| - |
| - testErrors |= pictErrors; |
| - } |
| - |
| - // TODO: add a test in which the RTree rendering results in a |
| - // different bitmap than the standard rendering. It should |
| - // show up as failed in the JSON summary, and should be listed |
| - // in the stdout also. |
| - if (!(gmFlags & GM::kSkipPicture_Flag) && doRTree) { |
| - SkPicture* pict = gmmain.generate_new_picture( |
| - gm, kRTree_BbhType, SkPicture::kUsePathBoundsForClip_RecordingFlag); |
| - SkAutoUnref aur(pict); |
| - SkBitmap bitmap; |
| - gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| - &bitmap); |
| - testErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| - gm, compareConfig, "-rtree", bitmap, &comparisonBitmap); |
| - } |
| - |
| - if (!(gmFlags & GM::kSkipPicture_Flag) && doTileGrid) { |
| - for(int scaleIndex = 0; scaleIndex < tileGridReplayScales.count(); ++scaleIndex) { |
| - SkScalar replayScale = tileGridReplayScales[scaleIndex]; |
| - if ((gmFlags & GM::kSkipScaledReplay_Flag) && replayScale != 1) |
| - continue; |
| - // We record with the reciprocal scale to obtain a replay |
| - // result that can be validated against comparisonBitmap. |
| - SkScalar recordScale = SkScalarInvert(replayScale); |
| - SkPicture* pict = gmmain.generate_new_picture( |
| - gm, kTileGrid_BbhType, SkPicture::kUsePathBoundsForClip_RecordingFlag, |
| - recordScale); |
| - SkAutoUnref aur(pict); |
| - SkBitmap bitmap; |
| - gmmain.generate_image_from_picture(gm, compareConfig, pict, |
| - &bitmap, replayScale); |
| - SkString suffix("-tilegrid"); |
| - if (SK_Scalar1 != replayScale) { |
| - suffix += "-scale-"; |
| - suffix.appendScalar(replayScale); |
| - } |
| - testErrors |= gmmain.compare_test_results_to_reference_bitmap( |
| - gm, compareConfig, suffix.c_str(), bitmap, |
| - &comparisonBitmap); |
| - } |
| - } |
| - |
| - // run the pipe centric GM steps |
| - if (!(gmFlags & GM::kSkipPipe_Flag)) { |
| - |
| - ErrorBitfield pipeErrors = kEmptyErrorBitfield; |
| - |
| - if ((kEmptyErrorBitfield == testErrors) && doPipe) { |
| - pipeErrors |= gmmain.test_pipe_playback(gm, compareConfig, |
| - comparisonBitmap); |
| - } |
| - |
| - if ((kEmptyErrorBitfield == testErrors) && |
| - (kEmptyErrorBitfield == pipeErrors) && |
| - doTiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { |
| - pipeErrors |= gmmain.test_tiled_pipe_playback(gm, compareConfig, |
| - comparisonBitmap); |
| - } |
| - |
| - testErrors |= pipeErrors; |
| - } |
| - |
| // Update overall results. |
| // We only tabulate the particular error types that we currently |
| // care about (e.g., missing reference images). Later on, if we |