summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc')
-rw-r--r--third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc153
1 files changed, 153 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc b/third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc
new file mode 100644
index 0000000000..f3002a5ac3
--- /dev/null
+++ b/third_party/jpeg-xl/lib/jxl/modular/transform/rct.cc
@@ -0,0 +1,153 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "lib/jxl/modular/transform/rct.h"
+#undef HWY_TARGET_INCLUDE
+#define HWY_TARGET_INCLUDE "lib/jxl/modular/transform/rct.cc"
+#include <hwy/foreach_target.h>
+#include <hwy/highway.h>
+HWY_BEFORE_NAMESPACE();
+namespace jxl {
+namespace HWY_NAMESPACE {
+
+// These templates are not found via ADL.
+using hwy::HWY_NAMESPACE::Add;
+using hwy::HWY_NAMESPACE::ShiftRight;
+using hwy::HWY_NAMESPACE::Sub;
+
+template <int transform_type>
+void InvRCTRow(const pixel_type* in0, const pixel_type* in1,
+ const pixel_type* in2, pixel_type* out0, pixel_type* out1,
+ pixel_type* out2, size_t w) {
+ static_assert(transform_type >= 0 && transform_type < 7,
+ "Invalid transform type");
+ int second = transform_type >> 1;
+ int third = transform_type & 1;
+
+ size_t x = 0;
+ const HWY_FULL(pixel_type) d;
+ const size_t N = Lanes(d);
+ for (; x + N - 1 < w; x += N) {
+ if (transform_type == 6) {
+ auto Y = Load(d, in0 + x);
+ auto Co = Load(d, in1 + x);
+ auto Cg = Load(d, in2 + x);
+ Y = Sub(Y, ShiftRight<1>(Cg));
+ auto G = Add(Cg, Y);
+ Y = Sub(Y, ShiftRight<1>(Co));
+ auto R = Add(Y, Co);
+ Store(R, d, out0 + x);
+ Store(G, d, out1 + x);
+ Store(Y, d, out2 + x);
+ } else {
+ auto First = Load(d, in0 + x);
+ auto Second = Load(d, in1 + x);
+ auto Third = Load(d, in2 + x);
+ if (third) Third = Add(Third, First);
+ if (second == 1) {
+ Second = Add(Second, First);
+ } else if (second == 2) {
+ Second = Add(Second, ShiftRight<1>(Add(First, Third)));
+ }
+ Store(First, d, out0 + x);
+ Store(Second, d, out1 + x);
+ Store(Third, d, out2 + x);
+ }
+ }
+ for (; x < w; x++) {
+ if (transform_type == 6) {
+ pixel_type Y = in0[x];
+ pixel_type Co = in1[x];
+ pixel_type Cg = in2[x];
+ pixel_type tmp = PixelAdd(Y, -(Cg >> 1));
+ pixel_type G = PixelAdd(Cg, tmp);
+ pixel_type B = PixelAdd(tmp, -(Co >> 1));
+ pixel_type R = PixelAdd(B, Co);
+ out0[x] = R;
+ out1[x] = G;
+ out2[x] = B;
+ } else {
+ pixel_type First = in0[x];
+ pixel_type Second = in1[x];
+ pixel_type Third = in2[x];
+ if (third) Third = PixelAdd(Third, First);
+ if (second == 1) {
+ Second = PixelAdd(Second, First);
+ } else if (second == 2) {
+ Second = PixelAdd(Second, (PixelAdd(First, Third) >> 1));
+ }
+ out0[x] = First;
+ out1[x] = Second;
+ out2[x] = Third;
+ }
+ }
+}
+
+Status InvRCT(Image& input, size_t begin_c, size_t rct_type, ThreadPool* pool) {
+ JXL_RETURN_IF_ERROR(CheckEqualChannels(input, begin_c, begin_c + 2));
+ size_t m = begin_c;
+ Channel& c0 = input.channel[m + 0];
+ size_t w = c0.w;
+ size_t h = c0.h;
+ if (rct_type == 0) { // noop
+ return true;
+ }
+ // Permutation: 0=RGB, 1=GBR, 2=BRG, 3=RBG, 4=GRB, 5=BGR
+ int permutation = rct_type / 7;
+ JXL_CHECK(permutation < 6);
+ // 0-5 values have the low bit corresponding to Third and the high bits
+ // corresponding to Second. 6 corresponds to YCoCg.
+ //
+ // Second: 0=nop, 1=SubtractFirst, 2=SubtractAvgFirstThird
+ //
+ // Third: 0=nop, 1=SubtractFirst
+ int custom = rct_type % 7;
+ // Special case: permute-only. Swap channels around.
+ if (custom == 0) {
+ Channel ch0 = std::move(input.channel[m]);
+ Channel ch1 = std::move(input.channel[m + 1]);
+ Channel ch2 = std::move(input.channel[m + 2]);
+ input.channel[m + (permutation % 3)] = std::move(ch0);
+ input.channel[m + ((permutation + 1 + permutation / 3) % 3)] =
+ std::move(ch1);
+ input.channel[m + ((permutation + 2 - permutation / 3) % 3)] =
+ std::move(ch2);
+ return true;
+ }
+ constexpr decltype(&InvRCTRow<0>) inv_rct_row[] = {
+ InvRCTRow<0>, InvRCTRow<1>, InvRCTRow<2>, InvRCTRow<3>,
+ InvRCTRow<4>, InvRCTRow<5>, InvRCTRow<6>};
+ JXL_RETURN_IF_ERROR(RunOnPool(
+ pool, 0, h, ThreadPool::NoInit,
+ [&](const uint32_t task, size_t /* thread */) {
+ const size_t y = task;
+ const pixel_type* in0 = input.channel[m].Row(y);
+ const pixel_type* in1 = input.channel[m + 1].Row(y);
+ const pixel_type* in2 = input.channel[m + 2].Row(y);
+ pixel_type* out0 = input.channel[m + (permutation % 3)].Row(y);
+ pixel_type* out1 =
+ input.channel[m + ((permutation + 1 + permutation / 3) % 3)].Row(y);
+ pixel_type* out2 =
+ input.channel[m + ((permutation + 2 - permutation / 3) % 3)].Row(y);
+ inv_rct_row[custom](in0, in1, in2, out0, out1, out2, w);
+ },
+ "InvRCT"));
+ return true;
+}
+
+} // namespace HWY_NAMESPACE
+} // namespace jxl
+HWY_AFTER_NAMESPACE();
+
+#if HWY_ONCE
+namespace jxl {
+
+HWY_EXPORT(InvRCT);
+Status InvRCT(Image& input, size_t begin_c, size_t rct_type, ThreadPool* pool) {
+ return HWY_DYNAMIC_DISPATCH(InvRCT)(input, begin_c, rct_type, pool);
+}
+
+} // namespace jxl
+#endif