'<(skia_include_path)/private/SkMiniRecorder.h',
'<(skia_include_path)/private/SkMutex.h',
'<(skia_include_path)/private/SkOnce.h',
+ '<(skia_include_path)/private/SkOncePtr.h',
'<(skia_include_path)/private/SkRecords.h',
'<(skia_include_path)/private/SkSemaphore.h',
'<(skia_include_path)/private/SkSpinlock.h',
--- /dev/null
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkOncePtr_DEFINED
+#define SkOncePtr_DEFINED
+
+#include "../private/SkAtomics.h"
+#include <memory>
+
+// Use this to create a global static pointer that's intialized exactly once when you call get().
+#define SK_DECLARE_STATIC_ONCE_PTR(type, name) namespace {} static SkBaseOncePtr<type> name;
+
+template <typename T>
+class SkBaseOncePtr {
+public:
+ template <typename F>
+ T* get(const F& f) const {
+ uintptr_t state = sk_atomic_load(&fState, sk_memory_order_acquire);
+ if (state < 2) {
+ if (state == 0) {
+ // It looks like no one has tried to create our pointer yet.
+ // We try to claim that task by atomically swapping our state from '0' to '1'.
+ // See SkOnce.h for why we use an acquire memory order here rather than relaxed.
+ if (sk_atomic_compare_exchange(
+ &fState, &state, (uintptr_t)1, sk_memory_order_acquire, sk_memory_order_acquire)) {
+ // We've claimed it. Create our pointer and store it into fState.
+ state = (uintptr_t)f();
+ SkASSERT(state > 1);
+ sk_atomic_store(&fState, state, sk_memory_order_release);
+ } else {
+ // Someone else claimed it.
+ // We fall through to the spin loop just below to wait for them to finish.
+ }
+ }
+
+ while (state == 1) {
+ // State '1' is our busy-but-not-done state.
+ // Some other thread has claimed the job of creating our pointer.
+ // We just need to wait for it to finish.
+ state = sk_atomic_load(&fState, sk_memory_order_acquire);
+ }
+
+ // We shouldn't be able to get here without having created our pointer.
+ SkASSERT(state > 1);
+ }
+ return (T*)state;
+ }
+
+ operator T*() const {
+ auto state = sk_atomic_load(&fState, sk_memory_order_acquire);
+ return state < 2 ? nullptr : (T*)state;
+ // TODO: If state == 1 spin until it's not?
+ }
+
+ // fState == 0 --> we have not created our ptr yet
+ // fState == 1 --> someone is in the middle of creating our ptr
+ // else --> (T*)fState is our ptr
+ mutable uintptr_t fState;
+};
+
+#endif//SkOncePtr_DEFINED
#include "SkAtomics.h"
#include "SkColorSpace.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
static bool color_space_almost_equal(float a, float b) {
return SkTAbs(a - b) < 0.01f;
0.1430f, 0.0606f, 0.7139f, // * B
};
+SK_DECLARE_STATIC_ONCE_PTR(SkColorSpace, sRGB);
+
sk_sp<SkColorSpace> SkColorSpace::NewRGB(SkGammas gammas, const SkMatrix44& toXYZD50) {
// Check if we really have sRGB
if (color_space_almost_equal(2.2f, gammas.fRed.fValue) &&
}
sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) {
- static SkOnce once;
- static SkColorSpace* sRGB;
-
switch (named) {
case kSRGB_Named: {
- once([] {
- SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
- srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50);
- sRGB = new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50, kSRGB_Named);
- });
- return sk_ref_sp(sRGB);
+ SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
+ srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50);
+ return sk_ref_sp(sRGB.get([=]{
+ return new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50, kSRGB_Named);
+ }));
}
default:
break;
#include "SkData.h"
#include "SkOSFile.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkReadBuffer.h"
#include "SkStream.h"
#include "SkWriteBuffer.h"
///////////////////////////////////////////////////////////////////////////////
+SK_DECLARE_STATIC_ONCE_PTR(SkData, gEmpty);
sk_sp<SkData> SkData::MakeEmpty() {
- static SkOnce once;
- static SkData* empty;
-
- once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); });
- return sk_ref_sp(empty);
+ SkData* data = SkRef(gEmpty.get([]{return new SkData(nullptr, 0, nullptr, nullptr); }));
+ return sk_sp<SkData>(data);
}
// assumes fPtr was allocated via sk_malloc
#include "SkFontDescriptor.h"
#include "SkFontMgr.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkStream.h"
#include "SkTypes.h"
return this->onLegacyCreateTypeface(familyName, style);
}
+SK_DECLARE_STATIC_ONCE_PTR(SkFontMgr, singleton);
SkFontMgr* SkFontMgr::RefDefault() {
- static SkOnce once;
- static SkFontMgr* singleton;
-
- once([]{
+ return SkRef(singleton.get([]{
SkFontMgr* fm = SkFontMgr::Factory();
- singleton = fm ? fm : new SkEmptyFontMgr;
- });
- return SkRef(singleton);
+ return fm ? fm : new SkEmptyFontMgr;
+ }));
}
/**
#include "SkGlyphCache.h"
#include "SkGlyphCache_Globals.h"
#include "SkGraphics.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkPath.h"
#include "SkTemplates.h"
#include "SkTraceMemoryDump.h"
} // namespace
// Returns the shared globals
+SK_DECLARE_STATIC_ONCE_PTR(SkGlyphCache_Globals, globals);
static SkGlyphCache_Globals& get_globals() {
- static SkOnce once;
- static SkGlyphCache_Globals* globals;
-
- once([]{ globals = new SkGlyphCache_Globals; });
- return *globals;
+ return *globals.get([]{ return new SkGlyphCache_Globals; });
}
///////////////////////////////////////////////////////////////////////////////
#include "SkChecksum.h"
#include "SkMutex.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkRefCnt.h"
#include "SkSpecialImage.h"
#include "SkTDynamicHash.h"
return new CacheImpl(maxBytes);
}
+SK_DECLARE_STATIC_ONCE_PTR(SkImageFilterCache, cache);
SkImageFilterCache* SkImageFilterCache::Get() {
- static SkOnce once;
- static SkImageFilterCache* cache;
-
- once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); });
- return cache;
+ return cache.get([]{ return SkImageFilterCache::Create(kDefaultCacheSize); });
}
#define SkMessageBus_DEFINED
#include "SkMutex.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkTArray.h"
#include "SkTDArray.h"
#include "SkTypes.h"
// This must go in a single .cpp file, not some .h, or we risk creating more than one global
// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
+ SK_DECLARE_STATIC_ONCE_PTR(SkMessageBus<Message>, bus); \
template <> \
SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
- static SkOnce once; \
- static SkMessageBus<Message>* bus; \
- once([] { bus = new SkMessageBus<Message>(); }); \
- return bus; \
+ return bus.get([]{ return new SkMessageBus<Message>(); }); \
}
// ----------------------- Implementation of SkMessageBus::Inbox -----------------------
#include "SkCanvas.h"
#include "SkTLazy.h"
#include "SkMiniRecorder.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkPicture.h"
#include "SkPictureCommon.h"
#include "SkRecordDraw.h"
int numSlowPaths() const override { return 0; }
bool willPlayBackBitmaps() const override { return false; }
};
+SK_DECLARE_STATIC_ONCE_PTR(SkEmptyPicture, gEmptyPicture);
template <typename T>
class SkMiniPicture final : public SkPicture {
fState = State::kEmpty; \
return sk_make_sp<SkMiniPicture<Type>>(cull, reinterpret_cast<Type*>(fBuffer.get()))
- static SkOnce once;
- static SkPicture* empty;
-
switch (fState) {
- case State::kEmpty:
- once([]{ empty = new SkEmptyPicture; });
- return sk_ref_sp(empty);
+ case State::kEmpty: return sk_ref_sp(gEmptyPicture.get([]{ return new SkEmptyPicture; }));
CASE(DrawBitmapRectFixedSize);
CASE(DrawPath);
CASE(DrawRect);
*/
#include "SkBuffer.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkPath.h"
#include "SkPathRef.h"
#include <limits>
SkDEBUGCODE(fEditorsAttached = 0x7777777;)
}
-static SkPathRef* gEmpty = nullptr;
-
+SK_DECLARE_STATIC_ONCE_PTR(SkPathRef, empty);
SkPathRef* SkPathRef::CreateEmpty() {
- static SkOnce once;
- once([]{
- gEmpty = new SkPathRef;
- gEmpty->computeBounds(); // Avoids races later to be the first to do this.
- });
- return SkRef(gEmpty);
+ return SkRef(empty.get([]{
+ SkPathRef* pr = new SkPathRef;
+ pr->computeBounds(); // Avoids races later to be the first to do this.
+ return pr;
+ }));
}
void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
}
void SkPathRef::addGenIDChangeListener(GenIDChangeListener* listener) {
- if (nullptr == listener || this == gEmpty) {
+ if (nullptr == listener || this == (SkPathRef*)empty) {
delete listener;
return;
}
#include "SkThreadUtils.h"
#if defined(SK_BUILD_FOR_WIN32)
- static void query_num_cores(int* cores) {
+ static void query_num_cores(int* num_cores) {
SYSTEM_INFO sysinfo;
GetNativeSystemInfo(&sysinfo);
- *cores = sysinfo.dwNumberOfProcessors;
+ *num_cores = sysinfo.dwNumberOfProcessors;
}
#else
#include <unistd.h>
- static void query_num_cores(int* cores) {
- *cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ static void query_num_cores(int* num_cores) {
+ *num_cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
}
#endif
-static int num_cores() {
- // We cache num_cores() so we only query the OS once.
- static int cores = 0;
+int sk_num_cores() {
+ // We cache sk_num_cores() so we only query the OS once.
+ static int num_cores = 0;
static SkOnce once;
- once(query_num_cores, &cores);
- SkASSERT(cores > 0);
- return cores;
+ once(query_num_cores, &num_cores);
+ SkASSERT(num_cores > 0);
+ return num_cores;
}
namespace {
explicit ThreadPool(int threads) {
if (threads == -1) {
- threads = num_cores();
+ threads = sk_num_cores();
}
for (int i = 0; i < threads; i++) {
fThreads.push(new SkThread(&ThreadPool::Loop, this));
SkAtomic<int32_t> fPending;
};
+// Returns best estimate of number of CPU cores available to use.
+int sk_num_cores();
+
#endif//SkTaskGroup_DEFINED
#include "SkFontMgr.h"
#include "SkMutex.h"
#include "SkOTTable_OS_2.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkStream.h"
#include "SkTypeface.h"
}
SK_DECLARE_STATIC_MUTEX(gCreateDefaultMutex);
+SK_DECLARE_STATIC_ONCE_PTR(SkTypeface, defaults[4]);
SkTypeface* SkTypeface::GetDefaultTypeface(Style style) {
- static SkOnce once[4];
- static SkTypeface* defaults[4];
-
SkASSERT((int)style < 4);
- once[style]([style] {
+ return defaults[style].get([=]{
// It is not safe to call FontConfigTypeface::LegacyCreateTypeface concurrently.
// To be safe, we serialize here with a mutex so only one call to
// CreateTypeface is happening at any given time.
// TODO(bungeman, mtklein): This is sad. Make our fontconfig code safe?
SkAutoMutexAcquire lock(&gCreateDefaultMutex);
+
SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
SkTypeface* t = fm->legacyCreateTypeface(nullptr, SkFontStyle::FromOldStyle(style));
- defaults[style] = t ? t : SkEmptyTypeface::Create();
+ return t ? t : SkEmptyTypeface::Create();
});
- return defaults[style];
}
SkTypeface* SkTypeface::RefDefault(Style style) {
#include "SkXfermode_proccoeff.h"
#include "SkColorPriv.h"
#include "SkMathPriv.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkOpts.h"
#include "SkReadBuffer.h"
#include "SkString.h"
#endif
+SK_DECLARE_STATIC_ONCE_PTR(SkXfermode, cached[SkXfermode::kLastMode + 1]);
+
sk_sp<SkXfermode> SkXfermode::Make(Mode mode) {
+ SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
+
if ((unsigned)mode >= kModeCount) {
// report error
return nullptr;
return nullptr;
}
- SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
-
- static SkOnce once[SkXfermode::kLastMode+1];
- static SkXfermode* cached[SkXfermode::kLastMode+1];
-
- once[mode]([mode] {
+ return sk_ref_sp(cached[mode].get([=]{
ProcCoeff rec = gProcCoeffs[mode];
if (auto xfermode = SkOpts::create_xfermode(rec, mode)) {
- cached[mode] = xfermode;
- } else {
- cached[mode] = new SkProcCoeffXfermode(rec, mode);
+ return xfermode;
}
- });
- return sk_ref_sp(cached[mode]);
+ return (SkXfermode*) new SkProcCoeffXfermode(rec, mode);
+ }));
}
SkXfermodeProc SkXfermode::GetProc(Mode mode) {
* found in the LICENSE file.
*/
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkRemotableFontMgr.h"
SkRemotableFontIdentitySet::SkRemotableFontIdentitySet(int count, SkFontIdentity** data)
*data = fData;
}
+SK_DECLARE_STATIC_ONCE_PTR(SkRemotableFontIdentitySet, empty);
SkRemotableFontIdentitySet* SkRemotableFontIdentitySet::NewEmpty() {
- static SkOnce once;
- static SkRemotableFontIdentitySet* empty;
- once([]{ empty = new SkRemotableFontIdentitySet; });
- return SkRef(empty);
+ return SkRef(empty.get([]{ return new SkRemotableFontIdentitySet; }));
}
#include "SkDiscardableMemoryPool.h"
#include "SkImageGenerator.h"
#include "SkMutex.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkTInternalLList.h"
// Note:
}
SK_DECLARE_STATIC_MUTEX(gMutex);
+SK_DECLARE_STATIC_ONCE_PTR(SkDiscardableMemoryPool, global);
SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
- static SkOnce once;
- static SkDiscardableMemoryPool* global;
- once([]{
- global = SkDiscardableMemoryPool::Create(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
- &gMutex);
+ return global.get([] {
+ return SkDiscardableMemoryPool::Create(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
+ &gMutex);
});
- return global;
}
#include "SkBlitRow.h"
#include "SkBlitRow_opts_SSE2.h"
#include "SkCpu.h"
+#include "SkOncePtr.h"
#include "SkRTConf.h"
#include "SkOTTable_hhea.h"
#include "SkOTTable_loca.h"
#include "SkOTUtils.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkSFNTHeader.h"
return &legacy_CTFontDrawGlyphs;
}
+SK_DECLARE_STATIC_ONCE_PTR(CTFontDrawGlyphsProc, gCTFontDrawGlyphs);
+
CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
CGGlyph glyphID, size_t* rowBytesPtr,
bool generateA8FromLCD) {
- static SkOnce once;
- static CTFontDrawGlyphsProc* ctFontDrawGlyphs;
- once([]{ ctFontDrawGlyphs = choose_CTFontDrawGlyphs(); });
+ auto ctFontDrawGlyphs = gCTFontDrawGlyphs.get(choose_CTFontDrawGlyphs);
if (!fRGBSpace) {
//It doesn't appear to matter what color space is specified.
#include "SkAtomics.h"
#include "SkEventTracer.h"
-#include "SkOnce.h"
+#include "SkOncePtr.h"
#include <stdlib.h>
}
};
-// We prefer gUserTracer if it's been set, otherwise we fall back on a default tracer;
+// We prefer gUserTracer if it's been set, otherwise we fall back on gDefaultTracer.
static SkEventTracer* gUserTracer = nullptr;
+SK_DECLARE_STATIC_ONCE_PTR(SkDefaultEventTracer, gDefaultTracer);
void SkEventTracer::SetInstance(SkEventTracer* tracer) {
SkASSERT(nullptr == sk_atomic_load(&gUserTracer, sk_memory_order_acquire));
if (SkEventTracer* tracer = sk_atomic_load(&gUserTracer, sk_memory_order_acquire)) {
return tracer;
}
- static SkOnce once;
- static SkDefaultEventTracer* defaultTracer;
- once([] { defaultTracer = new SkDefaultEventTracer; });
- return defaultTracer;
+ return gDefaultTracer.get([]{ return new SkDefaultEventTracer; });
}
--- /dev/null
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkOncePtr.h"
+#include "SkTaskGroup.h"
+
+SK_DECLARE_STATIC_ONCE_PTR(int, once);
+
+DEF_TEST(OncePtr, r) {
+ static SkAtomic<int> calls(0);
+ auto create = [&] {
+ calls.fetch_add(1);
+ return new int(5);
+ };
+
+ SkTaskGroup().batch(sk_num_cores()*4, [&](size_t) {
+ int* n = once.get(create);
+ REPORTER_ASSERT(r, *n == 5);
+ });
+ REPORTER_ASSERT(r, calls.load() == 1);
+}