doom3-bfg/neo/renderer/DXT/DXTEncoder_SSE2.cpp

1581 lines
66 KiB
C++
Raw Normal View History

2012-11-26 18:58:24 +00:00
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
/*
================================================================================================
Contains the DxtEncoder implementation for SSE2.
================================================================================================
*/
#pragma hdrstop
#include "DXTCodec_local.h"
#include "DXTCodec.h"
//#define TEST_COMPRESSION
#ifdef TEST_COMPRESSION
#include <malloc.h>
#endif
#define INSET_COLOR_SHIFT 4 // inset the bounding box with ( range >> shift )
#define INSET_ALPHA_SHIFT 5 // inset alpha channel
#define C565_5_MASK 0xF8 // 0xFF minus last three bits
#define C565_6_MASK 0xFC // 0xFF minus last two bits
#define NVIDIA_7X_HARDWARE_BUG_FIX // keep the DXT5 colors sorted as: max, min
#if !defined( R_SHUFFLE_D )
#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
#endif
typedef uint16 word;
typedef uint32 dword;
ALIGN16( static __m128i SIMD_SSE2_zero ) = { 0, 0, 0, 0 };
ALIGN16( static dword SIMD_SSE2_dword_byte_mask[4] ) = { 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF };
ALIGN16( static dword SIMD_SSE2_dword_word_mask[4] ) = { 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF };
ALIGN16( static dword SIMD_SSE2_dword_red_mask[4] ) = { 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF };
ALIGN16( static dword SIMD_SSE2_dword_green_mask[4] ) = { 0x0000FF00, 0x0000FF00, 0x0000FF00, 0x0000FF00 };
ALIGN16( static dword SIMD_SSE2_dword_blue_mask[4] ) = { 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000 };
ALIGN16( static dword SIMD_SSE2_dword_colorMask_1010[4] ) = { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 };
ALIGN16( static dword SIMD_SSE2_dword_colorMask_0100[4] ) = { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask0[4] ) = { 3<<0, 0, 3<<0, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask1[4] ) = { 3<<2, 0, 3<<2, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask2[4] ) = { 3<<4, 0, 3<<4, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask3[4] ) = { 3<<6, 0, 3<<6, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask4[4] ) = { 3<<8, 0, 3<<8, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask5[4] ) = { 3<<10, 0, 3<<10, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask6[4] ) = { 3<<12, 0, 3<<12, 0 };
ALIGN16( static dword SIMD_SSE2_dword_color_bit_mask7[4] ) = { 3<<14, 0, 3<<14, 0 };
ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
ALIGN16( static word SIMD_SSE2_word_3[8] ) = { 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003 };
ALIGN16( static word SIMD_SSE2_word_7[8] ) = { 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007 };
ALIGN16( static word SIMD_SSE2_word_8[8] ) = { 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 };
ALIGN16( static word SIMD_SSE2_word_31[8] ) = { 31, 31, 31, 31, 31, 31, 31, 31 };
ALIGN16( static word SIMD_SSE2_word_63[8] ) = { 63, 63, 63, 63, 63, 63, 63, 63 };
ALIGN16( static word SIMD_SSE2_word_127[8] ) = { 127, 127, 127, 127, 127, 127, 127, 127 };
ALIGN16( static word SIMD_SSE2_word_255[8] ) = { 255, 255, 255, 255, 255, 255, 255, 255 };
ALIGN16( static word SIMD_SSE2_word_center_128[8] ) = { 128, 128, 0, 0, 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
ALIGN16( static word SIMD_SSE2_word_div_by_6[8] ) = { (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1, (1<<16)/6+1 };
ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
ALIGN16( static word SIMD_SSE2_word_scale_7_9_11_13[8] ) = { 7, 7, 9, 9, 11, 11, 13, 13 };
ALIGN16( static word SIMD_SSE2_word_scale_7_5_3_1[8] ) = { 7, 7, 5, 5, 3, 3, 1, 1 };
ALIGN16( static word SIMD_SSE2_word_scale_5_3_1[8] ) = { 5, 3, 1, 0, 5, 3, 1, 0 };
ALIGN16( static word SIMD_SSE2_word_scale_1_3_5[8] ) = { 1, 3, 5, 0, 1, 3, 5, 0 };
ALIGN16( static word SIMD_SSE2_word_insetShift[8] ) = { 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_ALPHA_SHIFT ), 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgRound[8] ) = { ((1<<(INSET_COLOR_SHIFT-1))-1), ((1<<(INSET_COLOR_SHIFT-1))-1), ((1<<(INSET_COLOR_SHIFT-1))-1), ((1<<(INSET_ALPHA_SHIFT-1))-1), 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgMask[8] ) = { 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgShiftUp[8] ) = { 1 << INSET_COLOR_SHIFT, 1 << INSET_COLOR_SHIFT, 1 << INSET_COLOR_SHIFT, 1 << INSET_ALPHA_SHIFT, 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgShiftDown[8] ) = { 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_COLOR_SHIFT ), 1 << ( 16 - INSET_ALPHA_SHIFT ), 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgQuantMask[8] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0xFF, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0xFF };
ALIGN16( static word SIMD_SSE2_word_insetYCoCgRep[8] ) = { 1 << ( 16 - 5 ), 1 << ( 16 - 6 ), 1 << ( 16 - 5 ), 0, 1 << ( 16 - 5 ), 1 << ( 16 - 6 ), 1 << ( 16 - 5 ), 0 };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5Round[8] ) = { 0, ((1<<(INSET_COLOR_SHIFT-1))-1), 0, ((1<<(INSET_ALPHA_SHIFT-1))-1), 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5Mask[8] ) = { 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000 };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5ShiftUp[8] ) = { 1, 1 << INSET_COLOR_SHIFT, 1, 1 << INSET_ALPHA_SHIFT, 1, 1, 1, 1 };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5ShiftDown[8] ) = { 0, 1 << ( 16 - INSET_COLOR_SHIFT ), 0, 1 << ( 16 - INSET_ALPHA_SHIFT ), 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5QuantMask[8] ) = { 0xFF, C565_6_MASK, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
ALIGN16( static word SIMD_SSE2_word_insetNormalDXT5Rep[8] ) = { 0, 1 << ( 16 - 6 ), 0, 0, 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetNormal3DcRound[8] ) = { ((1<<(INSET_ALPHA_SHIFT-1))-1), ((1<<(INSET_ALPHA_SHIFT-1))-1), 0, 0, 0, 0, 0, 0 };
ALIGN16( static word SIMD_SSE2_word_insetNormal3DcMask[8] ) = { 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
ALIGN16( static word SIMD_SSE2_word_insetNormal3DcShiftUp[8] ) = { 1 << INSET_ALPHA_SHIFT, 1 << INSET_ALPHA_SHIFT, 1, 1, 1, 1, 1, 1 };
ALIGN16( static word SIMD_SSE2_word_insetNormal3DcShiftDown[8] ) = { 1 << ( 16 - INSET_ALPHA_SHIFT ), 1 << ( 16 - INSET_ALPHA_SHIFT ), 0, 0, 0, 0, 0, 0 };
ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
ALIGN16( static byte SIMD_SSE2_byte_3[16] ) = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
ALIGN16( static byte SIMD_SSE2_byte_4[16] ) = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
ALIGN16( static byte SIMD_SSE2_byte_8[16] ) = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 };
ALIGN16( static byte SIMD_SSE2_byte_not[16] ) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_colorMask2[16] ) = { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_ctx1Mask[16] ) = { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_diagonalMask[16] ) = { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_scale_mask0[16] ) = { 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF };
ALIGN16( static byte SIMD_SSE2_byte_scale_mask1[16] ) = { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_scale_mask2[16] ) = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_scale_mask3[16] ) = { 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_scale_mask4[16] ) = { 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
ALIGN16( static byte SIMD_SSE2_byte_minus_128_0[16] ) = { (byte)-128, (byte)-128, 0, 0, (byte)-128, (byte)-128, 0, 0, (byte)-128, (byte)-128, 0, 0, (byte)-128, (byte)-128, 0, 0 };
/*
========================
idDxtEncoder::ExtractBlock_SSE2
params: inPtr - input image, 4 bytes per pixel
paramO: colorBlock - 4*4 output tile, 4 bytes per pixel
========================
*/
ID_INLINE void idDxtEncoder::ExtractBlock_SSE2( const byte * inPtr, int width, byte * colorBlock ) const {
*((__m128i *)(&colorBlock[ 0])) = _mm_load_si128( (__m128i *)( inPtr + width * 4 * 0 ) );
*((__m128i *)(&colorBlock[16])) = _mm_load_si128( (__m128i *)( inPtr + width * 4 * 1 ) );
*((__m128i *)(&colorBlock[32])) = _mm_load_si128( (__m128i *)( inPtr + width * 4 * 2 ) );
*((__m128i *)(&colorBlock[48])) = _mm_load_si128( (__m128i *)( inPtr + width * 4 * 3 ) );
}
/*
========================
idDxtEncoder::GetMinMaxBBox_SSE2
Takes the extents of the bounding box of the colors in the 4x4 block.
params: colorBlock - 4*4 input tile, 4 bytes per pixel
paramO: minColor - Min 4 byte output color
paramO: maxColor - Max 4 byte output color
========================
*/
ID_INLINE void idDxtEncoder::GetMinMaxBBox_SSE2( const byte * colorBlock, byte * minColor, byte * maxColor ) const {
__m128i block0 = *((__m128i *)(&colorBlock[ 0]));
__m128i block1 = *((__m128i *)(&colorBlock[16]));
__m128i block2 = *((__m128i *)(&colorBlock[32]));
__m128i block3 = *((__m128i *)(&colorBlock[48]));
__m128i max1 = _mm_max_epu8( block0, block1 );
__m128i min1 = _mm_min_epu8( block0, block1 );
__m128i max2 = _mm_max_epu8( block2, block3 );
__m128i min2 = _mm_min_epu8( block2, block3 );
__m128i max3 = _mm_max_epu8( max1, max2 );
__m128i min3 = _mm_min_epu8( min1, min2 );
__m128i max4 = _mm_shuffle_epi32( max3, R_SHUFFLE_D( 2, 3, 2, 3 ) );
__m128i min4 = _mm_shuffle_epi32( min3, R_SHUFFLE_D( 2, 3, 2, 3 ) );
__m128i max5 = _mm_max_epu8( max3, max4 );
__m128i min5 = _mm_min_epu8( min3, min4 );
__m128i max6 = _mm_shufflelo_epi16( max5, R_SHUFFLE_D( 2, 3, 2, 3 ) );
__m128i min6 = _mm_shufflelo_epi16( min5, R_SHUFFLE_D( 2, 3, 2, 3 ) );
max6 = _mm_max_epu8( max5, max6 );
min6 = _mm_min_epu8( min5, min6 );
*((int *)maxColor) = _mm_cvtsi128_si32( max6 );
*((int *)minColor) = _mm_cvtsi128_si32( min6 );
}
/*
========================
idDxtEncoder::InsetColorsBBox_SSE2
========================
*/
ID_INLINE void idDxtEncoder::InsetColorsBBox_SSE2( byte * minColor, byte * maxColor ) const {
__m128i min = _mm_cvtsi32_si128( *(int *)minColor );
__m128i max = _mm_cvtsi32_si128( *(int *)maxColor );
__m128i xmm0 = _mm_unpacklo_epi8( min, *(__m128i *)SIMD_SSE2_byte_0 );
__m128i xmm1 = _mm_unpacklo_epi8( max, *(__m128i *)SIMD_SSE2_byte_0 );
__m128i xmm2 = _mm_sub_epi16( xmm1, xmm0 );
xmm2 = _mm_mulhi_epi16( xmm2, *(__m128i *)SIMD_SSE2_word_insetShift );
xmm0 = _mm_add_epi16( xmm0, xmm2 );
xmm1 = _mm_sub_epi16( xmm1, xmm2 );
xmm0 = _mm_packus_epi16( xmm0, xmm0 );
xmm1 = _mm_packus_epi16( xmm1, xmm1 );
*((int *)minColor) = _mm_cvtsi128_si32( xmm0 );
*((int *)maxColor) = _mm_cvtsi128_si32( xmm1 );
}
/*
========================
idDxtEncoder::EmitColorIndices_SSE2
params: colorBlock - 16 pixel block for which to find color indices
paramO: minColor - Min alpha found
paramO: maxColor - Max alpha found
return: 4 byte color index block
========================
*/
void idDxtEncoder::EmitColorIndices_SSE2( const byte * colorBlock, const byte * minColor_, const byte * maxColor_ ) {
__m128c zero = SIMD_SSE2_zero;
__m128c result = SIMD_SSE2_zero;
__m128c color0, color1, color2, color3;
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
__m128c minColor = _mm_cvtsi32_si128( *(int *)minColor_ );
__m128c maxColor = _mm_cvtsi32_si128( *(int *)maxColor_ );
__m128c blocka[2], blockb[2];
blocka[0] = *((__m128i *)(&colorBlock[ 0]));
blocka[1] = *((__m128i *)(&colorBlock[32]));
blockb[0] = *((__m128i *)(&colorBlock[16]));
blockb[1] = *((__m128i *)(&colorBlock[48]));
temp0 = _mm_and_si128( maxColor, (const __m128i &)SIMD_SSE2_byte_colorMask );
temp0 = _mm_unpacklo_epi8( temp0, zero );
temp4 = _mm_shufflelo_epi16( temp0, R_SHUFFLE_D( 0, 3, 2, 3 ) );
temp5 = _mm_shufflelo_epi16( temp0, R_SHUFFLE_D( 3, 1, 3, 3 ) );
temp4 = _mm_srli_epi16( temp4, 5 );
temp5 = _mm_srli_epi16( temp5, 6 );
temp0 = _mm_or_si128( temp0, temp4 );
temp0 = _mm_or_si128( temp0, temp5 );
temp1 = _mm_and_si128( minColor, (const __m128i &)SIMD_SSE2_byte_colorMask );
temp1 = _mm_unpacklo_epi8( temp1, zero );
temp4 = _mm_shufflelo_epi16( temp1, R_SHUFFLE_D( 0, 3, 2, 3 ) );
temp5 = _mm_shufflelo_epi16( temp1, R_SHUFFLE_D( 3, 1, 3, 3 ) );
temp4 = _mm_srli_epi16( temp4, 5 );
temp5 = _mm_srli_epi16( temp5, 6 );
temp1 = _mm_or_si128( temp1, temp4 );
temp1 = _mm_or_si128( temp1, temp5 );
temp2 = _mm_packus_epi16( temp0, zero );
color0 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp6 = _mm_add_epi16( temp0, temp0 );
temp6 = _mm_add_epi16( temp6, temp1 );
temp6 = _mm_mulhi_epi16( temp6, (const __m128i &)SIMD_SSE2_word_div_by_3 ); // * ( ( 1 << 16 ) / 3 + 1 ) ) >> 16
temp6 = _mm_packus_epi16( temp6, zero );
color2 = _mm_shuffle_epi32( temp6, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp3 = _mm_packus_epi16( temp1, zero );
color1 = _mm_shuffle_epi32( temp3, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp1 = _mm_add_epi16( temp1, temp1 );
temp0 = _mm_add_epi16( temp0, temp1 );
temp0 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_div_by_3 ); // * ( ( 1 << 16 ) / 3 + 1 ) ) >> 16
temp0 = _mm_packus_epi16( temp0, zero );
color3 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 0, 1, 0, 1 ) );
for ( int i = 1; i >= 0; i-- ) {
// Load block
temp3 = _mm_shuffle_epi32( blocka[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blocka[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp0 = _mm_sad_epu8( temp3, color0 );
temp6 = _mm_sad_epu8( temp5, color0 );
temp0 = _mm_packs_epi32( temp0, temp6 );
temp1 = _mm_sad_epu8( temp3, color1 );
temp6 = _mm_sad_epu8( temp5, color1 );
temp1 = _mm_packs_epi32( temp1, temp6 );
temp2 = _mm_sad_epu8( temp3, color2 );
temp6 = _mm_sad_epu8( temp5, color2 );
temp2 = _mm_packs_epi32( temp2, temp6 );
temp3 = _mm_sad_epu8( temp3, color3 );
temp5 = _mm_sad_epu8( temp5, color3 );
temp3 = _mm_packs_epi32( temp3, temp5 );
// Load block
temp4 = _mm_shuffle_epi32( blockb[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blockb[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp6 = _mm_sad_epu8( temp4, color0 );
temp7 = _mm_sad_epu8( temp5, color0 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp0 = _mm_packs_epi32( temp0, temp6 ); // d0
temp6 = _mm_sad_epu8( temp4, color1 );
temp7 = _mm_sad_epu8( temp5, color1 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp1 = _mm_packs_epi32( temp1, temp6 ); // d1
temp6 = _mm_sad_epu8( temp4, color2 );
temp7 = _mm_sad_epu8( temp5, color2 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp2 = _mm_packs_epi32( temp2, temp6 ); // d2
temp4 = _mm_sad_epu8( temp4, color3 );
temp5 = _mm_sad_epu8( temp5, color3 );
temp4 = _mm_packs_epi32( temp4, temp5 );
temp3 = _mm_packs_epi32( temp3, temp4 ); // d3
temp7 = _mm_slli_epi32( result, 16 );
temp4 = _mm_cmpgt_epi16( temp0, temp2 ); // b2
temp5 = _mm_cmpgt_epi16( temp1, temp3 ); // b3
temp0 = _mm_cmpgt_epi16( temp0, temp3 ); // b0
temp1 = _mm_cmpgt_epi16( temp1, temp2 ); // b1
temp2 = _mm_cmpgt_epi16( temp2, temp3 ); // b4
temp4 = _mm_and_si128( temp4, temp1 ); // x0
temp5 = _mm_and_si128( temp5, temp0 ); // x1
temp2 = _mm_and_si128( temp2, temp0 ); // x2
temp4 = _mm_or_si128( temp4, temp5 );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_1 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_word_2 );
temp2 = _mm_or_si128( temp2, temp4 );
temp5 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp2 = _mm_unpacklo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_unpacklo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_slli_epi32( temp5, 8 );
temp7 = _mm_or_si128( temp7, temp5 );
result = _mm_or_si128( temp7, temp2 );
}
temp4 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 1, 2, 3, 0 ) );
temp5 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp6 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 3, 0, 1, 2 ) );
temp4 = _mm_slli_epi32( temp4, 2 );
temp5 = _mm_slli_epi32( temp5, 4 );
temp6 = _mm_slli_epi32( temp6, 6 );
temp7 = _mm_or_si128( result, temp4 );
temp7 = _mm_or_si128( temp7, temp5 );
temp7 = _mm_or_si128( temp7, temp6 );
unsigned int out = _mm_cvtsi128_si32( temp7 );
EmitUInt( out );
}
/*
========================
idDxtEncoder::EmitColorAlphaIndices_SSE2
params: colorBlock - 16 pixel block for which find color indexes
paramO: minColor - Min color found
paramO: maxColor - Max color found
return: 4 byte color index block
========================
*/
void idDxtEncoder::EmitColorAlphaIndices_SSE2( const byte *colorBlock, const byte *minColor_, const byte *maxColor_ ) {
__m128c zero = SIMD_SSE2_zero;
__m128c result = SIMD_SSE2_zero;
__m128c color0, color1, color2;
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
__m128c minColor = _mm_cvtsi32_si128( *(int *)minColor_ );
__m128c maxColor = _mm_cvtsi32_si128( *(int *)maxColor_ );
__m128c blocka[2], blockb[2];
blocka[0] = *((__m128i *)(&colorBlock[ 0]));
blocka[1] = *((__m128i *)(&colorBlock[32]));
blockb[0] = *((__m128i *)(&colorBlock[16]));
blockb[1] = *((__m128i *)(&colorBlock[48]));
temp0 = _mm_and_si128( maxColor, *(__m128c*)SIMD_SSE2_byte_colorMask );
temp0 = _mm_unpacklo_epi8( temp0, zero );
temp4 = _mm_shufflelo_epi16( temp0, R_SHUFFLE_D( 0, 3, 2, 3 ) );
temp5 = _mm_shufflelo_epi16( temp0, R_SHUFFLE_D( 3, 1, 3, 3 ) );
temp4 = _mm_srli_epi16( temp4, 5 );
temp5 = _mm_srli_epi16( temp5, 6 );
temp0 = _mm_or_si128( temp0, temp4 );
temp0 = _mm_or_si128( temp0, temp5 );
temp1 = _mm_and_si128( minColor, *(__m128c*)SIMD_SSE2_byte_colorMask );
temp1 = _mm_unpacklo_epi8( temp1, zero );
temp4 = _mm_shufflelo_epi16( temp1, R_SHUFFLE_D( 0, 3, 2, 3 ) );
temp5 = _mm_shufflelo_epi16( temp1, R_SHUFFLE_D( 3, 1, 3, 3 ) );
temp4 = _mm_srli_epi16( temp4, 5 );
temp5 = _mm_srli_epi16( temp5, 6 );
temp1 = _mm_or_si128( temp1, temp4 );
temp1 = _mm_or_si128( temp1, temp5 );
temp2 = _mm_packus_epi16( temp0, zero );
color0 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp6 = _mm_add_epi16( temp0, temp0 );
temp6 = _mm_srli_epi16( temp6, 1 ); // diff from color
temp6 = _mm_packus_epi16( temp6, zero );
color2 = _mm_shuffle_epi32( temp6, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp3 = _mm_packus_epi16( temp1, zero );
color1 = _mm_shuffle_epi32( temp3, R_SHUFFLE_D( 0, 1, 0, 1 ) );
// not used
//color3 = zero;
for ( int i = 1; i >= 0; i-- ) {
// Load block
temp3 = _mm_shuffle_epi32( blocka[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blocka[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp0 = _mm_sad_epu8( temp3, color0 );
temp6 = _mm_sad_epu8( temp5, color0 );
temp0 = _mm_packs_epi32( temp0, temp6 );
temp1 = _mm_sad_epu8( temp3, color1 );
temp6 = _mm_sad_epu8( temp5, color1 );
temp1 = _mm_packs_epi32( temp1, temp6 );
temp2 = _mm_sad_epu8( temp3, color2 );
temp6 = _mm_sad_epu8( temp5, color2 );
temp2 = _mm_packs_epi32( temp2, temp6 );
// diff from color
temp3 = _mm_shuffle_ps( temp3, temp5, R_SHUFFLE_D( 0, 2, 0, 2 ) );
temp3 = _mm_srli_epi32( temp3, 24 );
temp3 = _mm_packs_epi32( temp3, temp3 );
// Load block
temp4 = _mm_shuffle_epi32( blockb[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blockb[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp6 = _mm_sad_epu8( temp4, color0 );
temp7 = _mm_sad_epu8( temp5, color0 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp0 = _mm_packs_epi32( temp0, temp6 ); // d0
temp6 = _mm_sad_epu8( temp4, color1 );
temp7 = _mm_sad_epu8( temp5, color1 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp1 = _mm_packs_epi32( temp1, temp6 ); // d1
temp6 = _mm_sad_epu8( temp4, color2 );
temp7 = _mm_sad_epu8( temp5, color2 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp2 = _mm_packs_epi32( temp2, temp6 ); // d2
// diff from color
temp4 = _mm_shuffle_ps( temp4, temp5, R_SHUFFLE_D( 0, 2, 0, 2 ) ); // c3
temp4 = _mm_srli_epi32( temp4, 24 );
temp4 = _mm_packs_epi32( temp4, temp4 );
temp3 = _mm_unpacklo_epi64( temp3, temp4 );
temp7 = _mm_slli_epi32( result, 16 );
// diff from color
temp4 = _mm_cmpgt_epi16( temp2, temp1 ); // b1
temp2 = _mm_cmpgt_epi16( temp2, temp0 ); // b0
temp1 = _mm_cmpgt_epi16( temp1, temp0 ); // b2
temp3 = _mm_max_epi16( temp3, (const __m128i &)SIMD_SSE2_word_127 ); // b3
temp3 = _mm_cmpeq_epi16( temp3, (const __m128i &)SIMD_SSE2_word_127 );
temp2 = _mm_and_si128( temp2, temp4 );
temp2 = _mm_or_si128( temp2, temp3 ); // b0 & b1 | b3
temp1 = _mm_xor_si128( temp1, temp4 );
temp1 = _mm_or_si128( temp1, temp3 ); // b2 ^ b1 | b3
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_2 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_word_1 );
temp2 = _mm_or_si128( temp2, temp1 );
temp5 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp2 = _mm_unpacklo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_unpacklo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_slli_epi32( temp5, 8 );
temp7 = _mm_or_si128( temp7, temp5 );
result = _mm_or_si128( temp7, temp2 );
}
temp4 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 1, 2, 3, 0 ) );
temp5 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp6 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 3, 0, 1, 2 ) );
temp4 = _mm_slli_epi32( temp4, 2 );
temp5 = _mm_slli_epi32( temp5, 4 );
temp6 = _mm_slli_epi32( temp6, 6 );
temp7 = _mm_or_si128( result, temp4 );
temp7 = _mm_or_si128( temp7, temp5 );
temp7 = _mm_or_si128( temp7, temp6 );
unsigned int out = _mm_cvtsi128_si32( temp7 );
EmitUInt( out );
}
/*
========================
idDxtEncoder::EmitCoCgIndices_SSE2
params: colorBlock - 16 pixel block for which to find color indices
paramO: minColor - Min alpha found
paramO: maxColor - Max alpha found
return: 4 byte color index block
========================
*/
void idDxtEncoder::EmitCoCgIndices_SSE2( const byte *colorBlock, const byte *minColor_, const byte *maxColor_ ) {
__m128c zero = SIMD_SSE2_zero;
__m128c result = SIMD_SSE2_zero;
__m128c color0, color1, color2, color3;
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
__m128c minColor = _mm_cvtsi32_si128( *(int *)minColor_ );
__m128c maxColor = _mm_cvtsi32_si128( *(int *)maxColor_ );
__m128c blocka[2], blockb[2];
blocka[0] = *((__m128i *)(&colorBlock[ 0]));
blocka[1] = *((__m128i *)(&colorBlock[32]));
blockb[0] = *((__m128i *)(&colorBlock[16]));
blockb[1] = *((__m128i *)(&colorBlock[48]));
temp7 = zero;
temp0 = maxColor;
temp0 = _mm_and_si128( temp0, *(__m128c*)SIMD_SSE2_byte_colorMask2 );
color0 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp1 = minColor;
temp1 = _mm_and_si128( temp1, *(__m128c*)SIMD_SSE2_byte_colorMask2 );
color1 = _mm_shuffle_epi32( temp1, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp0 = _mm_unpacklo_epi8( color0, zero );
temp1 = _mm_unpacklo_epi8( color1, zero );
temp6 = _mm_add_epi16( temp1, temp0 );
temp0 = _mm_add_epi16( temp0, temp6 );
temp0 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_div_by_3 ); // * ( ( 1 << 16 ) / 3 + 1 ) ) >> 16
temp0 = _mm_packus_epi16( temp0, zero );
color2 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 0, 1, 0, 1 ) );
temp1 = _mm_add_epi16( temp1, temp6 );
temp1 = _mm_mulhi_epi16( temp1, (const __m128i &)SIMD_SSE2_word_div_by_3 ); // * ( ( 1 << 16 ) / 3 + 1 ) ) >> 16
temp1 = _mm_packus_epi16( temp1, zero );
color3 = _mm_shuffle_epi32( temp1, R_SHUFFLE_D( 0, 1, 0, 1 ) );
for ( int i = 1; i >= 0; i-- ) {
// Load block
temp3 = _mm_shuffle_epi32( blocka[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blocka[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp0 = _mm_sad_epu8( temp3, color0 );
temp6 = _mm_sad_epu8( temp5, color0 );
temp0 = _mm_packs_epi32( temp0, temp6 );
temp1 = _mm_sad_epu8( temp3, color1 );
temp6 = _mm_sad_epu8( temp5, color1 );
temp1 = _mm_packs_epi32( temp1, temp6 );
temp2 = _mm_sad_epu8( temp3, color2 );
temp6 = _mm_sad_epu8( temp5, color2 );
temp2 = _mm_packs_epi32( temp2, temp6 );
temp3 = _mm_sad_epu8( temp3, color3 );
temp5 = _mm_sad_epu8( temp5, color3 );
temp3 = _mm_packs_epi32( temp3, temp5 );
// Load block
temp4 = _mm_shuffle_epi32( blockb[i], R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp5 = _mm_shuffle_ps( blockb[i], zero, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp6 = _mm_sad_epu8( temp4, color0 );
temp7 = _mm_sad_epu8( temp5, color0 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp0 = _mm_packs_epi32( temp0, temp6 ); // d0
temp6 = _mm_sad_epu8( temp4, color1 );
temp7 = _mm_sad_epu8( temp5, color1 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp1 = _mm_packs_epi32( temp1, temp6 ); // d1
temp6 = _mm_sad_epu8( temp4, color2 );
temp7 = _mm_sad_epu8( temp5, color2 );
temp6 = _mm_packs_epi32( temp6, temp7 );
temp2 = _mm_packs_epi32( temp2, temp6 ); // d2
temp4 = _mm_sad_epu8( temp4, color3 );
temp5 = _mm_sad_epu8( temp5, color3 );
temp4 = _mm_packs_epi32( temp4, temp5 );
temp3 = _mm_packs_epi32( temp3, temp4 ); // d3
temp7 = _mm_slli_epi32( result, 16 );
temp4 = _mm_cmpgt_epi16( temp0, temp2 ); // b2
temp5 = _mm_cmpgt_epi16( temp1, temp3 ); // b3
temp0 = _mm_cmpgt_epi16( temp0, temp3 ); // b0
temp1 = _mm_cmpgt_epi16( temp1, temp2 ); // b1
temp2 = _mm_cmpgt_epi16( temp2, temp3 ); // b4
temp4 = _mm_and_si128( temp4, temp1 ); // x0
temp5 = _mm_and_si128( temp5, temp0 ); // x1
temp2 = _mm_and_si128( temp2, temp0 ); // x2
temp4 = _mm_or_si128( temp4, temp5 );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_1 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_word_2 );
temp2 = _mm_or_si128( temp2, temp4 );
temp5 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp2 = _mm_unpacklo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_unpacklo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_0 );
temp5 = _mm_slli_epi32( temp5, 8 );
temp7 = _mm_or_si128( temp7, temp5 );
result = _mm_or_si128( temp7, temp2 );
}
temp4 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 1, 2, 3, 0 ) );
temp5 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 2, 3, 0, 1 ) );
temp6 = _mm_shuffle_epi32( result, R_SHUFFLE_D( 3, 0, 1, 2 ) );
temp4 = _mm_slli_epi32( temp4, 2 );
temp5 = _mm_slli_epi32( temp5, 4 );
temp6 = _mm_slli_epi32( temp6, 6 );
temp7 = _mm_or_si128( result, temp4 );
temp7 = _mm_or_si128( temp7, temp5 );
temp7 = _mm_or_si128( temp7, temp6 );
unsigned int out = _mm_cvtsi128_si32( temp7 );
EmitUInt( out );
}
/*
========================
idDxtEncoder::EmitAlphaIndices_SSE2
params: block - 16 pixel block for which to find alpha indices
paramO: minAlpha - Min alpha found
paramO: maxAlpha - Max alpha found
========================
*/
void idDxtEncoder::EmitAlphaIndices_SSE2( const byte *block, const int minAlpha_, const int maxAlpha_ ) {
__m128i block0 = *((__m128i *)(&block[ 0]));
__m128i block1 = *((__m128i *)(&block[16]));
__m128i block2 = *((__m128i *)(&block[32]));
__m128i block3 = *((__m128i *)(&block[48]));
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp0 = _mm_srli_epi32( block0, 24 );
temp5 = _mm_srli_epi32( block1, 24 );
temp6 = _mm_srli_epi32( block2, 24 );
temp4 = _mm_srli_epi32( block3, 24 );
temp0 = _mm_packus_epi16( temp0, temp5 );
temp6 = _mm_packus_epi16( temp6, temp4 );
//---------------------
// ab0 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / 14
// ab3 = ( 9 * maxAlpha + 5 * minAlpha + ALPHA_RANGE ) / 14
// ab2 = ( 11 * maxAlpha + 3 * minAlpha + ALPHA_RANGE ) / 14
// ab1 = ( 13 * maxAlpha + 1 * minAlpha + ALPHA_RANGE ) / 14
// ab4 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / 14
// ab5 = ( 5 * maxAlpha + 9 * minAlpha + ALPHA_RANGE ) / 14
// ab6 = ( 3 * maxAlpha + 11 * minAlpha + ALPHA_RANGE ) / 14
// ab7 = ( 1 * maxAlpha + 13 * minAlpha + ALPHA_RANGE ) / 14
temp5 = _mm_cvtsi32_si128( maxAlpha_ );
temp5 = _mm_shufflelo_epi16( temp5, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_cvtsi32_si128( minAlpha_ );
temp2 = _mm_shufflelo_epi16( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp7 = _mm_mullo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_scale_7_5_3_1 );
temp5 = _mm_mullo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_scale_7_9_11_13 );
temp3 = _mm_mullo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_scale_7_9_11_13 );
temp2 = _mm_mullo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_scale_7_5_3_1 );
temp5 = _mm_add_epi16( temp5, temp2 );
temp7 = _mm_add_epi16( temp7, temp3 );
temp5 = _mm_add_epi16( temp5, (const __m128i &)SIMD_SSE2_word_7 );
temp7 = _mm_add_epi16( temp7, (const __m128i &)SIMD_SSE2_word_7 );
temp5 = _mm_mulhi_epi16( temp5, (const __m128i &)SIMD_SSE2_word_div_by_14 );
temp7 = _mm_mulhi_epi16( temp7, (const __m128i &)SIMD_SSE2_word_div_by_14 );
temp1 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 3, 3, 3, 3 ) );
temp2 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 2, 2, 2, 2 ) );
temp3 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 1, 1, 1, 1 ) );
temp1 = _mm_packus_epi16( temp1, temp1 );
temp2 = _mm_packus_epi16( temp2, temp2 );
temp3 = _mm_packus_epi16( temp3, temp3 );
temp0 = _mm_packus_epi16( temp0, temp6 );
temp4 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp5 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 1, 1, 1, 1 ) );
temp6 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 2, 2, 2, 2 ) );
temp7 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 3, 3, 3, 3 ) );
temp4 = _mm_packus_epi16( temp4, temp4 );
temp5 = _mm_packus_epi16( temp5, temp5 );
temp6 = _mm_packus_epi16( temp6, temp6 );
temp7 = _mm_packus_epi16( temp7, temp7 );
temp1 = _mm_max_epu8( temp1, temp0 );
temp2 = _mm_max_epu8( temp2, temp0 );
temp3 = _mm_max_epu8( temp3, temp0 );
temp1 = _mm_cmpeq_epi8( temp1, temp0 );
temp2 = _mm_cmpeq_epi8( temp2, temp0 );
temp3 = _mm_cmpeq_epi8( temp3, temp0 );
temp4 = _mm_max_epu8( temp4, temp0 );
temp5 = _mm_max_epu8( temp5, temp0 );
temp6 = _mm_max_epu8( temp6, temp0 );
temp7 = _mm_max_epu8( temp7, temp0 );
temp4 = _mm_cmpeq_epi8( temp4, temp0 );
temp5 = _mm_cmpeq_epi8( temp5, temp0 );
temp6 = _mm_cmpeq_epi8( temp6, temp0 );
temp7 = _mm_cmpeq_epi8( temp7, temp0 );
temp0 = _mm_adds_epi8( (const __m128i &)SIMD_SSE2_byte_8, temp1 );
temp2 = _mm_adds_epi8( temp2, temp3 );
temp4 = _mm_adds_epi8( temp4, temp5 );
temp6 = _mm_adds_epi8( temp6, temp7 );
temp0 = _mm_adds_epi8( temp0, temp2 );
temp4 = _mm_adds_epi8( temp4, temp6 );
temp0 = _mm_adds_epi8( temp0, temp4 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_byte_7 );
temp1 = _mm_cmpgt_epi8( (const __m128i &)SIMD_SSE2_byte_2, temp0 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_byte_1 );
temp0 = _mm_xor_si128( temp0, temp1 );
temp1 = _mm_srli_epi64( temp0, 8 - 3 );
temp2 = _mm_srli_epi64( temp0, 16 - 6 );
temp3 = _mm_srli_epi64( temp0, 24 - 9 );
temp4 = _mm_srli_epi64( temp0, 32 - 12 );
temp5 = _mm_srli_epi64( temp0, 40 - 15 );
temp6 = _mm_srli_epi64( temp0, 48 - 18 );
temp7 = _mm_srli_epi64( temp0, 56 - 21 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask0 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask1 );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask2 );
temp3 = _mm_and_si128( temp3, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask3 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask4 );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask5 );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask6 );
temp7 = _mm_and_si128( temp7, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask7 );
temp0 = _mm_or_si128( temp0, temp1 );
temp2 = _mm_or_si128( temp2, temp3 );
temp4 = _mm_or_si128( temp4, temp5 );
temp6 = _mm_or_si128( temp6, temp7 );
temp0 = _mm_or_si128( temp0, temp2 );
temp4 = _mm_or_si128( temp4, temp6 );
temp0 = _mm_or_si128( temp0, temp4 );
int out = _mm_cvtsi128_si32( temp0 );
EmitUInt( out );
outData--;
temp1 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 2, 3, 0, 1 ) );
out = _mm_cvtsi128_si32( temp1 );
EmitUInt( out );
outData--;
}
/*
========================
idDxtEncoder::EmitAlphaIndices_SSE2
========================
*/
void idDxtEncoder::EmitAlphaIndices_SSE2( const byte *block, const int channelBitOffset, const int minAlpha_, const int maxAlpha_ ) {
__m128i block0 = *((__m128i *)(&block[ 0]));
__m128i block1 = *((__m128i *)(&block[16]));
__m128i block2 = *((__m128i *)(&block[32]));
__m128i block3 = *((__m128i *)(&block[48]));
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp7 = _mm_cvtsi32_si128( channelBitOffset );
temp0 = _mm_srl_epi32( block0, temp7 );
temp5 = _mm_srl_epi32( block1, temp7 );
temp6 = _mm_srl_epi32( block2, temp7 );
temp4 = _mm_srl_epi32( block3, temp7 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp0 = _mm_packus_epi16( temp0, temp5 );
temp6 = _mm_packus_epi16( temp6, temp4 );
//---------------------
// ab0 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / 14
// ab3 = ( 9 * maxAlpha + 5 * minAlpha + ALPHA_RANGE ) / 14
// ab2 = ( 11 * maxAlpha + 3 * minAlpha + ALPHA_RANGE ) / 14
// ab1 = ( 13 * maxAlpha + 1 * minAlpha + ALPHA_RANGE ) / 14
// ab4 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / 14
// ab5 = ( 5 * maxAlpha + 9 * minAlpha + ALPHA_RANGE ) / 14
// ab6 = ( 3 * maxAlpha + 11 * minAlpha + ALPHA_RANGE ) / 14
// ab7 = ( 1 * maxAlpha + 13 * minAlpha + ALPHA_RANGE ) / 14
temp5 = _mm_cvtsi32_si128( maxAlpha_ );
temp5 = _mm_shufflelo_epi16( temp5, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp5 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_cvtsi32_si128( minAlpha_ );
temp2 = _mm_shufflelo_epi16( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp7 = _mm_mullo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_scale_7_5_3_1 );
temp5 = _mm_mullo_epi16( temp5, (const __m128i &)SIMD_SSE2_word_scale_7_9_11_13 );
temp3 = _mm_mullo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_scale_7_9_11_13 );
temp2 = _mm_mullo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_scale_7_5_3_1 );
temp5 = _mm_add_epi16( temp5, temp2 );
temp7 = _mm_add_epi16( temp7, temp3 );
temp5 = _mm_add_epi16( temp5, (const __m128i &)SIMD_SSE2_word_7 );
temp7 = _mm_add_epi16( temp7, (const __m128i &)SIMD_SSE2_word_7 );
temp5 = _mm_mulhi_epi16( temp5, (const __m128i &)SIMD_SSE2_word_div_by_14 );
temp7 = _mm_mulhi_epi16( temp7, (const __m128i &)SIMD_SSE2_word_div_by_14 );
temp1 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 3, 3, 3, 3 ) );
temp2 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 2, 2, 2, 2 ) );
temp3 = _mm_shuffle_epi32( temp5, R_SHUFFLE_D( 1, 1, 1, 1 ) );
temp1 = _mm_packus_epi16( temp1, temp1 );
temp2 = _mm_packus_epi16( temp2, temp2 );
temp3 = _mm_packus_epi16( temp3, temp3 );
temp0 = _mm_packus_epi16( temp0, temp6 );
temp4 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp5 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 1, 1, 1, 1 ) );
temp6 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 2, 2, 2, 2 ) );
temp7 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 3, 3, 3, 3 ) );
temp4 = _mm_packus_epi16( temp4, temp4 );
temp5 = _mm_packus_epi16( temp5, temp5 );
temp6 = _mm_packus_epi16( temp6, temp6 );
temp7 = _mm_packus_epi16( temp7, temp7 );
temp1 = _mm_max_epu8( temp1, temp0 );
temp2 = _mm_max_epu8( temp2, temp0 );
temp3 = _mm_max_epu8( temp3, temp0 );
temp1 = _mm_cmpeq_epi8( temp1, temp0 );
temp2 = _mm_cmpeq_epi8( temp2, temp0 );
temp3 = _mm_cmpeq_epi8( temp3, temp0 );
temp4 = _mm_max_epu8( temp4, temp0 );
temp5 = _mm_max_epu8( temp5, temp0 );
temp6 = _mm_max_epu8( temp6, temp0 );
temp7 = _mm_max_epu8( temp7, temp0 );
temp4 = _mm_cmpeq_epi8( temp4, temp0 );
temp5 = _mm_cmpeq_epi8( temp5, temp0 );
temp6 = _mm_cmpeq_epi8( temp6, temp0 );
temp7 = _mm_cmpeq_epi8( temp7, temp0 );
temp0 = _mm_adds_epi8( (const __m128i &)SIMD_SSE2_byte_8, temp1 );
temp2 = _mm_adds_epi8( temp2, temp3 );
temp4 = _mm_adds_epi8( temp4, temp5 );
temp6 = _mm_adds_epi8( temp6, temp7 );
temp0 = _mm_adds_epi8( temp0, temp2 );
temp4 = _mm_adds_epi8( temp4, temp6 );
temp0 = _mm_adds_epi8( temp0, temp4 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_byte_7 );
temp1 = _mm_cmpgt_epi8( (const __m128i &)SIMD_SSE2_byte_2, temp0 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_byte_1 );
temp0 = _mm_xor_si128( temp0, temp1 );
temp1 = _mm_srli_epi64( temp0, 8 - 3 );
temp2 = _mm_srli_epi64( temp0, 16 - 6 );
temp3 = _mm_srli_epi64( temp0, 24 - 9 );
temp4 = _mm_srli_epi64( temp0, 32 - 12 );
temp5 = _mm_srli_epi64( temp0, 40 - 15 );
temp6 = _mm_srli_epi64( temp0, 48 - 18 );
temp7 = _mm_srli_epi64( temp0, 56 - 21 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask0 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask1 );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask2 );
temp3 = _mm_and_si128( temp3, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask3 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask4 );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask5 );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask6 );
temp7 = _mm_and_si128( temp7, (const __m128i &)SIMD_SSE2_dword_alpha_bit_mask7 );
temp0 = _mm_or_si128( temp0, temp1 );
temp2 = _mm_or_si128( temp2, temp3 );
temp4 = _mm_or_si128( temp4, temp5 );
temp6 = _mm_or_si128( temp6, temp7 );
temp0 = _mm_or_si128( temp0, temp2 );
temp4 = _mm_or_si128( temp4, temp6 );
temp0 = _mm_or_si128( temp0, temp4 );
int out = _mm_cvtsi128_si32( temp0 );
EmitUInt( out );
outData--;
temp1 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 2, 3, 0, 1 ) );
out = _mm_cvtsi128_si32( temp1 );
EmitUInt( out );
outData--;
}
/*
========================
idDxtEncoder::CompressImageDXT1Fast_SSE2
params: inBuf - image to compress
paramO: outBuf - result of compression
params: width - width of image
params: height - height of image
========================
*/
void idDxtEncoder::CompressImageDXT1Fast_SSE2( const byte *inBuf, byte *outBuf, int width, int height ) {
ALIGN16( byte block[64] );
ALIGN16( byte minColor[4] );
ALIGN16( byte maxColor[4] );
assert( width >= 4 && ( width & 3 ) == 0 );
assert( height >= 4 && ( height & 3 ) == 0 );
this->width = width;
this->height = height;
this->outData = outBuf;
for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
for ( int i = 0; i < width; i += 4 ) {
ExtractBlock_SSE2( inBuf + i * 4, width, block );
GetMinMaxBBox_SSE2( block, minColor, maxColor );
InsetColorsBBox_SSE2( minColor, maxColor );
EmitUShort( ColorTo565( maxColor ) );
EmitUShort( ColorTo565( minColor ) );
EmitColorIndices_SSE2( block, minColor, maxColor );
}
outData += dstPadding;
inBuf += srcPadding;
}
#ifdef TEST_COMPRESSION
int tmpDstPadding = dstPadding;
dstPadding = 0;
byte * testOutBuf = (byte *) _alloca16( width * height / 2 );
CompressImageDXT1Fast_Generic( inBuf, testOutBuf, width, height );
for ( int j = 0; j < height/4; j++ ) {
for ( int i = 0; i < width/4; i++ ) {
byte * ptr1 = outBuf + ( j * width/4 + i ) * 8 + j * tmpDstPadding;
byte * ptr2 = testOutBuf + ( j * width/4 + i ) * 8;
for ( int k = 0; k < 8; k++ ) {
assert( ptr1[k] == ptr2[k] );
}
}
}
dstPadding = tmpDstPadding;
#endif
}
/*
========================
idDxtEncoder::CompressImageDXT1AlphaFast_SSE2
params: inBuf - image to compress
paramO: outBuf - result of compression
params: width - width of image
params: height - height of image
========================
*/
void idDxtEncoder::CompressImageDXT1AlphaFast_SSE2( const byte *inBuf, byte *outBuf, int width, int height ) {
ALIGN16( byte block[64] );
ALIGN16( byte minColor[4] );
ALIGN16( byte maxColor[4] );
assert( width >= 4 && ( width & 3 ) == 0 );
assert( height >= 4 && ( height & 3 ) == 0 );
this->width = width;
this->height = height;
this->outData = outBuf;
for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
for ( int i = 0; i < width; i += 4 ) {
ExtractBlock_SSE2( inBuf + i * 4, width, block );
GetMinMaxBBox_SSE2( block, minColor, maxColor );
byte minAlpha = minColor[3];
InsetColorsBBox_SSE2( minColor, maxColor );
if ( minAlpha >= 128 ) {
EmitUShort( ColorTo565( maxColor ) );
EmitUShort( ColorTo565( minColor ) );
EmitColorIndices_SSE2( block, minColor, maxColor );
} else {
EmitUShort( ColorTo565( minColor ) );
EmitUShort( ColorTo565( maxColor ) );
EmitColorAlphaIndices_SSE2( block, minColor, maxColor );
}
}
outData += dstPadding;
inBuf += srcPadding;
}
#ifdef TEST_COMPRESSION
int tmpDstPadding = dstPadding;
dstPadding = 0;
byte * testOutBuf = (byte *) _alloca16( width * height / 2 );
CompressImageDXT1AlphaFast_Generic( inBuf, testOutBuf, width, height );
for ( int j = 0; j < height/4; j++ ) {
for ( int i = 0; i < width/4; i++ ) {
byte * ptr1 = outBuf + ( j * width/4 + i ) * 8 + j * tmpDstPadding;
byte * ptr2 = testOutBuf + ( j * width/4 + i ) * 8;
for ( int k = 0; k < 8; k++ ) {
assert( ptr1[k] == ptr2[k] );
}
}
}
dstPadding = tmpDstPadding;
#endif
}
/*
========================
idDxtEncoder::CompressImageDXT5Fast_SSE2
params: inBuf - image to compress
paramO: outBuf - result of compression
params: width - width of image
params: height - height of image
========================
*/
void idDxtEncoder::CompressImageDXT5Fast_SSE2( const byte *inBuf, byte *outBuf, int width, int height ) {
ALIGN16( byte block[64] );
ALIGN16( byte minColor[4] );
ALIGN16( byte maxColor[4] );
assert( width >= 4 && ( width & 3 ) == 0 );
assert( height >= 4 && ( height & 3 ) == 0 );
this->width = width;
this->height = height;
this->outData = outBuf;
for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
for ( int i = 0; i < width; i += 4 ) {
ExtractBlock_SSE2( inBuf + i * 4, width, block );
GetMinMaxBBox_SSE2( block, minColor, maxColor );
InsetColorsBBox_SSE2( minColor, maxColor );
EmitByte( maxColor[3] );
EmitByte( minColor[3] );
EmitAlphaIndices_SSE2( block, minColor[3], maxColor[3] );
EmitUShort( ColorTo565( maxColor ) );
EmitUShort( ColorTo565( minColor ) );
EmitColorIndices_SSE2( block, minColor, maxColor );
}
outData += dstPadding;
inBuf += srcPadding;
}
#ifdef TEST_COMPRESSION
int tmpDstPadding = dstPadding;
dstPadding = 0;
byte * testOutBuf = (byte *) _alloca16( width * height );
CompressImageDXT5Fast_Generic( inBuf, testOutBuf, width, height );
for ( int j = 0; j < height / 4; j++ ) {
for ( int i = 0; i < width / 4; i++ ) {
byte * ptr1 = outBuf + ( j * width/4 + i ) * 16 + j * tmpDstPadding;
byte * ptr2 = testOutBuf + ( j * width/4 + i ) * 16;
for ( int k = 0; k < 16; k++ ) {
assert( ptr1[k] == ptr2[k] );
}
}
}
dstPadding = tmpDstPadding;
#endif
}
/*
========================
idDxtEncoder::ScaleYCoCg_SSE2
========================
*/
ID_INLINE void idDxtEncoder::ScaleYCoCg_SSE2( byte *colorBlock, byte *minColor, byte *maxColor ) const {
__m128i block0 = *((__m128i *)(&colorBlock[ 0]));
__m128i block1 = *((__m128i *)(&colorBlock[16]));
__m128i block2 = *((__m128i *)(&colorBlock[32]));
__m128i block3 = *((__m128i *)(&colorBlock[48]));
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp0 = _mm_cvtsi32_si128( *(int *)minColor );
temp1 = _mm_cvtsi32_si128( *(int *)maxColor );
temp0 = _mm_unpacklo_epi8( temp0, (const __m128i &)SIMD_SSE2_byte_0 );
temp1 = _mm_unpacklo_epi8( temp1, (const __m128i &)SIMD_SSE2_byte_0 );
// TODO: Algorithm seems to be get the absolute difference
temp6 = _mm_sub_epi16( (const __m128i &)SIMD_SSE2_word_center_128, temp0 );
temp7 = _mm_sub_epi16( (const __m128i &)SIMD_SSE2_word_center_128, temp1 );
temp0 = _mm_sub_epi16( temp0, (const __m128i &)SIMD_SSE2_word_center_128 );
temp1 = _mm_sub_epi16( temp1, (const __m128i &)SIMD_SSE2_word_center_128 );
temp6 = _mm_max_epi16( temp6, temp0 );
temp7 = _mm_max_epi16( temp7, temp1 );
temp6 = _mm_max_epi16( temp6, temp7 );
temp7 = _mm_shufflelo_epi16( temp6, R_SHUFFLE_D( 1, 0, 1, 0 ) );
temp6 = _mm_max_epi16( temp6, temp7 );
temp6 = _mm_shuffle_epi32( temp6, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp7 = temp6;
temp6 = _mm_cmpgt_epi16( temp6, (const __m128i &)SIMD_SSE2_word_63 ); // mask0
temp7 = _mm_cmpgt_epi16( temp7, (const __m128i &)SIMD_SSE2_word_31 ); // mask1
temp7 = _mm_andnot_si128( temp7, (const __m128i &)SIMD_SSE2_byte_2 );
temp7 = _mm_or_si128( temp7, (const __m128i &)SIMD_SSE2_byte_1 );
temp6 = _mm_andnot_si128( temp6, temp7 );
temp3 = temp6;
temp7 = temp6;
temp7 = _mm_xor_si128( temp7, (const __m128i &)SIMD_SSE2_byte_not );
temp7 = _mm_or_si128( temp7, (const __m128i &)SIMD_SSE2_byte_scale_mask0 ); // 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00
temp6 = _mm_add_epi16( temp6, (const __m128i &)SIMD_SSE2_byte_1 );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_byte_scale_mask1 ); // 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF
temp6 = _mm_or_si128( temp6, (const __m128i &)SIMD_SSE2_byte_scale_mask2 ); // 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00
// TODO: remove this second store
temp4 = _mm_cvtsi32_si128( *(int *)minColor );
temp5 = _mm_cvtsi32_si128( *(int *)maxColor );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_byte_scale_mask3 ); // 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_byte_scale_mask3 );
temp3 = _mm_slli_epi32( temp3, 3 );
temp3 = _mm_and_si128( temp3, (const __m128i &)SIMD_SSE2_byte_scale_mask4 ); // 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00
temp4 = _mm_or_si128( temp4, temp3 );
temp5 = _mm_or_si128( temp5, temp3 );
temp4 = _mm_add_epi8( temp4, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp5 = _mm_add_epi8( temp5, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp4 = _mm_mullo_epi16( temp4, temp6 );
temp5 = _mm_mullo_epi16( temp5, temp6 );
temp4 = _mm_and_si128( temp4, temp7 );
temp5 = _mm_and_si128( temp5, temp7 );
temp4 = _mm_sub_epi8( temp4, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp5 = _mm_sub_epi8( temp5, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
*(int *)minColor = _mm_cvtsi128_si32( temp4 );
*(int *)maxColor = _mm_cvtsi128_si32( temp5 );
temp0 = _mm_add_epi8( block0, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp1 = _mm_add_epi8( block1, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp2 = _mm_add_epi8( block2, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp3 = _mm_add_epi8( block3, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
temp0 = _mm_mullo_epi16( temp0, temp6 );
temp1 = _mm_mullo_epi16( temp1, temp6 );
temp2 = _mm_mullo_epi16( temp2, temp6 );
temp3 = _mm_mullo_epi16( temp3, temp6 );
temp0 = _mm_and_si128( temp0, temp7 );
temp1 = _mm_and_si128( temp1, temp7 );
temp2 = _mm_and_si128( temp2, temp7 );
temp3 = _mm_and_si128( temp3, temp7 );
*((__m128i *)(&colorBlock[ 0])) = _mm_sub_epi8( temp0, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
*((__m128i *)(&colorBlock[16])) = _mm_sub_epi8( temp1, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
*((__m128i *)(&colorBlock[32])) = _mm_sub_epi8( temp2, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
*((__m128i *)(&colorBlock[48])) = _mm_sub_epi8( temp3, (const __m128i &)SIMD_SSE2_byte_minus_128_0 );
}
/*
========================
idDxtEncoder::InsetYCoCgBBox_SSE2
========================
*/
ID_INLINE void idDxtEncoder::InsetYCoCgBBox_SSE2( byte *minColor, byte *maxColor ) const {
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp0 = _mm_cvtsi32_si128( *(int *)minColor );
temp1 = _mm_cvtsi32_si128( *(int *)maxColor );
temp0 = _mm_unpacklo_epi8( temp0, (const __m128i &)SIMD_SSE2_byte_0 );
temp1 = _mm_unpacklo_epi8( temp1, (const __m128i &)SIMD_SSE2_byte_0 );
temp2 = _mm_sub_epi16( temp1, temp0 );
temp2 = _mm_sub_epi16( temp2, (const __m128i &)SIMD_SSE2_word_insetYCoCgRound );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_insetYCoCgMask );
temp0 = _mm_mullo_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetYCoCgShiftUp );
temp1 = _mm_mullo_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetYCoCgShiftUp );
temp0 = _mm_add_epi16( temp0, temp2 );
temp1 = _mm_sub_epi16( temp1, temp2 );
temp0 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetYCoCgShiftDown );
temp1 = _mm_mulhi_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetYCoCgShiftDown );
temp0 = _mm_max_epi16( temp0, (const __m128i &)SIMD_SSE2_word_0 );
temp1 = _mm_max_epi16( temp1, (const __m128i &)SIMD_SSE2_word_0 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_word_insetYCoCgQuantMask );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_word_insetYCoCgQuantMask );
temp2 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetYCoCgRep );
temp3 = _mm_mulhi_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetYCoCgRep );
temp0 = _mm_or_si128( temp0, temp2 );
temp1 = _mm_or_si128( temp1, temp3 );
temp0 = _mm_packus_epi16( temp0, temp0 );
temp1 = _mm_packus_epi16( temp1, temp1 );
*(int *)minColor = _mm_cvtsi128_si32( temp0 );
*(int *)maxColor = _mm_cvtsi128_si32( temp1 );
}
/*
========================
idDxtEncoder::SelectYCoCgDiagonal_SSE2
params: colorBlock - 16 pixel block to find color indexes for
paramO: minColor - min color found
paramO: maxColor - max color found
return: diagonal to use
========================
*/
ID_INLINE void idDxtEncoder::SelectYCoCgDiagonal_SSE2( const byte *colorBlock, byte *minColor, byte *maxColor ) const {
__m128i block0 = *((__m128i *)(&colorBlock[ 0]));
__m128i block1 = *((__m128i *)(&colorBlock[16]));
__m128i block2 = *((__m128i *)(&colorBlock[32]));
__m128i block3 = *((__m128i *)(&colorBlock[48]));
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp0 = _mm_and_si128( block0, (const __m128i &)SIMD_SSE2_dword_word_mask );
temp1 = _mm_and_si128( block1, (const __m128i &)SIMD_SSE2_dword_word_mask );
temp2 = _mm_and_si128( block2, (const __m128i &)SIMD_SSE2_dword_word_mask );
temp3 = _mm_and_si128( block3, (const __m128i &)SIMD_SSE2_dword_word_mask );
temp1 = _mm_slli_si128( temp1, 2 );
temp3 = _mm_slli_si128( temp3, 2 );
temp0 = _mm_or_si128( temp0, temp1 );
temp2 = _mm_or_si128( temp2, temp3 );
temp6 = _mm_cvtsi32_si128( *(int *)minColor );
temp7 = _mm_cvtsi32_si128( *(int *)maxColor );
temp1 = _mm_avg_epu8( temp6, temp7 );
temp1 = _mm_shufflelo_epi16( temp1, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp1 = _mm_shuffle_epi32( temp1, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp3 = _mm_max_epu8( temp1, temp2 );
temp1 = _mm_max_epu8( temp1, temp0 );
temp1 = _mm_cmpeq_epi8( temp1, temp0 );
temp3 = _mm_cmpeq_epi8( temp3, temp2 );
temp0 = _mm_srli_si128( temp1, 1 );
temp2 = _mm_srli_si128( temp3, 1 );
temp0 = _mm_xor_si128( temp0, temp1 );
temp2 = _mm_xor_si128( temp2, temp3 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_word_1 );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_1 );
temp0 = _mm_add_epi16( temp0, temp2 );
temp0 = _mm_sad_epu8( temp0, (const __m128i &)SIMD_SSE2_byte_0 );
temp1 = _mm_shuffle_epi32( temp0, R_SHUFFLE_D( 2, 3, 0, 1 ) );
#ifdef NVIDIA_7X_HARDWARE_BUG_FIX
temp1 = _mm_add_epi16( temp1, temp0 );
temp1 = _mm_cmpgt_epi16( temp1, (const __m128i &)SIMD_SSE2_word_8 );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_byte_diagonalMask );
temp0 = _mm_cmpeq_epi8( temp6, temp7 );
temp0 = _mm_slli_si128( temp0, 1 );
temp0 = _mm_andnot_si128( temp0, temp1 );
#else
temp0 = _mm_add_epi16( temp0, temp1 );
temp0 = _mm_cmpgt_epi16( temp0, (const __m128i &)SIMD_SSE2_word_8 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_byte_diagonalMask );
#endif
temp6 = _mm_xor_si128( temp6, temp7 );
temp0 = _mm_and_si128( temp0, temp6 );
temp7 = _mm_xor_si128( temp7, temp0 );
temp6 = _mm_xor_si128( temp6, temp7 );
*(int *)minColor = _mm_cvtsi128_si32( temp6 );
*(int *)maxColor = _mm_cvtsi128_si32( temp7 );
}
/*
========================
idDxtEncoder::CompressYCoCgDXT5Fast_SSE2
params: inBuf - image to compress
paramO: outBuf - result of compression
params: width - width of image
params: height - height of image
========================
*/
void idDxtEncoder::CompressYCoCgDXT5Fast_SSE2( const byte *inBuf, byte *outBuf, int width, int height ) {
ALIGN16( byte block[64] );
ALIGN16( byte minColor[4] );
ALIGN16( byte maxColor[4] );
//assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) );
assert( width >= 4 && ( width & 3 ) == 0 );
assert( height >= 4 && ( height & 3 ) == 0 );
this->width = width;
this->height = height;
this->outData = outBuf;
for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
for ( int i = 0; i < width; i += 4 ) {
ExtractBlock_SSE2( inBuf + i * 4, width, block );
GetMinMaxBBox_SSE2( block, minColor, maxColor );
ScaleYCoCg_SSE2( block, minColor, maxColor );
InsetYCoCgBBox_SSE2( minColor, maxColor );
SelectYCoCgDiagonal_SSE2( block, minColor, maxColor );
EmitByte( maxColor[3] );
EmitByte( minColor[3] );
EmitAlphaIndices_SSE2( block, minColor[3], maxColor[3] );
EmitUShort( ColorTo565( maxColor ) );
EmitUShort( ColorTo565( minColor ) );
EmitCoCgIndices_SSE2( block, minColor, maxColor );
}
outData += dstPadding;
inBuf += srcPadding;
}
#ifdef TEST_COMPRESSION
int tmpDstPadding = dstPadding;
dstPadding = 0;
byte * testOutBuf = (byte *) _alloca16( width * height );
CompressYCoCgDXT5Fast_Generic( inBuf, testOutBuf, width, height );
for ( int j = 0; j < height / 4; j++ ) {
for ( int i = 0; i < width / 4; i++ ) {
byte * ptr1 = outBuf + ( j * width/4 + i ) * 16 + j * tmpDstPadding;
byte * ptr2 = testOutBuf + ( j * width/4 + i ) * 16;
for ( int k = 0; k < 16; k++ ) {
assert( ptr1[k] == ptr2[k] );
}
}
}
dstPadding = tmpDstPadding;
#endif
}
/*
========================
idDxtEncoder::EmitGreenIndices_SSE2
params: block - 16-normal block for which to find normal Y indices
paramO: minGreen - Minimal normal Y found
paramO: maxGreen - Maximal normal Y found
========================
*/
void idDxtEncoder::EmitGreenIndices_SSE2( const byte *block, const int channelBitOffset, const int minGreen, const int maxGreen ) {
__m128i block0 = *((__m128i *)(&block[ 0]));
__m128i block1 = *((__m128i *)(&block[16]));
__m128i block2 = *((__m128i *)(&block[32]));
__m128i block3 = *((__m128i *)(&block[48]));
__m128c temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
temp7 = _mm_cvtsi32_si128( channelBitOffset );
temp0 = _mm_srl_epi32( block0, temp7 );
temp5 = _mm_srl_epi32( block1, temp7 );
temp6 = _mm_srl_epi32( block2, temp7 );
temp4 = _mm_srl_epi32( block3, temp7 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_byte_mask );
temp0 = _mm_packus_epi16( temp0, temp5 );
temp6 = _mm_packus_epi16( temp6, temp4 );
//---------------------
temp2 = _mm_cvtsi32_si128( maxGreen );
temp2 = _mm_shufflelo_epi16( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp3 = _mm_cvtsi32_si128( minGreen );
temp3 = _mm_shufflelo_epi16( temp3, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_mullo_epi16( temp2, (const __m128i &)SIMD_SSE2_word_scale_5_3_1 );
temp3 = _mm_mullo_epi16( temp3, (const __m128i &)SIMD_SSE2_word_scale_1_3_5 );
temp2 = _mm_add_epi16( temp2, (const __m128i &)SIMD_SSE2_word_3 );
temp3 = _mm_add_epi16( temp3, temp2 );
temp3 = _mm_mulhi_epi16( temp3, (const __m128i &)SIMD_SSE2_word_div_by_6 );
temp1 = _mm_shufflelo_epi16( temp3, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_shufflelo_epi16( temp3, R_SHUFFLE_D( 1, 1, 1, 1 ) );
temp3 = _mm_shufflelo_epi16( temp3, R_SHUFFLE_D( 2, 2, 2, 2 ) );
temp1 = _mm_shuffle_epi32( temp1, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp2 = _mm_shuffle_epi32( temp2, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp3 = _mm_shuffle_epi32( temp3, R_SHUFFLE_D( 0, 0, 0, 0 ) );
temp1 = _mm_packus_epi16( temp1, temp1 );
temp2 = _mm_packus_epi16( temp2, temp2 );
temp3 = _mm_packus_epi16( temp3, temp3 );
temp0 = _mm_packus_epi16( temp0, temp6 );
temp1 = _mm_max_epu8( temp1, temp0 );
temp2 = _mm_max_epu8( temp2, temp0 );
temp3 = _mm_max_epu8( temp3, temp0 );
temp1 = _mm_cmpeq_epi8( temp1, temp0 );
temp2 = _mm_cmpeq_epi8( temp2, temp0 );
temp3 = _mm_cmpeq_epi8( temp3, temp0 );
temp0 = (const __m128i &)SIMD_SSE2_byte_4;
temp0 = _mm_adds_epi8( temp0, temp1 );
temp2 = _mm_adds_epi8( temp2, temp3 );
temp0 = _mm_adds_epi8( temp0, temp2 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_byte_3 );
temp4 = (const __m128i &)SIMD_SSE2_byte_2;
temp4 = _mm_cmpgt_epi8( temp4, temp0 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_byte_1 );
temp0 = _mm_xor_si128( temp0, temp4 );
temp4 = _mm_srli_epi64( temp0, 8 - 2 );
temp5 = _mm_srli_epi64( temp0, 16 - 4 );
temp6 = _mm_srli_epi64( temp0, 24 - 6 );
temp7 = _mm_srli_epi64( temp0, 32 - 8 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_color_bit_mask1 );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_color_bit_mask2 );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_color_bit_mask3 );
temp7 = _mm_and_si128( temp7, (const __m128i &)SIMD_SSE2_dword_color_bit_mask4 );
temp5 = _mm_or_si128( temp5, temp4 );
temp7 = _mm_or_si128( temp7, temp6 );
temp7 = _mm_or_si128( temp7, temp5 );
temp4 = _mm_srli_epi64( temp0, 40 - 10 );
temp5 = _mm_srli_epi64( temp0, 48 - 12 );
temp6 = _mm_srli_epi64( temp0, 56 - 14 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_dword_color_bit_mask0 );
temp4 = _mm_and_si128( temp4, (const __m128i &)SIMD_SSE2_dword_color_bit_mask5 );
temp5 = _mm_and_si128( temp5, (const __m128i &)SIMD_SSE2_dword_color_bit_mask6 );
temp6 = _mm_and_si128( temp6, (const __m128i &)SIMD_SSE2_dword_color_bit_mask7 );
temp4 = _mm_or_si128( temp4, temp5 );
temp0 = _mm_or_si128( temp0, temp6 );
temp7 = _mm_or_si128( temp7, temp4 );
temp7 = _mm_or_si128( temp7, temp0 );
temp7 = _mm_shuffle_epi32( temp7, R_SHUFFLE_D( 0, 2, 1, 3 ) );
temp7 = _mm_shufflelo_epi16( temp7, R_SHUFFLE_D( 0, 2, 1, 3 ) );
int result = _mm_cvtsi128_si32( temp7 );
EmitUInt( result );
}
/*
========================
idDxtEncoder::InsetNormalsBBoxDXT5_SSE2
========================
*/
void idDxtEncoder::InsetNormalsBBoxDXT5_SSE2( byte *minNormal, byte *maxNormal ) const {
__m128i temp0, temp1, temp2, temp3;
temp0 = _mm_cvtsi32_si128( *(int *)minNormal );
temp1 = _mm_cvtsi32_si128( *(int *)maxNormal );
temp0 = _mm_unpacklo_epi8( temp0, (const __m128i &)SIMD_SSE2_byte_0 );
temp1 = _mm_unpacklo_epi8( temp1, (const __m128i &)SIMD_SSE2_byte_0 );
temp2 = _mm_sub_epi16( temp1, temp0 );
temp2 = _mm_sub_epi16( temp2, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5Round );
temp2 = _mm_and_si128( temp2, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5Mask ); // xmm2 = inset (1 & 3)
temp0 = _mm_mullo_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5ShiftUp );
temp1 = _mm_mullo_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5ShiftUp );
temp0 = _mm_add_epi16( temp0, temp2 );
temp1 = _mm_sub_epi16( temp1, temp2 );
temp0 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5ShiftDown ); // xmm0 = mini
temp1 = _mm_mulhi_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5ShiftDown ); // xmm1 = maxi
// mini and maxi must be >= 0 and <= 255
temp0 = _mm_max_epi16( temp0, (const __m128i &)SIMD_SSE2_word_0 );
temp1 = _mm_max_epi16( temp1, (const __m128i &)SIMD_SSE2_word_0 );
temp0 = _mm_min_epi16( temp0, (const __m128i &)SIMD_SSE2_word_255 );
temp1 = _mm_min_epi16( temp1, (const __m128i &)SIMD_SSE2_word_255 );
temp0 = _mm_and_si128( temp0, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5QuantMask );
temp1 = _mm_and_si128( temp1, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5QuantMask );
temp2 = _mm_mulhi_epi16( temp0, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5Rep );
temp3 = _mm_mulhi_epi16( temp1, (const __m128i &)SIMD_SSE2_word_insetNormalDXT5Rep );
temp0 = _mm_or_si128( temp0, temp2 );
temp1 = _mm_or_si128( temp1, temp3 );
temp0 = _mm_packus_epi16( temp0, temp0 );
temp1 = _mm_packus_epi16( temp1, temp1 );
*(int *)minNormal = _mm_cvtsi128_si32( temp0 );
*(int *)maxNormal = _mm_cvtsi128_si32( temp1 );
}
/*
========================
idDxtEncoder::CompressNormalMapDXT5Fast_SSE2
params: inBuf - image to compress in _y_x component order
paramO: outBuf - result of compression
params: width - width of image
params: height - height of image
========================
*/
void idDxtEncoder::CompressNormalMapDXT5Fast_SSE2( const byte *inBuf, byte *outBuf, int width, int height ) {
ALIGN16( byte block[64] );
ALIGN16( byte normal1[4] );
ALIGN16( byte normal2[4] );
assert( width >= 4 && ( width & 3 ) == 0 );
assert( height >= 4 && ( height & 3 ) == 0 );
this->width = width;
this->height = height;
this->outData = outBuf;
for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
for ( int i = 0; i < width; i += 4 ) {
ExtractBlock_SSE2( inBuf + i * 4, width, block );
GetMinMaxBBox_SSE2( block, normal1, normal2 );
InsetNormalsBBoxDXT5_SSE2( normal1, normal2 );
// Write out Nx into alpha channel.
EmitByte( normal2[3] );
EmitByte( normal1[3] );
EmitAlphaIndices_SSE2( block, 3*8, normal1[3], normal2[3] );
// Write out Ny into green channel.
EmitUShort( ColorTo565( block[0], normal2[1], block[2] ) );
EmitUShort( ColorTo565( block[0], normal1[1], block[2] ) );
EmitGreenIndices_SSE2( block, 1*8, normal1[1], normal2[1] );
}
outData += dstPadding;
inBuf += srcPadding;
}
#ifdef TEST_COMPRESSION
int tmpDstPadding = dstPadding;
dstPadding = 0;
byte * testOutBuf = (byte *) _alloca16( width * height );
CompressNormalMapDXT5Fast_Generic( inBuf, testOutBuf, width, height );
for ( int j = 0; j < height / 4; j++ ) {
for ( int i = 0; i < width / 4; i++ ) {
byte * ptr1 = outBuf + ( j * width/4 + i ) * 16 + j * tmpDstPadding;
byte * ptr2 = testOutBuf + ( j * width/4 + i ) * 16;
for ( int k = 0; k < 16; k++ ) {
assert( ptr1[k] == ptr2[k] );
}
}
}
dstPadding = tmpDstPadding;
#endif
}