blob: 3eaf8b8a381b0c364e60d25467d0ff9339ccca49 [file] [log] [blame]
/*
* Copyright 2019 The libgav1 Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBGAV1_SRC_TILE_SCRATCH_BUFFER_H_
#define LIBGAV1_SRC_TILE_SCRATCH_BUFFER_H_
#include <cstdint>
#include <mutex> // NOLINT (unapproved c++11 header)
#include "src/dsp/constants.h"
#include "src/utils/common.h"
#include "src/utils/compiler_attributes.h"
#include "src/utils/constants.h"
#include "src/utils/memory.h"
#include "src/utils/stack.h"
namespace libgav1 {
// Buffer to facilitate decoding a superblock.
struct TileScratchBuffer : public MaxAlignedAllocable {
static constexpr int kBlockDecodedStride = 34;
LIBGAV1_MUST_USE_RESULT bool Init(int bitdepth) {
#if LIBGAV1_MAX_BITDEPTH >= 10
const int pixel_size = (bitdepth == 8) ? 1 : 2;
#else
assert(bitdepth == 8);
static_cast<void>(bitdepth);
const int pixel_size = 1;
#endif
constexpr int unaligned_convolve_buffer_stride =
kMaxScaledSuperBlockSizeInPixels + kConvolveBorderLeftTop +
kConvolveBorderRight;
convolve_block_buffer_stride = Align<ptrdiff_t>(
unaligned_convolve_buffer_stride * pixel_size, kMaxAlignment);
constexpr int convolve_buffer_height = kMaxScaledSuperBlockSizeInPixels +
kConvolveBorderLeftTop +
kConvolveBorderBottom;
convolve_block_buffer = MakeAlignedUniquePtr<uint8_t>(
kMaxAlignment, convolve_buffer_height * convolve_block_buffer_stride);
return convolve_block_buffer != nullptr;
}
// kCompoundPredictionTypeDiffWeighted prediction mode needs a mask of the
// prediction block size. This buffer is used to store that mask. The masks
// will be created for the Y plane and will be re-used for the U & V planes.
alignas(kMaxAlignment) uint8_t weight_mask[kMaxSuperBlockSizeSquareInPixels];
// For each instance of the TileScratchBuffer, only one of the following
// buffers will be used at any given time, so it is ok to share them in a
// union.
union {
// Buffers used for prediction process.
// Compound prediction calculations always output 16-bit values. Depending
// on the bitdepth the values may be treated as int16_t or uint16_t. See
// src/dsp/convolve.cc and src/dsp/warp.cc for explanations.
// Inter/intra calculations output Pixel values.
// These buffers always use width as the stride. This enables packing the
// values in and simplifies loads/stores for small values.
// 10/12 bit compound prediction and 10/12 bit inter/intra prediction.
alignas(kMaxAlignment) uint16_t
prediction_buffer[2][kMaxSuperBlockSizeSquareInPixels];
// 8 bit compound prediction buffer.
alignas(kMaxAlignment) int16_t
compound_prediction_buffer_8bpp[2][kMaxSuperBlockSizeSquareInPixels];
// Union usage note: This is used only by functions in the "intra"
// prediction path.
//
// Buffer used for storing subsampled luma samples needed for CFL
// prediction. This buffer is used to avoid repetition of the subsampling
// for the V plane when it is already done for the U plane.
int16_t cfl_luma_buffer[kCflLumaBufferStride][kCflLumaBufferStride];
};
// Buffer used for convolve. The maximum size required for this buffer is:
// maximum block height (with scaling and border) = 2 * 128 + 3 + 4 = 263.
// maximum block stride (with scaling and border aligned to 16) =
// (2 * 128 + 3 + 8 + 5) * pixel_size = 272 * pixel_size.
// Where pixel_size is (bitdepth == 8) ? 1 : 2.
// Has an alignment of kMaxAlignment when allocated.
AlignedUniquePtr<uint8_t> convolve_block_buffer;
ptrdiff_t convolve_block_buffer_stride;
// Flag indicating whether the data in |cfl_luma_buffer| is valid.
bool cfl_luma_buffer_valid;
// Equivalent to BlockDecoded array in the spec. This stores the decoded
// state of every 4x4 block in a superblock. It has 1 row/column border on
// all 4 sides (hence the 34x34 dimension instead of 32x32). Note that the
// spec uses "-1" as an index to access the left and top borders. In the
// code, we treat the index (1, 1) as equivalent to the spec's (0, 0). So
// all accesses into this array will be offset by +1 when compared with the
// spec.
bool block_decoded[kMaxPlanes][kBlockDecodedStride][kBlockDecodedStride];
};
class TileScratchBufferPool {
public:
void Reset(int bitdepth) {
if (bitdepth_ == bitdepth) return;
#if LIBGAV1_MAX_BITDEPTH >= 10
if (bitdepth_ == 8 && bitdepth != 8) {
// We are going from a pixel size of 1 to a pixel size of 2. So invalidate
// the stack.
std::lock_guard<std::mutex> lock(mutex_);
while (!buffers_.Empty()) {
buffers_.Pop();
}
}
#endif
bitdepth_ = bitdepth;
}
std::unique_ptr<TileScratchBuffer> Get() {
std::lock_guard<std::mutex> lock(mutex_);
if (buffers_.Empty()) {
std::unique_ptr<TileScratchBuffer> scratch_buffer(new (std::nothrow)
TileScratchBuffer);
if (scratch_buffer == nullptr || !scratch_buffer->Init(bitdepth_)) {
return nullptr;
}
return scratch_buffer;
}
return buffers_.Pop();
}
void Release(std::unique_ptr<TileScratchBuffer> scratch_buffer) {
std::lock_guard<std::mutex> lock(mutex_);
buffers_.Push(std::move(scratch_buffer));
}
private:
std::mutex mutex_;
// We will never need more than kMaxThreads scratch buffers since that is the
// maximum amount of work that will be done at any given time.
Stack<std::unique_ptr<TileScratchBuffer>, kMaxThreads> buffers_
LIBGAV1_GUARDED_BY(mutex_);
int bitdepth_ = 0;
};
} // namespace libgav1
#endif // LIBGAV1_SRC_TILE_SCRATCH_BUFFER_H_