blob: bae155824fc58a37521ce6c5fd44e842e2aec751 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// 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
//
// https://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.
// -----------------------------------------------------------------------------
//
// Iterator for splitting blocks.
//
// Author: Maryla (maryla@google.com)
#ifndef WP2_UTILS_SPLIT_ITERATOR_H_
#define WP2_UTILS_SPLIT_ITERATOR_H_
#include <cstdint>
#include "src/common/lossy/block.h"
#include "src/common/lossy/block_size.h"
#include "src/utils/plane.h"
#include "src/utils/vector.h"
#include "src/wp2/base.h"
#include "src/wp2/format_constants.h"
namespace WP2 {
//------------------------------------------------------------------------------
// Class for iterating over blocks by splitting them using various split
// patterns. Usage:
// while (!it.Done()) {
// if (it.CurrentBlock().splittable) {
// (... choose a split_idx out of it.NumSplitPatterns())
// it.SplitCurrentBlock(split_idx);
// } else {
// (... do something with it.CurrentBlock().block)
// it.NextBlock();
// }
// }
class SplitIteratorBase {
public:
virtual ~SplitIteratorBase() = default;
virtual WP2Status Init(PartitionSet partition_set, uint32_t width,
uint32_t height);
// Returns true if the whole area has been covered.
bool Done() const;
PartitionSet partition_set() const { return partition_set_; }
struct SplitInfo {
Block block;
// True if the block can be split, false if it is final.
bool splittable;
};
// Returns the current block being considered.
virtual const SplitInfo& CurrentBlock() const = 0;
// -- If the current block is splittable --
// Returns the number of possible split patterns for the current block.
// A split pattern is a way of splitting (or not) a block into 1 to 4 blocks,
// e.g. keeping it as a single block, splitting in 2 vertically or
// horizontally, splitting in 4, etc.
uint32_t NumSplitPatterns() const;
// Fills 'sub_blocks' with the various sub-blocks corresponding to the
// split_pattern 'split_idx' for the current block. 'split_idx' must be
// smaller than NumSplitPatterns(). Fills 'splittable' with booleans
// indicating if each sub block is further splittable.
// Returns the number of sub-blocks (between 1 and 4).
uint32_t GetSplitPatternBlocks(uint32_t split_idx, Block sub_blocks[4],
bool splittable[4]) const;
// Splits the current block using the split_idx'th split pattern. Only valid
// if CurrentBlock().splittable is true. 'split_idx' must be smaller than
// NumSplitPatterns(). Updates the current block.
virtual void SplitCurrentBlock(uint32_t split_idx) = 0;
// -- If the current block is NOT splittable --
// Updates the CurrentBlock() to the next block. Only valid if
// CurrantBlock().splittable is false.
virtual void NextBlock() = 0;
protected:
WP2Status CopyInternal(const SplitIteratorBase& other);
// Fills 'splittable' with booleans indicating if each sub block is further
// splittable.
virtual void GetSplittable(const Block sub_blocks[4], uint32_t num_sub_blocks,
bool splittable[4]) const = 0;
// Returns the 'sub_blocks' given a 'block' (size and position) and a
// 'split_pattern'.
static void GetSplitPatternBlocks(const Block& block,
const SplitPattern& split_pattern,
Block* sub_blocks);
FrontMgrBase front_mgr_;
PartitionSet partition_set_;
};
// SplitIterator that iterates over blocks in lexicographic order.
class SplitIteratorLexico : public SplitIteratorBase {
public:
WP2Status Init(PartitionSet partition_set, uint32_t width,
uint32_t height) override;
WP2Status CopyFrom(const SplitIteratorLexico& other);
const SplitInfo& CurrentBlock() const override;
void SplitCurrentBlock(uint32_t split_idx) override;
void NextBlock() override;
protected:
void GetSplittable(const Block sub_blocks[4], uint32_t num_sub_blocks,
bool splittable[4]) const override;
private:
void SetCurrentBlock(uint32_t bx, uint32_t by);
bool IsSplittable(BlockSize dim) const;
// Same as SplitInfo but with just the BlockSize instead of Block (to make it
// smaller).
struct LightSplitInfo {
BlockSize size; // BLK_LAST if nothing decided yet.
bool splittable; // False if the decision is definitive
// or true if smaller blocks may be tried.
bool operator==(const LightSplitInfo& other) const {
return size == other.size && splittable == other.splittable;
}
bool operator!=(const LightSplitInfo& other) const {
return !operator==(other);
}
};
// No decision.
static constexpr LightSplitInfo kNoSplitInfo = {BLK_LAST, false};
// Gets the split pattern decision for a given block position.
const LightSplitInfo& GetSplitInfo(uint32_t x, uint32_t y) const;
// Sets the split pattern decision for a given 'block' area.
void SetSplitInfo(const Block& block, bool recursive);
SplitInfo current_block_;
Plane<LightSplitInfo> split_info_;
};
// SplitIterator that iterates over blocks in recursive (quad tree like) order.
class SplitIteratorRecurse : public SplitIteratorBase {
public:
WP2Status Init(PartitionSet partition_set, uint32_t width,
uint32_t height) override;
WP2Status CopyFrom(const SplitIteratorRecurse& other);
void SplitCurrentBlock(uint32_t split_idx) override;
void NextBlock() override;
const SplitInfo& CurrentBlock() const override;
protected:
void GetSplittable(const Block sub_blocks[4], uint32_t num_sub_blocks,
bool splittable[4]) const override;
private:
void SetCurrentBlockLexico();
Vector<SplitInfo> block_queue_;
};
// This is the SplitIterator class that should be used by default.
typedef SplitIteratorRecurse SplitIteratorDefault;
//------------------------------------------------------------------------------
} // namespace WP2
#endif // WP2_UTILS_SPLIT_ITERATOR_H_