/* dvdisaster: Additional error correction for optical media. * Copyright (C) 2004-2015 Carsten Gnoerlich. * * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org * Project homepage: http://www.dvdisaster.org * * This file is part of dvdisaster. * * dvdisaster 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. * * dvdisaster 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 dvdisaster. If not, see . */ #include "dvdisaster.h" /*** *** Reed-Solomon encoding ***/ /* Portable (non-SSE2) version. * Using 32bit operands seems to be a good choice for the lowest * common denominator between the non-SSE2 systems. */ #ifdef HAVE_BIG_ENDIAN #define SHIFT_LEFT << #define SHIFT_RIGHT >> #else #define SHIFT_LEFT >> #define SHIFT_RIGHT << #endif /* HAVE_BIG_ENDIAN */ static void encode_next_layer_portable(ReedSolomonTables *rt, unsigned char *data, unsigned char *parity, guint64 layer_size, int shift) { gint32 *gf_index_of = rt->gfTables->indexOf; gint32 *enc_alpha_to = rt->gfTables->encAlphaTo; gint32 *rs_gpoly = rt->gpoly; int nroots = rt->nroots; int nroots_aligned = (nroots+15)&~15; int nroots_aligned32 = (nroots+3)&~3; int nroots_full = nroots_aligned32>>2; int i,j; for(i=0; ibLut[feedback]+(offset&~3))); /* Process lut in 32 bit steps */ switch(byte_offset) { case 0: for(j=nroots_full; j; j--) *par_idx++ ^= *e_lut++; break; case 1: { for(j=nroots_full; j; j--) { guint32 span = *e_lut SHIFT_LEFT 8; e_lut++; span |= *e_lut SHIFT_RIGHT 24; *par_idx++ ^= span; } } break; case 2: { for(j=nroots_full; j; j--) { guint32 span = *e_lut SHIFT_LEFT 16; e_lut++; span |= *e_lut SHIFT_RIGHT 16; *par_idx++ ^= span; } } break; case 3: { for(j=nroots_full; j; j--) { guint32 span = *e_lut SHIFT_LEFT 24; e_lut++; span |= *e_lut SHIFT_RIGHT 8; *par_idx++ ^= span; } } break; } parity[shift] = enc_alpha_to[feedback + rs_gpoly[0]]; } else /* zero feedback term */ parity[shift] = 0; parity += nroots_aligned; } } /* 64bit integer (non-SSE2) version. * May perform better on systems which have shared FPU/SSE2 units * between several cores. */ static void encode_next_layer_64bit(ReedSolomonTables *rt, unsigned char *data, unsigned char *parity, guint64 layer_size, int shift) { gint32 *gf_index_of = rt->gfTables->indexOf; gint32 *enc_alpha_to = rt->gfTables->encAlphaTo; gint32 *rs_gpoly = rt->gpoly; int nroots = rt->nroots; int nroots_aligned = (nroots+15)&~15; int nroots_aligned64 = (nroots+7)&~7; int nroots_full = nroots_aligned64>>3; int i,j; for(i=0; ibLut[feedback]+(offset&~7))); /* Process lut in 64 bit steps */ switch(byte_offset) { case 0: for(j=nroots_full; j; j--) *par_idx++ ^= *e_lut++; break; case 1: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 8; e_lut++; span |= *e_lut SHIFT_RIGHT 56; *par_idx++ ^= span; } } break; case 2: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 16; e_lut++; span |= *e_lut SHIFT_RIGHT 48; *par_idx++ ^= span; } } break; case 3: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 24; e_lut++; span |= *e_lut SHIFT_RIGHT 40; *par_idx++ ^= span; } } break; case 4: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 32; e_lut++; span |= *e_lut SHIFT_RIGHT 32; *par_idx++ ^= span; } } break; case 5: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 40; e_lut++; span |= *e_lut SHIFT_RIGHT 24; *par_idx++ ^= span; } } break; case 6: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 48; e_lut++; span |= *e_lut SHIFT_RIGHT 16; *par_idx++ ^= span; } } break; case 7: { for(j=nroots_full; j; j--) { guint64 span = *e_lut SHIFT_LEFT 56; e_lut++; span |= *e_lut SHIFT_RIGHT 8; *par_idx++ ^= span; } } break; } parity[shift] = enc_alpha_to[feedback + rs_gpoly[0]]; } else /* zero feedback term */ parity[shift] = 0; parity += nroots_aligned; } } /* * Dispatch upon availability of SSE2 intrinsics */ void encode_next_layer_sse2(ReedSolomonTables*, unsigned char*, unsigned char*, guint64, int); void encode_next_layer_altivec(ReedSolomonTables*, unsigned char*, unsigned char*, guint64, int); void EncodeNextLayer(ReedSolomonTables *rt, unsigned char *data, unsigned char *parity, guint64 layer_size, int shift) { switch(Closure->encodingAlgorithm) { case ENCODING_ALG_32BIT: encode_next_layer_portable(rt, data, parity, layer_size, shift); break; case ENCODING_ALG_64BIT: encode_next_layer_64bit(rt, data, parity, layer_size, shift); break; case ENCODING_ALG_SSE2: encode_next_layer_sse2(rt, data, parity, layer_size, shift); break; case ENCODING_ALG_ALTIVEC: encode_next_layer_altivec(rt, data, parity, layer_size, shift); break; case ENCODING_ALG_DEFAULT: if(Closure->useSSE2) encode_next_layer_sse2(rt, data, parity, layer_size, shift); else if(Closure->useAltiVec) encode_next_layer_altivec(rt, data, parity, layer_size, shift); else encode_next_layer_portable(rt, data, parity, layer_size, shift); break; } } /* * Provide textual description for current encoder parameters */ void DescribeRSEncoder(char **algorithm, char **iostrategy) { switch(Closure->encodingAlgorithm) { case ENCODING_ALG_32BIT: *algorithm="32bit"; break; case ENCODING_ALG_64BIT: *algorithm="64bit"; break; case ENCODING_ALG_SSE2: *algorithm="SSE2"; break; case ENCODING_ALG_ALTIVEC: *algorithm="AltiVec"; break; case ENCODING_ALG_DEFAULT: if(Closure->useSSE2) *algorithm="SSE2"; else if(Closure->useAltiVec) *algorithm="AltiVec"; else *algorithm="64bit"; break; } if(Closure->encodingIOStrategy == IO_STRATEGY_MMAP) *iostrategy="mmap"; else *iostrategy="read/write"; }