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& nextColumn = fRowData[threadId].fNextColumn;
     28 
     29     while (true) {
     30         SkASSERT(nextColumn <= fWidth);
     31         if (this->isFinishing() && nextColumn >= fWidth) {
     32             return;
     33         }
     34 
     35         if (nextColumn < fWidth) {
     36             fWork(threadId, nextColumn);
     37             nextColumn++;
     38         }
     39     }
     40 }
     41 
     42 SkFlexibleTaskGroup2D::SkFlexibleTaskGroup2D(Work2D&& w, int h, SkExecutor* x, int t)
     43         : SkTaskGroup2D(std::move(w), h, x, t), fRowData(h), fThreadData(t) {
     44     for (int i = 0; i < t; ++i) {
     45         fThreadData[i].fRowIndex = i;
     46     }
     47 }
     48 
     49 
     50 void SkFlexibleTaskGroup2D::work(int threadId) {
     51     int failCnt = 0;
     52     int& rowIndex = fThreadData[threadId].fRowIndex;
     53 
     54     // This loop looks for work to do as long as
     55     // either 1. isFinishing is false
     56     // or     2. isFinishing is true but some rows still have unfinished tasks
     57     while (true) {
     58         RowData& rowData = fRowData[rowIndex];
     59         bool processed = false;
     60 
     61         // The Android roller somehow gets a false-positive compile warning/error about the try-lock
     62         // and unlock process. Hence we disable -Wthread-safety-analysis to bypass it.
     63 #ifdef __clang__
     64 #pragma clang diagnostic push
     65 #pragma clang diagnostic ignored "-Wthread-safety-analysis"
     66 #endif
     67         if (rowData.fMutex.try_lock()) {
     68             if (rowData.fNextColumn < fWidth) {
     69                 fWork(rowIndex, rowData.fNextColumn);
     70                 rowData.fNextColumn++;
     71                 processed = true;
     72             } else {
     73                 // isFinishing can never go from true to false. Once it's true, we count how many
     74                 // times that a row is out of work. If that count reaches fHeight, then we're out of
     75                 // work for the whole group.
     76                 failCnt += this->isFinishing();
     77             }
     78             rowData.fMutex.unlock();
     79         }
     80 #ifdef __clang__
     81 #pragma clang diagnostic pop
     82 #endif
     83 
     84         if (!processed) {
     85             if (failCnt >= fHeight) {
     86                 return;
     87             }
     88             rowIndex = (rowIndex + 1) % fHeight;
     89         }
     90     }
     91 }
     92