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