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_RESIDUAL_BUFFER_POOL_H_ 18 #define LIBGAV1_SRC_RESIDUAL_BUFFER_POOL_H_ 19 20 #include <cstddef> 21 #include <cstdint> 22 #include <memory> 23 #include <mutex> // NOLINT (unapproved c++11 header) 24 #include <new> 25 26 #include "src/utils/common.h" 27 #include "src/utils/compiler_attributes.h" 28 #include "src/utils/constants.h" 29 #include "src/utils/memory.h" 30 #include "src/utils/types.h" 31 32 namespace libgav1 { 33 34 // A simple fixed size queue implementation to hold the transform parameters 35 // when |Tile::split_parse_and_decode_| is true. We don't have to do any 36 // boundary checks since we always push data into the queue before accessing it. 37 class TransformParameterQueue { 38 public: 39 TransformParameterQueue() = default; 40 41 // Move only. 42 TransformParameterQueue(TransformParameterQueue&& other) = default; 43 TransformParameterQueue& operator=(TransformParameterQueue&& other) = default; 44 Init(int max_size)45 LIBGAV1_MUST_USE_RESULT bool Init(int max_size) { 46 max_size_ = max_size; 47 // No initialization is necessary since the data will be always written to 48 // before being read. 49 non_zero_coeff_count_.reset(new (std::nothrow) int16_t[max_size_]); 50 tx_type_.reset(new (std::nothrow) TransformType[max_size_]); 51 return non_zero_coeff_count_ != nullptr && tx_type_ != nullptr; 52 } 53 54 // Adds the |non_zero_coeff_count| and the |tx_type| to the back of the queue. Push(int non_zero_coeff_count,TransformType tx_type)55 void Push(int non_zero_coeff_count, TransformType tx_type) { 56 assert(back_ < max_size_); 57 non_zero_coeff_count_[back_] = non_zero_coeff_count; 58 tx_type_[back_++] = tx_type; 59 } 60 61 // Returns the non_zero_coeff_count at the front of the queue. NonZeroCoeffCount()62 int16_t NonZeroCoeffCount() const { 63 assert(front_ != back_); 64 return non_zero_coeff_count_[front_]; 65 } 66 67 // Returns the tx_type at the front of the queue. Type()68 TransformType Type() const { 69 assert(front_ != back_); 70 return tx_type_[front_]; 71 } 72 73 // Removes the |non_zero_coeff_count| and the |tx_type| from the front of the 74 // queue. Pop()75 void Pop() { 76 assert(front_ != back_); 77 ++front_; 78 } 79 80 // Clears the queue. Reset()81 void Reset() { 82 front_ = 0; 83 back_ = 0; 84 } 85 86 // Used only in the tests. Returns the number of elements in the queue. Size()87 int Size() const { return back_ - front_; } 88 89 private: 90 int max_size_ = 0; 91 std::unique_ptr<int16_t[]> non_zero_coeff_count_; 92 std::unique_ptr<TransformType[]> tx_type_; 93 int front_ = 0; 94 int back_ = 0; 95 }; 96 97 // This class is used for parsing and decoding a superblock. Members of this 98 // class are populated in the "parse" step and consumed in the "decode" step. 99 class ResidualBuffer : public Allocable { 100 public: Create(size_t buffer_size,int queue_size)101 static std::unique_ptr<ResidualBuffer> Create(size_t buffer_size, 102 int queue_size) { 103 std::unique_ptr<ResidualBuffer> buffer(new (std::nothrow) ResidualBuffer); 104 if (buffer != nullptr) { 105 buffer->buffer_ = MakeAlignedUniquePtr<uint8_t>(32, buffer_size); 106 if (buffer->buffer_ == nullptr || 107 !buffer->transform_parameters_.Init(queue_size)) { 108 buffer = nullptr; 109 } 110 } 111 return buffer; 112 } 113 114 // Move only. 115 ResidualBuffer(ResidualBuffer&& other) = default; 116 ResidualBuffer& operator=(ResidualBuffer&& other) = default; 117 118 // Buffer used to store the residual values. buffer()119 uint8_t* buffer() { return buffer_.get(); } 120 // Queue used to store the transform parameters. transform_parameters()121 TransformParameterQueue* transform_parameters() { 122 return &transform_parameters_; 123 } 124 125 private: 126 friend class ResidualBufferStack; 127 128 ResidualBuffer() = default; 129 130 AlignedUniquePtr<uint8_t> buffer_; 131 TransformParameterQueue transform_parameters_; 132 // Used by ResidualBufferStack to form a chain of ResidualBuffers. 133 ResidualBuffer* next_ = nullptr; 134 }; 135 136 // A LIFO stack of ResidualBuffers. Owns the buffers in the stack. 137 class ResidualBufferStack { 138 public: 139 ResidualBufferStack() = default; 140 141 // Not copyable or movable 142 ResidualBufferStack(const ResidualBufferStack&) = delete; 143 ResidualBufferStack& operator=(const ResidualBufferStack&) = delete; 144 145 ~ResidualBufferStack(); 146 147 // Pushes |buffer| to the top of the stack. 148 void Push(std::unique_ptr<ResidualBuffer> buffer); 149 150 // If the stack is non-empty, returns the buffer at the top of the stack and 151 // removes it from the stack. If the stack is empty, returns nullptr. 152 std::unique_ptr<ResidualBuffer> Pop(); 153 154 // Swaps the contents of this stack and |other|. 155 void Swap(ResidualBufferStack* other); 156 157 // Returns the number of buffers in the stack. Size()158 size_t Size() const { return num_buffers_; } 159 160 private: 161 // A singly-linked list of ResidualBuffers, chained together using the next_ 162 // field of ResidualBuffer. 163 ResidualBuffer* top_ = nullptr; 164 size_t num_buffers_ = 0; 165 }; 166 167 // Utility class used to manage the residual buffers (and the transform 168 // parameters) used for multi-threaded decoding. This class uses a stack to 169 // store the buffers for better cache locality. Since buffers used more recently 170 // are more likely to be in the cache. All functions in this class are 171 // thread-safe. 172 class ResidualBufferPool : public Allocable { 173 public: 174 ResidualBufferPool(bool use_128x128_superblock, int subsampling_x, 175 int subsampling_y, size_t residual_size); 176 177 // Recomputes |buffer_size_| and invalidates the existing buffers if 178 // necessary. 179 void Reset(bool use_128x128_superblock, int subsampling_x, int subsampling_y, 180 size_t residual_size); 181 // Gets a residual buffer. The buffer is guaranteed to be large enough to 182 // store the residual values for one superblock whose parameters are the same 183 // as the constructor or the last call to Reset(). If there are free buffers 184 // in the stack, it returns one from the stack, otherwise a new buffer is 185 // allocated. 186 std::unique_ptr<ResidualBuffer> Get(); 187 // Returns the |buffer| back to the pool (by appending it to the stack). 188 // Subsequent calls to Get() may re-use this buffer. 189 void Release(std::unique_ptr<ResidualBuffer> buffer); 190 191 // Used only in the tests. Returns the number of buffers in the stack. 192 size_t Size() const; 193 194 private: 195 mutable std::mutex mutex_; 196 ResidualBufferStack buffers_ LIBGAV1_GUARDED_BY(mutex_); 197 size_t buffer_size_; 198 int queue_size_; 199 }; 200 201 } // namespace libgav1 202 203 #endif // LIBGAV1_SRC_RESIDUAL_BUFFER_POOL_H_ 204