Optionally run RAW images serially

RAW images use a lot of memory. Add a new FLAG to run one at a time so
we have less risk of running out of memory.

Isolate RAW images to their own thread on particular devices where our
images cause OOM errors.

Locally, this drops the max memory use from 3945 MB to 1664 MB (running only --image --images <RAW images we test>)

BUG=skia:4912
BUG=skia:4878
BUG=b/27035849
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1681553003

Review URL: https://codereview.chromium.org/1681553003
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 30cdbf0..dd994b6 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -38,6 +38,7 @@
 
 DEFINE_bool(multiPage, false, "For document-type backends, render the source"
             " into multiple pages");
+DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
 
 static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) {
     SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size));
@@ -238,6 +239,25 @@
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
+static bool serial_from_path_name(const SkString& path) {
+    if (!FLAGS_RAW_threading) {
+        static const char* const exts[] = {
+            "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
+            "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
+        };
+        const char* actualExt = strrchr(path.c_str(), '.');
+        if (actualExt) {
+            actualExt++;
+            for (auto* ext : exts) {
+                if (0 == strcmp(ext, actualExt)) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
                    float scale)
     : fPath(path)
@@ -245,6 +265,7 @@
     , fDstColorType(dstColorType)
     , fDstAlphaType(dstAlphaType)
     , fScale(scale)
+    , fRunSerially(serial_from_path_name(path))
 {}
 
 bool CodecSrc::veto(SinkFlags flags) const {
@@ -612,6 +633,7 @@
     , fDstColorType(dstColorType)
     , fDstAlphaType(dstAlphaType)
     , fSampleSize(sampleSize)
+    , fRunSerially(serial_from_path_name(path))
 {}
 
 bool AndroidCodecSrc::veto(SinkFlags flags) const {
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 64897d2..a987c7d 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -124,12 +124,14 @@
     SkISize size() const override;
     Name name() const override;
     bool veto(SinkFlags) const override;
+    bool serial() const override { return fRunSerially; }
 private:
     Path                    fPath;
     Mode                    fMode;
     DstColorType            fDstColorType;
     SkAlphaType             fDstAlphaType;
     float                   fScale;
+    bool                    fRunSerially;
 };
 
 class AndroidCodecSrc : public Src {
@@ -147,12 +149,14 @@
     SkISize size() const override;
     Name name() const override;
     bool veto(SinkFlags) const override;
+    bool serial() const override { return fRunSerially; }
 private:
     Path                    fPath;
     Mode                    fMode;
     CodecSrc::DstColorType  fDstColorType;
     SkAlphaType             fDstAlphaType;
     int                     fSampleSize;
+    bool                    fRunSerially;
 };
 
 // Allows for testing of various implementations of Android's BitmapRegionDecoder
diff --git a/tools/dm_flags.json b/tools/dm_flags.json
index e6e8fc5..67e5845 100644
--- a/tools/dm_flags.json
+++ b/tools/dm_flags.json
@@ -1631,7 +1631,8 @@
     "_", 
     "image", 
     "_", 
-    ".SRW"
+    ".SRW", 
+    "--noRAW_threading"
   ], 
   "Test-Android-GCC-NexusPlayer-CPU-SSSE3-x86-Release": [
     "--pre_log", 
@@ -1840,88 +1841,9 @@
     "gm", 
     "_", 
     "image-cacherator-from-ctable", 
-    "_", 
-    "image", 
-    "_", 
-    ".arw", 
-    "_", 
-    "image", 
-    "_", 
-    ".cr2", 
-    "_", 
-    "image", 
-    "_", 
-    ".dng", 
-    "_", 
-    "image", 
-    "_", 
-    ".nef", 
-    "_", 
-    "image", 
-    "_", 
-    ".nrw", 
-    "_", 
-    "image", 
-    "_", 
-    ".orf", 
-    "_", 
-    "image", 
-    "_", 
-    ".raf", 
-    "_", 
-    "image", 
-    "_", 
-    ".rw2", 
-    "_", 
-    "image", 
-    "_", 
-    ".pef", 
-    "_", 
-    "image", 
-    "_", 
-    ".srw", 
-    "_", 
-    "image", 
-    "_", 
-    ".ARW", 
-    "_", 
-    "image", 
-    "_", 
-    ".CR2", 
-    "_", 
-    "image", 
-    "_", 
-    ".DNG", 
-    "_", 
-    "image", 
-    "_", 
-    ".NEF", 
-    "_", 
-    "image", 
-    "_", 
-    ".NRW", 
-    "_", 
-    "image", 
-    "_", 
-    ".ORF", 
-    "_", 
-    "image", 
-    "_", 
-    ".RAF", 
-    "_", 
-    "image", 
-    "_", 
-    ".RW2", 
-    "_", 
-    "image", 
-    "_", 
-    ".PEF", 
-    "_", 
-    "image", 
-    "_", 
-    ".SRW", 
     "--match", 
-    "~ResourceCache"
+    "~ResourceCache", 
+    "--noRAW_threading"
   ], 
   "Test-Mac10.8-Clang-MacMini4.1-CPU-SSE4-x86_64-Release": [
     "--pre_log", 
diff --git a/tools/dm_flags.py b/tools/dm_flags.py
index e9d5d64..5542e4f 100755
--- a/tools/dm_flags.py
+++ b/tools/dm_flags.py
@@ -155,14 +155,10 @@
     blacklist.extend([   '2ndpic-8888', 'gm', '_', test])
     blacklist.extend(['serialize-8888', 'gm', '_', test])
 
+  # Extensions for RAW images
   r = ["arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
        "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW"]
 
-  # NexusPlayer runs out of memory running RAW codec tests
-  if 'NexusPlayer' in bot:
-    for raw_ext in r:
-      blacklist.extend(('_ image _ .%s' % raw_ext).split(' '))
-
   # skbug.com/4888
   # Blacklist RAW images on GPU tests until we can resolve failures
   if 'GPU' in bot:
@@ -206,6 +202,11 @@
     args.append('--match')
     args.extend(match)
 
+  # These bots run out of memory running RAW codec tests. Do not run them in
+  # parallel
+  if 'NexusPlayer' in bot or 'Nexus5' in bot or 'Nexus9' in bot:
+    args.append('--noRAW_threading')
+
   return args
 cov_end = lineno()   # Don't care about code coverage past here.