• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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