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 <algorithm>
9
10 #include "lib/jxl/render_pipeline/low_memory_render_pipeline.h"
11 #include "lib/jxl/render_pipeline/simple_render_pipeline.h"
12 #include "lib/jxl/sanitizers.h"
13
14 namespace jxl {
15
AddStage(std::unique_ptr<RenderPipelineStage> stage)16 void RenderPipeline::Builder::AddStage(
17 std::unique_ptr<RenderPipelineStage> stage) {
18 stages_.push_back(std::move(stage));
19 }
20
Finalize(FrameDimensions frame_dimensions)21 std::unique_ptr<RenderPipeline> RenderPipeline::Builder::Finalize(
22 FrameDimensions frame_dimensions) && {
23 #if JXL_ENABLE_ASSERT
24 // Check that the last stage is not an kInOut stage for any channel, and that
25 // there is at least one stage.
26 JXL_ASSERT(!stages_.empty());
27 for (size_t c = 0; c < num_c_; c++) {
28 JXL_ASSERT(stages_.back()->GetChannelMode(c) !=
29 RenderPipelineChannelMode::kInOut);
30 }
31 #endif
32
33 std::unique_ptr<RenderPipeline> res;
34 if (use_simple_implementation_) {
35 res = jxl::make_unique<SimpleRenderPipeline>();
36 } else {
37 res = jxl::make_unique<LowMemoryRenderPipeline>();
38 }
39 res->padding_.resize(stages_.size());
40 std::vector<size_t> channel_border(num_c_);
41 for (size_t i = stages_.size(); i > 0; i--) {
42 const auto& stage = stages_[i - 1];
43 for (size_t c = 0; c < num_c_; c++) {
44 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) {
45 channel_border[c] = DivCeil(
46 channel_border[c],
47 1 << std::max(stage->settings_.shift_x, stage->settings_.shift_y));
48 channel_border[c] +=
49 std::max(stage->settings_.border_x, stage->settings_.border_y);
50 }
51 }
52 res->padding_[i - 1] =
53 *std::max_element(channel_border.begin(), channel_border.end());
54 }
55 res->frame_dimensions_ = frame_dimensions;
56 res->uses_noise_ = uses_noise_;
57 res->group_completed_passes_.resize(frame_dimensions.num_groups);
58 res->channel_shifts_.resize(stages_.size());
59 res->channel_shifts_[0].resize(num_c_);
60 for (size_t i = 1; i < stages_.size(); i++) {
61 auto& stage = stages_[i - 1];
62 for (size_t c = 0; c < num_c_; c++) {
63 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) {
64 res->channel_shifts_[0][c].first += stage->settings_.shift_x;
65 res->channel_shifts_[0][c].second += stage->settings_.shift_y;
66 }
67 }
68 }
69 for (size_t i = 1; i < stages_.size(); i++) {
70 auto& stage = stages_[i - 1];
71 res->channel_shifts_[i].resize(num_c_);
72 for (size_t c = 0; c < num_c_; c++) {
73 if (stage->GetChannelMode(c) == RenderPipelineChannelMode::kInOut) {
74 res->channel_shifts_[i][c].first =
75 res->channel_shifts_[i - 1][c].first - stage->settings_.shift_x;
76 res->channel_shifts_[i][c].second =
77 res->channel_shifts_[i - 1][c].second - stage->settings_.shift_y;
78 }
79 }
80 }
81 res->stages_ = std::move(stages_);
82 return res;
83 }
84
GetInputBuffers(size_t group_id,size_t thread_id)85 RenderPipelineInput RenderPipeline::GetInputBuffers(size_t group_id,
86 size_t thread_id) {
87 RenderPipelineInput ret;
88 JXL_DASSERT(group_id < group_completed_passes_.size());
89 ret.group_id_ = group_id;
90 ret.thread_id_ = thread_id;
91 ret.pipeline_ = this;
92 ret.buffers_ = PrepareBuffers(group_id, thread_id);
93 return ret;
94 }
95
InputReady(size_t group_id,size_t thread_id,const std::vector<std::pair<ImageF *,Rect>> & buffers)96 void RenderPipeline::InputReady(
97 size_t group_id, size_t thread_id,
98 const std::vector<std::pair<ImageF*, Rect>>& buffers) {
99 JXL_DASSERT(group_id < group_completed_passes_.size());
100 group_completed_passes_[group_id]++;
101 for (const auto& buf : buffers) {
102 (void)buf;
103 JXL_CHECK_IMAGE_INITIALIZED(*buf.first, buf.second);
104 }
105
106 ProcessBuffers(group_id, thread_id);
107 }
108
PrepareForThreads(size_t num)109 void RenderPipeline::PrepareForThreads(size_t num) {
110 temp_buffers_.resize(num);
111 for (auto& thread_buffer : temp_buffers_) {
112 size_t size = 0;
113 for (const auto& stage : stages_) {
114 size = std::max(stage->settings_.temp_buffer_size, size);
115 }
116 if (size) {
117 thread_buffer = AllocateArray(sizeof(float) * size);
118 }
119 }
120 PrepareForThreadsInternal(num);
121 }
122
Done()123 void RenderPipelineInput::Done() {
124 JXL_ASSERT(pipeline_);
125 pipeline_->InputReady(group_id_, thread_id_, buffers_);
126 }
127
128 } // namespace jxl
129