11// Copyright © 2021 Audulus LLC. All rights reserved.
22
33#include " testUtils.h"
4+ #include < algorithm>
5+ #include < cstdlib>
46#include < vector>
57#import < ImageIO/ImageIO.h>
68#import < UniformTypeIdentifiers/UniformTypeIdentifiers.h>
79
10+ static constexpr int kMaxPixelDifference = 2 ;
11+
812void writeCGImage (CGImageRef image, CFURLRef url) {
913 auto dest = CGImageDestinationCreateWithURL (url, (CFStringRef) UTTypePNG.identifier , 1 , nil );
1014 CGImageDestinationAddImage (dest, image, nil );
@@ -102,13 +106,53 @@ @implementation checkTextureBundleFinder
102106
103107@end
104108
109+ static CGImageRef createImage (NSURL * url) {
110+ auto source = CGImageSourceCreateWithURL ((__bridge CFURLRef)url, nil );
111+ if (!source) {
112+ return nil ;
113+ }
114+
115+ auto image = CGImageSourceCreateImageAtIndex (source, 0 , nil );
116+ CFRelease (source);
117+ return image;
118+ }
119+
120+ static bool getImagePixels (CGImageRef image, std::vector<UInt8>& pixels) {
121+ if (!image) {
122+ return false ;
123+ }
124+
125+ auto w = CGImageGetWidth (image);
126+ auto h = CGImageGetHeight (image);
127+ pixels.assign (4 *w*h, 0 );
128+
129+ auto colorSpace = CGColorSpaceCreateDeviceRGB ();
130+ auto bitmapInfo = static_cast <CGBitmapInfo>(kCGBitmapByteOrder32Big ) |
131+ static_cast <CGBitmapInfo>(kCGImageAlphaPremultipliedLast );
132+ auto context = CGBitmapContextCreate (pixels.data (),
133+ w,
134+ h,
135+ 8 ,
136+ 4 *w,
137+ colorSpace,
138+ bitmapInfo);
139+ CGColorSpaceRelease (colorSpace);
140+
141+ if (!context) {
142+ return false ;
143+ }
144+
145+ CGContextDrawImage (context, CGRectMake (0 , 0 , w, h), image);
146+ CGContextRelease (context);
147+ return true ;
148+ }
149+
105150bool checkTexture (id <MTLTexture > texture, NSString * name) {
106151
107152 auto tmpURL = [NSFileManager .defaultManager.temporaryDirectory URLByAppendingPathComponent: name];
108153 NSLog (@" saving to %@ " , tmpURL);
109154 CGImageRef image = createImage (texture);
110155 writeCGImage (image, (__bridge CFURLRef)tmpURL);
111- CGImageRelease (image);
112156
113157 // Get URL for baseline.
114158 NSString * path = @" Contents/Resources/vger_vgerTests.bundle/Contents/Resources/images/" ;
@@ -117,13 +161,59 @@ bool checkTexture(id<MTLTexture> texture, NSString* name) {
117161 auto baselineURL = [bundle.bundleURL URLByAppendingPathComponent: path];
118162 NSLog (@" checking against baseline %@ " , baselineURL);
119163
120- bool equal = [NSFileManager .defaultManager contentsEqualAtPath: baselineURL.path andPath: tmpURL.path];
164+ CGImageRef baselineImage = createImage (baselineURL);
165+ bool equal = false ;
166+
167+ if (!baselineImage) {
168+ NSLog (@" missing or unreadable baseline image %@ " , baselineURL);
169+ } else if (CGImageGetWidth (image) != CGImageGetWidth (baselineImage) ||
170+ CGImageGetHeight (image) != CGImageGetHeight (baselineImage)) {
171+ NSLog (@" image size mismatch: got %zu x%zu , expected %zu x%zu " ,
172+ CGImageGetWidth (image),
173+ CGImageGetHeight(image),
174+ CGImageGetWidth(baselineImage),
175+ CGImageGetHeight(baselineImage));
176+ } else {
177+ std::vector<UInt8> actualPixels;
178+ std::vector<UInt8> baselinePixels;
179+
180+ if (getImagePixels (image, actualPixels) && getImagePixels (baselineImage, baselinePixels)) {
181+ int maxDifference = 0 ;
182+ size_t maxDifferenceIndex = 0 ;
183+
184+ for (size_t i=0 ;i<actualPixels.size ();++i) {
185+ int difference = std::abs (int (actualPixels[i]) - int (baselinePixels[i]));
186+ if (difference > maxDifference) {
187+ maxDifference = difference;
188+ maxDifferenceIndex = i;
189+ }
190+ }
191+
192+ equal = maxDifference <= kMaxPixelDifference ;
193+ if (!equal) {
194+ auto pixelIndex = maxDifferenceIndex / 4 ;
195+ NSLog (@" maximum pixel difference %d exceeds epsilon %d at (%zu , %zu ), channel %zu " ,
196+ maxDifference,
197+ kMaxPixelDifference ,
198+ pixelIndex % CGImageGetWidth(image),
199+ pixelIndex / CGImageGetWidth(image),
200+ maxDifferenceIndex % 4);
201+ }
202+ } else {
203+ NSLog (@" could not decode images for comparison" );
204+ }
205+ }
121206
122207 if (!equal) {
123208#if TARGET_OS_OSX
124209 system ([NSString stringWithFormat: @" open %@ " , tmpURL.path].UTF8String );
125210#endif
126211 }
127212
213+ if (baselineImage) {
214+ CGImageRelease (baselineImage);
215+ }
216+ CGImageRelease (image);
217+
128218 return equal;
129219}
0 commit comments