1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTaskGroup2D.h" 9 10 void SkTaskGroup2D::start() { 11 fThreadsGroup->batch(fThreadCnt, [this](int threadId){ 12 this->work(threadId); 13 }); 14 } 15 16 void SkTaskGroup2D::addColumn() { 17 SkASSERT(!fIsFinishing); // we're not supposed to add more work after the calling of finish 18 fWidth++; 19 } 20 21 void SkTaskGroup2D::finish() { 22 fIsFinishing.store(true, std::memory_order_relaxed); 23 fThreadsGroup->wait(); 24 } 25 26 void SkSpinningTaskGroup2D::work(int threadId) { 27 int workCol = 0; 28 int initCol = 0; 29 30 while (true) { 31 SkASSERT(workCol <= fWidth); 32 if (this->isFinishing() && workCol >= fWidth) { 33 return; 34 } 35 36 // Note that row = threadId 37 if (workCol < fWidth && fKernel->work2D(threadId, workCol, threadId)) { 38 workCol++; 39 } else { 40 // Initialize something if we can't work 41 this->initAnUninitializedColumn(initCol, threadId); 42 } 43 } 44 } 45 46 void SkFlexibleTaskGroup2D::work(int threadId) { 47 int row = threadId; 48 int initCol = 0; 49 int numRowsCompleted = 0; 50 std::vector<bool> completedRows(fHeight, false); 51 52 // Only keep fHeight - numRowsCompleted number of threads looping. When rows are about to 53 // complete, this strategy keeps the contention low. 54 while (threadId < fHeight - numRowsCompleted) { 55 RowData& rowData = fRowData[row]; 56 57 // The Android roller somehow gets a false-positive compile warning/error about the try-lock 58 // and unlock process. Hence we disable -Wthread-safety-analysis to bypass it. 59 #ifdef __clang__ 60 #pragma clang diagnostic push 61 #pragma clang diagnostic ignored "-Wthread-safety-analysis" 62 #endif 63 if (rowData.fMutex.try_lock()) { 64 while (rowData.fNextColumn < fWidth && 65 fKernel->work2D(row, rowData.fNextColumn, threadId)) { 66 rowData.fNextColumn++; 67 } 68 // isFinishing can never go from true to false. Once it's true, we count how many rows 69 // are completed (out of work). If that count reaches fHeight, then we're out of work 70 // for the whole group and we can stop. 71 if (rowData.fNextColumn == fWidth && this->isFinishing()) { 72 numRowsCompleted += (completedRows[row] == false); 73 completedRows[row] = true; // so we won't count this row twice 74 } 75 rowData.fMutex.unlock(); 76 } 77 #ifdef __clang__ 78 #pragma clang diagnostic pop 79 #endif 80 81 // By reaching here, we're either unable to acquire the row, or out of work, or blocked by 82 // initialization 83 row = (row + 1) % fHeight; // Move to the next row 84 this->initAnUninitializedColumn(initCol, threadId); // Initialize something 85 } 86 } 87