1*09537850SAkhilesh Sanikop // Copyright 2019 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include "src/residual_buffer_pool.h"
16*09537850SAkhilesh Sanikop
17*09537850SAkhilesh Sanikop #include <mutex> // NOLINT (unapproved c++11 header)
18*09537850SAkhilesh Sanikop #include <utility>
19*09537850SAkhilesh Sanikop
20*09537850SAkhilesh Sanikop namespace libgav1 {
21*09537850SAkhilesh Sanikop namespace {
22*09537850SAkhilesh Sanikop
23*09537850SAkhilesh Sanikop // The maximum queue size is derived using the following formula:
24*09537850SAkhilesh Sanikop // ((sb_size * sb_size) / 16) + (2 * (((sb_size / x) * (sb_size / y)) / 16)).
25*09537850SAkhilesh Sanikop // Where:
26*09537850SAkhilesh Sanikop // sb_size is the superblock size (64 or 128).
27*09537850SAkhilesh Sanikop // 16 is 4*4 which is kMinTransformWidth * kMinTransformHeight.
28*09537850SAkhilesh Sanikop // x is subsampling_x + 1.
29*09537850SAkhilesh Sanikop // y is subsampling_y + 1.
30*09537850SAkhilesh Sanikop // The first component is for the Y plane and the second component is for the U
31*09537850SAkhilesh Sanikop // and V planes.
32*09537850SAkhilesh Sanikop // For example, for 128x128 superblocks with 422 subsampling the size is:
33*09537850SAkhilesh Sanikop // ((128 * 128) / 16) + (2 * (((128 / 2) * (128 / 1)) / 16)) = 2048.
34*09537850SAkhilesh Sanikop //
35*09537850SAkhilesh Sanikop // First dimension: use_128x128_superblock.
36*09537850SAkhilesh Sanikop // Second dimension: subsampling_x.
37*09537850SAkhilesh Sanikop // Third dimension: subsampling_y.
38*09537850SAkhilesh Sanikop constexpr int kMaxQueueSize[2][2][2] = {
39*09537850SAkhilesh Sanikop // 64x64 superblocks.
40*09537850SAkhilesh Sanikop {
41*09537850SAkhilesh Sanikop {768, 512},
42*09537850SAkhilesh Sanikop {512, 384},
43*09537850SAkhilesh Sanikop },
44*09537850SAkhilesh Sanikop // 128x128 superblocks.
45*09537850SAkhilesh Sanikop {
46*09537850SAkhilesh Sanikop {3072, 2048},
47*09537850SAkhilesh Sanikop {2048, 1536},
48*09537850SAkhilesh Sanikop },
49*09537850SAkhilesh Sanikop };
50*09537850SAkhilesh Sanikop
51*09537850SAkhilesh Sanikop } // namespace
52*09537850SAkhilesh Sanikop
~ResidualBufferStack()53*09537850SAkhilesh Sanikop ResidualBufferStack::~ResidualBufferStack() {
54*09537850SAkhilesh Sanikop while (top_ != nullptr) {
55*09537850SAkhilesh Sanikop ResidualBuffer* top = top_;
56*09537850SAkhilesh Sanikop top_ = top_->next_;
57*09537850SAkhilesh Sanikop delete top;
58*09537850SAkhilesh Sanikop }
59*09537850SAkhilesh Sanikop }
60*09537850SAkhilesh Sanikop
Push(std::unique_ptr<ResidualBuffer> buffer)61*09537850SAkhilesh Sanikop void ResidualBufferStack::Push(std::unique_ptr<ResidualBuffer> buffer) {
62*09537850SAkhilesh Sanikop buffer->next_ = top_;
63*09537850SAkhilesh Sanikop top_ = buffer.release();
64*09537850SAkhilesh Sanikop ++num_buffers_;
65*09537850SAkhilesh Sanikop }
66*09537850SAkhilesh Sanikop
Pop()67*09537850SAkhilesh Sanikop std::unique_ptr<ResidualBuffer> ResidualBufferStack::Pop() {
68*09537850SAkhilesh Sanikop std::unique_ptr<ResidualBuffer> top;
69*09537850SAkhilesh Sanikop if (top_ != nullptr) {
70*09537850SAkhilesh Sanikop top.reset(top_);
71*09537850SAkhilesh Sanikop top_ = top_->next_;
72*09537850SAkhilesh Sanikop top->next_ = nullptr;
73*09537850SAkhilesh Sanikop --num_buffers_;
74*09537850SAkhilesh Sanikop }
75*09537850SAkhilesh Sanikop return top;
76*09537850SAkhilesh Sanikop }
77*09537850SAkhilesh Sanikop
Swap(ResidualBufferStack * other)78*09537850SAkhilesh Sanikop void ResidualBufferStack::Swap(ResidualBufferStack* other) {
79*09537850SAkhilesh Sanikop std::swap(top_, other->top_);
80*09537850SAkhilesh Sanikop std::swap(num_buffers_, other->num_buffers_);
81*09537850SAkhilesh Sanikop }
82*09537850SAkhilesh Sanikop
ResidualBufferPool(bool use_128x128_superblock,int subsampling_x,int subsampling_y,size_t residual_size)83*09537850SAkhilesh Sanikop ResidualBufferPool::ResidualBufferPool(bool use_128x128_superblock,
84*09537850SAkhilesh Sanikop int subsampling_x, int subsampling_y,
85*09537850SAkhilesh Sanikop size_t residual_size)
86*09537850SAkhilesh Sanikop : buffer_size_(GetResidualBufferSize(
87*09537850SAkhilesh Sanikop use_128x128_superblock ? 128 : 64, use_128x128_superblock ? 128 : 64,
88*09537850SAkhilesh Sanikop subsampling_x, subsampling_y, residual_size)),
89*09537850SAkhilesh Sanikop queue_size_(kMaxQueueSize[static_cast<int>(use_128x128_superblock)]
90*09537850SAkhilesh Sanikop [subsampling_x][subsampling_y]) {}
91*09537850SAkhilesh Sanikop
Reset(bool use_128x128_superblock,int subsampling_x,int subsampling_y,size_t residual_size)92*09537850SAkhilesh Sanikop void ResidualBufferPool::Reset(bool use_128x128_superblock, int subsampling_x,
93*09537850SAkhilesh Sanikop int subsampling_y, size_t residual_size) {
94*09537850SAkhilesh Sanikop const size_t buffer_size = GetResidualBufferSize(
95*09537850SAkhilesh Sanikop use_128x128_superblock ? 128 : 64, use_128x128_superblock ? 128 : 64,
96*09537850SAkhilesh Sanikop subsampling_x, subsampling_y, residual_size);
97*09537850SAkhilesh Sanikop const int queue_size = kMaxQueueSize[static_cast<int>(use_128x128_superblock)]
98*09537850SAkhilesh Sanikop [subsampling_x][subsampling_y];
99*09537850SAkhilesh Sanikop if (buffer_size == buffer_size_ && queue_size == queue_size_) {
100*09537850SAkhilesh Sanikop // The existing buffers (if any) are still valid, so don't do anything.
101*09537850SAkhilesh Sanikop return;
102*09537850SAkhilesh Sanikop }
103*09537850SAkhilesh Sanikop buffer_size_ = buffer_size;
104*09537850SAkhilesh Sanikop queue_size_ = queue_size;
105*09537850SAkhilesh Sanikop // The existing buffers (if any) are no longer valid since the buffer size or
106*09537850SAkhilesh Sanikop // the queue size has changed. Clear the stack.
107*09537850SAkhilesh Sanikop ResidualBufferStack buffers;
108*09537850SAkhilesh Sanikop {
109*09537850SAkhilesh Sanikop std::lock_guard<std::mutex> lock(mutex_);
110*09537850SAkhilesh Sanikop // Move the buffers in the stack to the local variable |buffers| and clear
111*09537850SAkhilesh Sanikop // the stack.
112*09537850SAkhilesh Sanikop buffers.Swap(&buffers_);
113*09537850SAkhilesh Sanikop // Release mutex_ before freeing the buffers.
114*09537850SAkhilesh Sanikop }
115*09537850SAkhilesh Sanikop // As the local variable |buffers| goes out of scope, its destructor frees
116*09537850SAkhilesh Sanikop // the buffers that were in the stack.
117*09537850SAkhilesh Sanikop }
118*09537850SAkhilesh Sanikop
Get()119*09537850SAkhilesh Sanikop std::unique_ptr<ResidualBuffer> ResidualBufferPool::Get() {
120*09537850SAkhilesh Sanikop std::unique_ptr<ResidualBuffer> buffer = nullptr;
121*09537850SAkhilesh Sanikop {
122*09537850SAkhilesh Sanikop std::lock_guard<std::mutex> lock(mutex_);
123*09537850SAkhilesh Sanikop buffer = buffers_.Pop();
124*09537850SAkhilesh Sanikop }
125*09537850SAkhilesh Sanikop if (buffer == nullptr) {
126*09537850SAkhilesh Sanikop buffer = ResidualBuffer::Create(buffer_size_, queue_size_);
127*09537850SAkhilesh Sanikop }
128*09537850SAkhilesh Sanikop return buffer;
129*09537850SAkhilesh Sanikop }
130*09537850SAkhilesh Sanikop
Release(std::unique_ptr<ResidualBuffer> buffer)131*09537850SAkhilesh Sanikop void ResidualBufferPool::Release(std::unique_ptr<ResidualBuffer> buffer) {
132*09537850SAkhilesh Sanikop buffer->transform_parameters()->Clear();
133*09537850SAkhilesh Sanikop buffer->partition_tree_order()->Clear();
134*09537850SAkhilesh Sanikop std::lock_guard<std::mutex> lock(mutex_);
135*09537850SAkhilesh Sanikop buffers_.Push(std::move(buffer));
136*09537850SAkhilesh Sanikop }
137*09537850SAkhilesh Sanikop
Size() const138*09537850SAkhilesh Sanikop size_t ResidualBufferPool::Size() const {
139*09537850SAkhilesh Sanikop std::lock_guard<std::mutex> lock(mutex_);
140*09537850SAkhilesh Sanikop return buffers_.Size();
141*09537850SAkhilesh Sanikop }
142*09537850SAkhilesh Sanikop
143*09537850SAkhilesh Sanikop } // namespace libgav1
144