render_pipeline.cc (4863B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/jxl/render_pipeline/render_pipeline.h" 7 8 #include <jxl/memory_manager.h> 9 10 #include <memory> 11 #include <utility> 12 13 #include "lib/jxl/base/rect.h" 14 #include "lib/jxl/base/sanitizers.h" 15 #include "lib/jxl/base/status.h" 16 #include "lib/jxl/render_pipeline/low_memory_render_pipeline.h" 17 #include "lib/jxl/render_pipeline/simple_render_pipeline.h" 18 19 namespace jxl { 20 21 Status RenderPipeline::Builder::AddStage( 22 std::unique_ptr<RenderPipelineStage> stage) { 23 if (!stage) return JXL_FAILURE("internal: no stage to add"); 24 stages_.push_back(std::move(stage)); 25 return true; 26 } 27 28 StatusOr<std::unique_ptr<RenderPipeline>> RenderPipeline::Builder::Finalize( 29 FrameDimensions frame_dimensions) && { 30 // Check that the last stage is not a kInOut stage for any channel, and that 31 // there is at least one stage. 32 JXL_ENSURE(!stages_.empty()); 33 for (size_t c = 0; c < num_c_; c++) { 34 JXL_ENSURE(stages_.back()->GetChannelMode(c) != 35 RenderPipelineChannelMode::kInOut); 36 } 37 38 std::unique_ptr<RenderPipeline> res; 39 if (use_simple_implementation_) { 40 res = jxl::make_unique<SimpleRenderPipeline>(memory_manager_); 41 } else { 42 res = jxl::make_unique<LowMemoryRenderPipeline>(memory_manager_); 43 } 44 45 res->padding_.resize(stages_.size()); 46 for (size_t i = stages_.size(); i-- > 0;) { 47 const auto& stage = stages_[i]; 48 res->padding_[i].resize(num_c_); 49 if (i + 1 == stages_.size()) { 50 continue; 51 } 52 for (size_t c = 0; c < num_c_; c++) { 53 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) { 54 res->padding_[i][c].first = DivCeil(res->padding_[i + 1][c].first, 55 1 << stage->settings_.shift_x) + 56 stage->settings_.border_x; 57 res->padding_[i][c].second = DivCeil(res->padding_[i + 1][c].second, 58 1 << stage->settings_.shift_y) + 59 stage->settings_.border_y; 60 } else { 61 res->padding_[i][c] = res->padding_[i + 1][c]; 62 } 63 } 64 } 65 66 res->frame_dimensions_ = frame_dimensions; 67 res->group_completed_passes_.resize(frame_dimensions.num_groups); 68 res->channel_shifts_.resize(stages_.size()); 69 res->channel_shifts_[0].resize(num_c_); 70 for (size_t i = 1; i < stages_.size(); i++) { 71 auto& stage = stages_[i - 1]; 72 for (size_t c = 0; c < num_c_; c++) { 73 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) { 74 res->channel_shifts_[0][c].first += stage->settings_.shift_x; 75 res->channel_shifts_[0][c].second += stage->settings_.shift_y; 76 } 77 } 78 } 79 for (size_t i = 1; i < stages_.size(); i++) { 80 auto& stage = stages_[i - 1]; 81 res->channel_shifts_[i].resize(num_c_); 82 for (size_t c = 0; c < num_c_; c++) { 83 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) { 84 res->channel_shifts_[i][c].first = 85 res->channel_shifts_[i - 1][c].first - stage->settings_.shift_x; 86 res->channel_shifts_[i][c].second = 87 res->channel_shifts_[i - 1][c].second - stage->settings_.shift_y; 88 } else { 89 res->channel_shifts_[i][c].first = res->channel_shifts_[i - 1][c].first; 90 res->channel_shifts_[i][c].second = 91 res->channel_shifts_[i - 1][c].second; 92 } 93 } 94 } 95 res->stages_ = std::move(stages_); 96 JXL_RETURN_IF_ERROR(res->Init()); 97 return res; 98 } 99 100 RenderPipelineInput RenderPipeline::GetInputBuffers(size_t group_id, 101 size_t thread_id) { 102 RenderPipelineInput ret; 103 JXL_DASSERT(group_id < group_completed_passes_.size()); 104 ret.group_id_ = group_id; 105 ret.thread_id_ = thread_id; 106 ret.pipeline_ = this; 107 ret.buffers_ = PrepareBuffers(group_id, thread_id); 108 return ret; 109 } 110 111 Status RenderPipeline::InputReady( 112 size_t group_id, size_t thread_id, 113 const std::vector<std::pair<ImageF*, Rect>>& buffers) { 114 JXL_ENSURE(group_id < group_completed_passes_.size()); 115 group_completed_passes_[group_id]++; 116 for (size_t i = 0; i < buffers.size(); ++i) { 117 (void)i; 118 JXL_CHECK_PLANE_INITIALIZED(*buffers[i].first, buffers[i].second, i); 119 } 120 121 JXL_RETURN_IF_ERROR(ProcessBuffers(group_id, thread_id)); 122 return true; 123 } 124 125 Status RenderPipeline::PrepareForThreads(size_t num, bool use_group_ids) { 126 for (const auto& stage : stages_) { 127 JXL_RETURN_IF_ERROR(stage->PrepareForThreads(num)); 128 } 129 JXL_RETURN_IF_ERROR(PrepareForThreadsInternal(num, use_group_ids)); 130 return true; 131 } 132 133 Status RenderPipelineInput::Done() { 134 JXL_ENSURE(pipeline_); 135 JXL_RETURN_IF_ERROR(pipeline_->InputReady(group_id_, thread_id_, buffers_)); 136 return true; 137 } 138 139 } // namespace jxl