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/queue.h" 31 #include "src/utils/types.h" 32 33 namespace libgav1 { 34 35 // This class is used for parsing and decoding a superblock. Members of this 36 // class are populated in the "parse" step and consumed in the "decode" step. 37 class ResidualBuffer : public Allocable { 38 public: Create(size_t buffer_size,int queue_size)39 static std::unique_ptr<ResidualBuffer> Create(size_t buffer_size, 40 int queue_size) { 41 std::unique_ptr<ResidualBuffer> buffer(new (std::nothrow) ResidualBuffer); 42 if (buffer != nullptr) { 43 buffer->buffer_ = MakeAlignedUniquePtr<uint8_t>(32, buffer_size); 44 if (buffer->buffer_ == nullptr || 45 !buffer->transform_parameters_.Init(queue_size) || 46 !buffer->partition_tree_order_.Init(queue_size)) { 47 buffer = nullptr; 48 } 49 } 50 return buffer; 51 } 52 53 // Move only. 54 ResidualBuffer(ResidualBuffer&& other) = default; 55 ResidualBuffer& operator=(ResidualBuffer&& other) = default; 56 57 // Buffer used to store the residual values. buffer()58 uint8_t* buffer() { return buffer_.get(); } 59 // Queue used to store the transform parameters. transform_parameters()60 Queue<TransformParameters>* transform_parameters() { 61 return &transform_parameters_; 62 } 63 // Queue used to store the block ordering in the partition tree of the 64 // superblocks. partition_tree_order()65 Queue<PartitionTreeNode>* partition_tree_order() { 66 return &partition_tree_order_; 67 } 68 69 private: 70 friend class ResidualBufferStack; 71 72 ResidualBuffer() = default; 73 74 AlignedUniquePtr<uint8_t> buffer_; 75 Queue<TransformParameters> transform_parameters_; 76 Queue<PartitionTreeNode> partition_tree_order_; 77 // Used by ResidualBufferStack to form a chain of ResidualBuffers. 78 ResidualBuffer* next_ = nullptr; 79 }; 80 81 // A LIFO stack of ResidualBuffers. Owns the buffers in the stack. 82 class ResidualBufferStack { 83 public: 84 ResidualBufferStack() = default; 85 86 // Not copyable or movable 87 ResidualBufferStack(const ResidualBufferStack&) = delete; 88 ResidualBufferStack& operator=(const ResidualBufferStack&) = delete; 89 90 ~ResidualBufferStack(); 91 92 // Pushes |buffer| to the top of the stack. 93 void Push(std::unique_ptr<ResidualBuffer> buffer); 94 95 // If the stack is non-empty, returns the buffer at the top of the stack and 96 // removes it from the stack. If the stack is empty, returns nullptr. 97 std::unique_ptr<ResidualBuffer> Pop(); 98 99 // Swaps the contents of this stack and |other|. 100 void Swap(ResidualBufferStack* other); 101 102 // Returns the number of buffers in the stack. Size()103 size_t Size() const { return num_buffers_; } 104 105 private: 106 // A singly-linked list of ResidualBuffers, chained together using the next_ 107 // field of ResidualBuffer. 108 ResidualBuffer* top_ = nullptr; 109 size_t num_buffers_ = 0; 110 }; 111 112 // Utility class used to manage the residual buffers (and the transform 113 // parameters) used for multi-threaded decoding. This class uses a stack to 114 // store the buffers for better cache locality. Since buffers used more recently 115 // are more likely to be in the cache. All functions in this class are 116 // thread-safe. 117 class ResidualBufferPool : public Allocable { 118 public: 119 ResidualBufferPool(bool use_128x128_superblock, int subsampling_x, 120 int subsampling_y, size_t residual_size); 121 122 // Recomputes |buffer_size_| and invalidates the existing buffers if 123 // necessary. 124 void Reset(bool use_128x128_superblock, int subsampling_x, int subsampling_y, 125 size_t residual_size); 126 // Gets a residual buffer. The buffer is guaranteed to be large enough to 127 // store the residual values for one superblock whose parameters are the same 128 // as the constructor or the last call to Reset(). If there are free buffers 129 // in the stack, it returns one from the stack, otherwise a new buffer is 130 // allocated. 131 std::unique_ptr<ResidualBuffer> Get(); 132 // Returns the |buffer| back to the pool (by appending it to the stack). 133 // Subsequent calls to Get() may re-use this buffer. 134 void Release(std::unique_ptr<ResidualBuffer> buffer); 135 136 // Used only in the tests. Returns the number of buffers in the stack. 137 size_t Size() const; 138 139 private: 140 mutable std::mutex mutex_; 141 ResidualBufferStack buffers_ LIBGAV1_GUARDED_BY(mutex_); 142 size_t buffer_size_; 143 int queue_size_; 144 }; 145 146 } // namespace libgav1 147 148 #endif // LIBGAV1_SRC_RESIDUAL_BUFFER_POOL_H_ 149