Update the correct byte alignment and check with 8 * 4 bytes

The sd_isDecoded default value only check once
This commit is contained in:
DreamPiggy 2023-07-10 23:05:30 +08:00
parent 06589dbcc4
commit f6ca661537
5 changed files with 73 additions and 23 deletions

View File

@ -79,6 +79,13 @@ static inline size_t SDByteAlign(size_t size, size_t alignment) {
*/
+ (CGBitmapInfo)preferredBitmapInfo:(BOOL)containsAlpha;
/**
Check whether CGImage is hardware supported to rendering on screen, without the trigger of `CA::Render::copy_image`
You can debug the copied image by using Xcode's `Color Copied Image`, the copied image will turn Cyan and occupy double RAM for bitmap buffer.
Typically, when the CGImage's using the method above (`colorspace` / `byteAlignment` / `bitmapInfo`) can render withtout the copy.
*/
+ (BOOL)CGImageIsHardwareSupported:(_Nonnull CGImageRef)cgImage;
/**
Check whether CGImage contains alpha channel.

View File

@ -17,8 +17,11 @@
#import "SDInternalMacros.h"
#import "SDGraphicsImageRenderer.h"
#import "SDInternalMacros.h"
#import "SDDeviceHelper.h"
#import <Accelerate/Accelerate.h>
#define kCGColorSpaceDeviceRGB @"kCGColorSpaceDeviceRGB"
#if SD_UIKIT
static inline UIImage *SDImageDecodeUIKit(UIImage *image) {
// See: https://developer.apple.com/documentation/uikit/uiimage/3750834-imagebypreparingfordisplay
@ -296,13 +299,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
}
+ (size_t)preferredByteAlignment {
// Actually the page size of system
static int __pageSize = 0;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__pageSize = getpagesize();
});
return __pageSize;
// https://github.com/path/FastImageCache#byte-alignment
// A properly aligned bytes-per-row value must be a multiple of 8 pixels × bytes per pixel.
// return [SDDeviceHelper cacheLineSize]; // Seems not the CPU cache line size
return 32;
}
+ (CGBitmapInfo)preferredBitmapInfo:(BOOL)containsAlpha {
@ -315,6 +315,36 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return CGImageGetBitmapInfo(cgImage);
}
+ (BOOL)CGImageIsHardwareSupported:(CGImageRef)cgImage {
BOOL supported = YES;
// 1. Check byte alignment
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
if (SDByteAlign(bytesPerRow, [SDImageCoderHelper preferredByteAlignment]) == bytesPerRow) {
// byte aligned, OK
supported &= YES;
} else {
// not aligned
supported &= NO;
}
if (!supported) return supported;
// 2. Check color space
if (@available(iOS 10.0, tvOS 10.0, macOS 10.6, watchOS 3.0, *)) {
CGColorSpaceRef colorspace = CGImageGetColorSpace(cgImage);
NSString *colorspaceName = (__bridge_transfer NSString *)CGColorSpaceCopyName(colorspace);
// Seems sRGB/deviceRGB always supported, P3 not always
if ([colorspaceName isEqualToString:(__bridge NSString *)kCGColorSpaceSRGB] || [colorspaceName isEqualToString:kCGColorSpaceDeviceRGB]) {
supported &= YES;
} else {
supported &= NO;
}
return supported;
} else {
// Fallback on earlier versions
return supported;
}
}
+ (BOOL)CGImageContainsAlpha:(CGImageRef)cgImage {
if (!cgImage) {
return NO;

View File

@ -20,25 +20,22 @@
} else {
// Assume only CGImage based can use lazy decoding
CGImageRef cgImage = self.CGImage;
if (!cgImage) {
// Assume others as non-decoded
return NO;
}
CFStringRef uttype = CGImageGetUTType(self.CGImage);
if (uttype) {
// Only ImageIO can set `com.apple.ImageIO.imageSourceTypeIdentifier`
return NO;
} else {
// Now, let's check if the CGImage is byte-aligned (not aligned will cause extra copy)
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
if (SDByteAlign(bytesPerRow, [SDImageCoderHelper preferredByteAlignment]) == bytesPerRow) {
// byte aligned, OK
return YES;
BOOL isDecoded;
if (cgImage) {
CFStringRef uttype = CGImageGetUTType(self.CGImage);
if (uttype) {
// Only ImageIO can set `com.apple.ImageIO.imageSourceTypeIdentifier`
isDecoded = NO;
} else {
// not aligned, still need force-decode
return NO;
// Now, let's check if the CGImage is hardware supported (not byte-aligned will cause extra copy)
isDecoded = [SDImageCoderHelper CGImageIsHardwareSupported:cgImage];
}
} else {
// Assume others as non-decoded
isDecoded = NO;
}
objc_setAssociatedObject(self, @selector(sd_isDecoded), @(isDecoded), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return isDecoded;
}
}

View File

@ -14,5 +14,6 @@
+ (NSUInteger)totalMemory;
+ (NSUInteger)freeMemory;
+ (size_t)cacheLineSize;
@end

View File

@ -8,6 +8,7 @@
#import "SDDeviceHelper.h"
#import <mach/mach.h>
#import <sys/sysctl.h>
@implementation SDDeviceHelper
@ -29,4 +30,18 @@
return vm_stat.free_count * page_size;
}
+ (size_t)cacheLineSize {
size_t size;
sysctlbyname("hw.cachelinesize", NULL, &size, NULL, 0);
char *info = malloc(size);
sysctlbyname("hw.cachelinesize", info, &size, NULL, 0);
if (strlen(info)) {
// hardcode
return 64;
}
char *end;
long result = strtol(info, &end, 10);
return result;
}
@end