Home | History | Annotate | Download | only in core
      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