shithub: jbig2

Download patch

ref: 8a5ad7cc54f23fb99e231be3a123d6488829dc9e
parent: 190fc319c5a87c1a971ba0efa8238d9e1c88ea1f
author: Robin Watts <Robin.Watts@artifex.com>
date: Thu Jan 23 07:09:08 EST 2020

jbig2dec: Optimise jbig2_decode_generic_template0_TPGDON

Decodes of JBig2_042_08.pdf (the worst comparing file to
luratech in terms of time) show significant time in that
function (45%). With this patch that drops to 29%.

--- a/jbig2_generic.c
+++ b/jbig2_generic.c
@@ -831,6 +831,8 @@
     bool bit;
     int LTP = 0;
     int code = 0;
+    int gmin, gmax;
+    uint32_t left, right, top;
 
     if (pixel_outside_field(params->gbat[0], params->gbat[1]) ||
         pixel_outside_field(params->gbat[2], params->gbat[3]) ||
@@ -839,6 +841,45 @@
         return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                            "adaptive template pixel is out of field");
 
+    /* We divide the width into 3 regions 0..left...right...GBW,
+     * between left and right, we know that our accesses will never
+     * step outside the image, enabling us to use faster accessors. */
+    left = 4;
+    right = 2;
+    gmin = gmax = params->gbat[0];
+    if (params->gbat[2] < gmin)
+        gmin = params->gbat[2];
+    if (gmax < params->gbat[2])
+        gmax = params->gbat[2];
+    if (params->gbat[4] < gmin)
+        gmin = params->gbat[4];
+    if (gmax < params->gbat[4])
+        gmax = params->gbat[4];
+    if (params->gbat[6] < gmin)
+        gmin = params->gbat[6];
+    if (gmax < params->gbat[6])
+        gmax = params->gbat[6];
+    if (left < -gmin)
+        left = -gmin;
+    if (right < gmax)
+        right = gmax;
+    right = GBW - right;
+    /* So 0 <= x < left or right <= x < GBW needs bounds checking. */
+
+    /* Now we do the same for the height, but here there is no bottom
+     * region, as we only ever look up for y. */
+    top = 2;
+    gmin = params->gbat[1];
+    if (params->gbat[3] < gmin)
+        gmin = params->gbat[3];
+    if (params->gbat[5] < gmin)
+        gmin = params->gbat[5];
+    if (params->gbat[7] < gmin)
+        gmin = params->gbat[7];
+    if (top < -gmin)
+        top = -gmin;
+    /* So 0 <= y < top needs bounds checking. */
+
     for (y = 0; y < GBH; y++) {
         LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25], &code);
         if (code)
@@ -846,29 +887,57 @@
         if (!LTP) {
             for (x = 0; x < GBW; x++) {
                 if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
-                    jbig2_image_set_pixel(image, x, y, 0);
+                    jbig2_image_set_pixel_fast(image, x, y, 0);
                     continue;
                 }
-                CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
-                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
-                CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
-                CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
-                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
-                CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
-                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
-                CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7;
-                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
-                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
-                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
-                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
-                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
-                CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13;
-                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
-                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
+                if (y >= top && x >= left && x < right)
+                {
+                    CONTEXT = jbig2_image_get_pixel_fast(image, x - 1, y);
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 2, y) << 1;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 3, y) << 2;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 4, y) << 3;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[0], y + params->gbat[1]) << 4;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + 2, y - 1) << 5;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + 1, y - 1) << 6;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x, y - 1) << 7;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 1, y - 1) << 8;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 2, y - 1) << 9;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[2], y + params->gbat[3]) << 10;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[4], y + params->gbat[5]) << 11;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + 1, y - 2) << 12;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x, y - 2) << 13;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x - 1, y - 2) << 14;
+                    CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[6], y + params->gbat[7]) << 15;
+                }
+                else
+                {
+                    CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
+                    CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
+                    CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
+                    CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
+                    CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
+                    if (y >= 1)
+                    {
+                        CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
+                        CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
+                        CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7;
+                        CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
+                        CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
+                    }
+                    CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
+                    CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
+                    if (y >= 2)
+                    {
+                        CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
+                        CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13;
+                        CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
+                    }
+                    CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
+                }
                 bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
                 if (code)
                     return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2");
-                jbig2_image_set_pixel(image, x, y, bit);
+                jbig2_image_set_pixel_fast(image, x, y, bit);
             }
         } else {
             copy_prev_row(image, y);
--- a/jbig2_image.h
+++ b/jbig2_image.h
@@ -39,4 +39,28 @@
 int jbig2_image_get_pixel(Jbig2Image *image, int x, int y);
 void jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value);
 
+static inline int
+jbig2_image_get_pixel_fast(Jbig2Image *image, int x, int y)
+{
+    const int byte = (x >> 3) + y * image->stride;
+    const int bit = 7 - (x & 7);
+
+    return ((image->data[byte] >> bit) & 1);
+}
+
+/* set an individual pixel value in an image */
+static inline void
+jbig2_image_set_pixel_fast(Jbig2Image *image, int x, int y, bool value)
+{
+    int scratch, mask;
+    int bit, byte;
+
+    byte = (x >> 3) + y * image->stride;
+    bit = 7 - (x & 7);
+    mask = (1 << bit) ^ 0xff;
+
+    scratch = image->data[byte] & mask;
+    image->data[byte] = scratch | (value << bit);
+}
+
 #endif /* _JBIG2_IMAGE_H */