SkOnce for SkXfermode::Create(Mode)
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 28 Mar 2014 20:04:11 +0000 (20:04 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 28 Mar 2014 20:04:11 +0000 (20:04 +0000)
This removes the mutex from the fast path when we've already cached it.

BUG=skia:
R=reed@google.com, bungeman@google.com, mtklein@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/215533002

git-svn-id: http://skia.googlecode.com/svn/trunk@13986 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkXfermode.cpp

index 9b66a66..674078e 100644 (file)
 #include "SkXfermode.h"
 #include "SkXfermode_proccoeff.h"
 #include "SkColorPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
 #include "SkMathPriv.h"
+#include "SkOnce.h"
+#include "SkReadBuffer.h"
 #include "SkString.h"
 #include "SkUtilsArm.h"
+#include "SkWriteBuffer.h"
 
 #if !SK_ARM_NEON_IS_NONE
 #include "SkXfermode_opts_arm_neon.h"
@@ -1671,7 +1672,8 @@ void SkDstOutXfermode::toString(SkString* str) const {
 ///////////////////////////////////////////////////////////////////////////////
 
 SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
-static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];
+static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];  // All NULL to start.
+static bool gXfermodeCached[SK_ARRAY_COUNT(gCachedXfermodes)];  // All false to start.
 
 void SkXfermode::Term() {
     SkAutoMutexAcquire ac(gCachedXfermodesMutex);
@@ -1686,6 +1688,50 @@ extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
                                                       SkXfermode::Mode mode);
 extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
 
+
+static void create_mode(SkXfermode::Mode mode) {
+    SkASSERT(NULL == gCachedXfermodes[mode]);
+
+    ProcCoeff rec = gProcCoeffs[mode];
+    SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
+    if (pp != NULL) {
+        rec.fProc = pp;
+    }
+
+    SkXfermode* xfer = NULL;
+    // check if we have a platform optim for that
+    SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
+    if (xfm != NULL) {
+        xfer = xfm;
+    } else {
+        // All modes can in theory be represented by the ProcCoeff rec, since
+        // it contains function ptrs. However, a few modes are both simple and
+        // commonly used, so we call those out for their own subclasses here.
+        switch (mode) {
+            case SkXfermode::kClear_Mode:
+                xfer = SkClearXfermode::Create(rec);
+                break;
+            case SkXfermode::kSrc_Mode:
+                xfer = SkSrcXfermode::Create(rec);
+                break;
+            case SkXfermode::kSrcOver_Mode:
+                SkASSERT(false);    // should not land here
+                break;
+            case SkXfermode::kDstIn_Mode:
+                xfer = SkDstInXfermode::Create(rec);
+                break;
+            case SkXfermode::kDstOut_Mode:
+                xfer = SkDstOutXfermode::Create(rec);
+                break;
+            default:
+                // no special-case, just rely in the rec and its function-ptrs
+                xfer = SkProcCoeffXfermode::Create(rec, mode);
+                break;
+        }
+    }
+    gCachedXfermodes[mode] = xfer;
+}
+
 SkXfermode* SkXfermode::Create(Mode mode) {
     SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
     SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
@@ -1701,51 +1747,9 @@ SkXfermode* SkXfermode::Create(Mode mode) {
         return NULL;
     }
 
-    // guard our access to gCachedXfermodes, since we may write into it
-    SkAutoMutexAcquire ac(gCachedXfermodesMutex);
-
+    SkOnce(&gXfermodeCached[mode], &gCachedXfermodesMutex, create_mode, mode);
     SkXfermode* xfer = gCachedXfermodes[mode];
-    if (NULL == xfer) {
-        ProcCoeff rec = gProcCoeffs[mode];
-
-        SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
-
-        if (pp != NULL) {
-            rec.fProc = pp;
-        }
-
-        // check if we have a platform optim for that
-        SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
-        if (xfm != NULL) {
-            xfer = xfm;
-        } else {
-            // All modes can in theory be represented by the ProcCoeff rec, since
-            // it contains function ptrs. However, a few modes are both simple and
-            // commonly used, so we call those out for their own subclasses here.
-            switch (mode) {
-                case kClear_Mode:
-                    xfer = SkClearXfermode::Create(rec);
-                    break;
-                case kSrc_Mode:
-                    xfer = SkSrcXfermode::Create(rec);
-                    break;
-                case kSrcOver_Mode:
-                    SkASSERT(false);    // should not land here
-                    break;
-                case kDstIn_Mode:
-                    xfer = SkDstInXfermode::Create(rec);
-                    break;
-                case kDstOut_Mode:
-                    xfer = SkDstOutXfermode::Create(rec);
-                    break;
-                default:
-                    // no special-case, just rely in the rec and its function-ptrs
-                    xfer = SkProcCoeffXfermode::Create(rec, mode);
-                    break;
-            }
-        }
-        gCachedXfermodes[mode] = xfer;
-    }
+    SkASSERT(xfer != NULL);
     return SkSafeRef(xfer);
 }