1*09537850SAkhilesh Sanikop /* 2*09537850SAkhilesh Sanikop * Copyright 2019 The libgav1 Authors 3*09537850SAkhilesh Sanikop * 4*09537850SAkhilesh Sanikop * Licensed under the Apache License, Version 2.0 (the "License"); 5*09537850SAkhilesh Sanikop * you may not use this file except in compliance with the License. 6*09537850SAkhilesh Sanikop * You may obtain a copy of the License at 7*09537850SAkhilesh Sanikop * 8*09537850SAkhilesh Sanikop * http://www.apache.org/licenses/LICENSE-2.0 9*09537850SAkhilesh Sanikop * 10*09537850SAkhilesh Sanikop * Unless required by applicable law or agreed to in writing, software 11*09537850SAkhilesh Sanikop * distributed under the License is distributed on an "AS IS" BASIS, 12*09537850SAkhilesh Sanikop * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*09537850SAkhilesh Sanikop * See the License for the specific language governing permissions and 14*09537850SAkhilesh Sanikop * limitations under the License. 15*09537850SAkhilesh Sanikop */ 16*09537850SAkhilesh Sanikop 17*09537850SAkhilesh Sanikop #ifndef LIBGAV1_SRC_THREADING_STRATEGY_H_ 18*09537850SAkhilesh Sanikop #define LIBGAV1_SRC_THREADING_STRATEGY_H_ 19*09537850SAkhilesh Sanikop 20*09537850SAkhilesh Sanikop #include <memory> 21*09537850SAkhilesh Sanikop 22*09537850SAkhilesh Sanikop #include "src/obu_parser.h" 23*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h" 24*09537850SAkhilesh Sanikop #include "src/utils/threadpool.h" 25*09537850SAkhilesh Sanikop 26*09537850SAkhilesh Sanikop namespace libgav1 { 27*09537850SAkhilesh Sanikop 28*09537850SAkhilesh Sanikop class FrameScratchBufferPool; 29*09537850SAkhilesh Sanikop 30*09537850SAkhilesh Sanikop // This class allocates and manages the worker threads among thread pools used 31*09537850SAkhilesh Sanikop // for multi-threaded decoding. 32*09537850SAkhilesh Sanikop class ThreadingStrategy { 33*09537850SAkhilesh Sanikop public: 34*09537850SAkhilesh Sanikop ThreadingStrategy() = default; 35*09537850SAkhilesh Sanikop 36*09537850SAkhilesh Sanikop // Not copyable or movable. 37*09537850SAkhilesh Sanikop ThreadingStrategy(const ThreadingStrategy&) = delete; 38*09537850SAkhilesh Sanikop ThreadingStrategy& operator=(const ThreadingStrategy&) = delete; 39*09537850SAkhilesh Sanikop 40*09537850SAkhilesh Sanikop // Creates or re-allocates the thread pools based on the |frame_header| and 41*09537850SAkhilesh Sanikop // |thread_count|. This function is used only in non frame-parallel mode. This 42*09537850SAkhilesh Sanikop // function is idempotent if the |frame_header| and |thread_count| don't 43*09537850SAkhilesh Sanikop // change between calls (it will only create new threads on the first call and 44*09537850SAkhilesh Sanikop // do nothing on the subsequent calls). This function also starts the worker 45*09537850SAkhilesh Sanikop // threads whenever it creates new thread pools. 46*09537850SAkhilesh Sanikop // The following strategy is used to allocate threads: 47*09537850SAkhilesh Sanikop // * One thread is allocated for decoding each Tile. 48*09537850SAkhilesh Sanikop // * Any remaining threads are allocated for superblock row multi-threading 49*09537850SAkhilesh Sanikop // within each of the tile in a round robin fashion. 50*09537850SAkhilesh Sanikop // Note: During the lifetime of a ThreadingStrategy object, only one of the 51*09537850SAkhilesh Sanikop // Reset() variants will be used. 52*09537850SAkhilesh Sanikop LIBGAV1_MUST_USE_RESULT bool Reset(const ObuFrameHeader& frame_header, 53*09537850SAkhilesh Sanikop int thread_count); 54*09537850SAkhilesh Sanikop 55*09537850SAkhilesh Sanikop // Creates or re-allocates a thread pool with |thread_count| threads. This 56*09537850SAkhilesh Sanikop // function is used only in frame parallel mode. This function is idempotent 57*09537850SAkhilesh Sanikop // if the |thread_count| doesn't change between calls (it will only create new 58*09537850SAkhilesh Sanikop // threads on the first call and do nothing on the subsequent calls). 59*09537850SAkhilesh Sanikop // Note: During the lifetime of a ThreadingStrategy object, only one of the 60*09537850SAkhilesh Sanikop // Reset() variants will be used. 61*09537850SAkhilesh Sanikop LIBGAV1_MUST_USE_RESULT bool Reset(int thread_count); 62*09537850SAkhilesh Sanikop 63*09537850SAkhilesh Sanikop // Returns a pointer to the ThreadPool that is to be used for Tile 64*09537850SAkhilesh Sanikop // multi-threading. tile_thread_pool()65*09537850SAkhilesh Sanikop ThreadPool* tile_thread_pool() const { 66*09537850SAkhilesh Sanikop return (tile_thread_count_ != 0) ? thread_pool_.get() : nullptr; 67*09537850SAkhilesh Sanikop } 68*09537850SAkhilesh Sanikop tile_thread_count()69*09537850SAkhilesh Sanikop int tile_thread_count() const { return tile_thread_count_; } 70*09537850SAkhilesh Sanikop 71*09537850SAkhilesh Sanikop // Returns a pointer to the underlying ThreadPool. 72*09537850SAkhilesh Sanikop // Note: Valid only when |frame_parallel_| is true. This is used for 73*09537850SAkhilesh Sanikop // facilitating in-frame multi-threading in that case. thread_pool()74*09537850SAkhilesh Sanikop ThreadPool* thread_pool() const { return thread_pool_.get(); } 75*09537850SAkhilesh Sanikop 76*09537850SAkhilesh Sanikop // Returns a pointer to the ThreadPool that is to be used within the Tile at 77*09537850SAkhilesh Sanikop // index |tile_index| for superblock row multi-threading. 78*09537850SAkhilesh Sanikop // Note: Valid only when |frame_parallel_| is false. row_thread_pool(int tile_index)79*09537850SAkhilesh Sanikop ThreadPool* row_thread_pool(int tile_index) const { 80*09537850SAkhilesh Sanikop return tile_index < max_tile_index_for_row_threads_ ? thread_pool_.get() 81*09537850SAkhilesh Sanikop : nullptr; 82*09537850SAkhilesh Sanikop } 83*09537850SAkhilesh Sanikop 84*09537850SAkhilesh Sanikop // Returns a pointer to the ThreadPool that is to be used for post filter 85*09537850SAkhilesh Sanikop // multi-threading. 86*09537850SAkhilesh Sanikop // Note: Valid only when |frame_parallel_| is false. post_filter_thread_pool()87*09537850SAkhilesh Sanikop ThreadPool* post_filter_thread_pool() const { 88*09537850SAkhilesh Sanikop return frame_parallel_ ? nullptr : thread_pool_.get(); 89*09537850SAkhilesh Sanikop } 90*09537850SAkhilesh Sanikop 91*09537850SAkhilesh Sanikop // Returns a pointer to the ThreadPool that is to be used for film grain 92*09537850SAkhilesh Sanikop // synthesis and blending. 93*09537850SAkhilesh Sanikop // Note: Valid only when |frame_parallel_| is false. film_grain_thread_pool()94*09537850SAkhilesh Sanikop ThreadPool* film_grain_thread_pool() const { return thread_pool_.get(); } 95*09537850SAkhilesh Sanikop 96*09537850SAkhilesh Sanikop private: 97*09537850SAkhilesh Sanikop std::unique_ptr<ThreadPool> thread_pool_; 98*09537850SAkhilesh Sanikop int tile_thread_count_ = 0; 99*09537850SAkhilesh Sanikop int max_tile_index_for_row_threads_ = 0; 100*09537850SAkhilesh Sanikop bool frame_parallel_ = false; 101*09537850SAkhilesh Sanikop }; 102*09537850SAkhilesh Sanikop 103*09537850SAkhilesh Sanikop // Initializes the |frame_thread_pool| and the necessary worker threadpools (the 104*09537850SAkhilesh Sanikop // threading_strategy objects in each of the frame scratch buffer in 105*09537850SAkhilesh Sanikop // |frame_scratch_buffer_pool|) as follows: 106*09537850SAkhilesh Sanikop // * frame_threads = ComputeFrameThreadCount(); 107*09537850SAkhilesh Sanikop // * For more details on how frame_threads is computed, see the function 108*09537850SAkhilesh Sanikop // comment in ComputeFrameThreadCount(). 109*09537850SAkhilesh Sanikop // * |frame_thread_pool| is created with |frame_threads| threads. 110*09537850SAkhilesh Sanikop // * divide the remaining number of threads into each frame thread and 111*09537850SAkhilesh Sanikop // initialize a frame_scratch_buffer.threading_strategy for each frame 112*09537850SAkhilesh Sanikop // thread. 113*09537850SAkhilesh Sanikop // When this function is called, |frame_scratch_buffer_pool| must be empty. If 114*09537850SAkhilesh Sanikop // this function returns true, it means the initialization was successful and 115*09537850SAkhilesh Sanikop // one of the following is true: 116*09537850SAkhilesh Sanikop // * |frame_thread_pool| has been successfully initialized and 117*09537850SAkhilesh Sanikop // |frame_scratch_buffer_pool| has been successfully populated with 118*09537850SAkhilesh Sanikop // |frame_threads| buffers to be used by each frame thread. The total 119*09537850SAkhilesh Sanikop // number of threads that this function creates will always be equal to 120*09537850SAkhilesh Sanikop // |thread_count|. 121*09537850SAkhilesh Sanikop // * |frame_thread_pool| is nullptr. |frame_scratch_buffer_pool| is not 122*09537850SAkhilesh Sanikop // modified. This means that frame threading will not be used and the 123*09537850SAkhilesh Sanikop // decoder will continue to operate normally in non frame parallel mode. 124*09537850SAkhilesh Sanikop LIBGAV1_MUST_USE_RESULT bool InitializeThreadPoolsForFrameParallel( 125*09537850SAkhilesh Sanikop int thread_count, int tile_count, int tile_columns, 126*09537850SAkhilesh Sanikop std::unique_ptr<ThreadPool>* frame_thread_pool, 127*09537850SAkhilesh Sanikop FrameScratchBufferPool* frame_scratch_buffer_pool); 128*09537850SAkhilesh Sanikop 129*09537850SAkhilesh Sanikop } // namespace libgav1 130*09537850SAkhilesh Sanikop 131*09537850SAkhilesh Sanikop #endif // LIBGAV1_SRC_THREADING_STRATEGY_H_ 132