Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple crops #32

Merged
merged 7 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/libpisp/backend/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,16 @@ void BackEnd::GetGamma(pisp_be_gamma_config &gamma)

void BackEnd::SetCrop(pisp_be_crop_config const &crop)
{
be_config_extra_.crop = crop;
for (unsigned int i = 0; i < variant_.BackEndNumBranches(0); i++)
be_config_extra_.crop[i] = crop;
be_config_extra_.dirty_flags_extra |= PISP_BE_DIRTY_CROP;
retile_ = true;
}

void BackEnd::SetCrop(unsigned int i, pisp_be_crop_config const &crop)
{
PISP_ASSERT(i < variant_.BackEndNumBranches(0));
be_config_extra_.crop[i] = crop;
be_config_extra_.dirty_flags_extra |= PISP_BE_DIRTY_CROP;
retile_ = true;
}
Expand Down
3 changes: 2 additions & 1 deletion src/libpisp/backend/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class BackEnd final
void SetGamma(pisp_be_gamma_config const &gamma);
void GetGamma(pisp_be_gamma_config &gamma);
void SetCrop(pisp_be_crop_config const &crop);
void SetCrop(unsigned int i, pisp_be_crop_config const &crop);
void SetCsc(unsigned int i, pisp_be_ccm_config const &csc);
void GetCsc(unsigned int i, pisp_be_ccm_config &csc);
void SetOutputFormat(unsigned int i, pisp_be_output_format_config const &output_format);
Expand Down Expand Up @@ -155,7 +156,7 @@ class BackEnd final
pisp_be_cac_extra cac;
pisp_be_downscale_extra downscale[PISP_BACK_END_NUM_OUTPUTS];
pisp_be_resample_extra resample[PISP_BACK_END_NUM_OUTPUTS];
pisp_be_crop_config crop;
pisp_be_crop_config crop[PISP_BACK_END_NUM_OUTPUTS];
uint32_t dirty_flags_bayer; //these use pisp_be_bayer_enable
uint32_t dirty_flags_rgb; //use pisp_be_rgb_enable
uint32_t dirty_flags_extra; //these use pisp_be_dirty_t
Expand Down
45 changes: 23 additions & 22 deletions src/libpisp/backend/backend_prepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,9 +488,9 @@ void BackEnd::finaliseConfig()
if (enabled)
{
// crop is enabled when it contains non-zero width/height
uint16_t w = be_config_extra_.crop.width ? be_config_extra_.crop.width
uint16_t w = be_config_extra_.crop[j].width ? be_config_extra_.crop[j].width
: be_config_.input_format.width;
uint16_t h = be_config_extra_.crop.width ? be_config_extra_.crop.height
uint16_t h = be_config_extra_.crop[j].width ? be_config_extra_.crop[j].height
: be_config_.input_format.height;

if (dirty_flags_rgb & PISP_BE_RGB_ENABLE_DOWNSCALE(j))
Expand Down Expand Up @@ -537,18 +537,18 @@ void BackEnd::updateSmartResize()
{
std::string filter;

// First get the size of the input to the rescalers. The crops are zero when not in use.
uint16_t input_width = be_config_extra_.crop.width;
if (!input_width)
input_width = be_config_.input_format.width;
uint16_t input_height = be_config_extra_.crop.height;
if (!input_height)
input_height = be_config_.input_format.height;

// Look through the output branches adjusting the scaling blocks where "smart resizing"
// has been requested.
for (unsigned int i = 0; i < variant_.BackEndNumBranches(0); i++)
{
// First get the size of the input to the rescalers. The crops are zero when not in use.
uint16_t input_width = be_config_extra_.crop[i].width;
if (!input_width)
input_width = be_config_.input_format.width;
uint16_t input_height = be_config_extra_.crop[i].height;
if (!input_height)
input_height = be_config_.input_format.height;

if ((smart_resize_dirty_ & (1 << i)) || (be_config_extra_.dirty_flags_extra & PISP_BE_DIRTY_CROP))
{
if (smart_resize_[i].width && smart_resize_[i].height)
Expand Down Expand Up @@ -691,15 +691,16 @@ void BackEnd::updateTiles()
PISP_LOG(debug, "Input alignments are " << tiling_config.input_alignment << " pixels");

tiling_config.input_image_size = tiling::Length2(c.input_format.width, c.input_format.height);
tiling_config.crop = tiling::Interval2(tiling::Interval(ce.crop.offset_x, ce.crop.width),
tiling::Interval(ce.crop.offset_y, ce.crop.height));

if (tiling_config.crop.x.length == 0 || tiling_config.crop.y.length == 0)
tiling_config.crop = tiling::Interval2(tiling::Interval(0, c.input_format.width),
tiling::Interval(0, c.input_format.height));

for (unsigned int i = 0; i < variant_.BackEndNumBranches(0); i++)
{
tiling_config.crop[i] = tiling::Interval2(tiling::Interval(ce.crop[i].offset_x, ce.crop[i].width),
tiling::Interval(ce.crop[i].offset_y, ce.crop[i].height));

if (tiling_config.crop[i].x.length == 0 || tiling_config.crop[i].y.length == 0)
tiling_config.crop[i] = tiling::Interval2(tiling::Interval(0, c.input_format.width),
tiling::Interval(0, c.input_format.height));

tiling_config.output_h_mirror[i] = be_config_.output_format[i].transform & PISP_BE_TRANSFORM_HFLIP;
tiling_config.downscale_factor[i] =
tiling::Length2(c.downscale[i].scale_factor_h, c.downscale[i].scale_factor_v);
Expand Down Expand Up @@ -794,25 +795,25 @@ std::vector<pisp_tile> BackEnd::retilePipeline(TilingConfig const &tiling_config
}

tiling::Crop2 downscale_crop;
tiling::Interval2 resample_size = tiles[i].crop.output;
tiling::Interval2 resample_size = tiles[i].crop[j].output;
resample_size.x = resample_size.x - tiles[i].resample[j].crop.x;
resample_size.y = resample_size.y - tiles[i].resample[j].crop.y;

// When a resize stage is disabled, the tile size after the stage is found from the input of the
// next block. Also there will be no extra crop necessary for the resize operation.
if (be_config_.global.rgb_enables & PISP_BE_RGB_ENABLE_DOWNSCALE(j))
{
downscale_crop = tiles[i].downscale[j].crop + tiles[i].crop.crop;
downscale_crop = tiles[i].downscale[j].crop + tiles[i].crop[j].crop;
// Size of the tile going into the resample block needs to be set here.
resample_size = tiles[i].downscale[j].output;
}
else if (be_config_.global.rgb_enables & PISP_BE_RGB_ENABLE_RESAMPLE(j))
{
downscale_crop = tiles[i].resample[j].crop + tiles[i].crop.crop;
downscale_crop = tiles[i].resample[j].crop + tiles[i].crop[j].crop;
}
else
{
downscale_crop = tiles[i].output[j].crop + tiles[i].crop.crop;
downscale_crop = tiles[i].output[j].crop + tiles[i].crop[j].crop;
}

t.crop_x_start[j] = downscale_crop.x.start;
Expand Down Expand Up @@ -952,8 +953,8 @@ void BackEnd::getOutputSize(int i, uint16_t *width, uint16_t *height, pisp_image
*width = be_config_extra_.resample[i].scaled_width, *height = be_config_extra_.resample[i].scaled_height;
else if (be_config_.global.rgb_enables & PISP_BE_RGB_ENABLE_DOWNSCALE(i))
*width = be_config_extra_.downscale[i].scaled_width, *height = be_config_extra_.downscale[i].scaled_height;
else if (be_config_extra_.crop.width) // crop width and height will be zero when crop disabled
*width = be_config_extra_.crop.width, *height = be_config_extra_.crop.height;
else if (be_config_extra_.crop[i].width) // crop width and height will be zero when crop disabled
*width = be_config_extra_.crop[i].width, *height = be_config_extra_.crop[i].height;
else
*width = ifmt.width, *height = ifmt.height;
}
Expand Down
55 changes: 54 additions & 1 deletion src/libpisp/backend/tiling/crop_stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@

using namespace tiling;

namespace
{

inline bool interval_valid(const Interval &interval, const int min_tile_size)
{
return interval.End() >= min_tile_size && interval.length >= min_tile_size;
}

} // namespace

CropStage::CropStage(char const *name, Stage *upstream, Config const &config, int struct_offset)
: BasicStage(name, upstream->GetPipeline(), upstream, struct_offset), config_(config)
{
Expand All @@ -27,6 +37,11 @@ void CropStage::PushStartUp(int output_start, Dir dir)
PISP_LOG(debug, "(" << name_ << ") Enter with output_start " << output_start);

int input_start = output_start + config_.crop[dir].offset;
// input_start can never be negative here, but it is possible to have output_start
// negative if, for example, a branch starts producing output on the second
// tile in a row (or column) and the resampler requires left (or top) context pixels.
if (input_start < 0)
throw std::runtime_error("input start is negative: " + std::to_string(input_start));
output_interval_.offset = output_start;
input_interval_.offset = input_start;

Expand All @@ -39,11 +54,26 @@ int CropStage::PushEndDown(int input_end, Dir dir)
PISP_LOG(debug, "(" << name_ << ") Enter with input_end " << input_end);

int output_end = input_end - config_.crop[dir].offset;

if (output_end > config_.crop[dir].length)
output_end = config_.crop[dir].length;
input_interval_.SetEnd(input_end);

output_interval_.SetEnd(output_end);

// If this is the first tile to generate output, ensure we can make at least
// min_tile_size of output pixels. If not, terminate iteration here and don't
// go futher downstream. Defer the output for the next tile.
//
// output_end may also be negative if no output will be generated for this tile.
if (!interval_valid(output_interval_, GetPipeline()->GetConfig().min_tile_size[dir]))
{
PISP_LOG(debug, "(" << name_ << ") Output branch not started or output too small, terminating");
BasicStage::Reset();
return 0;
}

input_interval_.SetEnd(input_end);

PISP_LOG(debug, "(" << name_ << ") Exit with output_end " << output_end);
PushEndUp(downstream_->PushEndDown(output_end, dir), dir);
return input_interval_.End();
Expand All @@ -57,12 +87,30 @@ void CropStage::PushEndUp(int output_end, Dir dir)
input_interval_.SetEnd(input_end);
output_interval_.SetEnd(output_end);

// Same check as we do in PushEndDown().
if (!interval_valid(output_interval_, GetPipeline()->GetConfig().min_tile_size[dir]))
{
PISP_LOG(debug, "(" << name_ << ") Output branch not started or output too small, terminating");
BasicStage::Reset();
return;
}

PISP_LOG(debug, "(" << name_ << ") Exit with input_end " << input_end);
}

void CropStage::PushCropDown(Interval interval, Dir dir)
{
PISP_LOG(debug, "(" << name_ << ") Enter with interval " << interval);

// Branch has not started producing output. Terminate the iteration here
// and don't go futher downstream.
if (!interval_valid(output_interval_, GetPipeline()->GetConfig().min_tile_size[dir]))
{
PISP_LOG(debug, "(" << name_ << ") Output branch not started or output too small, terminating");
BasicStage::Reset();
return;
}

PISP_ASSERT(interval > input_interval_);

input_interval_ = interval;
Expand All @@ -72,3 +120,8 @@ void CropStage::PushCropDown(Interval interval, Dir dir)
PISP_LOG(debug, "(" << name_ << ") Exit with interval " << output_interval_);
downstream_->PushCropDown(output_interval_, dir);
}

bool CropStage::BranchInactive() const
{
return !output_interval_.length;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I feel slightly weird that BranchInactive() looks at the output_interval, but BranchComplete() doesn't - it slight offends my need for symmetry. Should BranchCompletel() look at output_interval_.End() or something? Or do I worry too much?

}
11 changes: 6 additions & 5 deletions src/libpisp/backend/tiling/crop_stage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ class CropStage : public BasicStage
Interval2 crop;
};
CropStage(char const *name, Stage *upstream, Config const &config, int struct_offset);
virtual Length2 GetOutputImageSize() const;
virtual void PushStartUp(int output_start, Dir dir);
virtual int PushEndDown(int input_end, Dir dir);
virtual void PushEndUp(int output_end, Dir dir);
virtual void PushCropDown(Interval interval, Dir dir);
virtual Length2 GetOutputImageSize() const override;
virtual void PushStartUp(int output_start, Dir dir) override;
virtual int PushEndDown(int input_end, Dir dir) override;
virtual void PushEndUp(int output_end, Dir dir) override;
virtual void PushCropDown(Interval interval, Dir dir) override;
bool BranchInactive() const override;

private:
Config config_;
Expand Down
18 changes: 15 additions & 3 deletions src/libpisp/backend/tiling/output_stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ using namespace tiling;
// the offset/length from the LH edge).

OutputStage::OutputStage(char const *name, Stage *upstream, Config const &config, int struct_offset)
: BasicStage(name, upstream->GetPipeline(), upstream, struct_offset), config_(config)
: BasicStage(name, upstream->GetPipeline(), upstream, struct_offset), config_(config), branch_complete_(false)
{
pipeline_->AddOutputStage(this);
}
Expand Down Expand Up @@ -118,7 +118,19 @@ void OutputStage::PushCropDown(Interval interval, [[maybe_unused]] Dir dir)
PISP_LOG(debug, "(" << name_ << ") Exit with interval " << output_interval_);
}

bool OutputStage::Done(Dir dir) const
void OutputStage::Reset()
{
return output_interval_.End() >= GetOutputImageSize()[dir];
BasicStage::Reset();
branch_complete_ = false;
}

bool OutputStage::GetBranchComplete() const
{
return branch_complete_;
}

void OutputStage::SetBranchComplete()
{
branch_complete_ = true;
PISP_LOG(debug, "(" << name_ << ") Setting branch complete");
}
5 changes: 4 additions & 1 deletion src/libpisp/backend/tiling/output_stage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ class OutputStage : public BasicStage
virtual int PushEndDown(int input_end, Dir dir);
virtual void PushEndUp(int output_end, Dir dir);
virtual void PushCropDown(Interval interval, Dir dir);
bool Done(Dir dir) const;
virtual void Reset();
bool GetBranchComplete() const;
void SetBranchComplete();

private:
Config config_;
bool branch_complete_;
};

} // namespace tiling
18 changes: 15 additions & 3 deletions src/libpisp/backend/tiling/pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

using namespace tiling;

Pipeline::Pipeline(char const *name, Config const &config) : name_(name), config_(config)
Pipeline::Pipeline(char const *name, Config const &config) : name_(name), config_(config), first_tile_(false)
{
}

Expand Down Expand Up @@ -74,13 +74,17 @@ int Pipeline::tileDirection(Dir dir, void *mem, size_t num_items, size_t item_si
reset();
bool done = false;
unsigned int num_tiles = 0;
first_tile_ = true;
for (; !done; num_tiles++)
{
PISP_LOG(debug, "----------------------------------------------------------------");
if (num_tiles == num_items)
throw std::runtime_error("Too many tiles!");
for (auto s : outputs_)
s->PushStartUp(s->GetOutputInterval().End(), dir);
{
if (!s->BranchComplete())
s->PushStartUp(s->GetOutputInterval().End(), dir);
}
for (auto s : inputs_)
s->PushEndDown(s->GetInputInterval().offset + config_.max_tile_size[dir], dir);
for (auto s : inputs_)
Expand All @@ -90,7 +94,15 @@ int Pipeline::tileDirection(Dir dir, void *mem, size_t num_items, size_t item_si
s->CopyOut(dest, dir);
done = true;
for (auto s : outputs_)
done &= s->Done(dir);
{
if (s->GetBranchComplete())
continue;
else if (s->GetOutputInterval().End() >= s->GetOutputImageSize()[dir])
s->SetBranchComplete();
else
done = false;
}
first_tile_ = false;
}

PISP_LOG(debug, "Made " << num_tiles << " tiles in direction " << dir);
Expand Down
2 changes: 2 additions & 0 deletions src/libpisp/backend/tiling/pipeline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Pipeline
void AddInputStage(InputStage *input_stage);
void AddOutputStage(OutputStage *output_stage);
void Tile(void *mem, size_t num_items, size_t item_size, Length2 *grid);
bool FirstTile() const { return first_tile_; }

private:
int tileDirection(Dir dir, void *mem, size_t num_items, size_t item_size);
Expand All @@ -46,6 +47,7 @@ class Pipeline
std::vector<Stage *> stages_;
std::vector<InputStage *> inputs_;
std::vector<OutputStage *> outputs_;
bool first_tile_;
};

} // namespace tiling
11 changes: 7 additions & 4 deletions src/libpisp/backend/tiling/pisp_tiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ void tile_pipeline(TilingConfig const &config, Tile *tiles, int num_tiles, Lengt
Length2(PipelineAlignX, PipelineAlignY));
ContextStage context_stage("context", &input_stage, context_config, offsetof(Tile, context));

CropStage::Config crop_config(config.crop);
CropStage crop_stage("crop", &context_stage, crop_config, offsetof(Tile, crop));

SplitStage split_stage("split", &crop_stage);
SplitStage split_stage("split", &context_stage);

std::unique_ptr<Stage> crop_stages[NumOutputBranches];
std::unique_ptr<Stage> downscale_stages[NumOutputBranches];
std::unique_ptr<Stage> resample_stages[NumOutputBranches];
std::unique_ptr<Stage> output_stages[NumOutputBranches];
Expand All @@ -74,6 +72,11 @@ void tile_pipeline(TilingConfig const &config, Tile *tiles, int num_tiles, Lengt
char name[32];
Stage *prev_stage = &split_stage;

sprintf(name, "crop%d", i);
crop_stages[i] = std::unique_ptr<Stage>(
new CropStage(name, prev_stage, config.crop[i], offsetof(Tile, crop) + i * sizeof(Region)));
prev_stage = crop_stages[i].get();

// There's a little awkwardness if the resize blocks (downscale and resample) are not enabled. Resize *does* change the output tile
// size, even if it's doing a 1-to-1 scaling (it loses context), so we must leave it out of the tiling
// calculation.
Expand Down
Loading
Loading