1 // Copyright (c) the JPEG XL Project
2 // SPDX-License-Identifier: Apache-2.0
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "hwy/contrib/image/image.h"
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
30 // After foreach_target:
31 #include "hwy/highway.h"
32 #include "hwy/tests/test_util-inl.h"
34 HWY_BEFORE_NAMESPACE();
36 namespace HWY_NAMESPACE {
38 // Ensure we can always write full aligned vectors.
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;
46 for (size_t ysize = 1; ysize < 4; ++ysize) {
47 for (size_t xsize = 1; xsize < 64; ++xsize) {
48 Image<T> img(xsize, ysize);
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);
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));
67 void TestAligned() { ForUnsignedTypes(TestAlignedT()); }
69 // Ensure we can write an unaligned vector starting at the last valid value.
70 struct TestUnalignedT {
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;
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();
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));
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));
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);
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);
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);
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]);
137 void TestUnaligned() { ForUnsignedTypes(TestUnalignedT()); }
139 // NOLINTNEXTLINE(google-readability-namespace-comments)
140 } // namespace HWY_NAMESPACE
142 HWY_AFTER_NAMESPACE();
147 HWY_BEFORE_TEST(ImageTest);
148 HWY_EXPORT_AND_TEST_P(ImageTest, TestAligned);
149 HWY_EXPORT_AND_TEST_P(ImageTest, TestUnaligned);