blob: fe8a5a89befa406bcab2fe248c4be4f6e9ce06bd [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTaskGroup2D.h"
void SkTaskGroup2D::start() {
fThreadsGroup->batch(fThreadCnt, [this](int threadId){
this->work(threadId);
});
}
void SkTaskGroup2D::addColumn() {
SkASSERT(!fIsFinishing); // we're not supposed to add more work after the calling of finish
fWidth++;
}
void SkTaskGroup2D::finish() {
fIsFinishing.store(true, std::memory_order_relaxed);
fThreadsGroup->wait();
}
void SkSpinningTaskGroup2D::work(int threadId) {
int& nextColumn = fRowData[threadId].fNextColumn;
while (true) {
SkASSERT(nextColumn <= fWidth);
if (this->isFinishing() && nextColumn >= fWidth) {
return;
}
if (nextColumn < fWidth) {
fWork(threadId, nextColumn);
nextColumn++;
}
}
}
SkFlexibleTaskGroup2D::SkFlexibleTaskGroup2D(Work2D&& w, int h, SkExecutor* x, int t)
: SkTaskGroup2D(std::move(w), h, x, t), fRowData(h), fThreadData(t) {
for (int i = 0; i < t; ++i) {
fThreadData[i].fRowIndex = i;
}
}
void SkFlexibleTaskGroup2D::work(int threadId) {
int failCnt = 0;
int& rowIndex = fThreadData[threadId].fRowIndex;
// This loop looks for work to do as long as
// either 1. isFinishing is false
// or 2. isFinishing is true but some rows still have unfinished tasks
while (true) {
RowData& rowData = fRowData[rowIndex];
bool processed = false;
// The Android roller somehow gets a false-positive compile warning/error about the try-lock
// and unlock process. Hence we disable -Wthread-safety-analysis to bypass it.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
#endif
if (rowData.fMutex.try_lock()) {
if (rowData.fNextColumn < fWidth) {
fWork(rowIndex, rowData.fNextColumn);
rowData.fNextColumn++;
processed = true;
} else {
// isFinishing can never go from true to false. Once it's true, we count how many
// times that a row is out of work. If that count reaches fHeight, then we're out of
// work for the whole group.
failCnt += this->isFinishing();
}
rowData.fMutex.unlock();
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
if (!processed) {
if (failCnt >= fHeight) {
return;
}
rowIndex = (rowIndex + 1) % fHeight;
}
}
}