image_test.cc (4765B)
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 <stdio.h> 20 #include <stdlib.h> 21 22 #include <random> 23 24 #undef HWY_TARGET_INCLUDE 25 #define HWY_TARGET_INCLUDE "hwy/contrib/image/image_test.cc" 26 #include "hwy/foreach_target.h" // IWYU pragma: keep 27 #include "hwy/highway.h" 28 #include "hwy/tests/test_util-inl.h" 29 30 HWY_BEFORE_NAMESPACE(); 31 namespace hwy { 32 namespace HWY_NAMESPACE { 33 namespace { 34 35 // Ensure we can always write full aligned vectors. 36 struct TestAlignedT { 37 template <typename T> 38 void operator()(T /*unused*/) const { 39 std::mt19937 rng(129); 40 std::uniform_int_distribution<int> dist(0, 16); 41 const ScalableTag<T> d; 42 43 for (size_t ysize = 1; ysize < 4; ++ysize) { 44 for (size_t xsize = 1; xsize < 64; ++xsize) { 45 Image<T> img(xsize, ysize); 46 47 for (size_t y = 0; y < ysize; ++y) { 48 T* HWY_RESTRICT row = img.MutableRow(y); 49 for (size_t x = 0; x < xsize; x += Lanes(d)) { 50 const auto values = Iota(d, dist(rng)); 51 Store(values, d, row + x); 52 } 53 } 54 55 // Sanity check to prevent optimizing out the writes 56 const auto x = std::uniform_int_distribution<size_t>(0, xsize - 1)(rng); 57 const auto y = std::uniform_int_distribution<size_t>(0, ysize - 1)(rng); 58 HWY_ASSERT(img.ConstRow(y)[x] < 16 + Lanes(d)); 59 } 60 } 61 } 62 }; 63 64 void TestAligned() { ForUnsignedTypes(TestAlignedT()); } 65 66 // Ensure we can write an unaligned vector starting at the last valid value. 67 struct TestUnalignedT { 68 template <typename T> 69 void operator()(T /*unused*/) const { 70 std::mt19937 rng(129); 71 std::uniform_int_distribution<int> dist(0, 3); 72 const ScalableTag<T> d; 73 74 for (size_t ysize = 1; ysize < 4; ++ysize) { 75 for (size_t xsize = 1; xsize < 128; ++xsize) { 76 Image<T> img(xsize, ysize); 77 img.InitializePaddingForUnalignedAccesses(); 78 79 // This test reads padding, which only works if it was initialized, 80 // which only happens in MSAN builds. 81 #if HWY_IS_MSAN || HWY_IDE 82 // Initialize only the valid samples 83 for (size_t y = 0; y < ysize; ++y) { 84 T* HWY_RESTRICT row = img.MutableRow(y); 85 for (size_t x = 0; x < xsize; ++x) { 86 row[x] = ConvertScalarTo<T>(1u << dist(rng)); 87 } 88 } 89 90 // Read padding bits 91 auto accum = Zero(d); 92 for (size_t y = 0; y < ysize; ++y) { 93 T* HWY_RESTRICT row = img.MutableRow(y); 94 for (size_t x = 0; x < xsize; ++x) { 95 accum = Or(accum, LoadU(d, row + x)); 96 } 97 } 98 99 // Ensure padding was zero 100 const size_t N = Lanes(d); 101 auto lanes = AllocateAligned<T>(N); 102 HWY_ASSERT(lanes); 103 Store(accum, d, lanes.get()); 104 for (size_t i = 0; i < N; ++i) { 105 HWY_ASSERT(lanes[i] < 16); 106 } 107 #else // Check that writing padding does not overwrite valid samples 108 // Initialize only the valid samples 109 for (size_t y = 0; y < ysize; ++y) { 110 T* HWY_RESTRICT row = img.MutableRow(y); 111 for (size_t x = 0; x < xsize; ++x) { 112 row[x] = ConvertScalarTo<T>(x); 113 } 114 } 115 116 // Zero padding and rightmost sample 117 for (size_t y = 0; y < ysize; ++y) { 118 T* HWY_RESTRICT row = img.MutableRow(y); 119 StoreU(Zero(d), d, row + xsize - 1); 120 } 121 122 // Ensure no samples except the rightmost were overwritten 123 for (size_t y = 0; y < ysize; ++y) { 124 T* HWY_RESTRICT row = img.MutableRow(y); 125 for (size_t x = 0; x < xsize - 1; ++x) { 126 HWY_ASSERT_EQ(ConvertScalarTo<T>(x), row[x]); 127 } 128 } 129 #endif 130 } 131 } 132 } 133 }; 134 135 void TestUnaligned() { ForUnsignedTypes(TestUnalignedT()); } 136 137 } // namespace 138 // NOLINTNEXTLINE(google-readability-namespace-comments) 139 } // namespace HWY_NAMESPACE 140 } // namespace hwy 141 HWY_AFTER_NAMESPACE(); 142 143 #if HWY_ONCE 144 namespace hwy { 145 namespace { 146 HWY_BEFORE_TEST(ImageTest); 147 HWY_EXPORT_AND_TEST_P(ImageTest, TestAligned); 148 HWY_EXPORT_AND_TEST_P(ImageTest, TestUnaligned); 149 HWY_AFTER_TEST(); 150 } // namespace 151 } // namespace hwy 152 HWY_TEST_MAIN(); 153 #endif // HWY_ONCE