render_pipeline.h (5019B)
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 #ifndef LIB_JXL_RENDER_PIPELINE_RENDER_PIPELINE_H_ 7 #define LIB_JXL_RENDER_PIPELINE_RENDER_PIPELINE_H_ 8 9 #include <jxl/memory_manager.h> 10 11 #include <algorithm> 12 #include <cstddef> 13 #include <cstdint> 14 #include <memory> 15 #include <utility> 16 #include <vector> 17 18 #include "lib/jxl/base/rect.h" 19 #include "lib/jxl/base/status.h" 20 #include "lib/jxl/frame_dimensions.h" 21 #include "lib/jxl/image.h" 22 #include "lib/jxl/render_pipeline/render_pipeline_stage.h" 23 24 namespace jxl { 25 26 // Interface to provide input to the rendering pipeline. When this object is 27 // destroyed, all the data in the provided ImageF's Rects must have been 28 // initialized. 29 class RenderPipelineInput { 30 public: 31 RenderPipelineInput(const RenderPipelineInput&) = delete; 32 RenderPipelineInput(RenderPipelineInput&& other) noexcept { 33 *this = std::move(other); 34 } 35 RenderPipelineInput& operator=(RenderPipelineInput&& other) noexcept { 36 pipeline_ = other.pipeline_; 37 group_id_ = other.group_id_; 38 thread_id_ = other.thread_id_; 39 buffers_ = std::move(other.buffers_); 40 other.pipeline_ = nullptr; 41 return *this; 42 } 43 44 RenderPipelineInput() = default; 45 Status Done(); 46 47 const std::pair<ImageF*, Rect>& GetBuffer(size_t c) const { 48 JXL_DASSERT(c < buffers_.size()); 49 return buffers_[c]; 50 } 51 52 private: 53 RenderPipeline* pipeline_ = nullptr; 54 size_t group_id_; 55 size_t thread_id_; 56 std::vector<std::pair<ImageF*, Rect>> buffers_; 57 friend class RenderPipeline; 58 }; 59 60 class RenderPipeline { 61 public: 62 class Builder { 63 public: 64 explicit Builder(JxlMemoryManager* memory_manager, size_t num_c) 65 : memory_manager_(memory_manager), num_c_(num_c) { 66 JXL_DASSERT(num_c > 0); 67 } 68 69 // Adds a stage to the pipeline. Must be called at least once; the last 70 // added stage cannot have kInOut channels. 71 Status AddStage(std::unique_ptr<RenderPipelineStage> stage); 72 73 // Enables using the simple (i.e. non-memory-efficient) implementation of 74 // the pipeline. 75 void UseSimpleImplementation() { use_simple_implementation_ = true; } 76 77 // Finalizes setup of the pipeline. Shifts for all channels should be 0 at 78 // this point. 79 StatusOr<std::unique_ptr<RenderPipeline>> Finalize( 80 FrameDimensions frame_dimensions) &&; 81 82 private: 83 JxlMemoryManager* memory_manager_; 84 std::vector<std::unique_ptr<RenderPipelineStage>> stages_; 85 size_t num_c_; 86 bool use_simple_implementation_ = false; 87 }; 88 89 friend class Builder; 90 91 virtual ~RenderPipeline() = default; 92 93 Status IsInitialized() const { 94 for (const auto& stage : stages_) { 95 JXL_RETURN_IF_ERROR(stage->IsInitialized()); 96 } 97 return true; 98 } 99 100 // Allocates storage to run with `num` threads. If `use_group_ids` is true, 101 // storage is allocated for each group, not each thread. The behaviour is 102 // undefined if calling this function multiple times with a different value 103 // for `use_group_ids`. 104 Status PrepareForThreads(size_t num, bool use_group_ids); 105 106 // Retrieves a buffer where input data should be stored by the callee. When 107 // input has been provided for all buffers, the pipeline will complete its 108 // processing. This method may be called multiple times concurrently from 109 // different threads, provided that a different `thread_id` is given. 110 RenderPipelineInput GetInputBuffers(size_t group_id, size_t thread_id); 111 112 size_t PassesWithAllInput() const { 113 return *std::min_element(group_completed_passes_.begin(), 114 group_completed_passes_.end()); 115 } 116 117 virtual void ClearDone(size_t i) {} 118 119 protected: 120 explicit RenderPipeline(JxlMemoryManager* memory_manager) 121 : memory_manager_(memory_manager) {} 122 JxlMemoryManager* memory_manager_; 123 124 std::vector<std::unique_ptr<RenderPipelineStage>> stages_; 125 // Shifts for every channel at the input of each stage. 126 std::vector<std::vector<std::pair<size_t, size_t>>> channel_shifts_; 127 128 // Amount of (cumulative) padding required by each stage and channel, in 129 // either direction. 130 std::vector<std::vector<std::pair<size_t, size_t>>> padding_; 131 132 FrameDimensions frame_dimensions_; 133 134 std::vector<uint8_t> group_completed_passes_; 135 136 friend class RenderPipelineInput; 137 138 private: 139 Status InputReady(size_t group_id, size_t thread_id, 140 const std::vector<std::pair<ImageF*, Rect>>& buffers); 141 142 virtual std::vector<std::pair<ImageF*, Rect>> PrepareBuffers( 143 size_t group_id, size_t thread_id) = 0; 144 145 virtual Status ProcessBuffers(size_t group_id, size_t thread_id) = 0; 146 147 // Note that this method may be called multiple times with different (or 148 // equal) `num`. 149 virtual Status PrepareForThreadsInternal(size_t num, bool use_group_ids) = 0; 150 151 // Called once frame dimensions and stages are known. 152 virtual Status Init() { return true; } 153 }; 154 155 } // namespace jxl 156 157 #endif // LIB_JXL_RENDER_PIPELINE_RENDER_PIPELINE_H_