Be able to test and bench the libspng library
That's libspng with an 's', instead of libpng without an 's'.
Wuffs' std/png and std/zlib implementations have not been fully
optimized yet, but as a snapshot, here's how it compares with these
"mimic" libraries, libspng and libpng.
On a mid-range x86_64 laptop:
Wuffs/clang9:
wuffs_png_decode_image_19k_8bpp/clang9 91.9MB/s ± 0%
wuffs_png_decode_image_40k_24bpp/clang9 128MB/s ± 0%
wuffs_png_decode_image_77k_8bpp/clang9 342MB/s ± 0%
wuffs_png_decode_image_552k_32bpp_ignore_checksum/clang9 324MB/s ± 0%
wuffs_png_decode_image_552k_32bpp_verify_checksum/clang9 258MB/s ± 0%
wuffs_png_decode_image_4002k_24bpp/clang9 127MB/s ± 0%
Wuffs/gcc10:
wuffs_png_decode_image_19k_8bpp/gcc10 94.3MB/s ± 0%
wuffs_png_decode_image_40k_24bpp/gcc10 131MB/s ± 0%
wuffs_png_decode_image_77k_8bpp/gcc10 348MB/s ± 1%
wuffs_png_decode_image_552k_32bpp_ignore_checksum/gcc10 319MB/s ± 0%
wuffs_png_decode_image_552k_32bpp_verify_checksum/gcc10 269MB/s ± 0%
wuffs_png_decode_image_4002k_24bpp/gcc10 131MB/s ± 0%
libspng/clang9:
mimic_png_decode_image_19k_8bpp/clang9 59.3MB/s ± 1%
mimic_png_decode_image_40k_24bpp/clang9 78.4MB/s ± 0%
mimic_png_decode_image_77k_8bpp/clang9 189MB/s ± 0%
mimic_png_decode_image_552k_32bpp_ignore_checksum/clang9 235MB/s ± 0%
mimic_png_decode_image_552k_32bpp_verify_checksum/clang9 203MB/s ± 0%
mimic_png_decode_image_4002k_24bpp/clang9 110MB/s ± 0%
libspng/gcc10:
mimic_png_decode_image_19k_8bpp/gcc10 59.5MB/s ± 0%
mimic_png_decode_image_40k_24bpp/gcc10 77.6MB/s ± 0%
mimic_png_decode_image_77k_8bpp/gcc10 188MB/s ± 0%
mimic_png_decode_image_552k_32bpp_ignore_checksum/gcc10 223MB/s ± 0%
mimic_png_decode_image_552k_32bpp_verify_checksum/gcc10 193MB/s ± 0%
mimic_png_decode_image_4002k_24bpp/gcc10 109MB/s ± 0%
libpng (Debian_Testing_Bullseye /usr/lib/x86_64-linux-gnu/libpng.so):
mimic_png_decode_image_19k_8bpp 58.3MB/s ± 0%
mimic_png_decode_image_40k_24bpp 73.1MB/s ± 0%
mimic_png_decode_image_77k_8bpp 177MB/s ± 0%
mimic_png_decode_image_552k_32bpp_ignore_checksum skipped
mimic_png_decode_image_552k_32bpp_verify_checksum 146MB/s ± 0%
mimic_png_decode_image_4002k_24bpp 104MB/s ± 0%
diff --git a/test/c/mimiclib/png.c b/test/c/mimiclib/png.c
index 3efa68b..32acd63 100644
--- a/test/c/mimiclib/png.c
+++ b/test/c/mimiclib/png.c
@@ -12,10 +12,119 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// ----------------
+
+// Uncomment this line to test and bench libspng instead of libpng.
+// #define WUFFS_MIMICLIB_USE_LIBSPNG_INSTEAD_OF_LIBPNG 1
+
+#ifdef WUFFS_MIMICLIB_USE_LIBSPNG_INSTEAD_OF_LIBPNG
+
+// We #include a foo.c file, not a foo.h file, as libspng is a "single file C
+// library".
+#include "/path/to/your/copy/of/github.com/randy408/libspng/spng/spng.c"
+
+// We deliberately do not define the
+// WUFFS_MIMICLIB_PNG_DOES_NOT_SUPPORT_QUIRK_IGNORE_CHECKSUM macro.
+
+// libspng (version 0.6.2, released November 2020) calculates but does not
+// verify the CRC-32 checksum on the final IDAT chunk. It also does not verify
+// the Adler-32 checksum. After calling spng_decode_image, it ends in
+// SPNG_STATE_EOI but not a later state such as SPNG_STATE_AFTER_IDAT.
+//
+// libspng commit 9c35dc3 "fix handling of SPNG_CTX_IGNORE_ADLER32", submitted
+// December 2020, fixed Adler-32 but not CRC-32.
+#define WUFFS_MIMICLIB_PNG_DOES_NOT_VERIFY_FINAL_IDAT_CHECKSUMS 1
+
+const char* //
+mimic_png_decode(uint64_t* n_bytes_out,
+ wuffs_base__io_buffer* dst,
+ uint32_t wuffs_initialize_flags,
+ wuffs_base__pixel_format pixfmt,
+ uint32_t* quirks_ptr,
+ size_t quirks_len,
+ wuffs_base__io_buffer* src) {
+ wuffs_base__io_buffer dst_fallback =
+ wuffs_base__slice_u8__writer(g_mimiclib_scratch_slice_u8);
+ if (!dst) {
+ dst = &dst_fallback;
+ }
+
+ const char* ret = NULL;
+
+ spng_ctx* ctx = spng_ctx_new(0);
+
+ size_t i;
+ for (i = 0; i < quirks_len; i++) {
+ uint32_t q = quirks_ptr[i];
+ if (q == WUFFS_BASE__QUIRK_IGNORE_CHECKSUM) {
+ spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
+ }
+ }
+
+ if (spng_set_png_buffer(ctx, wuffs_base__io_buffer__reader_pointer(src),
+ wuffs_base__io_buffer__reader_length(src))) {
+ ret = "mimic_png_decode: spng_set_png_buffer failed";
+ goto cleanup0;
+ }
+
+ int fmt = 0;
+ switch (pixfmt.repr) {
+ case WUFFS_BASE__PIXEL_FORMAT__Y:
+ fmt = SPNG_FMT_G8;
+ break;
+ case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
+ // libspng doesn't do BGRA8. RGBA8 is the closest approximation. We'll
+ // fix it up later.
+ fmt = SPNG_FMT_RGBA8;
+ break;
+ default:
+ ret = "mimic_png_decode: unsupported pixfmt";
+ goto cleanup0;
+ }
+
+ size_t n = 0;
+ if (spng_decoded_image_size(ctx, fmt, &n)) {
+ ret = "mimic_png_decode: spng_decoded_image_size failed";
+ goto cleanup0;
+ }
+ if (n > wuffs_base__io_buffer__writer_length(dst)) {
+ ret = "mimic_png_decode: image is too large";
+ goto cleanup0;
+ }
+
+ uint8_t* dst_ptr = wuffs_base__io_buffer__writer_pointer(dst);
+ if (spng_decode_image(ctx, dst_ptr, n, fmt, 0)) {
+ ret = "mimic_png_decode: spng_decode_image failed";
+ goto cleanup0;
+ }
+ dst->meta.wi += n;
+ if (n_bytes_out) {
+ *n_bytes_out += n;
+ }
+
+ // Fix up BGRA8 vs RGBA8.
+ if (fmt == SPNG_FMT_RGBA8) {
+ for (; n >= 4; n -= 4) {
+ uint8_t swap = dst_ptr[0];
+ dst_ptr[0] = dst_ptr[2];
+ dst_ptr[2] = swap;
+ dst_ptr += 4;
+ }
+ }
+
+cleanup0:;
+ spng_ctx_free(ctx);
+ return ret;
+}
+
+#else // WUFFS_MIMICLIB_USE_LIBSPNG_INSTEAD_OF_LIBPNG
#include "png.h"
#define WUFFS_MIMICLIB_PNG_DOES_NOT_SUPPORT_QUIRK_IGNORE_CHECKSUM 1
+// We deliberately do not define the
+// WUFFS_MIMICLIB_PNG_DOES_NOT_VERIFY_FINAL_IDAT_CHECKSUMS macro.
+
const char* //
mimic_png_decode(uint64_t* n_bytes_out,
wuffs_base__io_buffer* dst,
@@ -92,3 +201,4 @@
png_image_free(&pi);
return ret;
}
+#endif // WUFFS_MIMICLIB_USE_LIBSPNG_INSTEAD_OF_LIBPNG
diff --git a/test/c/std/png.c b/test/c/std/png.c
index d6a03a2..7d3e7b3 100644
--- a/test/c/std/png.c
+++ b/test/c/std/png.c
@@ -37,7 +37,11 @@
"wuffs mimic cflags" to run the mimic benchmarks.
*/
-// !! wuffs mimic cflags: -DWUFFS_MIMIC -lpng
+// Libpng requires -lpng (and nothing else). Libspng (note the 's') requires
+// -lm and -lz (and nothing else). It's easiest to just link with the union of
+// all of these libraries.
+//
+// !! wuffs mimic cflags: -DWUFFS_MIMIC -lm -lpng -lz
// Wuffs ships as a "single file C library" or "header file library" as per
// https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
@@ -104,12 +108,14 @@
"@001F=8A=00;test/data/hippopotamus.regular.png",
// Change a byte in a PLTE CRC-32 checksum.
"@0372=52=00;test/data/bricks-dither.png",
+ // Change a byte in a non-final IDAT CRC-32 checksum.
+ "@2029=B7=00;test/data/bricks-color.png",
+#ifndef WUFFS_MIMICLIB_PNG_DOES_NOT_VERIFY_FINAL_IDAT_CHECKSUMS
// Change a byte in a final IDAT Adler-32 checksum.
"@084E=26=00;test/data/hippopotamus.regular.png",
// Change a byte in a final IDAT CRC-32 checksum.
"@084F=F4=00;test/data/hippopotamus.regular.png",
- // Change a byte in a non-final IDAT CRC-32 checksum.
- "@2029=B7=00;test/data/bricks-color.png",
+#endif
};
int tc;