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_STAGE_H_ 7 #define LIB_JXL_RENDER_PIPELINE_RENDER_PIPELINE_STAGE_H_ 8 9 #include <stdint.h> 10 11 #include "lib/jxl/filters.h" 12 13 namespace jxl { 14 15 // The first pixel in the input to RenderPipelineStage will be located at 16 // this position. Pixels before this position may be accessed as padding. 17 constexpr size_t kRenderPipelineXOffset = 16; 18 19 enum class RenderPipelineChannelMode { 20 // This channel is not modified by this stage. 21 kIgnored = 0, 22 // This channel is modified in-place. 23 kInPlace = 1, 24 // This channel is modified and written to a new buffer. 25 kInOut = 2, 26 // This channel is only read. 27 kInput = 3, 28 }; 29 30 class RenderPipeline; 31 32 class RenderPipelineStage { 33 protected: 34 using Row = float*; 35 using ChannelRows = std::vector<Row>; 36 using RowInfo = std::vector<ChannelRows>; 37 38 public: 39 struct Settings { 40 // Amount of padding required in the various directions by all channels 41 // that have kInOut mode. 42 size_t border_x = 0; 43 size_t border_y = 0; 44 45 // Log2 of the number of columns/rows of output that this stage will produce 46 // for every input row for kInOut channels. 47 size_t shift_x = 0; 48 size_t shift_y = 0; 49 50 // Size (in floats) of the (aligned) per-thread temporary buffer to pass to 51 // ProcessRow. 52 size_t temp_buffer_size = 0; 53 ShiftXSettings54 static Settings ShiftX(size_t shift, size_t border) { 55 Settings settings; 56 settings.border_x = border; 57 settings.shift_x = shift; 58 return settings; 59 } 60 ShiftYSettings61 static Settings ShiftY(size_t shift, size_t border) { 62 Settings settings; 63 settings.border_y = border; 64 settings.shift_y = shift; 65 return settings; 66 } 67 68 static Settings Symmetric(size_t shift, size_t border, 69 size_t temp_buffer_size = 0) { 70 Settings settings; 71 settings.border_x = settings.border_y = border; 72 settings.shift_x = settings.shift_y = shift; 73 return settings; 74 } 75 SymmetricBorderOnlySettings76 static Settings SymmetricBorderOnly(size_t border) { 77 return Symmetric(0, border); 78 } 79 }; 80 81 virtual ~RenderPipelineStage() = default; 82 83 protected: IsInitialized()84 virtual Status IsInitialized() const { return true; } 85 86 // Processes one row of input, producing the appropriate number of rows of 87 // output. Input/output rows can be obtained by calls to 88 // `GetInputRow`/`GetOutputRow`. `xsize+2*xextra` represents the total number 89 // of pixels to be processed in the input row, where the first pixel is at 90 // position `kRenderPipelineXOffset-xextra`. All pixels in the 91 // `[kRenderPipelineXOffset-xextra-border_x, 92 // kRenderPipelineXOffset+xsize+xextra+border_x)` range are initialized and 93 // accessible. `xpos` and `ypos` represent the position of the first 94 // (non-extra, i.e. in position kRenderPipelineXOffset) pixel in the center 95 // row of the input in the full image. `xpos` is a multiple of 96 // `GroupBorderAssigner::kPaddingXRound`. If `settings_.temp_buffer_size` is 97 // nonzero, `temp` will point to an HWY-aligned buffer of at least that number 98 // of floats; concurrent calls will have different buffers. 99 virtual void ProcessRow(const RowInfo& input_rows, const RowInfo& output_rows, 100 size_t xextra, size_t xsize, size_t xpos, size_t ypos, 101 float* JXL_RESTRICT temp) const = 0; 102 103 // How each channel will be processed. Channels are numbered starting from 104 // color channels (always 3) and followed by all other channels. 105 virtual RenderPipelineChannelMode GetChannelMode(size_t c) const = 0; 106 RenderPipelineStage(Settings settings)107 explicit RenderPipelineStage(Settings settings) : settings_(settings) {} 108 109 // Returns a pointer to the input row of channel `c` with offset `y`. 110 // `y` must be in [-settings_.border_y, settings_.border_y]. `c` must be such 111 // that `GetChannelMode(c) != kIgnored`. The returned pointer points to the 112 // offset-ed row (i.e. kRenderPipelineXOffset has been applied). GetInputRow(const RowInfo & input_rows,size_t c,int offset)113 float* GetInputRow(const RowInfo& input_rows, size_t c, int offset) const { 114 JXL_DASSERT(GetChannelMode(c) != RenderPipelineChannelMode::kIgnored); 115 JXL_DASSERT(-offset <= static_cast<int>(settings_.border_y)); 116 JXL_DASSERT(offset <= static_cast<int>(settings_.border_y)); 117 return input_rows[c][settings_.border_y + offset] + kRenderPipelineXOffset; 118 } 119 // Similar to `GetInputRow`, but can only be used if `GetChannelMode(c) == 120 // kInOut`. Offset must be less than `1<<settings_.shift_y`.. The returned 121 // pointer points to the offset-ed row (i.e. kRenderPipelineXOffset has been 122 // applied). GetOutputRow(const RowInfo & output_rows,size_t c,size_t offset)123 float* GetOutputRow(const RowInfo& output_rows, size_t c, 124 size_t offset) const { 125 JXL_DASSERT(GetChannelMode(c) == RenderPipelineChannelMode::kInOut); 126 JXL_DASSERT(offset <= 1ul << settings_.shift_y); 127 return output_rows[c][offset] + kRenderPipelineXOffset; 128 } 129 130 Settings settings_; 131 friend class RenderPipeline; 132 friend class SimpleRenderPipeline; 133 friend class LowMemoryRenderPipeline; 134 }; 135 136 } // namespace jxl 137 138 #endif // LIB_JXL_RENDER_PIPELINE_RENDER_PIPELINE_STAGE_H_ 139