image.cc (3457B)
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 #include "lib/jxl/image.h" 7 8 #include <jxl/memory_manager.h> 9 10 #include <algorithm> // fill, swap 11 #include <cstddef> 12 #include <cstdint> 13 #include <limits> 14 15 #include "lib/jxl/base/status.h" 16 #include "lib/jxl/memory_manager_internal.h" 17 18 #if defined(MEMORY_SANITIZER) 19 #include "lib/jxl/base/common.h" 20 #include "lib/jxl/base/sanitizers.h" 21 #include "lib/jxl/simd_util.h" 22 #endif 23 24 namespace jxl { 25 namespace detail { 26 27 namespace { 28 29 // Initializes the minimum bytes required to suppress MSAN warnings from 30 // legitimate vector loads/stores on the right border, where some lanes are 31 // uninitialized and assumed to be unused. 32 void InitializePadding(PlaneBase& plane, const size_t sizeof_t) { 33 #if defined(MEMORY_SANITIZER) 34 size_t xsize = plane.xsize(); 35 size_t ysize = plane.ysize(); 36 if (xsize == 0 || ysize == 0) return; 37 38 const size_t vec_size = MaxVectorSize(); 39 if (vec_size == 0) return; // Scalar mode: no padding needed 40 41 const size_t valid_size = xsize * sizeof_t; 42 const size_t initialize_size = RoundUpTo(valid_size, vec_size); 43 if (valid_size == initialize_size) return; 44 45 for (size_t y = 0; y < ysize; ++y) { 46 uint8_t* JXL_RESTRICT row = plane.bytes() + y * plane.bytes_per_row(); 47 #if defined(__clang__) && \ 48 ((!defined(__apple_build_version__) && __clang_major__ <= 6) || \ 49 (defined(__apple_build_version__) && \ 50 __apple_build_version__ <= 10001145)) 51 // There's a bug in MSAN in clang-6 when handling AVX2 operations. This 52 // workaround allows tests to pass on MSAN, although it is slower and 53 // prevents MSAN warnings from uninitialized images. 54 std::fill(row, msan::kSanitizerSentinelByte, initialize_size); 55 #else 56 memset(row + valid_size, msan::kSanitizerSentinelByte, 57 initialize_size - valid_size); 58 #endif // clang6 59 } 60 #endif // MEMORY_SANITIZER 61 } 62 63 } // namespace 64 65 PlaneBase::PlaneBase(const uint32_t xsize, const uint32_t ysize, 66 const size_t sizeof_t) 67 : xsize_(xsize), 68 ysize_(ysize), 69 orig_xsize_(xsize), 70 orig_ysize_(ysize), 71 bytes_per_row_(BytesPerRow(xsize_, sizeof_t)), 72 sizeof_t_(sizeof_t) {} 73 74 Status PlaneBase::Allocate(JxlMemoryManager* memory_manager, 75 size_t pre_padding) { 76 JXL_ENSURE(bytes_.address<void>() == nullptr); 77 78 // Dimensions can be zero, e.g. for lazily-allocated images. Only allocate 79 // if nonzero, because "zero" bytes still have padding/bookkeeping overhead. 80 if (xsize_ == 0 || ysize_ == 0) { 81 return true; 82 } 83 84 size_t max_y_size = std::numeric_limits<size_t>::max() / bytes_per_row_; 85 if (ysize_ > max_y_size) { 86 return JXL_FAILURE("Image dimensions are too large"); 87 } 88 89 JXL_ASSIGN_OR_RETURN( 90 bytes_, AlignedMemory::Create(memory_manager, bytes_per_row_ * ysize_, 91 pre_padding * sizeof_t_)); 92 93 InitializePadding(*this, sizeof_t_); 94 95 return true; 96 } 97 98 void PlaneBase::Swap(PlaneBase& other) { 99 std::swap(xsize_, other.xsize_); 100 std::swap(ysize_, other.ysize_); 101 std::swap(orig_xsize_, other.orig_xsize_); 102 std::swap(orig_ysize_, other.orig_ysize_); 103 std::swap(bytes_per_row_, other.bytes_per_row_); 104 std::swap(bytes_, other.bytes_); 105 } 106 107 } // namespace detail 108 } // namespace jxl