1 /* Copyright 2021 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 #ifndef TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_BUFFERED_STRUCT_H_ 16 #define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_BUFFERED_STRUCT_H_ 17 18 #include <algorithm> 19 #include <cstddef> 20 #include <cstdlib> 21 #include <vector> 22 23 #include "tensorflow/lite/experimental/acceleration/mini_benchmark/libjpeg.h" 24 25 namespace tflite { 26 namespace acceleration { 27 namespace decode_jpeg_kernel { 28 29 // May provide an extra buffer of characters beyond the `jpeg_decompress_struct` 30 // for some builds of Libjpeg Dynamic Library on Android that expect a larger 31 // struct than we were compiled with. Zeroes out any allocated bytes beyond 32 // sizeof(jpeg_decompress_struct). This class is exclusively used by 33 // decode_jpeg.cc to resize `jpeg_decompress_struct`. This is to fix a struct 34 // mismatch problem. See go/libjpeg-android for more details. 35 class JpegDecompressBufferedStruct { 36 public: JpegDecompressBufferedStruct(std::size_t expected_size)37 explicit JpegDecompressBufferedStruct(std::size_t expected_size) 38 : resized_size_(std::max(sizeof(jpeg_decompress_struct), expected_size)), 39 buffer_(reinterpret_cast<char*>(malloc(resized_size_))) { 40 // Note: Malloc guarantees alignment for 8 bytes. Hence, using malloc 41 // instead of aligned_alloc. 42 // https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html 43 // alignof(jpeg_decompress_struct) is 8 bytes both on 32 and 64 bit. 44 // It's safe to align the buffered struct as 45 // alignof(jpeg_decompress_struct). This is because we only access the 46 // `jpeg_common_fields` fields of `jpeg_decompress_struct`, all of which are 47 // pointers. The alignment of these pointer fields is 8 and 4 bytes for 64 48 // bit and 32 bit platforms respectively. Since 49 // alignof(jpeg_decompress_struct) is 8 bytes on both platforms, accessing 50 // these fields shouldn't be a problem. 51 // Zero out any excess bytes. Zero-initialization is safe for the bytes 52 // beyond sizeof(jpeg_decompress_struct) because both the dynamic library 53 // and the implementation in decode_jpeg.cc limit their access only to 54 // `jpeg_common_fields` in `jpeg_decompress_struct`. 55 while (--expected_size >= sizeof(jpeg_decompress_struct)) { 56 buffer_[expected_size] = 0; 57 } 58 } ~JpegDecompressBufferedStruct()59 ~JpegDecompressBufferedStruct() { std::free(buffer_); } 60 JpegDecompressBufferedStruct(const JpegDecompressBufferedStruct&) = delete; 61 JpegDecompressBufferedStruct& operator=(const JpegDecompressBufferedStruct&) = 62 delete; get()63 jpeg_decompress_struct* get() const { 64 return reinterpret_cast<jpeg_decompress_struct*>(buffer_); 65 } size()66 int const size() { return resized_size_; } buffer()67 const char* buffer() { return buffer_; } 68 69 private: 70 int resized_size_; 71 char* const buffer_; 72 }; 73 74 } // namespace decode_jpeg_kernel 75 } // namespace acceleration 76 } // namespace tflite 77 78 #endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_BUFFERED_STRUCT_H_ 79