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