From 03aef286fa06d8dbe5f55e8163f1ec05c7310556 Mon Sep 17 00:00:00 2001 From: David Korth Date: Fri, 25 Oct 2024 01:33:05 -0400 Subject: [PATCH] [librptexture] KhronosKTX2.cpp: New inline helper function read_le32(). On i386/amd64, this is essentially the same code, since reading unaligned data is allowed and is usually fast. On other CPUs, reading unaligned data is either not allowed or is slow. Use byte reads and shifting instead. Effectively no change on i386/amd64, but this may help fix potential crashes on other CPUs. On ARMv5 and earlier, unaligned accesses crash. On ARMv6 and later, it probably won't crash, but it might be slow. --- src/librptexture/fileformat/KhronosKTX2.cpp | 134 +++++++++++--------- 1 file changed, 76 insertions(+), 58 deletions(-) diff --git a/src/librptexture/fileformat/KhronosKTX2.cpp b/src/librptexture/fileformat/KhronosKTX2.cpp index a94ba9376..fbffbc718 100644 --- a/src/librptexture/fileformat/KhronosKTX2.cpp +++ b/src/librptexture/fileformat/KhronosKTX2.cpp @@ -51,63 +51,81 @@ namespace LibRpTexture { class KhronosKTX2Private final : public FileFormatPrivate { - public: - KhronosKTX2Private(KhronosKTX2 *q, const IRpFilePtr &file); - - private: - typedef FileFormatPrivate super; - RP_DISABLE_COPY(KhronosKTX2Private) - - public: - /** TextureInfo **/ - static const char *const exts[]; - static const char *const mimeTypes[]; - static const TextureInfo textureInfo; - - public: - // KTX2 header - KTX2_Header ktx2Header; - - // Is HFlip/VFlip needed? - // Some textures may be stored upside-down due to - // the way GL texture coordinates are interpreted. - // Default without KTXorientation is HFlip=false, VFlip=true - rp_image::FlipOp flipOp; - - // Mipmap offsets - rp::uvector mipmap_data; - - // Decoded mipmaps - // Mipmap 0 is the full image. - vector mipmaps; - - // Invalid pixel format message - char invalid_pixel_format[24]; - - // Key/Value data - // NOTE: Stored as vector > instead of - // vector > for compatibility with - // RFT_LISTDATA. - RomFields::ListData_t kv_data; - - // KTXswizzle, if specified. - // Four bytes indicate the values of each channel. - // Each byte can be: [rgba01], where rgba corresponds - // to each channel, 0 is 0, and 1 is 1. - // If byte 0 is a literal \0, no KTXswizzle tag was found. - char ktx_swizzle[4]; - - /** - * Load the image. - * @param mip Mipmap number. (0 == full image) - * @return Image, or nullptr on error. - */ - rp_image_const_ptr loadImage(int mip); - - /** - * Load key/value data. - */ - void loadKeyValueData(void); +public: + KhronosKTX2Private(KhronosKTX2 *q, const IRpFilePtr &file); + +private: + typedef FileFormatPrivate super; + RP_DISABLE_COPY(KhronosKTX2Private) + +public: + /** TextureInfo **/ + static const char *const exts[]; + static const char *const mimeTypes[]; + static const TextureInfo textureInfo; + +public: + // KTX2 header + KTX2_Header ktx2Header; + + // Is HFlip/VFlip needed? + // Some textures may be stored upside-down due to + // the way GL texture coordinates are interpreted. + // Default without KTXorientation is HFlip=false, VFlip=true + rp_image::FlipOp flipOp; + + // Mipmap offsets + rp::uvector mipmap_data; + + // Decoded mipmaps + // Mipmap 0 is the full image. + vector mipmaps; + + // Invalid pixel format message + char invalid_pixel_format[24]; + + // Key/Value data + // NOTE: Stored as vector > instead of + // vector > for compatibility with + // RFT_LISTDATA. + RomFields::ListData_t kv_data; + + // KTXswizzle, if specified. + // Four bytes indicate the values of each channel. + // Each byte can be: [rgba01], where rgba corresponds + // to each channel, 0 is 0, and 1 is 1. + // If byte 0 is a literal \0, no KTXswizzle tag was found. + char ktx_swizzle[4]; + + /** + * Load the image. + * @param mip Mipmap number. (0 == full image) + * @return Image, or nullptr on error. + */ + rp_image_const_ptr loadImage(int mip); + + /** + * Load key/value data. + */ + void loadKeyValueData(void); + + /** + * Read a little-endian 32-bit value from an unaligned memory block. + * @param p Memory block + * @return Little-endian 32-bit value + */ + static inline uint32_t read_le32(const char *p) + { +#if defined(_M_IX86) || defined(__i386__) || \ + defined(_M_X64) || defined(_M_AMD64) || \ + defined(__amd64__) || defined(__x86_64__) + // i386/amd64: Unaligned accesses are allowed, and are usually fast. + return le32_to_cpu(*(reinterpret_cast(p))); +#else + // Other CPU: Unaligned accesses are either not allowed or are slow. + return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +#endif + } }; FILEFORMAT_IMPL(KhronosKTX2) @@ -663,7 +681,7 @@ void KhronosKTX2Private::loadKeyValueData(void) while (p < p_end-3) { // Check the next key/value size. - const uint32_t sz = le32_to_cpu(*((const uint32_t*)p)); + const uint32_t sz = read_le32(p); if (sz < 2) { // Must be at least 2 bytes for an empty key and its NULL terminator. // TODO: Show an error?