Sto cercando di venire con un algoritmo di soglia molto veloce utilizzando SSE per sostituire questo:soglia SSE veloce algoritmo
uint8_t *pSrc, *pDst;
// Assume pSrc and pDst point to valid data
// Handle left edge
*pDst++ = *pSrc++;
// Likeness filter
for (uint32_t k = 2; k < width; k++, pSrc++, pDst++)
if ((*pDst - *pSrc) * (*pDst - *pSrc) > 100 /*THRESHOLD_SQUARED*/) {
*pDst = *pSrc;
}
}
// Handle right edge
*pDst++ = *pSrc++;
Finora ho questo:
const uint8_t THRESHOLD = 10;
__attribute__((aligned (16))) static const uint8_t mask[16] = {
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD
};
__m128i xmm1, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9;
xmm1 = _mm_load_si128((__m128i const *)mask);
xmm6 = _mm_setzero_si128();
uint8_t *pSrc, *pDst;
// Assume pSrc and pDst point to valid data
// I have other code with another mask for the first 16 entries
for (uint32_t k = 16; k < (width - 16); k += 16, pSrc += 16, pDst += 16) {
xmm3 = _mm_load_si128((__m128i const *)pDst);
xmm4 = _mm_load_si128((__m128i const *)pSrc);
xmm5 = _mm_unpacklo_epi8(xmm3, xmm6);
xmm7 = _mm_unpackhi_epi8(xmm3, xmm6);
xmm8 = _mm_unpacklo_epi8(xmm4, xmm6);
xmm9 = _mm_unpackhi_epi8(xmm4, xmm6);
xmm5 = _mm_sub_epi16(xmm5, xmm8);
xmm7 = _mm_sub_epi16(xmm7, xmm9);
xmm5 = _mm_abs_epi16(xmm5);
xmm7 = _mm_abs_epi16(xmm7);
xmm5 = _mm_packs_epi16(xmm5, xmm7);
xmm5 = _mm_cmpgt_epi8(xmm5, xmm1);
xmm3 = _mm_blendv_epi8(xmm3, xmm4, xmm5);
_mm_store_si128((__m128i *)pDst, xmm3);
}
// I have other code with another mask for the last 16 entries
ho idea utilizzando un altro tipo di algoritmo per gestire il valore assoluto della differenza di due valori (principalmente per rimanere in U8 (uchar) spazio):
a' = a >> 1;
b' = b >> 1;
diff = (abs(sub(a' - b')) << 1) + ((a^b) & 1);
Th è necessario prendere 8 istruzioni SSE invece dei precedenti 9 (non includendo eventuali movimenti extra del registro generati dal compilatore) ma non sono sicuro se sia più veloce a causa delle latenze delle dipendenze.
Qualche altro esperto SSE ha suggerimenti migliori (utilizzando fino a SSE 4.2)?
Aggiornamento 1 - Grazie al suggerimento di Yves!
const uint8_t THRESHOLD = 10;
__attribute__((aligned (16))) static const uint8_t mask[16] = {
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD,
THRESHOLD, THRESHOLD, THRESHOLD, THRESHOLD
};
__m128i xmm1, xmm3, xmm4, xmm5, xmm6, xmm7;
xmm1 = _mm_load_si128((__m128i const *)mask);
xmm6 = _mm_setzero_si128();
uint8_t *pSrc, *pDst;
// Assume pSrc and pDst point to valid data
// I have other code with another mask for the first 16 entries
for (uint32_t k = 16; k < (width - 16); k += 16, pSrc += 16, pDst += 16) {
xmm3 = _mm_load_si128((__m128i const *)pDst);
xmm4 = _mm_load_si128((__m128i const *)pSrc);
xmm5 = _mm_subs_epu8(xmm3, xmm4);
xmm7 = _mm_subs_epu8(xmm4, xmm3);
xmm5 = _mm_adds_epu8(xmm5, xmm7);
xmm5 = _mm_subs_epu8(xmm5, xmm1);
xmm5 = _mm_cmpeq_epi8(xmm5, xmm6);
xmm4 = _mm_blendv_epi8(xmm4, xmm3, xmm5);
_mm_store_si128((__m128i *)pDst, xmm4);
}
// I have other code with another mask for the last 16 entries
Come mai è passato il tag da SSE a vettorializzazione? SSE dovrebbe essere uno dei tuoi tag. –
I due frammenti di codice non fanno la stessa cosa (il codice C lascia i valori che non vengono confrontati indefiniti mentre il codice SSE li imposta a zero). Inoltre, quasi certamente la larghezza di banda della memoria è vincolata con un'operazione semplice come la soglia SSE, quindi non aspettatevi molta differenza tra gli algoritmi. – Damon
@Damon, grazie all'istruzione di fusione, i valori Dst vengono mantenuti. –