diff --git a/src/libpisp/backend/backend.cpp b/src/libpisp/backend/backend.cpp index 88851af..dc33b96 100644 --- a/src/libpisp/backend/backend.cpp +++ b/src/libpisp/backend/backend.cpp @@ -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; } diff --git a/src/libpisp/backend/backend.hpp b/src/libpisp/backend/backend.hpp index 6b29213..cb5a4d2 100644 --- a/src/libpisp/backend/backend.hpp +++ b/src/libpisp/backend/backend.hpp @@ -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); @@ -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 diff --git a/src/libpisp/backend/backend_prepare.cpp b/src/libpisp/backend/backend_prepare.cpp index a57ac78..0c6798e 100644 --- a/src/libpisp/backend/backend_prepare.cpp +++ b/src/libpisp/backend/backend_prepare.cpp @@ -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)) @@ -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) @@ -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); @@ -794,7 +795,7 @@ std::vector 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; @@ -802,17 +803,17 @@ std::vector BackEnd::retilePipeline(TilingConfig const &tiling_config // 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; @@ -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; } diff --git a/src/libpisp/backend/tiling/crop_stage.cpp b/src/libpisp/backend/tiling/crop_stage.cpp index 81b2832..61ee9c1 100644 --- a/src/libpisp/backend/tiling/crop_stage.cpp +++ b/src/libpisp/backend/tiling/crop_stage.cpp @@ -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) { @@ -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; @@ -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(); @@ -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; @@ -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; +} diff --git a/src/libpisp/backend/tiling/crop_stage.hpp b/src/libpisp/backend/tiling/crop_stage.hpp index 2adc0d8..2708c0c 100644 --- a/src/libpisp/backend/tiling/crop_stage.hpp +++ b/src/libpisp/backend/tiling/crop_stage.hpp @@ -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_; diff --git a/src/libpisp/backend/tiling/output_stage.cpp b/src/libpisp/backend/tiling/output_stage.cpp index a526597..90a9e4d 100644 --- a/src/libpisp/backend/tiling/output_stage.cpp +++ b/src/libpisp/backend/tiling/output_stage.cpp @@ -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); } @@ -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"); } diff --git a/src/libpisp/backend/tiling/output_stage.hpp b/src/libpisp/backend/tiling/output_stage.hpp index 896589f..d3584c6 100644 --- a/src/libpisp/backend/tiling/output_stage.hpp +++ b/src/libpisp/backend/tiling/output_stage.hpp @@ -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 \ No newline at end of file diff --git a/src/libpisp/backend/tiling/pipeline.cpp b/src/libpisp/backend/tiling/pipeline.cpp index 7f7979a..a27c9a8 100644 --- a/src/libpisp/backend/tiling/pipeline.cpp +++ b/src/libpisp/backend/tiling/pipeline.cpp @@ -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) { } @@ -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_) @@ -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); diff --git a/src/libpisp/backend/tiling/pipeline.hpp b/src/libpisp/backend/tiling/pipeline.hpp index 9331028..bbf8b9f 100644 --- a/src/libpisp/backend/tiling/pipeline.hpp +++ b/src/libpisp/backend/tiling/pipeline.hpp @@ -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); @@ -46,6 +47,7 @@ class Pipeline std::vector stages_; std::vector inputs_; std::vector outputs_; + bool first_tile_; }; } // namespace tiling \ No newline at end of file diff --git a/src/libpisp/backend/tiling/pisp_tiling.cpp b/src/libpisp/backend/tiling/pisp_tiling.cpp index c66c878..cd88d2a 100644 --- a/src/libpisp/backend/tiling/pisp_tiling.cpp +++ b/src/libpisp/backend/tiling/pisp_tiling.cpp @@ -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 crop_stages[NumOutputBranches]; std::unique_ptr downscale_stages[NumOutputBranches]; std::unique_ptr resample_stages[NumOutputBranches]; std::unique_ptr output_stages[NumOutputBranches]; @@ -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( + 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. diff --git a/src/libpisp/backend/tiling/pisp_tiling.hpp b/src/libpisp/backend/tiling/pisp_tiling.hpp index 9e0b71c..ad3217e 100644 --- a/src/libpisp/backend/tiling/pisp_tiling.hpp +++ b/src/libpisp/backend/tiling/pisp_tiling.hpp @@ -22,7 +22,7 @@ struct Tile tiling::Region input; tiling::Region decompress; tiling::Region context; - tiling::Region crop; + tiling::Region crop[NumOutputBranches]; tiling::Region downscale[NumOutputBranches]; tiling::Region resample[NumOutputBranches]; tiling::Region output[NumOutputBranches]; @@ -31,7 +31,7 @@ struct Tile struct TilingConfig { tiling::Length2 input_image_size; - tiling::Interval2 crop; + tiling::Interval2 crop[NumOutputBranches]; tiling::Length2 downscale_image_size[NumOutputBranches]; tiling::Length2 output_image_size[NumOutputBranches]; tiling::Length2 max_tile_size; @@ -51,9 +51,9 @@ inline std::ostream &operator<<(std::ostream &os, TilingConfig const &tc) { os << "TilingConfig:" << std::endl; os << "\tinput_image_size " << tc.input_image_size << " align " << tc.input_alignment << std::endl; - os << "\tcrop " << tc.crop << std::endl; for (int i = 0; i < NumOutputBranches; i++) { + os << "\tcrop[" << i << "] " << tc.crop[i] << std::endl; os << "\toutput_image_size[" << i << "] " << tc.output_image_size[i] << " align max " << tc.output_max_alignment[i] << " min " << tc.output_min_alignment[i] << std::endl; os << "\tdownscale_image_size " << tc.downscale_image_size[i] << " downscale_factor " << tc.downscale_factor[i] diff --git a/src/libpisp/backend/tiling/rescale_stage.cpp b/src/libpisp/backend/tiling/rescale_stage.cpp index d55b091..c15fc8d 100644 --- a/src/libpisp/backend/tiling/rescale_stage.cpp +++ b/src/libpisp/backend/tiling/rescale_stage.cpp @@ -34,8 +34,11 @@ void RescaleStage::PushStartUp(int output_start, Dir dir) int input_start_P = output_start * config_.scale[dir]; int input_start = input_start_P >> config_.precision; int input_start_w_context = input_start - config_.start_context[dir]; - - if (input_start_w_context < 0) + // input_start_w_context is allowed to go negative here if, for example, the branch starts producing output + // on the second tile in a row/column and the resampler requires left context pixels. In such cases, the left/top + // edge flag will not be set on the tile and the hardware cannot remove the left/top context pixels. So allow + // negative values on all but the left/top edge tile. + if (GetPipeline()->FirstTile() && input_start_w_context < 0) input_start_w_context = 0; output_interval_.offset = output_start; input_interval_.offset = input_start_w_context; diff --git a/src/libpisp/backend/tiling/rescale_stage.hpp b/src/libpisp/backend/tiling/rescale_stage.hpp index a371a6e..d178bc9 100644 --- a/src/libpisp/backend/tiling/rescale_stage.hpp +++ b/src/libpisp/backend/tiling/rescale_stage.hpp @@ -46,7 +46,7 @@ class RescaleStage : public BasicStage private: Config config_; - uint32_t round_up; + int round_up; }; } // namespace tiling diff --git a/src/libpisp/backend/tiling/split_stage.cpp b/src/libpisp/backend/tiling/split_stage.cpp index 54d0b07..db9daf6 100644 --- a/src/libpisp/backend/tiling/split_stage.cpp +++ b/src/libpisp/backend/tiling/split_stage.cpp @@ -49,7 +49,13 @@ void SplitStage::PushStartUp(int output_start, Dir dir) input_interval_ = Interval(output_start); else input_interval_ |= output_start; - if (count_ == downstream_.size()) + + unsigned int branch_incomplete_count = 0; + for (auto const &d : downstream_) + if (!d->BranchComplete()) + branch_incomplete_count++; + + if (count_ == branch_incomplete_count) { count_ = 0; PISP_LOG(debug, "(" << name_ << ") Exit - call PushStartUp with " << input_interval_.offset); @@ -67,6 +73,8 @@ int SplitStage::PushEndDown(int input_end, Dir dir) input_interval_.SetEnd(0); for (auto d : downstream_) { + if (d->BranchComplete()) + continue; int branch_end = d->PushEndDown(input_end, dir); // (It is OK for a branch to make no progress at all - so long as another branch does!) if (branch_end > input_interval_.End()) @@ -82,7 +90,8 @@ int SplitStage::PushEndDown(int input_end, Dir dir) } for (auto d : downstream_) - d->PushEndDown(input_interval_.End(), dir); + if (!d->BranchComplete()) + d->PushEndDown(input_interval_.End(), dir); PushEndUp(input_interval_.End(), dir); return input_interval_.End(); @@ -105,6 +114,8 @@ void SplitStage::PushCropDown(Interval interval, Dir dir) input_interval_ = interval; for (auto d : downstream_) { + if (d->BranchComplete()) + continue; PISP_LOG(debug, "(" << name_ << ") Exit with interval " << interval); d->PushCropDown(interval, dir); } @@ -113,3 +124,18 @@ void SplitStage::PushCropDown(Interval interval, Dir dir) void SplitStage::CopyOut([[maybe_unused]] void *dest, [[maybe_unused]] Dir dir) { } + +bool SplitStage::BranchComplete() const +{ + bool done = true; + for (auto d : downstream_) + done &= d->BranchComplete(); + return done; +} + +bool SplitStage::BranchInactive() const +{ + if (!upstream_) + return false; + return upstream_->BranchInactive(); +} diff --git a/src/libpisp/backend/tiling/split_stage.hpp b/src/libpisp/backend/tiling/split_stage.hpp index 44dc4cb..58764d9 100644 --- a/src/libpisp/backend/tiling/split_stage.hpp +++ b/src/libpisp/backend/tiling/split_stage.hpp @@ -26,6 +26,8 @@ class SplitStage : public Stage virtual void PushEndUp(int output_end, Dir dir); virtual void PushCropDown(Interval interval, Dir dir); virtual void CopyOut(void *dest, Dir dir); + virtual bool BranchComplete() const; + virtual bool BranchInactive() const; private: Stage *upstream_; diff --git a/src/libpisp/backend/tiling/stages.cpp b/src/libpisp/backend/tiling/stages.cpp index 196a79c..bba4f6a 100644 --- a/src/libpisp/backend/tiling/stages.cpp +++ b/src/libpisp/backend/tiling/stages.cpp @@ -6,6 +6,7 @@ */ #include "stages.hpp" +#include "common/logging.hpp" #include "pipeline.hpp" #include @@ -74,8 +75,25 @@ void BasicStage::CopyOut(void *dest, Dir dir) if (struct_offset_ >= 0) { Region *region = (Region *)((uint8_t *)dest + struct_offset_); + + PISP_LOG(debug, "(" << name_ << ") complete: " << BranchComplete() << " inactive: " << BranchInactive()); + if (BranchComplete() || BranchInactive()) + BasicStage::Reset(); + region->input[dir] = input_interval_; region->crop[dir] = crop_; region->output[dir] = output_interval_; } } + +bool BasicStage::BranchComplete() const +{ + return downstream_->BranchComplete(); +} + +bool BasicStage::BranchInactive() const +{ + if (!upstream_) + return false; + return upstream_->BranchInactive(); +} diff --git a/src/libpisp/backend/tiling/stages.hpp b/src/libpisp/backend/tiling/stages.hpp index b752a06..bca01ba 100644 --- a/src/libpisp/backend/tiling/stages.hpp +++ b/src/libpisp/backend/tiling/stages.hpp @@ -36,6 +36,8 @@ class Stage virtual void PushEndUp(int output_end, Dir dir) = 0; virtual void PushCropDown(Interval interval, Dir dir) = 0; virtual void CopyOut(void *dest, Dir dir) = 0; + virtual bool BranchComplete() const = 0; + virtual bool BranchInactive() const = 0; void MergeRegions(void *dest, void *x_src, void *y_src) const; protected: @@ -55,6 +57,8 @@ class BasicStage : public Stage virtual void SetDownstream(Stage *downstream); virtual void Reset(); virtual void CopyOut(void *dest, Dir dir); + virtual bool BranchComplete() const; + virtual bool BranchInactive() const; protected: Stage *upstream_;