Commit Graph

30 Commits

Author SHA1 Message Date
DRC
607b668ff9 MSVC: Eliminate C4996 warnings in API libs
The primary purpose of this is to encourage adoption of libjpeg-turbo in
downstream Windows projects that forbid the use of "deprecated"
functions.  libjpeg-turbo's usage of those functions was not actually
unsafe, because:

- libjpeg-turbo always checks the return value of fopen() and ensures
  that a NULL filename can never be passed to it.

- libjpeg-turbo always checks the return value of getenv() and never
  passes a NULL argument to it.

- The sprintf() calls in format_message() (jerror.c) could never
  overflow the destination string buffer or leave it unterminated as
  long as the buffer was at least JMSG_LENGTH_MAX bytes in length, as
  instructed. (Regardless, this commit replaces those calls with
  snprintf() calls.)

- libjpeg-turbo never uses sscanf() to read strings or multi-byte
  character arrays.

- Because of b7d6e84d6a, wrjpgcom
  explicitly checks the bounds of the source and destination strings
  before calling strcat() and strcpy().

- libjpeg-turbo always ensures that the destination string is
  terminated when using strncpy().
  (548490fe5e made this explicit.)

Regarding thread safety:

Technically speaking, getenv() is not thread-safe, because the returned
pointer may be invalidated if another thread sets the same environment
variable between the time that the first thread calls getenv() and the
time that that thread uses the return value.  In practice, however, this
could only occur with libjpeg-turbo if:

(1) A multithreaded calling application used the deprecated and
undocumented TJFLAG_FORCEMMX/TJFLAG_FORCESSE/TJFLAG_FORCESSE2 flags in
the TurboJPEG API or set one of the corresponding environment variables
(which are only intended for testing purposes.)  Since the TurboJPEG API
library only ever passed string constants to putenv(), the only inherent
risk (i.e. the only risk introduced by the library and not the calling
application) was that the SIMD extensions may have read an incorrect
value from one of the aforementioned environment variables.

or

(2) A multithreaded calling application modified the value of the
JPEGMEM environment variable in one thread while another thread was
reading the value of that environment variable (in the body of
jpeg_create_compress() or jpeg_create_decompress().)  Given that the
libjpeg API provides a thread-safe way for applications to modify the
default memory limit without using the JPEGMEM environment variable,
direct modification of that environment variable by calling applications
is not supported.

Microsoft's implementation of getenv_s() does not claim to be
thread-safe either, so this commit uses getenv_s() solely to mollify
Visual Studio.  New inline functions and macros (GETENV_S() and
PUTENV_S) wrap getenv_s()/_putenv_s() when building for Visual Studio
and getenv()/setenv() otherwise, but GETENV_S()/PUTENV_S() provide no
advantages over getenv()/setenv() other than parameter validation.  They
are implemented solely for convenience.

Technically speaking, strerror() is not thread-safe, because the
returned pointer may be invalidated if another thread changes the locale
and/or calls strerror() between the time that the first thread calls
strerror() and the time that that thread uses the return value.  In
practice, however, this could only occur with libjpeg-turbo if a
multithreaded calling application encountered a file I/O error in
tjLoadImage() or tjSaveImage().  Since both of those functions
immediately copy the string returned from strerror() into a thread-local
buffer, the risk is minimal, and the worst case would involve an
incorrect error string being reported to the calling application.
Regardless, this commit uses strerror_s() in the TurboJPEG API library
when building for Visual Studio.  Note that strerror_r() could have been
used on Un*x systems, but it would have been necessary to handle both
the POSIX and GNU implementations of that function and perform
widespread compatibility testing.  Such is left as an exercise for
another day.

Fixes #568
2022-02-23 15:57:01 -06:00
DRC
e795afc330 SSE2: Fix prog Huff enc err if Sl%32==0 && Al!=0
(regression introduced by 16bd984557)

This implements the same fix for
jsimd_encode_mcu_AC_refine_prepare_sse2() that
a81a8c137b implemented for
jsimd_encode_mcu_AC_first_prepare_sse2().

Based on:
1a59587397
eb176a91d8

Fixes #509
Closes #510
2021-03-25 22:46:14 -05:00
DRC
7c1a1789d2 Merge branch 'master' into dev 2020-11-05 16:04:55 -06:00
DRC
6e632af9f6 Demote "fast" [I]DCT algorithms to legacy status
- Refer to the "slow" [I]DCT algorithms as "accurate" instead, since
  they are not slow under libjpeg-turbo.
- Adjust documentation claims to reflect the fact that the "slow" and
  "fast" algorithms produce about the same performance on AVX2-equipped
  CPUs (because of the dual-lane nature of AVX2, it was not possible to
  accelerate the "fast" algorithm beyond what was achievable with SSE2.)
  Also adjust the claims to reflect the fact that the "fast" algorithm
  tends to be ~5-15% faster than the "slow" algorithm on
  non-AVX2-equipped CPUs, regardless of the use of the libjpeg-turbo
  SIMD extensions.
- Indicate the legacy status of the "fast" and float algorithms in the
  documentation and cjpeg/djpeg usage info.
- Remove obsolete paragraph in the djpeg man page that suggested that
  the float algorithm could be faster than the "fast" algorithm on some
  CPUs.
2020-11-05 15:59:31 -06:00
DRC
9c6f79e919 Fix formatting issues detected by checkstyle 2019-11-14 12:16:38 -06:00
DRC
cbf0fcc8b7 i386 SSE2 Huffman: Fix pointer arithmetic issue
Splitting the pointer arithmetic in GET_SYM() into a separate add and
sub instruction was an attempt to work around an error ("invalid operand
type") that occurred when assembling the file with NASM.  However, this
created a link error on macOS ("ld: illegal text-relocation to
'_jconst_huff_encode_one_block' in
simd/CMakeFiles/simd.dir/i386/jchuff-sse2.asm.o from
'_jsimd_huff_encode_one_block_sse2' in
simd/CMakeFiles/simd.dir/i386/jchuff-sse2.asm.o for architecture i386")
and also changed the alignment of the code in ways that might have
affected the previous benchmark results (which took a great deal of time
to obtain.)  Ultimately, the path of least resistance is just to
require NASM 2.13 or later.
2019-11-05 15:56:28 -06:00
DRC
087c29e07f Optimize Huffman encoding
This commit improves the C and SSE2 Huffman encoding implementations in
the following ways:

- Avoid using xmm8-xmm15 in the x86-64 SSE2 implementation.  There is no
  actual need to use those registers, and avoiding them produces a
  cleaner WIN64 function entry/exit-- as well as shorter code, since REX
  prefixes can be avoided (this is helpful on certain CPUs, such as
  Intel Atom, for which instruction fetch and decoding can be a
  bottleneck.)
- Optimize register usage so that fewer REX prefixes and
  register-register moves are needed.
- Use the bit counter to store the number of free bits in the bit buffer
  rather than the number of bits in the bit buffer.  This changes the
  method for inserting a code into the bit buffer to:

  (put_buffer |= code << (free_bits -= code_size));

  As a result:
  * Only one bit counter needs to stay in a register (we just keep it in
    cl.)
  * The bit buffer contents are already properly aligned to be written
    out (after a byte swap.)
  * Adjusting the free bits counter and checking if the bit buffer is
    full can be combined into a single operation.
  * We can wait to flush the bit buffer until the buffer is actually
    full and not just in danger of becoming full.  Thus, eight bytes can
    be flushed at a time.

- Speed is quite sensitive to the alignment of branch target labels, so
  insert some padding and remove branches from the flush code.
  (Flushing this way isn't actually faster when compared to using
  branches, but the branchless code doesn't need extra alignment and is
  thus smaller.)
- Speculatively write out the bit buffer as a single 8-byte write,
  falling back to a byte-by-byte write only if there are any 0xFF bytes
  in the bit buffer that need to be encoded as 0xFF 0x00.
- Use MMX registers for the 32-bit implementation (so the bit buffer can
  be 64 bits wide.)
- Slightly reduce overall function code size.
- Eliminate or combine a few SSE instructions.
- Make some minor improvements to instruction scheduling.
- Adjust flush_bits() in jchuff.c to handle cases in which the bit
  buffer has less than 7 free bits (apparently that couldn't happen
  before.)

Based on:
947a09defa
262ebb6b81
6e9a091221

See change log for performance claims.

Closes #292
2019-11-04 19:04:05 -06:00
DRC
3a32d199df x86 SIMD: Consistify capitalization of NASM types
byte, word, dword, qword, oword, and yword are all assembler keywords,
so it makes sense to use lowercase for these so as not to mistake them
for macros or constants.
2019-10-17 20:02:20 -05:00
DRC
9a51a87af3 x86 SIMD: Remove obsolete [TAB8] comments
With apologies to Richard Hendricks, our assembly code no longer uses
tabs.
2019-10-17 14:11:35 -05:00
DRC
a81a8c137b SSE2 SIMD: Fix prog Huffman enc. error if Sl%16==0
(regression introduced by 5b177b3cab)

The SSE2 implementation of progressive Huffman encoding performed
extraneous iterations when the scan length was a multiple of 16.

Based on:
bb7f1ef983

Fixes #335
Closes #367
2019-08-14 22:01:30 -05:00
Chris Blume
aa9db61677 x86 SIMD: Check for CPUID leaf 07H before using
According to Intel's manual [1], "If a value entered for CPUID.EAX is
higher than the maximum input value for basic or extended function for
that processor then the data for the highest basic information leaf is
returned."

Right now, libjpeg-turbo doesn't first check that leaf 07H is supported
before attempting to use it, so the ostensible AVX2 bit (Bit 05) of the
CPUID result might actually be Bit 05 from a lower leaf.  That bit might
be set, even if the CPU doesn't support AVX2.

This commit modifies the x86 and x86-64 SIMD feature detection code so
that it first checks whether CPUID leaf 07H is supported before
attempting to use it to check for AVX2 instruction support.

DRC:
This commit should fix
https://bugzilla.mozilla.org/show_bug.cgi?id=1520760
However, I have not personally been able to reproduce that issue,
despite using a Nehalem (pre-AVX2) CPU on which the maximum CPUID leaf
has been limited via a BIOS setting.

Closes #348

[1]
"Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z", https://software.intel.com/sites/default/files/managed/a4/60/325383-sdm-vol-2abcd.pdf, page 3-192.
2019-04-16 17:07:28 -05:00
DRC
d5f281b734 SIMD: Fix c000001d exception on Win 7 w/o SP1
Apparently Windows 7 without SP1 has O/S support for XSAVE but not for
YMM registers, and this exposed a bug in our usage of xgetbv.  The test
instruction will set ZF only if none of the bits match between the two
operarands, so in effect, we were enabling AVX2 instructions if the O/S
supported XSAVE and the CPU supported AVX2 but the O/S only supported
XMM registers.  This bug was not exposed on, for instance, Windows XP or
RHEL 5 because those O/S's do not support XSAVE.

Fixes #288
2018-09-28 16:23:14 -05:00
mayeut
269e84c971 jsimd_can_encode_mcu_AC_*(): Remove useless checks
These were necessary for the first iteration of the feature (see #46),
which provided a different C front end for the SIMD version of the
function.  The final version of the feature uses a common C front end
for both SIMD and non-SIMD implementations, so these checks are no
longer necessary.

Closes #231
2018-04-09 21:30:25 -05:00
DRC
58cb10ee5f Eliminate compiler warnings w/ Solaris Studio 2018-03-31 14:03:37 -05:00
mayeut
5b177b3cab C/SSE2 optimization of encode_mcu_AC_first()
This commit adds C and SSE2 optimizations for the encode_mcu_AC_first()
function used in progressive Huffman encoding.

The image used for testing can be retrieved from this page:
https://blog.cloudflare.com/doubling-the-speed-of-jpegtran

All timings done on `Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz`
clang version is `Apple LLVM version 9.0.0 (clang-900.0.39.2)`
gcc-5 version is `gcc-5 (Homebrew GCC 5.5.0) 5.5.0`
gcc-7 version is `gcc-7 (Homebrew GCC 7.2.0) 7.2.0`

Here are the results in comparison to libjpeg-turbo@293263c using
`time ./jpegtran -outfile /dev/null -progressive -optimise -copy none print_poster_0025.jpg`

C
clang x86_64: +19%
gcc-5 x86_64: +80%
gcc-7 x86_64: +57%
clang i386: +5%
gcc-5 i386: +59%
gcc-7 i386: +51%

SSE2
clang x86_64: +79%
gcc-5 x86_64: +158%
gcc-7 x86_64: +122%
clang i386: +71%
gcc-5 i386: +134%
gcc-7 i386: +135%

Discussion in libjpeg-turbo/libjpeg-turbo#46
2018-03-22 15:49:23 -05:00
mayeut
16bd984557 C/SSE2 optimization of encode_mcu_AC_refine()
This commit adds C and SSE2 optimizations for the encode_mcu_AC_refine()
function used in progressive Huffman encoding.

The image used for testing can be retrieved from this page:
https://blog.cloudflare.com/doubling-the-speed-of-jpegtran

All timings done on `Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz`
clang version is `Apple LLVM version 9.0.0 (clang-900.0.39.2)`
gcc-5 version is `gcc-5 (Homebrew GCC 5.5.0) 5.5.0`
gcc-7 version is `gcc-7 (Homebrew GCC 7.2.0) 7.2.0`

Here are the results in comparison to libjpeg-turbo@3c54642 using
`time ./jpegtran -outfile /dev/null -progressive -optimise -copy none print_poster_0025.jpg`

C
clang x86_64: +7%
gcc-5 x86_64: +30%
gcc-7 x86_64: +33%
clang i386: +0%
gcc-5 i386: +24%
gcc-7 i386: +23%

SSE2
clang x86_64: +42%
gcc-5 x86_64: +53%
gcc-7 x86_64: +64%
clang i386: +35%
gcc-5 i386: +46%
gcc-7 i386: +49%

Discussion in libjpeg-turbo/libjpeg-turbo#46
2018-03-22 13:05:55 -05:00
DRC
81baa1b501 simd/i386/jchuff-sse2.asm: Minor formatting tweak 2018-03-21 13:03:30 -05:00
DRC
293263c352 Format preprocessor macros more consistently
Within the libjpeg API code, it seems to be more the convention than not
to separate the macro name and value by two or more spaces, which
improves general readability.  Making this consistent across all of
libjpeg-turbo is less about my individual preferences and more about
making it easy to automatically detect variations from our chosen
formatting convention.  I intend to release the script I'm using to
validate this stuff, once it matures and stabilizes a bit.
2018-03-17 15:19:41 -05:00
DRC
84fbd4f1ed Merge branch 'master' into dev 2018-03-17 00:27:49 -05:00
DRC
19c791cdac Improve code formatting consistency
With rare exceptions ...
- Always separate line continuation characters by one space from
  preceding code.
- Always use two-space indentation.  Never use tabs.
- Always use K&R-style conditional blocks.
- Always surround operators with spaces, except in raw assembly code.
- Always put a space after, but not before, a comma.
- Never put a space between type casts and variables/function calls.
- Never put a space between the function name and the argument list in
  function declarations and prototypes.
- Always surround braces ('{' and '}') with spaces.
- Always surround statements (if, for, else, catch, while, do, switch)
  with spaces.
- Always attach pointer symbols ('*' and '**') to the variable or
  function name.
- Always precede pointer symbols ('*' and '**') by a space in type
  casts.
- Use the MIN() macro from jpegint.h within the libjpeg and TurboJPEG
  API libraries (using min() from tjutil.h is still necessary for
  TJBench.)
- Where it makes sense (particularly in the TurboJPEG code), put a blank
  line after variable declaration blocks.
- Always separate statements in one-liners by two spaces.

The purpose of this was to ease maintenance on my part and also to make
it easier for contributors to figure out how to format patch
submissions.  This was admittedly confusing (even to me sometimes) when
we had 3 or 4 different style conventions in the same source tree.  The
new convention is more consistent with the formatting of other OSS code
bases.

This commit corrects deviations from the chosen formatting style in the
libjpeg API code and reformats the TurboJPEG API code such that it
conforms to the same standard.

NOTES:
- Although it is no longer necessary for the function name in function
  declarations to begin in Column 1 (this was historically necessary
  because of the ansi2knr utility, which allowed libjpeg to be built
  with non-ANSI compilers), we retain that formatting for the libjpeg
  code because it improves readability when using libjpeg's function
  attribute macros (GLOBAL(), etc.)
- This reformatting project was accomplished with the help of AStyle and
  Uncrustify, although neither was completely up to the task, and thus
  a great deal of manual tweaking was required.  Note to developers of
  code formatting utilities:  the libjpeg-turbo code base is an
  excellent test bed, because AFAICT, it breaks every single one of the
  utilities that are currently available.
- The legacy (MMX, SSE, 3DNow!) assembly code for i386 has been
  formatted to match the SSE2 code (refer to
  ff5685d5344273df321eb63a005eaae19d2496e3.)  I hadn't intended to
  bother with this, but the Loongson MMI implementation demonstrated
  that there is still academic value to the MMX implementation, as an
  algorithmic model for other 64-bit vector implementations.  Thus, it
  is desirable to improve its readability in the same manner as that of
  the SSE2 implementation.
2018-03-16 02:14:34 -05:00
DRC
35ed3c97b2 SIMD: Formatting tweaks + remove unnecessary code
+ "JSIMD_ARM_NEON" = "JSIMD_NEON"
+ "JSIMD_MIPS_DSPR2" = "JSIMD_DSPR2"
+ "*_mips_dspr2" = "*_dspr2"

It's obvious that "NEON" refers to Arm and "DSPr2" refers to MIPS, and
this naming convention is consistent with the other SIMD extensions.
2018-03-01 18:53:58 -06:00
mayeut
feaec37d32 Fix build with YASM
vinserti128 requires all operands to be specified
2018-02-24 16:50:03 -06:00
mayeut
88421563ad Make SIMD symbols private for x86[-64] ELF builds 2018-02-23 18:37:46 -06:00
DRC
9cdec16ceb 32-bit AVX2 implementation of slow int inverse DCT 2018-02-23 15:19:16 -06:00
DRC
845fe8bf80 32-bit AVX2 buglet: IS_ALIGNED_SSE=IS_ALIGNED_AVX 2018-02-23 12:24:10 -06:00
DRC
715b7c38a8 32-bit AVX2 implementation of int sample conv. 2018-02-19 00:24:53 -06:00
DRC
ca387e7fda 32-bit AVX2 implementation of slow int forward DCT 2018-02-19 00:00:55 -06:00
DRC
ff392d81ef AVX2: Introduce YMMBLOCK macro for readability 2018-02-17 17:29:38 -06:00
DRC
c0f3512d5a Merge branch 'master' into dev 2017-09-01 07:12:51 -05:00
DRC
6abd39160c Unified CMake-based build system
See #56 for discussion.

Fixes #21, Fixes #29, Fixes #37, Closes #56, Fixes #58, Closes #73
Obviates #82

See also:
https://sourceforge.net/p/libjpeg-turbo/feature-requests/5/
https://sourceforge.net/p/libjpeg-turbo/patches/5/
2016-11-22 13:06:30 -06:00