diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBlitter.cpp | 6 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 12 | ||||
-rw-r--r-- | src/core/SkThreadedBMPDevice.cpp | 2 | ||||
-rw-r--r-- | src/core/SkThreadedBMPDevice.h | 21 |
4 files changed, 30 insertions, 11 deletions
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 7a3e904e09..24494c1e71 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -92,7 +92,11 @@ void SkBlitter::blitCoverageDeltas(SkCoverageDeltaList* deltas, const SkIRect& c bool canUseMask = !deltas->forceRLE() && SkCoverageDeltaMask::CanHandle(SkIRect::MakeLTRB(0, 0, clip.width(), 1)); const SkAntiRect& antiRect = deltas->getAntiRect(); - for(int y = deltas->top(); y < deltas->bottom(); ++y) { + + // Only access rows within our clip. Otherwise, we'll have data race in the threaded backend. + int top = SkTMax(deltas->top(), clip.fTop); + int bottom = SkTMin(deltas->bottom(), clip.fBottom); + for(int y = top; y < bottom; ++y) { // If antiRect is non-empty and we're at its top row, blit it and skip to the bottom if (antiRect.fHeight && y == antiRect.fY) { this->blitAntiRect(antiRect.fX, antiRect.fY, antiRect.fWidth, antiRect.fHeight, diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 478617f828..4b847db295 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1019,7 +1019,7 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC if (iData == nullptr) { proc(devPath, *fRC, blitter); // proceed directly if we're not in threaded init-once - } else if (true || !doFill || !paint.isAntiAlias()) { + } else if (!doFill || !paint.isAntiAlias()) { // TODO remove true in the if statement above so we can proceed to DAA. // We're in threaded init-once but we can't use DAA. Hence we'll stop here and hand all the @@ -1033,7 +1033,15 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC }); } else { // We can use DAA to do scan conversion in the init-once phase. - // TODO To be implemented + SkDAARecord* record = iData->fAlloc->make<SkDAARecord>(iData->fAlloc); + SkNullBlitter nullBlitter; // We don't want to blit anything during the init phase + SkScan::AntiFillPath(devPath, *fRC, &nullBlitter, record); + iData->fElement->setDrawFn([record, devPath, blitter](SkArenaAlloc* alloc, + const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) { + SkASSERT(record->fType != SkDAARecord::Type::kToBeComputed); + SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds); + SkScan::AntiFillPath(devPath, *tileDraw.fRC, blitter, record); + }); } } diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp index ad3814ca72..7c1394d351 100644 --- a/src/core/SkThreadedBMPDevice.cpp +++ b/src/core/SkThreadedBMPDevice.cpp @@ -156,7 +156,7 @@ void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { SkRect drawBounds = path.isInverseFillType() ? SkRectPriv::MakeLargest() : get_fast_bounds(path.getBounds(), paint); - if (path.countVerbs() < 100) { // when path is small, init-once has too much overhead + if (path.countVerbs() < 4) { // when path is small, init-once has too much overhead fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds) { TileDraw(ds, tileBounds).drawPath(path, paint, prePathMatrix, false); }); diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h index a33715e340..c2e1aa375d 100644 --- a/src/core/SkThreadedBMPDevice.h +++ b/src/core/SkThreadedBMPDevice.h @@ -74,19 +74,26 @@ private: , fDrawBounds(device->transformDrawBounds(rawDrawBounds)) {} DrawElement(SkThreadedBMPDevice* device, InitFn&& initFn, const SkRect& rawDrawBounds) : fInitialized(false) + , fNeedInit(true) , fInitFn(std::move(initFn)) , fDS(device) , fDrawBounds(device->transformDrawBounds(rawDrawBounds)) {} SK_ALWAYS_INLINE bool tryInitOnce(SkArenaAlloc* alloc) { - if (fInitialized) { - return false; - } - std::call_once(fNeedInit, [this, alloc]{ + bool t = true; + // If there are multiple threads reaching this point simutaneously, + // compare_exchange_strong ensures that only one thread can enter the if condition and + // do the initialization. + if (!fInitialized && fNeedInit && fNeedInit.compare_exchange_strong(t, false)) { +#ifdef SK_DEBUG + fDrawFn = 0; // Invalidate fDrawFn +#endif fInitFn(alloc, this); fInitialized = true; - }); - return true; + SkASSERT(fDrawFn != 0); // Ensure that fInitFn does populate fDrawFn + return true; + } + return false; } SK_ALWAYS_INLINE bool tryDraw(const SkIRect& tileBounds, SkArenaAlloc* alloc) { @@ -105,7 +112,7 @@ private: private: std::atomic<bool> fInitialized; - std::once_flag fNeedInit; + std::atomic<bool> fNeedInit; InitFn fInitFn; DrawFn fDrawFn; DrawState fDS; |