2023-12-26 15:14:24 -05:00
# if defined(_MSC_VER)
# pragma warning
# endif
2023-12-17 15:04:57 -05:00
/* stb_image_resize2 - v2.04 - public domain image resizing
by Jeff Roberts ( v2 ) and Jorge L Rodriguez
http : //github.com/nothings/stb
Can be threaded with the extended API . SSE2 , AVX , Neon and WASM SIMD support . Only
scaling and translation is supported , no rotations or shears .
COMPILING & LINKING
In one C / C + + file that # includes this file , do this :
# define STB_IMAGE_RESIZE_IMPLEMENTATION
before the # include . That will create the implementation in that file .
PORTING FROM VERSION 1
The API has changed . You can continue to use the old version of stb_image_resize . h ,
which is available in the " deprecated/ " directory .
If you ' re using the old simple - to - use API , porting is straightforward .
( For more advanced APIs , read the documentation . )
stbir_resize_uint8 ( ) :
- call ` stbir_resize_uint8_linear ` , cast channel count to ` stbir_pixel_layout `
stbir_resize_float ( ) :
- call ` stbir_resize_float_linear ` , cast channel count to ` stbir_pixel_layout `
stbir_resize_uint8_srgb ( ) :
- function name is unchanged
- cast channel count to ` stbir_pixel_layout `
- above is sufficient unless your image has alpha and it ' s not RGBA / BGRA
- in that case , follow the below instructions for stbir_resize_uint8_srgb_edgemode
stbir_resize_uint8_srgb_edgemode ( )
- switch to the " medium complexity " API
- stbir_resize ( ) , very similar API but a few more parameters :
- pixel_layout : cast channel count to ` stbir_pixel_layout `
- data_type : STBIR_TYPE_UINT8_SRGB
- edge : unchanged ( STBIR_EDGE_WRAP , etc . )
- filter : STBIR_FILTER_DEFAULT
- which channel is alpha is specified in stbir_pixel_layout , see enum for details
EASY API CALLS :
Easy API downsamples w / Mitchell filter , upsamples w / cubic interpolation , clamps to edge .
stbir_resize_uint8_srgb ( input_pixels , input_w , input_h , input_stride_in_bytes ,
output_pixels , output_w , output_h , output_stride_in_bytes ,
pixel_layout_enum )
stbir_resize_uint8_linear ( input_pixels , input_w , input_h , input_stride_in_bytes ,
output_pixels , output_w , output_h , output_stride_in_bytes ,
pixel_layout_enum )
stbir_resize_float_linear ( input_pixels , input_w , input_h , input_stride_in_bytes ,
output_pixels , output_w , output_h , output_stride_in_bytes ,
pixel_layout_enum )
If you pass NULL or zero for the output_pixels , we will allocate the output buffer
for you and return it from the function ( free with free ( ) or STBIR_FREE ) .
As a special case , XX_stride_in_bytes of 0 means packed continuously in memory .
API LEVELS
There are three levels of API - easy - to - use , medium - complexity and extended - complexity .
See the " header file " section of the source for API documentation .
ADDITIONAL DOCUMENTATION
MEMORY ALLOCATION
By default , we use malloc and free for memory allocation . To override the
memory allocation , before the implementation # include , add a :
# define STBIR_MALLOC(size,user_data) ...
# define STBIR_FREE(ptr,user_data) ...
Each resize makes exactly one call to malloc / free ( unless you use the
extended API where you can do one allocation for many resizes ) . Under
address sanitizer , we do separate allocations to find overread / writes .
PERFORMANCE
This library was written with an emphasis on performance . When testing
stb_image_resize with RGBA , the fastest mode is STBIR_4CHANNEL with
STBIR_TYPE_UINT8 pixels and CLAMPed edges ( which is what many other resize
libs do by default ) . Also , make sure SIMD is turned on of course ( default
for 64 - bit targets ) . Avoid WRAP edge mode if you want the fastest speed .
This library also comes with profiling built - in . If you define STBIR_PROFILE ,
you can use the advanced API and get low - level profiling information by
calling stbir_resize_extended_profile_info ( ) or stbir_resize_split_profile_info ( )
after a resize .
SIMD
Most of the routines have optimized SSE2 , AVX , NEON and WASM versions .
On Microsoft compilers , we automatically turn on SIMD for 64 - bit x64 and
ARM ; for 32 - bit x86 and ARM , you select SIMD mode by defining STBIR_SSE2 or
STBIR_NEON . For AVX and AVX2 , we auto - select it by detecting the / arch : AVX
or / arch : AVX2 switches . You can also always manually turn SSE2 , AVX or AVX2
support on by defining STBIR_SSE2 , STBIR_AVX or STBIR_AVX2 .
On Linux , SSE2 and Neon is on by default for 64 - bit x64 or ARM64 . For 32 - bit ,
we select x86 SIMD mode by whether you have - msse2 , - mavx or - mavx2 enabled
on the command line . For 32 - bit ARM , you must pass - mfpu = neon - vfpv4 for both
clang and GCC , but GCC also requires an additional - mfp16 - format = ieee to
automatically enable NEON .
On x86 platforms , you can also define STBIR_FP16C to turn on FP16C instructions
for converting back and forth to half - floats . This is autoselected when we
are using AVX2 . Clang and GCC also require the - mf16c switch . ARM always uses
the built - in half float hardware NEON instructions .
You can also tell us to use multiply - add instructions with STBIR_USE_FMA .
Because x86 doesn ' t always have fma , we turn it off by default to maintain
determinism across all platforms . If you don ' t care about non - FMA determinism
and are willing to restrict yourself to more recent x86 CPUs ( around the AVX
timeframe ) , then fma will give you around a 15 % speedup .
You can force off SIMD in all cases by defining STBIR_NO_SIMD . You can turn
off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2 . AVX is 10 %
to 40 % faster , and AVX2 is generally another 12 % .
ALPHA CHANNEL
Most of the resizing functions provide the ability to control how the alpha
channel of an image is processed .
When alpha represents transparency , it is important that when combining
colors with filtering , the pixels should not be treated equally ; they
should use a weighted average based on their alpha values . For example ,
if a pixel is 1 % opaque bright green and another pixel is 99 % opaque
black and you average them , the average will be 50 % opaque , but the
unweighted average and will be a middling green color , while the weighted
average will be nearly black . This means the unweighted version introduced
green energy that didn ' t exist in the source image .
( If you want to know why this makes sense , you can work out the math for
the following : consider what happens if you alpha composite a source image
over a fixed color and then average the output , vs . if you average the
source image pixels and then composite that over the same fixed color .
Only the weighted average produces the same result as the ground truth
composite - then - average result . )
Therefore , it is in general best to " alpha weight " the pixels when applying
filters to them . This essentially means multiplying the colors by the alpha
values before combining them , and then dividing by the alpha value at the
end .
The computer graphics industry introduced a technique called " premultiplied
alpha " or " associated alpha " in which image colors are stored in image files
already multiplied by their alpha . This saves some math when compositing ,
and also avoids the need to divide by the alpha at the end ( which is quite
inefficient ) . However , while premultiplied alpha is common in the movie CGI
industry , it is not commonplace in other industries like videogames , and most
consumer file formats are generally expected to contain not - premultiplied
colors . For example , Photoshop saves PNG files " unpremultiplied " , and web
browsers like Chrome and Firefox expect PNG images to be unpremultiplied .
Note that there are three possibilities that might describe your image
and resize expectation :
1. images are not premultiplied , alpha weighting is desired
2. images are not premultiplied , alpha weighting is not desired
3. images are premultiplied
Both case # 2 and case # 3 require the exact same math : no alpha weighting
should be applied or removed . Only case 1 requires extra math operations ;
the other two cases can be handled identically .
stb_image_resize expects case # 1 by default , applying alpha weighting to
images , expecting the input images to be unpremultiplied . This is what the
COLOR + ALPHA buffer types tell the resizer to do .
When you use the pixel layouts STBIR_RGBA , STBIR_BGRA , STBIR_ARGB ,
STBIR_ABGR , STBIR_RX , or STBIR_XR you are telling us that the pixels are
non - premultiplied . In these cases , the resizer will alpha weight the colors
( effectively creating the premultiplied image ) , do the filtering , and then
convert back to non - premult on exit .
When you use the pixel layouts STBIR_RGBA_PM , STBIR_RGBA_PM , STBIR_RGBA_PM ,
STBIR_RGBA_PM , STBIR_RX_PM or STBIR_XR_PM , you are telling that the pixels
ARE premultiplied . In this case , the resizer doesn ' t have to do the
premultipling - it can filter directly on the input . This about twice as
fast as the non - premultiplied case , so it ' s the right option if your data is
already setup correctly .
When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL , you are
telling us that there is no channel that represents transparency ; it may be
RGB and some unrelated fourth channel that has been stored in the alpha
channel , but it is actually not alpha . No special processing will be
performed .
The difference between the generic 4 or 2 channel layouts , and the
specialized _PM versions is with the _PM versions you are telling us that
the data * is * alpha , just don ' t premultiply it . That ' s important when
using SRGB pixel formats , we need to know where the alpha is , because
it is converted linearly ( rather than with the SRGB converters ) .
Because alpha weighting produces the same effect as premultiplying , you
even have the option with non - premultiplied inputs to let the resizer
produce a premultiplied output . Because the intially computed alpha - weighted
output image is effectively premultiplied , this is actually more performant
than the normal path which un - premultiplies the output image as a final step .
Finally , when converting both in and out of non - premulitplied space ( for
example , when using STBIR_RGBA ) , we go to somewhat heroic measures to
ensure that areas with zero alpha value pixels get something reasonable
in the RGB values . If you don ' t care about the RGB values of zero alpha
pixels , you can call the stbir_set_non_pm_alpha_speed_over_quality ( )
function - this runs a premultiplied resize about 25 % faster . That said ,
when you really care about speed , using premultiplied pixels for both in
and out ( STBIR_RGBA_PM , etc ) much faster than both of these premultiplied
options .
PIXEL LAYOUT CONVERSION
The resizer can convert from some pixel layouts to others . When using the
stbir_set_pixel_layouts ( ) , you can , for example , specify STBIR_RGBA
on input , and STBIR_ARGB on output , and it will re - organize the channels
during the resize . Currently , you can only convert between two pixel
layouts with the same number of channels .
DETERMINISM
We commit to being deterministic ( from x64 to ARM to scalar to SIMD , etc ) .
This requires compiling with fast - math off ( using at least / fp : precise ) .
Also , you must turn off fp - contracting ( which turns mult + adds into fmas ) !
We attempt to do this with pragmas , but with Clang , you usually want to add
- ffp - contract = off to the command line as well .
For 32 - bit x86 , you must use SSE and SSE2 codegen for determinism . That is ,
if the scalar x87 unit gets used at all , we immediately lose determinism .
On Microsoft Visual Studio 2008 and earlier , from what we can tell there is
no way to be deterministic in 32 - bit x86 ( some x87 always leaks in , even
with fp : strict ) . On 32 - bit x86 GCC , determinism requires both - msse2 and
- fpmath = sse .
Note that we will not be deterministic with float data containing NaNs -
the NaNs will propagate differently on different SIMD and platforms .
If you turn on STBIR_USE_FMA , then we will be deterministic with other
fma targets , but we will differ from non - fma targets ( this is unavoidable ,
because a fma isn ' t simply an add with a mult - it also introduces a
rounding difference compared to non - fma instruction sequences .
FLOAT PIXEL FORMAT RANGE
Any range of values can be used for the non - alpha float data that you pass
in ( 0 to 1 , - 1 to 1 , whatever ) . However , if you are inputting float values
but * outputting * bytes or shorts , you must use a range of 0 to 1 so that we
scale back properly . The alpha channel must also be 0 to 1 for any format
that does premultiplication prior to resizing .
Note also that with float output , using filters with negative lobes , the
output filtered values might go slightly out of range . You can define
STBIR_FLOAT_LOW_CLAMP and / or STBIR_FLOAT_HIGH_CLAMP to specify the range
to clamp to on output , if that ' s important .
MAX / MIN SCALE FACTORS
The input pixel resolutions are in integers , and we do the internal pointer
resolution in size_t sized integers . However , the scale ratio from input
resolution to output resolution is calculated in float form . This means
the effective possible scale ratio is limited to 24 bits ( or 16 million
to 1 ) . As you get close to the size of the float resolution ( again , 16
million pixels wide or high ) , you might start seeing float inaccuracy
issues in general in the pipeline . If you have to do extreme resizes ,
you can usually do this is multiple stages ( using float intermediate
buffers ) .
FLIPPED IMAGES
Stride is just the delta from one scanline to the next . This means you can
use a negative stride to handle inverted images ( point to the final
scanline and use a negative stride ) . You can invert the input or output ,
using negative strides .
DEFAULT FILTERS
For functions which don ' t provide explicit control over what filters to
use , you can change the compile - time defaults with :
# define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
# define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
See stbir_filter in the header - file section for the list of filters .
NEW FILTERS
A number of 1 D filter kernels are supplied . For a list of supported
filters , see the stbir_filter enum . You can install your own filters by
using the stbir_set_filter_callbacks function .
PROGRESS
For interactive use with slow resize operations , you can use the the
scanline callbacks in the extended API . It would have to be a * very * large
image resample to need progress though - we ' re very fast .
CEIL and FLOOR
In scalar mode , the only functions we use from math . h are ceilf and floorf ,
but if you have your own versions , you can define the STBIR_CEILF ( v ) and
STBIR_FLOORF ( v ) macros and we ' ll use them instead . In SIMD , we just use
our own versions .
ASSERT
Define STBIR_ASSERT ( boolval ) to override assert ( ) and not use assert . h
FUTURE TODOS
* For polyphase integral filters , we just memcpy the coeffs to dupe
them , but we should indirect and use the same coeff memory .
* Add pixel layout conversions for sensible different channel counts
( maybe , 1 - > 3 / 4 , 3 - > 4 , 4 - > 1 , 3 - > 1 ) .
* For SIMD encode and decode scanline routines , do any pre - aligning
for bad input / output buffer alignments and pitch ?
* For very wide scanlines , we should we do vertical strips to stay within
L2 cache . Maybe do chunks of 1 K pixels at a time . There would be
some pixel reconversion , but probably dwarfed by things falling out
of cache . Probably also something possible with alternating between
scattering and gathering at high resize scales ?
* Rewrite the coefficient generator to do many at once .
* AVX - 512 vertical kernels - worried about downclocking here .
* Convert the reincludes to macros when we know they aren ' t changing .
* Experiment with pivoting the horizontal and always using the
vertical filters ( which are faster , but perhaps not enough to overcome
the pivot cost and the extra memory touches ) . Need to buffer the whole
image so have to balance memory use .
* Most of our code is internally function pointers , should we compile
all the SIMD stuff always and dynamically dispatch ?
CONTRIBUTORS
Jeff Roberts : 2.0 implementation , optimizations , SIMD
Martins Mozeiko : NEON simd , WASM simd , clang and GCC whisperer .
Fabian Giesen : half float and srgb converters
Sean Barrett : API design , optimizations
Jorge L Rodriguez : Original 1.0 implementation
Aras Pranckevicius : bugfixes for 1.0
Nathan Reed : warning fixes for 1.0
REVISIONS
2.04 ( 2023 - 11 - 17 ) Fix for rare AVX bug , shadowed symbol ( thanks Nikola Smiljanic ) .
2.03 ( 2023 - 11 - 01 ) ASAN and TSAN warnings fixed , minor tweaks .
2.00 ( 2023 - 10 - 10 ) mostly new source : new api , optimizations , simd , vertical - first , etc
( 2 x - 5 x faster without simd , 4 x - 12 x faster with simd )
( in some cases , 20 x to 40 x faster - resizing to very small for example )
0.96 ( 2019 - 03 - 04 ) fixed warnings
0.95 ( 2017 - 07 - 23 ) fixed warnings
0.94 ( 2017 - 03 - 18 ) fixed warnings
0.93 ( 2017 - 03 - 03 ) fixed bug with certain combinations of heights
0.92 ( 2017 - 01 - 02 ) fix integer overflow on large ( > 2 GB ) images
0.91 ( 2016 - 04 - 02 ) fix warnings ; fix handling of subpixel regions
0.90 ( 2014 - 09 - 17 ) first released version
LICENSE
See end of file for license information .
*/
# if !defined(STB_IMAGE_RESIZE_DO_HORIZONTALS) && !defined(STB_IMAGE_RESIZE_DO_VERTICALS) && !defined(STB_IMAGE_RESIZE_DO_CODERS) // for internal re-includes
# ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
# define STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
# include <stddef.h>
# ifdef _MSC_VER
typedef unsigned char stbir_uint8 ;
typedef unsigned short stbir_uint16 ;
typedef unsigned int stbir_uint32 ;
typedef unsigned __int64 stbir_uint64 ;
# else
# include <stdint.h>
typedef uint8_t stbir_uint8 ;
typedef uint16_t stbir_uint16 ;
typedef uint32_t stbir_uint32 ;
typedef uint64_t stbir_uint64 ;
# endif
# ifdef _M_IX86_FP
# if ( _M_IX86_FP >= 1 )
# ifndef STBIR_SSE
# define STBIR_SSE
# endif
# endif
# endif
# if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2)
# ifndef STBIR_SSE2
# define STBIR_SSE2
# endif
# if defined(__AVX__) || defined(STBIR_AVX2)
# ifndef STBIR_AVX
# ifndef STBIR_NO_AVX
# define STBIR_AVX
# endif
# endif
# endif
# if defined(__AVX2__) || defined(STBIR_AVX2)
# ifndef STBIR_NO_AVX2
# ifndef STBIR_AVX2
# define STBIR_AVX2
# endif
# if defined( _MSC_VER ) && !defined(__clang__)
# ifndef STBIR_FP16C // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c
# define STBIR_FP16C
# endif
# endif
# endif
# endif
# ifdef __F16C__
# ifndef STBIR_FP16C // turn on FP16C instructions if the define is set (for clang and gcc)
# define STBIR_FP16C
# endif
# endif
# endif
# if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 && __ARM_FP16_FORMAT_IEEE != 0
# ifndef STBIR_NEON
# define STBIR_NEON
# endif
# endif
# if defined(_M_ARM)
# ifdef STBIR_USE_FMA
# undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
# endif
# endif
# if defined(__wasm__) && defined(__wasm_simd128__)
# ifndef STBIR_WASM
# define STBIR_WASM
# endif
# endif
# ifndef STBIRDEF
# ifdef STB_IMAGE_RESIZE_STATIC
# define STBIRDEF static
# else
# ifdef __cplusplus
# define STBIRDEF extern "C"
# else
# define STBIRDEF extern
# endif
# endif
# endif
//////////////////////////////////////////////////////////////////////////////
//// start "header file" ///////////////////////////////////////////////////
//
// Easy-to-use API:
//
// * stride is the offset between successive rows of image data
// in memory, in bytes. specify 0 for packed continuously in memory
// * colorspace is linear or sRGB as specified by function name
// * Uses the default filters
// * Uses edge mode clamped
// * returned result is 1 for success or 0 in case of an error.
// stbir_pixel_layout specifies:
// number of channels
// order of channels
// whether color is premultiplied by alpha
// for back compatibility, you can cast the old channel count to an stbir_pixel_layout
typedef enum
{
STBIR_1CHANNEL = 1 ,
STBIR_2CHANNEL = 2 ,
STBIR_RGB = 3 , // 3-chan, with order specified (for channel flipping)
STBIR_BGR = 0 , // 3-chan, with order specified (for channel flipping)
STBIR_4CHANNEL = 5 ,
STBIR_RGBA = 4 , // alpha formats, where alpha is NOT premultiplied into color channels
STBIR_BGRA = 6 ,
STBIR_ARGB = 7 ,
STBIR_ABGR = 8 ,
STBIR_RA = 9 ,
STBIR_AR = 10 ,
STBIR_RGBA_PM = 11 , // alpha formats, where alpha is premultiplied into color channels
STBIR_BGRA_PM = 12 ,
STBIR_ARGB_PM = 13 ,
STBIR_ABGR_PM = 14 ,
STBIR_RA_PM = 15 ,
STBIR_AR_PM = 16 ,
STBIR_RGBA_NO_AW = 11 , // alpha formats, where NO alpha weighting is applied at all!
STBIR_BGRA_NO_AW = 12 , // these are just synonyms for the _PM flags (which also do
STBIR_ARGB_NO_AW = 13 , // no alpha weighting). These names just make it more clear
STBIR_ABGR_NO_AW = 14 , // for some folks).
STBIR_RA_NO_AW = 15 ,
STBIR_AR_NO_AW = 16 ,
} stbir_pixel_layout ;
//===============================================================
// Simple-complexity API
//
// If output_pixels is NULL (0), then we will allocate the buffer and return it to you.
//--------------------------------
STBIRDEF unsigned char * stbir_resize_uint8_srgb ( const unsigned char * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
unsigned char * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_type ) ;
STBIRDEF unsigned char * stbir_resize_uint8_linear ( const unsigned char * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
unsigned char * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_type ) ;
STBIRDEF float * stbir_resize_float_linear ( const float * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
float * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_type ) ;
//===============================================================
//===============================================================
// Medium-complexity API
//
// This extends the easy-to-use API as follows:
//
// * Can specify the datatype - U8, U8_SRGB, U16, FLOAT, HALF_FLOAT
// * Edge wrap can selected explicitly
// * Filter can be selected explicitly
//--------------------------------
typedef enum
{
STBIR_EDGE_CLAMP = 0 ,
STBIR_EDGE_REFLECT = 1 ,
STBIR_EDGE_WRAP = 2 , // this edge mode is slower and uses more memory
STBIR_EDGE_ZERO = 3 ,
} stbir_edge ;
typedef enum
{
STBIR_FILTER_DEFAULT = 0 , // use same filter type that easy-to-use API chooses
STBIR_FILTER_BOX = 1 , // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
STBIR_FILTER_TRIANGLE = 2 , // On upsampling, produces same results as bilinear texture filtering
STBIR_FILTER_CUBICBSPLINE = 3 , // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
STBIR_FILTER_CATMULLROM = 4 , // An interpolating cubic spline
STBIR_FILTER_MITCHELL = 5 , // Mitchell-Netrevalli filter with B=1/3, C=1/3
STBIR_FILTER_POINT_SAMPLE = 6 , // Simple point sampling
STBIR_FILTER_OTHER = 7 , // User callback specified
} stbir_filter ;
typedef enum
{
STBIR_TYPE_UINT8 = 0 ,
STBIR_TYPE_UINT8_SRGB = 1 ,
STBIR_TYPE_UINT8_SRGB_ALPHA = 2 , // alpha channel, when present, should also be SRGB (this is very unusual)
STBIR_TYPE_UINT16 = 3 ,
STBIR_TYPE_FLOAT = 4 ,
STBIR_TYPE_HALF_FLOAT = 5
} stbir_datatype ;
// medium api
STBIRDEF void * stbir_resize ( const void * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
void * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_layout , stbir_datatype data_type ,
stbir_edge edge , stbir_filter filter ) ;
//===============================================================
//===============================================================
// Extended-complexity API
//
// This API exposes all resize functionality.
//
// * Separate filter types for each axis
// * Separate edge modes for each axis
// * Separate input and output data types
// * Can specify regions with subpixel correctness
// * Can specify alpha flags
// * Can specify a memory callback
// * Can specify a callback data type for pixel input and output
// * Can be threaded for a single resize
// * Can be used to resize many frames without recalculating the sampler info
//
// Use this API as follows:
// 1) Call the stbir_resize_init function on a local STBIR_RESIZE structure
// 2) Call any of the stbir_set functions
// 3) Optionally call stbir_build_samplers() if you are going to resample multiple times
// with the same input and output dimensions (like resizing video frames)
// 4) Resample by calling stbir_resize_extended().
// 5) Call stbir_free_samplers() if you called stbir_build_samplers()
//--------------------------------
// Types:
// INPUT CALLBACK: this callback is used for input scanlines
typedef void const * stbir_input_callback ( void * optional_output , void const * input_ptr , int num_pixels , int x , int y , void * context ) ;
// OUTPUT CALLBACK: this callback is used for output scanlines
typedef void stbir_output_callback ( void const * output_ptr , int num_pixels , int y , void * context ) ;
// callbacks for user installed filters
typedef float stbir__kernel_callback ( float x , float scale , void * user_data ) ; // centered at zero
typedef float stbir__support_callback ( float scale , void * user_data ) ;
// internal structure with precomputed scaling
typedef struct stbir__info stbir__info ;
typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override functions to set these values for future compatibility
{
void * user_data ;
void const * input_pixels ;
int input_w , input_h ;
double input_s0 , input_t0 , input_s1 , input_t1 ;
stbir_input_callback * input_cb ;
void * output_pixels ;
int output_w , output_h ;
int output_subx , output_suby , output_subw , output_subh ;
stbir_output_callback * output_cb ;
int input_stride_in_bytes ;
int output_stride_in_bytes ;
int splits ;
int fast_alpha ;
int needs_rebuild ;
int called_alloc ;
stbir_pixel_layout input_pixel_layout_public ;
stbir_pixel_layout output_pixel_layout_public ;
stbir_datatype input_data_type ;
stbir_datatype output_data_type ;
stbir_filter horizontal_filter , vertical_filter ;
stbir_edge horizontal_edge , vertical_edge ;
stbir__kernel_callback * horizontal_filter_kernel ; stbir__support_callback * horizontal_filter_support ;
stbir__kernel_callback * vertical_filter_kernel ; stbir__support_callback * vertical_filter_support ;
stbir__info * samplers ;
} STBIR_RESIZE ;
// extended complexity api
// First off, you must ALWAYS call stbir_resize_init on your resize structure before any of the other calls!
STBIRDEF void stbir_resize_init ( STBIR_RESIZE * resize ,
const void * input_pixels , int input_w , int input_h , int input_stride_in_bytes , // stride can be zero
void * output_pixels , int output_w , int output_h , int output_stride_in_bytes , // stride can be zero
stbir_pixel_layout pixel_layout , stbir_datatype data_type ) ;
//===============================================================
// You can update these parameters any time after resize_init and there is no cost
//--------------------------------
STBIRDEF void stbir_set_datatypes ( STBIR_RESIZE * resize , stbir_datatype input_type , stbir_datatype output_type ) ;
STBIRDEF void stbir_set_pixel_callbacks ( STBIR_RESIZE * resize , stbir_input_callback * input_cb , stbir_output_callback * output_cb ) ; // no callbacks by default
STBIRDEF void stbir_set_user_data ( STBIR_RESIZE * resize , void * user_data ) ; // pass back STBIR_RESIZE* by default
STBIRDEF void stbir_set_buffer_ptrs ( STBIR_RESIZE * resize , const void * input_pixels , int input_stride_in_bytes , void * output_pixels , int output_stride_in_bytes ) ;
//===============================================================
//===============================================================
// If you call any of these functions, you will trigger a sampler rebuild!
//--------------------------------
STBIRDEF int stbir_set_pixel_layouts ( STBIR_RESIZE * resize , stbir_pixel_layout input_pixel_layout , stbir_pixel_layout output_pixel_layout ) ; // sets new buffer layouts
STBIRDEF int stbir_set_edgemodes ( STBIR_RESIZE * resize , stbir_edge horizontal_edge , stbir_edge vertical_edge ) ; // CLAMP by default
STBIRDEF int stbir_set_filters ( STBIR_RESIZE * resize , stbir_filter horizontal_filter , stbir_filter vertical_filter ) ; // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default
STBIRDEF int stbir_set_filter_callbacks ( STBIR_RESIZE * resize , stbir__kernel_callback * horizontal_filter , stbir__support_callback * horizontal_support , stbir__kernel_callback * vertical_filter , stbir__support_callback * vertical_support ) ;
STBIRDEF int stbir_set_pixel_subrect ( STBIR_RESIZE * resize , int subx , int suby , int subw , int subh ) ; // sets both sub-regions (full regions by default)
STBIRDEF int stbir_set_input_subrect ( STBIR_RESIZE * resize , double s0 , double t0 , double s1 , double t1 ) ; // sets input sub-region (full region by default)
STBIRDEF int stbir_set_output_pixel_subrect ( STBIR_RESIZE * resize , int subx , int suby , int subw , int subh ) ; // sets output sub-region (full region by default)
// when inputting AND outputting non-premultiplied alpha pixels, we use a slower but higher quality technique
// that fills the zero alpha pixel's RGB values with something plausible. If you don't care about areas of
// zero alpha, you can call this function to get about a 25% speed improvement for STBIR_RGBA to STBIR_RGBA
// types of resizes.
STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality ( STBIR_RESIZE * resize , int non_pma_alpha_speed_over_quality ) ;
//===============================================================
//===============================================================
// You can call build_samplers to prebuild all the internal data we need to resample.
// Then, if you call resize_extended many times with the same resize, you only pay the
// cost once.
// If you do call build_samplers, you MUST call free_samplers eventually.
//--------------------------------
// This builds the samplers and does one allocation
STBIRDEF int stbir_build_samplers ( STBIR_RESIZE * resize ) ;
// You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits
STBIRDEF void stbir_free_samplers ( STBIR_RESIZE * resize ) ;
//===============================================================
// And this is the main function to perform the resize synchronously on one thread.
STBIRDEF int stbir_resize_extended ( STBIR_RESIZE * resize ) ;
//===============================================================
// Use these functions for multithreading.
// 1) You call stbir_build_samplers_with_splits first on the main thread
// 2) Then stbir_resize_with_split on each thread
// 3) stbir_free_samplers when done on the main thread
//--------------------------------
// This will build samplers for threading.
// You can pass in the number of threads you'd like to use (try_splits).
// It returns the number of splits (threads) that you can call it with.
/// It might be less if the image resize can't be split up that many ways.
STBIRDEF int stbir_build_samplers_with_splits ( STBIR_RESIZE * resize , int try_splits ) ;
// This function does a split of the resizing (you call this fuction for each
// split, on multiple threads). A split is a piece of the output resize pixel space.
// Note that you MUST call stbir_build_samplers_with_splits before stbir_resize_extended_split!
// Usually, you will always call stbir_resize_split with split_start as the thread_index
// and "1" for the split_count.
// But, if you have a weird situation where you MIGHT want 8 threads, but sometimes
// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the
// split_count each time to turn in into a 4 thread resize. (This is unusual).
STBIRDEF int stbir_resize_extended_split ( STBIR_RESIZE * resize , int split_start , int split_count ) ;
//===============================================================
//===============================================================
// Pixel Callbacks info:
//--------------------------------
// The input callback is super flexible - it calls you with the input address
// (based on the stride and base pointer), it gives you an optional_output
// pointer that you can fill, or you can just return your own pointer into
// your own data.
//
// You can also do conversion from non-supported data types if necessary - in
// this case, you ignore the input_ptr and just use the x and y parameters to
// calculate your own input_ptr based on the size of each non-supported pixel.
// (Something like the third example below.)
//
// You can also install just an input or just an output callback by setting the
// callback that you don't want to zero.
//
// First example, progress: (getting a callback that you can monitor the progress):
// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
// {
// percentage_done = y / input_height;
// return input_ptr; // use buffer from call
// }
//
// Next example, copying: (copy from some other buffer or stream):
// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
// {
// CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes );
// return optional_output; // return the optional buffer that we filled
// }
//
// Third example, input another buffer without copying: (zero-copy from other buffer):
// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
// {
// void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes );
// return pixels; // return pointer to your data without copying
// }
//
//
// The output callback is considerably simpler - it just calls you so that you can dump
// out each scanline. You could even directly copy out to disk if you have a simple format
// like TGA or BMP. You can also convert to other output types here if you want.
//
// Simple example:
// void const * my_output( void * output_ptr, int num_pixels, int y, void * context )
// {
// percentage_done = y / output_height;
// fwrite( output_ptr, pixel_width_in_bytes, num_pixels, output_file );
// }
//===============================================================
//===============================================================
// optional built-in profiling API
//--------------------------------
# ifdef STBIR_PROFILE
typedef struct STBIR_PROFILE_INFO
{
stbir_uint64 total_clocks ;
// how many clocks spent (of total_clocks) in the various resize routines, along with a string description
// there are "resize_count" number of zones
stbir_uint64 clocks [ 8 ] ;
char const * * descriptions ;
// count of clocks and descriptions
stbir_uint32 count ;
} STBIR_PROFILE_INFO ;
// use after calling stbir_resize_extended (or stbir_build_samplers or stbir_build_samplers_with_splits)
STBIRDEF void stbir_resize_build_profile_info ( STBIR_PROFILE_INFO * out_info , STBIR_RESIZE const * resize ) ;
// use after calling stbir_resize_extended
STBIRDEF void stbir_resize_extended_profile_info ( STBIR_PROFILE_INFO * out_info , STBIR_RESIZE const * resize ) ;
// use after calling stbir_resize_extended_split
STBIRDEF void stbir_resize_split_profile_info ( STBIR_PROFILE_INFO * out_info , STBIR_RESIZE const * resize , int split_start , int split_num ) ;
//===============================================================
# endif
//// end header file /////////////////////////////////////////////////////
# endif // STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
# if defined(STB_IMAGE_RESIZE_IMPLEMENTATION) || defined(STB_IMAGE_RESIZE2_IMPLEMENTATION)
# ifndef STBIR_ASSERT
# include <assert.h>
# define STBIR_ASSERT(x) assert(x)
# endif
# ifndef STBIR_MALLOC
# include <stdlib.h>
# define STBIR_MALLOC(size,user_data) ((void)(user_data), malloc(size))
# define STBIR_FREE(ptr,user_data) ((void)(user_data), free(ptr))
// (we used the comma operator to evaluate user_data, to avoid "unused parameter" warnings)
# endif
# ifdef _MSC_VER
# define stbir__inline __forceinline
# else
# define stbir__inline __inline__
// Clang address sanitizer
# if defined(__has_feature)
# if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer)
# ifndef STBIR__SEPARATE_ALLOCATIONS
# define STBIR__SEPARATE_ALLOCATIONS
# endif
# endif
# endif
# endif
// GCC and MSVC
# if defined(__SANITIZE_ADDRESS__)
# ifndef STBIR__SEPARATE_ALLOCATIONS
# define STBIR__SEPARATE_ALLOCATIONS
# endif
# endif
// Always turn off automatic FMA use - use STBIR_USE_FMA if you want.
// Otherwise, this is a determinism disaster.
# ifndef STBIR_DONT_CHANGE_FP_CONTRACT // override in case you don't want this behavior
# if defined(_MSC_VER) && !defined(__clang__)
# if _MSC_VER > 1200
# pragma fp_contract(off)
# endif
# elif defined(__GNUC__) && !defined(__clang__)
# pragma GCC optimize("fp-contract=off")
# else
# pragma STDC FP_CONTRACT OFF
# endif
# endif
# ifdef _MSC_VER
# define STBIR__UNUSED(v) (void)(v)
# else
# define STBIR__UNUSED(v) (void)sizeof(v)
# endif
# define STBIR__ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
# ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
# define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
# endif
# ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
# define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
# endif
# ifndef STBIR__HEADER_FILENAME
# define STBIR__HEADER_FILENAME "stb_image_resize2.h"
# endif
// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
typedef enum
{
STBIRI_1CHANNEL = 0 ,
STBIRI_2CHANNEL = 1 ,
STBIRI_RGB = 2 ,
STBIRI_BGR = 3 ,
STBIRI_4CHANNEL = 4 ,
STBIRI_RGBA = 5 ,
STBIRI_BGRA = 6 ,
STBIRI_ARGB = 7 ,
STBIRI_ABGR = 8 ,
STBIRI_RA = 9 ,
STBIRI_AR = 10 ,
STBIRI_RGBA_PM = 11 ,
STBIRI_BGRA_PM = 12 ,
STBIRI_ARGB_PM = 13 ,
STBIRI_ABGR_PM = 14 ,
STBIRI_RA_PM = 15 ,
STBIRI_AR_PM = 16 ,
} stbir_internal_pixel_layout ;
// define the public pixel layouts to not compile inside the implementation (to avoid accidental use)
# define STBIR_BGR bad_dont_use_in_implementation
# define STBIR_1CHANNEL STBIR_BGR
# define STBIR_2CHANNEL STBIR_BGR
# define STBIR_RGB STBIR_BGR
# define STBIR_RGBA STBIR_BGR
# define STBIR_4CHANNEL STBIR_BGR
# define STBIR_BGRA STBIR_BGR
# define STBIR_ARGB STBIR_BGR
# define STBIR_ABGR STBIR_BGR
# define STBIR_RA STBIR_BGR
# define STBIR_AR STBIR_BGR
# define STBIR_RGBA_PM STBIR_BGR
# define STBIR_BGRA_PM STBIR_BGR
# define STBIR_ARGB_PM STBIR_BGR
# define STBIR_ABGR_PM STBIR_BGR
# define STBIR_RA_PM STBIR_BGR
# define STBIR_AR_PM STBIR_BGR
// must match stbir_datatype
static unsigned char stbir__type_size [ ] = {
1 , 1 , 1 , 2 , 4 , 2 // STBIR_TYPE_UINT8,STBIR_TYPE_UINT8_SRGB,STBIR_TYPE_UINT8_SRGB_ALPHA,STBIR_TYPE_UINT16,STBIR_TYPE_FLOAT,STBIR_TYPE_HALF_FLOAT
} ;
// When gathering, the contributors are which source pixels contribute.
// When scattering, the contributors are which destination pixels are contributed to.
typedef struct
{
int n0 ; // First contributing pixel
int n1 ; // Last contributing pixel
} stbir__contributors ;
typedef struct
{
int lowest ; // First sample index for whole filter
int highest ; // Last sample index for whole filter
int widest ; // widest single set of samples for an output
} stbir__filter_extent_info ;
typedef struct
{
int n0 ; // First pixel of decode buffer to write to
int n1 ; // Last pixel of decode that will be written to
int pixel_offset_for_input ; // Pixel offset into input_scanline
} stbir__span ;
typedef struct stbir__scale_info
{
int input_full_size ;
int output_sub_size ;
float scale ;
float inv_scale ;
float pixel_shift ; // starting shift in output pixel space (in pixels)
int scale_is_rational ;
stbir_uint32 scale_numerator , scale_denominator ;
} stbir__scale_info ;
typedef struct
{
stbir__contributors * contributors ;
float * coefficients ;
stbir__contributors * gather_prescatter_contributors ;
float * gather_prescatter_coefficients ;
stbir__scale_info scale_info ;
float support ;
stbir_filter filter_enum ;
stbir__kernel_callback * filter_kernel ;
stbir__support_callback * filter_support ;
stbir_edge edge ;
int coefficient_width ;
int filter_pixel_width ;
int filter_pixel_margin ;
int num_contributors ;
int contributors_size ;
int coefficients_size ;
stbir__filter_extent_info extent_info ;
int is_gather ; // 0 = scatter, 1 = gather with scale >= 1, 2 = gather with scale < 1
int gather_prescatter_num_contributors ;
int gather_prescatter_coefficient_width ;
int gather_prescatter_contributors_size ;
int gather_prescatter_coefficients_size ;
} stbir__sampler ;
typedef struct
{
stbir__contributors conservative ;
int edge_sizes [ 2 ] ; // this can be less than filter_pixel_margin, if the filter and scaling falls off
stbir__span spans [ 2 ] ; // can be two spans, if doing input subrect with clamp mode WRAP
} stbir__extents ;
typedef struct
{
# ifdef STBIR_PROFILE
union
{
struct { stbir_uint64 total , looping , vertical , horizontal , decode , encode , alpha , unalpha ; } named ;
stbir_uint64 array [ 8 ] ;
} profile ;
stbir_uint64 * current_zone_excluded_ptr ;
# endif
float * decode_buffer ;
int ring_buffer_first_scanline ;
int ring_buffer_last_scanline ;
int ring_buffer_begin_index ; // first_scanline is at this index in the ring buffer
int start_output_y , end_output_y ;
int start_input_y , end_input_y ; // used in scatter only
# ifdef STBIR__SEPARATE_ALLOCATIONS
float * * ring_buffers ; // one pointer for each ring buffer
# else
float * ring_buffer ; // one big buffer that we index into
# endif
float * vertical_buffer ;
char no_cache_straddle [ 64 ] ;
} stbir__per_split_info ;
typedef void stbir__decode_pixels_func ( float * decode , int width_times_channels , void const * input ) ;
typedef void stbir__alpha_weight_func ( float * decode_buffer , int width_times_channels ) ;
typedef void stbir__horizontal_gather_channels_func ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer ,
stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width ) ;
typedef void stbir__alpha_unweight_func ( float * encode_buffer , int width_times_channels ) ;
typedef void stbir__encode_pixels_func ( void * output , int width_times_channels , float const * encode ) ;
struct stbir__info
{
# ifdef STBIR_PROFILE
union
{
struct { stbir_uint64 total , build , alloc , horizontal , vertical , cleanup , pivot ; } named ;
stbir_uint64 array [ 7 ] ;
} profile ;
stbir_uint64 * current_zone_excluded_ptr ;
# endif
stbir__sampler horizontal ;
stbir__sampler vertical ;
void const * input_data ;
void * output_data ;
int input_stride_bytes ;
int output_stride_bytes ;
int ring_buffer_length_bytes ; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_num_entries ; // Total number of entries in the ring buffer.
stbir_datatype input_type ;
stbir_datatype output_type ;
stbir_input_callback * in_pixels_cb ;
void * user_data ;
stbir_output_callback * out_pixels_cb ;
stbir__extents scanline_extents ;
void * alloced_mem ;
stbir__per_split_info * split_info ; // by default 1, but there will be N of these allocated based on the thread init you did
stbir__decode_pixels_func * decode_pixels ;
stbir__alpha_weight_func * alpha_weight ;
stbir__horizontal_gather_channels_func * horizontal_gather_channels ;
stbir__alpha_unweight_func * alpha_unweight ;
stbir__encode_pixels_func * encode_pixels ;
int alloced_total ;
int splits ; // count of splits
stbir_internal_pixel_layout input_pixel_layout_internal ;
stbir_internal_pixel_layout output_pixel_layout_internal ;
int input_color_and_type ;
int offset_x , offset_y ; // offset within output_data
int vertical_first ;
int channels ;
int effective_channels ; // same as channels, except on RGBA/ARGB (7), or XA/AX (3)
int alloc_ring_buffer_num_entries ; // Number of entries in the ring buffer that will be allocated
} ;
# define stbir__max_uint8_as_float 255.0f
# define stbir__max_uint16_as_float 65535.0f
# define stbir__max_uint8_as_float_inverted (1.0f / 255.0f)
# define stbir__max_uint16_as_float_inverted (1.0f / 65535.0f)
# define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
// min/max friendly
# define STBIR_CLAMP(x, xmin, xmax) do { \
if ( ( x ) < ( xmin ) ) ( x ) = ( xmin ) ; \
if ( ( x ) > ( xmax ) ) ( x ) = ( xmax ) ; \
} while ( 0 )
static stbir__inline int stbir__min ( int a , int b )
{
return a < b ? a : b ;
}
static stbir__inline int stbir__max ( int a , int b )
{
return a > b ? a : b ;
}
static float stbir__srgb_uchar_to_linear_float [ 256 ] = {
0.000000f , 0.000304f , 0.000607f , 0.000911f , 0.001214f , 0.001518f , 0.001821f , 0.002125f , 0.002428f , 0.002732f , 0.003035f ,
0.003347f , 0.003677f , 0.004025f , 0.004391f , 0.004777f , 0.005182f , 0.005605f , 0.006049f , 0.006512f , 0.006995f , 0.007499f ,
0.008023f , 0.008568f , 0.009134f , 0.009721f , 0.010330f , 0.010960f , 0.011612f , 0.012286f , 0.012983f , 0.013702f , 0.014444f ,
0.015209f , 0.015996f , 0.016807f , 0.017642f , 0.018500f , 0.019382f , 0.020289f , 0.021219f , 0.022174f , 0.023153f , 0.024158f ,
0.025187f , 0.026241f , 0.027321f , 0.028426f , 0.029557f , 0.030713f , 0.031896f , 0.033105f , 0.034340f , 0.035601f , 0.036889f ,
0.038204f , 0.039546f , 0.040915f , 0.042311f , 0.043735f , 0.045186f , 0.046665f , 0.048172f , 0.049707f , 0.051269f , 0.052861f ,
0.054480f , 0.056128f , 0.057805f , 0.059511f , 0.061246f , 0.063010f , 0.064803f , 0.066626f , 0.068478f , 0.070360f , 0.072272f ,
0.074214f , 0.076185f , 0.078187f , 0.080220f , 0.082283f , 0.084376f , 0.086500f , 0.088656f , 0.090842f , 0.093059f , 0.095307f ,
0.097587f , 0.099899f , 0.102242f , 0.104616f , 0.107023f , 0.109462f , 0.111932f , 0.114435f , 0.116971f , 0.119538f , 0.122139f ,
0.124772f , 0.127438f , 0.130136f , 0.132868f , 0.135633f , 0.138432f , 0.141263f , 0.144128f , 0.147027f , 0.149960f , 0.152926f ,
0.155926f , 0.158961f , 0.162029f , 0.165132f , 0.168269f , 0.171441f , 0.174647f , 0.177888f , 0.181164f , 0.184475f , 0.187821f ,
0.191202f , 0.194618f , 0.198069f , 0.201556f , 0.205079f , 0.208637f , 0.212231f , 0.215861f , 0.219526f , 0.223228f , 0.226966f ,
0.230740f , 0.234551f , 0.238398f , 0.242281f , 0.246201f , 0.250158f , 0.254152f , 0.258183f , 0.262251f , 0.266356f , 0.270498f ,
0.274677f , 0.278894f , 0.283149f , 0.287441f , 0.291771f , 0.296138f , 0.300544f , 0.304987f , 0.309469f , 0.313989f , 0.318547f ,
0.323143f , 0.327778f , 0.332452f , 0.337164f , 0.341914f , 0.346704f , 0.351533f , 0.356400f , 0.361307f , 0.366253f , 0.371238f ,
0.376262f , 0.381326f , 0.386430f , 0.391573f , 0.396755f , 0.401978f , 0.407240f , 0.412543f , 0.417885f , 0.423268f , 0.428691f ,
0.434154f , 0.439657f , 0.445201f , 0.450786f , 0.456411f , 0.462077f , 0.467784f , 0.473532f , 0.479320f , 0.485150f , 0.491021f ,
0.496933f , 0.502887f , 0.508881f , 0.514918f , 0.520996f , 0.527115f , 0.533276f , 0.539480f , 0.545725f , 0.552011f , 0.558340f ,
0.564712f , 0.571125f , 0.577581f , 0.584078f , 0.590619f , 0.597202f , 0.603827f , 0.610496f , 0.617207f , 0.623960f , 0.630757f ,
0.637597f , 0.644480f , 0.651406f , 0.658375f , 0.665387f , 0.672443f , 0.679543f , 0.686685f , 0.693872f , 0.701102f , 0.708376f ,
0.715694f , 0.723055f , 0.730461f , 0.737911f , 0.745404f , 0.752942f , 0.760525f , 0.768151f , 0.775822f , 0.783538f , 0.791298f ,
0.799103f , 0.806952f , 0.814847f , 0.822786f , 0.830770f , 0.838799f , 0.846873f , 0.854993f , 0.863157f , 0.871367f , 0.879622f ,
0.887923f , 0.896269f , 0.904661f , 0.913099f , 0.921582f , 0.930111f , 0.938686f , 0.947307f , 0.955974f , 0.964686f , 0.973445f ,
0.982251f , 0.991102f , 1.0f
} ;
typedef union
{
unsigned int u ;
float f ;
} stbir__FP32 ;
// From https://gist.github.com/rygorous/2203834
static const stbir_uint32 fp32_to_srgb8_tab4 [ 104 ] = {
0x0073000d , 0x007a000d , 0x0080000d , 0x0087000d , 0x008d000d , 0x0094000d , 0x009a000d , 0x00a1000d ,
0x00a7001a , 0x00b4001a , 0x00c1001a , 0x00ce001a , 0x00da001a , 0x00e7001a , 0x00f4001a , 0x0101001a ,
0x010e0033 , 0x01280033 , 0x01410033 , 0x015b0033 , 0x01750033 , 0x018f0033 , 0x01a80033 , 0x01c20033 ,
0x01dc0067 , 0x020f0067 , 0x02430067 , 0x02760067 , 0x02aa0067 , 0x02dd0067 , 0x03110067 , 0x03440067 ,
0x037800ce , 0x03df00ce , 0x044600ce , 0x04ad00ce , 0x051400ce , 0x057b00c5 , 0x05dd00bc , 0x063b00b5 ,
0x06970158 , 0x07420142 , 0x07e30130 , 0x087b0120 , 0x090b0112 , 0x09940106 , 0x0a1700fc , 0x0a9500f2 ,
0x0b0f01cb , 0x0bf401ae , 0x0ccb0195 , 0x0d950180 , 0x0e56016e , 0x0f0d015e , 0x0fbc0150 , 0x10630143 ,
0x11070264 , 0x1238023e , 0x1357021d , 0x14660201 , 0x156601e9 , 0x165a01d3 , 0x174401c0 , 0x182401af ,
0x18fe0331 , 0x1a9602fe , 0x1c1502d2 , 0x1d7e02ad , 0x1ed4028d , 0x201a0270 , 0x21520256 , 0x227d0240 ,
0x239f0443 , 0x25c003fe , 0x27bf03c4 , 0x29a10392 , 0x2b6a0367 , 0x2d1d0341 , 0x2ebe031f , 0x304d0300 ,
0x31d105b0 , 0x34a80555 , 0x37520507 , 0x39d504c5 , 0x3c37048b , 0x3e7c0458 , 0x40a8042a , 0x42bd0401 ,
0x44c20798 , 0x488e071e , 0x4c1c06b6 , 0x4f76065d , 0x52a50610 , 0x55ac05cc , 0x5892058f , 0x5b590559 ,
0x5e0c0a23 , 0x631c0980 , 0x67db08f6 , 0x6c55087f , 0x70940818 , 0x74a007bd , 0x787d076c , 0x7c330723 ,
} ;
static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar ( float in )
{
static const stbir__FP32 almostone = { 0x3f7fffff } ; // 1-eps
static const stbir__FP32 minval = { ( 127 - 13 ) < < 23 } ;
stbir_uint32 tab , bias , scale , t ;
stbir__FP32 f ;
// Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
// The tests are carefully written so that NaNs map to 0, same as in the reference
// implementation.
if ( ! ( in > minval . f ) ) // written this way to catch NaNs
return 0 ;
if ( in > almostone . f )
return 255 ;
// Do the table lookup and unpack bias, scale
f . f = in ;
tab = fp32_to_srgb8_tab4 [ ( f . u - minval . u ) > > 20 ] ;
bias = ( tab > > 16 ) < < 9 ;
scale = tab & 0xffff ;
// Grab next-highest mantissa bits and perform linear interpolation
t = ( f . u > > 12 ) & 0xff ;
return ( unsigned char ) ( ( bias + scale * t ) > > 16 ) ;
}
# ifndef STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT
# define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win.
# endif
# ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS
# define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split?
# endif
// restrict pointers for the output pointers
# if defined( _MSC_VER ) && !defined(__clang__)
# define STBIR_STREAMOUT_PTR( star ) star __restrict
# define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop
# elif defined( __clang__ )
# define STBIR_STREAMOUT_PTR( star ) star __restrict__
# define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
# elif defined( __GNUC__ )
# define STBIR_STREAMOUT_PTR( star ) star __restrict__
# define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
# else
# define STBIR_STREAMOUT_PTR( star ) star
# define STBIR_NO_UNROLL( ptr )
# endif
# ifdef STBIR_NO_SIMD // force simd off for whatever reason
// force simd off overrides everything else, so clear it all
# ifdef STBIR_SSE2
# undef STBIR_SSE2
# endif
# ifdef STBIR_AVX
# undef STBIR_AVX
# endif
# ifdef STBIR_NEON
# undef STBIR_NEON
# endif
# ifdef STBIR_AVX2
# undef STBIR_AVX2
# endif
# ifdef STBIR_FP16C
# undef STBIR_FP16C
# endif
# ifdef STBIR_WASM
# undef STBIR_WASM
# endif
# ifdef STBIR_SIMD
# undef STBIR_SIMD
# endif
# else // STBIR_SIMD
# ifdef STBIR_SSE2
# include <emmintrin.h>
# define stbir__simdf __m128
# define stbir__simdi __m128i
# define stbir_simdi_castf( reg ) _mm_castps_si128(reg)
# define stbir_simdf_casti( reg ) _mm_castsi128_ps(reg)
# define stbir__simdf_load( reg, ptr ) (reg) = _mm_loadu_ps( (float const*)(ptr) )
# define stbir__simdi_load( reg, ptr ) (reg) = _mm_loadu_si128 ( (stbir__simdi const*)(ptr) )
# define stbir__simdf_load1( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdi_load1( out, ptr ) (out) = _mm_castps_si128( _mm_load_ss( (float const*)(ptr) ))
# define stbir__simdf_load1z( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) ) // top values must be zero
# define stbir__simdf_frep4( fvar ) _mm_set_ps1( fvar )
# define stbir__simdf_load1frep4( out, fvar ) (out) = _mm_set_ps1( fvar )
# define stbir__simdf_load2( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdf_load2z( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values must be zero
# define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = _mm_castpd_ps(_mm_loadh_pd( _mm_castps_pd(reg), (double*)(ptr) ))
# define stbir__simdf_zeroP() _mm_setzero_ps()
# define stbir__simdf_zero( reg ) (reg) = _mm_setzero_ps()
# define stbir__simdf_store( ptr, reg ) _mm_storeu_ps( (float*)(ptr), reg )
# define stbir__simdf_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), reg )
# define stbir__simdf_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), _mm_castps_si128(reg) )
# define stbir__simdf_store2h( ptr, reg ) _mm_storeh_pd( (double*)(ptr), _mm_castps_pd(reg) )
# define stbir__simdi_store( ptr, reg ) _mm_storeu_si128( (__m128i*)(ptr), reg )
# define stbir__simdi_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), _mm_castsi128_ps(reg) )
# define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) )
# define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 )
# define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
{ \
stbir__simdi zero = _mm_setzero_si128 ( ) ; \
out2 = _mm_unpacklo_epi8 ( ireg , zero ) ; \
out3 = _mm_unpackhi_epi8 ( ireg , zero ) ; \
out0 = _mm_unpacklo_epi16 ( out2 , zero ) ; \
out1 = _mm_unpackhi_epi16 ( out2 , zero ) ; \
out2 = _mm_unpacklo_epi16 ( out3 , zero ) ; \
out3 = _mm_unpackhi_epi16 ( out3 , zero ) ; \
}
# define stbir__simdi_expand_u8_to_1u32(out,ireg) \
{ \
stbir__simdi zero = _mm_setzero_si128 ( ) ; \
out = _mm_unpacklo_epi8 ( ireg , zero ) ; \
out = _mm_unpacklo_epi16 ( out , zero ) ; \
}
# define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
{ \
stbir__simdi zero = _mm_setzero_si128 ( ) ; \
out0 = _mm_unpacklo_epi16 ( ireg , zero ) ; \
out1 = _mm_unpackhi_epi16 ( ireg , zero ) ; \
}
# define stbir__simdf_convert_float_to_i32( i, f ) (i) = _mm_cvttps_epi32(f)
# define stbir__simdf_convert_float_to_int( f ) _mm_cvtt_ss2si(f)
# define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps()))))
# define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps()))))
# define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i)
# define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg )
# define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 )
# define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 )
# define stbir__simdf_mult_mem( out, reg, ptr ) (out) = _mm_mul_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )
# define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = _mm_mul_ss( reg, _mm_load_ss( (float const*)(ptr) ) )
# define stbir__simdf_add_mem( out, reg, ptr ) (out) = _mm_add_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )
# define stbir__simdf_add1_mem( out, reg, ptr ) (out) = _mm_add_ss( reg, _mm_load_ss( (float const*)(ptr) ) )
# ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd
# include <immintrin.h>
# define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_fmadd_ps( mul1, mul2, add )
# define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_fmadd_ss( mul1, mul2, add )
# define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ps( mul, _mm_loadu_ps( (float const*)(ptr) ), add )
# define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ss( mul, _mm_load_ss( (float const*)(ptr) ), add )
# else
# define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_add_ps( add, _mm_mul_ps( mul1, mul2 ) )
# define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_add_ss( add, _mm_mul_ss( mul1, mul2 ) )
# define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_add_ps( add, _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) )
# define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_add_ss( add, _mm_mul_ss( mul, _mm_load_ss( (float const*)(ptr) ) ) )
# endif
# define stbir__simdf_add1( out, reg0, reg1 ) (out) = _mm_add_ss( reg0, reg1 )
# define stbir__simdf_mult1( out, reg0, reg1 ) (out) = _mm_mul_ss( reg0, reg1 )
# define stbir__simdf_and( out, reg0, reg1 ) (out) = _mm_and_ps( reg0, reg1 )
# define stbir__simdf_or( out, reg0, reg1 ) (out) = _mm_or_ps( reg0, reg1 )
# define stbir__simdf_min( out, reg0, reg1 ) (out) = _mm_min_ps( reg0, reg1 )
# define stbir__simdf_max( out, reg0, reg1 ) (out) = _mm_max_ps( reg0, reg1 )
# define stbir__simdf_min1( out, reg0, reg1 ) (out) = _mm_min_ss( reg0, reg1 )
# define stbir__simdf_max1( out, reg0, reg1 ) (out) = _mm_max_ss( reg0, reg1 )
# define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (3<<0) + (0<<2) + (1<<4) + (2<<6) ) )
# define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (2<<0) + (3<<2) + (0<<4) + (1<<6) ) )
static const stbir__simdf STBIR_zeroones = { 0.0f , 1.0f , 0.0f , 1.0f } ;
static const stbir__simdf STBIR_onezeros = { 1.0f , 0.0f , 1.0f , 0.0f } ;
# define stbir__simdf_aaa1( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movehl_ps( ones, alp ) ), (1<<0) + (1<<2) + (1<<4) + (2<<6) ) )
# define stbir__simdf_1aaa( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movelh_ps( ones, alp ) ), (0<<0) + (2<<2) + (2<<4) + (2<<6) ) )
# define stbir__simdf_a1a1( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_srli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_zeroones )
# define stbir__simdf_1a1a( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_slli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_onezeros )
# define stbir__simdf_swiz( reg, one, two, three, four ) _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( reg ), (one<<0) + (two<<2) + (three<<4) + (four<<6) ) )
# define stbir__simdi_and( out, reg0, reg1 ) (out) = _mm_and_si128( reg0, reg1 )
# define stbir__simdi_or( out, reg0, reg1 ) (out) = _mm_or_si128( reg0, reg1 )
# define stbir__simdi_16madd( out, reg0, reg1 ) (out) = _mm_madd_epi16( reg0, reg1 )
# define stbir__simdf_pack_to_8bytes(out,aa,bb) \
{ \
stbir__simdf af , bf ; \
stbir__simdi a , b ; \
af = _mm_min_ps ( aa , STBIR_max_uint8_as_float ) ; \
bf = _mm_min_ps ( bb , STBIR_max_uint8_as_float ) ; \
af = _mm_max_ps ( af , _mm_setzero_ps ( ) ) ; \
bf = _mm_max_ps ( bf , _mm_setzero_ps ( ) ) ; \
a = _mm_cvttps_epi32 ( af ) ; \
b = _mm_cvttps_epi32 ( bf ) ; \
a = _mm_packs_epi32 ( a , b ) ; \
out = _mm_packus_epi16 ( a , a ) ; \
}
# define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
stbir__simdf_load ( o0 , ( ptr ) ) ; \
stbir__simdf_load ( o1 , ( ptr ) + 4 ) ; \
stbir__simdf_load ( o2 , ( ptr ) + 8 ) ; \
stbir__simdf_load ( o3 , ( ptr ) + 12 ) ; \
{ \
__m128 tmp0 , tmp1 , tmp2 , tmp3 ; \
tmp0 = _mm_unpacklo_ps ( o0 , o1 ) ; \
tmp2 = _mm_unpacklo_ps ( o2 , o3 ) ; \
tmp1 = _mm_unpackhi_ps ( o0 , o1 ) ; \
tmp3 = _mm_unpackhi_ps ( o2 , o3 ) ; \
o0 = _mm_movelh_ps ( tmp0 , tmp2 ) ; \
o1 = _mm_movehl_ps ( tmp2 , tmp0 ) ; \
o2 = _mm_movelh_ps ( tmp1 , tmp3 ) ; \
o3 = _mm_movehl_ps ( tmp3 , tmp1 ) ; \
}
# define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
r0 = _mm_packs_epi32 ( r0 , r1 ) ; \
r2 = _mm_packs_epi32 ( r2 , r3 ) ; \
r1 = _mm_unpacklo_epi16 ( r0 , r2 ) ; \
r3 = _mm_unpackhi_epi16 ( r0 , r2 ) ; \
r0 = _mm_unpacklo_epi16 ( r1 , r3 ) ; \
r2 = _mm_unpackhi_epi16 ( r1 , r3 ) ; \
r0 = _mm_packus_epi16 ( r0 , r2 ) ; \
stbir__simdi_store ( ptr , r0 ) ; \
# define stbir__simdi_32shr( out, reg, imm ) out = _mm_srli_epi32( reg, imm )
# if defined(_MSC_VER) && !defined(__clang__)
// msvc inits with 8 bytes
# define STBIR__CONST_32_TO_8( v ) (char)(unsigned char)((v)&255),(char)(unsigned char)(((v)>>8)&255),(char)(unsigned char)(((v)>>16)&255),(char)(unsigned char)(((v)>>24)&255)
# define STBIR__CONST_4_32i( v ) STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v )
# define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) STBIR__CONST_32_TO_8( v0 ), STBIR__CONST_32_TO_8( v1 ), STBIR__CONST_32_TO_8( v2 ), STBIR__CONST_32_TO_8( v3 )
# else
// everything else inits with long long's
# define STBIR__CONST_4_32i( v ) (long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))),(long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v)))
# define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) (long long)((((stbir_uint64)(stbir_uint32)(v1))<<32)|((stbir_uint64)(stbir_uint32)(v0))),(long long)((((stbir_uint64)(stbir_uint32)(v3))<<32)|((stbir_uint64)(stbir_uint32)(v2)))
# endif
# define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }
# define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { STBIR__CONST_4_32i(x) }
# define STBIR__CONSTF(var) (var)
# define STBIR__CONSTI(var) (var)
# if defined(STBIR_AVX) || defined(__SSE4_1__)
# include <smmintrin.h>
# define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))
# else
STBIR__SIMDI_CONST ( stbir__s32_32768 , 32768 ) ;
STBIR__SIMDI_CONST ( stbir__s16_32768 , ( ( 32768 < < 16 ) | 32768 ) ) ;
# define stbir__simdf_pack_to_8words(out,reg0,reg1) \
{ \
stbir__simdi tmp0 , tmp1 ; \
tmp0 = _mm_cvttps_epi32 ( _mm_max_ps ( _mm_min_ps ( reg0 , STBIR__CONSTF ( STBIR_max_uint16_as_float ) ) , _mm_setzero_ps ( ) ) ) ; \
tmp1 = _mm_cvttps_epi32 ( _mm_max_ps ( _mm_min_ps ( reg1 , STBIR__CONSTF ( STBIR_max_uint16_as_float ) ) , _mm_setzero_ps ( ) ) ) ; \
tmp0 = _mm_sub_epi32 ( tmp0 , stbir__s32_32768 ) ; \
tmp1 = _mm_sub_epi32 ( tmp1 , stbir__s32_32768 ) ; \
out = _mm_packs_epi32 ( tmp0 , tmp1 ) ; \
out = _mm_sub_epi16 ( out , stbir__s16_32768 ) ; \
}
# endif
# define STBIR_SIMD
// if we detect AVX, set the simd8 defines
# ifdef STBIR_AVX
# include <immintrin.h>
# define STBIR_SIMD8
# define stbir__simdf8 __m256
# define stbir__simdi8 __m256i
# define stbir__simdf8_load( out, ptr ) (out) = _mm256_loadu_ps( (float const *)(ptr) )
# define stbir__simdi8_load( out, ptr ) (out) = _mm256_loadu_si256( (__m256i const *)(ptr) )
# define stbir__simdf8_mult( out, a, b ) (out) = _mm256_mul_ps( (a), (b) )
# define stbir__simdf8_store( ptr, out ) _mm256_storeu_ps( (float*)(ptr), out )
# define stbir__simdi8_store( ptr, reg ) _mm256_storeu_si256( (__m256i*)(ptr), reg )
# define stbir__simdf8_frep8( fval ) _mm256_set1_ps( fval )
# define stbir__simdf8_min( out, reg0, reg1 ) (out) = _mm256_min_ps( reg0, reg1 )
# define stbir__simdf8_max( out, reg0, reg1 ) (out) = _mm256_max_ps( reg0, reg1 )
# define stbir__simdf8_add4halves( out, bot4, top8 ) (out) = _mm_add_ps( bot4, _mm256_extractf128_ps( top8, 1 ) )
# define stbir__simdf8_mult_mem( out, reg, ptr ) (out) = _mm256_mul_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )
# define stbir__simdf8_add_mem( out, reg, ptr ) (out) = _mm256_add_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )
# define stbir__simdf8_add( out, a, b ) (out) = _mm256_add_ps( a, b )
# define stbir__simdf8_load1b( out, ptr ) (out) = _mm256_broadcast_ss( ptr )
# define stbir__simdf_load1rep4( out, ptr ) (out) = _mm_broadcast_ss( ptr ) // avx load instruction
# define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg )
# define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f)
# define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) )
# define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) )
# define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1)
# ifdef STBIR_AVX2
# define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \
{ \
stbir__simdi8 a , zero = _mm256_setzero_si256 ( ) ; \
a = _mm256_permute4x64_epi64 ( _mm256_unpacklo_epi8 ( _mm256_permute4x64_epi64 ( _mm256_castsi128_si256 ( ireg ) , ( 0 < < 0 ) + ( 2 < < 2 ) + ( 1 < < 4 ) + ( 3 < < 6 ) ) , zero ) , ( 0 < < 0 ) + ( 2 < < 2 ) + ( 1 < < 4 ) + ( 3 < < 6 ) ) ; \
out0 = _mm256_unpacklo_epi16 ( a , zero ) ; \
out1 = _mm256_unpackhi_epi16 ( a , zero ) ; \
}
# define stbir__simdf8_pack_to_16bytes(out,aa,bb) \
{ \
stbir__simdi8 t ; \
stbir__simdf8 af , bf ; \
stbir__simdi8 a , b ; \
af = _mm256_min_ps ( aa , STBIR_max_uint8_as_floatX ) ; \
bf = _mm256_min_ps ( bb , STBIR_max_uint8_as_floatX ) ; \
af = _mm256_max_ps ( af , _mm256_setzero_ps ( ) ) ; \
bf = _mm256_max_ps ( bf , _mm256_setzero_ps ( ) ) ; \
a = _mm256_cvttps_epi32 ( af ) ; \
b = _mm256_cvttps_epi32 ( bf ) ; \
t = _mm256_permute4x64_epi64 ( _mm256_packs_epi32 ( a , b ) , ( 0 < < 0 ) + ( 2 < < 2 ) + ( 1 < < 4 ) + ( 3 < < 6 ) ) ; \
out = _mm256_castsi256_si128 ( _mm256_permute4x64_epi64 ( _mm256_packus_epi16 ( t , t ) , ( 0 < < 0 ) + ( 2 < < 2 ) + ( 1 < < 4 ) + ( 3 < < 6 ) ) ) ; \
}
# define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() );
# define stbir__simdf8_pack_to_16words(out,aa,bb) \
{ \
stbir__simdf8 af , bf ; \
stbir__simdi8 a , b ; \
af = _mm256_min_ps ( aa , STBIR_max_uint16_as_floatX ) ; \
bf = _mm256_min_ps ( bb , STBIR_max_uint16_as_floatX ) ; \
af = _mm256_max_ps ( af , _mm256_setzero_ps ( ) ) ; \
bf = _mm256_max_ps ( bf , _mm256_setzero_ps ( ) ) ; \
a = _mm256_cvttps_epi32 ( af ) ; \
b = _mm256_cvttps_epi32 ( bf ) ; \
( out ) = _mm256_permute4x64_epi64 ( _mm256_packus_epi32 ( a , b ) , ( 0 < < 0 ) + ( 2 < < 2 ) + ( 1 < < 4 ) + ( 3 < < 6 ) ) ; \
}
# else
# define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \
{ \
stbir__simdi a , zero = _mm_setzero_si128 ( ) ; \
a = _mm_unpacklo_epi8 ( ireg , zero ) ; \
out0 = _mm256_setr_m128i ( _mm_unpacklo_epi16 ( a , zero ) , _mm_unpackhi_epi16 ( a , zero ) ) ; \
a = _mm_unpackhi_epi8 ( ireg , zero ) ; \
out1 = _mm256_setr_m128i ( _mm_unpacklo_epi16 ( a , zero ) , _mm_unpackhi_epi16 ( a , zero ) ) ; \
}
# define stbir__simdf8_pack_to_16bytes(out,aa,bb) \
{ \
stbir__simdi t ; \
stbir__simdf8 af , bf ; \
stbir__simdi8 a , b ; \
af = _mm256_min_ps ( aa , STBIR_max_uint8_as_floatX ) ; \
bf = _mm256_min_ps ( bb , STBIR_max_uint8_as_floatX ) ; \
af = _mm256_max_ps ( af , _mm256_setzero_ps ( ) ) ; \
bf = _mm256_max_ps ( bf , _mm256_setzero_ps ( ) ) ; \
a = _mm256_cvttps_epi32 ( af ) ; \
b = _mm256_cvttps_epi32 ( bf ) ; \
out = _mm_packs_epi32 ( _mm256_castsi256_si128 ( a ) , _mm256_extractf128_si256 ( a , 1 ) ) ; \
out = _mm_packus_epi16 ( out , out ) ; \
t = _mm_packs_epi32 ( _mm256_castsi256_si128 ( b ) , _mm256_extractf128_si256 ( b , 1 ) ) ; \
t = _mm_packus_epi16 ( t , t ) ; \
out = _mm_castps_si128 ( _mm_shuffle_ps ( _mm_castsi128_ps ( out ) , _mm_castsi128_ps ( t ) , ( 0 < < 0 ) + ( 1 < < 2 ) + ( 0 < < 4 ) + ( 1 < < 6 ) ) ) ; \
}
# define stbir__simdi8_expand_u16_to_u32(out,ireg) \
{ \
stbir__simdi a , b , zero = _mm_setzero_si128 ( ) ; \
a = _mm_unpacklo_epi16 ( ireg , zero ) ; \
b = _mm_unpackhi_epi16 ( ireg , zero ) ; \
out = _mm256_insertf128_si256 ( _mm256_castsi128_si256 ( a ) , b , 1 ) ; \
}
# define stbir__simdf8_pack_to_16words(out,aa,bb) \
{ \
stbir__simdi t0 , t1 ; \
stbir__simdf8 af , bf ; \
stbir__simdi8 a , b ; \
af = _mm256_min_ps ( aa , STBIR_max_uint16_as_floatX ) ; \
bf = _mm256_min_ps ( bb , STBIR_max_uint16_as_floatX ) ; \
af = _mm256_max_ps ( af , _mm256_setzero_ps ( ) ) ; \
bf = _mm256_max_ps ( bf , _mm256_setzero_ps ( ) ) ; \
a = _mm256_cvttps_epi32 ( af ) ; \
b = _mm256_cvttps_epi32 ( bf ) ; \
t0 = _mm_packus_epi32 ( _mm256_castsi256_si128 ( a ) , _mm256_extractf128_si256 ( a , 1 ) ) ; \
t1 = _mm_packus_epi32 ( _mm256_castsi256_si128 ( b ) , _mm256_extractf128_si256 ( b , 1 ) ) ; \
out = _mm256_setr_m128i ( t0 , t1 ) ; \
}
# endif
static __m256i stbir_00001111 = { STBIR__CONST_4d_32i ( 0 , 0 , 0 , 0 ) , STBIR__CONST_4d_32i ( 1 , 1 , 1 , 1 ) } ;
# define stbir__simdf8_0123to00001111( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00001111 )
static __m256i stbir_22223333 = { STBIR__CONST_4d_32i ( 2 , 2 , 2 , 2 ) , STBIR__CONST_4d_32i ( 3 , 3 , 3 , 3 ) } ;
# define stbir__simdf8_0123to22223333( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_22223333 )
# define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 )
# define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) )
static __m256i stbir_00112233 = { STBIR__CONST_4d_32i ( 0 , 0 , 1 , 1 ) , STBIR__CONST_4d_32i ( 2 , 2 , 3 , 3 ) } ;
# define stbir__simdf8_0123to00112233( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00112233 )
# define stbir__simdf8_add4( out, a8, b ) (out) = _mm256_add_ps( a8, _mm256_castps128_ps256( b ) )
static __m256i stbir_load6 = { STBIR__CONST_4_32i ( 0x80000000 ) , STBIR__CONST_4d_32i ( 0x80000000 , 0x80000000 , 0 , 0 ) } ;
# define stbir__simdf8_load6z( out, ptr ) (out) = _mm256_maskload_ps( ptr, stbir_load6 )
# define stbir__simdf8_0123to00000000( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(0<<4)+(0<<6) )
# define stbir__simdf8_0123to11111111( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(1<<4)+(1<<6) )
# define stbir__simdf8_0123to22222222( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(2<<2)+(2<<4)+(2<<6) )
# define stbir__simdf8_0123to33333333( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(3<<2)+(3<<4)+(3<<6) )
# define stbir__simdf8_0123to21032103( out, in ) (out) = _mm256_shuffle_ps ( in, in, (2<<0)+(1<<2)+(0<<4)+(3<<6) )
# define stbir__simdf8_0123to32103210( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(2<<2)+(1<<4)+(0<<6) )
# define stbir__simdf8_0123to12301230( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(2<<2)+(3<<4)+(0<<6) )
# define stbir__simdf8_0123to10321032( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(0<<2)+(3<<4)+(2<<6) )
# define stbir__simdf8_0123to30123012( out, in ) (out) = _mm256_shuffle_ps ( in, in, (3<<0)+(0<<2)+(1<<4)+(2<<6) )
# define stbir__simdf8_0123to11331133( out, in ) (out) = _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(3<<4)+(3<<6) )
# define stbir__simdf8_0123to00220022( out, in ) (out) = _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(2<<4)+(2<<6) )
# define stbir__simdf8_aaa1( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(1<<1)+(1<<2)+(0<<3)+(1<<4)+(1<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (3<<0) + (3<<2) + (3<<4) + (0<<6) )
# define stbir__simdf8_1aaa( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(1<<2)+(1<<3)+(0<<4)+(1<<5)+(1<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (0<<4) + (0<<6) )
# define stbir__simdf8_a1a1( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(0<<1)+(1<<2)+(0<<3)+(1<<4)+(0<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )
# define stbir__simdf8_1a1a( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(0<<2)+(1<<3)+(0<<4)+(1<<5)+(0<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )
# define stbir__simdf8_zero( reg ) (reg) = _mm256_setzero_ps()
# ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd
# define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add )
# define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add )
# define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add )
# else
# define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) )
# define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) )
# define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) )
# endif
# define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val )
# endif
# ifdef STBIR_FLOORF
# undef STBIR_FLOORF
# endif
# define STBIR_FLOORF stbir_simd_floorf
static stbir__inline float stbir_simd_floorf ( float x ) // martins floorf
{
# if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)
__m128 t = _mm_set_ss ( x ) ;
return _mm_cvtss_f32 ( _mm_floor_ss ( t , t ) ) ;
# else
__m128 f = _mm_set_ss ( x ) ;
__m128 t = _mm_cvtepi32_ps ( _mm_cvttps_epi32 ( f ) ) ;
__m128 r = _mm_add_ss ( t , _mm_and_ps ( _mm_cmplt_ss ( f , t ) , _mm_set_ss ( - 1.0f ) ) ) ;
return _mm_cvtss_f32 ( r ) ;
# endif
}
# ifdef STBIR_CEILF
# undef STBIR_CEILF
# endif
# define STBIR_CEILF stbir_simd_ceilf
static stbir__inline float stbir_simd_ceilf ( float x ) // martins ceilf
{
# if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)
__m128 t = _mm_set_ss ( x ) ;
return _mm_cvtss_f32 ( _mm_ceil_ss ( t , t ) ) ;
# else
__m128 f = _mm_set_ss ( x ) ;
__m128 t = _mm_cvtepi32_ps ( _mm_cvttps_epi32 ( f ) ) ;
__m128 r = _mm_add_ss ( t , _mm_and_ps ( _mm_cmplt_ss ( t , f ) , _mm_set_ss ( 1.0f ) ) ) ;
return _mm_cvtss_f32 ( r ) ;
# endif
}
# elif defined(STBIR_NEON)
# include <arm_neon.h>
# define stbir__simdf float32x4_t
# define stbir__simdi uint32x4_t
# define stbir_simdi_castf( reg ) vreinterpretq_u32_f32(reg)
# define stbir_simdf_casti( reg ) vreinterpretq_f32_u32(reg)
# define stbir__simdf_load( reg, ptr ) (reg) = vld1q_f32( (float const*)(ptr) )
# define stbir__simdi_load( reg, ptr ) (reg) = vld1q_u32( (uint32_t const*)(ptr) )
# define stbir__simdf_load1( out, ptr ) (out) = vld1q_dup_f32( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdi_load1( out, ptr ) (out) = vld1q_dup_u32( (uint32_t const*)(ptr) )
# define stbir__simdf_load1z( out, ptr ) (out) = vld1q_lane_f32( (float const*)(ptr), vdupq_n_f32(0), 0 ) // top values must be zero
# define stbir__simdf_frep4( fvar ) vdupq_n_f32( fvar )
# define stbir__simdf_load1frep4( out, fvar ) (out) = vdupq_n_f32( fvar )
# define stbir__simdf_load2( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdf_load2z( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values must be zero
# define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = vcombine_f32( vget_low_f32(reg), vld1_f32( (float const*)(ptr) ) )
# define stbir__simdf_zeroP() vdupq_n_f32(0)
# define stbir__simdf_zero( reg ) (reg) = vdupq_n_f32(0)
# define stbir__simdf_store( ptr, reg ) vst1q_f32( (float*)(ptr), reg )
# define stbir__simdf_store1( ptr, reg ) vst1q_lane_f32( (float*)(ptr), reg, 0)
# define stbir__simdf_store2( ptr, reg ) vst1_f32( (float*)(ptr), vget_low_f32(reg) )
# define stbir__simdf_store2h( ptr, reg ) vst1_f32( (float*)(ptr), vget_high_f32(reg) )
# define stbir__simdi_store( ptr, reg ) vst1q_u32( (uint32_t*)(ptr), reg )
# define stbir__simdi_store1( ptr, reg ) vst1q_lane_u32( (uint32_t*)(ptr), reg, 0 )
# define stbir__simdi_store2( ptr, reg ) vst1_u32( (uint32_t*)(ptr), vget_low_u32(reg) )
# define stbir__prefetch( ptr )
# define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
{ \
uint16x8_t l = vmovl_u8 ( vget_low_u8 ( vreinterpretq_u8_u32 ( ireg ) ) ) ; \
uint16x8_t h = vmovl_u8 ( vget_high_u8 ( vreinterpretq_u8_u32 ( ireg ) ) ) ; \
out0 = vmovl_u16 ( vget_low_u16 ( l ) ) ; \
out1 = vmovl_u16 ( vget_high_u16 ( l ) ) ; \
out2 = vmovl_u16 ( vget_low_u16 ( h ) ) ; \
out3 = vmovl_u16 ( vget_high_u16 ( h ) ) ; \
}
# define stbir__simdi_expand_u8_to_1u32(out,ireg) \
{ \
uint16x8_t tmp = vmovl_u8 ( vget_low_u8 ( vreinterpretq_u8_u32 ( ireg ) ) ) ; \
out = vmovl_u16 ( vget_low_u16 ( tmp ) ) ; \
}
# define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
{ \
uint16x8_t tmp = vreinterpretq_u16_u32 ( ireg ) ; \
out0 = vmovl_u16 ( vget_low_u16 ( tmp ) ) ; \
out1 = vmovl_u16 ( vget_high_u16 ( tmp ) ) ; \
}
# define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) )
# define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0)
# define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0)
# define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0))
# define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0))
# define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) )
# define stbir__simdf_add( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )
# define stbir__simdf_mult( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )
# define stbir__simdf_mult_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_f32( (float const*)(ptr) ) )
# define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )
# define stbir__simdf_add_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_f32( (float const*)(ptr) ) )
# define stbir__simdf_add1_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )
# ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd (and also x64 no madd to arm madd)
# define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )
# define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )
# define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_f32( (float const*)(ptr) ) )
# define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_dup_f32( (float const*)(ptr) ) )
# else
# define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )
# define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )
# define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_f32( (float const*)(ptr) ) ) )
# define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_dup_f32( (float const*)(ptr) ) ) )
# endif
# define stbir__simdf_add1( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )
# define stbir__simdf_mult1( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )
# define stbir__simdf_and( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vandq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )
# define stbir__simdf_or( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )
# define stbir__simdf_min( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )
# define stbir__simdf_max( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )
# define stbir__simdf_min1( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )
# define stbir__simdf_max1( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )
# define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 3 )
# define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 2 )
# define stbir__simdf_a1a1( out, alp, ones ) (out) = vzipq_f32(vuzpq_f32(alp, alp).val[1], ones).val[0]
# define stbir__simdf_1a1a( out, alp, ones ) (out) = vzipq_f32(ones, vuzpq_f32(alp, alp).val[0]).val[0]
# if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
# define stbir__simdf_aaa1( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3, ones, 3)
# define stbir__simdf_1aaa( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0, ones, 0)
# if defined( _MSC_VER ) && !defined(__clang__)
# define stbir_make16(a,b,c,d) vcombine_u8( \
vcreate_u8 ( ( 4 * a + 0 ) | ( ( 4 * a + 1 ) < < 8 ) | ( ( 4 * a + 2 ) < < 16 ) | ( ( 4 * a + 3 ) < < 24 ) | \
( ( stbir_uint64 ) ( 4 * b + 0 ) < < 32 ) | ( ( stbir_uint64 ) ( 4 * b + 1 ) < < 40 ) | ( ( stbir_uint64 ) ( 4 * b + 2 ) < < 48 ) | ( ( stbir_uint64 ) ( 4 * b + 3 ) < < 56 ) ) , \
vcreate_u8 ( ( 4 * c + 0 ) | ( ( 4 * c + 1 ) < < 8 ) | ( ( 4 * c + 2 ) < < 16 ) | ( ( 4 * c + 3 ) < < 24 ) | \
( ( stbir_uint64 ) ( 4 * d + 0 ) < < 32 ) | ( ( stbir_uint64 ) ( 4 * d + 1 ) < < 40 ) | ( ( stbir_uint64 ) ( 4 * d + 2 ) < < 48 ) | ( ( stbir_uint64 ) ( 4 * d + 3 ) < < 56 ) ) )
# else
# define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3}
# endif
# define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) )
# define stbir__simdi_16madd( out, reg0, reg1 ) \
{ \
int16x8_t r0 = vreinterpretq_s16_u32 ( reg0 ) ; \
int16x8_t r1 = vreinterpretq_s16_u32 ( reg1 ) ; \
int32x4_t tmp0 = vmull_s16 ( vget_low_s16 ( r0 ) , vget_low_s16 ( r1 ) ) ; \
int32x4_t tmp1 = vmull_s16 ( vget_high_s16 ( r0 ) , vget_high_s16 ( r1 ) ) ; \
( out ) = vreinterpretq_u32_s32 ( vpaddq_s32 ( tmp0 , tmp1 ) ) ; \
}
# else
# define stbir__simdf_aaa1( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3)
# define stbir__simdf_1aaa( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0)
# if defined( _MSC_VER ) && !defined(__clang__)
static stbir__inline uint8x8x2_t stbir_make8x2 ( float32x4_t reg )
{
uint8x8x2_t r = { { vget_low_u8 ( vreinterpretq_u8_f32 ( reg ) ) , vget_high_u8 ( vreinterpretq_u8_f32 ( reg ) ) } } ;
return r ;
}
# define stbir_make8(a,b) vcreate_u8( \
( 4 * a + 0 ) | ( ( 4 * a + 1 ) < < 8 ) | ( ( 4 * a + 2 ) < < 16 ) | ( ( 4 * a + 3 ) < < 24 ) | \
( ( stbir_uint64 ) ( 4 * b + 0 ) < < 32 ) | ( ( stbir_uint64 ) ( 4 * b + 1 ) < < 40 ) | ( ( stbir_uint64 ) ( 4 * b + 2 ) < < 48 ) | ( ( stbir_uint64 ) ( 4 * b + 3 ) < < 56 ) )
# else
# define stbir_make8x2(reg) (uint8x8x2_t){ { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } }
# define stbir_make8(a,b) (uint8x8_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3}
# endif
# define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vcombine_u8( \
vtbl2_u8 ( stbir_make8x2 ( reg ) , stbir_make8 ( one , two ) ) , \
vtbl2_u8 ( stbir_make8x2 ( reg ) , stbir_make8 ( three , four ) ) ) )
# define stbir__simdi_16madd( out, reg0, reg1 ) \
{ \
int16x8_t r0 = vreinterpretq_s16_u32 ( reg0 ) ; \
int16x8_t r1 = vreinterpretq_s16_u32 ( reg1 ) ; \
int32x4_t tmp0 = vmull_s16 ( vget_low_s16 ( r0 ) , vget_low_s16 ( r1 ) ) ; \
int32x4_t tmp1 = vmull_s16 ( vget_high_s16 ( r0 ) , vget_high_s16 ( r1 ) ) ; \
int32x2_t out0 = vpadd_s32 ( vget_low_s32 ( tmp0 ) , vget_high_s32 ( tmp0 ) ) ; \
int32x2_t out1 = vpadd_s32 ( vget_low_s32 ( tmp1 ) , vget_high_s32 ( tmp1 ) ) ; \
( out ) = vreinterpretq_u32_s32 ( vcombine_s32 ( out0 , out1 ) ) ; \
}
# endif
# define stbir__simdi_and( out, reg0, reg1 ) (out) = vandq_u32( reg0, reg1 )
# define stbir__simdi_or( out, reg0, reg1 ) (out) = vorrq_u32( reg0, reg1 )
# define stbir__simdf_pack_to_8bytes(out,aa,bb) \
{ \
float32x4_t af = vmaxq_f32 ( vminq_f32 ( aa , STBIR__CONSTF ( STBIR_max_uint8_as_float ) ) , vdupq_n_f32 ( 0 ) ) ; \
float32x4_t bf = vmaxq_f32 ( vminq_f32 ( bb , STBIR__CONSTF ( STBIR_max_uint8_as_float ) ) , vdupq_n_f32 ( 0 ) ) ; \
int16x4_t ai = vqmovn_s32 ( vcvtq_s32_f32 ( af ) ) ; \
int16x4_t bi = vqmovn_s32 ( vcvtq_s32_f32 ( bf ) ) ; \
uint8x8_t out8 = vqmovun_s16 ( vcombine_s16 ( ai , bi ) ) ; \
out = vreinterpretq_u32_u8 ( vcombine_u8 ( out8 , out8 ) ) ; \
}
# define stbir__simdf_pack_to_8words(out,aa,bb) \
{ \
float32x4_t af = vmaxq_f32 ( vminq_f32 ( aa , STBIR__CONSTF ( STBIR_max_uint16_as_float ) ) , vdupq_n_f32 ( 0 ) ) ; \
float32x4_t bf = vmaxq_f32 ( vminq_f32 ( bb , STBIR__CONSTF ( STBIR_max_uint16_as_float ) ) , vdupq_n_f32 ( 0 ) ) ; \
int32x4_t ai = vcvtq_s32_f32 ( af ) ; \
int32x4_t bi = vcvtq_s32_f32 ( bf ) ; \
out = vreinterpretq_u32_u16 ( vcombine_u16 ( vqmovun_s32 ( ai ) , vqmovun_s32 ( bi ) ) ) ; \
}
# define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
{ \
int16x4x2_t tmp0 = vzip_s16 ( vqmovn_s32 ( vreinterpretq_s32_u32 ( r0 ) ) , vqmovn_s32 ( vreinterpretq_s32_u32 ( r2 ) ) ) ; \
int16x4x2_t tmp1 = vzip_s16 ( vqmovn_s32 ( vreinterpretq_s32_u32 ( r1 ) ) , vqmovn_s32 ( vreinterpretq_s32_u32 ( r3 ) ) ) ; \
uint8x8x2_t out = \
{ { \
vqmovun_s16 ( vcombine_s16 ( tmp0 . val [ 0 ] , tmp0 . val [ 1 ] ) ) , \
vqmovun_s16 ( vcombine_s16 ( tmp1 . val [ 0 ] , tmp1 . val [ 1 ] ) ) , \
} } ; \
vst2_u8 ( ptr , out ) ; \
}
# define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
{ \
float32x4x4_t tmp = vld4q_f32 ( ptr ) ; \
o0 = tmp . val [ 0 ] ; \
o1 = tmp . val [ 1 ] ; \
o2 = tmp . val [ 2 ] ; \
o3 = tmp . val [ 3 ] ; \
}
# define stbir__simdi_32shr( out, reg, imm ) out = vshrq_n_u32( reg, imm )
# if defined( _MSC_VER ) && !defined(__clang__)
# define STBIR__SIMDF_CONST(var, x) __declspec(align(8)) float var[] = { x, x, x, x }
# define STBIR__SIMDI_CONST(var, x) __declspec(align(8)) uint32_t var[] = { x, x, x, x }
# define STBIR__CONSTF(var) (*(const float32x4_t*)var)
# define STBIR__CONSTI(var) (*(const uint32x4_t*)var)
# else
# define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }
# define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }
# define STBIR__CONSTF(var) (var)
# define STBIR__CONSTI(var) (var)
# endif
# ifdef STBIR_FLOORF
# undef STBIR_FLOORF
# endif
# define STBIR_FLOORF stbir_simd_floorf
static stbir__inline float stbir_simd_floorf ( float x )
{
# if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
return vget_lane_f32 ( vrndm_f32 ( vdup_n_f32 ( x ) ) , 0 ) ;
# else
float32x2_t f = vdup_n_f32 ( x ) ;
float32x2_t t = vcvt_f32_s32 ( vcvt_s32_f32 ( f ) ) ;
uint32x2_t a = vclt_f32 ( f , t ) ;
uint32x2_t b = vreinterpret_u32_f32 ( vdup_n_f32 ( - 1.0f ) ) ;
float32x2_t r = vadd_f32 ( t , vreinterpret_f32_u32 ( vand_u32 ( a , b ) ) ) ;
return vget_lane_f32 ( r , 0 ) ;
# endif
}
# ifdef STBIR_CEILF
# undef STBIR_CEILF
# endif
# define STBIR_CEILF stbir_simd_ceilf
static stbir__inline float stbir_simd_ceilf ( float x )
{
# if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
return vget_lane_f32 ( vrndp_f32 ( vdup_n_f32 ( x ) ) , 0 ) ;
# else
float32x2_t f = vdup_n_f32 ( x ) ;
float32x2_t t = vcvt_f32_s32 ( vcvt_s32_f32 ( f ) ) ;
uint32x2_t a = vclt_f32 ( t , f ) ;
uint32x2_t b = vreinterpret_u32_f32 ( vdup_n_f32 ( 1.0f ) ) ;
float32x2_t r = vadd_f32 ( t , vreinterpret_f32_u32 ( vand_u32 ( a , b ) ) ) ;
return vget_lane_f32 ( r , 0 ) ;
# endif
}
# define STBIR_SIMD
# elif defined(STBIR_WASM)
# include <wasm_simd128.h>
# define stbir__simdf v128_t
# define stbir__simdi v128_t
# define stbir_simdi_castf( reg ) (reg)
# define stbir_simdf_casti( reg ) (reg)
# define stbir__simdf_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )
# define stbir__simdi_load( reg, ptr ) (reg) = wasm_v128_load( (void const*)(ptr) )
# define stbir__simdf_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdi_load1( out, ptr ) (out) = wasm_v128_load32_splat( (void const*)(ptr) )
# define stbir__simdf_load1z( out, ptr ) (out) = wasm_v128_load32_zero( (void const*)(ptr) ) // top values must be zero
# define stbir__simdf_frep4( fvar ) wasm_f32x4_splat( fvar )
# define stbir__simdf_load1frep4( out, fvar ) (out) = wasm_f32x4_splat( fvar )
# define stbir__simdf_load2( out, ptr ) (out) = wasm_v128_load64_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)
# define stbir__simdf_load2z( out, ptr ) (out) = wasm_v128_load64_zero( (void const*)(ptr) ) // top values must be zero
# define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = wasm_v128_load64_lane( (void const*)(ptr), reg, 1 )
# define stbir__simdf_zeroP() wasm_f32x4_const_splat(0)
# define stbir__simdf_zero( reg ) (reg) = wasm_f32x4_const_splat(0)
# define stbir__simdf_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )
# define stbir__simdf_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )
# define stbir__simdf_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )
# define stbir__simdf_store2h( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 1 )
# define stbir__simdi_store( ptr, reg ) wasm_v128_store( (void*)(ptr), reg )
# define stbir__simdi_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )
# define stbir__simdi_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )
# define stbir__prefetch( ptr )
# define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
{ \
v128_t l = wasm_u16x8_extend_low_u8x16 ( ireg ) ; \
v128_t h = wasm_u16x8_extend_high_u8x16 ( ireg ) ; \
out0 = wasm_u32x4_extend_low_u16x8 ( l ) ; \
out1 = wasm_u32x4_extend_high_u16x8 ( l ) ; \
out2 = wasm_u32x4_extend_low_u16x8 ( h ) ; \
out3 = wasm_u32x4_extend_high_u16x8 ( h ) ; \
}
# define stbir__simdi_expand_u8_to_1u32(out,ireg) \
{ \
v128_t tmp = wasm_u16x8_extend_low_u8x16 ( ireg ) ; \
out = wasm_u32x4_extend_low_u16x8 ( tmp ) ; \
}
# define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
{ \
out0 = wasm_u32x4_extend_low_u16x8 ( ireg ) ; \
out1 = wasm_u32x4_extend_high_u16x8 ( ireg ) ; \
}
# define stbir__simdf_convert_float_to_i32( i, f ) (i) = wasm_i32x4_trunc_sat_f32x4(f)
# define stbir__simdf_convert_float_to_int( f ) wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0)
# define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0)
# define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0))
# define stbir__simdf_convert_float_to_short( f ) ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0))
# define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg)
# define stbir__simdf_add( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )
# define stbir__simdf_mult( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )
# define stbir__simdf_mult_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load( (void const*)(ptr) ) )
# define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = wasm_f32x4_mul( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )
# define stbir__simdf_add_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load( (void const*)(ptr) ) )
# define stbir__simdf_add1_mem( out, reg, ptr ) (out) = wasm_f32x4_add( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )
# define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )
# define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )
# define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load( (void const*)(ptr) ) ) )
# define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load32_splat( (void const*)(ptr) ) ) )
# define stbir__simdf_add1( out, reg0, reg1 ) (out) = wasm_f32x4_add( reg0, reg1 )
# define stbir__simdf_mult1( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )
# define stbir__simdf_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )
# define stbir__simdf_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )
# define stbir__simdf_min( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )
# define stbir__simdf_max( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )
# define stbir__simdf_min1( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )
# define stbir__simdf_max1( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )
# define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 3, 4, 5, -1 )
# define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 2, 3, 4, -1 )
# define stbir__simdf_aaa1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 3, 3, 3, 4)
# define stbir__simdf_1aaa(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 0, 0)
# define stbir__simdf_a1a1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 1, 4, 3, 4)
# define stbir__simdf_1a1a(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 4, 2)
# define stbir__simdf_swiz( reg, one, two, three, four ) wasm_i32x4_shuffle(reg, reg, one, two, three, four)
# define stbir__simdi_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )
# define stbir__simdi_or( out, reg0, reg1 ) (out) = wasm_v128_or( reg0, reg1 )
# define stbir__simdi_16madd( out, reg0, reg1 ) (out) = wasm_i32x4_dot_i16x8( reg0, reg1 )
# define stbir__simdf_pack_to_8bytes(out,aa,bb) \
{ \
v128_t af = wasm_f32x4_max ( wasm_f32x4_min ( aa , STBIR_max_uint8_as_float ) , wasm_f32x4_const_splat ( 0 ) ) ; \
v128_t bf = wasm_f32x4_max ( wasm_f32x4_min ( bb , STBIR_max_uint8_as_float ) , wasm_f32x4_const_splat ( 0 ) ) ; \
v128_t ai = wasm_i32x4_trunc_sat_f32x4 ( af ) ; \
v128_t bi = wasm_i32x4_trunc_sat_f32x4 ( bf ) ; \
v128_t out16 = wasm_i16x8_narrow_i32x4 ( ai , bi ) ; \
out = wasm_u8x16_narrow_i16x8 ( out16 , out16 ) ; \
}
# define stbir__simdf_pack_to_8words(out,aa,bb) \
{ \
v128_t af = wasm_f32x4_max ( wasm_f32x4_min ( aa , STBIR_max_uint16_as_float ) , wasm_f32x4_const_splat ( 0 ) ) ; \
v128_t bf = wasm_f32x4_max ( wasm_f32x4_min ( bb , STBIR_max_uint16_as_float ) , wasm_f32x4_const_splat ( 0 ) ) ; \
v128_t ai = wasm_i32x4_trunc_sat_f32x4 ( af ) ; \
v128_t bi = wasm_i32x4_trunc_sat_f32x4 ( bf ) ; \
out = wasm_u16x8_narrow_i32x4 ( ai , bi ) ; \
}
# define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
{ \
v128_t tmp0 = wasm_i16x8_narrow_i32x4 ( r0 , r1 ) ; \
v128_t tmp1 = wasm_i16x8_narrow_i32x4 ( r2 , r3 ) ; \
v128_t tmp = wasm_u8x16_narrow_i16x8 ( tmp0 , tmp1 ) ; \
tmp = wasm_i8x16_shuffle ( tmp , tmp , 0 , 4 , 8 , 12 , 1 , 5 , 9 , 13 , 2 , 6 , 10 , 14 , 3 , 7 , 11 , 15 ) ; \
wasm_v128_store ( ( void * ) ( ptr ) , tmp ) ; \
}
# define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
{ \
v128_t t0 = wasm_v128_load ( ptr ) ; \
v128_t t1 = wasm_v128_load ( ptr + 4 ) ; \
v128_t t2 = wasm_v128_load ( ptr + 8 ) ; \
v128_t t3 = wasm_v128_load ( ptr + 12 ) ; \
v128_t s0 = wasm_i32x4_shuffle ( t0 , t1 , 0 , 4 , 2 , 6 ) ; \
v128_t s1 = wasm_i32x4_shuffle ( t0 , t1 , 1 , 5 , 3 , 7 ) ; \
v128_t s2 = wasm_i32x4_shuffle ( t2 , t3 , 0 , 4 , 2 , 6 ) ; \
v128_t s3 = wasm_i32x4_shuffle ( t2 , t3 , 1 , 5 , 3 , 7 ) ; \
o0 = wasm_i32x4_shuffle ( s0 , s2 , 0 , 1 , 4 , 5 ) ; \
o1 = wasm_i32x4_shuffle ( s1 , s3 , 0 , 1 , 4 , 5 ) ; \
o2 = wasm_i32x4_shuffle ( s0 , s2 , 2 , 3 , 6 , 7 ) ; \
o3 = wasm_i32x4_shuffle ( s1 , s3 , 2 , 3 , 6 , 7 ) ; \
}
# define stbir__simdi_32shr( out, reg, imm ) out = wasm_u32x4_shr( reg, imm )
typedef float stbir__f32x4 __attribute__ ( ( __vector_size__ ( 16 ) , __aligned__ ( 16 ) ) ) ;
# define STBIR__SIMDF_CONST(var, x) stbir__simdf var = (v128_t)(stbir__f32x4){ x, x, x, x }
# define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }
# define STBIR__CONSTF(var) (var)
# define STBIR__CONSTI(var) (var)
# ifdef STBIR_FLOORF
# undef STBIR_FLOORF
# endif
# define STBIR_FLOORF stbir_simd_floorf
static stbir__inline float stbir_simd_floorf ( float x )
{
return wasm_f32x4_extract_lane ( wasm_f32x4_floor ( wasm_f32x4_splat ( x ) ) , 0 ) ;
}
# ifdef STBIR_CEILF
# undef STBIR_CEILF
# endif
# define STBIR_CEILF stbir_simd_ceilf
static stbir__inline float stbir_simd_ceilf ( float x )
{
return wasm_f32x4_extract_lane ( wasm_f32x4_ceil ( wasm_f32x4_splat ( x ) ) , 0 ) ;
}
# define STBIR_SIMD
# endif // SSE2/NEON/WASM
# endif // NO SIMD
# ifdef STBIR_SIMD8
# define stbir__simdfX stbir__simdf8
# define stbir__simdiX stbir__simdi8
# define stbir__simdfX_load stbir__simdf8_load
# define stbir__simdiX_load stbir__simdi8_load
# define stbir__simdfX_mult stbir__simdf8_mult
# define stbir__simdfX_add_mem stbir__simdf8_add_mem
# define stbir__simdfX_madd_mem stbir__simdf8_madd_mem
# define stbir__simdfX_store stbir__simdf8_store
# define stbir__simdiX_store stbir__simdi8_store
# define stbir__simdf_frepX stbir__simdf8_frep8
# define stbir__simdfX_madd stbir__simdf8_madd
# define stbir__simdfX_min stbir__simdf8_min
# define stbir__simdfX_max stbir__simdf8_max
# define stbir__simdfX_aaa1 stbir__simdf8_aaa1
# define stbir__simdfX_1aaa stbir__simdf8_1aaa
# define stbir__simdfX_a1a1 stbir__simdf8_a1a1
# define stbir__simdfX_1a1a stbir__simdf8_1a1a
# define stbir__simdfX_convert_float_to_i32 stbir__simdf8_convert_float_to_i32
# define stbir__simdfX_pack_to_words stbir__simdf8_pack_to_16words
# define stbir__simdfX_zero stbir__simdf8_zero
# define STBIR_onesX STBIR_ones8
# define STBIR_max_uint8_as_floatX STBIR_max_uint8_as_float8
# define STBIR_max_uint16_as_floatX STBIR_max_uint16_as_float8
# define STBIR_simd_point5X STBIR_simd_point58
# define stbir__simdfX_float_count 8
# define stbir__simdfX_0123to1230 stbir__simdf8_0123to12301230
# define stbir__simdfX_0123to2103 stbir__simdf8_0123to21032103
static const stbir__simdf8 STBIR_max_uint16_as_float_inverted8 = { stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted } ;
static const stbir__simdf8 STBIR_max_uint8_as_float_inverted8 = { stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted } ;
static const stbir__simdf8 STBIR_ones8 = { 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 } ;
static const stbir__simdf8 STBIR_simd_point58 = { 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 } ;
static const stbir__simdf8 STBIR_max_uint8_as_float8 = { stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float , stbir__max_uint8_as_float } ;
static const stbir__simdf8 STBIR_max_uint16_as_float8 = { stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float , stbir__max_uint16_as_float } ;
# else
# define stbir__simdfX stbir__simdf
# define stbir__simdiX stbir__simdi
# define stbir__simdfX_load stbir__simdf_load
# define stbir__simdiX_load stbir__simdi_load
# define stbir__simdfX_mult stbir__simdf_mult
# define stbir__simdfX_add_mem stbir__simdf_add_mem
# define stbir__simdfX_madd_mem stbir__simdf_madd_mem
# define stbir__simdfX_store stbir__simdf_store
# define stbir__simdiX_store stbir__simdi_store
# define stbir__simdf_frepX stbir__simdf_frep4
# define stbir__simdfX_madd stbir__simdf_madd
# define stbir__simdfX_min stbir__simdf_min
# define stbir__simdfX_max stbir__simdf_max
# define stbir__simdfX_aaa1 stbir__simdf_aaa1
# define stbir__simdfX_1aaa stbir__simdf_1aaa
# define stbir__simdfX_a1a1 stbir__simdf_a1a1
# define stbir__simdfX_1a1a stbir__simdf_1a1a
# define stbir__simdfX_convert_float_to_i32 stbir__simdf_convert_float_to_i32
# define stbir__simdfX_pack_to_words stbir__simdf_pack_to_8words
# define stbir__simdfX_zero stbir__simdf_zero
# define STBIR_onesX STBIR__CONSTF(STBIR_ones)
# define STBIR_simd_point5X STBIR__CONSTF(STBIR_simd_point5)
# define STBIR_max_uint8_as_floatX STBIR__CONSTF(STBIR_max_uint8_as_float)
# define STBIR_max_uint16_as_floatX STBIR__CONSTF(STBIR_max_uint16_as_float)
# define stbir__simdfX_float_count 4
# define stbir__if_simdf8_cast_to_simdf4( val ) ( val )
# define stbir__simdfX_0123to1230 stbir__simdf_0123to1230
# define stbir__simdfX_0123to2103 stbir__simdf_0123to2103
# endif
# if defined(STBIR_NEON) && !defined(_M_ARM)
# if defined( _MSC_VER ) && !defined(__clang__)
typedef __int16 stbir__FP16 ;
# else
typedef float16_t stbir__FP16 ;
# endif
# else // no NEON, or 32-bit ARM for MSVC
typedef union stbir__FP16
{
unsigned short u ;
} stbir__FP16 ;
# endif
# if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM)
// Fabian's half float routines, see: https://gist.github.com/rygorous/2156668
static stbir__inline float stbir__half_to_float ( stbir__FP16 h )
{
static const stbir__FP32 magic = { ( 254 - 15 ) < < 23 } ;
static const stbir__FP32 was_infnan = { ( 127 + 16 ) < < 23 } ;
stbir__FP32 o ;
o . u = ( h . u & 0x7fff ) < < 13 ; // exponent/mantissa bits
o . f * = magic . f ; // exponent adjust
if ( o . f > = was_infnan . f ) // make sure Inf/NaN survive
o . u | = 255 < < 23 ;
o . u | = ( h . u & 0x8000 ) < < 16 ; // sign bit
return o . f ;
}
static stbir__inline stbir__FP16 stbir__float_to_half ( float val )
{
stbir__FP32 f32infty = { 255 < < 23 } ;
stbir__FP32 f16max = { ( 127 + 16 ) < < 23 } ;
stbir__FP32 denorm_magic = { ( ( 127 - 15 ) + ( 23 - 10 ) + 1 ) < < 23 } ;
unsigned int sign_mask = 0x80000000u ;
stbir__FP16 o = { 0 } ;
stbir__FP32 f ;
unsigned int sign ;
f . f = val ;
sign = f . u & sign_mask ;
f . u ^ = sign ;
if ( f . u > = f16max . u ) // result is Inf or NaN (all exponent bits set)
o . u = ( f . u > f32infty . u ) ? 0x7e00 : 0x7c00 ; // NaN->qNaN and Inf->Inf
else // (De)normalized number or zero
{
if ( f . u < ( 113 < < 23 ) ) // resulting FP16 is subnormal or zero
{
// use a magic value to align our 10 mantissa bits at the bottom of
// the float. as long as FP addition is round-to-nearest-even this
// just works.
f . f + = denorm_magic . f ;
// and one integer subtract of the bias later, we have our final float!
o . u = ( unsigned short ) ( f . u - denorm_magic . u ) ;
}
else
{
unsigned int mant_odd = ( f . u > > 13 ) & 1 ; // resulting mantissa is odd
// update exponent, rounding bias part 1
f . u = f . u + ( ( 15u - 127 ) < < 23 ) + 0xfff ;
// rounding bias part 2
f . u + = mant_odd ;
// take the bits!
o . u = ( unsigned short ) ( f . u > > 13 ) ;
}
}
o . u | = sign > > 16 ;
return o ;
}
# endif
# if defined(STBIR_FP16C)
# include <immintrin.h>
static stbir__inline void stbir__half_to_float_SIMD ( float * output , stbir__FP16 const * input )
{
_mm256_storeu_ps ( ( float * ) output , _mm256_cvtph_ps ( _mm_loadu_si128 ( ( __m128i const * ) input ) ) ) ;
}
static stbir__inline void stbir__float_to_half_SIMD ( stbir__FP16 * output , float const * input )
{
_mm_storeu_si128 ( ( __m128i * ) output , _mm256_cvtps_ph ( _mm256_loadu_ps ( input ) , 0 ) ) ;
}
static stbir__inline float stbir__half_to_float ( stbir__FP16 h )
{
return _mm_cvtss_f32 ( _mm_cvtph_ps ( _mm_cvtsi32_si128 ( ( int ) h . u ) ) ) ;
}
static stbir__inline stbir__FP16 stbir__float_to_half ( float f )
{
stbir__FP16 h ;
h . u = ( unsigned short ) _mm_cvtsi128_si32 ( _mm_cvtps_ph ( _mm_set_ss ( f ) , 0 ) ) ;
return h ;
}
# elif defined(STBIR_SSE2)
// Fabian's half float routines, see: https://gist.github.com/rygorous/2156668
stbir__inline static void stbir__half_to_float_SIMD ( float * output , void const * input )
{
static const STBIR__SIMDI_CONST ( mask_nosign , 0x7fff ) ;
static const STBIR__SIMDI_CONST ( smallest_normal , 0x0400 ) ;
static const STBIR__SIMDI_CONST ( infinity , 0x7c00 ) ;
static const STBIR__SIMDI_CONST ( expadjust_normal , ( 127 - 15 ) < < 23 ) ;
static const STBIR__SIMDI_CONST ( magic_denorm , 113 < < 23 ) ;
__m128i i = _mm_loadu_si128 ( ( __m128i const * ) ( input ) ) ;
__m128i h = _mm_unpacklo_epi16 ( i , _mm_setzero_si128 ( ) ) ;
__m128i mnosign = STBIR__CONSTI ( mask_nosign ) ;
__m128i eadjust = STBIR__CONSTI ( expadjust_normal ) ;
__m128i smallest = STBIR__CONSTI ( smallest_normal ) ;
__m128i infty = STBIR__CONSTI ( infinity ) ;
__m128i expmant = _mm_and_si128 ( mnosign , h ) ;
__m128i justsign = _mm_xor_si128 ( h , expmant ) ;
__m128i b_notinfnan = _mm_cmpgt_epi32 ( infty , expmant ) ;
__m128i b_isdenorm = _mm_cmpgt_epi32 ( smallest , expmant ) ;
__m128i shifted = _mm_slli_epi32 ( expmant , 13 ) ;
__m128i adj_infnan = _mm_andnot_si128 ( b_notinfnan , eadjust ) ;
__m128i adjusted = _mm_add_epi32 ( eadjust , shifted ) ;
__m128i den1 = _mm_add_epi32 ( shifted , STBIR__CONSTI ( magic_denorm ) ) ;
__m128i adjusted2 = _mm_add_epi32 ( adjusted , adj_infnan ) ;
__m128 den2 = _mm_sub_ps ( _mm_castsi128_ps ( den1 ) , * ( const __m128 * ) & magic_denorm ) ;
__m128 adjusted3 = _mm_and_ps ( den2 , _mm_castsi128_ps ( b_isdenorm ) ) ;
__m128 adjusted4 = _mm_andnot_ps ( _mm_castsi128_ps ( b_isdenorm ) , _mm_castsi128_ps ( adjusted2 ) ) ;
__m128 adjusted5 = _mm_or_ps ( adjusted3 , adjusted4 ) ;
__m128i sign = _mm_slli_epi32 ( justsign , 16 ) ;
__m128 final = _mm_or_ps ( adjusted5 , _mm_castsi128_ps ( sign ) ) ;
stbir__simdf_store ( output + 0 , final ) ;
h = _mm_unpackhi_epi16 ( i , _mm_setzero_si128 ( ) ) ;
expmant = _mm_and_si128 ( mnosign , h ) ;
justsign = _mm_xor_si128 ( h , expmant ) ;
b_notinfnan = _mm_cmpgt_epi32 ( infty , expmant ) ;
b_isdenorm = _mm_cmpgt_epi32 ( smallest , expmant ) ;
shifted = _mm_slli_epi32 ( expmant , 13 ) ;
adj_infnan = _mm_andnot_si128 ( b_notinfnan , eadjust ) ;
adjusted = _mm_add_epi32 ( eadjust , shifted ) ;
den1 = _mm_add_epi32 ( shifted , STBIR__CONSTI ( magic_denorm ) ) ;
adjusted2 = _mm_add_epi32 ( adjusted , adj_infnan ) ;
den2 = _mm_sub_ps ( _mm_castsi128_ps ( den1 ) , * ( const __m128 * ) & magic_denorm ) ;
adjusted3 = _mm_and_ps ( den2 , _mm_castsi128_ps ( b_isdenorm ) ) ;
adjusted4 = _mm_andnot_ps ( _mm_castsi128_ps ( b_isdenorm ) , _mm_castsi128_ps ( adjusted2 ) ) ;
adjusted5 = _mm_or_ps ( adjusted3 , adjusted4 ) ;
sign = _mm_slli_epi32 ( justsign , 16 ) ;
final = _mm_or_ps ( adjusted5 , _mm_castsi128_ps ( sign ) ) ;
stbir__simdf_store ( output + 4 , final ) ;
// ~38 SSE2 ops for 8 values
}
// Fabian's round-to-nearest-even float to half
// ~48 SSE2 ops for 8 output
stbir__inline static void stbir__float_to_half_SIMD ( void * output , float const * input )
{
static const STBIR__SIMDI_CONST ( mask_sign , 0x80000000u ) ;
static const STBIR__SIMDI_CONST ( c_f16max , ( 127 + 16 ) < < 23 ) ; // all FP32 values >=this round to +inf
static const STBIR__SIMDI_CONST ( c_nanbit , 0x200 ) ;
static const STBIR__SIMDI_CONST ( c_infty_as_fp16 , 0x7c00 ) ;
static const STBIR__SIMDI_CONST ( c_min_normal , ( 127 - 14 ) < < 23 ) ; // smallest FP32 that yields a normalized FP16
static const STBIR__SIMDI_CONST ( c_subnorm_magic , ( ( 127 - 15 ) + ( 23 - 10 ) + 1 ) < < 23 ) ;
static const STBIR__SIMDI_CONST ( c_normal_bias , 0xfff - ( ( 127 - 15 ) < < 23 ) ) ; // adjust exponent and add mantissa rounding
__m128 f = _mm_loadu_ps ( input ) ;
__m128 msign = _mm_castsi128_ps ( STBIR__CONSTI ( mask_sign ) ) ;
__m128 justsign = _mm_and_ps ( msign , f ) ;
__m128 absf = _mm_xor_ps ( f , justsign ) ;
__m128i absf_int = _mm_castps_si128 ( absf ) ; // the cast is "free" (extra bypass latency, but no thruput hit)
__m128i f16max = STBIR__CONSTI ( c_f16max ) ;
__m128 b_isnan = _mm_cmpunord_ps ( absf , absf ) ; // is this a NaN?
__m128i b_isregular = _mm_cmpgt_epi32 ( f16max , absf_int ) ; // (sub)normalized or special?
__m128i nanbit = _mm_and_si128 ( _mm_castps_si128 ( b_isnan ) , STBIR__CONSTI ( c_nanbit ) ) ;
__m128i inf_or_nan = _mm_or_si128 ( nanbit , STBIR__CONSTI ( c_infty_as_fp16 ) ) ; // output for specials
__m128i min_normal = STBIR__CONSTI ( c_min_normal ) ;
__m128i b_issub = _mm_cmpgt_epi32 ( min_normal , absf_int ) ;
// "result is subnormal" path
__m128 subnorm1 = _mm_add_ps ( absf , _mm_castsi128_ps ( STBIR__CONSTI ( c_subnorm_magic ) ) ) ; // magic value to round output mantissa
__m128i subnorm2 = _mm_sub_epi32 ( _mm_castps_si128 ( subnorm1 ) , STBIR__CONSTI ( c_subnorm_magic ) ) ; // subtract out bias
// "result is normal" path
__m128i mantoddbit = _mm_slli_epi32 ( absf_int , 31 - 13 ) ; // shift bit 13 (mantissa LSB) to sign
__m128i mantodd = _mm_srai_epi32 ( mantoddbit , 31 ) ; // -1 if FP16 mantissa odd, else 0
__m128i round1 = _mm_add_epi32 ( absf_int , STBIR__CONSTI ( c_normal_bias ) ) ;
__m128i round2 = _mm_sub_epi32 ( round1 , mantodd ) ; // if mantissa LSB odd, bias towards rounding up (RTNE)
__m128i normal = _mm_srli_epi32 ( round2 , 13 ) ; // rounded result
// combine the two non-specials
__m128i nonspecial = _mm_or_si128 ( _mm_and_si128 ( subnorm2 , b_issub ) , _mm_andnot_si128 ( b_issub , normal ) ) ;
// merge in specials as well
__m128i joined = _mm_or_si128 ( _mm_and_si128 ( nonspecial , b_isregular ) , _mm_andnot_si128 ( b_isregular , inf_or_nan ) ) ;
__m128i sign_shift = _mm_srai_epi32 ( _mm_castps_si128 ( justsign ) , 16 ) ;
__m128i final2 , final = _mm_or_si128 ( joined , sign_shift ) ;
f = _mm_loadu_ps ( input + 4 ) ;
justsign = _mm_and_ps ( msign , f ) ;
absf = _mm_xor_ps ( f , justsign ) ;
absf_int = _mm_castps_si128 ( absf ) ; // the cast is "free" (extra bypass latency, but no thruput hit)
b_isnan = _mm_cmpunord_ps ( absf , absf ) ; // is this a NaN?
b_isregular = _mm_cmpgt_epi32 ( f16max , absf_int ) ; // (sub)normalized or special?
nanbit = _mm_and_si128 ( _mm_castps_si128 ( b_isnan ) , c_nanbit ) ;
inf_or_nan = _mm_or_si128 ( nanbit , STBIR__CONSTI ( c_infty_as_fp16 ) ) ; // output for specials
b_issub = _mm_cmpgt_epi32 ( min_normal , absf_int ) ;
// "result is subnormal" path
subnorm1 = _mm_add_ps ( absf , _mm_castsi128_ps ( STBIR__CONSTI ( c_subnorm_magic ) ) ) ; // magic value to round output mantissa
subnorm2 = _mm_sub_epi32 ( _mm_castps_si128 ( subnorm1 ) , STBIR__CONSTI ( c_subnorm_magic ) ) ; // subtract out bias
// "result is normal" path
mantoddbit = _mm_slli_epi32 ( absf_int , 31 - 13 ) ; // shift bit 13 (mantissa LSB) to sign
mantodd = _mm_srai_epi32 ( mantoddbit , 31 ) ; // -1 if FP16 mantissa odd, else 0
round1 = _mm_add_epi32 ( absf_int , STBIR__CONSTI ( c_normal_bias ) ) ;
round2 = _mm_sub_epi32 ( round1 , mantodd ) ; // if mantissa LSB odd, bias towards rounding up (RTNE)
normal = _mm_srli_epi32 ( round2 , 13 ) ; // rounded result
// combine the two non-specials
nonspecial = _mm_or_si128 ( _mm_and_si128 ( subnorm2 , b_issub ) , _mm_andnot_si128 ( b_issub , normal ) ) ;
// merge in specials as well
joined = _mm_or_si128 ( _mm_and_si128 ( nonspecial , b_isregular ) , _mm_andnot_si128 ( b_isregular , inf_or_nan ) ) ;
sign_shift = _mm_srai_epi32 ( _mm_castps_si128 ( justsign ) , 16 ) ;
final2 = _mm_or_si128 ( joined , sign_shift ) ;
final = _mm_packs_epi32 ( final , final2 ) ;
stbir__simdi_store ( output , final ) ;
}
# elif defined(STBIR_WASM) || (defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM)) // WASM or 32-bit ARM on MSVC/clang
static stbir__inline void stbir__half_to_float_SIMD ( float * output , stbir__FP16 const * input )
{
for ( int i = 0 ; i < 8 ; i + + )
{
output [ i ] = stbir__half_to_float ( input [ i ] ) ;
}
}
static stbir__inline void stbir__float_to_half_SIMD ( stbir__FP16 * output , float const * input )
{
for ( int i = 0 ; i < 8 ; i + + )
{
output [ i ] = stbir__float_to_half ( input [ i ] ) ;
}
}
# elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang)
static stbir__inline void stbir__half_to_float_SIMD ( float * output , stbir__FP16 const * input )
{
float16x4_t in0 = vld1_f16 ( input + 0 ) ;
float16x4_t in1 = vld1_f16 ( input + 4 ) ;
vst1q_f32 ( output + 0 , vcvt_f32_f16 ( in0 ) ) ;
vst1q_f32 ( output + 4 , vcvt_f32_f16 ( in1 ) ) ;
}
static stbir__inline void stbir__float_to_half_SIMD ( stbir__FP16 * output , float const * input )
{
float16x4_t out0 = vcvt_f16_f32 ( vld1q_f32 ( input + 0 ) ) ;
float16x4_t out1 = vcvt_f16_f32 ( vld1q_f32 ( input + 4 ) ) ;
vst1_f16 ( output + 0 , out0 ) ;
vst1_f16 ( output + 4 , out1 ) ;
}
static stbir__inline float stbir__half_to_float ( stbir__FP16 h )
{
return vgetq_lane_f32 ( vcvt_f32_f16 ( vld1_dup_f16 ( & h ) ) , 0 ) ;
}
static stbir__inline stbir__FP16 stbir__float_to_half ( float f )
{
return vget_lane_f16 ( vcvt_f16_f32 ( vdupq_n_f32 ( f ) ) , 0 ) . n16_u16 [ 0 ] ;
}
# elif defined(STBIR_NEON) // 64-bit ARM
static stbir__inline void stbir__half_to_float_SIMD ( float * output , stbir__FP16 const * input )
{
float16x8_t in = vld1q_f16 ( input ) ;
vst1q_f32 ( output + 0 , vcvt_f32_f16 ( vget_low_f16 ( in ) ) ) ;
vst1q_f32 ( output + 4 , vcvt_f32_f16 ( vget_high_f16 ( in ) ) ) ;
}
static stbir__inline void stbir__float_to_half_SIMD ( stbir__FP16 * output , float const * input )
{
float16x4_t out0 = vcvt_f16_f32 ( vld1q_f32 ( input + 0 ) ) ;
float16x4_t out1 = vcvt_f16_f32 ( vld1q_f32 ( input + 4 ) ) ;
vst1q_f16 ( output , vcombine_f16 ( out0 , out1 ) ) ;
}
static stbir__inline float stbir__half_to_float ( stbir__FP16 h )
{
return vgetq_lane_f32 ( vcvt_f32_f16 ( vdup_n_f16 ( h ) ) , 0 ) ;
}
static stbir__inline stbir__FP16 stbir__float_to_half ( float f )
{
return vget_lane_f16 ( vcvt_f16_f32 ( vdupq_n_f32 ( f ) ) , 0 ) ;
}
# endif
# ifdef STBIR_SIMD
# define stbir__simdf_0123to3333( out, reg ) (out) = stbir__simdf_swiz( reg, 3,3,3,3 )
# define stbir__simdf_0123to2222( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,2,2 )
# define stbir__simdf_0123to1111( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,1,1 )
# define stbir__simdf_0123to0000( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,0 )
# define stbir__simdf_0123to0003( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,3 )
# define stbir__simdf_0123to0001( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,1 )
# define stbir__simdf_0123to1122( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,2,2 )
# define stbir__simdf_0123to2333( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,3,3 )
# define stbir__simdf_0123to0023( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,3 )
# define stbir__simdf_0123to1230( out, reg ) (out) = stbir__simdf_swiz( reg, 1,2,3,0 )
# define stbir__simdf_0123to2103( out, reg ) (out) = stbir__simdf_swiz( reg, 2,1,0,3 )
# define stbir__simdf_0123to3210( out, reg ) (out) = stbir__simdf_swiz( reg, 3,2,1,0 )
# define stbir__simdf_0123to2301( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,0,1 )
# define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 )
# define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 )
# define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 )
# define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 )
# define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 )
# define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 )
# define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 )
typedef union stbir__simdi_u32
{
stbir_uint32 m128i_u32 [ 4 ] ;
int m128i_i32 [ 4 ] ;
stbir__simdi m128i_i128 ;
} stbir__simdi_u32 ;
static const int STBIR_mask [ 9 ] = { 0 , 0 , 0 , - 1 , - 1 , - 1 , 0 , 0 , 0 } ;
static const STBIR__SIMDF_CONST ( STBIR_max_uint8_as_float , stbir__max_uint8_as_float ) ;
static const STBIR__SIMDF_CONST ( STBIR_max_uint16_as_float , stbir__max_uint16_as_float ) ;
static const STBIR__SIMDF_CONST ( STBIR_max_uint8_as_float_inverted , stbir__max_uint8_as_float_inverted ) ;
static const STBIR__SIMDF_CONST ( STBIR_max_uint16_as_float_inverted , stbir__max_uint16_as_float_inverted ) ;
static const STBIR__SIMDF_CONST ( STBIR_simd_point5 , 0.5f ) ;
static const STBIR__SIMDF_CONST ( STBIR_ones , 1.0f ) ;
static const STBIR__SIMDI_CONST ( STBIR_almost_zero , ( 127 - 13 ) < < 23 ) ;
static const STBIR__SIMDI_CONST ( STBIR_almost_one , 0x3f7fffff ) ;
static const STBIR__SIMDI_CONST ( STBIR_mastissa_mask , 0xff ) ;
static const STBIR__SIMDI_CONST ( STBIR_topscale , 0x02000000 ) ;
// Basically, in simd mode, we unroll the proper amount, and we don't want
// the non-simd remnant loops to be unroll because they only run a few times
// Adding this switch saves about 5K on clang which is Captain Unroll the 3rd.
# define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star )
# define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr)
# ifdef STBIR_MEMCPY
# undef STBIR_MEMCPY
# define STBIR_MEMCPY stbir_simd_memcpy
# endif
// override normal use of memcpy with much simpler copy (faster and smaller with our sized copies)
static void stbir_simd_memcpy ( void * dest , void const * src , size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR ( * ) d = ( char * ) dest ;
char STBIR_SIMD_STREAMOUT_PTR ( * ) d_end = ( ( char * ) dest ) + bytes ;
ptrdiff_t ofs_to_src = ( char * ) src - ( char * ) dest ;
// check overlaps
STBIR_ASSERT ( ( ( d > = ( ( char * ) src ) + bytes ) ) | | ( ( d + bytes ) < = ( char * ) src ) ) ;
if ( bytes < ( 16 * stbir__simdfX_float_count ) )
{
if ( bytes < 16 )
{
if ( bytes )
{
do
{
STBIR_SIMD_NO_UNROLL ( d ) ;
d [ 0 ] = d [ ofs_to_src ] ;
+ + d ;
} while ( d < d_end ) ;
}
}
else
{
stbir__simdf x ;
// do one unaligned to get us aligned for the stream out below
stbir__simdf_load ( x , ( d + ofs_to_src ) ) ;
stbir__simdf_store ( d , x ) ;
d = ( char * ) ( ( ( ( ptrdiff_t ) d ) + 16 ) & ~ 15 ) ;
for ( ; ; )
{
STBIR_SIMD_NO_UNROLL ( d ) ;
if ( d > ( d_end - 16 ) )
{
if ( d = = d_end )
return ;
d = d_end - 16 ;
}
stbir__simdf_load ( x , ( d + ofs_to_src ) ) ;
stbir__simdf_store ( d , x ) ;
d + = 16 ;
}
}
}
else
{
stbir__simdfX x0 , x1 , x2 , x3 ;
// do one unaligned to get us aligned for the stream out below
stbir__simdfX_load ( x0 , ( d + ofs_to_src ) + 0 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x1 , ( d + ofs_to_src ) + 4 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x2 , ( d + ofs_to_src ) + 8 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x3 , ( d + ofs_to_src ) + 12 * stbir__simdfX_float_count ) ;
stbir__simdfX_store ( d + 0 * stbir__simdfX_float_count , x0 ) ;
stbir__simdfX_store ( d + 4 * stbir__simdfX_float_count , x1 ) ;
stbir__simdfX_store ( d + 8 * stbir__simdfX_float_count , x2 ) ;
stbir__simdfX_store ( d + 12 * stbir__simdfX_float_count , x3 ) ;
d = ( char * ) ( ( ( ( ptrdiff_t ) d ) + ( 16 * stbir__simdfX_float_count ) ) & ~ ( ( 16 * stbir__simdfX_float_count ) - 1 ) ) ;
for ( ; ; )
{
STBIR_SIMD_NO_UNROLL ( d ) ;
if ( d > ( d_end - ( 16 * stbir__simdfX_float_count ) ) )
{
if ( d = = d_end )
return ;
d = d_end - ( 16 * stbir__simdfX_float_count ) ;
}
stbir__simdfX_load ( x0 , ( d + ofs_to_src ) + 0 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x1 , ( d + ofs_to_src ) + 4 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x2 , ( d + ofs_to_src ) + 8 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( x3 , ( d + ofs_to_src ) + 12 * stbir__simdfX_float_count ) ;
stbir__simdfX_store ( d + 0 * stbir__simdfX_float_count , x0 ) ;
stbir__simdfX_store ( d + 4 * stbir__simdfX_float_count , x1 ) ;
stbir__simdfX_store ( d + 8 * stbir__simdfX_float_count , x2 ) ;
stbir__simdfX_store ( d + 12 * stbir__simdfX_float_count , x3 ) ;
d + = ( 16 * stbir__simdfX_float_count ) ;
}
}
}
// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
// the diff between dest and src)
static void stbir_overlapping_memcpy ( void * dest , void const * src , size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR ( * ) sd = ( char * ) src ;
char STBIR_SIMD_STREAMOUT_PTR ( * ) s_end = ( ( char * ) src ) + bytes ;
ptrdiff_t ofs_to_dest = ( char * ) dest - ( char * ) src ;
if ( ofs_to_dest > = 16 ) // is the overlap more than 16 away?
{
char STBIR_SIMD_STREAMOUT_PTR ( * ) s_end16 = ( ( char * ) src ) + ( bytes & ~ 15 ) ;
do
{
stbir__simdf x ;
STBIR_SIMD_NO_UNROLL ( sd ) ;
stbir__simdf_load ( x , sd ) ;
stbir__simdf_store ( ( sd + ofs_to_dest ) , x ) ;
sd + = 16 ;
} while ( sd < s_end16 ) ;
if ( sd = = s_end )
return ;
}
do
{
STBIR_SIMD_NO_UNROLL ( sd ) ;
* ( int * ) ( sd + ofs_to_dest ) = * ( int * ) sd ;
sd + = 4 ;
} while ( sd < s_end ) ;
}
# else // no SSE2
// when in scalar mode, we let unrolling happen, so this macro just does the __restrict
# define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star )
# define STBIR_SIMD_NO_UNROLL(ptr)
# endif // SSE2
# ifdef STBIR_PROFILE
# if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
# ifdef _MSC_VER
STBIRDEF stbir_uint64 __rdtsc ( ) ;
# define STBIR_PROFILE_FUNC() __rdtsc()
# else // non msvc
static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC ( )
{
stbir_uint32 lo , hi ;
asm volatile ( " rdtsc " : " =a " ( lo ) , " =d " ( hi ) ) ;
return ( ( ( stbir_uint64 ) hi ) < < 32 ) | ( ( stbir_uint64 ) lo ) ;
}
# endif // msvc
# elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
# if defined( _MSC_VER ) && !defined(__clang__)
# define STBIR_PROFILE_FUNC() _ReadStatusReg(ARM64_CNTVCT)
# else
static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC ( )
{
stbir_uint64 tsc ;
asm volatile ( " mrs %0, cntvct_el0 " : " =r " ( tsc ) ) ;
return tsc ;
}
# endif
# else // x64, arm
# error Unknown platform for profiling.
# endif //x64 and
# define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info
# define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info
# define STBIR_ONLY_PROFILE_BUILD_GET_INFO ,stbir__info * profile_info
# define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info
// super light-weight micro profiler
# define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded;
# define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; }
# define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh );
# define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;i<STBIR__ARRAY_SIZE((info)->profile.array);i++) (info)[extra].profile.array[i]=0; } }
// for thread data
# define STBIR_PROFILE_START( wh ) STBIR_PROFILE_START_ll( split_info, wh )
# define STBIR_PROFILE_END( wh ) STBIR_PROFILE_END_ll( split_info, wh )
# define STBIR_PROFILE_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( split_info, wh )
# define STBIR_PROFILE_CLEAR_EXTRAS() STBIR_PROFILE_CLEAR_EXTRAS_ll( split_info, split_count )
// for build data
# define STBIR_PROFILE_BUILD_START( wh ) STBIR_PROFILE_START_ll( profile_info, wh )
# define STBIR_PROFILE_BUILD_END( wh ) STBIR_PROFILE_END_ll( profile_info, wh )
# define STBIR_PROFILE_BUILD_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( profile_info, wh )
# define STBIR_PROFILE_BUILD_CLEAR( info ) { int i; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; }
# else // no profile
# define STBIR_ONLY_PROFILE_GET_SPLIT_INFO
# define STBIR_ONLY_PROFILE_SET_SPLIT_INFO
# define STBIR_ONLY_PROFILE_BUILD_GET_INFO
# define STBIR_ONLY_PROFILE_BUILD_SET_INFO
# define STBIR_PROFILE_START( wh )
# define STBIR_PROFILE_END( wh )
# define STBIR_PROFILE_FIRST_START( wh )
# define STBIR_PROFILE_CLEAR_EXTRAS( )
# define STBIR_PROFILE_BUILD_START( wh )
# define STBIR_PROFILE_BUILD_END( wh )
# define STBIR_PROFILE_BUILD_FIRST_START( wh )
# define STBIR_PROFILE_BUILD_CLEAR( info )
# endif // stbir_profile
# ifndef STBIR_CEILF
# include <math.h>
# if _MSC_VER <= 1200 // support VC6 for Sean
# define STBIR_CEILF(x) ((float)ceil((float)(x)))
# define STBIR_FLOORF(x) ((float)floor((float)(x)))
# else
# define STBIR_CEILF(x) ceilf(x)
# define STBIR_FLOORF(x) floorf(x)
# endif
# endif
# ifndef STBIR_MEMCPY
// For memcpy
# include <string.h>
# define STBIR_MEMCPY( dest, src, len ) memcpy( dest, src, len )
# endif
# ifndef STBIR_SIMD
// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
// the diff between dest and src)
static void stbir_overlapping_memcpy ( void * dest , void const * src , size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR ( * ) sd = ( char * ) src ;
char STBIR_SIMD_STREAMOUT_PTR ( * ) s_end = ( ( char * ) src ) + bytes ;
ptrdiff_t ofs_to_dest = ( char * ) dest - ( char * ) src ;
if ( ofs_to_dest > = 8 ) // is the overlap more than 8 away?
{
char STBIR_SIMD_STREAMOUT_PTR ( * ) s_end8 = ( ( char * ) src ) + ( bytes & ~ 7 ) ;
do
{
STBIR_NO_UNROLL ( sd ) ;
* ( stbir_uint64 * ) ( sd + ofs_to_dest ) = * ( stbir_uint64 * ) sd ;
sd + = 8 ;
} while ( sd < s_end8 ) ;
if ( sd = = s_end )
return ;
}
do
{
STBIR_NO_UNROLL ( sd ) ;
* ( int * ) ( sd + ofs_to_dest ) = * ( int * ) sd ;
sd + = 4 ;
} while ( sd < s_end ) ;
}
# endif
static float stbir__filter_trapezoid ( float x , float scale , void * user_data )
{
float halfscale = scale / 2 ;
float t = 0.5f + halfscale ;
STBIR_ASSERT ( scale < = 1 ) ;
STBIR__UNUSED ( user_data ) ;
if ( x < 0.0f ) x = - x ;
if ( x > = t )
return 0.0f ;
else
{
float r = 0.5f - halfscale ;
if ( x < = r )
return 1.0f ;
else
return ( t - x ) / scale ;
}
}
static float stbir__support_trapezoid ( float scale , void * user_data )
{
STBIR__UNUSED ( user_data ) ;
return 0.5f + scale / 2.0f ;
}
static float stbir__filter_triangle ( float x , float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
if ( x < 0.0f ) x = - x ;
if ( x < = 1.0f )
return 1.0f - x ;
else
return 0.0f ;
}
static float stbir__filter_point ( float x , float s , void * user_data )
{
STBIR__UNUSED ( x ) ;
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
return 1.0f ;
}
static float stbir__filter_cubic ( float x , float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
if ( x < 0.0f ) x = - x ;
if ( x < 1.0f )
return ( 4.0f + x * x * ( 3.0f * x - 6.0f ) ) / 6.0f ;
else if ( x < 2.0f )
return ( 8.0f + x * ( - 12.0f + x * ( 6.0f - x ) ) ) / 6.0f ;
return ( 0.0f ) ;
}
static float stbir__filter_catmullrom ( float x , float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
if ( x < 0.0f ) x = - x ;
if ( x < 1.0f )
return 1.0f - x * x * ( 2.5f - 1.5f * x ) ;
else if ( x < 2.0f )
return 2.0f - x * ( 4.0f + x * ( 0.5f * x - 2.5f ) ) ;
return ( 0.0f ) ;
}
static float stbir__filter_mitchell ( float x , float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
if ( x < 0.0f ) x = - x ;
if ( x < 1.0f )
return ( 16.0f + x * x * ( 21.0f * x - 36.0f ) ) / 18.0f ;
else if ( x < 2.0f )
return ( 32.0f + x * ( - 60.0f + x * ( 36.0f - 7.0f * x ) ) ) / 18.0f ;
return ( 0.0f ) ;
}
2023-12-26 15:14:24 -05:00
static float stbir__support_zero ( float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
return 0 ;
}
2023-12-17 15:04:57 -05:00
static float stbir__support_zeropoint5 ( float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
return 0.5f ;
}
static float stbir__support_one ( float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
return 1 ;
}
static float stbir__support_two ( float s , void * user_data )
{
STBIR__UNUSED ( s ) ;
STBIR__UNUSED ( user_data ) ;
return 2 ;
}
// This is the maximum number of input samples that can affect an output sample
// with the given filter from the output pixel's perspective
static int stbir__get_filter_pixel_width ( stbir__support_callback * support , float scale , void * user_data )
{
STBIR_ASSERT ( support ! = 0 ) ;
if ( scale > = ( 1.0f - stbir__small_float ) ) // upscale
return ( int ) STBIR_CEILF ( support ( 1.0f / scale , user_data ) * 2.0f ) ;
else
return ( int ) STBIR_CEILF ( support ( scale , user_data ) * 2.0f / scale ) ;
}
// this is how many coefficents per run of the filter (which is different
// from the filter_pixel_width depending on if we are scattering or gathering)
static int stbir__get_coefficient_width ( stbir__sampler * samp , int is_gather , void * user_data )
{
float scale = samp - > scale_info . scale ;
stbir__support_callback * support = samp - > filter_support ;
switch ( is_gather )
{
case 1 :
return ( int ) STBIR_CEILF ( support ( 1.0f / scale , user_data ) * 2.0f ) ;
case 2 :
return ( int ) STBIR_CEILF ( support ( scale , user_data ) * 2.0f / scale ) ;
case 0 :
return ( int ) STBIR_CEILF ( support ( scale , user_data ) * 2.0f ) ;
default :
STBIR_ASSERT ( ( is_gather > = 0 ) & & ( is_gather < = 2 ) ) ;
return 0 ;
}
}
static int stbir__get_contributors ( stbir__sampler * samp , int is_gather )
{
if ( is_gather )
return samp - > scale_info . output_sub_size ;
else
return ( samp - > scale_info . input_full_size + samp - > filter_pixel_margin * 2 ) ;
}
static int stbir__edge_zero_full ( int n , int max )
{
STBIR__UNUSED ( n ) ;
STBIR__UNUSED ( max ) ;
return 0 ; // NOTREACHED
}
static int stbir__edge_clamp_full ( int n , int max )
{
if ( n < 0 )
return 0 ;
if ( n > = max )
return max - 1 ;
return n ; // NOTREACHED
}
static int stbir__edge_reflect_full ( int n , int max )
{
if ( n < 0 )
{
if ( n > - max )
return - n ;
else
return max - 1 ;
}
if ( n > = max )
{
int max2 = max * 2 ;
if ( n > = max2 )
return 0 ;
else
return max2 - n - 1 ;
}
return n ; // NOTREACHED
}
static int stbir__edge_wrap_full ( int n , int max )
{
if ( n > = 0 )
return ( n % max ) ;
else
{
int m = ( - n ) % max ;
if ( m ! = 0 )
m = max - m ;
return ( m ) ;
}
}
typedef int stbir__edge_wrap_func ( int n , int max ) ;
static stbir__edge_wrap_func * stbir__edge_wrap_slow [ ] =
{
stbir__edge_clamp_full , // STBIR_EDGE_CLAMP
stbir__edge_reflect_full , // STBIR_EDGE_REFLECT
stbir__edge_wrap_full , // STBIR_EDGE_WRAP
stbir__edge_zero_full , // STBIR_EDGE_ZERO
} ;
stbir__inline static int stbir__edge_wrap ( stbir_edge edge , int n , int max )
{
// avoid per-pixel switch
if ( n > = 0 & & n < max )
return n ;
return stbir__edge_wrap_slow [ edge ] ( n , max ) ;
}
# define STBIR__MERGE_RUNS_PIXEL_THRESHOLD 16
// get information on the extents of a sampler
static void stbir__get_extents ( stbir__sampler * samp , stbir__extents * scanline_extents )
{
int j , stop ;
int left_margin , right_margin ;
int min_n = 0x7fffffff , max_n = - 0x7fffffff ;
int min_left = 0x7fffffff , max_left = - 0x7fffffff ;
int min_right = 0x7fffffff , max_right = - 0x7fffffff ;
stbir_edge edge = samp - > edge ;
stbir__contributors * contributors = samp - > contributors ;
int output_sub_size = samp - > scale_info . output_sub_size ;
int input_full_size = samp - > scale_info . input_full_size ;
int filter_pixel_margin = samp - > filter_pixel_margin ;
STBIR_ASSERT ( samp - > is_gather ) ;
stop = output_sub_size ;
for ( j = 0 ; j < stop ; j + + )
{
STBIR_ASSERT ( contributors [ j ] . n1 > = contributors [ j ] . n0 ) ;
if ( contributors [ j ] . n0 < min_n )
{
min_n = contributors [ j ] . n0 ;
stop = j + filter_pixel_margin ; // if we find a new min, only scan another filter width
if ( stop > output_sub_size ) stop = output_sub_size ;
}
}
stop = 0 ;
for ( j = output_sub_size - 1 ; j > = stop ; j - - )
{
STBIR_ASSERT ( contributors [ j ] . n1 > = contributors [ j ] . n0 ) ;
if ( contributors [ j ] . n1 > max_n )
{
max_n = contributors [ j ] . n1 ;
stop = j - filter_pixel_margin ; // if we find a new max, only scan another filter width
if ( stop < 0 ) stop = 0 ;
}
}
STBIR_ASSERT ( scanline_extents - > conservative . n0 < = min_n ) ;
STBIR_ASSERT ( scanline_extents - > conservative . n1 > = max_n ) ;
// now calculate how much into the margins we really read
left_margin = 0 ;
if ( min_n < 0 )
{
left_margin = - min_n ;
min_n = 0 ;
}
right_margin = 0 ;
if ( max_n > = input_full_size )
{
right_margin = max_n - input_full_size + 1 ;
max_n = input_full_size - 1 ;
}
// index 1 is margin pixel extents (how many pixels we hang over the edge)
scanline_extents - > edge_sizes [ 0 ] = left_margin ;
scanline_extents - > edge_sizes [ 1 ] = right_margin ;
// index 2 is pixels read from the input
scanline_extents - > spans [ 0 ] . n0 = min_n ;
scanline_extents - > spans [ 0 ] . n1 = max_n ;
scanline_extents - > spans [ 0 ] . pixel_offset_for_input = min_n ;
// default to no other input range
scanline_extents - > spans [ 1 ] . n0 = 0 ;
scanline_extents - > spans [ 1 ] . n1 = - 1 ;
scanline_extents - > spans [ 1 ] . pixel_offset_for_input = 0 ;
// don't have to do edge calc for zero clamp
if ( edge = = STBIR_EDGE_ZERO )
return ;
// convert margin pixels to the pixels within the input (min and max)
for ( j = - left_margin ; j < 0 ; j + + )
{
int p = stbir__edge_wrap ( edge , j , input_full_size ) ;
if ( p < min_left )
min_left = p ;
if ( p > max_left )
max_left = p ;
}
for ( j = input_full_size ; j < ( input_full_size + right_margin ) ; j + + )
{
int p = stbir__edge_wrap ( edge , j , input_full_size ) ;
if ( p < min_right )
min_right = p ;
if ( p > max_right )
max_right = p ;
}
// merge the left margin pixel region if it connects within 4 pixels of main pixel region
if ( min_left ! = 0x7fffffff )
{
if ( ( ( min_left < = min_n ) & & ( ( max_left + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) > = min_n ) ) | |
( ( min_n < = min_left ) & & ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) > = max_left ) ) )
{
scanline_extents - > spans [ 0 ] . n0 = min_n = stbir__min ( min_n , min_left ) ;
scanline_extents - > spans [ 0 ] . n1 = max_n = stbir__max ( max_n , max_left ) ;
scanline_extents - > spans [ 0 ] . pixel_offset_for_input = min_n ;
left_margin = 0 ;
}
}
// merge the right margin pixel region if it connects within 4 pixels of main pixel region
if ( min_right ! = 0x7fffffff )
{
if ( ( ( min_right < = min_n ) & & ( ( max_right + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) > = min_n ) ) | |
( ( min_n < = min_right ) & & ( ( max_n + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) > = max_right ) ) )
{
scanline_extents - > spans [ 0 ] . n0 = min_n = stbir__min ( min_n , min_right ) ;
scanline_extents - > spans [ 0 ] . n1 = max_n = stbir__max ( max_n , max_right ) ;
scanline_extents - > spans [ 0 ] . pixel_offset_for_input = min_n ;
right_margin = 0 ;
}
}
STBIR_ASSERT ( scanline_extents - > conservative . n0 < = min_n ) ;
STBIR_ASSERT ( scanline_extents - > conservative . n1 > = max_n ) ;
// you get two ranges when you have the WRAP edge mode and you are doing just the a piece of the resize
// so you need to get a second run of pixels from the opposite side of the scanline (which you
// wouldn't need except for WRAP)
// if we can't merge the min_left range, add it as a second range
if ( ( left_margin ) & & ( min_left ! = 0x7fffffff ) )
{
stbir__span * newspan = scanline_extents - > spans + 1 ;
STBIR_ASSERT ( right_margin = = 0 ) ;
if ( min_left < scanline_extents - > spans [ 0 ] . n0 )
{
scanline_extents - > spans [ 1 ] . pixel_offset_for_input = scanline_extents - > spans [ 0 ] . n0 ;
scanline_extents - > spans [ 1 ] . n0 = scanline_extents - > spans [ 0 ] . n0 ;
scanline_extents - > spans [ 1 ] . n1 = scanline_extents - > spans [ 0 ] . n1 ;
- - newspan ;
}
newspan - > pixel_offset_for_input = min_left ;
newspan - > n0 = - left_margin ;
newspan - > n1 = ( max_left - min_left ) - left_margin ;
scanline_extents - > edge_sizes [ 0 ] = 0 ; // don't need to copy the left margin, since we are directly decoding into the margin
return ;
}
// if we can't merge the min_left range, add it as a second range
if ( ( right_margin ) & & ( min_right ! = 0x7fffffff ) )
{
stbir__span * newspan = scanline_extents - > spans + 1 ;
if ( min_right < scanline_extents - > spans [ 0 ] . n0 )
{
scanline_extents - > spans [ 1 ] . pixel_offset_for_input = scanline_extents - > spans [ 0 ] . n0 ;
scanline_extents - > spans [ 1 ] . n0 = scanline_extents - > spans [ 0 ] . n0 ;
scanline_extents - > spans [ 1 ] . n1 = scanline_extents - > spans [ 0 ] . n1 ;
- - newspan ;
}
newspan - > pixel_offset_for_input = min_right ;
newspan - > n0 = scanline_extents - > spans [ 1 ] . n1 + 1 ;
newspan - > n1 = scanline_extents - > spans [ 1 ] . n1 + 1 + ( max_right - min_right ) ;
scanline_extents - > edge_sizes [ 1 ] = 0 ; // don't need to copy the right margin, since we are directly decoding into the margin
return ;
}
}
static void stbir__calculate_in_pixel_range ( int * first_pixel , int * last_pixel , float out_pixel_center , float out_filter_radius , float inv_scale , float out_shift , int input_size , stbir_edge edge )
{
int first , last ;
float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius ;
float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius ;
float in_pixel_influence_lowerbound = ( out_pixel_influence_lowerbound + out_shift ) * inv_scale ;
float in_pixel_influence_upperbound = ( out_pixel_influence_upperbound + out_shift ) * inv_scale ;
first = ( int ) ( STBIR_FLOORF ( in_pixel_influence_lowerbound + 0.5f ) ) ;
last = ( int ) ( STBIR_FLOORF ( in_pixel_influence_upperbound - 0.5f ) ) ;
if ( edge = = STBIR_EDGE_WRAP )
{
if ( first < = - input_size )
first = - ( input_size - 1 ) ;
if ( last > = ( input_size * 2 ) )
last = ( input_size * 2 ) - 1 ;
}
* first_pixel = first ;
* last_pixel = last ;
}
static void stbir__calculate_coefficients_for_gather_upsample ( float out_filter_radius , stbir__kernel_callback * kernel , stbir__scale_info * scale_info , int num_contributors , stbir__contributors * contributors , float * coefficient_group , int coefficient_width , stbir_edge edge , void * user_data )
{
int n , end ;
float inv_scale = scale_info - > inv_scale ;
float out_shift = scale_info - > pixel_shift ;
int input_size = scale_info - > input_full_size ;
int numerator = scale_info - > scale_numerator ;
int polyphase = ( ( scale_info - > scale_is_rational ) & & ( numerator < num_contributors ) ) ;
// Looping through out pixels
end = num_contributors ; if ( polyphase ) end = numerator ;
for ( n = 0 ; n < end ; n + + )
{
int i ;
int last_non_zero ;
float out_pixel_center = ( float ) n + 0.5f ;
float in_center_of_out = ( out_pixel_center + out_shift ) * inv_scale ;
int in_first_pixel , in_last_pixel ;
stbir__calculate_in_pixel_range ( & in_first_pixel , & in_last_pixel , out_pixel_center , out_filter_radius , inv_scale , out_shift , input_size , edge ) ;
last_non_zero = - 1 ;
for ( i = 0 ; i < = in_last_pixel - in_first_pixel ; i + + )
{
float in_pixel_center = ( float ) ( i + in_first_pixel ) + 0.5f ;
float coeff = kernel ( in_center_of_out - in_pixel_center , inv_scale , user_data ) ;
// kill denormals
if ( ( ( coeff < stbir__small_float ) & & ( coeff > - stbir__small_float ) ) )
{
if ( i = = 0 ) // if we're at the front, just eat zero contributors
{
STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) ! = 0 ) ; // there should be at least one contrib
+ + in_first_pixel ;
i - - ;
continue ;
}
coeff = 0 ; // make sure is fully zero (should keep denormals away)
}
else
last_non_zero = i ;
coefficient_group [ i ] = coeff ;
}
in_last_pixel = last_non_zero + in_first_pixel ; // kills trailing zeros
contributors - > n0 = in_first_pixel ;
contributors - > n1 = in_last_pixel ;
STBIR_ASSERT ( contributors - > n1 > = contributors - > n0 ) ;
+ + contributors ;
coefficient_group + = coefficient_width ;
}
}
static void stbir__insert_coeff ( stbir__contributors * contribs , float * coeffs , int new_pixel , float new_coeff )
{
if ( new_pixel < = contribs - > n1 ) // before the end
{
if ( new_pixel < contribs - > n0 ) // before the front?
{
int j , o = contribs - > n0 - new_pixel ;
for ( j = contribs - > n1 - contribs - > n0 ; j < = 0 ; j - - )
coeffs [ j + o ] = coeffs [ j ] ;
for ( j = 1 ; j < o ; j - - )
coeffs [ j ] = coeffs [ 0 ] ;
coeffs [ 0 ] = new_coeff ;
contribs - > n0 = new_pixel ;
}
else
{
coeffs [ new_pixel - contribs - > n0 ] + = new_coeff ;
}
}
else
{
int j , e = new_pixel - contribs - > n0 ;
for ( j = ( contribs - > n1 - contribs - > n0 ) + 1 ; j < e ; j + + ) // clear in-betweens coeffs if there are any
coeffs [ j ] = 0 ;
coeffs [ e ] = new_coeff ;
contribs - > n1 = new_pixel ;
}
}
static void stbir__calculate_out_pixel_range ( int * first_pixel , int * last_pixel , float in_pixel_center , float in_pixels_radius , float scale , float out_shift , int out_size )
{
float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius ;
float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius ;
float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale - out_shift ;
float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale - out_shift ;
int out_first_pixel = ( int ) ( STBIR_FLOORF ( out_pixel_influence_lowerbound + 0.5f ) ) ;
int out_last_pixel = ( int ) ( STBIR_FLOORF ( out_pixel_influence_upperbound - 0.5f ) ) ;
if ( out_first_pixel < 0 )
out_first_pixel = 0 ;
if ( out_last_pixel > = out_size )
out_last_pixel = out_size - 1 ;
* first_pixel = out_first_pixel ;
* last_pixel = out_last_pixel ;
}
static void stbir__calculate_coefficients_for_gather_downsample ( int start , int end , float in_pixels_radius , stbir__kernel_callback * kernel , stbir__scale_info * scale_info , int coefficient_width , int num_contributors , stbir__contributors * contributors , float * coefficient_group , void * user_data )
{
int in_pixel ;
int i ;
int first_out_inited = - 1 ;
float scale = scale_info - > scale ;
float out_shift = scale_info - > pixel_shift ;
int out_size = scale_info - > output_sub_size ;
int numerator = scale_info - > scale_numerator ;
int polyphase = ( ( scale_info - > scale_is_rational ) & & ( numerator < out_size ) ) ;
STBIR__UNUSED ( num_contributors ) ;
// Loop through the input pixels
for ( in_pixel = start ; in_pixel < end ; in_pixel + + )
{
float in_pixel_center = ( float ) in_pixel + 0.5f ;
float out_center_of_in = in_pixel_center * scale - out_shift ;
int out_first_pixel , out_last_pixel ;
stbir__calculate_out_pixel_range ( & out_first_pixel , & out_last_pixel , in_pixel_center , in_pixels_radius , scale , out_shift , out_size ) ;
if ( out_first_pixel > out_last_pixel )
continue ;
// clamp or exit if we are using polyphase filtering, and the limit is up
if ( polyphase )
{
// when polyphase, you only have to do coeffs up to the numerator count
if ( out_first_pixel = = numerator )
break ;
// don't do any extra work, clamp last pixel at numerator too
if ( out_last_pixel > = numerator )
out_last_pixel = numerator - 1 ;
}
for ( i = 0 ; i < = out_last_pixel - out_first_pixel ; i + + )
{
float out_pixel_center = ( float ) ( i + out_first_pixel ) + 0.5f ;
float x = out_pixel_center - out_center_of_in ;
float coeff = kernel ( x , scale , user_data ) * scale ;
// kill the coeff if it's too small (avoid denormals)
if ( ( ( coeff < stbir__small_float ) & & ( coeff > - stbir__small_float ) ) )
coeff = 0.0f ;
{
int out = i + out_first_pixel ;
float * coeffs = coefficient_group + out * coefficient_width ;
stbir__contributors * contribs = contributors + out ;
// is this the first time this output pixel has been seen? Init it.
if ( out > first_out_inited )
{
STBIR_ASSERT ( out = = ( first_out_inited + 1 ) ) ; // ensure we have only advanced one at time
first_out_inited = out ;
contribs - > n0 = in_pixel ;
contribs - > n1 = in_pixel ;
coeffs [ 0 ] = coeff ;
}
else
{
// insert on end (always in order)
if ( coeffs [ 0 ] = = 0.0f ) // if the first coefficent is zero, then zap it for this coeffs
{
STBIR_ASSERT ( ( in_pixel - contribs - > n0 ) = = 1 ) ; // ensure that when we zap, we're at the 2nd pos
contribs - > n0 = in_pixel ;
}
contribs - > n1 = in_pixel ;
STBIR_ASSERT ( ( in_pixel - contribs - > n0 ) < coefficient_width ) ;
coeffs [ in_pixel - contribs - > n0 ] = coeff ;
}
}
}
}
}
static void stbir__cleanup_gathered_coefficients ( stbir_edge edge , stbir__filter_extent_info * filter_info , stbir__scale_info * scale_info , int num_contributors , stbir__contributors * contributors , float * coefficient_group , int coefficient_width )
{
int input_size = scale_info - > input_full_size ;
int input_last_n1 = input_size - 1 ;
int n , end ;
int lowest = 0x7fffffff ;
int highest = - 0x7fffffff ;
int widest = - 1 ;
int numerator = scale_info - > scale_numerator ;
int denominator = scale_info - > scale_denominator ;
int polyphase = ( ( scale_info - > scale_is_rational ) & & ( numerator < num_contributors ) ) ;
float * coeffs ;
stbir__contributors * contribs ;
// weight all the coeffs for each sample
coeffs = coefficient_group ;
contribs = contributors ;
end = num_contributors ; if ( polyphase ) end = numerator ;
for ( n = 0 ; n < end ; n + + )
{
int i ;
float filter_scale , total_filter = 0 ;
int e ;
// add all contribs
e = contribs - > n1 - contribs - > n0 ;
for ( i = 0 ; i < = e ; i + + )
{
total_filter + = coeffs [ i ] ;
STBIR_ASSERT ( ( coeffs [ i ] > = - 2.0f ) & & ( coeffs [ i ] < = 2.0f ) ) ; // check for wonky weights
}
// rescale
if ( ( total_filter < stbir__small_float ) & & ( total_filter > - stbir__small_float ) )
{
// all coeffs are extremely small, just zero it
contribs - > n1 = contribs - > n0 ;
coeffs [ 0 ] = 0.0f ;
}
else
{
// if the total isn't 1.0, rescale everything
if ( ( total_filter < ( 1.0f - stbir__small_float ) ) | | ( total_filter > ( 1.0f + stbir__small_float ) ) )
{
filter_scale = 1.0f / total_filter ;
// scale them all
for ( i = 0 ; i < = e ; i + + )
coeffs [ i ] * = filter_scale ;
}
}
+ + contribs ;
coeffs + = coefficient_width ;
}
// if we have a rational for the scale, we can exploit the polyphaseness to not calculate
// most of the coefficients, so we copy them here
if ( polyphase )
{
stbir__contributors * prev_contribs = contributors ;
stbir__contributors * cur_contribs = contributors + numerator ;
for ( n = numerator ; n < num_contributors ; n + + )
{
cur_contribs - > n0 = prev_contribs - > n0 + denominator ;
cur_contribs - > n1 = prev_contribs - > n1 + denominator ;
+ + cur_contribs ;
+ + prev_contribs ;
}
stbir_overlapping_memcpy ( coefficient_group + numerator * coefficient_width , coefficient_group , ( num_contributors - numerator ) * coefficient_width * sizeof ( coeffs [ 0 ] ) ) ;
}
coeffs = coefficient_group ;
contribs = contributors ;
for ( n = 0 ; n < num_contributors ; n + + )
{
int i ;
// in zero edge mode, just remove out of bounds contribs completely (since their weights are accounted for now)
if ( edge = = STBIR_EDGE_ZERO )
{
// shrink the right side if necessary
if ( contribs - > n1 > input_last_n1 )
contribs - > n1 = input_last_n1 ;
// shrink the left side
if ( contribs - > n0 < 0 )
{
int j , left , skips = 0 ;
skips = - contribs - > n0 ;
contribs - > n0 = 0 ;
// now move down the weights
left = contribs - > n1 - contribs - > n0 + 1 ;
if ( left > 0 )
{
for ( j = 0 ; j < left ; j + + )
coeffs [ j ] = coeffs [ j + skips ] ;
}
}
}
else if ( ( edge = = STBIR_EDGE_CLAMP ) | | ( edge = = STBIR_EDGE_REFLECT ) )
{
// for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight
// right hand side first
if ( contribs - > n1 > input_last_n1 )
{
int start = contribs - > n0 ;
int endi = contribs - > n1 ;
contribs - > n1 = input_last_n1 ;
for ( i = input_size ; i < = endi ; i + + )
stbir__insert_coeff ( contribs , coeffs , stbir__edge_wrap_slow [ edge ] ( i , input_size ) , coeffs [ i - start ] ) ;
}
// now check left hand edge
if ( contribs - > n0 < 0 )
{
int save_n0 ;
float save_n0_coeff ;
float * c = coeffs - ( contribs - > n0 + 1 ) ;
// reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist)
for ( i = - 1 ; i > contribs - > n0 ; i - - )
stbir__insert_coeff ( contribs , coeffs , stbir__edge_wrap_slow [ edge ] ( i , input_size ) , * c - - ) ;
save_n0 = contribs - > n0 ;
save_n0_coeff = c [ 0 ] ; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)!
// now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib
contribs - > n0 = 0 ;
for ( i = 0 ; i < = contribs - > n1 ; i + + )
coeffs [ i ] = coeffs [ i - save_n0 ] ;
// now that we have shrunk down the contribs, we insert the first one safely
stbir__insert_coeff ( contribs , coeffs , stbir__edge_wrap_slow [ edge ] ( save_n0 , input_size ) , save_n0_coeff ) ;
}
}
if ( contribs - > n0 < = contribs - > n1 )
{
int diff = contribs - > n1 - contribs - > n0 + 1 ;
while ( diff & & ( coeffs [ diff - 1 ] = = 0.0f ) )
- - diff ;
contribs - > n1 = contribs - > n0 + diff - 1 ;
if ( contribs - > n0 < = contribs - > n1 )
{
if ( contribs - > n0 < lowest )
lowest = contribs - > n0 ;
if ( contribs - > n1 > highest )
highest = contribs - > n1 ;
if ( diff > widest )
widest = diff ;
}
// re-zero out unused coefficients (if any)
for ( i = diff ; i < coefficient_width ; i + + )
coeffs [ i ] = 0.0f ;
}
+ + contribs ;
coeffs + = coefficient_width ;
}
filter_info - > lowest = lowest ;
filter_info - > highest = highest ;
filter_info - > widest = widest ;
}
static int stbir__pack_coefficients ( int num_contributors , stbir__contributors * contributors , float * coefficents , int coefficient_width , int widest , int row_width )
{
# define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; }
# define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; }
# ifdef STBIR_SIMD
# define STBIR_MOVE_4( dest, src ) { stbir__simdf t; STBIR_NO_UNROLL(dest); stbir__simdf_load( t, src ); stbir__simdf_store( dest, t ); }
# else
# define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; }
# endif
if ( coefficient_width ! = widest )
{
float * pc = coefficents ;
float * coeffs = coefficents ;
float * pc_end = coefficents + num_contributors * widest ;
switch ( widest )
{
case 1 :
do {
STBIR_MOVE_1 ( pc , coeffs ) ;
+ + pc ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 2 :
do {
STBIR_MOVE_2 ( pc , coeffs ) ;
pc + = 2 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 3 :
do {
STBIR_MOVE_2 ( pc , coeffs ) ;
STBIR_MOVE_1 ( pc + 2 , coeffs + 2 ) ;
pc + = 3 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 4 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
pc + = 4 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 5 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_1 ( pc + 4 , coeffs + 4 ) ;
pc + = 5 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 6 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_2 ( pc + 4 , coeffs + 4 ) ;
pc + = 6 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 7 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_2 ( pc + 4 , coeffs + 4 ) ;
STBIR_MOVE_1 ( pc + 6 , coeffs + 6 ) ;
pc + = 7 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 8 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_4 ( pc + 4 , coeffs + 4 ) ;
pc + = 8 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 9 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_4 ( pc + 4 , coeffs + 4 ) ;
STBIR_MOVE_1 ( pc + 8 , coeffs + 8 ) ;
pc + = 9 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 10 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_4 ( pc + 4 , coeffs + 4 ) ;
STBIR_MOVE_2 ( pc + 8 , coeffs + 8 ) ;
pc + = 10 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 11 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_4 ( pc + 4 , coeffs + 4 ) ;
STBIR_MOVE_2 ( pc + 8 , coeffs + 8 ) ;
STBIR_MOVE_1 ( pc + 10 , coeffs + 10 ) ;
pc + = 11 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
case 12 :
do {
STBIR_MOVE_4 ( pc , coeffs ) ;
STBIR_MOVE_4 ( pc + 4 , coeffs + 4 ) ;
STBIR_MOVE_4 ( pc + 8 , coeffs + 8 ) ;
pc + = 12 ;
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
default :
do {
float * copy_end = pc + widest - 4 ;
float * c = coeffs ;
do {
STBIR_NO_UNROLL ( pc ) ;
STBIR_MOVE_4 ( pc , c ) ;
pc + = 4 ;
c + = 4 ;
} while ( pc < = copy_end ) ;
copy_end + = 4 ;
while ( pc < copy_end )
{
STBIR_MOVE_1 ( pc , c ) ;
+ + pc ; + + c ;
}
coeffs + = coefficient_width ;
} while ( pc < pc_end ) ;
break ;
}
}
// some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal
coefficents [ widest * num_contributors ] = 8888.0f ;
// the minimum we might read for unrolled filters widths is 12. So, we need to
// make sure we never read outside the decode buffer, by possibly moving
// the sample area back into the scanline, and putting zeros weights first.
// we start on the right edge and check until we're well past the possible
// clip area (2*widest).
{
stbir__contributors * contribs = contributors + num_contributors - 1 ;
float * coeffs = coefficents + widest * ( num_contributors - 1 ) ;
// go until no chance of clipping (this is usually less than 8 lops)
while ( ( contribs > = contributors ) & & ( ( contribs - > n0 + widest * 2 ) > = row_width ) )
{
// might we clip??
if ( ( contribs - > n0 + widest ) > row_width )
{
int stop_range = widest ;
// if range is larger than 12, it will be handled by generic loops that can terminate on the exact length
// of this contrib n1, instead of a fixed widest amount - so calculate this
if ( widest > 12 )
{
int mod ;
// how far will be read in the n_coeff loop (which depends on the widest count mod4);
mod = widest & 3 ;
stop_range = ( ( ( contribs - > n1 - contribs - > n0 + 1 ) - mod + 3 ) & ~ 3 ) + mod ;
// the n_coeff loops do a minimum amount of coeffs, so factor that in!
if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod ;
}
// now see if we still clip with the refined range
if ( ( contribs - > n0 + stop_range ) > row_width )
{
int new_n0 = row_width - stop_range ;
int num = contribs - > n1 - contribs - > n0 + 1 ;
int backup = contribs - > n0 - new_n0 ;
float * from_co = coeffs + num - 1 ;
float * to_co = from_co + backup ;
STBIR_ASSERT ( ( new_n0 > = 0 ) & & ( new_n0 < contribs - > n0 ) ) ;
// move the coeffs over
while ( num )
{
* to_co - - = * from_co - - ;
- - num ;
}
// zero new positions
while ( to_co > = coeffs )
* to_co - - = 0 ;
// set new start point
contribs - > n0 = new_n0 ;
if ( widest > 12 )
{
int mod ;
// how far will be read in the n_coeff loop (which depends on the widest count mod4);
mod = widest & 3 ;
stop_range = ( ( ( contribs - > n1 - contribs - > n0 + 1 ) - mod + 3 ) & ~ 3 ) + mod ;
// the n_coeff loops do a minimum amount of coeffs, so factor that in!
if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod ;
}
}
}
- - contribs ;
coeffs - = widest ;
}
}
return widest ;
# undef STBIR_MOVE_1
# undef STBIR_MOVE_2
# undef STBIR_MOVE_4
}
static void stbir__calculate_filters ( stbir__sampler * samp , stbir__sampler * other_axis_for_pivot , void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )
{
int n ;
float scale = samp - > scale_info . scale ;
stbir__kernel_callback * kernel = samp - > filter_kernel ;
stbir__support_callback * support = samp - > filter_support ;
float inv_scale = samp - > scale_info . inv_scale ;
int input_full_size = samp - > scale_info . input_full_size ;
int gather_num_contributors = samp - > num_contributors ;
stbir__contributors * gather_contributors = samp - > contributors ;
float * gather_coeffs = samp - > coefficients ;
int gather_coefficient_width = samp - > coefficient_width ;
switch ( samp - > is_gather )
{
case 1 : // gather upsample
{
float out_pixels_radius = support ( inv_scale , user_data ) * scale ;
stbir__calculate_coefficients_for_gather_upsample ( out_pixels_radius , kernel , & samp - > scale_info , gather_num_contributors , gather_contributors , gather_coeffs , gather_coefficient_width , samp - > edge , user_data ) ;
STBIR_PROFILE_BUILD_START ( cleanup ) ;
stbir__cleanup_gathered_coefficients ( samp - > edge , & samp - > extent_info , & samp - > scale_info , gather_num_contributors , gather_contributors , gather_coeffs , gather_coefficient_width ) ;
STBIR_PROFILE_BUILD_END ( cleanup ) ;
}
break ;
case 0 : // scatter downsample (only on vertical)
case 2 : // gather downsample
{
float in_pixels_radius = support ( scale , user_data ) * inv_scale ;
int filter_pixel_margin = samp - > filter_pixel_margin ;
int input_end = input_full_size + filter_pixel_margin ;
// if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after
if ( ! samp - > is_gather )
{
// check if we are using the same gather downsample on the horizontal as this vertical,
// if so, then we don't have to generate them, we can just pivot from the horizontal.
if ( other_axis_for_pivot )
{
gather_contributors = other_axis_for_pivot - > contributors ;
gather_coeffs = other_axis_for_pivot - > coefficients ;
gather_coefficient_width = other_axis_for_pivot - > coefficient_width ;
gather_num_contributors = other_axis_for_pivot - > num_contributors ;
samp - > extent_info . lowest = other_axis_for_pivot - > extent_info . lowest ;
samp - > extent_info . highest = other_axis_for_pivot - > extent_info . highest ;
samp - > extent_info . widest = other_axis_for_pivot - > extent_info . widest ;
goto jump_right_to_pivot ;
}
gather_contributors = samp - > gather_prescatter_contributors ;
gather_coeffs = samp - > gather_prescatter_coefficients ;
gather_coefficient_width = samp - > gather_prescatter_coefficient_width ;
gather_num_contributors = samp - > gather_prescatter_num_contributors ;
}
stbir__calculate_coefficients_for_gather_downsample ( - filter_pixel_margin , input_end , in_pixels_radius , kernel , & samp - > scale_info , gather_coefficient_width , gather_num_contributors , gather_contributors , gather_coeffs , user_data ) ;
STBIR_PROFILE_BUILD_START ( cleanup ) ;
stbir__cleanup_gathered_coefficients ( samp - > edge , & samp - > extent_info , & samp - > scale_info , gather_num_contributors , gather_contributors , gather_coeffs , gather_coefficient_width ) ;
STBIR_PROFILE_BUILD_END ( cleanup ) ;
if ( ! samp - > is_gather )
{
// if this is a scatter (vertical only), then we need to pivot the coeffs
stbir__contributors * scatter_contributors ;
int highest_set ;
jump_right_to_pivot :
STBIR_PROFILE_BUILD_START ( pivot ) ;
highest_set = ( - filter_pixel_margin ) - 1 ;
for ( n = 0 ; n < gather_num_contributors ; n + + )
{
int k ;
int gn0 = gather_contributors - > n0 , gn1 = gather_contributors - > n1 ;
int scatter_coefficient_width = samp - > coefficient_width ;
float * scatter_coeffs = samp - > coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width ;
float * g_coeffs = gather_coeffs ;
scatter_contributors = samp - > contributors + ( gn0 + filter_pixel_margin ) ;
for ( k = gn0 ; k < = gn1 ; k + + )
{
float gc = * g_coeffs + + ;
if ( ( k > highest_set ) | | ( scatter_contributors - > n0 > scatter_contributors - > n1 ) )
{
{
// if we are skipping over several contributors, we need to clear the skipped ones
stbir__contributors * clear_contributors = samp - > contributors + ( highest_set + filter_pixel_margin + 1 ) ;
while ( clear_contributors < scatter_contributors )
{
clear_contributors - > n0 = 0 ;
clear_contributors - > n1 = - 1 ;
+ + clear_contributors ;
}
}
scatter_contributors - > n0 = n ;
scatter_contributors - > n1 = n ;
scatter_coeffs [ 0 ] = gc ;
highest_set = k ;
}
else
{
stbir__insert_coeff ( scatter_contributors , scatter_coeffs , n , gc ) ;
}
+ + scatter_contributors ;
scatter_coeffs + = scatter_coefficient_width ;
}
+ + gather_contributors ;
gather_coeffs + = gather_coefficient_width ;
}
// now clear any unset contribs
{
stbir__contributors * clear_contributors = samp - > contributors + ( highest_set + filter_pixel_margin + 1 ) ;
stbir__contributors * end_contributors = samp - > contributors + samp - > num_contributors ;
while ( clear_contributors < end_contributors )
{
clear_contributors - > n0 = 0 ;
clear_contributors - > n1 = - 1 ;
+ + clear_contributors ;
}
}
STBIR_PROFILE_BUILD_END ( pivot ) ;
}
}
break ;
}
}
//========================================================================================================
// scanline decoders and encoders
# define stbir__coder_min_num 1
# define STB_IMAGE_RESIZE_DO_CODERS
# include STBIR__HEADER_FILENAME
# define stbir__decode_suffix BGRA
# define stbir__decode_swizzle
# define stbir__decode_order0 2
# define stbir__decode_order1 1
# define stbir__decode_order2 0
# define stbir__decode_order3 3
# define stbir__encode_order0 2
# define stbir__encode_order1 1
# define stbir__encode_order2 0
# define stbir__encode_order3 3
# define stbir__coder_min_num 4
# define STB_IMAGE_RESIZE_DO_CODERS
# include STBIR__HEADER_FILENAME
# define stbir__decode_suffix ARGB
# define stbir__decode_swizzle
# define stbir__decode_order0 1
# define stbir__decode_order1 2
# define stbir__decode_order2 3
# define stbir__decode_order3 0
# define stbir__encode_order0 3
# define stbir__encode_order1 0
# define stbir__encode_order2 1
# define stbir__encode_order3 2
# define stbir__coder_min_num 4
# define STB_IMAGE_RESIZE_DO_CODERS
# include STBIR__HEADER_FILENAME
# define stbir__decode_suffix ABGR
# define stbir__decode_swizzle
# define stbir__decode_order0 3
# define stbir__decode_order1 2
# define stbir__decode_order2 1
# define stbir__decode_order3 0
# define stbir__encode_order0 3
# define stbir__encode_order1 2
# define stbir__encode_order2 1
# define stbir__encode_order3 0
# define stbir__coder_min_num 4
# define STB_IMAGE_RESIZE_DO_CODERS
# include STBIR__HEADER_FILENAME
# define stbir__decode_suffix AR
# define stbir__decode_swizzle
# define stbir__decode_order0 1
# define stbir__decode_order1 0
# define stbir__decode_order2 3
# define stbir__decode_order3 2
# define stbir__encode_order0 1
# define stbir__encode_order1 0
# define stbir__encode_order2 3
# define stbir__encode_order3 2
# define stbir__coder_min_num 2
# define STB_IMAGE_RESIZE_DO_CODERS
# include STBIR__HEADER_FILENAME
// fancy alpha means we expand to keep both premultipied and non-premultiplied color channels
static void stbir__fancy_alpha_weight_4ch ( float * out_buffer , int width_times_channels )
{
float STBIR_STREAMOUT_PTR ( * ) out = out_buffer ;
float const * end_decode = out_buffer + ( width_times_channels / 4 ) * 7 ; // decode buffer aligned to end of out_buffer
float STBIR_STREAMOUT_PTR ( * ) decode = ( float * ) end_decode - width_times_channels ;
// fancy alpha is stored internally as R G B A Rpm Gpm Bpm
# ifdef STBIR_SIMD
# ifdef STBIR_SIMD8
decode + = 16 ;
while ( decode < = end_decode )
{
stbir__simdf8 d0 , d1 , a0 , a1 , p0 , p1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdf8_load ( d0 , decode - 16 ) ;
stbir__simdf8_load ( d1 , decode - 16 + 8 ) ;
stbir__simdf8_0123to33333333 ( a0 , d0 ) ;
stbir__simdf8_0123to33333333 ( a1 , d1 ) ;
stbir__simdf8_mult ( p0 , a0 , d0 ) ;
stbir__simdf8_mult ( p1 , a1 , d1 ) ;
stbir__simdf8_bot4s ( a0 , d0 , p0 ) ;
stbir__simdf8_bot4s ( a1 , d1 , p1 ) ;
stbir__simdf8_top4s ( d0 , d0 , p0 ) ;
stbir__simdf8_top4s ( d1 , d1 , p1 ) ;
stbir__simdf8_store ( out , a0 ) ;
stbir__simdf8_store ( out + 7 , d0 ) ;
stbir__simdf8_store ( out + 14 , a1 ) ;
stbir__simdf8_store ( out + 21 , d1 ) ;
decode + = 16 ;
out + = 28 ;
}
decode - = 16 ;
# else
decode + = 8 ;
while ( decode < = end_decode )
{
stbir__simdf d0 , a0 , d1 , a1 , p0 , p1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdf_load ( d0 , decode - 8 ) ;
stbir__simdf_load ( d1 , decode - 8 + 4 ) ;
stbir__simdf_0123to3333 ( a0 , d0 ) ;
stbir__simdf_0123to3333 ( a1 , d1 ) ;
stbir__simdf_mult ( p0 , a0 , d0 ) ;
stbir__simdf_mult ( p1 , a1 , d1 ) ;
stbir__simdf_store ( out , d0 ) ;
stbir__simdf_store ( out + 4 , p0 ) ;
stbir__simdf_store ( out + 7 , d1 ) ;
stbir__simdf_store ( out + 7 + 4 , p1 ) ;
decode + = 8 ;
out + = 14 ;
}
decode - = 8 ;
# endif
// might be one last odd pixel
# ifdef STBIR_SIMD8
while ( decode < end_decode )
# else
if ( decode < end_decode )
# endif
{
stbir__simdf d , a , p ;
stbir__simdf_load ( d , decode ) ;
stbir__simdf_0123to3333 ( a , d ) ;
stbir__simdf_mult ( p , a , d ) ;
stbir__simdf_store ( out , d ) ;
stbir__simdf_store ( out + 4 , p ) ;
decode + = 4 ;
out + = 7 ;
}
# else
while ( decode < end_decode )
{
float r = decode [ 0 ] , g = decode [ 1 ] , b = decode [ 2 ] , alpha = decode [ 3 ] ;
out [ 0 ] = r ;
out [ 1 ] = g ;
out [ 2 ] = b ;
out [ 3 ] = alpha ;
out [ 4 ] = r * alpha ;
out [ 5 ] = g * alpha ;
out [ 6 ] = b * alpha ;
out + = 7 ;
decode + = 4 ;
}
# endif
}
static void stbir__fancy_alpha_weight_2ch ( float * out_buffer , int width_times_channels )
{
float STBIR_STREAMOUT_PTR ( * ) out = out_buffer ;
float const * end_decode = out_buffer + ( width_times_channels / 2 ) * 3 ;
float STBIR_STREAMOUT_PTR ( * ) decode = ( float * ) end_decode - width_times_channels ;
// for fancy alpha, turns into: [X A Xpm][X A Xpm],etc
# ifdef STBIR_SIMD
decode + = 8 ;
if ( decode < = end_decode )
{
do {
# ifdef STBIR_SIMD8
stbir__simdf8 d0 , a0 , p0 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdf8_load ( d0 , decode - 8 ) ;
stbir__simdf8_0123to11331133 ( p0 , d0 ) ;
stbir__simdf8_0123to00220022 ( a0 , d0 ) ;
stbir__simdf8_mult ( p0 , p0 , a0 ) ;
stbir__simdf_store2 ( out , stbir__if_simdf8_cast_to_simdf4 ( d0 ) ) ;
stbir__simdf_store ( out + 2 , stbir__if_simdf8_cast_to_simdf4 ( p0 ) ) ;
stbir__simdf_store2h ( out + 3 , stbir__if_simdf8_cast_to_simdf4 ( d0 ) ) ;
stbir__simdf_store2 ( out + 6 , stbir__simdf8_gettop4 ( d0 ) ) ;
stbir__simdf_store ( out + 8 , stbir__simdf8_gettop4 ( p0 ) ) ;
stbir__simdf_store2h ( out + 9 , stbir__simdf8_gettop4 ( d0 ) ) ;
# else
stbir__simdf d0 , a0 , d1 , a1 , p0 , p1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdf_load ( d0 , decode - 8 ) ;
stbir__simdf_load ( d1 , decode - 8 + 4 ) ;
stbir__simdf_0123to1133 ( p0 , d0 ) ;
stbir__simdf_0123to1133 ( p1 , d1 ) ;
stbir__simdf_0123to0022 ( a0 , d0 ) ;
stbir__simdf_0123to0022 ( a1 , d1 ) ;
stbir__simdf_mult ( p0 , p0 , a0 ) ;
stbir__simdf_mult ( p1 , p1 , a1 ) ;
stbir__simdf_store2 ( out , d0 ) ;
stbir__simdf_store ( out + 2 , p0 ) ;
stbir__simdf_store2h ( out + 3 , d0 ) ;
stbir__simdf_store2 ( out + 6 , d1 ) ;
stbir__simdf_store ( out + 8 , p1 ) ;
stbir__simdf_store2h ( out + 9 , d1 ) ;
# endif
decode + = 8 ;
out + = 12 ;
} while ( decode < = end_decode ) ;
}
decode - = 8 ;
# endif
while ( decode < end_decode )
{
float x = decode [ 0 ] , y = decode [ 1 ] ;
STBIR_SIMD_NO_UNROLL ( decode ) ;
out [ 0 ] = x ;
out [ 1 ] = y ;
out [ 2 ] = x * y ;
out + = 3 ;
decode + = 2 ;
}
}
static void stbir__fancy_alpha_unweight_4ch ( float * encode_buffer , int width_times_channels )
{
float STBIR_SIMD_STREAMOUT_PTR ( * ) encode = encode_buffer ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) input = encode_buffer ;
float const * end_output = encode_buffer + width_times_channels ;
// fancy RGBA is stored internally as R G B A Rpm Gpm Bpm
do {
float alpha = input [ 3 ] ;
# ifdef STBIR_SIMD
stbir__simdf i , ia ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
if ( alpha < stbir__small_float )
{
stbir__simdf_load ( i , input ) ;
stbir__simdf_store ( encode , i ) ;
}
else
{
stbir__simdf_load1frep4 ( ia , 1.0f / alpha ) ;
stbir__simdf_load ( i , input + 4 ) ;
stbir__simdf_mult ( i , i , ia ) ;
stbir__simdf_store ( encode , i ) ;
encode [ 3 ] = alpha ;
}
# else
if ( alpha < stbir__small_float )
{
encode [ 0 ] = input [ 0 ] ;
encode [ 1 ] = input [ 1 ] ;
encode [ 2 ] = input [ 2 ] ;
}
else
{
float ialpha = 1.0f / alpha ;
encode [ 0 ] = input [ 4 ] * ialpha ;
encode [ 1 ] = input [ 5 ] * ialpha ;
encode [ 2 ] = input [ 6 ] * ialpha ;
}
encode [ 3 ] = alpha ;
# endif
input + = 7 ;
encode + = 4 ;
} while ( encode < end_output ) ;
}
// format: [X A Xpm][X A Xpm] etc
static void stbir__fancy_alpha_unweight_2ch ( float * encode_buffer , int width_times_channels )
{
float STBIR_SIMD_STREAMOUT_PTR ( * ) encode = encode_buffer ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) input = encode_buffer ;
float const * end_output = encode_buffer + width_times_channels ;
do {
float alpha = input [ 1 ] ;
encode [ 0 ] = input [ 0 ] ;
if ( alpha > = stbir__small_float )
encode [ 0 ] = input [ 2 ] / alpha ;
encode [ 1 ] = alpha ;
input + = 3 ;
encode + = 2 ;
} while ( encode < end_output ) ;
}
static void stbir__simple_alpha_weight_4ch ( float * decode_buffer , int width_times_channels )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decode_buffer ;
float const * end_decode = decode_buffer + width_times_channels ;
# ifdef STBIR_SIMD
{
decode + = 2 * stbir__simdfX_float_count ;
while ( decode < = end_decode )
{
stbir__simdfX d0 , a0 , d1 , a1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdfX_load ( d0 , decode - 2 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( d1 , decode - 2 * stbir__simdfX_float_count + stbir__simdfX_float_count ) ;
stbir__simdfX_aaa1 ( a0 , d0 , STBIR_onesX ) ;
stbir__simdfX_aaa1 ( a1 , d1 , STBIR_onesX ) ;
stbir__simdfX_mult ( d0 , d0 , a0 ) ;
stbir__simdfX_mult ( d1 , d1 , a1 ) ;
stbir__simdfX_store ( decode - 2 * stbir__simdfX_float_count , d0 ) ;
stbir__simdfX_store ( decode - 2 * stbir__simdfX_float_count + stbir__simdfX_float_count , d1 ) ;
decode + = 2 * stbir__simdfX_float_count ;
}
decode - = 2 * stbir__simdfX_float_count ;
// few last pixels remnants
# ifdef STBIR_SIMD8
while ( decode < end_decode )
# else
if ( decode < end_decode )
# endif
{
stbir__simdf d , a ;
stbir__simdf_load ( d , decode ) ;
stbir__simdf_aaa1 ( a , d , STBIR__CONSTF ( STBIR_ones ) ) ;
stbir__simdf_mult ( d , d , a ) ;
stbir__simdf_store ( decode , d ) ;
decode + = 4 ;
}
}
# else
while ( decode < end_decode )
{
float alpha = decode [ 3 ] ;
decode [ 0 ] * = alpha ;
decode [ 1 ] * = alpha ;
decode [ 2 ] * = alpha ;
decode + = 4 ;
}
# endif
}
static void stbir__simple_alpha_weight_2ch ( float * decode_buffer , int width_times_channels )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decode_buffer ;
float const * end_decode = decode_buffer + width_times_channels ;
# ifdef STBIR_SIMD
decode + = 2 * stbir__simdfX_float_count ;
while ( decode < = end_decode )
{
stbir__simdfX d0 , a0 , d1 , a1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdfX_load ( d0 , decode - 2 * stbir__simdfX_float_count ) ;
stbir__simdfX_load ( d1 , decode - 2 * stbir__simdfX_float_count + stbir__simdfX_float_count ) ;
stbir__simdfX_a1a1 ( a0 , d0 , STBIR_onesX ) ;
stbir__simdfX_a1a1 ( a1 , d1 , STBIR_onesX ) ;
stbir__simdfX_mult ( d0 , d0 , a0 ) ;
stbir__simdfX_mult ( d1 , d1 , a1 ) ;
stbir__simdfX_store ( decode - 2 * stbir__simdfX_float_count , d0 ) ;
stbir__simdfX_store ( decode - 2 * stbir__simdfX_float_count + stbir__simdfX_float_count , d1 ) ;
decode + = 2 * stbir__simdfX_float_count ;
}
decode - = 2 * stbir__simdfX_float_count ;
# endif
while ( decode < end_decode )
{
float alpha = decode [ 1 ] ;
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 ] * = alpha ;
decode + = 2 ;
}
}
static void stbir__simple_alpha_unweight_4ch ( float * encode_buffer , int width_times_channels )
{
float STBIR_SIMD_STREAMOUT_PTR ( * ) encode = encode_buffer ;
float const * end_output = encode_buffer + width_times_channels ;
do {
float alpha = encode [ 3 ] ;
# ifdef STBIR_SIMD
stbir__simdf i , ia ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
if ( alpha > = stbir__small_float )
{
stbir__simdf_load1frep4 ( ia , 1.0f / alpha ) ;
stbir__simdf_load ( i , encode ) ;
stbir__simdf_mult ( i , i , ia ) ;
stbir__simdf_store ( encode , i ) ;
encode [ 3 ] = alpha ;
}
# else
if ( alpha > = stbir__small_float )
{
float ialpha = 1.0f / alpha ;
encode [ 0 ] * = ialpha ;
encode [ 1 ] * = ialpha ;
encode [ 2 ] * = ialpha ;
}
# endif
encode + = 4 ;
} while ( encode < end_output ) ;
}
static void stbir__simple_alpha_unweight_2ch ( float * encode_buffer , int width_times_channels )
{
float STBIR_SIMD_STREAMOUT_PTR ( * ) encode = encode_buffer ;
float const * end_output = encode_buffer + width_times_channels ;
do {
float alpha = encode [ 1 ] ;
if ( alpha > = stbir__small_float )
encode [ 0 ] / = alpha ;
encode + = 2 ;
} while ( encode < end_output ) ;
}
// only used in RGB->BGR or BGR->RGB
static void stbir__simple_flip_3ch ( float * decode_buffer , int width_times_channels )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decode_buffer ;
float const * end_decode = decode_buffer + width_times_channels ;
decode + = 12 ;
while ( decode < = end_decode )
{
float t0 , t1 , t2 , t3 ;
STBIR_NO_UNROLL ( decode ) ;
t0 = decode [ 0 ] ; t1 = decode [ 3 ] ; t2 = decode [ 6 ] ; t3 = decode [ 9 ] ;
decode [ 0 ] = decode [ 2 ] ; decode [ 3 ] = decode [ 5 ] ; decode [ 6 ] = decode [ 8 ] ; decode [ 9 ] = decode [ 11 ] ;
decode [ 2 ] = t0 ; decode [ 5 ] = t1 ; decode [ 8 ] = t2 ; decode [ 11 ] = t3 ;
decode + = 12 ;
}
decode - = 12 ;
while ( decode < end_decode )
{
float t = decode [ 0 ] ;
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = decode [ 2 ] ;
decode [ 2 ] = t ;
decode + = 3 ;
}
}
static void stbir__decode_scanline ( stbir__info const * stbir_info , int n , float * output_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
{
int channels = stbir_info - > channels ;
int effective_channels = stbir_info - > effective_channels ;
int input_sample_in_bytes = stbir__type_size [ stbir_info - > input_type ] * channels ;
stbir_edge edge_horizontal = stbir_info - > horizontal . edge ;
stbir_edge edge_vertical = stbir_info - > vertical . edge ;
int row = stbir__edge_wrap ( edge_vertical , n , stbir_info - > vertical . scale_info . input_full_size ) ;
const void * input_plane_data = ( ( char * ) stbir_info - > input_data ) + ( ptrdiff_t ) row * ( ptrdiff_t ) stbir_info - > input_stride_bytes ;
stbir__span const * spans = stbir_info - > scanline_extents . spans ;
float * full_decode_buffer = output_buffer - stbir_info - > scanline_extents . conservative . n0 * effective_channels ;
// if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed
STBIR_ASSERT ( ! ( edge_vertical = = STBIR_EDGE_ZERO & & ( n < 0 | | n > = stbir_info - > vertical . scale_info . input_full_size ) ) ) ;
do
{
float * decode_buffer ;
void const * input_data ;
float * end_decode ;
int width_times_channels ;
int width ;
if ( spans - > n1 < spans - > n0 )
break ;
width = spans - > n1 + 1 - spans - > n0 ;
decode_buffer = full_decode_buffer + spans - > n0 * effective_channels ;
end_decode = full_decode_buffer + ( spans - > n1 + 1 ) * effective_channels ;
width_times_channels = width * channels ;
// read directly out of input plane by default
input_data = ( ( char * ) input_plane_data ) + spans - > pixel_offset_for_input * input_sample_in_bytes ;
// if we have an input callback, call it to get the input data
if ( stbir_info - > in_pixels_cb )
{
// call the callback with a temp buffer (that they can choose to use or not). the temp is just right aligned memory in the decode_buffer itself
input_data = stbir_info - > in_pixels_cb ( ( ( char * ) end_decode ) - ( width * input_sample_in_bytes ) , input_plane_data , width , spans - > pixel_offset_for_input , row , stbir_info - > user_data ) ;
}
STBIR_PROFILE_START ( decode ) ;
// convert the pixels info the float decode_buffer, (we index from end_decode, so that when channels<effective_channels, we are right justified in the buffer)
stbir_info - > decode_pixels ( ( float * ) end_decode - width_times_channels , width_times_channels , input_data ) ;
STBIR_PROFILE_END ( decode ) ;
if ( stbir_info - > alpha_weight )
{
STBIR_PROFILE_START ( alpha ) ;
stbir_info - > alpha_weight ( decode_buffer , width_times_channels ) ;
STBIR_PROFILE_END ( alpha ) ;
}
+ + spans ;
} while ( spans < = ( & stbir_info - > scanline_extents . spans [ 1 ] ) ) ;
// handle the edge_wrap filter (all other types are handled back out at the calculate_filter stage)
// basically the idea here is that if we have the whole scanline in memory, we don't redecode the
// wrapped edge pixels, and instead just memcpy them from the scanline into the edge positions
if ( ( edge_horizontal = = STBIR_EDGE_WRAP ) & & ( stbir_info - > scanline_extents . edge_sizes [ 0 ] | stbir_info - > scanline_extents . edge_sizes [ 1 ] ) )
{
// this code only runs if we're in edge_wrap, and we're doing the entire scanline
int e , start_x [ 2 ] ;
int input_full_size = stbir_info - > horizontal . scale_info . input_full_size ;
start_x [ 0 ] = - stbir_info - > scanline_extents . edge_sizes [ 0 ] ; // left edge start x
start_x [ 1 ] = input_full_size ; // right edge
for ( e = 0 ; e < 2 ; e + + )
{
// do each margin
int margin = stbir_info - > scanline_extents . edge_sizes [ e ] ;
if ( margin )
{
int x = start_x [ e ] ;
float * marg = full_decode_buffer + x * effective_channels ;
float const * src = full_decode_buffer + stbir__edge_wrap ( edge_horizontal , x , input_full_size ) * effective_channels ;
STBIR_MEMCPY ( marg , src , margin * effective_channels * sizeof ( float ) ) ;
}
}
}
}
//=================
// Do 1 channel horizontal routines
# ifdef STBIR_SIMD
# define stbir__1_coeff_only() \
stbir__simdf tot , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1 ( c , hc ) ; \
stbir__simdf_mult1_mem ( tot , c , decode ) ;
# define stbir__2_coeff_only() \
stbir__simdf tot , c , d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2z ( c , hc ) ; \
stbir__simdf_load2 ( d , decode ) ; \
stbir__simdf_mult ( tot , c , d ) ; \
stbir__simdf_0123to1230 ( c , tot ) ; \
stbir__simdf_add1 ( tot , tot , c ) ;
# define stbir__3_coeff_only() \
stbir__simdf tot , c , t ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( c , hc ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ; \
stbir__simdf_0123to1230 ( c , tot ) ; \
stbir__simdf_0123to2301 ( t , tot ) ; \
stbir__simdf_add1 ( tot , tot , c ) ; \
stbir__simdf_add1 ( tot , tot , t ) ;
# define stbir__store_output_tiny() \
stbir__simdf_store1 ( output , tot ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 1 ;
# define stbir__4_coeff_start() \
stbir__simdf tot , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( c , hc ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ; \
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( c , hc + ( ofs ) ) ; \
stbir__simdf_madd_mem ( tot , tot , c , decode + ( ofs ) ) ;
# define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
stbir__simdf_load1z ( c , hc + ( ofs ) ) ; \
stbir__simdf_load1 ( d , decode + ( ofs ) ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ; }
# define stbir__2_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
stbir__simdf_load2z ( c , hc + ( ofs ) ) ; \
stbir__simdf_load2 ( d , decode + ( ofs ) ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ; }
# define stbir__3_coeff_setup() \
stbir__simdf mask ; \
stbir__simdf_load ( mask , STBIR_mask + 3 ) ;
# define stbir__3_coeff_remnant( ofs ) \
stbir__simdf_load ( c , hc + ( ofs ) ) ; \
stbir__simdf_and ( c , c , mask ) ; \
stbir__simdf_madd_mem ( tot , tot , c , decode + ( ofs ) ) ;
# define stbir__store_output() \
stbir__simdf_0123to2301 ( c , tot ) ; \
stbir__simdf_add ( tot , tot , c ) ; \
stbir__simdf_0123to1230 ( c , tot ) ; \
stbir__simdf_add1 ( tot , tot , c ) ; \
stbir__simdf_store1 ( output , tot ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 1 ;
# else
# define stbir__1_coeff_only() \
float tot ; \
tot = decode [ 0 ] * hc [ 0 ] ;
# define stbir__2_coeff_only() \
float tot ; \
tot = decode [ 0 ] * hc [ 0 ] ; \
tot + = decode [ 1 ] * hc [ 1 ] ;
# define stbir__3_coeff_only() \
float tot ; \
tot = decode [ 0 ] * hc [ 0 ] ; \
tot + = decode [ 1 ] * hc [ 1 ] ; \
tot + = decode [ 2 ] * hc [ 2 ] ;
# define stbir__store_output_tiny() \
output [ 0 ] = tot ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 1 ;
# define stbir__4_coeff_start() \
float tot0 , tot1 , tot2 , tot3 ; \
tot0 = decode [ 0 ] * hc [ 0 ] ; \
tot1 = decode [ 1 ] * hc [ 1 ] ; \
tot2 = decode [ 2 ] * hc [ 2 ] ; \
tot3 = decode [ 3 ] * hc [ 3 ] ;
# define stbir__4_coeff_continue_from_4( ofs ) \
tot0 + = decode [ 0 + ( ofs ) ] * hc [ 0 + ( ofs ) ] ; \
tot1 + = decode [ 1 + ( ofs ) ] * hc [ 1 + ( ofs ) ] ; \
tot2 + = decode [ 2 + ( ofs ) ] * hc [ 2 + ( ofs ) ] ; \
tot3 + = decode [ 3 + ( ofs ) ] * hc [ 3 + ( ofs ) ] ;
# define stbir__1_coeff_remnant( ofs ) \
tot0 + = decode [ 0 + ( ofs ) ] * hc [ 0 + ( ofs ) ] ;
# define stbir__2_coeff_remnant( ofs ) \
tot0 + = decode [ 0 + ( ofs ) ] * hc [ 0 + ( ofs ) ] ; \
tot1 + = decode [ 1 + ( ofs ) ] * hc [ 1 + ( ofs ) ] ; \
# define stbir__3_coeff_remnant( ofs ) \
tot0 + = decode [ 0 + ( ofs ) ] * hc [ 0 + ( ofs ) ] ; \
tot1 + = decode [ 1 + ( ofs ) ] * hc [ 1 + ( ofs ) ] ; \
tot2 + = decode [ 2 + ( ofs ) ] * hc [ 2 + ( ofs ) ] ;
# define stbir__store_output() \
output [ 0 ] = ( tot0 + tot2 ) + ( tot1 + tot3 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 1 ;
# endif
# define STBIR__horizontal_channels 1
# define STB_IMAGE_RESIZE_DO_HORIZONTALS
# include STBIR__HEADER_FILENAME
//=================
// Do 2 channel horizontal routines
# ifdef STBIR_SIMD
# define stbir__1_coeff_only() \
stbir__simdf tot , c , d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1z ( c , hc ) ; \
stbir__simdf_0123to0011 ( c , c ) ; \
stbir__simdf_load2 ( d , decode ) ; \
stbir__simdf_mult ( tot , d , c ) ;
# define stbir__2_coeff_only() \
stbir__simdf tot , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( c , hc ) ; \
stbir__simdf_0123to0011 ( c , c ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ;
# define stbir__3_coeff_only() \
stbir__simdf tot , c , cs , d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_load2z ( d , decode + 4 ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ;
# define stbir__store_output_tiny() \
stbir__simdf_0123to2301 ( c , tot ) ; \
stbir__simdf_add ( tot , tot , c ) ; \
stbir__simdf_store2 ( output , tot ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 2 ;
# ifdef STBIR_SIMD8
# define stbir__4_coeff_start() \
stbir__simdf8 tot0 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc ) ; \
stbir__simdf8_0123to00112233 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot0 , c , decode ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00112233 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 2 ) ;
# define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf t ; \
stbir__simdf_load1z ( t , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( t , t ) ; \
stbir__simdf_mult_mem ( t , t , decode + ( ofs ) * 2 ) ; \
stbir__simdf8_add4 ( tot0 , tot0 , t ) ; }
# define stbir__2_coeff_remnant( ofs ) \
{ stbir__simdf t ; \
stbir__simdf_load2 ( t , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( t , t ) ; \
stbir__simdf_mult_mem ( t , t , decode + ( ofs ) * 2 ) ; \
stbir__simdf8_add4 ( tot0 , tot0 , t ) ; }
# define stbir__3_coeff_remnant( ofs ) \
{ stbir__simdf8 d ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00112233 ( c , cs ) ; \
stbir__simdf8_load6z ( d , decode + ( ofs ) * 2 ) ; \
stbir__simdf8_madd ( tot0 , tot0 , c , d ) ; }
# define stbir__store_output() \
{ stbir__simdf t , d ; \
stbir__simdf8_add4halves ( t , stbir__if_simdf8_cast_to_simdf4 ( tot0 ) , tot0 ) ; \
stbir__simdf_0123to2301 ( d , t ) ; \
stbir__simdf_add ( t , t , d ) ; \
stbir__simdf_store2 ( output , t ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 2 ; }
# else
# define stbir__4_coeff_start() \
stbir__simdf tot0 , tot1 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_0123to2233 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 4 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 2 ) ; \
stbir__simdf_0123to2233 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 2 + 4 ) ;
# define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
stbir__simdf_load1z ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_load2 ( d , decode + ( ofs ) * 2 ) ; \
stbir__simdf_madd ( tot0 , tot0 , d , c ) ; }
# define stbir__2_coeff_remnant( ofs ) \
stbir__simdf_load2 ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 2 ) ;
# define stbir__3_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0011 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 2 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_load2z ( d , decode + ( ofs ) * 2 + 4 ) ; \
stbir__simdf_madd ( tot1 , tot1 , d , c ) ; }
# define stbir__store_output() \
stbir__simdf_add ( tot0 , tot0 , tot1 ) ; \
stbir__simdf_0123to2301 ( c , tot0 ) ; \
stbir__simdf_add ( tot0 , tot0 , c ) ; \
stbir__simdf_store2 ( output , tot0 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 2 ;
# endif
# else
# define stbir__1_coeff_only() \
float tota , totb , c ; \
c = hc [ 0 ] ; \
tota = decode [ 0 ] * c ; \
totb = decode [ 1 ] * c ;
# define stbir__2_coeff_only() \
float tota , totb , c ; \
c = hc [ 0 ] ; \
tota = decode [ 0 ] * c ; \
totb = decode [ 1 ] * c ; \
c = hc [ 1 ] ; \
tota + = decode [ 2 ] * c ; \
totb + = decode [ 3 ] * c ;
// this weird order of add matches the simd
# define stbir__3_coeff_only() \
float tota , totb , c ; \
c = hc [ 0 ] ; \
tota = decode [ 0 ] * c ; \
totb = decode [ 1 ] * c ; \
c = hc [ 2 ] ; \
tota + = decode [ 4 ] * c ; \
totb + = decode [ 5 ] * c ; \
c = hc [ 1 ] ; \
tota + = decode [ 2 ] * c ; \
totb + = decode [ 3 ] * c ;
# define stbir__store_output_tiny() \
output [ 0 ] = tota ; \
output [ 1 ] = totb ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 2 ;
# define stbir__4_coeff_start() \
float tota0 , tota1 , tota2 , tota3 , totb0 , totb1 , totb2 , totb3 , c ; \
c = hc [ 0 ] ; \
tota0 = decode [ 0 ] * c ; \
totb0 = decode [ 1 ] * c ; \
c = hc [ 1 ] ; \
tota1 = decode [ 2 ] * c ; \
totb1 = decode [ 3 ] * c ; \
c = hc [ 2 ] ; \
tota2 = decode [ 4 ] * c ; \
totb2 = decode [ 5 ] * c ; \
c = hc [ 3 ] ; \
tota3 = decode [ 6 ] * c ; \
totb3 = decode [ 7 ] * c ;
# define stbir__4_coeff_continue_from_4( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 2 ] * c ; \
totb0 + = decode [ 1 + ( ofs ) * 2 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
tota1 + = decode [ 2 + ( ofs ) * 2 ] * c ; \
totb1 + = decode [ 3 + ( ofs ) * 2 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
tota2 + = decode [ 4 + ( ofs ) * 2 ] * c ; \
totb2 + = decode [ 5 + ( ofs ) * 2 ] * c ; \
c = hc [ 3 + ( ofs ) ] ; \
tota3 + = decode [ 6 + ( ofs ) * 2 ] * c ; \
totb3 + = decode [ 7 + ( ofs ) * 2 ] * c ;
# define stbir__1_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 2 ] * c ; \
totb0 + = decode [ 1 + ( ofs ) * 2 ] * c ;
# define stbir__2_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 2 ] * c ; \
totb0 + = decode [ 1 + ( ofs ) * 2 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
tota1 + = decode [ 2 + ( ofs ) * 2 ] * c ; \
totb1 + = decode [ 3 + ( ofs ) * 2 ] * c ;
# define stbir__3_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 2 ] * c ; \
totb0 + = decode [ 1 + ( ofs ) * 2 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
tota1 + = decode [ 2 + ( ofs ) * 2 ] * c ; \
totb1 + = decode [ 3 + ( ofs ) * 2 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
tota2 + = decode [ 4 + ( ofs ) * 2 ] * c ; \
totb2 + = decode [ 5 + ( ofs ) * 2 ] * c ;
# define stbir__store_output() \
output [ 0 ] = ( tota0 + tota2 ) + ( tota1 + tota3 ) ; \
output [ 1 ] = ( totb0 + totb2 ) + ( totb1 + totb3 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 2 ;
# endif
# define STBIR__horizontal_channels 2
# define STB_IMAGE_RESIZE_DO_HORIZONTALS
# include STBIR__HEADER_FILENAME
//=================
// Do 3 channel horizontal routines
# ifdef STBIR_SIMD
# define stbir__1_coeff_only() \
stbir__simdf tot , c , d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1z ( c , hc ) ; \
stbir__simdf_0123to0001 ( c , c ) ; \
stbir__simdf_load ( d , decode ) ; \
stbir__simdf_mult ( tot , d , c ) ;
# define stbir__2_coeff_only() \
stbir__simdf tot , c , cs , d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_load ( d , decode ) ; \
stbir__simdf_mult ( tot , d , c ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_load ( d , decode + 3 ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ;
# define stbir__3_coeff_only() \
stbir__simdf tot , c , d , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_load ( d , decode ) ; \
stbir__simdf_mult ( tot , d , c ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_load ( d , decode + 3 ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_load ( d , decode + 6 ) ; \
stbir__simdf_madd ( tot , tot , d , c ) ;
# define stbir__store_output_tiny() \
stbir__simdf_store2 ( output , tot ) ; \
stbir__simdf_0123to2301 ( tot , tot ) ; \
stbir__simdf_store1 ( output + 2 , tot ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 3 ;
# ifdef STBIR_SIMD8
// we're loading from the XXXYYY decode by -1 to get the XXXYYY into different halves of the AVX reg fyi
# define stbir__4_coeff_start() \
stbir__simdf8 tot0 , tot1 , c , cs ; stbir__simdf t ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot0 , c , decode - 1 ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot1 , c , decode + 6 - 1 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 - 1 ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 3 + 6 - 1 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1rep4 ( t , hc + ( ofs ) ) ; \
stbir__simdf8_madd_mem4 ( tot0 , tot0 , t , decode + ( ofs ) * 3 - 1 ) ;
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) - 2 ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 - 1 ) ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 - 1 ) ; \
stbir__simdf8_0123to2222 ( t , cs ) ; \
stbir__simdf8_madd_mem4 ( tot1 , tot1 , t , decode + ( ofs ) * 3 + 6 - 1 ) ;
# define stbir__store_output() \
stbir__simdf8_add ( tot0 , tot0 , tot1 ) ; \
stbir__simdf_0123to1230 ( t , stbir__if_simdf8_cast_to_simdf4 ( tot0 ) ) ; \
stbir__simdf8_add4halves ( t , t , tot0 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 3 ; \
if ( output < output_end ) \
{ \
stbir__simdf_store ( output - 3 , t ) ; \
continue ; \
} \
{ stbir__simdf tt ; stbir__simdf_0123to2301 ( tt , t ) ; \
stbir__simdf_store2 ( output - 3 , t ) ; \
stbir__simdf_store1 ( output + 2 - 3 , tt ) ; } \
break ;
# else
# define stbir__4_coeff_start() \
stbir__simdf tot0 , tot1 , tot2 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0001 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_0123to1122 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 4 ) ; \
stbir__simdf_0123to2333 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot2 , c , decode + 8 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0001 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 ) ; \
stbir__simdf_0123to1122 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 3 + 4 ) ; \
stbir__simdf_0123to2333 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + ( ofs ) * 3 + 8 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1z ( c , hc + ( ofs ) ) ; \
stbir__simdf_0123to0001 ( c , c ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 ) ;
# define stbir__2_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2z ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0001 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 ) ; \
stbir__simdf_0123to1122 ( c , cs ) ; \
stbir__simdf_load2z ( d , decode + ( ofs ) * 3 + 4 ) ; \
stbir__simdf_madd ( tot1 , tot1 , c , d ) ; }
# define stbir__3_coeff_remnant( ofs ) \
{ stbir__simdf d ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0001 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 3 ) ; \
stbir__simdf_0123to1122 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 3 + 4 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_load1z ( d , decode + ( ofs ) * 3 + 8 ) ; \
stbir__simdf_madd ( tot2 , tot2 , c , d ) ; }
# define stbir__store_output() \
stbir__simdf_0123ABCDto3ABx ( c , tot0 , tot1 ) ; \
stbir__simdf_0123ABCDto23Ax ( cs , tot1 , tot2 ) ; \
stbir__simdf_0123to1230 ( tot2 , tot2 ) ; \
stbir__simdf_add ( tot0 , tot0 , cs ) ; \
stbir__simdf_add ( c , c , tot2 ) ; \
stbir__simdf_add ( tot0 , tot0 , c ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 3 ; \
if ( output < output_end ) \
{ \
stbir__simdf_store ( output - 3 , tot0 ) ; \
continue ; \
} \
stbir__simdf_0123to2301 ( tot1 , tot0 ) ; \
stbir__simdf_store2 ( output - 3 , tot0 ) ; \
stbir__simdf_store1 ( output + 2 - 3 , tot1 ) ; \
break ;
# endif
# else
# define stbir__1_coeff_only() \
float tot0 , tot1 , tot2 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ;
# define stbir__2_coeff_only() \
float tot0 , tot1 , tot2 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ; \
c = hc [ 1 ] ; \
tot0 + = decode [ 3 ] * c ; \
tot1 + = decode [ 4 ] * c ; \
tot2 + = decode [ 5 ] * c ;
# define stbir__3_coeff_only() \
float tot0 , tot1 , tot2 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ; \
c = hc [ 1 ] ; \
tot0 + = decode [ 3 ] * c ; \
tot1 + = decode [ 4 ] * c ; \
tot2 + = decode [ 5 ] * c ; \
c = hc [ 2 ] ; \
tot0 + = decode [ 6 ] * c ; \
tot1 + = decode [ 7 ] * c ; \
tot2 + = decode [ 8 ] * c ;
# define stbir__store_output_tiny() \
output [ 0 ] = tot0 ; \
output [ 1 ] = tot1 ; \
output [ 2 ] = tot2 ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 3 ;
# define stbir__4_coeff_start() \
float tota0 , tota1 , tota2 , totb0 , totb1 , totb2 , totc0 , totc1 , totc2 , totd0 , totd1 , totd2 , c ; \
c = hc [ 0 ] ; \
tota0 = decode [ 0 ] * c ; \
tota1 = decode [ 1 ] * c ; \
tota2 = decode [ 2 ] * c ; \
c = hc [ 1 ] ; \
totb0 = decode [ 3 ] * c ; \
totb1 = decode [ 4 ] * c ; \
totb2 = decode [ 5 ] * c ; \
c = hc [ 2 ] ; \
totc0 = decode [ 6 ] * c ; \
totc1 = decode [ 7 ] * c ; \
totc2 = decode [ 8 ] * c ; \
c = hc [ 3 ] ; \
totd0 = decode [ 9 ] * c ; \
totd1 = decode [ 10 ] * c ; \
totd2 = decode [ 11 ] * c ;
# define stbir__4_coeff_continue_from_4( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 3 ] * c ; \
tota1 + = decode [ 1 + ( ofs ) * 3 ] * c ; \
tota2 + = decode [ 2 + ( ofs ) * 3 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
totb0 + = decode [ 3 + ( ofs ) * 3 ] * c ; \
totb1 + = decode [ 4 + ( ofs ) * 3 ] * c ; \
totb2 + = decode [ 5 + ( ofs ) * 3 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
totc0 + = decode [ 6 + ( ofs ) * 3 ] * c ; \
totc1 + = decode [ 7 + ( ofs ) * 3 ] * c ; \
totc2 + = decode [ 8 + ( ofs ) * 3 ] * c ; \
c = hc [ 3 + ( ofs ) ] ; \
totd0 + = decode [ 9 + ( ofs ) * 3 ] * c ; \
totd1 + = decode [ 10 + ( ofs ) * 3 ] * c ; \
totd2 + = decode [ 11 + ( ofs ) * 3 ] * c ;
# define stbir__1_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 3 ] * c ; \
tota1 + = decode [ 1 + ( ofs ) * 3 ] * c ; \
tota2 + = decode [ 2 + ( ofs ) * 3 ] * c ;
# define stbir__2_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 3 ] * c ; \
tota1 + = decode [ 1 + ( ofs ) * 3 ] * c ; \
tota2 + = decode [ 2 + ( ofs ) * 3 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
totb0 + = decode [ 3 + ( ofs ) * 3 ] * c ; \
totb1 + = decode [ 4 + ( ofs ) * 3 ] * c ; \
totb2 + = decode [ 5 + ( ofs ) * 3 ] * c ; \
# define stbir__3_coeff_remnant( ofs ) \
c = hc [ 0 + ( ofs ) ] ; \
tota0 + = decode [ 0 + ( ofs ) * 3 ] * c ; \
tota1 + = decode [ 1 + ( ofs ) * 3 ] * c ; \
tota2 + = decode [ 2 + ( ofs ) * 3 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
totb0 + = decode [ 3 + ( ofs ) * 3 ] * c ; \
totb1 + = decode [ 4 + ( ofs ) * 3 ] * c ; \
totb2 + = decode [ 5 + ( ofs ) * 3 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
totc0 + = decode [ 6 + ( ofs ) * 3 ] * c ; \
totc1 + = decode [ 7 + ( ofs ) * 3 ] * c ; \
totc2 + = decode [ 8 + ( ofs ) * 3 ] * c ;
# define stbir__store_output() \
output [ 0 ] = ( tota0 + totc0 ) + ( totb0 + totd0 ) ; \
output [ 1 ] = ( tota1 + totc1 ) + ( totb1 + totd1 ) ; \
output [ 2 ] = ( tota2 + totc2 ) + ( totb2 + totd2 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 3 ;
# endif
# define STBIR__horizontal_channels 3
# define STB_IMAGE_RESIZE_DO_HORIZONTALS
# include STBIR__HEADER_FILENAME
//=================
// Do 4 channel horizontal routines
# ifdef STBIR_SIMD
# define stbir__1_coeff_only() \
stbir__simdf tot , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1 ( c , hc ) ; \
stbir__simdf_0123to0000 ( c , c ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ;
# define stbir__2_coeff_only() \
stbir__simdf tot , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot , tot , c , decode + 4 ) ;
# define stbir__3_coeff_only() \
stbir__simdf tot , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot , c , decode ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot , tot , c , decode + 4 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot , tot , c , decode + 8 ) ;
# define stbir__store_output_tiny() \
stbir__simdf_store ( output , tot ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 4 ;
# ifdef STBIR_SIMD8
# define stbir__4_coeff_start() \
stbir__simdf8 tot0 , c , cs ; stbir__simdf t ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + 8 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 + 8 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1rep4 ( t , hc + ( ofs ) ) ; \
stbir__simdf8_madd_mem4 ( tot0 , tot0 , t , decode + ( ofs ) * 4 ) ;
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) - 2 ) ; \
stbir__simdf8_0123to22223333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00001111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ; \
stbir__simdf8_0123to2222 ( t , cs ) ; \
stbir__simdf8_madd_mem4 ( tot0 , tot0 , t , decode + ( ofs ) * 4 + 8 ) ;
# define stbir__store_output() \
stbir__simdf8_add4halves ( t , stbir__if_simdf8_cast_to_simdf4 ( tot0 ) , tot0 ) ; \
stbir__simdf_store ( output , t ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 4 ;
# else
# define stbir__4_coeff_start() \
stbir__simdf tot0 , tot1 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 4 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + 8 ) ; \
stbir__simdf_0123to3333 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + 12 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 4 + 4 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 + 8 ) ; \
stbir__simdf_0123to3333 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 4 + 12 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1 ( c , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , c ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ;
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 4 + 4 ) ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 4 + 4 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 4 + 8 ) ;
# define stbir__store_output() \
stbir__simdf_add ( tot0 , tot0 , tot1 ) ; \
stbir__simdf_store ( output , tot0 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 4 ;
# endif
# else
# define stbir__1_coeff_only() \
float p0 , p1 , p2 , p3 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 ] ; \
p0 = decode [ 0 ] * c ; \
p1 = decode [ 1 ] * c ; \
p2 = decode [ 2 ] * c ; \
p3 = decode [ 3 ] * c ;
# define stbir__2_coeff_only() \
float p0 , p1 , p2 , p3 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 ] ; \
p0 = decode [ 0 ] * c ; \
p1 = decode [ 1 ] * c ; \
p2 = decode [ 2 ] * c ; \
p3 = decode [ 3 ] * c ; \
c = hc [ 1 ] ; \
p0 + = decode [ 4 ] * c ; \
p1 + = decode [ 5 ] * c ; \
p2 + = decode [ 6 ] * c ; \
p3 + = decode [ 7 ] * c ;
# define stbir__3_coeff_only() \
float p0 , p1 , p2 , p3 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 ] ; \
p0 = decode [ 0 ] * c ; \
p1 = decode [ 1 ] * c ; \
p2 = decode [ 2 ] * c ; \
p3 = decode [ 3 ] * c ; \
c = hc [ 1 ] ; \
p0 + = decode [ 4 ] * c ; \
p1 + = decode [ 5 ] * c ; \
p2 + = decode [ 6 ] * c ; \
p3 + = decode [ 7 ] * c ; \
c = hc [ 2 ] ; \
p0 + = decode [ 8 ] * c ; \
p1 + = decode [ 9 ] * c ; \
p2 + = decode [ 10 ] * c ; \
p3 + = decode [ 11 ] * c ;
# define stbir__store_output_tiny() \
output [ 0 ] = p0 ; \
output [ 1 ] = p1 ; \
output [ 2 ] = p2 ; \
output [ 3 ] = p3 ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 4 ;
# define stbir__4_coeff_start() \
float x0 , x1 , x2 , x3 , y0 , y1 , y2 , y3 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 ] ; \
x0 = decode [ 0 ] * c ; \
x1 = decode [ 1 ] * c ; \
x2 = decode [ 2 ] * c ; \
x3 = decode [ 3 ] * c ; \
c = hc [ 1 ] ; \
y0 = decode [ 4 ] * c ; \
y1 = decode [ 5 ] * c ; \
y2 = decode [ 6 ] * c ; \
y3 = decode [ 7 ] * c ; \
c = hc [ 2 ] ; \
x0 + = decode [ 8 ] * c ; \
x1 + = decode [ 9 ] * c ; \
x2 + = decode [ 10 ] * c ; \
x3 + = decode [ 11 ] * c ; \
c = hc [ 3 ] ; \
y0 + = decode [ 12 ] * c ; \
y1 + = decode [ 13 ] * c ; \
y2 + = decode [ 14 ] * c ; \
y3 + = decode [ 15 ] * c ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 4 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 4 + ( ofs ) * 4 ] * c ; \
y1 + = decode [ 5 + ( ofs ) * 4 ] * c ; \
y2 + = decode [ 6 + ( ofs ) * 4 ] * c ; \
y3 + = decode [ 7 + ( ofs ) * 4 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
x0 + = decode [ 8 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 9 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 10 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 11 + ( ofs ) * 4 ] * c ; \
c = hc [ 3 + ( ofs ) ] ; \
y0 + = decode [ 12 + ( ofs ) * 4 ] * c ; \
y1 + = decode [ 13 + ( ofs ) * 4 ] * c ; \
y2 + = decode [ 14 + ( ofs ) * 4 ] * c ; \
y3 + = decode [ 15 + ( ofs ) * 4 ] * c ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 4 ] * c ;
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 4 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 4 + ( ofs ) * 4 ] * c ; \
y1 + = decode [ 5 + ( ofs ) * 4 ] * c ; \
y2 + = decode [ 6 + ( ofs ) * 4 ] * c ; \
y3 + = decode [ 7 + ( ofs ) * 4 ] * c ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 4 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 4 + ( ofs ) * 4 ] * c ; \
y1 + = decode [ 5 + ( ofs ) * 4 ] * c ; \
y2 + = decode [ 6 + ( ofs ) * 4 ] * c ; \
y3 + = decode [ 7 + ( ofs ) * 4 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
x0 + = decode [ 8 + ( ofs ) * 4 ] * c ; \
x1 + = decode [ 9 + ( ofs ) * 4 ] * c ; \
x2 + = decode [ 10 + ( ofs ) * 4 ] * c ; \
x3 + = decode [ 11 + ( ofs ) * 4 ] * c ;
# define stbir__store_output() \
output [ 0 ] = x0 + y0 ; \
output [ 1 ] = x1 + y1 ; \
output [ 2 ] = x2 + y2 ; \
output [ 3 ] = x3 + y3 ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 4 ;
# endif
# define STBIR__horizontal_channels 4
# define STB_IMAGE_RESIZE_DO_HORIZONTALS
# include STBIR__HEADER_FILENAME
//=================
// Do 7 channel horizontal routines
# ifdef STBIR_SIMD
# define stbir__1_coeff_only() \
stbir__simdf tot0 , tot1 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1 ( c , hc ) ; \
stbir__simdf_0123to0000 ( c , c ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 3 ) ;
# define stbir__2_coeff_only() \
stbir__simdf tot0 , tot1 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + 10 ) ;
# define stbir__3_coeff_only() \
stbir__simdf tot0 , tot1 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + 10 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + 14 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + 17 ) ;
# define stbir__store_output_tiny() \
stbir__simdf_store ( output + 3 , tot1 ) ; \
stbir__simdf_store ( output , tot0 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 7 ;
# ifdef STBIR_SIMD8
# define stbir__4_coeff_start() \
stbir__simdf8 tot0 , tot1 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc ) ; \
stbir__simdf8_0123to00000000 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf8_0123to11111111 ( c , cs ) ; \
stbir__simdf8_mult_mem ( tot1 , c , decode + 7 ) ; \
stbir__simdf8_0123to22222222 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + 14 ) ; \
stbir__simdf8_0123to33333333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + 21 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00000000 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf8_0123to11111111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 7 ) ; \
stbir__simdf8_0123to22222222 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 + 14 ) ; \
stbir__simdf8_0123to33333333 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 21 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load1b ( c , hc + ( ofs ) ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ;
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load1b ( c , hc + ( ofs ) ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf8_load1b ( c , hc + ( ofs ) + 1 ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 7 ) ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf8_load4b ( cs , hc + ( ofs ) ) ; \
stbir__simdf8_0123to00000000 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf8_0123to11111111 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 7 ) ; \
stbir__simdf8_0123to22222222 ( c , cs ) ; \
stbir__simdf8_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 + 14 ) ;
# define stbir__store_output() \
stbir__simdf8_add ( tot0 , tot0 , tot1 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 7 ; \
if ( output < output_end ) \
{ \
stbir__simdf8_store ( output - 7 , tot0 ) ; \
continue ; \
} \
stbir__simdf_store ( output - 7 + 3 , stbir__simdf_swiz ( stbir__simdf8_gettop4 ( tot0 ) , 0 , 0 , 1 , 2 ) ) ; \
stbir__simdf_store ( output - 7 , stbir__if_simdf8_cast_to_simdf4 ( tot0 ) ) ; \
break ;
# else
# define stbir__4_coeff_start() \
stbir__simdf tot0 , tot1 , tot2 , tot3 , c , cs ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot0 , c , decode ) ; \
stbir__simdf_mult_mem ( tot1 , c , decode + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_mult_mem ( tot2 , c , decode + 7 ) ; \
stbir__simdf_mult_mem ( tot3 , c , decode + 10 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + 14 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + 17 ) ; \
stbir__simdf_0123to3333 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + 21 ) ; \
stbir__simdf_madd_mem ( tot3 , tot3 , c , decode + 24 ) ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + ( ofs ) * 7 + 7 ) ; \
stbir__simdf_madd_mem ( tot3 , tot3 , c , decode + ( ofs ) * 7 + 10 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 + 14 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 17 ) ; \
stbir__simdf_0123to3333 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + ( ofs ) * 7 + 21 ) ; \
stbir__simdf_madd_mem ( tot3 , tot3 , c , decode + ( ofs ) * 7 + 24 ) ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load1 ( c , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , c ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 3 ) ; \
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load2 ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + ( ofs ) * 7 + 7 ) ; \
stbir__simdf_madd_mem ( tot3 , tot3 , c , decode + ( ofs ) * 7 + 10 ) ;
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
stbir__simdf_load ( cs , hc + ( ofs ) ) ; \
stbir__simdf_0123to0000 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 3 ) ; \
stbir__simdf_0123to1111 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot2 , tot2 , c , decode + ( ofs ) * 7 + 7 ) ; \
stbir__simdf_madd_mem ( tot3 , tot3 , c , decode + ( ofs ) * 7 + 10 ) ; \
stbir__simdf_0123to2222 ( c , cs ) ; \
stbir__simdf_madd_mem ( tot0 , tot0 , c , decode + ( ofs ) * 7 + 14 ) ; \
stbir__simdf_madd_mem ( tot1 , tot1 , c , decode + ( ofs ) * 7 + 17 ) ;
# define stbir__store_output() \
stbir__simdf_add ( tot0 , tot0 , tot2 ) ; \
stbir__simdf_add ( tot1 , tot1 , tot3 ) ; \
stbir__simdf_store ( output + 3 , tot1 ) ; \
stbir__simdf_store ( output , tot0 ) ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 7 ;
# endif
# else
# define stbir__1_coeff_only() \
float tot0 , tot1 , tot2 , tot3 , tot4 , tot5 , tot6 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ; \
tot3 = decode [ 3 ] * c ; \
tot4 = decode [ 4 ] * c ; \
tot5 = decode [ 5 ] * c ; \
tot6 = decode [ 6 ] * c ;
# define stbir__2_coeff_only() \
float tot0 , tot1 , tot2 , tot3 , tot4 , tot5 , tot6 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ; \
tot3 = decode [ 3 ] * c ; \
tot4 = decode [ 4 ] * c ; \
tot5 = decode [ 5 ] * c ; \
tot6 = decode [ 6 ] * c ; \
c = hc [ 1 ] ; \
tot0 + = decode [ 7 ] * c ; \
tot1 + = decode [ 8 ] * c ; \
tot2 + = decode [ 9 ] * c ; \
tot3 + = decode [ 10 ] * c ; \
tot4 + = decode [ 11 ] * c ; \
tot5 + = decode [ 12 ] * c ; \
tot6 + = decode [ 13 ] * c ; \
# define stbir__3_coeff_only() \
float tot0 , tot1 , tot2 , tot3 , tot4 , tot5 , tot6 , c ; \
c = hc [ 0 ] ; \
tot0 = decode [ 0 ] * c ; \
tot1 = decode [ 1 ] * c ; \
tot2 = decode [ 2 ] * c ; \
tot3 = decode [ 3 ] * c ; \
tot4 = decode [ 4 ] * c ; \
tot5 = decode [ 5 ] * c ; \
tot6 = decode [ 6 ] * c ; \
c = hc [ 1 ] ; \
tot0 + = decode [ 7 ] * c ; \
tot1 + = decode [ 8 ] * c ; \
tot2 + = decode [ 9 ] * c ; \
tot3 + = decode [ 10 ] * c ; \
tot4 + = decode [ 11 ] * c ; \
tot5 + = decode [ 12 ] * c ; \
tot6 + = decode [ 13 ] * c ; \
c = hc [ 2 ] ; \
tot0 + = decode [ 14 ] * c ; \
tot1 + = decode [ 15 ] * c ; \
tot2 + = decode [ 16 ] * c ; \
tot3 + = decode [ 17 ] * c ; \
tot4 + = decode [ 18 ] * c ; \
tot5 + = decode [ 19 ] * c ; \
tot6 + = decode [ 20 ] * c ; \
# define stbir__store_output_tiny() \
output [ 0 ] = tot0 ; \
output [ 1 ] = tot1 ; \
output [ 2 ] = tot2 ; \
output [ 3 ] = tot3 ; \
output [ 4 ] = tot4 ; \
output [ 5 ] = tot5 ; \
output [ 6 ] = tot6 ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 7 ;
# define stbir__4_coeff_start() \
float x0 , x1 , x2 , x3 , x4 , x5 , x6 , y0 , y1 , y2 , y3 , y4 , y5 , y6 , c ; \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 ] ; \
x0 = decode [ 0 ] * c ; \
x1 = decode [ 1 ] * c ; \
x2 = decode [ 2 ] * c ; \
x3 = decode [ 3 ] * c ; \
x4 = decode [ 4 ] * c ; \
x5 = decode [ 5 ] * c ; \
x6 = decode [ 6 ] * c ; \
c = hc [ 1 ] ; \
y0 = decode [ 7 ] * c ; \
y1 = decode [ 8 ] * c ; \
y2 = decode [ 9 ] * c ; \
y3 = decode [ 10 ] * c ; \
y4 = decode [ 11 ] * c ; \
y5 = decode [ 12 ] * c ; \
y6 = decode [ 13 ] * c ; \
c = hc [ 2 ] ; \
x0 + = decode [ 14 ] * c ; \
x1 + = decode [ 15 ] * c ; \
x2 + = decode [ 16 ] * c ; \
x3 + = decode [ 17 ] * c ; \
x4 + = decode [ 18 ] * c ; \
x5 + = decode [ 19 ] * c ; \
x6 + = decode [ 20 ] * c ; \
c = hc [ 3 ] ; \
y0 + = decode [ 21 ] * c ; \
y1 + = decode [ 22 ] * c ; \
y2 + = decode [ 23 ] * c ; \
y3 + = decode [ 24 ] * c ; \
y4 + = decode [ 25 ] * c ; \
y5 + = decode [ 26 ] * c ; \
y6 + = decode [ 27 ] * c ;
# define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 4 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 5 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 6 + ( ofs ) * 7 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 7 + ( ofs ) * 7 ] * c ; \
y1 + = decode [ 8 + ( ofs ) * 7 ] * c ; \
y2 + = decode [ 9 + ( ofs ) * 7 ] * c ; \
y3 + = decode [ 10 + ( ofs ) * 7 ] * c ; \
y4 + = decode [ 11 + ( ofs ) * 7 ] * c ; \
y5 + = decode [ 12 + ( ofs ) * 7 ] * c ; \
y6 + = decode [ 13 + ( ofs ) * 7 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
x0 + = decode [ 14 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 15 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 16 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 17 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 18 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 19 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 20 + ( ofs ) * 7 ] * c ; \
c = hc [ 3 + ( ofs ) ] ; \
y0 + = decode [ 21 + ( ofs ) * 7 ] * c ; \
y1 + = decode [ 22 + ( ofs ) * 7 ] * c ; \
y2 + = decode [ 23 + ( ofs ) * 7 ] * c ; \
y3 + = decode [ 24 + ( ofs ) * 7 ] * c ; \
y4 + = decode [ 25 + ( ofs ) * 7 ] * c ; \
y5 + = decode [ 26 + ( ofs ) * 7 ] * c ; \
y6 + = decode [ 27 + ( ofs ) * 7 ] * c ;
# define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 4 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 5 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 6 + ( ofs ) * 7 ] * c ; \
# define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 4 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 5 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 6 + ( ofs ) * 7 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 7 + ( ofs ) * 7 ] * c ; \
y1 + = decode [ 8 + ( ofs ) * 7 ] * c ; \
y2 + = decode [ 9 + ( ofs ) * 7 ] * c ; \
y3 + = decode [ 10 + ( ofs ) * 7 ] * c ; \
y4 + = decode [ 11 + ( ofs ) * 7 ] * c ; \
y5 + = decode [ 12 + ( ofs ) * 7 ] * c ; \
y6 + = decode [ 13 + ( ofs ) * 7 ] * c ; \
# define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL ( decode ) ; \
c = hc [ 0 + ( ofs ) ] ; \
x0 + = decode [ 0 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 1 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 2 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 3 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 4 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 5 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 6 + ( ofs ) * 7 ] * c ; \
c = hc [ 1 + ( ofs ) ] ; \
y0 + = decode [ 7 + ( ofs ) * 7 ] * c ; \
y1 + = decode [ 8 + ( ofs ) * 7 ] * c ; \
y2 + = decode [ 9 + ( ofs ) * 7 ] * c ; \
y3 + = decode [ 10 + ( ofs ) * 7 ] * c ; \
y4 + = decode [ 11 + ( ofs ) * 7 ] * c ; \
y5 + = decode [ 12 + ( ofs ) * 7 ] * c ; \
y6 + = decode [ 13 + ( ofs ) * 7 ] * c ; \
c = hc [ 2 + ( ofs ) ] ; \
x0 + = decode [ 14 + ( ofs ) * 7 ] * c ; \
x1 + = decode [ 15 + ( ofs ) * 7 ] * c ; \
x2 + = decode [ 16 + ( ofs ) * 7 ] * c ; \
x3 + = decode [ 17 + ( ofs ) * 7 ] * c ; \
x4 + = decode [ 18 + ( ofs ) * 7 ] * c ; \
x5 + = decode [ 19 + ( ofs ) * 7 ] * c ; \
x6 + = decode [ 20 + ( ofs ) * 7 ] * c ; \
# define stbir__store_output() \
output [ 0 ] = x0 + y0 ; \
output [ 1 ] = x1 + y1 ; \
output [ 2 ] = x2 + y2 ; \
output [ 3 ] = x3 + y3 ; \
output [ 4 ] = x4 + y4 ; \
output [ 5 ] = x5 + y5 ; \
output [ 6 ] = x6 + y6 ; \
horizontal_coefficients + = coefficient_width ; \
+ + horizontal_contributors ; \
output + = 7 ;
# endif
# define STBIR__horizontal_channels 7
# define STB_IMAGE_RESIZE_DO_HORIZONTALS
# include STBIR__HEADER_FILENAME
// include all of the vertical resamplers (both scatter and gather versions)
# define STBIR__vertical_channels 1
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 1
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 2
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 2
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 3
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 3
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 4
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 4
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 5
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 5
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 6
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 6
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 7
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 7
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 8
# define STB_IMAGE_RESIZE_DO_VERTICALS
# include STBIR__HEADER_FILENAME
# define STBIR__vertical_channels 8
# define STB_IMAGE_RESIZE_DO_VERTICALS
# define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# include STBIR__HEADER_FILENAME
typedef void STBIR_VERTICAL_GATHERFUNC ( float * output , float const * coeffs , float const * * inputs , float const * input0_end ) ;
static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers [ 8 ] =
{
stbir__vertical_gather_with_1_coeffs , stbir__vertical_gather_with_2_coeffs , stbir__vertical_gather_with_3_coeffs , stbir__vertical_gather_with_4_coeffs , stbir__vertical_gather_with_5_coeffs , stbir__vertical_gather_with_6_coeffs , stbir__vertical_gather_with_7_coeffs , stbir__vertical_gather_with_8_coeffs
} ;
static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers_continues [ 8 ] =
{
stbir__vertical_gather_with_1_coeffs_cont , stbir__vertical_gather_with_2_coeffs_cont , stbir__vertical_gather_with_3_coeffs_cont , stbir__vertical_gather_with_4_coeffs_cont , stbir__vertical_gather_with_5_coeffs_cont , stbir__vertical_gather_with_6_coeffs_cont , stbir__vertical_gather_with_7_coeffs_cont , stbir__vertical_gather_with_8_coeffs_cont
} ;
typedef void STBIR_VERTICAL_SCATTERFUNC ( float * * outputs , float const * coeffs , float const * input , float const * input_end ) ;
static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_sets [ 8 ] =
{
stbir__vertical_scatter_with_1_coeffs , stbir__vertical_scatter_with_2_coeffs , stbir__vertical_scatter_with_3_coeffs , stbir__vertical_scatter_with_4_coeffs , stbir__vertical_scatter_with_5_coeffs , stbir__vertical_scatter_with_6_coeffs , stbir__vertical_scatter_with_7_coeffs , stbir__vertical_scatter_with_8_coeffs
} ;
static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_blends [ 8 ] =
{
stbir__vertical_scatter_with_1_coeffs_cont , stbir__vertical_scatter_with_2_coeffs_cont , stbir__vertical_scatter_with_3_coeffs_cont , stbir__vertical_scatter_with_4_coeffs_cont , stbir__vertical_scatter_with_5_coeffs_cont , stbir__vertical_scatter_with_6_coeffs_cont , stbir__vertical_scatter_with_7_coeffs_cont , stbir__vertical_scatter_with_8_coeffs_cont
} ;
static void stbir__encode_scanline ( stbir__info const * stbir_info , void * output_buffer_data , float * encode_buffer , int row STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
{
int num_pixels = stbir_info - > horizontal . scale_info . output_sub_size ;
int channels = stbir_info - > channels ;
int width_times_channels = num_pixels * channels ;
void * output_buffer ;
// un-alpha weight if we need to
if ( stbir_info - > alpha_unweight )
{
STBIR_PROFILE_START ( unalpha ) ;
stbir_info - > alpha_unweight ( encode_buffer , width_times_channels ) ;
STBIR_PROFILE_END ( unalpha ) ;
}
// write directly into output by default
output_buffer = output_buffer_data ;
// if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback)
if ( stbir_info - > out_pixels_cb )
output_buffer = encode_buffer ;
STBIR_PROFILE_START ( encode ) ;
// convert into the output buffer
stbir_info - > encode_pixels ( output_buffer , width_times_channels , encode_buffer ) ;
STBIR_PROFILE_END ( encode ) ;
// if we have an output callback, call it to send the data
if ( stbir_info - > out_pixels_cb )
stbir_info - > out_pixels_cb ( output_buffer_data , num_pixels , row , stbir_info - > user_data ) ;
}
// Get the ring buffer pointer for an index
static float * stbir__get_ring_buffer_entry ( stbir__info const * stbir_info , stbir__per_split_info const * split_info , int index )
{
STBIR_ASSERT ( index < stbir_info - > ring_buffer_num_entries ) ;
# ifdef STBIR__SEPARATE_ALLOCATIONS
return split_info - > ring_buffers [ index ] ;
# else
return ( float * ) ( ( ( char * ) split_info - > ring_buffer ) + ( index * stbir_info - > ring_buffer_length_bytes ) ) ;
# endif
}
// Get the specified scan line from the ring buffer
static float * stbir__get_ring_buffer_scanline ( stbir__info const * stbir_info , stbir__per_split_info const * split_info , int get_scanline )
{
int ring_buffer_index = ( split_info - > ring_buffer_begin_index + ( get_scanline - split_info - > ring_buffer_first_scanline ) ) % stbir_info - > ring_buffer_num_entries ;
return stbir__get_ring_buffer_entry ( stbir_info , split_info , ring_buffer_index ) ;
}
static void stbir__resample_horizontal_gather ( stbir__info const * stbir_info , float * output_buffer , float const * input_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
{
float const * decode_buffer = input_buffer - ( stbir_info - > scanline_extents . conservative . n0 * stbir_info - > effective_channels ) ;
STBIR_PROFILE_START ( horizontal ) ;
if ( ( stbir_info - > horizontal . filter_enum = = STBIR_FILTER_POINT_SAMPLE ) & & ( stbir_info - > horizontal . scale_info . scale = = 1.0f ) )
STBIR_MEMCPY ( output_buffer , input_buffer , stbir_info - > horizontal . scale_info . output_sub_size * sizeof ( float ) * stbir_info - > effective_channels ) ;
else
stbir_info - > horizontal_gather_channels ( output_buffer , stbir_info - > horizontal . scale_info . output_sub_size , decode_buffer , stbir_info - > horizontal . contributors , stbir_info - > horizontal . coefficients , stbir_info - > horizontal . coefficient_width ) ;
STBIR_PROFILE_END ( horizontal ) ;
}
static void stbir__resample_vertical_gather ( stbir__info const * stbir_info , stbir__per_split_info * split_info , int n , int contrib_n0 , int contrib_n1 , float const * vertical_coefficients )
{
float * encode_buffer = split_info - > vertical_buffer ;
float * decode_buffer = split_info - > decode_buffer ;
int vertical_first = stbir_info - > vertical_first ;
int width = ( vertical_first ) ? ( stbir_info - > scanline_extents . conservative . n1 - stbir_info - > scanline_extents . conservative . n0 + 1 ) : stbir_info - > horizontal . scale_info . output_sub_size ;
int width_times_channels = stbir_info - > effective_channels * width ;
STBIR_ASSERT ( stbir_info - > vertical . is_gather ) ;
// loop over the contributing scanlines and scale into the buffer
STBIR_PROFILE_START ( vertical ) ;
{
int k = 0 , total = contrib_n1 - contrib_n0 + 1 ;
STBIR_ASSERT ( total > 0 ) ;
do {
float const * inputs [ 8 ] ;
int i , cnt = total ; if ( cnt > 8 ) cnt = 8 ;
for ( i = 0 ; i < cnt ; i + + )
inputs [ i ] = stbir__get_ring_buffer_scanline ( stbir_info , split_info , k + i + contrib_n0 ) ;
// call the N scanlines at a time function (up to 8 scanlines of blending at once)
( ( k = = 0 ) ? stbir__vertical_gathers : stbir__vertical_gathers_continues ) [ cnt - 1 ] ( ( vertical_first ) ? decode_buffer : encode_buffer , vertical_coefficients + k , inputs , inputs [ 0 ] + width_times_channels ) ;
k + = cnt ;
total - = cnt ;
} while ( total ) ;
}
STBIR_PROFILE_END ( vertical ) ;
if ( vertical_first )
{
// Now resample the gathered vertical data in the horizontal axis into the encode buffer
stbir__resample_horizontal_gather ( stbir_info , encode_buffer , decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
}
stbir__encode_scanline ( stbir_info , ( ( char * ) stbir_info - > output_data ) + ( ( ptrdiff_t ) n * ( ptrdiff_t ) stbir_info - > output_stride_bytes ) ,
encode_buffer , n STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
}
static void stbir__decode_and_resample_for_vertical_gather_loop ( stbir__info const * stbir_info , stbir__per_split_info * split_info , int n )
{
int ring_buffer_index ;
float * ring_buffer ;
// Decode the nth scanline from the source image into the decode buffer.
stbir__decode_scanline ( stbir_info , n , split_info - > decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// update new end scanline
split_info - > ring_buffer_last_scanline = n ;
// get ring buffer
ring_buffer_index = ( split_info - > ring_buffer_begin_index + ( split_info - > ring_buffer_last_scanline - split_info - > ring_buffer_first_scanline ) ) % stbir_info - > ring_buffer_num_entries ;
ring_buffer = stbir__get_ring_buffer_entry ( stbir_info , split_info , ring_buffer_index ) ;
// Now resample it into the ring buffer.
stbir__resample_horizontal_gather ( stbir_info , ring_buffer , split_info - > decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
}
static void stbir__vertical_gather_loop ( stbir__info const * stbir_info , stbir__per_split_info * split_info , int split_count )
{
int y , start_output_y , end_output_y ;
stbir__contributors * vertical_contributors = stbir_info - > vertical . contributors ;
float const * vertical_coefficients = stbir_info - > vertical . coefficients ;
STBIR_ASSERT ( stbir_info - > vertical . is_gather ) ;
start_output_y = split_info - > start_output_y ;
end_output_y = split_info [ split_count - 1 ] . end_output_y ;
vertical_contributors + = start_output_y ;
vertical_coefficients + = start_output_y * stbir_info - > vertical . coefficient_width ;
// initialize the ring buffer for gathering
split_info - > ring_buffer_begin_index = 0 ;
split_info - > ring_buffer_first_scanline = stbir_info - > vertical . extent_info . lowest ;
split_info - > ring_buffer_last_scanline = split_info - > ring_buffer_first_scanline - 1 ; // means "empty"
for ( y = start_output_y ; y < end_output_y ; y + + )
{
int in_first_scanline , in_last_scanline ;
in_first_scanline = vertical_contributors - > n0 ;
in_last_scanline = vertical_contributors - > n1 ;
// make sure the indexing hasn't broken
STBIR_ASSERT ( in_first_scanline > = split_info - > ring_buffer_first_scanline ) ;
// Load in new scanlines
while ( in_last_scanline > split_info - > ring_buffer_last_scanline )
{
STBIR_ASSERT ( ( split_info - > ring_buffer_last_scanline - split_info - > ring_buffer_first_scanline + 1 ) < = stbir_info - > ring_buffer_num_entries ) ;
// make sure there was room in the ring buffer when we add new scanlines
if ( ( split_info - > ring_buffer_last_scanline - split_info - > ring_buffer_first_scanline + 1 ) = = stbir_info - > ring_buffer_num_entries )
{
split_info - > ring_buffer_first_scanline + + ;
split_info - > ring_buffer_begin_index + + ;
}
if ( stbir_info - > vertical_first )
{
float * ring_buffer = stbir__get_ring_buffer_scanline ( stbir_info , split_info , + + split_info - > ring_buffer_last_scanline ) ;
// Decode the nth scanline from the source image into the decode buffer.
stbir__decode_scanline ( stbir_info , split_info - > ring_buffer_last_scanline , ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
}
else
{
stbir__decode_and_resample_for_vertical_gather_loop ( stbir_info , split_info , split_info - > ring_buffer_last_scanline + 1 ) ;
}
}
// Now all buffers should be ready to write a row of vertical sampling, so do it.
stbir__resample_vertical_gather ( stbir_info , split_info , y , in_first_scanline , in_last_scanline , vertical_coefficients ) ;
+ + vertical_contributors ;
vertical_coefficients + = stbir_info - > vertical . coefficient_width ;
}
}
# define STBIR__FLOAT_EMPTY_MARKER 3.0e+38F
# define STBIR__FLOAT_BUFFER_IS_EMPTY(ptr) ((ptr)[0]==STBIR__FLOAT_EMPTY_MARKER)
static void stbir__encode_first_scanline_from_scatter ( stbir__info const * stbir_info , stbir__per_split_info * split_info )
{
// evict a scanline out into the output buffer
float * ring_buffer_entry = stbir__get_ring_buffer_entry ( stbir_info , split_info , split_info - > ring_buffer_begin_index ) ;
// dump the scanline out
stbir__encode_scanline ( stbir_info , ( ( char * ) stbir_info - > output_data ) + ( ( ptrdiff_t ) split_info - > ring_buffer_first_scanline * ( ptrdiff_t ) stbir_info - > output_stride_bytes ) , ring_buffer_entry , split_info - > ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// mark it as empty
ring_buffer_entry [ 0 ] = STBIR__FLOAT_EMPTY_MARKER ;
// advance the first scanline
split_info - > ring_buffer_first_scanline + + ;
if ( + + split_info - > ring_buffer_begin_index = = stbir_info - > ring_buffer_num_entries )
split_info - > ring_buffer_begin_index = 0 ;
}
static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter ( stbir__info const * stbir_info , stbir__per_split_info * split_info )
{
// evict a scanline out into the output buffer
float * ring_buffer_entry = stbir__get_ring_buffer_entry ( stbir_info , split_info , split_info - > ring_buffer_begin_index ) ;
// Now resample it into the buffer.
stbir__resample_horizontal_gather ( stbir_info , split_info - > vertical_buffer , ring_buffer_entry STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// dump the scanline out
stbir__encode_scanline ( stbir_info , ( ( char * ) stbir_info - > output_data ) + ( ( ptrdiff_t ) split_info - > ring_buffer_first_scanline * ( ptrdiff_t ) stbir_info - > output_stride_bytes ) , split_info - > vertical_buffer , split_info - > ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// mark it as empty
ring_buffer_entry [ 0 ] = STBIR__FLOAT_EMPTY_MARKER ;
// advance the first scanline
split_info - > ring_buffer_first_scanline + + ;
if ( + + split_info - > ring_buffer_begin_index = = stbir_info - > ring_buffer_num_entries )
split_info - > ring_buffer_begin_index = 0 ;
}
static void stbir__resample_vertical_scatter ( stbir__info const * stbir_info , stbir__per_split_info * split_info , int n0 , int n1 , float const * vertical_coefficients , float const * vertical_buffer , float const * vertical_buffer_end )
{
STBIR_ASSERT ( ! stbir_info - > vertical . is_gather ) ;
STBIR_PROFILE_START ( vertical ) ;
{
int k = 0 , total = n1 - n0 + 1 ;
STBIR_ASSERT ( total > 0 ) ;
do {
float * outputs [ 8 ] ;
int i , n = total ; if ( n > 8 ) n = 8 ;
for ( i = 0 ; i < n ; i + + )
{
outputs [ i ] = stbir__get_ring_buffer_scanline ( stbir_info , split_info , k + i + n0 ) ;
if ( ( i ) & & ( STBIR__FLOAT_BUFFER_IS_EMPTY ( outputs [ i ] ) ! = STBIR__FLOAT_BUFFER_IS_EMPTY ( outputs [ 0 ] ) ) ) // make sure runs are of the same type
{
n = i ;
break ;
}
}
// call the scatter to N scanlines at a time function (up to 8 scanlines of scattering at once)
( ( STBIR__FLOAT_BUFFER_IS_EMPTY ( outputs [ 0 ] ) ) ? stbir__vertical_scatter_sets : stbir__vertical_scatter_blends ) [ n - 1 ] ( outputs , vertical_coefficients + k , vertical_buffer , vertical_buffer_end ) ;
k + = n ;
total - = n ;
} while ( total ) ;
}
STBIR_PROFILE_END ( vertical ) ;
}
typedef void stbir__handle_scanline_for_scatter_func ( stbir__info const * stbir_info , stbir__per_split_info * split_info ) ;
static void stbir__vertical_scatter_loop ( stbir__info const * stbir_info , stbir__per_split_info * split_info , int split_count )
{
int y , start_output_y , end_output_y , start_input_y , end_input_y ;
stbir__contributors * vertical_contributors = stbir_info - > vertical . contributors ;
float const * vertical_coefficients = stbir_info - > vertical . coefficients ;
stbir__handle_scanline_for_scatter_func * handle_scanline_for_scatter ;
void * scanline_scatter_buffer ;
void * scanline_scatter_buffer_end ;
int on_first_input_y , last_input_y ;
STBIR_ASSERT ( ! stbir_info - > vertical . is_gather ) ;
start_output_y = split_info - > start_output_y ;
end_output_y = split_info [ split_count - 1 ] . end_output_y ; // may do multiple split counts
start_input_y = split_info - > start_input_y ;
end_input_y = split_info [ split_count - 1 ] . end_input_y ;
// adjust for starting offset start_input_y
y = start_input_y + stbir_info - > vertical . filter_pixel_margin ;
vertical_contributors + = y ;
vertical_coefficients + = stbir_info - > vertical . coefficient_width * y ;
if ( stbir_info - > vertical_first )
{
handle_scanline_for_scatter = stbir__horizontal_resample_and_encode_first_scanline_from_scatter ;
scanline_scatter_buffer = split_info - > decode_buffer ;
scanline_scatter_buffer_end = ( ( char * ) scanline_scatter_buffer ) + sizeof ( float ) * stbir_info - > effective_channels * ( stbir_info - > scanline_extents . conservative . n1 - stbir_info - > scanline_extents . conservative . n0 + 1 ) ;
}
else
{
handle_scanline_for_scatter = stbir__encode_first_scanline_from_scatter ;
scanline_scatter_buffer = split_info - > vertical_buffer ;
scanline_scatter_buffer_end = ( ( char * ) scanline_scatter_buffer ) + sizeof ( float ) * stbir_info - > effective_channels * stbir_info - > horizontal . scale_info . output_sub_size ;
}
// initialize the ring buffer for scattering
split_info - > ring_buffer_first_scanline = start_output_y ;
split_info - > ring_buffer_last_scanline = - 1 ;
split_info - > ring_buffer_begin_index = - 1 ;
// mark all the buffers as empty to start
for ( y = 0 ; y < stbir_info - > ring_buffer_num_entries ; y + + )
stbir__get_ring_buffer_entry ( stbir_info , split_info , y ) [ 0 ] = STBIR__FLOAT_EMPTY_MARKER ; // only used on scatter
// do the loop in input space
on_first_input_y = 1 ; last_input_y = start_input_y ;
for ( y = start_input_y ; y < end_input_y ; y + + )
{
int out_first_scanline , out_last_scanline ;
out_first_scanline = vertical_contributors - > n0 ;
out_last_scanline = vertical_contributors - > n1 ;
STBIR_ASSERT ( out_last_scanline - out_first_scanline + 1 < = stbir_info - > ring_buffer_num_entries ) ;
if ( ( out_last_scanline > = out_first_scanline ) & & ( ( ( out_first_scanline > = start_output_y ) & & ( out_first_scanline < end_output_y ) ) | | ( ( out_last_scanline > = start_output_y ) & & ( out_last_scanline < end_output_y ) ) ) )
{
float const * vc = vertical_coefficients ;
// keep track of the range actually seen for the next resize
last_input_y = y ;
if ( ( on_first_input_y ) & & ( y > start_input_y ) )
split_info - > start_input_y = y ;
on_first_input_y = 0 ;
// clip the region
if ( out_first_scanline < start_output_y )
{
vc + = start_output_y - out_first_scanline ;
out_first_scanline = start_output_y ;
}
if ( out_last_scanline > = end_output_y )
out_last_scanline = end_output_y - 1 ;
// if very first scanline, init the index
if ( split_info - > ring_buffer_begin_index < 0 )
split_info - > ring_buffer_begin_index = out_first_scanline - start_output_y ;
STBIR_ASSERT ( split_info - > ring_buffer_begin_index < = out_first_scanline ) ;
// Decode the nth scanline from the source image into the decode buffer.
stbir__decode_scanline ( stbir_info , y , split_info - > decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// When horizontal first, we resample horizontally into the vertical buffer before we scatter it out
if ( ! stbir_info - > vertical_first )
stbir__resample_horizontal_gather ( stbir_info , split_info - > vertical_buffer , split_info - > decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ) ;
// Now it's sitting in the buffer ready to be distributed into the ring buffers.
// evict from the ringbuffer, if we need are full
if ( ( ( split_info - > ring_buffer_last_scanline - split_info - > ring_buffer_first_scanline + 1 ) = = stbir_info - > ring_buffer_num_entries ) & &
( out_last_scanline > split_info - > ring_buffer_last_scanline ) )
handle_scanline_for_scatter ( stbir_info , split_info ) ;
// Now the horizontal buffer is ready to write to all ring buffer rows, so do it.
stbir__resample_vertical_scatter ( stbir_info , split_info , out_first_scanline , out_last_scanline , vc , ( float * ) scanline_scatter_buffer , ( float * ) scanline_scatter_buffer_end ) ;
// update the end of the buffer
if ( out_last_scanline > split_info - > ring_buffer_last_scanline )
split_info - > ring_buffer_last_scanline = out_last_scanline ;
}
+ + vertical_contributors ;
vertical_coefficients + = stbir_info - > vertical . coefficient_width ;
}
// now evict the scanlines that are left over in the ring buffer
while ( split_info - > ring_buffer_first_scanline < end_output_y )
handle_scanline_for_scatter ( stbir_info , split_info ) ;
// update the end_input_y if we do multiple resizes with the same data
+ + last_input_y ;
for ( y = 0 ; y < split_count ; y + + )
if ( split_info [ y ] . end_input_y > last_input_y )
split_info [ y ] . end_input_y = last_input_y ;
}
static stbir__kernel_callback * stbir__builtin_kernels [ ] = { 0 , stbir__filter_trapezoid , stbir__filter_triangle , stbir__filter_cubic , stbir__filter_catmullrom , stbir__filter_mitchell , stbir__filter_point } ;
static stbir__support_callback * stbir__builtin_supports [ ] = { 0 , stbir__support_trapezoid , stbir__support_one , stbir__support_two , stbir__support_two , stbir__support_two , stbir__support_zeropoint5 } ;
static void stbir__set_sampler ( stbir__sampler * samp , stbir_filter filter , stbir__kernel_callback * kernel , stbir__support_callback * support , stbir_edge edge , stbir__scale_info * scale_info , int always_gather , void * user_data )
{
// set filter
if ( filter = = 0 )
{
filter = STBIR_DEFAULT_FILTER_DOWNSAMPLE ; // default to downsample
if ( scale_info - > scale > = ( 1.0f - stbir__small_float ) )
{
if ( ( scale_info - > scale < = ( 1.0f + stbir__small_float ) ) & & ( STBIR_CEILF ( scale_info - > pixel_shift ) = = scale_info - > pixel_shift ) )
filter = STBIR_FILTER_POINT_SAMPLE ;
else
filter = STBIR_DEFAULT_FILTER_UPSAMPLE ;
}
}
samp - > filter_enum = filter ;
STBIR_ASSERT ( samp - > filter_enum ! = 0 ) ;
STBIR_ASSERT ( ( unsigned ) samp - > filter_enum < STBIR_FILTER_OTHER ) ;
samp - > filter_kernel = stbir__builtin_kernels [ filter ] ;
samp - > filter_support = stbir__builtin_supports [ filter ] ;
if ( kernel & & support )
{
samp - > filter_kernel = kernel ;
samp - > filter_support = support ;
samp - > filter_enum = STBIR_FILTER_OTHER ;
}
samp - > edge = edge ;
samp - > filter_pixel_width = stbir__get_filter_pixel_width ( samp - > filter_support , scale_info - > scale , user_data ) ;
// Gather is always better, but in extreme downsamples, you have to most or all of the data in memory
// For horizontal, we always have all the pixels, so we always use gather here (always_gather==1).
// For vertical, we use gather if scaling up (which means we will have samp->filter_pixel_width
// scanlines in memory at once).
samp - > is_gather = 0 ;
if ( scale_info - > scale > = ( 1.0f - stbir__small_float ) )
samp - > is_gather = 1 ;
else if ( ( always_gather ) | | ( samp - > filter_pixel_width < = STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ) )
samp - > is_gather = 2 ;
// pre calculate stuff based on the above
samp - > coefficient_width = stbir__get_coefficient_width ( samp , samp - > is_gather , user_data ) ;
if ( edge = = STBIR_EDGE_WRAP )
if ( samp - > filter_pixel_width > ( scale_info - > input_full_size * 2 ) ) // this can only happen when shrinking to a single pixel
samp - > filter_pixel_width = scale_info - > input_full_size * 2 ;
// This is how much to expand buffers to account for filters seeking outside
// the image boundaries.
samp - > filter_pixel_margin = samp - > filter_pixel_width / 2 ;
samp - > num_contributors = stbir__get_contributors ( samp , samp - > is_gather ) ;
samp - > contributors_size = samp - > num_contributors * sizeof ( stbir__contributors ) ;
samp - > coefficients_size = samp - > num_contributors * samp - > coefficient_width * sizeof ( float ) + sizeof ( float ) ; // extra sizeof(float) is padding
samp - > gather_prescatter_contributors = 0 ;
samp - > gather_prescatter_coefficients = 0 ;
if ( samp - > is_gather = = 0 )
{
samp - > gather_prescatter_coefficient_width = samp - > filter_pixel_width ;
samp - > gather_prescatter_num_contributors = stbir__get_contributors ( samp , 2 ) ;
samp - > gather_prescatter_contributors_size = samp - > gather_prescatter_num_contributors * sizeof ( stbir__contributors ) ;
samp - > gather_prescatter_coefficients_size = samp - > gather_prescatter_num_contributors * samp - > gather_prescatter_coefficient_width * sizeof ( float ) ;
}
}
static void stbir__get_conservative_extents ( stbir__sampler * samp , stbir__contributors * range , void * user_data )
{
float scale = samp - > scale_info . scale ;
float out_shift = samp - > scale_info . pixel_shift ;
stbir__support_callback * support = samp - > filter_support ;
int input_full_size = samp - > scale_info . input_full_size ;
stbir_edge edge = samp - > edge ;
float inv_scale = samp - > scale_info . inv_scale ;
STBIR_ASSERT ( samp - > is_gather ! = 0 ) ;
if ( samp - > is_gather = = 1 )
{
int in_first_pixel , in_last_pixel ;
float out_filter_radius = support ( inv_scale , user_data ) * scale ;
stbir__calculate_in_pixel_range ( & in_first_pixel , & in_last_pixel , 0.5 , out_filter_radius , inv_scale , out_shift , input_full_size , edge ) ;
range - > n0 = in_first_pixel ;
stbir__calculate_in_pixel_range ( & in_first_pixel , & in_last_pixel , ( ( float ) ( samp - > scale_info . output_sub_size - 1 ) ) + 0.5f , out_filter_radius , inv_scale , out_shift , input_full_size , edge ) ;
range - > n1 = in_last_pixel ;
}
else if ( samp - > is_gather = = 2 ) // downsample gather, refine
{
float in_pixels_radius = support ( scale , user_data ) * inv_scale ;
int filter_pixel_margin = samp - > filter_pixel_margin ;
int output_sub_size = samp - > scale_info . output_sub_size ;
int input_end ;
int n ;
int in_first_pixel , in_last_pixel ;
// get a conservative area of the input range
stbir__calculate_in_pixel_range ( & in_first_pixel , & in_last_pixel , 0 , 0 , inv_scale , out_shift , input_full_size , edge ) ;
range - > n0 = in_first_pixel ;
stbir__calculate_in_pixel_range ( & in_first_pixel , & in_last_pixel , ( float ) output_sub_size , 0 , inv_scale , out_shift , input_full_size , edge ) ;
range - > n1 = in_last_pixel ;
// now go through the margin to the start of area to find bottom
n = range - > n0 + 1 ;
input_end = - filter_pixel_margin ;
while ( n > = input_end )
{
int out_first_pixel , out_last_pixel ;
stbir__calculate_out_pixel_range ( & out_first_pixel , & out_last_pixel , ( ( float ) n ) + 0.5f , in_pixels_radius , scale , out_shift , output_sub_size ) ;
if ( out_first_pixel > out_last_pixel )
break ;
if ( ( out_first_pixel < output_sub_size ) | | ( out_last_pixel > = 0 ) )
range - > n0 = n ;
- - n ;
}
// now go through the end of the area through the margin to find top
n = range - > n1 - 1 ;
input_end = n + 1 + filter_pixel_margin ;
while ( n < = input_end )
{
int out_first_pixel , out_last_pixel ;
stbir__calculate_out_pixel_range ( & out_first_pixel , & out_last_pixel , ( ( float ) n ) + 0.5f , in_pixels_radius , scale , out_shift , output_sub_size ) ;
if ( out_first_pixel > out_last_pixel )
break ;
if ( ( out_first_pixel < output_sub_size ) | | ( out_last_pixel > = 0 ) )
range - > n1 = n ;
+ + n ;
}
}
if ( samp - > edge = = STBIR_EDGE_WRAP )
{
// if we are wrapping, and we are very close to the image size (so the edges might merge), just use the scanline up to the edge
if ( ( range - > n0 > 0 ) & & ( range - > n1 > = input_full_size ) )
{
int marg = range - > n1 - input_full_size + 1 ;
if ( ( marg + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) > = range - > n0 )
range - > n0 = 0 ;
}
if ( ( range - > n0 < 0 ) & & ( range - > n1 < ( input_full_size - 1 ) ) )
{
int marg = - range - > n0 ;
if ( ( input_full_size - marg - STBIR__MERGE_RUNS_PIXEL_THRESHOLD - 1 ) < = range - > n1 )
range - > n1 = input_full_size - 1 ;
}
}
else
{
// for non-edge-wrap modes, we never read over the edge, so clamp
if ( range - > n0 < 0 )
range - > n0 = 0 ;
if ( range - > n1 > = input_full_size )
range - > n1 = input_full_size - 1 ;
}
}
static void stbir__get_split_info ( stbir__per_split_info * split_info , int splits , int output_height , int vertical_pixel_margin , int input_full_height )
{
int i , cur ;
int left = output_height ;
cur = 0 ;
for ( i = 0 ; i < splits ; i + + )
{
int each ;
split_info [ i ] . start_output_y = cur ;
each = left / ( splits - i ) ;
split_info [ i ] . end_output_y = cur + each ;
cur + = each ;
left - = each ;
// scatter range (updated to minimum as you run it)
split_info [ i ] . start_input_y = - vertical_pixel_margin ;
split_info [ i ] . end_input_y = input_full_height + vertical_pixel_margin ;
}
}
static void stbir__free_internal_mem ( stbir__info * info )
{
# define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } }
if ( info )
{
# ifndef STBIR__SEPARATE_ALLOCATIONS
STBIR__FREE_AND_CLEAR ( info - > alloced_mem ) ;
# else
int i , j ;
if ( ( info - > vertical . gather_prescatter_contributors ) & & ( ( void * ) info - > vertical . gather_prescatter_contributors ! = ( void * ) info - > split_info [ 0 ] . decode_buffer ) )
{
STBIR__FREE_AND_CLEAR ( info - > vertical . gather_prescatter_coefficients ) ;
STBIR__FREE_AND_CLEAR ( info - > vertical . gather_prescatter_contributors ) ;
}
for ( i = 0 ; i < info - > splits ; i + + )
{
for ( j = 0 ; j < info - > alloc_ring_buffer_num_entries ; j + + )
{
# ifdef STBIR_SIMD8
if ( info - > effective_channels = = 3 )
- - info - > split_info [ i ] . ring_buffers [ j ] ; // avx in 3 channel mode needs one float at the start of the buffer
# endif
STBIR__FREE_AND_CLEAR ( info - > split_info [ i ] . ring_buffers [ j ] ) ;
}
# ifdef STBIR_SIMD8
if ( info - > effective_channels = = 3 )
- - info - > split_info [ i ] . decode_buffer ; // avx in 3 channel mode needs one float at the start of the buffer
# endif
STBIR__FREE_AND_CLEAR ( info - > split_info [ i ] . decode_buffer ) ;
STBIR__FREE_AND_CLEAR ( info - > split_info [ i ] . ring_buffers ) ;
STBIR__FREE_AND_CLEAR ( info - > split_info [ i ] . vertical_buffer ) ;
}
STBIR__FREE_AND_CLEAR ( info - > split_info ) ;
if ( info - > vertical . coefficients ! = info - > horizontal . coefficients )
{
STBIR__FREE_AND_CLEAR ( info - > vertical . coefficients ) ;
STBIR__FREE_AND_CLEAR ( info - > vertical . contributors ) ;
}
STBIR__FREE_AND_CLEAR ( info - > horizontal . coefficients ) ;
STBIR__FREE_AND_CLEAR ( info - > horizontal . contributors ) ;
STBIR__FREE_AND_CLEAR ( info - > alloced_mem ) ;
STBIR__FREE_AND_CLEAR ( info ) ;
# endif
}
# undef STBIR__FREE_AND_CLEAR
}
static int stbir__get_max_split ( int splits , int height )
{
int i ;
int max = 0 ;
for ( i = 0 ; i < splits ; i + + )
{
int each = height / ( splits - i ) ;
if ( each > max )
max = each ;
height - = each ;
}
return max ;
}
static stbir__horizontal_gather_channels_func * * stbir__horizontal_gather_n_coeffs_funcs [ 8 ] =
{
0 , stbir__horizontal_gather_1_channels_with_n_coeffs_funcs , stbir__horizontal_gather_2_channels_with_n_coeffs_funcs , stbir__horizontal_gather_3_channels_with_n_coeffs_funcs , stbir__horizontal_gather_4_channels_with_n_coeffs_funcs , 0 , 0 , stbir__horizontal_gather_7_channels_with_n_coeffs_funcs
} ;
static stbir__horizontal_gather_channels_func * * stbir__horizontal_gather_channels_funcs [ 8 ] =
{
0 , stbir__horizontal_gather_1_channels_funcs , stbir__horizontal_gather_2_channels_funcs , stbir__horizontal_gather_3_channels_funcs , stbir__horizontal_gather_4_channels_funcs , 0 , 0 , stbir__horizontal_gather_7_channels_funcs
} ;
// there are six resize classifications: 0 == vertical scatter, 1 == vertical gather < 1x scale, 2 == vertical gather 1x-2x scale, 4 == vertical gather < 3x scale, 4 == vertical gather > 3x scale, 5 == <=4 pixel height, 6 == <=4 pixel wide column
# define STBIR_RESIZE_CLASSIFICATIONS 8
static float stbir__compute_weights [ 5 ] [ STBIR_RESIZE_CLASSIFICATIONS ] [ 4 ] = // 5 = 0=1chan, 1=2chan, 2=3chan, 3=4chan, 4=7chan
{
{
{ 1.00000f , 1.00000f , 0.31250f , 1.00000f } ,
{ 0.56250f , 0.59375f , 0.00000f , 0.96875f } ,
{ 1.00000f , 0.06250f , 0.00000f , 1.00000f } ,
{ 0.00000f , 0.09375f , 1.00000f , 1.00000f } ,
{ 1.00000f , 1.00000f , 1.00000f , 1.00000f } ,
{ 0.03125f , 0.12500f , 1.00000f , 1.00000f } ,
{ 0.06250f , 0.12500f , 0.00000f , 1.00000f } ,
{ 0.00000f , 1.00000f , 0.00000f , 0.03125f } ,
} , {
{ 0.00000f , 0.84375f , 0.00000f , 0.03125f } ,
{ 0.09375f , 0.93750f , 0.00000f , 0.78125f } ,
{ 0.87500f , 0.21875f , 0.00000f , 0.96875f } ,
{ 0.09375f , 0.09375f , 1.00000f , 1.00000f } ,
{ 1.00000f , 1.00000f , 1.00000f , 1.00000f } ,
{ 0.03125f , 0.12500f , 1.00000f , 1.00000f } ,
{ 0.06250f , 0.12500f , 0.00000f , 1.00000f } ,
{ 0.00000f , 1.00000f , 0.00000f , 0.53125f } ,
} , {
{ 0.00000f , 0.53125f , 0.00000f , 0.03125f } ,
{ 0.06250f , 0.96875f , 0.00000f , 0.53125f } ,
{ 0.87500f , 0.18750f , 0.00000f , 0.93750f } ,
{ 0.00000f , 0.09375f , 1.00000f , 1.00000f } ,
{ 1.00000f , 1.00000f , 1.00000f , 1.00000f } ,
{ 0.03125f , 0.12500f , 1.00000f , 1.00000f } ,
{ 0.06250f , 0.12500f , 0.00000f , 1.00000f } ,
{ 0.00000f , 1.00000f , 0.00000f , 0.56250f } ,
} , {
{ 0.00000f , 0.50000f , 0.00000f , 0.71875f } ,
{ 0.06250f , 0.84375f , 0.00000f , 0.87500f } ,
{ 1.00000f , 0.50000f , 0.50000f , 0.96875f } ,
{ 1.00000f , 0.09375f , 0.31250f , 0.50000f } ,
{ 1.00000f , 1.00000f , 1.00000f , 1.00000f } ,
{ 1.00000f , 0.03125f , 0.03125f , 0.53125f } ,
{ 0.18750f , 0.12500f , 0.00000f , 1.00000f } ,
{ 0.00000f , 1.00000f , 0.03125f , 0.18750f } ,
} , {
{ 0.00000f , 0.59375f , 0.00000f , 0.96875f } ,
{ 0.06250f , 0.81250f , 0.06250f , 0.59375f } ,
{ 0.75000f , 0.43750f , 0.12500f , 0.96875f } ,
{ 0.87500f , 0.06250f , 0.18750f , 0.43750f } ,
{ 1.00000f , 1.00000f , 1.00000f , 1.00000f } ,
{ 0.15625f , 0.12500f , 1.00000f , 1.00000f } ,
{ 0.06250f , 0.12500f , 0.00000f , 1.00000f } ,
{ 0.00000f , 1.00000f , 0.03125f , 0.34375f } ,
}
} ;
// structure that allow us to query and override info for training the costs
typedef struct STBIR__V_FIRST_INFO
{
double v_cost , h_cost ;
int control_v_first ; // 0 = no control, 1 = force hori, 2 = force vert
int v_first ;
int v_resize_classification ;
int is_gather ;
} STBIR__V_FIRST_INFO ;
# ifdef STBIR__V_FIRST_INFO_BUFFER
static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = { 0 } ;
# define STBIR__V_FIRST_INFO_POINTER &STBIR__V_FIRST_INFO_BUFFER
# else
# define STBIR__V_FIRST_INFO_POINTER 0
# endif
// Figure out whether to scale along the horizontal or vertical first.
// This only *super* important when you are scaling by a massively
// different amount in the vertical vs the horizontal (for example, if
// you are scaling by 2x in the width, and 0.5x in the height, then you
// want to do the vertical scale first, because it's around 3x faster
// in that order.
//
// In more normal circumstances, this makes a 20-40% differences, so
// it's good to get right, but not critical. The normal way that you
// decide which direction goes first is just figuring out which
// direction does more multiplies. But with modern CPUs with their
// fancy caches and SIMD and high IPC abilities, so there's just a lot
// more that goes into it.
//
// My handwavy sort of solution is to have an app that does a whole
// bunch of timing for both vertical and horizontal first modes,
// and then another app that can read lots of these timing files
// and try to search for the best weights to use. Dotimings.c
// is the app that does a bunch of timings, and vf_train.c is the
// app that solves for the best weights (and shows how well it
// does currently).
static int stbir__should_do_vertical_first ( float weights_table [ STBIR_RESIZE_CLASSIFICATIONS ] [ 4 ] , int horizontal_filter_pixel_width , float horizontal_scale , int horizontal_output_size , int vertical_filter_pixel_width , float vertical_scale , int vertical_output_size , int is_gather , STBIR__V_FIRST_INFO * info )
{
double v_cost , h_cost ;
float * weights ;
int vertical_first ;
int v_classification ;
// categorize the resize into buckets
if ( ( vertical_output_size < = 4 ) | | ( horizontal_output_size < = 4 ) )
v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7 ;
else if ( vertical_scale < = 1.0f )
v_classification = ( is_gather ) ? 1 : 0 ;
else if ( vertical_scale < = 2.0f )
v_classification = 2 ;
else if ( vertical_scale < = 3.0f )
v_classification = 3 ;
else if ( vertical_scale < = 4.0f )
v_classification = 5 ;
else
v_classification = 6 ;
// use the right weights
weights = weights_table [ v_classification ] ;
// this is the costs when you don't take into account modern CPUs with high ipc and simd and caches - wish we had a better estimate
h_cost = ( float ) horizontal_filter_pixel_width * weights [ 0 ] + horizontal_scale * ( float ) vertical_filter_pixel_width * weights [ 1 ] ;
v_cost = ( float ) vertical_filter_pixel_width * weights [ 2 ] + vertical_scale * ( float ) horizontal_filter_pixel_width * weights [ 3 ] ;
// use computation estimate to decide vertical first or not
vertical_first = ( v_cost < = h_cost ) ? 1 : 0 ;
// save these, if requested
if ( info )
{
info - > h_cost = h_cost ;
info - > v_cost = v_cost ;
info - > v_resize_classification = v_classification ;
info - > v_first = vertical_first ;
info - > is_gather = is_gather ;
}
// and this allows us to override everything for testing (see dotiming.c)
if ( ( info ) & & ( info - > control_v_first ) )
vertical_first = ( info - > control_v_first = = 2 ) ? 1 : 0 ;
return vertical_first ;
}
// layout lookups - must match stbir_internal_pixel_layout
static unsigned char stbir__pixel_channels [ ] = {
1 , 2 , 3 , 3 , 4 , // 1ch, 2ch, rgb, bgr, 4ch
4 , 4 , 4 , 4 , 2 , 2 , // RGBA,BGRA,ARGB,ABGR,RA,AR
4 , 4 , 4 , 4 , 2 , 2 , // RGBA_PM,BGRA_PM,ARGB_PM,ABGR_PM,RA_PM,AR_PM
} ;
// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal [ ] = {
STBIRI_BGR , STBIRI_1CHANNEL , STBIRI_2CHANNEL , STBIRI_RGB , STBIRI_RGBA ,
STBIRI_4CHANNEL , STBIRI_BGRA , STBIRI_ARGB , STBIRI_ABGR , STBIRI_RA , STBIRI_AR ,
STBIRI_RGBA_PM , STBIRI_BGRA_PM , STBIRI_ARGB_PM , STBIRI_ABGR_PM , STBIRI_RA_PM , STBIRI_AR_PM ,
} ;
static stbir__info * stbir__alloc_internal_mem_and_build_samplers ( stbir__sampler * horizontal , stbir__sampler * vertical , stbir__contributors * conservative , stbir_pixel_layout input_pixel_layout_public , stbir_pixel_layout output_pixel_layout_public , int splits , int new_x , int new_y , int fast_alpha , void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )
{
static char stbir_channel_count_index [ 8 ] = { 9 , 0 , 1 , 2 , 3 , 9 , 9 , 4 } ;
stbir__info * info = 0 ;
void * alloced = 0 ;
int alloced_total = 0 ;
int vertical_first ;
int decode_buffer_size , ring_buffer_length_bytes , ring_buffer_size , vertical_buffer_size , alloc_ring_buffer_num_entries ;
int alpha_weighting_type = 0 ; // 0=none, 1=simple, 2=fancy
int conservative_split_output_size = stbir__get_max_split ( splits , vertical - > scale_info . output_sub_size ) ;
stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal [ input_pixel_layout_public ] ;
stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal [ output_pixel_layout_public ] ;
int channels = stbir__pixel_channels [ input_pixel_layout ] ;
int effective_channels = channels ;
// first figure out what type of alpha weighting to use (if any)
if ( ( horizontal - > filter_enum ! = STBIR_FILTER_POINT_SAMPLE ) | | ( vertical - > filter_enum ! = STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling
{
if ( ( input_pixel_layout > = STBIRI_RGBA ) & & ( input_pixel_layout < = STBIRI_AR ) & & ( output_pixel_layout > = STBIRI_RGBA ) & & ( output_pixel_layout < = STBIRI_AR ) )
{
if ( fast_alpha )
{
alpha_weighting_type = 4 ;
}
else
{
static int fancy_alpha_effective_cnts [ 6 ] = { 7 , 7 , 7 , 7 , 3 , 3 } ;
alpha_weighting_type = 2 ;
effective_channels = fancy_alpha_effective_cnts [ input_pixel_layout - STBIRI_RGBA ] ;
}
}
else if ( ( input_pixel_layout > = STBIRI_RGBA_PM ) & & ( input_pixel_layout < = STBIRI_AR_PM ) & & ( output_pixel_layout > = STBIRI_RGBA ) & & ( output_pixel_layout < = STBIRI_AR ) )
{
// input premult, output non-premult
alpha_weighting_type = 3 ;
}
else if ( ( input_pixel_layout > = STBIRI_RGBA ) & & ( input_pixel_layout < = STBIRI_AR ) & & ( output_pixel_layout > = STBIRI_RGBA_PM ) & & ( output_pixel_layout < = STBIRI_AR_PM ) )
{
// input non-premult, output premult
alpha_weighting_type = 1 ;
}
}
// channel in and out count must match currently
if ( channels ! = stbir__pixel_channels [ output_pixel_layout ] )
return 0 ;
// get vertical first
vertical_first = stbir__should_do_vertical_first ( stbir__compute_weights [ ( int ) stbir_channel_count_index [ effective_channels ] ] , horizontal - > filter_pixel_width , horizontal - > scale_info . scale , horizontal - > scale_info . output_sub_size , vertical - > filter_pixel_width , vertical - > scale_info . scale , vertical - > scale_info . output_sub_size , vertical - > is_gather , STBIR__V_FIRST_INFO_POINTER ) ;
// sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect)
decode_buffer_size = ( conservative - > n1 - conservative - > n0 + 1 ) * effective_channels * sizeof ( float ) + sizeof ( float ) ; // extra float for padding
# if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8)
if ( effective_channels = = 3 )
decode_buffer_size + = sizeof ( float ) ; // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations)
# endif
ring_buffer_length_bytes = horizontal - > scale_info . output_sub_size * effective_channels * sizeof ( float ) + sizeof ( float ) ; // extra float for padding
// if we do vertical first, the ring buffer holds a whole decoded line
if ( vertical_first )
ring_buffer_length_bytes = ( decode_buffer_size + 15 ) & ~ 15 ;
if ( ( ring_buffer_length_bytes & 4095 ) = = 0 ) ring_buffer_length_bytes + = 64 * 3 ; // avoid 4k alias
// One extra entry because floating point precision problems sometimes cause an extra to be necessary.
alloc_ring_buffer_num_entries = vertical - > filter_pixel_width + 1 ;
// we never need more ring buffer entries than the scanlines we're outputting when in scatter mode
if ( ( ! vertical - > is_gather ) & & ( alloc_ring_buffer_num_entries > conservative_split_output_size ) )
alloc_ring_buffer_num_entries = conservative_split_output_size ;
ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes ;
2024-01-08 21:12:31 -05:00
( void ) ring_buffer_size ;
2023-12-17 15:04:57 -05:00
// The vertical buffer is used differently, depending on whether we are scattering
// the vertical scanlines, or gathering them.
// If scattering, it's used at the temp buffer to accumulate each output.
// If gathering, it's just the output buffer.
vertical_buffer_size = horizontal - > scale_info . output_sub_size * effective_channels * sizeof ( float ) + sizeof ( float ) ; // extra float for padding
// we make two passes through this loop, 1st to add everything up, 2nd to allocate and init
for ( ; ; )
{
int i ;
void * advance_mem = alloced ;
int copy_horizontal = 0 ;
stbir__sampler * possibly_use_horizontal_for_pivot = 0 ;
# ifdef STBIR__SEPARATE_ALLOCATIONS
# define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; }
# else
# define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size);
# endif
STBIR__NEXT_PTR ( info , sizeof ( stbir__info ) , stbir__info ) ;
STBIR__NEXT_PTR ( info - > split_info , sizeof ( stbir__per_split_info ) * splits , stbir__per_split_info ) ;
if ( info )
{
static stbir__alpha_weight_func * fancy_alpha_weights [ 6 ] = { stbir__fancy_alpha_weight_4ch , stbir__fancy_alpha_weight_4ch , stbir__fancy_alpha_weight_4ch , stbir__fancy_alpha_weight_4ch , stbir__fancy_alpha_weight_2ch , stbir__fancy_alpha_weight_2ch } ;
static stbir__alpha_unweight_func * fancy_alpha_unweights [ 6 ] = { stbir__fancy_alpha_unweight_4ch , stbir__fancy_alpha_unweight_4ch , stbir__fancy_alpha_unweight_4ch , stbir__fancy_alpha_unweight_4ch , stbir__fancy_alpha_unweight_2ch , stbir__fancy_alpha_unweight_2ch } ;
static stbir__alpha_weight_func * simple_alpha_weights [ 6 ] = { stbir__simple_alpha_weight_4ch , stbir__simple_alpha_weight_4ch , stbir__simple_alpha_weight_4ch , stbir__simple_alpha_weight_4ch , stbir__simple_alpha_weight_2ch , stbir__simple_alpha_weight_2ch } ;
static stbir__alpha_unweight_func * simple_alpha_unweights [ 6 ] = { stbir__simple_alpha_unweight_4ch , stbir__simple_alpha_unweight_4ch , stbir__simple_alpha_unweight_4ch , stbir__simple_alpha_unweight_4ch , stbir__simple_alpha_unweight_2ch , stbir__simple_alpha_unweight_2ch } ;
// initialize info fields
info - > alloced_mem = alloced ;
info - > alloced_total = alloced_total ;
info - > channels = channels ;
info - > effective_channels = effective_channels ;
info - > offset_x = new_x ;
info - > offset_y = new_y ;
info - > alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries ;
info - > ring_buffer_num_entries = 0 ;
info - > ring_buffer_length_bytes = ring_buffer_length_bytes ;
info - > splits = splits ;
info - > vertical_first = vertical_first ;
info - > input_pixel_layout_internal = input_pixel_layout ;
info - > output_pixel_layout_internal = output_pixel_layout ;
// setup alpha weight functions
info - > alpha_weight = 0 ;
info - > alpha_unweight = 0 ;
// handle alpha weighting functions and overrides
if ( alpha_weighting_type = = 2 )
{
// high quality alpha multiplying on the way in, dividing on the way out
info - > alpha_weight = fancy_alpha_weights [ input_pixel_layout - STBIRI_RGBA ] ;
info - > alpha_unweight = fancy_alpha_unweights [ output_pixel_layout - STBIRI_RGBA ] ;
}
else if ( alpha_weighting_type = = 4 )
{
// fast alpha multiplying on the way in, dividing on the way out
info - > alpha_weight = simple_alpha_weights [ input_pixel_layout - STBIRI_RGBA ] ;
info - > alpha_unweight = simple_alpha_unweights [ output_pixel_layout - STBIRI_RGBA ] ;
}
else if ( alpha_weighting_type = = 1 )
{
// fast alpha on the way in, leave in premultiplied form on way out
info - > alpha_weight = simple_alpha_weights [ input_pixel_layout - STBIRI_RGBA ] ;
}
else if ( alpha_weighting_type = = 3 )
{
// incoming is premultiplied, fast alpha dividing on the way out - non-premultiplied output
info - > alpha_unweight = simple_alpha_unweights [ output_pixel_layout - STBIRI_RGBA ] ;
}
// handle 3-chan color flipping, using the alpha weight path
if ( ( ( input_pixel_layout = = STBIRI_RGB ) & & ( output_pixel_layout = = STBIRI_BGR ) ) | |
( ( input_pixel_layout = = STBIRI_BGR ) & & ( output_pixel_layout = = STBIRI_RGB ) ) )
{
// do the flipping on the smaller of the two ends
if ( horizontal - > scale_info . scale < 1.0f )
info - > alpha_unweight = stbir__simple_flip_3ch ;
else
info - > alpha_weight = stbir__simple_flip_3ch ;
}
}
// get all the per-split buffers
for ( i = 0 ; i < splits ; i + + )
{
STBIR__NEXT_PTR ( info - > split_info [ i ] . decode_buffer , decode_buffer_size , float ) ;
# ifdef STBIR__SEPARATE_ALLOCATIONS
# ifdef STBIR_SIMD8
if ( ( info ) & & ( effective_channels = = 3 ) )
+ + info - > split_info [ i ] . decode_buffer ; // avx in 3 channel mode needs one float at the start of the buffer
# endif
STBIR__NEXT_PTR ( info - > split_info [ i ] . ring_buffers , alloc_ring_buffer_num_entries * sizeof ( float * ) , float * ) ;
{
int j ;
for ( j = 0 ; j < alloc_ring_buffer_num_entries ; j + + )
{
STBIR__NEXT_PTR ( info - > split_info [ i ] . ring_buffers [ j ] , ring_buffer_length_bytes , float ) ;
# ifdef STBIR_SIMD8
if ( ( info ) & & ( effective_channels = = 3 ) )
+ + info - > split_info [ i ] . ring_buffers [ j ] ; // avx in 3 channel mode needs one float at the start of the buffer
# endif
}
}
# else
STBIR__NEXT_PTR ( info - > split_info [ i ] . ring_buffer , ring_buffer_size , float ) ;
# endif
STBIR__NEXT_PTR ( info - > split_info [ i ] . vertical_buffer , vertical_buffer_size , float ) ;
}
// alloc memory for to-be-pivoted coeffs (if necessary)
if ( vertical - > is_gather = = 0 )
{
int both ;
int temp_mem_amt ;
// when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after,
// that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that
// is too small, we just allocate extra memory to use as this temp.
both = vertical - > gather_prescatter_contributors_size + vertical - > gather_prescatter_coefficients_size ;
# ifdef STBIR__SEPARATE_ALLOCATIONS
temp_mem_amt = decode_buffer_size ;
# else
temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits ;
# endif
if ( temp_mem_amt > = both )
{
if ( info )
{
vertical - > gather_prescatter_contributors = ( stbir__contributors * ) info - > split_info [ 0 ] . decode_buffer ;
vertical - > gather_prescatter_coefficients = ( float * ) ( ( ( char * ) info - > split_info [ 0 ] . decode_buffer ) + vertical - > gather_prescatter_contributors_size ) ;
}
}
else
{
// ring+decode memory is too small, so allocate temp memory
STBIR__NEXT_PTR ( vertical - > gather_prescatter_contributors , vertical - > gather_prescatter_contributors_size , stbir__contributors ) ;
STBIR__NEXT_PTR ( vertical - > gather_prescatter_coefficients , vertical - > gather_prescatter_coefficients_size , float ) ;
}
}
STBIR__NEXT_PTR ( horizontal - > contributors , horizontal - > contributors_size , stbir__contributors ) ;
STBIR__NEXT_PTR ( horizontal - > coefficients , horizontal - > coefficients_size , float ) ;
// are the two filters identical?? (happens a lot with mipmap generation)
if ( ( horizontal - > filter_kernel = = vertical - > filter_kernel ) & & ( horizontal - > filter_support = = vertical - > filter_support ) & & ( horizontal - > edge = = vertical - > edge ) & & ( horizontal - > scale_info . output_sub_size = = vertical - > scale_info . output_sub_size ) )
{
float diff_scale = horizontal - > scale_info . scale - vertical - > scale_info . scale ;
float diff_shift = horizontal - > scale_info . pixel_shift - vertical - > scale_info . pixel_shift ;
if ( diff_scale < 0.0f ) diff_scale = - diff_scale ;
if ( diff_shift < 0.0f ) diff_shift = - diff_shift ;
if ( ( diff_scale < = stbir__small_float ) & & ( diff_shift < = stbir__small_float ) )
{
if ( horizontal - > is_gather = = vertical - > is_gather )
{
copy_horizontal = 1 ;
goto no_vert_alloc ;
}
// everything matches, but vertical is scatter, horizontal is gather, use horizontal coeffs for vertical pivot coeffs
possibly_use_horizontal_for_pivot = horizontal ;
}
}
STBIR__NEXT_PTR ( vertical - > contributors , vertical - > contributors_size , stbir__contributors ) ;
STBIR__NEXT_PTR ( vertical - > coefficients , vertical - > coefficients_size , float ) ;
no_vert_alloc :
if ( info )
{
STBIR_PROFILE_BUILD_START ( horizontal ) ;
stbir__calculate_filters ( horizontal , 0 , user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ) ;
// setup the horizontal gather functions
// start with defaulting to the n_coeffs functions (specialized on channels and remnant leftover)
info - > horizontal_gather_channels = stbir__horizontal_gather_n_coeffs_funcs [ effective_channels ] [ horizontal - > extent_info . widest & 3 ] ;
// but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size
if ( horizontal - > extent_info . widest < = 12 )
info - > horizontal_gather_channels = stbir__horizontal_gather_channels_funcs [ effective_channels ] [ horizontal - > extent_info . widest - 1 ] ;
info - > scanline_extents . conservative . n0 = conservative - > n0 ;
info - > scanline_extents . conservative . n1 = conservative - > n1 ;
// get exact extents
stbir__get_extents ( horizontal , & info - > scanline_extents ) ;
// pack the horizontal coeffs
horizontal - > coefficient_width = stbir__pack_coefficients ( horizontal - > num_contributors , horizontal - > contributors , horizontal - > coefficients , horizontal - > coefficient_width , horizontal - > extent_info . widest , info - > scanline_extents . conservative . n1 + 1 ) ;
STBIR_MEMCPY ( & info - > horizontal , horizontal , sizeof ( stbir__sampler ) ) ;
STBIR_PROFILE_BUILD_END ( horizontal ) ;
if ( copy_horizontal )
{
STBIR_MEMCPY ( & info - > vertical , horizontal , sizeof ( stbir__sampler ) ) ;
}
else
{
STBIR_PROFILE_BUILD_START ( vertical ) ;
stbir__calculate_filters ( vertical , possibly_use_horizontal_for_pivot , user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ) ;
STBIR_MEMCPY ( & info - > vertical , vertical , sizeof ( stbir__sampler ) ) ;
STBIR_PROFILE_BUILD_END ( vertical ) ;
}
// setup the vertical split ranges
stbir__get_split_info ( info - > split_info , info - > splits , info - > vertical . scale_info . output_sub_size , info - > vertical . filter_pixel_margin , info - > vertical . scale_info . input_full_size ) ;
// now we know precisely how many entries we need
info - > ring_buffer_num_entries = info - > vertical . extent_info . widest ;
// we never need more ring buffer entries than the scanlines we're outputting
if ( ( ! info - > vertical . is_gather ) & & ( info - > ring_buffer_num_entries > conservative_split_output_size ) )
info - > ring_buffer_num_entries = conservative_split_output_size ;
STBIR_ASSERT ( info - > ring_buffer_num_entries < = info - > alloc_ring_buffer_num_entries ) ;
// a few of the horizontal gather functions read one dword past the end (but mask it out), so put in a normal value so no snans or denormals accidentally sneak in
for ( i = 0 ; i < splits ; i + + )
{
int width , ofs ;
// find the right most span
if ( info - > scanline_extents . spans [ 0 ] . n1 > info - > scanline_extents . spans [ 1 ] . n1 )
width = info - > scanline_extents . spans [ 0 ] . n1 - info - > scanline_extents . spans [ 0 ] . n0 ;
else
width = info - > scanline_extents . spans [ 1 ] . n1 - info - > scanline_extents . spans [ 1 ] . n0 ;
// this calc finds the exact end of the decoded scanline for all filter modes.
// usually this is just the width * effective channels. But we have to account
// for the area to the left of the scanline for wrap filtering and alignment, this
// is stored as a negative value in info->scanline_extents.conservative.n0. Next,
// we need to skip the exact size of the right hand size filter area (again for
// wrap mode), this is in info->scanline_extents.edge_sizes[1]).
ofs = ( width + 1 - info - > scanline_extents . conservative . n0 + info - > scanline_extents . edge_sizes [ 1 ] ) * effective_channels ;
// place a known, but numerically valid value in the decode buffer
info - > split_info [ i ] . decode_buffer [ ofs ] = 9999.0f ;
// if vertical filtering first, place a known, but numerically valid value in the all
// of the ring buffer accumulators
if ( vertical_first )
{
int j ;
for ( j = 0 ; j < info - > ring_buffer_num_entries ; j + + )
{
stbir__get_ring_buffer_entry ( info , info - > split_info + i , j ) [ ofs ] = 9999.0f ;
}
}
}
}
# undef STBIR__NEXT_PTR
// is this the first time through loop?
if ( info = = 0 )
{
alloced_total = ( int ) ( 15 + ( size_t ) advance_mem ) ;
alloced = STBIR_MALLOC ( alloced_total , user_data ) ;
if ( alloced = = 0 )
return 0 ;
}
else
return info ; // success
}
}
static int stbir__perform_resize ( stbir__info const * info , int split_start , int split_count )
{
stbir__per_split_info * split_info = info - > split_info + split_start ;
STBIR_PROFILE_CLEAR_EXTRAS ( ) ;
STBIR_PROFILE_FIRST_START ( looping ) ;
if ( info - > vertical . is_gather )
stbir__vertical_gather_loop ( info , split_info , split_count ) ;
else
stbir__vertical_scatter_loop ( info , split_info , split_count ) ;
STBIR_PROFILE_END ( looping ) ;
return 1 ;
}
static void stbir__update_info_from_resize ( stbir__info * info , STBIR_RESIZE * resize )
{
static stbir__decode_pixels_func * decode_simple [ STBIR_TYPE_HALF_FLOAT - STBIR_TYPE_UINT8_SRGB + 1 ] =
{
/* 1ch-4ch */ stbir__decode_uint8_srgb , stbir__decode_uint8_srgb , 0 , stbir__decode_float_linear , stbir__decode_half_float_linear ,
} ;
static stbir__decode_pixels_func * decode_alphas [ STBIRI_AR - STBIRI_RGBA + 1 ] [ STBIR_TYPE_HALF_FLOAT - STBIR_TYPE_UINT8_SRGB + 1 ] =
{
{ /* RGBA */ stbir__decode_uint8_srgb4_linearalpha , stbir__decode_uint8_srgb , 0 , stbir__decode_float_linear , stbir__decode_half_float_linear } ,
{ /* BGRA */ stbir__decode_uint8_srgb4_linearalpha_BGRA , stbir__decode_uint8_srgb_BGRA , 0 , stbir__decode_float_linear_BGRA , stbir__decode_half_float_linear_BGRA } ,
{ /* ARGB */ stbir__decode_uint8_srgb4_linearalpha_ARGB , stbir__decode_uint8_srgb_ARGB , 0 , stbir__decode_float_linear_ARGB , stbir__decode_half_float_linear_ARGB } ,
{ /* ABGR */ stbir__decode_uint8_srgb4_linearalpha_ABGR , stbir__decode_uint8_srgb_ABGR , 0 , stbir__decode_float_linear_ABGR , stbir__decode_half_float_linear_ABGR } ,
{ /* RA */ stbir__decode_uint8_srgb2_linearalpha , stbir__decode_uint8_srgb , 0 , stbir__decode_float_linear , stbir__decode_half_float_linear } ,
{ /* AR */ stbir__decode_uint8_srgb2_linearalpha_AR , stbir__decode_uint8_srgb_AR , 0 , stbir__decode_float_linear_AR , stbir__decode_half_float_linear_AR } ,
} ;
static stbir__decode_pixels_func * decode_simple_scaled_or_not [ 2 ] [ 2 ] =
{
{ stbir__decode_uint8_linear_scaled , stbir__decode_uint8_linear } , { stbir__decode_uint16_linear_scaled , stbir__decode_uint16_linear } ,
} ;
static stbir__decode_pixels_func * decode_alphas_scaled_or_not [ STBIRI_AR - STBIRI_RGBA + 1 ] [ 2 ] [ 2 ] =
{
{ /* RGBA */ { stbir__decode_uint8_linear_scaled , stbir__decode_uint8_linear } , { stbir__decode_uint16_linear_scaled , stbir__decode_uint16_linear } } ,
{ /* BGRA */ { stbir__decode_uint8_linear_scaled_BGRA , stbir__decode_uint8_linear_BGRA } , { stbir__decode_uint16_linear_scaled_BGRA , stbir__decode_uint16_linear_BGRA } } ,
{ /* ARGB */ { stbir__decode_uint8_linear_scaled_ARGB , stbir__decode_uint8_linear_ARGB } , { stbir__decode_uint16_linear_scaled_ARGB , stbir__decode_uint16_linear_ARGB } } ,
{ /* ABGR */ { stbir__decode_uint8_linear_scaled_ABGR , stbir__decode_uint8_linear_ABGR } , { stbir__decode_uint16_linear_scaled_ABGR , stbir__decode_uint16_linear_ABGR } } ,
{ /* RA */ { stbir__decode_uint8_linear_scaled , stbir__decode_uint8_linear } , { stbir__decode_uint16_linear_scaled , stbir__decode_uint16_linear } } ,
{ /* AR */ { stbir__decode_uint8_linear_scaled_AR , stbir__decode_uint8_linear_AR } , { stbir__decode_uint16_linear_scaled_AR , stbir__decode_uint16_linear_AR } }
} ;
static stbir__encode_pixels_func * encode_simple [ STBIR_TYPE_HALF_FLOAT - STBIR_TYPE_UINT8_SRGB + 1 ] =
{
/* 1ch-4ch */ stbir__encode_uint8_srgb , stbir__encode_uint8_srgb , 0 , stbir__encode_float_linear , stbir__encode_half_float_linear ,
} ;
static stbir__encode_pixels_func * encode_alphas [ STBIRI_AR - STBIRI_RGBA + 1 ] [ STBIR_TYPE_HALF_FLOAT - STBIR_TYPE_UINT8_SRGB + 1 ] =
{
{ /* RGBA */ stbir__encode_uint8_srgb4_linearalpha , stbir__encode_uint8_srgb , 0 , stbir__encode_float_linear , stbir__encode_half_float_linear } ,
{ /* BGRA */ stbir__encode_uint8_srgb4_linearalpha_BGRA , stbir__encode_uint8_srgb_BGRA , 0 , stbir__encode_float_linear_BGRA , stbir__encode_half_float_linear_BGRA } ,
{ /* ARGB */ stbir__encode_uint8_srgb4_linearalpha_ARGB , stbir__encode_uint8_srgb_ARGB , 0 , stbir__encode_float_linear_ARGB , stbir__encode_half_float_linear_ARGB } ,
{ /* ABGR */ stbir__encode_uint8_srgb4_linearalpha_ABGR , stbir__encode_uint8_srgb_ABGR , 0 , stbir__encode_float_linear_ABGR , stbir__encode_half_float_linear_ABGR } ,
{ /* RA */ stbir__encode_uint8_srgb2_linearalpha , stbir__encode_uint8_srgb , 0 , stbir__encode_float_linear , stbir__encode_half_float_linear } ,
{ /* AR */ stbir__encode_uint8_srgb2_linearalpha_AR , stbir__encode_uint8_srgb_AR , 0 , stbir__encode_float_linear_AR , stbir__encode_half_float_linear_AR }
} ;
static stbir__encode_pixels_func * encode_simple_scaled_or_not [ 2 ] [ 2 ] =
{
{ stbir__encode_uint8_linear_scaled , stbir__encode_uint8_linear } , { stbir__encode_uint16_linear_scaled , stbir__encode_uint16_linear } ,
} ;
static stbir__encode_pixels_func * encode_alphas_scaled_or_not [ STBIRI_AR - STBIRI_RGBA + 1 ] [ 2 ] [ 2 ] =
{
{ /* RGBA */ { stbir__encode_uint8_linear_scaled , stbir__encode_uint8_linear } , { stbir__encode_uint16_linear_scaled , stbir__encode_uint16_linear } } ,
{ /* BGRA */ { stbir__encode_uint8_linear_scaled_BGRA , stbir__encode_uint8_linear_BGRA } , { stbir__encode_uint16_linear_scaled_BGRA , stbir__encode_uint16_linear_BGRA } } ,
{ /* ARGB */ { stbir__encode_uint8_linear_scaled_ARGB , stbir__encode_uint8_linear_ARGB } , { stbir__encode_uint16_linear_scaled_ARGB , stbir__encode_uint16_linear_ARGB } } ,
{ /* ABGR */ { stbir__encode_uint8_linear_scaled_ABGR , stbir__encode_uint8_linear_ABGR } , { stbir__encode_uint16_linear_scaled_ABGR , stbir__encode_uint16_linear_ABGR } } ,
{ /* RA */ { stbir__encode_uint8_linear_scaled , stbir__encode_uint8_linear } , { stbir__encode_uint16_linear_scaled , stbir__encode_uint16_linear } } ,
{ /* AR */ { stbir__encode_uint8_linear_scaled_AR , stbir__encode_uint8_linear_AR } , { stbir__encode_uint16_linear_scaled_AR , stbir__encode_uint16_linear_AR } }
} ;
stbir__decode_pixels_func * decode_pixels = 0 ;
stbir__encode_pixels_func * encode_pixels = 0 ;
stbir_datatype input_type , output_type ;
input_type = resize - > input_data_type ;
output_type = resize - > output_data_type ;
info - > input_data = resize - > input_pixels ;
info - > input_stride_bytes = resize - > input_stride_in_bytes ;
info - > output_stride_bytes = resize - > output_stride_in_bytes ;
// if we're completely point sampling, then we can turn off SRGB
if ( ( info - > horizontal . filter_enum = = STBIR_FILTER_POINT_SAMPLE ) & & ( info - > vertical . filter_enum = = STBIR_FILTER_POINT_SAMPLE ) )
{
if ( ( ( input_type = = STBIR_TYPE_UINT8_SRGB ) | | ( input_type = = STBIR_TYPE_UINT8_SRGB_ALPHA ) ) & &
( ( output_type = = STBIR_TYPE_UINT8_SRGB ) | | ( output_type = = STBIR_TYPE_UINT8_SRGB_ALPHA ) ) )
{
input_type = STBIR_TYPE_UINT8 ;
output_type = STBIR_TYPE_UINT8 ;
}
}
// recalc the output and input strides
if ( info - > input_stride_bytes = = 0 )
info - > input_stride_bytes = info - > channels * info - > horizontal . scale_info . input_full_size * stbir__type_size [ input_type ] ;
if ( info - > output_stride_bytes = = 0 )
info - > output_stride_bytes = info - > channels * info - > horizontal . scale_info . output_sub_size * stbir__type_size [ output_type ] ;
// calc offset
info - > output_data = ( ( char * ) resize - > output_pixels ) + ( ( ptrdiff_t ) info - > offset_y * ( ptrdiff_t ) resize - > output_stride_in_bytes ) + ( info - > offset_x * info - > channels * stbir__type_size [ output_type ] ) ;
info - > in_pixels_cb = resize - > input_cb ;
info - > user_data = resize - > user_data ;
info - > out_pixels_cb = resize - > output_cb ;
// setup the input format converters
if ( ( input_type = = STBIR_TYPE_UINT8 ) | | ( input_type = = STBIR_TYPE_UINT16 ) )
{
int non_scaled = 0 ;
// check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16)
if ( ( ! info - > alpha_weight ) & & ( ! info - > alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual)
if ( ( ( input_type = = STBIR_TYPE_UINT8 ) & & ( output_type = = STBIR_TYPE_UINT8 ) ) | | ( ( input_type = = STBIR_TYPE_UINT16 ) & & ( output_type = = STBIR_TYPE_UINT16 ) ) )
non_scaled = 1 ;
if ( info - > input_pixel_layout_internal < = STBIRI_4CHANNEL )
decode_pixels = decode_simple_scaled_or_not [ input_type = = STBIR_TYPE_UINT16 ] [ non_scaled ] ;
else
decode_pixels = decode_alphas_scaled_or_not [ ( info - > input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR - STBIRI_RGBA + 1 ) ] [ input_type = = STBIR_TYPE_UINT16 ] [ non_scaled ] ;
}
else
{
if ( info - > input_pixel_layout_internal < = STBIRI_4CHANNEL )
decode_pixels = decode_simple [ input_type - STBIR_TYPE_UINT8_SRGB ] ;
else
decode_pixels = decode_alphas [ ( info - > input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR - STBIRI_RGBA + 1 ) ] [ input_type - STBIR_TYPE_UINT8_SRGB ] ;
}
// setup the output format converters
if ( ( output_type = = STBIR_TYPE_UINT8 ) | | ( output_type = = STBIR_TYPE_UINT16 ) )
{
int non_scaled = 0 ;
// check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16)
if ( ( ! info - > alpha_weight ) & & ( ! info - > alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual)
if ( ( ( input_type = = STBIR_TYPE_UINT8 ) & & ( output_type = = STBIR_TYPE_UINT8 ) ) | | ( ( input_type = = STBIR_TYPE_UINT16 ) & & ( output_type = = STBIR_TYPE_UINT16 ) ) )
non_scaled = 1 ;
if ( info - > output_pixel_layout_internal < = STBIRI_4CHANNEL )
encode_pixels = encode_simple_scaled_or_not [ output_type = = STBIR_TYPE_UINT16 ] [ non_scaled ] ;
else
encode_pixels = encode_alphas_scaled_or_not [ ( info - > output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR - STBIRI_RGBA + 1 ) ] [ output_type = = STBIR_TYPE_UINT16 ] [ non_scaled ] ;
}
else
{
if ( info - > output_pixel_layout_internal < = STBIRI_4CHANNEL )
encode_pixels = encode_simple [ output_type - STBIR_TYPE_UINT8_SRGB ] ;
else
encode_pixels = encode_alphas [ ( info - > output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR - STBIRI_RGBA + 1 ) ] [ output_type - STBIR_TYPE_UINT8_SRGB ] ;
}
info - > input_type = input_type ;
info - > output_type = output_type ;
info - > decode_pixels = decode_pixels ;
info - > encode_pixels = encode_pixels ;
}
static void stbir__clip ( int * outx , int * outsubw , int outw , double * u0 , double * u1 )
{
double per , adj ;
int over ;
// do left/top edge
if ( * outx < 0 )
{
per = ( ( double ) * outx ) / ( ( double ) * outsubw ) ; // is negative
adj = per * ( * u1 - * u0 ) ;
* u0 - = adj ; // increases u0
* outx = 0 ;
}
// do right/bot edge
over = outw - ( * outx + * outsubw ) ;
if ( over < 0 )
{
per = ( ( double ) over ) / ( ( double ) * outsubw ) ; // is negative
adj = per * ( * u1 - * u0 ) ;
* u1 + = adj ; // decrease u1
* outsubw = outw - * outx ;
}
}
// converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so)
static int stbir__double_to_rational ( double f , stbir_uint32 limit , stbir_uint32 * numer , stbir_uint32 * denom , int limit_denom ) // limit_denom (1) or limit numer (0)
{
double err ;
stbir_uint64 top , bot ;
stbir_uint64 numer_last = 0 ;
stbir_uint64 denom_last = 1 ;
stbir_uint64 numer_estimate = 1 ;
stbir_uint64 denom_estimate = 0 ;
// scale to past float error range
top = ( stbir_uint64 ) ( f * ( double ) ( 1 < < 25 ) ) ;
bot = 1 < < 25 ;
// keep refining, but usually stops in a few loops - usually 5 for bad cases
for ( ; ; )
{
stbir_uint64 est , temp ;
// hit limit, break out and do best full range estimate
if ( ( ( limit_denom ) ? denom_estimate : numer_estimate ) > = limit )
break ;
// is the current error less than 1 bit of a float? if so, we're done
if ( denom_estimate )
{
err = ( ( double ) numer_estimate / ( double ) denom_estimate ) - f ;
if ( err < 0.0 ) err = - err ;
if ( err < ( 1.0 / ( double ) ( 1 < < 24 ) ) )
{
// yup, found it
* numer = ( stbir_uint32 ) numer_estimate ;
* denom = ( stbir_uint32 ) denom_estimate ;
return 1 ;
}
}
// no more refinement bits left? break out and do full range estimate
if ( bot = = 0 )
break ;
// gcd the estimate bits
est = top / bot ;
temp = top % bot ;
top = bot ;
bot = temp ;
// move remainders
temp = est * denom_estimate + denom_last ;
denom_last = denom_estimate ;
denom_estimate = temp ;
// move remainders
temp = est * numer_estimate + numer_last ;
numer_last = numer_estimate ;
numer_estimate = temp ;
}
// we didn't fine anything good enough for float, use a full range estimate
if ( limit_denom )
{
numer_estimate = ( stbir_uint64 ) ( f * ( double ) limit + 0.5 ) ;
denom_estimate = limit ;
}
else
{
numer_estimate = limit ;
denom_estimate = ( stbir_uint64 ) ( ( ( double ) limit / f ) + 0.5 ) ;
}
* numer = ( stbir_uint32 ) numer_estimate ;
* denom = ( stbir_uint32 ) denom_estimate ;
err = ( denom_estimate ) ? ( ( ( double ) ( stbir_uint32 ) numer_estimate / ( double ) ( stbir_uint32 ) denom_estimate ) - f ) : 1.0 ;
if ( err < 0.0 ) err = - err ;
return ( err < ( 1.0 / ( double ) ( 1 < < 24 ) ) ) ? 1 : 0 ;
}
static int stbir__calculate_region_transform ( stbir__scale_info * scale_info , int output_full_range , int * output_offset , int output_sub_range , int input_full_range , double input_s0 , double input_s1 )
{
double output_range , input_range , output_s , input_s , ratio , scale ;
input_s = input_s1 - input_s0 ;
// null area
if ( ( output_full_range = = 0 ) | | ( input_full_range = = 0 ) | |
( output_sub_range = = 0 ) | | ( input_s < = stbir__small_float ) )
return 0 ;
// are either of the ranges completely out of bounds?
if ( ( * output_offset > = output_full_range ) | | ( ( * output_offset + output_sub_range ) < = 0 ) | | ( input_s0 > = ( 1.0f - stbir__small_float ) ) | | ( input_s1 < = stbir__small_float ) )
return 0 ;
output_range = ( double ) output_full_range ;
input_range = ( double ) input_full_range ;
output_s = ( ( double ) output_sub_range ) / output_range ;
// figure out the scaling to use
ratio = output_s / input_s ;
// save scale before clipping
scale = ( output_range / input_range ) * ratio ;
scale_info - > scale = ( float ) scale ;
scale_info - > inv_scale = ( float ) ( 1.0 / scale ) ;
// clip output area to left/right output edges (and adjust input area)
stbir__clip ( output_offset , & output_sub_range , output_full_range , & input_s0 , & input_s1 ) ;
// recalc input area
input_s = input_s1 - input_s0 ;
// after clipping do we have zero input area?
if ( input_s < = stbir__small_float )
return 0 ;
// calculate and store the starting source offsets in output pixel space
scale_info - > pixel_shift = ( float ) ( input_s0 * ratio * output_range ) ;
scale_info - > scale_is_rational = stbir__double_to_rational ( scale , ( scale < = 1.0 ) ? output_full_range : input_full_range , & scale_info - > scale_numerator , & scale_info - > scale_denominator , ( scale > = 1.0 ) ) ;
scale_info - > input_full_size = input_full_range ;
scale_info - > output_sub_size = output_sub_range ;
return 1 ;
}
static void stbir__init_and_set_layout ( STBIR_RESIZE * resize , stbir_pixel_layout pixel_layout , stbir_datatype data_type )
{
resize - > input_cb = 0 ;
resize - > output_cb = 0 ;
resize - > user_data = resize ;
resize - > samplers = 0 ;
resize - > called_alloc = 0 ;
resize - > horizontal_filter = STBIR_FILTER_DEFAULT ;
resize - > horizontal_filter_kernel = 0 ; resize - > horizontal_filter_support = 0 ;
resize - > vertical_filter = STBIR_FILTER_DEFAULT ;
resize - > vertical_filter_kernel = 0 ; resize - > vertical_filter_support = 0 ;
resize - > horizontal_edge = STBIR_EDGE_CLAMP ;
resize - > vertical_edge = STBIR_EDGE_CLAMP ;
resize - > input_s0 = 0 ; resize - > input_t0 = 0 ; resize - > input_s1 = 1 ; resize - > input_t1 = 1 ;
resize - > output_subx = 0 ; resize - > output_suby = 0 ; resize - > output_subw = resize - > output_w ; resize - > output_subh = resize - > output_h ;
resize - > input_data_type = data_type ;
resize - > output_data_type = data_type ;
resize - > input_pixel_layout_public = pixel_layout ;
resize - > output_pixel_layout_public = pixel_layout ;
resize - > needs_rebuild = 1 ;
}
STBIRDEF void stbir_resize_init ( STBIR_RESIZE * resize ,
const void * input_pixels , int input_w , int input_h , int input_stride_in_bytes , // stride can be zero
void * output_pixels , int output_w , int output_h , int output_stride_in_bytes , // stride can be zero
stbir_pixel_layout pixel_layout , stbir_datatype data_type )
{
resize - > input_pixels = input_pixels ;
resize - > input_w = input_w ;
resize - > input_h = input_h ;
resize - > input_stride_in_bytes = input_stride_in_bytes ;
resize - > output_pixels = output_pixels ;
resize - > output_w = output_w ;
resize - > output_h = output_h ;
resize - > output_stride_in_bytes = output_stride_in_bytes ;
resize - > fast_alpha = 0 ;
stbir__init_and_set_layout ( resize , pixel_layout , data_type ) ;
}
// You can update parameters any time after resize_init
STBIRDEF void stbir_set_datatypes ( STBIR_RESIZE * resize , stbir_datatype input_type , stbir_datatype output_type ) // by default, datatype from resize_init
{
resize - > input_data_type = input_type ;
resize - > output_data_type = output_type ;
if ( ( resize - > samplers ) & & ( ! resize - > needs_rebuild ) )
stbir__update_info_from_resize ( resize - > samplers , resize ) ;
}
STBIRDEF void stbir_set_pixel_callbacks ( STBIR_RESIZE * resize , stbir_input_callback * input_cb , stbir_output_callback * output_cb ) // no callbacks by default
{
resize - > input_cb = input_cb ;
resize - > output_cb = output_cb ;
if ( ( resize - > samplers ) & & ( ! resize - > needs_rebuild ) )
{
resize - > samplers - > in_pixels_cb = input_cb ;
resize - > samplers - > out_pixels_cb = output_cb ;
}
}
STBIRDEF void stbir_set_user_data ( STBIR_RESIZE * resize , void * user_data ) // pass back STBIR_RESIZE* by default
{
resize - > user_data = user_data ;
if ( ( resize - > samplers ) & & ( ! resize - > needs_rebuild ) )
resize - > samplers - > user_data = user_data ;
}
STBIRDEF void stbir_set_buffer_ptrs ( STBIR_RESIZE * resize , const void * input_pixels , int input_stride_in_bytes , void * output_pixels , int output_stride_in_bytes )
{
resize - > input_pixels = input_pixels ;
resize - > input_stride_in_bytes = input_stride_in_bytes ;
resize - > output_pixels = output_pixels ;
resize - > output_stride_in_bytes = output_stride_in_bytes ;
if ( ( resize - > samplers ) & & ( ! resize - > needs_rebuild ) )
stbir__update_info_from_resize ( resize - > samplers , resize ) ;
}
STBIRDEF int stbir_set_edgemodes ( STBIR_RESIZE * resize , stbir_edge horizontal_edge , stbir_edge vertical_edge ) // CLAMP by default
{
resize - > horizontal_edge = horizontal_edge ;
resize - > vertical_edge = vertical_edge ;
resize - > needs_rebuild = 1 ;
return 1 ;
}
STBIRDEF int stbir_set_filters ( STBIR_RESIZE * resize , stbir_filter horizontal_filter , stbir_filter vertical_filter ) // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default
{
resize - > horizontal_filter = horizontal_filter ;
resize - > vertical_filter = vertical_filter ;
resize - > needs_rebuild = 1 ;
return 1 ;
}
STBIRDEF int stbir_set_filter_callbacks ( STBIR_RESIZE * resize , stbir__kernel_callback * horizontal_filter , stbir__support_callback * horizontal_support , stbir__kernel_callback * vertical_filter , stbir__support_callback * vertical_support )
{
resize - > horizontal_filter_kernel = horizontal_filter ; resize - > horizontal_filter_support = horizontal_support ;
resize - > vertical_filter_kernel = vertical_filter ; resize - > vertical_filter_support = vertical_support ;
resize - > needs_rebuild = 1 ;
return 1 ;
}
STBIRDEF int stbir_set_pixel_layouts ( STBIR_RESIZE * resize , stbir_pixel_layout input_pixel_layout , stbir_pixel_layout output_pixel_layout ) // sets new pixel layouts
{
resize - > input_pixel_layout_public = input_pixel_layout ;
resize - > output_pixel_layout_public = output_pixel_layout ;
resize - > needs_rebuild = 1 ;
return 1 ;
}
STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality ( STBIR_RESIZE * resize , int non_pma_alpha_speed_over_quality ) // sets alpha speed
{
resize - > fast_alpha = non_pma_alpha_speed_over_quality ;
resize - > needs_rebuild = 1 ;
return 1 ;
}
STBIRDEF int stbir_set_input_subrect ( STBIR_RESIZE * resize , double s0 , double t0 , double s1 , double t1 ) // sets input region (full region by default)
{
resize - > input_s0 = s0 ;
resize - > input_t0 = t0 ;
resize - > input_s1 = s1 ;
resize - > input_t1 = t1 ;
resize - > needs_rebuild = 1 ;
// are we inbounds?
if ( ( s1 < stbir__small_float ) | | ( ( s1 - s0 ) < stbir__small_float ) | |
( t1 < stbir__small_float ) | | ( ( t1 - t0 ) < stbir__small_float ) | |
( s0 > ( 1.0f - stbir__small_float ) ) | |
( t0 > ( 1.0f - stbir__small_float ) ) )
return 0 ;
return 1 ;
}
STBIRDEF int stbir_set_output_pixel_subrect ( STBIR_RESIZE * resize , int subx , int suby , int subw , int subh ) // sets input region (full region by default)
{
resize - > output_subx = subx ;
resize - > output_suby = suby ;
resize - > output_subw = subw ;
resize - > output_subh = subh ;
resize - > needs_rebuild = 1 ;
// are we inbounds?
if ( ( subx > = resize - > output_w ) | | ( ( subx + subw ) < = 0 ) | | ( suby > = resize - > output_h ) | | ( ( suby + subh ) < = 0 ) | | ( subw = = 0 ) | | ( subh = = 0 ) )
return 0 ;
return 1 ;
}
STBIRDEF int stbir_set_pixel_subrect ( STBIR_RESIZE * resize , int subx , int suby , int subw , int subh ) // sets both regions (full regions by default)
{
double s0 , t0 , s1 , t1 ;
s0 = ( ( double ) subx ) / ( ( double ) resize - > output_w ) ;
t0 = ( ( double ) suby ) / ( ( double ) resize - > output_h ) ;
s1 = ( ( double ) ( subx + subw ) ) / ( ( double ) resize - > output_w ) ;
t1 = ( ( double ) ( suby + subh ) ) / ( ( double ) resize - > output_h ) ;
resize - > input_s0 = s0 ;
resize - > input_t0 = t0 ;
resize - > input_s1 = s1 ;
resize - > input_t1 = t1 ;
resize - > output_subx = subx ;
resize - > output_suby = suby ;
resize - > output_subw = subw ;
resize - > output_subh = subh ;
resize - > needs_rebuild = 1 ;
// are we inbounds?
if ( ( subx > = resize - > output_w ) | | ( ( subx + subw ) < = 0 ) | | ( suby > = resize - > output_h ) | | ( ( suby + subh ) < = 0 ) | | ( subw = = 0 ) | | ( subh = = 0 ) )
return 0 ;
return 1 ;
}
static int stbir__perform_build ( STBIR_RESIZE * resize , int splits )
{
stbir__contributors conservative = { 0 , 0 } ;
stbir__sampler horizontal , vertical ;
int new_output_subx , new_output_suby ;
stbir__info * out_info ;
# ifdef STBIR_PROFILE
stbir__info profile_infod ; // used to contain building profile info before everything is allocated
stbir__info * profile_info = & profile_infod ;
# endif
// have we already built the samplers?
if ( resize - > samplers )
return 0 ;
# define STBIR_RETURN_ERROR_AND_ASSERT( exp ) STBIR_ASSERT( !(exp) ); if (exp) return 0;
STBIR_RETURN_ERROR_AND_ASSERT ( ( unsigned ) resize - > horizontal_filter > = STBIR_FILTER_OTHER )
STBIR_RETURN_ERROR_AND_ASSERT ( ( unsigned ) resize - > vertical_filter > = STBIR_FILTER_OTHER )
# undef STBIR_RETURN_ERROR_AND_ASSERT
if ( splits < = 0 )
return 0 ;
STBIR_PROFILE_BUILD_FIRST_START ( build ) ;
new_output_subx = resize - > output_subx ;
new_output_suby = resize - > output_suby ;
// do horizontal clip and scale calcs
if ( ! stbir__calculate_region_transform ( & horizontal . scale_info , resize - > output_w , & new_output_subx , resize - > output_subw , resize - > input_w , resize - > input_s0 , resize - > input_s1 ) )
return 0 ;
// do vertical clip and scale calcs
if ( ! stbir__calculate_region_transform ( & vertical . scale_info , resize - > output_h , & new_output_suby , resize - > output_subh , resize - > input_h , resize - > input_t0 , resize - > input_t1 ) )
return 0 ;
// if nothing to do, just return
if ( ( horizontal . scale_info . output_sub_size = = 0 ) | | ( vertical . scale_info . output_sub_size = = 0 ) )
return 0 ;
stbir__set_sampler ( & horizontal , resize - > horizontal_filter , resize - > horizontal_filter_kernel , resize - > horizontal_filter_support , resize - > horizontal_edge , & horizontal . scale_info , 1 , resize - > user_data ) ;
stbir__get_conservative_extents ( & horizontal , & conservative , resize - > user_data ) ;
stbir__set_sampler ( & vertical , resize - > vertical_filter , resize - > horizontal_filter_kernel , resize - > vertical_filter_support , resize - > vertical_edge , & vertical . scale_info , 0 , resize - > user_data ) ;
if ( ( vertical . scale_info . output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice)
{
splits = vertical . scale_info . output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ;
if ( splits = = 0 ) splits = 1 ;
}
STBIR_PROFILE_BUILD_START ( alloc ) ;
out_info = stbir__alloc_internal_mem_and_build_samplers ( & horizontal , & vertical , & conservative , resize - > input_pixel_layout_public , resize - > output_pixel_layout_public , splits , new_output_subx , new_output_suby , resize - > fast_alpha , resize - > user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ) ;
STBIR_PROFILE_BUILD_END ( alloc ) ;
STBIR_PROFILE_BUILD_END ( build ) ;
if ( out_info )
{
resize - > splits = splits ;
resize - > samplers = out_info ;
resize - > needs_rebuild = 0 ;
# ifdef STBIR_PROFILE
STBIR_MEMCPY ( & out_info - > profile , & profile_infod . profile , sizeof ( out_info - > profile ) ) ;
# endif
// update anything that can be changed without recalcing samplers
stbir__update_info_from_resize ( out_info , resize ) ;
return splits ;
}
return 0 ;
}
void stbir_free_samplers ( STBIR_RESIZE * resize )
{
if ( resize - > samplers )
{
stbir__free_internal_mem ( resize - > samplers ) ;
resize - > samplers = 0 ;
resize - > called_alloc = 0 ;
}
}
STBIRDEF int stbir_build_samplers_with_splits ( STBIR_RESIZE * resize , int splits )
{
if ( ( resize - > samplers = = 0 ) | | ( resize - > needs_rebuild ) )
{
if ( resize - > samplers )
stbir_free_samplers ( resize ) ;
resize - > called_alloc = 1 ;
return stbir__perform_build ( resize , splits ) ;
}
STBIR_PROFILE_BUILD_CLEAR ( resize - > samplers ) ;
return 1 ;
}
STBIRDEF int stbir_build_samplers ( STBIR_RESIZE * resize )
{
return stbir_build_samplers_with_splits ( resize , 1 ) ;
}
STBIRDEF int stbir_resize_extended ( STBIR_RESIZE * resize )
{
int result ;
if ( ( resize - > samplers = = 0 ) | | ( resize - > needs_rebuild ) )
{
int alloc_state = resize - > called_alloc ; // remember allocated state
if ( resize - > samplers )
{
stbir__free_internal_mem ( resize - > samplers ) ;
resize - > samplers = 0 ;
}
if ( ! stbir_build_samplers ( resize ) )
return 0 ;
resize - > called_alloc = alloc_state ;
// if build_samplers succeeded (above), but there are no samplers set, then
// the area to stretch into was zero pixels, so don't do anything and return
// success
if ( resize - > samplers = = 0 )
return 1 ;
}
else
{
// didn't build anything - clear it
STBIR_PROFILE_BUILD_CLEAR ( resize - > samplers ) ;
}
// do resize
result = stbir__perform_resize ( resize - > samplers , 0 , resize - > splits ) ;
// if we alloced, then free
if ( ! resize - > called_alloc )
{
stbir_free_samplers ( resize ) ;
resize - > samplers = 0 ;
}
return result ;
}
STBIRDEF int stbir_resize_extended_split ( STBIR_RESIZE * resize , int split_start , int split_count )
{
STBIR_ASSERT ( resize - > samplers ) ;
// if we're just doing the whole thing, call full
if ( ( split_start = = - 1 ) | | ( ( split_start = = 0 ) & & ( split_count = = resize - > splits ) ) )
return stbir_resize_extended ( resize ) ;
// you **must** build samplers first when using split resize
if ( ( resize - > samplers = = 0 ) | | ( resize - > needs_rebuild ) )
return 0 ;
if ( ( split_start > = resize - > splits ) | | ( split_start < 0 ) | | ( ( split_start + split_count ) > resize - > splits ) | | ( split_count < = 0 ) )
return 0 ;
// do resize
return stbir__perform_resize ( resize - > samplers , split_start , split_count ) ;
}
static int stbir__check_output_stuff ( void * * ret_ptr , int * ret_pitch , void * output_pixels , int type_size , int output_w , int output_h , int output_stride_in_bytes , stbir_internal_pixel_layout pixel_layout )
{
size_t size ;
int pitch ;
void * ptr ;
pitch = output_w * type_size * stbir__pixel_channels [ pixel_layout ] ;
if ( pitch = = 0 )
return 0 ;
if ( output_stride_in_bytes = = 0 )
output_stride_in_bytes = pitch ;
if ( output_stride_in_bytes < pitch )
return 0 ;
size = output_stride_in_bytes * output_h ;
if ( size = = 0 )
return 0 ;
* ret_ptr = 0 ;
* ret_pitch = output_stride_in_bytes ;
if ( output_pixels = = 0 )
{
ptr = STBIR_MALLOC ( size , 0 ) ;
if ( ptr = = 0 )
return 0 ;
* ret_ptr = ptr ;
* ret_pitch = pitch ;
}
return 1 ;
}
STBIRDEF unsigned char * stbir_resize_uint8_linear ( const unsigned char * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
unsigned char * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_layout )
{
STBIR_RESIZE resize ;
unsigned char * optr ;
int opitch ;
if ( ! stbir__check_output_stuff ( ( void * * ) & optr , & opitch , output_pixels , sizeof ( unsigned char ) , output_w , output_h , output_stride_in_bytes , stbir__pixel_layout_convert_public_to_internal [ pixel_layout ] ) )
return 0 ;
stbir_resize_init ( & resize ,
input_pixels , input_w , input_h , input_stride_in_bytes ,
( optr ) ? optr : output_pixels , output_w , output_h , opitch ,
pixel_layout , STBIR_TYPE_UINT8 ) ;
if ( ! stbir_resize_extended ( & resize ) )
{
if ( optr )
STBIR_FREE ( optr , 0 ) ;
return 0 ;
}
return ( optr ) ? optr : output_pixels ;
}
STBIRDEF unsigned char * stbir_resize_uint8_srgb ( const unsigned char * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
unsigned char * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_layout )
{
STBIR_RESIZE resize ;
unsigned char * optr ;
int opitch ;
if ( ! stbir__check_output_stuff ( ( void * * ) & optr , & opitch , output_pixels , sizeof ( unsigned char ) , output_w , output_h , output_stride_in_bytes , stbir__pixel_layout_convert_public_to_internal [ pixel_layout ] ) )
return 0 ;
stbir_resize_init ( & resize ,
input_pixels , input_w , input_h , input_stride_in_bytes ,
( optr ) ? optr : output_pixels , output_w , output_h , opitch ,
pixel_layout , STBIR_TYPE_UINT8_SRGB ) ;
if ( ! stbir_resize_extended ( & resize ) )
{
if ( optr )
STBIR_FREE ( optr , 0 ) ;
return 0 ;
}
return ( optr ) ? optr : output_pixels ;
}
STBIRDEF float * stbir_resize_float_linear ( const float * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
float * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_layout )
{
STBIR_RESIZE resize ;
float * optr ;
int opitch ;
if ( ! stbir__check_output_stuff ( ( void * * ) & optr , & opitch , output_pixels , sizeof ( float ) , output_w , output_h , output_stride_in_bytes , stbir__pixel_layout_convert_public_to_internal [ pixel_layout ] ) )
return 0 ;
stbir_resize_init ( & resize ,
input_pixels , input_w , input_h , input_stride_in_bytes ,
( optr ) ? optr : output_pixels , output_w , output_h , opitch ,
pixel_layout , STBIR_TYPE_FLOAT ) ;
if ( ! stbir_resize_extended ( & resize ) )
{
if ( optr )
STBIR_FREE ( optr , 0 ) ;
return 0 ;
}
return ( optr ) ? optr : output_pixels ;
}
STBIRDEF void * stbir_resize ( const void * input_pixels , int input_w , int input_h , int input_stride_in_bytes ,
void * output_pixels , int output_w , int output_h , int output_stride_in_bytes ,
stbir_pixel_layout pixel_layout , stbir_datatype data_type ,
stbir_edge edge , stbir_filter filter )
{
STBIR_RESIZE resize ;
float * optr ;
int opitch ;
if ( ! stbir__check_output_stuff ( ( void * * ) & optr , & opitch , output_pixels , stbir__type_size [ data_type ] , output_w , output_h , output_stride_in_bytes , stbir__pixel_layout_convert_public_to_internal [ pixel_layout ] ) )
return 0 ;
stbir_resize_init ( & resize ,
input_pixels , input_w , input_h , input_stride_in_bytes ,
( optr ) ? optr : output_pixels , output_w , output_h , output_stride_in_bytes ,
pixel_layout , data_type ) ;
resize . horizontal_edge = edge ;
resize . vertical_edge = edge ;
resize . horizontal_filter = filter ;
resize . vertical_filter = filter ;
if ( ! stbir_resize_extended ( & resize ) )
{
if ( optr )
STBIR_FREE ( optr , 0 ) ;
return 0 ;
}
return ( optr ) ? optr : output_pixels ;
}
# ifdef STBIR_PROFILE
STBIRDEF void stbir_resize_build_profile_info ( STBIR_PROFILE_INFO * info , STBIR_RESIZE const * resize )
{
static char const * bdescriptions [ 6 ] = { " Building " , " Allocating " , " Horizontal sampler " , " Vertical sampler " , " Coefficient cleanup " , " Coefficient piovot " } ;
stbir__info * samp = resize - > samplers ;
int i ;
typedef int testa [ ( STBIR__ARRAY_SIZE ( bdescriptions ) = = ( STBIR__ARRAY_SIZE ( samp - > profile . array ) - 1 ) ) ? 1 : - 1 ] ;
typedef int testb [ ( sizeof ( samp - > profile . array ) = = ( sizeof ( samp - > profile . named ) ) ) ? 1 : - 1 ] ;
typedef int testc [ ( sizeof ( info - > clocks ) > = ( sizeof ( samp - > profile . named ) ) ) ? 1 : - 1 ] ;
for ( i = 0 ; i < STBIR__ARRAY_SIZE ( bdescriptions ) ; i + + )
info - > clocks [ i ] = samp - > profile . array [ i + 1 ] ;
info - > total_clocks = samp - > profile . named . total ;
info - > descriptions = bdescriptions ;
info - > count = STBIR__ARRAY_SIZE ( bdescriptions ) ;
}
STBIRDEF void stbir_resize_split_profile_info ( STBIR_PROFILE_INFO * info , STBIR_RESIZE const * resize , int split_start , int split_count )
{
static char const * descriptions [ 7 ] = { " Looping " , " Vertical sampling " , " Horizontal sampling " , " Scanline input " , " Scanline output " , " Alpha weighting " , " Alpha unweighting " } ;
stbir__per_split_info * split_info ;
int s , i ;
typedef int testa [ ( STBIR__ARRAY_SIZE ( descriptions ) = = ( STBIR__ARRAY_SIZE ( split_info - > profile . array ) - 1 ) ) ? 1 : - 1 ] ;
typedef int testb [ ( sizeof ( split_info - > profile . array ) = = ( sizeof ( split_info - > profile . named ) ) ) ? 1 : - 1 ] ;
typedef int testc [ ( sizeof ( info - > clocks ) > = ( sizeof ( split_info - > profile . named ) ) ) ? 1 : - 1 ] ;
if ( split_start = = - 1 )
{
split_start = 0 ;
split_count = resize - > samplers - > splits ;
}
if ( ( split_start > = resize - > splits ) | | ( split_start < 0 ) | | ( ( split_start + split_count ) > resize - > splits ) | | ( split_count < = 0 ) )
{
info - > total_clocks = 0 ;
info - > descriptions = 0 ;
info - > count = 0 ;
return ;
}
split_info = resize - > samplers - > split_info + split_start ;
// sum up the profile from all the splits
for ( i = 0 ; i < STBIR__ARRAY_SIZE ( descriptions ) ; i + + )
{
stbir_uint64 sum = 0 ;
for ( s = 0 ; s < split_count ; s + + )
sum + = split_info [ s ] . profile . array [ i + 1 ] ;
info - > clocks [ i ] = sum ;
}
info - > total_clocks = split_info - > profile . named . total ;
info - > descriptions = descriptions ;
info - > count = STBIR__ARRAY_SIZE ( descriptions ) ;
}
STBIRDEF void stbir_resize_extended_profile_info ( STBIR_PROFILE_INFO * info , STBIR_RESIZE const * resize )
{
stbir_resize_split_profile_info ( info , resize , - 1 , 0 ) ;
}
# endif // STBIR_PROFILE
# undef STBIR_BGR
# undef STBIR_1CHANNEL
# undef STBIR_2CHANNEL
# undef STBIR_RGB
# undef STBIR_RGBA
# undef STBIR_4CHANNEL
# undef STBIR_BGRA
# undef STBIR_ARGB
# undef STBIR_ABGR
# undef STBIR_RA
# undef STBIR_AR
# undef STBIR_RGBA_PM
# undef STBIR_BGRA_PM
# undef STBIR_ARGB_PM
# undef STBIR_ABGR_PM
# undef STBIR_RA_PM
# undef STBIR_AR_PM
# endif // STB_IMAGE_RESIZE_IMPLEMENTATION
# else // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS
// we reinclude the header file to define all the horizontal functions
// specializing each function for the number of coeffs is 20-40% faster *OVERALL*
// by including the header file again this way, we can still debug the functions
# define STBIR_strs_join2( start, mid, end ) start##mid##end
# define STBIR_strs_join1( start, mid, end ) STBIR_strs_join2( start, mid, end )
# define STBIR_strs_join24( start, mid1, mid2, end ) start##mid1##mid2##end
# define STBIR_strs_join14( start, mid1, mid2, end ) STBIR_strs_join24( start, mid1, mid2, end )
# ifdef STB_IMAGE_RESIZE_DO_CODERS
# ifdef stbir__decode_suffix
# define STBIR__CODER_NAME( name ) STBIR_strs_join1( name, _, stbir__decode_suffix )
# else
# define STBIR__CODER_NAME( name ) name
# endif
# ifdef stbir__decode_swizzle
# define stbir__decode_simdf8_flip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3),stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)
# define stbir__decode_simdf4_flip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)
# define stbir__encode_simdf8_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3),stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)
# define stbir__encode_simdf4_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)
# else
# define stbir__decode_order0 0
# define stbir__decode_order1 1
# define stbir__decode_order2 2
# define stbir__decode_order3 3
# define stbir__encode_order0 0
# define stbir__encode_order1 1
# define stbir__encode_order2 2
# define stbir__encode_order3 3
# define stbir__decode_simdf8_flip(reg)
# define stbir__decode_simdf4_flip(reg)
# define stbir__encode_simdf8_unflip(reg)
# define stbir__encode_simdf4_unflip(reg)
# endif
# ifdef STBIR_SIMD8
# define stbir__encode_simdfX_unflip stbir__encode_simdf8_unflip
# else
# define stbir__encode_simdfX_unflip stbir__encode_simdf4_unflip
# endif
static void STBIR__CODER_NAME ( stbir__decode_uint8_linear_scaled ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
unsigned char const * input = ( unsigned char const * ) inputp ;
# ifdef STBIR_SIMD
unsigned char const * end_input_m16 = input + width_times_channels - 16 ;
if ( width_times_channels > = 16 )
{
decode_end - = 16 ;
for ( ; ; )
{
# ifdef STBIR_SIMD8
stbir__simdi i ; stbir__simdi8 o0 , o1 ;
stbir__simdf8 of0 , of1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi8_expand_u8_to_u32 ( o0 , o1 , i ) ;
stbir__simdi8_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi8_convert_i32_to_float ( of1 , o1 ) ;
stbir__simdf8_mult ( of0 , of0 , STBIR_max_uint8_as_float_inverted8 ) ;
stbir__simdf8_mult ( of1 , of1 , STBIR_max_uint8_as_float_inverted8 ) ;
stbir__decode_simdf8_flip ( of0 ) ;
stbir__decode_simdf8_flip ( of1 ) ;
stbir__simdf8_store ( decode + 0 , of0 ) ;
stbir__simdf8_store ( decode + 8 , of1 ) ;
# else
stbir__simdi i , o0 , o1 , o2 , o3 ;
stbir__simdf of0 , of1 , of2 , of3 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi_expand_u8_to_u32 ( o0 , o1 , o2 , o3 , i ) ;
stbir__simdi_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi_convert_i32_to_float ( of1 , o1 ) ;
stbir__simdi_convert_i32_to_float ( of2 , o2 ) ;
stbir__simdi_convert_i32_to_float ( of3 , o3 ) ;
stbir__simdf_mult ( of0 , of0 , STBIR__CONSTF ( STBIR_max_uint8_as_float_inverted ) ) ;
stbir__simdf_mult ( of1 , of1 , STBIR__CONSTF ( STBIR_max_uint8_as_float_inverted ) ) ;
stbir__simdf_mult ( of2 , of2 , STBIR__CONSTF ( STBIR_max_uint8_as_float_inverted ) ) ;
stbir__simdf_mult ( of3 , of3 , STBIR__CONSTF ( STBIR_max_uint8_as_float_inverted ) ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__decode_simdf4_flip ( of2 ) ;
stbir__decode_simdf4_flip ( of3 ) ;
stbir__simdf_store ( decode + 0 , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
stbir__simdf_store ( decode + 8 , of2 ) ;
stbir__simdf_store ( decode + 12 , of3 ) ;
# endif
decode + = 16 ;
input + = 16 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 16 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m16 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) * stbir__max_uint8_as_float_inverted ;
decode [ 1 - 4 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) * stbir__max_uint8_as_float_inverted ;
decode [ 2 - 4 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) * stbir__max_uint8_as_float_inverted ;
decode [ 3 - 4 ] = ( ( float ) ( input [ stbir__decode_order3 ] ) ) * stbir__max_uint8_as_float_inverted ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) * stbir__max_uint8_as_float_inverted ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) * stbir__max_uint8_as_float_inverted ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) * stbir__max_uint8_as_float_inverted ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_uint8_linear_scaled ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned char STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned char * ) outputp ;
unsigned char * end_output = ( ( unsigned char * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
if ( width_times_channels > = stbir__simdfX_float_count * 2 )
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count * 2 ;
end_output - = stbir__simdfX_float_count * 2 ;
for ( ; ; )
{
stbir__simdfX e0 , e1 ;
stbir__simdi i ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdfX_madd_mem ( e0 , STBIR_simd_point5X , STBIR_max_uint8_as_floatX , encode ) ;
stbir__simdfX_madd_mem ( e1 , STBIR_simd_point5X , STBIR_max_uint8_as_floatX , encode + stbir__simdfX_float_count ) ;
stbir__encode_simdfX_unflip ( e0 ) ;
stbir__encode_simdfX_unflip ( e1 ) ;
# ifdef STBIR_SIMD8
stbir__simdf8_pack_to_16bytes ( i , e0 , e1 ) ;
stbir__simdi_store ( output , i ) ;
# else
stbir__simdf_pack_to_8bytes ( i , e0 , e1 ) ;
stbir__simdi_store2 ( output , i ) ;
# endif
encode + = stbir__simdfX_float_count * 2 ;
output + = stbir__simdfX_float_count * 2 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + stbir__simdfX_float_count * 2 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
stbir__simdf e0 ;
stbir__simdi i0 ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_load ( e0 , encode ) ;
stbir__simdf_madd ( e0 , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint8_as_float ) , e0 ) ;
stbir__encode_simdf4_unflip ( e0 ) ;
stbir__simdf_pack_to_8bytes ( i0 , e0 , e0 ) ; // only use first 4
* ( int * ) ( output - 4 ) = stbir__simdi_to_int ( i0 ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
stbir__simdf e0 ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_madd1_mem ( e0 , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint8_as_float ) , encode + stbir__encode_order0 ) ; output [ 0 ] = stbir__simdf_convert_float_to_uint8 ( e0 ) ;
# if stbir__coder_min_num >= 2
stbir__simdf_madd1_mem ( e0 , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint8_as_float ) , encode + stbir__encode_order1 ) ; output [ 1 ] = stbir__simdf_convert_float_to_uint8 ( e0 ) ;
# endif
# if stbir__coder_min_num >= 3
stbir__simdf_madd1_mem ( e0 , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint8_as_float ) , encode + stbir__encode_order2 ) ; output [ 2 ] = stbir__simdf_convert_float_to_uint8 ( e0 ) ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
# else
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
float f ;
f = encode [ stbir__encode_order0 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 0 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order1 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 1 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order2 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 2 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order3 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 3 - 4 ] = ( unsigned char ) f ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
float f ;
STBIR_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 0 ] = ( unsigned char ) f ;
# if stbir__coder_min_num >= 2
f = encode [ stbir__encode_order1 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 1 ] = ( unsigned char ) f ;
# endif
# if stbir__coder_min_num >= 3
f = encode [ stbir__encode_order2 ] * stbir__max_uint8_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 2 ] = ( unsigned char ) f ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
# endif
}
static void STBIR__CODER_NAME ( stbir__decode_uint8_linear ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
unsigned char const * input = ( unsigned char const * ) inputp ;
# ifdef STBIR_SIMD
unsigned char const * end_input_m16 = input + width_times_channels - 16 ;
if ( width_times_channels > = 16 )
{
decode_end - = 16 ;
for ( ; ; )
{
# ifdef STBIR_SIMD8
stbir__simdi i ; stbir__simdi8 o0 , o1 ;
stbir__simdf8 of0 , of1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi8_expand_u8_to_u32 ( o0 , o1 , i ) ;
stbir__simdi8_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi8_convert_i32_to_float ( of1 , o1 ) ;
stbir__decode_simdf8_flip ( of0 ) ;
stbir__decode_simdf8_flip ( of1 ) ;
stbir__simdf8_store ( decode + 0 , of0 ) ;
stbir__simdf8_store ( decode + 8 , of1 ) ;
# else
stbir__simdi i , o0 , o1 , o2 , o3 ;
stbir__simdf of0 , of1 , of2 , of3 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi_expand_u8_to_u32 ( o0 , o1 , o2 , o3 , i ) ;
stbir__simdi_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi_convert_i32_to_float ( of1 , o1 ) ;
stbir__simdi_convert_i32_to_float ( of2 , o2 ) ;
stbir__simdi_convert_i32_to_float ( of3 , o3 ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__decode_simdf4_flip ( of2 ) ;
stbir__decode_simdf4_flip ( of3 ) ;
stbir__simdf_store ( decode + 0 , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
stbir__simdf_store ( decode + 8 , of2 ) ;
stbir__simdf_store ( decode + 12 , of3 ) ;
# endif
decode + = 16 ;
input + = 16 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 16 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m16 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) ;
decode [ 1 - 4 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) ;
decode [ 2 - 4 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) ;
decode [ 3 - 4 ] = ( ( float ) ( input [ stbir__decode_order3 ] ) ) ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_uint8_linear ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned char STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned char * ) outputp ;
unsigned char * end_output = ( ( unsigned char * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
if ( width_times_channels > = stbir__simdfX_float_count * 2 )
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count * 2 ;
end_output - = stbir__simdfX_float_count * 2 ;
for ( ; ; )
{
stbir__simdfX e0 , e1 ;
stbir__simdi i ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdfX_add_mem ( e0 , STBIR_simd_point5X , encode ) ;
stbir__simdfX_add_mem ( e1 , STBIR_simd_point5X , encode + stbir__simdfX_float_count ) ;
stbir__encode_simdfX_unflip ( e0 ) ;
stbir__encode_simdfX_unflip ( e1 ) ;
# ifdef STBIR_SIMD8
stbir__simdf8_pack_to_16bytes ( i , e0 , e1 ) ;
stbir__simdi_store ( output , i ) ;
# else
stbir__simdf_pack_to_8bytes ( i , e0 , e1 ) ;
stbir__simdi_store2 ( output , i ) ;
# endif
encode + = stbir__simdfX_float_count * 2 ;
output + = stbir__simdfX_float_count * 2 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + stbir__simdfX_float_count * 2 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
stbir__simdf e0 ;
stbir__simdi i0 ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_load ( e0 , encode ) ;
stbir__simdf_add ( e0 , STBIR__CONSTF ( STBIR_simd_point5 ) , e0 ) ;
stbir__encode_simdf4_unflip ( e0 ) ;
stbir__simdf_pack_to_8bytes ( i0 , e0 , e0 ) ; // only use first 4
* ( int * ) ( output - 4 ) = stbir__simdi_to_int ( i0 ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# else
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
float f ;
f = encode [ stbir__encode_order0 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 0 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order1 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 1 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order2 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 2 - 4 ] = ( unsigned char ) f ;
f = encode [ stbir__encode_order3 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 3 - 4 ] = ( unsigned char ) f ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
float f ;
STBIR_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 0 ] = ( unsigned char ) f ;
# if stbir__coder_min_num >= 2
f = encode [ stbir__encode_order1 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 1 ] = ( unsigned char ) f ;
# endif
# if stbir__coder_min_num >= 3
f = encode [ stbir__encode_order2 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 255 ) ; output [ 2 ] = ( unsigned char ) f ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__decode_uint8_srgb ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float const * decode_end = ( float * ) decode + width_times_channels ;
unsigned char const * input = ( unsigned char const * ) inputp ;
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
decode [ 0 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order0 ] ] ;
decode [ 1 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order1 ] ] ;
decode [ 2 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order2 ] ] ;
decode [ 3 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order3 ] ] ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order0 ] ] ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order1 ] ] ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order2 ] ] ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
# define stbir__min_max_shift20( i, f ) \
stbir__simdf_max ( f , f , stbir_simdf_casti ( STBIR__CONSTI ( STBIR_almost_zero ) ) ) ; \
stbir__simdf_min ( f , f , stbir_simdf_casti ( STBIR__CONSTI ( STBIR_almost_one ) ) ) ; \
stbir__simdi_32shr ( i , stbir_simdi_castf ( f ) , 20 ) ;
# define stbir__scale_and_convert( i, f ) \
stbir__simdf_madd ( f , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint8_as_float ) , f ) ; \
stbir__simdf_max ( f , f , stbir__simdf_zeroP ( ) ) ; \
stbir__simdf_min ( f , f , STBIR__CONSTF ( STBIR_max_uint8_as_float ) ) ; \
stbir__simdf_convert_float_to_i32 ( i , f ) ;
# define stbir__linear_to_srgb_finish( i, f ) \
{ \
stbir__simdi temp ; \
stbir__simdi_32shr ( temp , stbir_simdi_castf ( f ) , 12 ) ; \
stbir__simdi_and ( temp , temp , STBIR__CONSTI ( STBIR_mastissa_mask ) ) ; \
stbir__simdi_or ( temp , temp , STBIR__CONSTI ( STBIR_topscale ) ) ; \
stbir__simdi_16madd ( i , i , temp ) ; \
stbir__simdi_32shr ( i , i , 16 ) ; \
}
# define stbir__simdi_table_lookup2( v0,v1, table ) \
{ \
stbir__simdi_u32 temp0 , temp1 ; \
temp0 . m128i_i128 = v0 ; \
temp1 . m128i_i128 = v1 ; \
temp0 . m128i_u32 [ 0 ] = table [ temp0 . m128i_i32 [ 0 ] ] ; temp0 . m128i_u32 [ 1 ] = table [ temp0 . m128i_i32 [ 1 ] ] ; temp0 . m128i_u32 [ 2 ] = table [ temp0 . m128i_i32 [ 2 ] ] ; temp0 . m128i_u32 [ 3 ] = table [ temp0 . m128i_i32 [ 3 ] ] ; \
temp1 . m128i_u32 [ 0 ] = table [ temp1 . m128i_i32 [ 0 ] ] ; temp1 . m128i_u32 [ 1 ] = table [ temp1 . m128i_i32 [ 1 ] ] ; temp1 . m128i_u32 [ 2 ] = table [ temp1 . m128i_i32 [ 2 ] ] ; temp1 . m128i_u32 [ 3 ] = table [ temp1 . m128i_i32 [ 3 ] ] ; \
v0 = temp0 . m128i_i128 ; \
v1 = temp1 . m128i_i128 ; \
}
# define stbir__simdi_table_lookup3( v0,v1,v2, table ) \
{ \
stbir__simdi_u32 temp0 , temp1 , temp2 ; \
temp0 . m128i_i128 = v0 ; \
temp1 . m128i_i128 = v1 ; \
temp2 . m128i_i128 = v2 ; \
temp0 . m128i_u32 [ 0 ] = table [ temp0 . m128i_i32 [ 0 ] ] ; temp0 . m128i_u32 [ 1 ] = table [ temp0 . m128i_i32 [ 1 ] ] ; temp0 . m128i_u32 [ 2 ] = table [ temp0 . m128i_i32 [ 2 ] ] ; temp0 . m128i_u32 [ 3 ] = table [ temp0 . m128i_i32 [ 3 ] ] ; \
temp1 . m128i_u32 [ 0 ] = table [ temp1 . m128i_i32 [ 0 ] ] ; temp1 . m128i_u32 [ 1 ] = table [ temp1 . m128i_i32 [ 1 ] ] ; temp1 . m128i_u32 [ 2 ] = table [ temp1 . m128i_i32 [ 2 ] ] ; temp1 . m128i_u32 [ 3 ] = table [ temp1 . m128i_i32 [ 3 ] ] ; \
temp2 . m128i_u32 [ 0 ] = table [ temp2 . m128i_i32 [ 0 ] ] ; temp2 . m128i_u32 [ 1 ] = table [ temp2 . m128i_i32 [ 1 ] ] ; temp2 . m128i_u32 [ 2 ] = table [ temp2 . m128i_i32 [ 2 ] ] ; temp2 . m128i_u32 [ 3 ] = table [ temp2 . m128i_i32 [ 3 ] ] ; \
v0 = temp0 . m128i_i128 ; \
v1 = temp1 . m128i_i128 ; \
v2 = temp2 . m128i_i128 ; \
}
# define stbir__simdi_table_lookup4( v0,v1,v2,v3, table ) \
{ \
stbir__simdi_u32 temp0 , temp1 , temp2 , temp3 ; \
temp0 . m128i_i128 = v0 ; \
temp1 . m128i_i128 = v1 ; \
temp2 . m128i_i128 = v2 ; \
temp3 . m128i_i128 = v3 ; \
temp0 . m128i_u32 [ 0 ] = table [ temp0 . m128i_i32 [ 0 ] ] ; temp0 . m128i_u32 [ 1 ] = table [ temp0 . m128i_i32 [ 1 ] ] ; temp0 . m128i_u32 [ 2 ] = table [ temp0 . m128i_i32 [ 2 ] ] ; temp0 . m128i_u32 [ 3 ] = table [ temp0 . m128i_i32 [ 3 ] ] ; \
temp1 . m128i_u32 [ 0 ] = table [ temp1 . m128i_i32 [ 0 ] ] ; temp1 . m128i_u32 [ 1 ] = table [ temp1 . m128i_i32 [ 1 ] ] ; temp1 . m128i_u32 [ 2 ] = table [ temp1 . m128i_i32 [ 2 ] ] ; temp1 . m128i_u32 [ 3 ] = table [ temp1 . m128i_i32 [ 3 ] ] ; \
temp2 . m128i_u32 [ 0 ] = table [ temp2 . m128i_i32 [ 0 ] ] ; temp2 . m128i_u32 [ 1 ] = table [ temp2 . m128i_i32 [ 1 ] ] ; temp2 . m128i_u32 [ 2 ] = table [ temp2 . m128i_i32 [ 2 ] ] ; temp2 . m128i_u32 [ 3 ] = table [ temp2 . m128i_i32 [ 3 ] ] ; \
temp3 . m128i_u32 [ 0 ] = table [ temp3 . m128i_i32 [ 0 ] ] ; temp3 . m128i_u32 [ 1 ] = table [ temp3 . m128i_i32 [ 1 ] ] ; temp3 . m128i_u32 [ 2 ] = table [ temp3 . m128i_i32 [ 2 ] ] ; temp3 . m128i_u32 [ 3 ] = table [ temp3 . m128i_i32 [ 3 ] ] ; \
v0 = temp0 . m128i_i128 ; \
v1 = temp1 . m128i_i128 ; \
v2 = temp2 . m128i_i128 ; \
v3 = temp3 . m128i_i128 ; \
}
static void STBIR__CODER_NAME ( stbir__encode_uint8_srgb ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned char STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned char * ) outputp ;
unsigned char * end_output = ( ( unsigned char * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - ( 127 - 13 ) * 8 ;
if ( width_times_channels > = 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16 ;
end_output - = 16 ;
for ( ; ; )
{
stbir__simdf f0 , f1 , f2 , f3 ;
stbir__simdi i0 , i1 , i2 , i3 ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdf_load4_transposed ( f0 , f1 , f2 , f3 , encode ) ;
stbir__min_max_shift20 ( i0 , f0 ) ;
stbir__min_max_shift20 ( i1 , f1 ) ;
stbir__min_max_shift20 ( i2 , f2 ) ;
stbir__min_max_shift20 ( i3 , f3 ) ;
stbir__simdi_table_lookup4 ( i0 , i1 , i2 , i3 , to_srgb ) ;
stbir__linear_to_srgb_finish ( i0 , f0 ) ;
stbir__linear_to_srgb_finish ( i1 , f1 ) ;
stbir__linear_to_srgb_finish ( i2 , f2 ) ;
stbir__linear_to_srgb_finish ( i3 , f3 ) ;
stbir__interleave_pack_and_store_16_u8 ( output , STBIR_strs_join1 ( i , , stbir__encode_order0 ) , STBIR_strs_join1 ( i , , stbir__encode_order1 ) , STBIR_strs_join1 ( i , , stbir__encode_order2 ) , STBIR_strs_join1 ( i , , stbir__encode_order3 ) ) ;
encode + = 16 ;
output + = 16 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + 16 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m16 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
STBIR_SIMD_NO_UNROLL ( encode ) ;
output [ 0 - 4 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order0 ] ) ;
output [ 1 - 4 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order1 ] ) ;
output [ 2 - 4 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order2 ] ) ;
output [ 3 - 4 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order3 ] ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
STBIR_NO_UNROLL ( encode ) ;
output [ 0 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order0 ] ) ;
# if stbir__coder_min_num >= 2
output [ 1 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order1 ] ) ;
# endif
# if stbir__coder_min_num >= 3
output [ 2 ] = stbir__linear_to_srgb_uchar ( encode [ stbir__encode_order2 ] ) ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
}
# if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
static void STBIR__CODER_NAME ( stbir__decode_uint8_srgb4_linearalpha ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float const * decode_end = ( float * ) decode + width_times_channels ;
unsigned char const * input = ( unsigned char const * ) inputp ;
do {
decode [ 0 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order0 ] ] ;
decode [ 1 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order1 ] ] ;
decode [ 2 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order2 ] ] ;
decode [ 3 ] = ( ( float ) input [ stbir__decode_order3 ] ) * stbir__max_uint8_as_float_inverted ;
input + = 4 ;
decode + = 4 ;
} while ( decode < decode_end ) ;
}
static void STBIR__CODER_NAME ( stbir__encode_uint8_srgb4_linearalpha ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned char STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned char * ) outputp ;
unsigned char * end_output = ( ( unsigned char * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - ( 127 - 13 ) * 8 ;
if ( width_times_channels > = 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16 ;
end_output - = 16 ;
for ( ; ; )
{
stbir__simdf f0 , f1 , f2 , f3 ;
stbir__simdi i0 , i1 , i2 , i3 ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdf_load4_transposed ( f0 , f1 , f2 , f3 , encode ) ;
stbir__min_max_shift20 ( i0 , f0 ) ;
stbir__min_max_shift20 ( i1 , f1 ) ;
stbir__min_max_shift20 ( i2 , f2 ) ;
stbir__scale_and_convert ( i3 , f3 ) ;
stbir__simdi_table_lookup3 ( i0 , i1 , i2 , to_srgb ) ;
stbir__linear_to_srgb_finish ( i0 , f0 ) ;
stbir__linear_to_srgb_finish ( i1 , f1 ) ;
stbir__linear_to_srgb_finish ( i2 , f2 ) ;
stbir__interleave_pack_and_store_16_u8 ( output , STBIR_strs_join1 ( i , , stbir__encode_order0 ) , STBIR_strs_join1 ( i , , stbir__encode_order1 ) , STBIR_strs_join1 ( i , , stbir__encode_order2 ) , STBIR_strs_join1 ( i , , stbir__encode_order3 ) ) ;
output + = 16 ;
encode + = 16 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + 16 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m16 ;
}
return ;
}
# endif
do {
float f ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
output [ stbir__decode_order0 ] = stbir__linear_to_srgb_uchar ( encode [ 0 ] ) ;
output [ stbir__decode_order1 ] = stbir__linear_to_srgb_uchar ( encode [ 1 ] ) ;
output [ stbir__decode_order2 ] = stbir__linear_to_srgb_uchar ( encode [ 2 ] ) ;
f = encode [ 3 ] * stbir__max_uint8_as_float + 0.5f ;
STBIR_CLAMP ( f , 0 , 255 ) ;
output [ stbir__decode_order3 ] = ( unsigned char ) f ;
output + = 4 ;
encode + = 4 ;
} while ( output < end_output ) ;
}
# endif
# if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
static void STBIR__CODER_NAME ( stbir__decode_uint8_srgb2_linearalpha ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float const * decode_end = ( float * ) decode + width_times_channels ;
unsigned char const * input = ( unsigned char const * ) inputp ;
decode + = 4 ;
while ( decode < = decode_end )
{
decode [ 0 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order0 ] ] ;
decode [ 1 - 4 ] = ( ( float ) input [ stbir__decode_order1 ] ) * stbir__max_uint8_as_float_inverted ;
decode [ 2 - 4 ] = stbir__srgb_uchar_to_linear_float [ input [ stbir__decode_order0 + 2 ] ] ;
decode [ 3 - 4 ] = ( ( float ) input [ stbir__decode_order1 + 2 ] ) * stbir__max_uint8_as_float_inverted ;
input + = 4 ;
decode + = 4 ;
}
decode - = 4 ;
if ( decode < decode_end )
{
decode [ 0 ] = stbir__srgb_uchar_to_linear_float [ stbir__decode_order0 ] ;
decode [ 1 ] = ( ( float ) input [ stbir__decode_order1 ] ) * stbir__max_uint8_as_float_inverted ;
}
}
static void STBIR__CODER_NAME ( stbir__encode_uint8_srgb2_linearalpha ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned char STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned char * ) outputp ;
unsigned char * end_output = ( ( unsigned char * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
2023-12-26 15:14:24 -05:00
stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - ( 127 - 13 ) * 8 ;
2023-12-17 15:04:57 -05:00
if ( width_times_channels > = 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16 ;
end_output - = 16 ;
for ( ; ; )
{
stbir__simdf f0 , f1 , f2 , f3 ;
stbir__simdi i0 , i1 , i2 , i3 ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdf_load4_transposed ( f0 , f1 , f2 , f3 , encode ) ;
stbir__min_max_shift20 ( i0 , f0 ) ;
stbir__scale_and_convert ( i1 , f1 ) ;
stbir__min_max_shift20 ( i2 , f2 ) ;
stbir__scale_and_convert ( i3 , f3 ) ;
stbir__simdi_table_lookup2 ( i0 , i2 , to_srgb ) ;
stbir__linear_to_srgb_finish ( i0 , f0 ) ;
stbir__linear_to_srgb_finish ( i2 , f2 ) ;
stbir__interleave_pack_and_store_16_u8 ( output , STBIR_strs_join1 ( i , , stbir__encode_order0 ) , STBIR_strs_join1 ( i , , stbir__encode_order1 ) , STBIR_strs_join1 ( i , , stbir__encode_order2 ) , STBIR_strs_join1 ( i , , stbir__encode_order3 ) ) ;
output + = 16 ;
encode + = 16 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + 16 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m16 ;
}
return ;
}
# endif
do {
float f ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
output [ stbir__decode_order0 ] = stbir__linear_to_srgb_uchar ( encode [ 0 ] ) ;
f = encode [ 1 ] * stbir__max_uint8_as_float + 0.5f ;
STBIR_CLAMP ( f , 0 , 255 ) ;
output [ stbir__decode_order1 ] = ( unsigned char ) f ;
output + = 2 ;
encode + = 2 ;
} while ( output < end_output ) ;
}
# endif
static void STBIR__CODER_NAME ( stbir__decode_uint16_linear_scaled ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
unsigned short const * input = ( unsigned short const * ) inputp ;
# ifdef STBIR_SIMD
unsigned short const * end_input_m8 = input + width_times_channels - 8 ;
if ( width_times_channels > = 8 )
{
decode_end - = 8 ;
for ( ; ; )
{
# ifdef STBIR_SIMD8
stbir__simdi i ; stbir__simdi8 o ;
stbir__simdf8 of ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi8_expand_u16_to_u32 ( o , i ) ;
stbir__simdi8_convert_i32_to_float ( of , o ) ;
stbir__simdf8_mult ( of , of , STBIR_max_uint16_as_float_inverted8 ) ;
stbir__decode_simdf8_flip ( of ) ;
stbir__simdf8_store ( decode + 0 , of ) ;
# else
stbir__simdi i , o0 , o1 ;
stbir__simdf of0 , of1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi_expand_u16_to_u32 ( o0 , o1 , i ) ;
stbir__simdi_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi_convert_i32_to_float ( of1 , o1 ) ;
stbir__simdf_mult ( of0 , of0 , STBIR__CONSTF ( STBIR_max_uint16_as_float_inverted ) ) ;
stbir__simdf_mult ( of1 , of1 , STBIR__CONSTF ( STBIR_max_uint16_as_float_inverted ) ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__simdf_store ( decode + 0 , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
# endif
decode + = 8 ;
input + = 8 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 8 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m8 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) * stbir__max_uint16_as_float_inverted ;
decode [ 1 - 4 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) * stbir__max_uint16_as_float_inverted ;
decode [ 2 - 4 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) * stbir__max_uint16_as_float_inverted ;
decode [ 3 - 4 ] = ( ( float ) ( input [ stbir__decode_order3 ] ) ) * stbir__max_uint16_as_float_inverted ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) * stbir__max_uint16_as_float_inverted ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) * stbir__max_uint16_as_float_inverted ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) * stbir__max_uint16_as_float_inverted ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_uint16_linear_scaled ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned short STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned short * ) outputp ;
unsigned short * end_output = ( ( unsigned short * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
{
if ( width_times_channels > = stbir__simdfX_float_count * 2 )
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count * 2 ;
end_output - = stbir__simdfX_float_count * 2 ;
for ( ; ; )
{
stbir__simdfX e0 , e1 ;
stbir__simdiX i ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdfX_madd_mem ( e0 , STBIR_simd_point5X , STBIR_max_uint16_as_floatX , encode ) ;
stbir__simdfX_madd_mem ( e1 , STBIR_simd_point5X , STBIR_max_uint16_as_floatX , encode + stbir__simdfX_float_count ) ;
stbir__encode_simdfX_unflip ( e0 ) ;
stbir__encode_simdfX_unflip ( e1 ) ;
stbir__simdfX_pack_to_words ( i , e0 , e1 ) ;
stbir__simdiX_store ( output , i ) ;
encode + = stbir__simdfX_float_count * 2 ;
output + = stbir__simdfX_float_count * 2 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + stbir__simdfX_float_count * 2 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
}
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
stbir__simdf e ;
stbir__simdi i ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_load ( e , encode ) ;
stbir__simdf_madd ( e , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint16_as_float ) , e ) ;
stbir__encode_simdf4_unflip ( e ) ;
stbir__simdf_pack_to_8words ( i , e , e ) ; // only use first 4
stbir__simdi_store2 ( output - 4 , i ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
stbir__simdf e ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_madd1_mem ( e , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint16_as_float ) , encode + stbir__encode_order0 ) ; output [ 0 ] = stbir__simdf_convert_float_to_short ( e ) ;
# if stbir__coder_min_num >= 2
stbir__simdf_madd1_mem ( e , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint16_as_float ) , encode + stbir__encode_order1 ) ; output [ 1 ] = stbir__simdf_convert_float_to_short ( e ) ;
# endif
# if stbir__coder_min_num >= 3
stbir__simdf_madd1_mem ( e , STBIR__CONSTF ( STBIR_simd_point5 ) , STBIR__CONSTF ( STBIR_max_uint16_as_float ) , encode + stbir__encode_order2 ) ; output [ 2 ] = stbir__simdf_convert_float_to_short ( e ) ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
# else
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
float f ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 0 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order1 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 1 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order2 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 2 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order3 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 3 - 4 ] = ( unsigned short ) f ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
float f ;
STBIR_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 0 ] = ( unsigned short ) f ;
# if stbir__coder_min_num >= 2
f = encode [ stbir__encode_order1 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 1 ] = ( unsigned short ) f ;
# endif
# if stbir__coder_min_num >= 3
f = encode [ stbir__encode_order2 ] * stbir__max_uint16_as_float + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 2 ] = ( unsigned short ) f ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
# endif
}
static void STBIR__CODER_NAME ( stbir__decode_uint16_linear ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
unsigned short const * input = ( unsigned short const * ) inputp ;
# ifdef STBIR_SIMD
unsigned short const * end_input_m8 = input + width_times_channels - 8 ;
if ( width_times_channels > = 8 )
{
decode_end - = 8 ;
for ( ; ; )
{
# ifdef STBIR_SIMD8
stbir__simdi i ; stbir__simdi8 o ;
stbir__simdf8 of ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi8_expand_u16_to_u32 ( o , i ) ;
stbir__simdi8_convert_i32_to_float ( of , o ) ;
stbir__decode_simdf8_flip ( of ) ;
stbir__simdf8_store ( decode + 0 , of ) ;
# else
stbir__simdi i , o0 , o1 ;
stbir__simdf of0 , of1 ;
STBIR_NO_UNROLL ( decode ) ;
stbir__simdi_load ( i , input ) ;
stbir__simdi_expand_u16_to_u32 ( o0 , o1 , i ) ;
stbir__simdi_convert_i32_to_float ( of0 , o0 ) ;
stbir__simdi_convert_i32_to_float ( of1 , o1 ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__simdf_store ( decode + 0 , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
# endif
decode + = 8 ;
input + = 8 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 8 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m8 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) ;
decode [ 1 - 4 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) ;
decode [ 2 - 4 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) ;
decode [ 3 - 4 ] = ( ( float ) ( input [ stbir__decode_order3 ] ) ) ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = ( ( float ) ( input [ stbir__decode_order0 ] ) ) ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = ( ( float ) ( input [ stbir__decode_order1 ] ) ) ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = ( ( float ) ( input [ stbir__decode_order2 ] ) ) ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_uint16_linear ) ( void * outputp , int width_times_channels , float const * encode )
{
unsigned short STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( unsigned short * ) outputp ;
unsigned short * end_output = ( ( unsigned short * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
{
if ( width_times_channels > = stbir__simdfX_float_count * 2 )
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count * 2 ;
end_output - = stbir__simdfX_float_count * 2 ;
for ( ; ; )
{
stbir__simdfX e0 , e1 ;
stbir__simdiX i ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdfX_add_mem ( e0 , STBIR_simd_point5X , encode ) ;
stbir__simdfX_add_mem ( e1 , STBIR_simd_point5X , encode + stbir__simdfX_float_count ) ;
stbir__encode_simdfX_unflip ( e0 ) ;
stbir__encode_simdfX_unflip ( e1 ) ;
stbir__simdfX_pack_to_words ( i , e0 , e1 ) ;
stbir__simdiX_store ( output , i ) ;
encode + = stbir__simdfX_float_count * 2 ;
output + = stbir__simdfX_float_count * 2 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + stbir__simdfX_float_count * 2 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
}
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
stbir__simdf e ;
stbir__simdi i ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_load ( e , encode ) ;
stbir__simdf_add ( e , STBIR__CONSTF ( STBIR_simd_point5 ) , e ) ;
stbir__encode_simdf4_unflip ( e ) ;
stbir__simdf_pack_to_8words ( i , e , e ) ; // only use first 4
stbir__simdi_store2 ( output - 4 , i ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# else
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
float f ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 0 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order1 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 1 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order2 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 2 - 4 ] = ( unsigned short ) f ;
f = encode [ stbir__encode_order3 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 3 - 4 ] = ( unsigned short ) f ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
float f ;
STBIR_NO_UNROLL ( encode ) ;
f = encode [ stbir__encode_order0 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 0 ] = ( unsigned short ) f ;
# if stbir__coder_min_num >= 2
f = encode [ stbir__encode_order1 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 1 ] = ( unsigned short ) f ;
# endif
# if stbir__coder_min_num >= 3
f = encode [ stbir__encode_order2 ] + 0.5f ; STBIR_CLAMP ( f , 0 , 65535 ) ; output [ 2 ] = ( unsigned short ) f ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__decode_half_float_linear ) ( float * decodep , int width_times_channels , void const * inputp )
{
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
stbir__FP16 const * input = ( stbir__FP16 const * ) inputp ;
# ifdef STBIR_SIMD
if ( width_times_channels > = 8 )
{
stbir__FP16 const * end_input_m8 = input + width_times_channels - 8 ;
decode_end - = 8 ;
for ( ; ; )
{
STBIR_NO_UNROLL ( decode ) ;
stbir__half_to_float_SIMD ( decode , input ) ;
# ifdef stbir__decode_swizzle
# ifdef STBIR_SIMD8
{
stbir__simdf8 of ;
stbir__simdf8_load ( of , decode ) ;
stbir__decode_simdf8_flip ( of ) ;
stbir__simdf8_store ( decode , of ) ;
}
# else
{
stbir__simdf of0 , of1 ;
stbir__simdf_load ( of0 , decode ) ;
stbir__simdf_load ( of1 , decode + 4 ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__simdf_store ( decode , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
}
# endif
# endif
decode + = 8 ;
input + = 8 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 8 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m8 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = stbir__half_to_float ( input [ stbir__decode_order0 ] ) ;
decode [ 1 - 4 ] = stbir__half_to_float ( input [ stbir__decode_order1 ] ) ;
decode [ 2 - 4 ] = stbir__half_to_float ( input [ stbir__decode_order2 ] ) ;
decode [ 3 - 4 ] = stbir__half_to_float ( input [ stbir__decode_order3 ] ) ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = stbir__half_to_float ( input [ stbir__decode_order0 ] ) ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = stbir__half_to_float ( input [ stbir__decode_order1 ] ) ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = stbir__half_to_float ( input [ stbir__decode_order2 ] ) ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_half_float_linear ) ( void * outputp , int width_times_channels , float const * encode )
{
stbir__FP16 STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( stbir__FP16 * ) outputp ;
stbir__FP16 * end_output = ( ( stbir__FP16 * ) output ) + width_times_channels ;
# ifdef STBIR_SIMD
if ( width_times_channels > = 8 )
{
float const * end_encode_m8 = encode + width_times_channels - 8 ;
end_output - = 8 ;
for ( ; ; )
{
STBIR_SIMD_NO_UNROLL ( encode ) ;
# ifdef stbir__decode_swizzle
# ifdef STBIR_SIMD8
{
stbir__simdf8 of ;
stbir__simdf8_load ( of , encode ) ;
stbir__encode_simdf8_unflip ( of ) ;
stbir__float_to_half_SIMD ( output , ( float * ) & of ) ;
}
# else
{
stbir__simdf of [ 2 ] ;
stbir__simdf_load ( of [ 0 ] , encode ) ;
stbir__simdf_load ( of [ 1 ] , encode + 4 ) ;
stbir__encode_simdf4_unflip ( of [ 0 ] ) ;
stbir__encode_simdf4_unflip ( of [ 1 ] ) ;
stbir__float_to_half_SIMD ( output , ( float * ) of ) ;
}
# endif
# else
stbir__float_to_half_SIMD ( output , encode ) ;
# endif
encode + = 8 ;
output + = 8 ;
if ( output < = end_output )
continue ;
if ( output = = ( end_output + 8 ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
STBIR_SIMD_NO_UNROLL ( output ) ;
output [ 0 - 4 ] = stbir__float_to_half ( encode [ stbir__encode_order0 ] ) ;
output [ 1 - 4 ] = stbir__float_to_half ( encode [ stbir__encode_order1 ] ) ;
output [ 2 - 4 ] = stbir__float_to_half ( encode [ stbir__encode_order2 ] ) ;
output [ 3 - 4 ] = stbir__float_to_half ( encode [ stbir__encode_order3 ] ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
STBIR_NO_UNROLL ( output ) ;
output [ 0 ] = stbir__float_to_half ( encode [ stbir__encode_order0 ] ) ;
# if stbir__coder_min_num >= 2
output [ 1 ] = stbir__float_to_half ( encode [ stbir__encode_order1 ] ) ;
# endif
# if stbir__coder_min_num >= 3
output [ 2 ] = stbir__float_to_half ( encode [ stbir__encode_order2 ] ) ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
}
static void STBIR__CODER_NAME ( stbir__decode_float_linear ) ( float * decodep , int width_times_channels , void const * inputp )
{
# ifdef stbir__decode_swizzle
float STBIR_STREAMOUT_PTR ( * ) decode = decodep ;
float * decode_end = ( float * ) decode + width_times_channels ;
float const * input = ( float const * ) inputp ;
# ifdef STBIR_SIMD
if ( width_times_channels > = 16 )
{
float const * end_input_m16 = input + width_times_channels - 16 ;
decode_end - = 16 ;
for ( ; ; )
{
STBIR_NO_UNROLL ( decode ) ;
# ifdef stbir__decode_swizzle
# ifdef STBIR_SIMD8
{
stbir__simdf8 of0 , of1 ;
stbir__simdf8_load ( of0 , input ) ;
stbir__simdf8_load ( of1 , input + 8 ) ;
stbir__decode_simdf8_flip ( of0 ) ;
stbir__decode_simdf8_flip ( of1 ) ;
stbir__simdf8_store ( decode , of0 ) ;
stbir__simdf8_store ( decode + 8 , of1 ) ;
}
# else
{
stbir__simdf of0 , of1 , of2 , of3 ;
stbir__simdf_load ( of0 , input ) ;
stbir__simdf_load ( of1 , input + 4 ) ;
stbir__simdf_load ( of2 , input + 8 ) ;
stbir__simdf_load ( of3 , input + 12 ) ;
stbir__decode_simdf4_flip ( of0 ) ;
stbir__decode_simdf4_flip ( of1 ) ;
stbir__decode_simdf4_flip ( of2 ) ;
stbir__decode_simdf4_flip ( of3 ) ;
stbir__simdf_store ( decode , of0 ) ;
stbir__simdf_store ( decode + 4 , of1 ) ;
stbir__simdf_store ( decode + 8 , of2 ) ;
stbir__simdf_store ( decode + 12 , of3 ) ;
}
# endif
# endif
decode + = 16 ;
input + = 16 ;
if ( decode < = decode_end )
continue ;
if ( decode = = ( decode_end + 16 ) )
break ;
decode = decode_end ; // backup and do last couple
input = end_input_m16 ;
}
return ;
}
# endif
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode + = 4 ;
while ( decode < = decode_end )
{
STBIR_SIMD_NO_UNROLL ( decode ) ;
decode [ 0 - 4 ] = input [ stbir__decode_order0 ] ;
decode [ 1 - 4 ] = input [ stbir__decode_order1 ] ;
decode [ 2 - 4 ] = input [ stbir__decode_order2 ] ;
decode [ 3 - 4 ] = input [ stbir__decode_order3 ] ;
decode + = 4 ;
input + = 4 ;
}
decode - = 4 ;
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( decode < decode_end )
{
STBIR_NO_UNROLL ( decode ) ;
decode [ 0 ] = input [ stbir__decode_order0 ] ;
# if stbir__coder_min_num >= 2
decode [ 1 ] = input [ stbir__decode_order1 ] ;
# endif
# if stbir__coder_min_num >= 3
decode [ 2 ] = input [ stbir__decode_order2 ] ;
# endif
decode + = stbir__coder_min_num ;
input + = stbir__coder_min_num ;
}
# endif
# else
if ( ( void * ) decodep ! = inputp )
STBIR_MEMCPY ( decodep , inputp , width_times_channels * sizeof ( float ) ) ;
# endif
}
static void STBIR__CODER_NAME ( stbir__encode_float_linear ) ( void * outputp , int width_times_channels , float const * encode )
{
# if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle)
if ( ( void * ) outputp ! = ( void * ) encode )
STBIR_MEMCPY ( outputp , encode , width_times_channels * sizeof ( float ) ) ;
# else
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = ( float * ) outputp ;
float * end_output = ( ( float * ) output ) + width_times_channels ;
# ifdef STBIR_FLOAT_HIGH_CLAMP
# define stbir_scalar_hi_clamp( v ) if ( v > STBIR_FLOAT_HIGH_CLAMP ) v = STBIR_FLOAT_HIGH_CLAMP;
# else
# define stbir_scalar_hi_clamp( v )
# endif
# ifdef STBIR_FLOAT_LOW_CLAMP
# define stbir_scalar_lo_clamp( v ) if ( v < STBIR_FLOAT_LOW_CLAMP ) v = STBIR_FLOAT_LOW_CLAMP;
# else
# define stbir_scalar_lo_clamp( v )
# endif
# ifdef STBIR_SIMD
# ifdef STBIR_FLOAT_HIGH_CLAMP
const stbir__simdfX high_clamp = stbir__simdf_frepX ( STBIR_FLOAT_HIGH_CLAMP ) ;
# endif
# ifdef STBIR_FLOAT_LOW_CLAMP
const stbir__simdfX low_clamp = stbir__simdf_frepX ( STBIR_FLOAT_LOW_CLAMP ) ;
# endif
if ( width_times_channels > = ( stbir__simdfX_float_count * 2 ) )
{
float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 ) ;
end_output - = ( stbir__simdfX_float_count * 2 ) ;
for ( ; ; )
{
stbir__simdfX e0 , e1 ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
stbir__simdfX_load ( e0 , encode ) ;
stbir__simdfX_load ( e1 , encode + stbir__simdfX_float_count ) ;
# ifdef STBIR_FLOAT_HIGH_CLAMP
stbir__simdfX_min ( e0 , e0 , high_clamp ) ;
stbir__simdfX_min ( e1 , e1 , high_clamp ) ;
# endif
# ifdef STBIR_FLOAT_LOW_CLAMP
stbir__simdfX_max ( e0 , e0 , low_clamp ) ;
stbir__simdfX_max ( e1 , e1 , low_clamp ) ;
# endif
stbir__encode_simdfX_unflip ( e0 ) ;
stbir__encode_simdfX_unflip ( e1 ) ;
stbir__simdfX_store ( output , e0 ) ;
stbir__simdfX_store ( output + stbir__simdfX_float_count , e1 ) ;
encode + = stbir__simdfX_float_count * 2 ;
output + = stbir__simdfX_float_count * 2 ;
if ( output < end_output )
continue ;
if ( output = = ( end_output + ( stbir__simdfX_float_count * 2 ) ) )
break ;
output = end_output ; // backup and do last couple
encode = end_encode_m8 ;
}
return ;
}
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
stbir__simdf e0 ;
STBIR_NO_UNROLL ( encode ) ;
stbir__simdf_load ( e0 , encode ) ;
# ifdef STBIR_FLOAT_HIGH_CLAMP
stbir__simdf_min ( e0 , e0 , high_clamp ) ;
# endif
# ifdef STBIR_FLOAT_LOW_CLAMP
stbir__simdf_max ( e0 , e0 , low_clamp ) ;
# endif
stbir__encode_simdf4_unflip ( e0 ) ;
stbir__simdf_store ( output - 4 , e0 ) ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# else
// try to do blocks of 4 when you can
# if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output + = 4 ;
while ( output < = end_output )
{
float e ;
STBIR_SIMD_NO_UNROLL ( encode ) ;
e = encode [ stbir__encode_order0 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 0 - 4 ] = e ;
e = encode [ stbir__encode_order1 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 1 - 4 ] = e ;
e = encode [ stbir__encode_order2 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 2 - 4 ] = e ;
e = encode [ stbir__encode_order3 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 3 - 4 ] = e ;
output + = 4 ;
encode + = 4 ;
}
output - = 4 ;
# endif
# endif
// do the remnants
# if stbir__coder_min_num < 4
while ( output < end_output )
{
float e ;
STBIR_NO_UNROLL ( encode ) ;
e = encode [ stbir__encode_order0 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 0 ] = e ;
# if stbir__coder_min_num >= 2
e = encode [ stbir__encode_order1 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 1 ] = e ;
# endif
# if stbir__coder_min_num >= 3
e = encode [ stbir__encode_order2 ] ; stbir_scalar_hi_clamp ( e ) ; stbir_scalar_lo_clamp ( e ) ; output [ 2 ] = e ;
# endif
output + = stbir__coder_min_num ;
encode + = stbir__coder_min_num ;
}
# endif
# endif
}
# undef stbir__decode_suffix
# undef stbir__decode_simdf8_flip
# undef stbir__decode_simdf4_flip
# undef stbir__decode_order0
# undef stbir__decode_order1
# undef stbir__decode_order2
# undef stbir__decode_order3
# undef stbir__encode_order0
# undef stbir__encode_order1
# undef stbir__encode_order2
# undef stbir__encode_order3
# undef stbir__encode_simdf8_unflip
# undef stbir__encode_simdf4_unflip
# undef stbir__encode_simdfX_unflip
# undef STBIR__CODER_NAME
# undef stbir__coder_min_num
# undef stbir__decode_swizzle
# undef stbir_scalar_hi_clamp
# undef stbir_scalar_lo_clamp
# undef STB_IMAGE_RESIZE_DO_CODERS
# elif defined( STB_IMAGE_RESIZE_DO_VERTICALS)
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# define STBIR_chans( start, end ) STBIR_strs_join14(start,STBIR__vertical_channels,end,_cont)
# else
# define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__vertical_channels,end)
# endif
# if STBIR__vertical_channels >= 1
# define stbIF0( code ) code
# else
# define stbIF0( code )
# endif
# if STBIR__vertical_channels >= 2
# define stbIF1( code ) code
# else
# define stbIF1( code )
# endif
# if STBIR__vertical_channels >= 3
# define stbIF2( code ) code
# else
# define stbIF2( code )
# endif
# if STBIR__vertical_channels >= 4
# define stbIF3( code ) code
# else
# define stbIF3( code )
# endif
# if STBIR__vertical_channels >= 5
# define stbIF4( code ) code
# else
# define stbIF4( code )
# endif
# if STBIR__vertical_channels >= 6
# define stbIF5( code ) code
# else
# define stbIF5( code )
# endif
# if STBIR__vertical_channels >= 7
# define stbIF6( code ) code
# else
# define stbIF6( code )
# endif
# if STBIR__vertical_channels >= 8
# define stbIF7( code ) code
# else
# define stbIF7( code )
# endif
static void STBIR_chans ( stbir__vertical_scatter_with_ , _coeffs ) ( float * * outputs , float const * vertical_coefficients , float const * input , float const * input_end )
{
stbIF0 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output0 = outputs [ 0 ] ; float c0s = vertical_coefficients [ 0 ] ; )
stbIF1 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output1 = outputs [ 1 ] ; float c1s = vertical_coefficients [ 1 ] ; )
stbIF2 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output2 = outputs [ 2 ] ; float c2s = vertical_coefficients [ 2 ] ; )
stbIF3 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output3 = outputs [ 3 ] ; float c3s = vertical_coefficients [ 3 ] ; )
stbIF4 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output4 = outputs [ 4 ] ; float c4s = vertical_coefficients [ 4 ] ; )
stbIF5 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output5 = outputs [ 5 ] ; float c5s = vertical_coefficients [ 5 ] ; )
stbIF6 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output6 = outputs [ 6 ] ; float c6s = vertical_coefficients [ 6 ] ; )
stbIF7 ( float STBIR_SIMD_STREAMOUT_PTR ( * ) output7 = outputs [ 7 ] ; float c7s = vertical_coefficients [ 7 ] ; )
# ifdef STBIR_SIMD
{
stbIF0 ( stbir__simdfX c0 = stbir__simdf_frepX ( c0s ) ; )
stbIF1 ( stbir__simdfX c1 = stbir__simdf_frepX ( c1s ) ; )
stbIF2 ( stbir__simdfX c2 = stbir__simdf_frepX ( c2s ) ; )
stbIF3 ( stbir__simdfX c3 = stbir__simdf_frepX ( c3s ) ; )
stbIF4 ( stbir__simdfX c4 = stbir__simdf_frepX ( c4s ) ; )
stbIF5 ( stbir__simdfX c5 = stbir__simdf_frepX ( c5s ) ; )
stbIF6 ( stbir__simdfX c6 = stbir__simdf_frepX ( c6s ) ; )
stbIF7 ( stbir__simdfX c7 = stbir__simdf_frepX ( c7s ) ; )
while ( ( ( char * ) input_end - ( char * ) input ) > = ( 16 * stbir__simdfX_float_count ) )
{
stbir__simdfX o0 , o1 , o2 , o3 , r0 , r1 , r2 , r3 ;
STBIR_SIMD_NO_UNROLL ( output0 ) ;
stbir__simdfX_load ( r0 , input ) ; stbir__simdfX_load ( r1 , input + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input + ( 3 * stbir__simdfX_float_count ) ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( stbir__simdfX_load ( o0 , output0 ) ; stbir__simdfX_load ( o1 , output0 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output0 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output0 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c0 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c0 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c0 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c0 ) ;
stbir__simdfX_store ( output0 , o0 ) ; stbir__simdfX_store ( output0 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output0 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output0 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF1 ( stbir__simdfX_load ( o0 , output1 ) ; stbir__simdfX_load ( o1 , output1 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output1 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output1 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c1 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c1 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c1 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c1 ) ;
stbir__simdfX_store ( output1 , o0 ) ; stbir__simdfX_store ( output1 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output1 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output1 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF2 ( stbir__simdfX_load ( o0 , output2 ) ; stbir__simdfX_load ( o1 , output2 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output2 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output2 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c2 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c2 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c2 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c2 ) ;
stbir__simdfX_store ( output2 , o0 ) ; stbir__simdfX_store ( output2 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output2 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output2 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF3 ( stbir__simdfX_load ( o0 , output3 ) ; stbir__simdfX_load ( o1 , output3 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output3 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output3 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c3 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c3 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c3 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c3 ) ;
stbir__simdfX_store ( output3 , o0 ) ; stbir__simdfX_store ( output3 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output3 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output3 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF4 ( stbir__simdfX_load ( o0 , output4 ) ; stbir__simdfX_load ( o1 , output4 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output4 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output4 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c4 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c4 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c4 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c4 ) ;
stbir__simdfX_store ( output4 , o0 ) ; stbir__simdfX_store ( output4 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output4 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output4 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF5 ( stbir__simdfX_load ( o0 , output5 ) ; stbir__simdfX_load ( o1 , output5 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output5 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output5 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c5 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c5 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c5 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c5 ) ;
stbir__simdfX_store ( output5 , o0 ) ; stbir__simdfX_store ( output5 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output5 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output5 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF6 ( stbir__simdfX_load ( o0 , output6 ) ; stbir__simdfX_load ( o1 , output6 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output6 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output6 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c6 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c6 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c6 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c6 ) ;
stbir__simdfX_store ( output6 , o0 ) ; stbir__simdfX_store ( output6 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output6 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output6 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF7 ( stbir__simdfX_load ( o0 , output7 ) ; stbir__simdfX_load ( o1 , output7 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output7 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output7 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c7 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c7 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c7 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c7 ) ;
stbir__simdfX_store ( output7 , o0 ) ; stbir__simdfX_store ( output7 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output7 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output7 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
# else
stbIF0 ( stbir__simdfX_mult ( o0 , r0 , c0 ) ; stbir__simdfX_mult ( o1 , r1 , c0 ) ; stbir__simdfX_mult ( o2 , r2 , c0 ) ; stbir__simdfX_mult ( o3 , r3 , c0 ) ;
stbir__simdfX_store ( output0 , o0 ) ; stbir__simdfX_store ( output0 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output0 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output0 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF1 ( stbir__simdfX_mult ( o0 , r0 , c1 ) ; stbir__simdfX_mult ( o1 , r1 , c1 ) ; stbir__simdfX_mult ( o2 , r2 , c1 ) ; stbir__simdfX_mult ( o3 , r3 , c1 ) ;
stbir__simdfX_store ( output1 , o0 ) ; stbir__simdfX_store ( output1 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output1 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output1 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF2 ( stbir__simdfX_mult ( o0 , r0 , c2 ) ; stbir__simdfX_mult ( o1 , r1 , c2 ) ; stbir__simdfX_mult ( o2 , r2 , c2 ) ; stbir__simdfX_mult ( o3 , r3 , c2 ) ;
stbir__simdfX_store ( output2 , o0 ) ; stbir__simdfX_store ( output2 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output2 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output2 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF3 ( stbir__simdfX_mult ( o0 , r0 , c3 ) ; stbir__simdfX_mult ( o1 , r1 , c3 ) ; stbir__simdfX_mult ( o2 , r2 , c3 ) ; stbir__simdfX_mult ( o3 , r3 , c3 ) ;
stbir__simdfX_store ( output3 , o0 ) ; stbir__simdfX_store ( output3 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output3 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output3 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF4 ( stbir__simdfX_mult ( o0 , r0 , c4 ) ; stbir__simdfX_mult ( o1 , r1 , c4 ) ; stbir__simdfX_mult ( o2 , r2 , c4 ) ; stbir__simdfX_mult ( o3 , r3 , c4 ) ;
stbir__simdfX_store ( output4 , o0 ) ; stbir__simdfX_store ( output4 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output4 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output4 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF5 ( stbir__simdfX_mult ( o0 , r0 , c5 ) ; stbir__simdfX_mult ( o1 , r1 , c5 ) ; stbir__simdfX_mult ( o2 , r2 , c5 ) ; stbir__simdfX_mult ( o3 , r3 , c5 ) ;
stbir__simdfX_store ( output5 , o0 ) ; stbir__simdfX_store ( output5 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output5 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output5 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF6 ( stbir__simdfX_mult ( o0 , r0 , c6 ) ; stbir__simdfX_mult ( o1 , r1 , c6 ) ; stbir__simdfX_mult ( o2 , r2 , c6 ) ; stbir__simdfX_mult ( o3 , r3 , c6 ) ;
stbir__simdfX_store ( output6 , o0 ) ; stbir__simdfX_store ( output6 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output6 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output6 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
stbIF7 ( stbir__simdfX_mult ( o0 , r0 , c7 ) ; stbir__simdfX_mult ( o1 , r1 , c7 ) ; stbir__simdfX_mult ( o2 , r2 , c7 ) ; stbir__simdfX_mult ( o3 , r3 , c7 ) ;
stbir__simdfX_store ( output7 , o0 ) ; stbir__simdfX_store ( output7 + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output7 + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output7 + ( 3 * stbir__simdfX_float_count ) , o3 ) ; )
# endif
input + = ( 4 * stbir__simdfX_float_count ) ;
stbIF0 ( output0 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF1 ( output1 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF2 ( output2 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF3 ( output3 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF4 ( output4 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF5 ( output5 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF6 ( output6 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF7 ( output7 + = ( 4 * stbir__simdfX_float_count ) ; )
}
while ( ( ( char * ) input_end - ( char * ) input ) > = 16 )
{
stbir__simdf o0 , r0 ;
STBIR_SIMD_NO_UNROLL ( output0 ) ;
stbir__simdf_load ( r0 , input ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( stbir__simdf_load ( o0 , output0 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c0 ) ) ; stbir__simdf_store ( output0 , o0 ) ; )
stbIF1 ( stbir__simdf_load ( o0 , output1 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c1 ) ) ; stbir__simdf_store ( output1 , o0 ) ; )
stbIF2 ( stbir__simdf_load ( o0 , output2 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c2 ) ) ; stbir__simdf_store ( output2 , o0 ) ; )
stbIF3 ( stbir__simdf_load ( o0 , output3 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c3 ) ) ; stbir__simdf_store ( output3 , o0 ) ; )
stbIF4 ( stbir__simdf_load ( o0 , output4 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c4 ) ) ; stbir__simdf_store ( output4 , o0 ) ; )
stbIF5 ( stbir__simdf_load ( o0 , output5 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c5 ) ) ; stbir__simdf_store ( output5 , o0 ) ; )
stbIF6 ( stbir__simdf_load ( o0 , output6 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c6 ) ) ; stbir__simdf_store ( output6 , o0 ) ; )
stbIF7 ( stbir__simdf_load ( o0 , output7 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c7 ) ) ; stbir__simdf_store ( output7 , o0 ) ; )
# else
stbIF0 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c0 ) ) ; stbir__simdf_store ( output0 , o0 ) ; )
stbIF1 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c1 ) ) ; stbir__simdf_store ( output1 , o0 ) ; )
stbIF2 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c2 ) ) ; stbir__simdf_store ( output2 , o0 ) ; )
stbIF3 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c3 ) ) ; stbir__simdf_store ( output3 , o0 ) ; )
stbIF4 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c4 ) ) ; stbir__simdf_store ( output4 , o0 ) ; )
stbIF5 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c5 ) ) ; stbir__simdf_store ( output5 , o0 ) ; )
stbIF6 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c6 ) ) ; stbir__simdf_store ( output6 , o0 ) ; )
stbIF7 ( stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c7 ) ) ; stbir__simdf_store ( output7 , o0 ) ; )
# endif
input + = 4 ;
stbIF0 ( output0 + = 4 ; ) stbIF1 ( output1 + = 4 ; ) stbIF2 ( output2 + = 4 ; ) stbIF3 ( output3 + = 4 ; ) stbIF4 ( output4 + = 4 ; ) stbIF5 ( output5 + = 4 ; ) stbIF6 ( output6 + = 4 ; ) stbIF7 ( output7 + = 4 ; )
}
}
# else
while ( ( ( char * ) input_end - ( char * ) input ) > = 16 )
{
float r0 , r1 , r2 , r3 ;
STBIR_NO_UNROLL ( input ) ;
r0 = input [ 0 ] , r1 = input [ 1 ] , r2 = input [ 2 ] , r3 = input [ 3 ] ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( output0 [ 0 ] + = ( r0 * c0s ) ; output0 [ 1 ] + = ( r1 * c0s ) ; output0 [ 2 ] + = ( r2 * c0s ) ; output0 [ 3 ] + = ( r3 * c0s ) ; )
stbIF1 ( output1 [ 0 ] + = ( r0 * c1s ) ; output1 [ 1 ] + = ( r1 * c1s ) ; output1 [ 2 ] + = ( r2 * c1s ) ; output1 [ 3 ] + = ( r3 * c1s ) ; )
stbIF2 ( output2 [ 0 ] + = ( r0 * c2s ) ; output2 [ 1 ] + = ( r1 * c2s ) ; output2 [ 2 ] + = ( r2 * c2s ) ; output2 [ 3 ] + = ( r3 * c2s ) ; )
stbIF3 ( output3 [ 0 ] + = ( r0 * c3s ) ; output3 [ 1 ] + = ( r1 * c3s ) ; output3 [ 2 ] + = ( r2 * c3s ) ; output3 [ 3 ] + = ( r3 * c3s ) ; )
stbIF4 ( output4 [ 0 ] + = ( r0 * c4s ) ; output4 [ 1 ] + = ( r1 * c4s ) ; output4 [ 2 ] + = ( r2 * c4s ) ; output4 [ 3 ] + = ( r3 * c4s ) ; )
stbIF5 ( output5 [ 0 ] + = ( r0 * c5s ) ; output5 [ 1 ] + = ( r1 * c5s ) ; output5 [ 2 ] + = ( r2 * c5s ) ; output5 [ 3 ] + = ( r3 * c5s ) ; )
stbIF6 ( output6 [ 0 ] + = ( r0 * c6s ) ; output6 [ 1 ] + = ( r1 * c6s ) ; output6 [ 2 ] + = ( r2 * c6s ) ; output6 [ 3 ] + = ( r3 * c6s ) ; )
stbIF7 ( output7 [ 0 ] + = ( r0 * c7s ) ; output7 [ 1 ] + = ( r1 * c7s ) ; output7 [ 2 ] + = ( r2 * c7s ) ; output7 [ 3 ] + = ( r3 * c7s ) ; )
# else
stbIF0 ( output0 [ 0 ] = ( r0 * c0s ) ; output0 [ 1 ] = ( r1 * c0s ) ; output0 [ 2 ] = ( r2 * c0s ) ; output0 [ 3 ] = ( r3 * c0s ) ; )
stbIF1 ( output1 [ 0 ] = ( r0 * c1s ) ; output1 [ 1 ] = ( r1 * c1s ) ; output1 [ 2 ] = ( r2 * c1s ) ; output1 [ 3 ] = ( r3 * c1s ) ; )
stbIF2 ( output2 [ 0 ] = ( r0 * c2s ) ; output2 [ 1 ] = ( r1 * c2s ) ; output2 [ 2 ] = ( r2 * c2s ) ; output2 [ 3 ] = ( r3 * c2s ) ; )
stbIF3 ( output3 [ 0 ] = ( r0 * c3s ) ; output3 [ 1 ] = ( r1 * c3s ) ; output3 [ 2 ] = ( r2 * c3s ) ; output3 [ 3 ] = ( r3 * c3s ) ; )
stbIF4 ( output4 [ 0 ] = ( r0 * c4s ) ; output4 [ 1 ] = ( r1 * c4s ) ; output4 [ 2 ] = ( r2 * c4s ) ; output4 [ 3 ] = ( r3 * c4s ) ; )
stbIF5 ( output5 [ 0 ] = ( r0 * c5s ) ; output5 [ 1 ] = ( r1 * c5s ) ; output5 [ 2 ] = ( r2 * c5s ) ; output5 [ 3 ] = ( r3 * c5s ) ; )
stbIF6 ( output6 [ 0 ] = ( r0 * c6s ) ; output6 [ 1 ] = ( r1 * c6s ) ; output6 [ 2 ] = ( r2 * c6s ) ; output6 [ 3 ] = ( r3 * c6s ) ; )
stbIF7 ( output7 [ 0 ] = ( r0 * c7s ) ; output7 [ 1 ] = ( r1 * c7s ) ; output7 [ 2 ] = ( r2 * c7s ) ; output7 [ 3 ] = ( r3 * c7s ) ; )
# endif
input + = 4 ;
stbIF0 ( output0 + = 4 ; ) stbIF1 ( output1 + = 4 ; ) stbIF2 ( output2 + = 4 ; ) stbIF3 ( output3 + = 4 ; ) stbIF4 ( output4 + = 4 ; ) stbIF5 ( output5 + = 4 ; ) stbIF6 ( output6 + = 4 ; ) stbIF7 ( output7 + = 4 ; )
}
# endif
while ( input < input_end )
{
float r = input [ 0 ] ;
STBIR_NO_UNROLL ( output0 ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( output0 [ 0 ] + = ( r * c0s ) ; )
stbIF1 ( output1 [ 0 ] + = ( r * c1s ) ; )
stbIF2 ( output2 [ 0 ] + = ( r * c2s ) ; )
stbIF3 ( output3 [ 0 ] + = ( r * c3s ) ; )
stbIF4 ( output4 [ 0 ] + = ( r * c4s ) ; )
stbIF5 ( output5 [ 0 ] + = ( r * c5s ) ; )
stbIF6 ( output6 [ 0 ] + = ( r * c6s ) ; )
stbIF7 ( output7 [ 0 ] + = ( r * c7s ) ; )
# else
stbIF0 ( output0 [ 0 ] = ( r * c0s ) ; )
stbIF1 ( output1 [ 0 ] = ( r * c1s ) ; )
stbIF2 ( output2 [ 0 ] = ( r * c2s ) ; )
stbIF3 ( output3 [ 0 ] = ( r * c3s ) ; )
stbIF4 ( output4 [ 0 ] = ( r * c4s ) ; )
stbIF5 ( output5 [ 0 ] = ( r * c5s ) ; )
stbIF6 ( output6 [ 0 ] = ( r * c6s ) ; )
stbIF7 ( output7 [ 0 ] = ( r * c7s ) ; )
# endif
+ + input ;
stbIF0 ( + + output0 ; ) stbIF1 ( + + output1 ; ) stbIF2 ( + + output2 ; ) stbIF3 ( + + output3 ; ) stbIF4 ( + + output4 ; ) stbIF5 ( + + output5 ; ) stbIF6 ( + + output6 ; ) stbIF7 ( + + output7 ; )
}
}
static void STBIR_chans ( stbir__vertical_gather_with_ , _coeffs ) ( float * outputp , float const * vertical_coefficients , float const * * inputs , float const * input0_end )
{
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = outputp ;
stbIF0 ( float const * input0 = inputs [ 0 ] ; float c0s = vertical_coefficients [ 0 ] ; )
stbIF1 ( float const * input1 = inputs [ 1 ] ; float c1s = vertical_coefficients [ 1 ] ; )
stbIF2 ( float const * input2 = inputs [ 2 ] ; float c2s = vertical_coefficients [ 2 ] ; )
stbIF3 ( float const * input3 = inputs [ 3 ] ; float c3s = vertical_coefficients [ 3 ] ; )
stbIF4 ( float const * input4 = inputs [ 4 ] ; float c4s = vertical_coefficients [ 4 ] ; )
stbIF5 ( float const * input5 = inputs [ 5 ] ; float c5s = vertical_coefficients [ 5 ] ; )
stbIF6 ( float const * input6 = inputs [ 6 ] ; float c6s = vertical_coefficients [ 6 ] ; )
stbIF7 ( float const * input7 = inputs [ 7 ] ; float c7s = vertical_coefficients [ 7 ] ; )
# if ( STBIR__vertical_channels == 1 ) && !defined(STB_IMAGE_RESIZE_VERTICAL_CONTINUE)
// check single channel one weight
if ( ( c0s > = ( 1.0f - 0.000001f ) ) & & ( c0s < = ( 1.0f + 0.000001f ) ) )
{
STBIR_MEMCPY ( output , input0 , ( char * ) input0_end - ( char * ) input0 ) ;
return ;
}
# endif
# ifdef STBIR_SIMD
{
stbIF0 ( stbir__simdfX c0 = stbir__simdf_frepX ( c0s ) ; )
stbIF1 ( stbir__simdfX c1 = stbir__simdf_frepX ( c1s ) ; )
stbIF2 ( stbir__simdfX c2 = stbir__simdf_frepX ( c2s ) ; )
stbIF3 ( stbir__simdfX c3 = stbir__simdf_frepX ( c3s ) ; )
stbIF4 ( stbir__simdfX c4 = stbir__simdf_frepX ( c4s ) ; )
stbIF5 ( stbir__simdfX c5 = stbir__simdf_frepX ( c5s ) ; )
stbIF6 ( stbir__simdfX c6 = stbir__simdf_frepX ( c6s ) ; )
stbIF7 ( stbir__simdfX c7 = stbir__simdf_frepX ( c7s ) ; )
while ( ( ( char * ) input0_end - ( char * ) input0 ) > = ( 16 * stbir__simdfX_float_count ) )
{
stbir__simdfX o0 , o1 , o2 , o3 , r0 , r1 , r2 , r3 ;
STBIR_SIMD_NO_UNROLL ( output ) ;
// prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones)
stbIF0 ( stbir__prefetch ( input0 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF1 ( stbir__prefetch ( input1 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF2 ( stbir__prefetch ( input2 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF3 ( stbir__prefetch ( input3 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF4 ( stbir__prefetch ( input4 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF5 ( stbir__prefetch ( input5 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF6 ( stbir__prefetch ( input6 + ( 16 * stbir__simdfX_float_count ) ) ; )
stbIF7 ( stbir__prefetch ( input7 + ( 16 * stbir__simdfX_float_count ) ) ; )
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( stbir__simdfX_load ( o0 , output ) ; stbir__simdfX_load ( o1 , output + stbir__simdfX_float_count ) ; stbir__simdfX_load ( o2 , output + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( o3 , output + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_load ( r0 , input0 ) ; stbir__simdfX_load ( r1 , input0 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input0 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input0 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c0 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c0 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c0 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c0 ) ; )
# else
stbIF0 ( stbir__simdfX_load ( r0 , input0 ) ; stbir__simdfX_load ( r1 , input0 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input0 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input0 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_mult ( o0 , r0 , c0 ) ; stbir__simdfX_mult ( o1 , r1 , c0 ) ; stbir__simdfX_mult ( o2 , r2 , c0 ) ; stbir__simdfX_mult ( o3 , r3 , c0 ) ; )
# endif
stbIF1 ( stbir__simdfX_load ( r0 , input1 ) ; stbir__simdfX_load ( r1 , input1 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input1 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input1 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c1 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c1 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c1 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c1 ) ; )
stbIF2 ( stbir__simdfX_load ( r0 , input2 ) ; stbir__simdfX_load ( r1 , input2 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input2 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input2 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c2 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c2 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c2 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c2 ) ; )
stbIF3 ( stbir__simdfX_load ( r0 , input3 ) ; stbir__simdfX_load ( r1 , input3 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input3 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input3 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c3 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c3 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c3 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c3 ) ; )
stbIF4 ( stbir__simdfX_load ( r0 , input4 ) ; stbir__simdfX_load ( r1 , input4 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input4 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input4 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c4 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c4 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c4 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c4 ) ; )
stbIF5 ( stbir__simdfX_load ( r0 , input5 ) ; stbir__simdfX_load ( r1 , input5 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input5 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input5 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c5 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c5 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c5 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c5 ) ; )
stbIF6 ( stbir__simdfX_load ( r0 , input6 ) ; stbir__simdfX_load ( r1 , input6 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input6 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input6 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c6 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c6 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c6 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c6 ) ; )
stbIF7 ( stbir__simdfX_load ( r0 , input7 ) ; stbir__simdfX_load ( r1 , input7 + stbir__simdfX_float_count ) ; stbir__simdfX_load ( r2 , input7 + ( 2 * stbir__simdfX_float_count ) ) ; stbir__simdfX_load ( r3 , input7 + ( 3 * stbir__simdfX_float_count ) ) ;
stbir__simdfX_madd ( o0 , o0 , r0 , c7 ) ; stbir__simdfX_madd ( o1 , o1 , r1 , c7 ) ; stbir__simdfX_madd ( o2 , o2 , r2 , c7 ) ; stbir__simdfX_madd ( o3 , o3 , r3 , c7 ) ; )
stbir__simdfX_store ( output , o0 ) ; stbir__simdfX_store ( output + stbir__simdfX_float_count , o1 ) ; stbir__simdfX_store ( output + ( 2 * stbir__simdfX_float_count ) , o2 ) ; stbir__simdfX_store ( output + ( 3 * stbir__simdfX_float_count ) , o3 ) ;
output + = ( 4 * stbir__simdfX_float_count ) ;
stbIF0 ( input0 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF1 ( input1 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF2 ( input2 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF3 ( input3 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF4 ( input4 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF5 ( input5 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF6 ( input6 + = ( 4 * stbir__simdfX_float_count ) ; ) stbIF7 ( input7 + = ( 4 * stbir__simdfX_float_count ) ; )
}
while ( ( ( char * ) input0_end - ( char * ) input0 ) > = 16 )
{
stbir__simdf o0 , r0 ;
STBIR_SIMD_NO_UNROLL ( output ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( stbir__simdf_load ( o0 , output ) ; stbir__simdf_load ( r0 , input0 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c0 ) ) ; )
# else
stbIF0 ( stbir__simdf_load ( r0 , input0 ) ; stbir__simdf_mult ( o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c0 ) ) ; )
# endif
stbIF1 ( stbir__simdf_load ( r0 , input1 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c1 ) ) ; )
stbIF2 ( stbir__simdf_load ( r0 , input2 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c2 ) ) ; )
stbIF3 ( stbir__simdf_load ( r0 , input3 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c3 ) ) ; )
stbIF4 ( stbir__simdf_load ( r0 , input4 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c4 ) ) ; )
stbIF5 ( stbir__simdf_load ( r0 , input5 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c5 ) ) ; )
stbIF6 ( stbir__simdf_load ( r0 , input6 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c6 ) ) ; )
stbIF7 ( stbir__simdf_load ( r0 , input7 ) ; stbir__simdf_madd ( o0 , o0 , r0 , stbir__if_simdf8_cast_to_simdf4 ( c7 ) ) ; )
stbir__simdf_store ( output , o0 ) ;
output + = 4 ;
stbIF0 ( input0 + = 4 ; ) stbIF1 ( input1 + = 4 ; ) stbIF2 ( input2 + = 4 ; ) stbIF3 ( input3 + = 4 ; ) stbIF4 ( input4 + = 4 ; ) stbIF5 ( input5 + = 4 ; ) stbIF6 ( input6 + = 4 ; ) stbIF7 ( input7 + = 4 ; )
}
}
# else
while ( ( ( char * ) input0_end - ( char * ) input0 ) > = 16 )
{
float o0 , o1 , o2 , o3 ;
STBIR_NO_UNROLL ( output ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( o0 = output [ 0 ] + input0 [ 0 ] * c0s ; o1 = output [ 1 ] + input0 [ 1 ] * c0s ; o2 = output [ 2 ] + input0 [ 2 ] * c0s ; o3 = output [ 3 ] + input0 [ 3 ] * c0s ; )
# else
stbIF0 ( o0 = input0 [ 0 ] * c0s ; o1 = input0 [ 1 ] * c0s ; o2 = input0 [ 2 ] * c0s ; o3 = input0 [ 3 ] * c0s ; )
# endif
stbIF1 ( o0 + = input1 [ 0 ] * c1s ; o1 + = input1 [ 1 ] * c1s ; o2 + = input1 [ 2 ] * c1s ; o3 + = input1 [ 3 ] * c1s ; )
stbIF2 ( o0 + = input2 [ 0 ] * c2s ; o1 + = input2 [ 1 ] * c2s ; o2 + = input2 [ 2 ] * c2s ; o3 + = input2 [ 3 ] * c2s ; )
stbIF3 ( o0 + = input3 [ 0 ] * c3s ; o1 + = input3 [ 1 ] * c3s ; o2 + = input3 [ 2 ] * c3s ; o3 + = input3 [ 3 ] * c3s ; )
stbIF4 ( o0 + = input4 [ 0 ] * c4s ; o1 + = input4 [ 1 ] * c4s ; o2 + = input4 [ 2 ] * c4s ; o3 + = input4 [ 3 ] * c4s ; )
stbIF5 ( o0 + = input5 [ 0 ] * c5s ; o1 + = input5 [ 1 ] * c5s ; o2 + = input5 [ 2 ] * c5s ; o3 + = input5 [ 3 ] * c5s ; )
stbIF6 ( o0 + = input6 [ 0 ] * c6s ; o1 + = input6 [ 1 ] * c6s ; o2 + = input6 [ 2 ] * c6s ; o3 + = input6 [ 3 ] * c6s ; )
stbIF7 ( o0 + = input7 [ 0 ] * c7s ; o1 + = input7 [ 1 ] * c7s ; o2 + = input7 [ 2 ] * c7s ; o3 + = input7 [ 3 ] * c7s ; )
output [ 0 ] = o0 ; output [ 1 ] = o1 ; output [ 2 ] = o2 ; output [ 3 ] = o3 ;
output + = 4 ;
stbIF0 ( input0 + = 4 ; ) stbIF1 ( input1 + = 4 ; ) stbIF2 ( input2 + = 4 ; ) stbIF3 ( input3 + = 4 ; ) stbIF4 ( input4 + = 4 ; ) stbIF5 ( input5 + = 4 ; ) stbIF6 ( input6 + = 4 ; ) stbIF7 ( input7 + = 4 ; )
}
# endif
while ( input0 < input0_end )
{
float o0 ;
STBIR_NO_UNROLL ( output ) ;
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0 ( o0 = output [ 0 ] + input0 [ 0 ] * c0s ; )
# else
stbIF0 ( o0 = input0 [ 0 ] * c0s ; )
# endif
stbIF1 ( o0 + = input1 [ 0 ] * c1s ; )
stbIF2 ( o0 + = input2 [ 0 ] * c2s ; )
stbIF3 ( o0 + = input3 [ 0 ] * c3s ; )
stbIF4 ( o0 + = input4 [ 0 ] * c4s ; )
stbIF5 ( o0 + = input5 [ 0 ] * c5s ; )
stbIF6 ( o0 + = input6 [ 0 ] * c6s ; )
stbIF7 ( o0 + = input7 [ 0 ] * c7s ; )
output [ 0 ] = o0 ;
+ + output ;
stbIF0 ( + + input0 ; ) stbIF1 ( + + input1 ; ) stbIF2 ( + + input2 ; ) stbIF3 ( + + input3 ; ) stbIF4 ( + + input4 ; ) stbIF5 ( + + input5 ; ) stbIF6 ( + + input6 ; ) stbIF7 ( + + input7 ; )
}
}
# undef stbIF0
# undef stbIF1
# undef stbIF2
# undef stbIF3
# undef stbIF4
# undef stbIF5
# undef stbIF6
# undef stbIF7
# undef STB_IMAGE_RESIZE_DO_VERTICALS
# undef STBIR__vertical_channels
# undef STB_IMAGE_RESIZE_DO_HORIZONTALS
# undef STBIR_strs_join24
# undef STBIR_strs_join14
# undef STBIR_chans
# ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# undef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
# endif
# else // !STB_IMAGE_RESIZE_DO_VERTICALS
# define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__horizontal_channels,end)
# ifndef stbir__2_coeff_only
# define stbir__2_coeff_only() \
stbir__1_coeff_only ( ) ; \
stbir__1_coeff_remnant ( 1 ) ;
# endif
# ifndef stbir__2_coeff_remnant
# define stbir__2_coeff_remnant( ofs ) \
stbir__1_coeff_remnant ( ofs ) ; \
stbir__1_coeff_remnant ( ( ofs ) + 1 ) ;
# endif
# ifndef stbir__3_coeff_only
# define stbir__3_coeff_only() \
stbir__2_coeff_only ( ) ; \
stbir__1_coeff_remnant ( 2 ) ;
# endif
# ifndef stbir__3_coeff_remnant
# define stbir__3_coeff_remnant( ofs ) \
stbir__2_coeff_remnant ( ofs ) ; \
stbir__1_coeff_remnant ( ( ofs ) + 2 ) ;
# endif
# ifndef stbir__3_coeff_setup
# define stbir__3_coeff_setup()
# endif
# ifndef stbir__4_coeff_start
# define stbir__4_coeff_start() \
stbir__2_coeff_only ( ) ; \
stbir__2_coeff_remnant ( 2 ) ;
# endif
# ifndef stbir__4_coeff_continue_from_4
# define stbir__4_coeff_continue_from_4( ofs ) \
stbir__2_coeff_remnant ( ofs ) ; \
stbir__2_coeff_remnant ( ( ofs ) + 2 ) ;
# endif
# ifndef stbir__store_output_tiny
# define stbir__store_output_tiny stbir__store_output
# endif
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_1_coeff ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__1_coeff_only ( ) ;
stbir__store_output_tiny ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_2_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__2_coeff_only ( ) ;
stbir__store_output_tiny ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_3_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__3_coeff_only ( ) ;
stbir__store_output_tiny ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_4_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_5_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__1_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_6_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__2_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_7_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
stbir__3_coeff_setup ( ) ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__3_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_8_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__4_coeff_continue_from_4 ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_9_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__4_coeff_continue_from_4 ( 4 ) ;
stbir__1_coeff_remnant ( 8 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_10_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__4_coeff_continue_from_4 ( 4 ) ;
stbir__2_coeff_remnant ( 8 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_11_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
stbir__3_coeff_setup ( ) ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__4_coeff_continue_from_4 ( 4 ) ;
stbir__3_coeff_remnant ( 8 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_12_coeffs ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
stbir__4_coeff_continue_from_4 ( 4 ) ;
stbir__4_coeff_continue_from_4 ( 8 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod0 ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
int n = ( ( horizontal_contributors - > n1 - horizontal_contributors - > n0 + 1 ) - 4 + 3 ) > > 2 ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
do {
hc + = 4 ;
decode + = STBIR__horizontal_channels * 4 ;
stbir__4_coeff_continue_from_4 ( 0 ) ;
- - n ;
} while ( n > 0 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod1 ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
int n = ( ( horizontal_contributors - > n1 - horizontal_contributors - > n0 + 1 ) - 5 + 3 ) > > 2 ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
do {
hc + = 4 ;
decode + = STBIR__horizontal_channels * 4 ;
stbir__4_coeff_continue_from_4 ( 0 ) ;
- - n ;
} while ( n > 0 ) ;
stbir__1_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod2 ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
int n = ( ( horizontal_contributors - > n1 - horizontal_contributors - > n0 + 1 ) - 6 + 3 ) > > 2 ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
do {
hc + = 4 ;
decode + = STBIR__horizontal_channels * 4 ;
stbir__4_coeff_continue_from_4 ( 0 ) ;
- - n ;
} while ( n > 0 ) ;
stbir__2_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static void STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod3 ) ( float * output_buffer , unsigned int output_sub_size , float const * decode_buffer , stbir__contributors const * horizontal_contributors , float const * horizontal_coefficients , int coefficient_width )
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels ;
float STBIR_SIMD_STREAMOUT_PTR ( * ) output = output_buffer ;
stbir__3_coeff_setup ( ) ;
do {
float const * decode = decode_buffer + horizontal_contributors - > n0 * STBIR__horizontal_channels ;
int n = ( ( horizontal_contributors - > n1 - horizontal_contributors - > n0 + 1 ) - 7 + 3 ) > > 2 ;
float const * hc = horizontal_coefficients ;
stbir__4_coeff_start ( ) ;
do {
hc + = 4 ;
decode + = STBIR__horizontal_channels * 4 ;
stbir__4_coeff_continue_from_4 ( 0 ) ;
- - n ;
} while ( n > 0 ) ;
stbir__3_coeff_remnant ( 4 ) ;
stbir__store_output ( ) ;
} while ( output < output_end ) ;
}
static stbir__horizontal_gather_channels_func * STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_funcs ) [ 4 ] =
{
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod0 ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod1 ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod2 ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_n_coeffs_mod3 ) ,
} ;
static stbir__horizontal_gather_channels_func * STBIR_chans ( stbir__horizontal_gather_ , _channels_funcs ) [ 12 ] =
{
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_1_coeff ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_2_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_3_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_4_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_5_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_6_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_7_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_8_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_9_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_10_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_11_coeffs ) ,
STBIR_chans ( stbir__horizontal_gather_ , _channels_with_12_coeffs ) ,
} ;
# undef STBIR__horizontal_channels
# undef STB_IMAGE_RESIZE_DO_HORIZONTALS
# undef stbir__1_coeff_only
# undef stbir__1_coeff_remnant
# undef stbir__2_coeff_only
# undef stbir__2_coeff_remnant
# undef stbir__3_coeff_only
# undef stbir__3_coeff_remnant
# undef stbir__3_coeff_setup
# undef stbir__4_coeff_start
# undef stbir__4_coeff_continue_from_4
# undef stbir__store_output
# undef stbir__store_output_tiny
# undef STBIR_chans
# endif // HORIZONALS
# undef STBIR_strs_join2
# undef STBIR_strs_join1
# endif // STB_IMAGE_RESIZE_DO_HORIZONTALS/VERTICALS/CODERS
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This software is available under 2 licenses - - choose whichever you prefer .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE A - MIT License
Copyright ( c ) 2017 Sean Barrett
Permission is hereby granted , free of charge , to any person obtaining a copy of
this software and associated documentation files ( the " Software " ) , to deal in
the Software without restriction , including without limitation the rights to
use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
of the Software , and to permit persons to whom the Software is furnished to do
so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE B - Public Domain ( www . unlicense . org )
This is free and unencumbered software released into the public domain .
Anyone is free to copy , modify , publish , use , compile , sell , or distribute this
software , either in source code form or as a compiled binary , for any purpose ,
commercial or non - commercial , and by any means .
In jurisdictions that recognize copyright laws , the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain . We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors . We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/