Imported Upstream version 0.7.0
[platform/upstream/libjxl.git] / third_party / highway / hwy / contrib / image / image_test.cc
1 // Copyright (c) the JPEG XL Project
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "hwy/contrib/image/image.h"
17
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include <random>
24 #include <utility>
25
26 #undef HWY_TARGET_INCLUDE
27 #define HWY_TARGET_INCLUDE "hwy/contrib/image/image_test.cc"
28 #include "hwy/foreach_target.h"  // IWYU pragma: keep
29
30 // After foreach_target:
31 #include "hwy/highway.h"
32 #include "hwy/tests/test_util-inl.h"
33
34 HWY_BEFORE_NAMESPACE();
35 namespace hwy {
36 namespace HWY_NAMESPACE {
37
38 // Ensure we can always write full aligned vectors.
39 struct TestAlignedT {
40   template <typename T>
41   void operator()(T /*unused*/) const {
42     std::mt19937 rng(129);
43     std::uniform_int_distribution<int> dist(0, 16);
44     const ScalableTag<T> d;
45
46     for (size_t ysize = 1; ysize < 4; ++ysize) {
47       for (size_t xsize = 1; xsize < 64; ++xsize) {
48         Image<T> img(xsize, ysize);
49
50         for (size_t y = 0; y < ysize; ++y) {
51           T* HWY_RESTRICT row = img.MutableRow(y);
52           for (size_t x = 0; x < xsize; x += Lanes(d)) {
53             const auto values = Iota(d, static_cast<T>(dist(rng)));
54             Store(values, d, row + x);
55           }
56         }
57
58         // Sanity check to prevent optimizing out the writes
59         const auto x = std::uniform_int_distribution<size_t>(0, xsize - 1)(rng);
60         const auto y = std::uniform_int_distribution<size_t>(0, ysize - 1)(rng);
61         HWY_ASSERT(img.ConstRow(y)[x] < 16 + Lanes(d));
62       }
63     }
64   }
65 };
66
67 void TestAligned() { ForUnsignedTypes(TestAlignedT()); }
68
69 // Ensure we can write an unaligned vector starting at the last valid value.
70 struct TestUnalignedT {
71   template <typename T>
72   void operator()(T /*unused*/) const {
73     std::mt19937 rng(129);
74     std::uniform_int_distribution<int> dist(0, 3);
75     const ScalableTag<T> d;
76
77     for (size_t ysize = 1; ysize < 4; ++ysize) {
78       for (size_t xsize = 1; xsize < 128; ++xsize) {
79         Image<T> img(xsize, ysize);
80         img.InitializePaddingForUnalignedAccesses();
81
82 // This test reads padding, which only works if it was initialized,
83 // which only happens in MSAN builds.
84 #if HWY_IS_MSAN || HWY_IDE
85         // Initialize only the valid samples
86         for (size_t y = 0; y < ysize; ++y) {
87           T* HWY_RESTRICT row = img.MutableRow(y);
88           for (size_t x = 0; x < xsize; ++x) {
89             row[x] = static_cast<T>(1u << dist(rng));
90           }
91         }
92
93         // Read padding bits
94         auto accum = Zero(d);
95         for (size_t y = 0; y < ysize; ++y) {
96           T* HWY_RESTRICT row = img.MutableRow(y);
97           for (size_t x = 0; x < xsize; ++x) {
98             accum = Or(accum, LoadU(d, row + x));
99           }
100         }
101
102         // Ensure padding was zero
103         const size_t N = Lanes(d);
104         auto lanes = AllocateAligned<T>(N);
105         Store(accum, d, lanes.get());
106         for (size_t i = 0; i < N; ++i) {
107           HWY_ASSERT(lanes[i] < 16);
108         }
109 #else  // Check that writing padding does not overwrite valid samples
110        // Initialize only the valid samples
111         for (size_t y = 0; y < ysize; ++y) {
112           T* HWY_RESTRICT row = img.MutableRow(y);
113           for (size_t x = 0; x < xsize; ++x) {
114             row[x] = static_cast<T>(x);
115           }
116         }
117
118         // Zero padding and rightmost sample
119         for (size_t y = 0; y < ysize; ++y) {
120           T* HWY_RESTRICT row = img.MutableRow(y);
121           StoreU(Zero(d), d, row + xsize - 1);
122         }
123
124         // Ensure no samples except the rightmost were overwritten
125         for (size_t y = 0; y < ysize; ++y) {
126           T* HWY_RESTRICT row = img.MutableRow(y);
127           for (size_t x = 0; x < xsize - 1; ++x) {
128             HWY_ASSERT_EQ(static_cast<T>(x), row[x]);
129           }
130         }
131 #endif
132       }
133     }
134   }
135 };
136
137 void TestUnaligned() { ForUnsignedTypes(TestUnalignedT()); }
138
139 // NOLINTNEXTLINE(google-readability-namespace-comments)
140 }  // namespace HWY_NAMESPACE
141 }  // namespace hwy
142 HWY_AFTER_NAMESPACE();
143
144 #if HWY_ONCE
145
146 namespace hwy {
147 HWY_BEFORE_TEST(ImageTest);
148 HWY_EXPORT_AND_TEST_P(ImageTest, TestAligned);
149 HWY_EXPORT_AND_TEST_P(ImageTest, TestUnaligned);
150 }  // namespace hwy
151
152 #endif