242 static_assert(tPixels >= 8u,
"Invalid buffer size!");
244 constexpr unsigned int tChannels = 3u;
246 ocean_assert(buffer !=
nullptr && meanValues !=
nullptr);
248 constexpr unsigned int bufferElements = tChannels * tPixels;
250 constexpr unsigned int blocks48 = bufferElements / 48u;
251 constexpr unsigned int remainingAfterFullBlocks48 = bufferElements % 48u;
253 constexpr bool partialBlock48 = remainingAfterFullBlocks48 > 2u * 16u;
255 constexpr unsigned int remainingAfterPartialBlock48 = partialBlock48 ? 0u : remainingAfterFullBlocks48;
257 constexpr unsigned int blocks24 = remainingAfterPartialBlock48 / 24u;
259 constexpr unsigned int remainingAfterPartialBlock24 = remainingAfterPartialBlock48 % 24u;
261 constexpr unsigned int blocks21 = remainingAfterPartialBlock24 / 21u;
263 constexpr unsigned int remainingAfterPartialBlock21 = remainingAfterPartialBlock24 % 21u;
265 constexpr unsigned int blocks15 = remainingAfterPartialBlock21 / 15u;
267 constexpr unsigned int remainingAfterPartialBlock15 = remainingAfterPartialBlock21 % 15u;
269 constexpr unsigned int blocks1 = remainingAfterPartialBlock15;
271 static_assert(blocks1 % 3u == 0u,
"Invalid number of single blocks");
273 __m128i sumChannel0_128i = _mm_setzero_si128();
274 __m128i sumChannel1_128i = _mm_setzero_si128();
275 __m128i sumChannel2_128i = _mm_setzero_si128();
277 uint32_t sumIndividual[3] = {0u};
279 for (
unsigned int n = 0u; n < blocks48; ++n)
281 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(buffer + 0));
282 const __m128i bufferB_128i = _mm_lddqu_si128((
const __m128i*)(buffer + 16));
283 const __m128i bufferC_128i = _mm_lddqu_si128((
const __m128i*)(buffer + 32));
290 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_sad_epu8(channel0, _mm_setzero_si128()));
291 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_sad_epu8(channel1, _mm_setzero_si128()));
292 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2, _mm_setzero_si128()));
297 if constexpr (partialBlock48)
299 constexpr int overlappingElements = int(48u - remainingAfterFullBlocks48);
301 const __m128i bufferA_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(buffer)), overlappingElements);
302 const __m128i bufferB_128i = _mm_lddqu_si128((
const __m128i*)(buffer - overlappingElements + 16));
303 const __m128i bufferC_128i = _mm_lddqu_si128((
const __m128i*)(buffer - overlappingElements + 32));
310 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_sad_epu8(channel0, _mm_setzero_si128()));
311 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_sad_epu8(channel1, _mm_setzero_si128()));
312 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2, _mm_setzero_si128()));
314 buffer += remainingAfterFullBlocks48;
317 for (
unsigned int n = 0u; n < blocks24; ++n)
319 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(buffer + 0));
320 const __m128i bufferB_128i = _mm_loadl_epi64((
const __m128i*)(buffer + 16));
322 __m128i channel01_128i;
323 __m128i channel2_128i;
326 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
328 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
329 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
330 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
335 for (
unsigned int n = 0u; n < blocks21; ++n)
337 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(buffer + 0));
338 const __m128i bufferB_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(buffer + 16 - 3)), 3);
340 __m128i channel01_128i;
341 __m128i channel2_128i;
344 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
346 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
347 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
348 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
353 for (
unsigned int n = 0u; n < blocks15; ++n)
355 const __m128i buffer_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(buffer - 1)), 1);
357 __m128i channel01_128i;
358 __m128i channel2_128i;
361 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
363 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
364 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
365 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
370 if constexpr (blocks1 != 0u)
372 constexpr unsigned int pixels = blocks1 / 3u;
374 for (
unsigned int x = 0u; x < pixels; ++x)
376 for (
unsigned int n = 0u; n < 3u; ++n)
378 sumIndividual[n] += buffer[x * 3u + n];
419 static_assert(tPatchSize >= 5u,
"Invalid patch size!");
421 constexpr unsigned int tChannels = 1u;
423 ocean_assert(patch !=
nullptr && meanValues !=
nullptr);
425 ocean_assert(patchStrideElements >= tChannels * tPatchSize);
427 constexpr unsigned int patchWidthElements = tChannels * tPatchSize;
429 constexpr unsigned int blocks16 = patchWidthElements / 16u;
430 constexpr unsigned int remainingAfterBlocks16 = patchWidthElements % 16u;
432 constexpr bool partialBlock16 = remainingAfterBlocks16 > 8u;
434 constexpr bool fullBlock8 = !partialBlock16 && remainingAfterBlocks16 == 8u;
436 constexpr bool partialBlock8 = !partialBlock16 && !fullBlock8 && remainingAfterBlocks16 >= 3u;
438 constexpr unsigned int blocks1 = (!partialBlock16 && !fullBlock8 && !partialBlock8) ? remainingAfterBlocks16 : 0u;
440 static_assert(blocks1 <= 2u,
"Invalid block size!");
442 __m128i sum_128i = _mm_setzero_si128();
444 uint32_t sumIndividual = 0u;
446 for (
unsigned int y = 0u; y < tPatchSize; ++y)
450 for (
unsigned int n = 0u; n < blocks16; ++n)
452 const __m128i buffer_128i = _mm_lddqu_si128((
const __m128i*)patch);
454 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
459 if constexpr (fullBlock8)
461 const __m128i buffer_128i = _mm_loadl_epi64((
const __m128i*)patch);
463 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
468 if constexpr (partialBlock16)
470 constexpr unsigned int overlapElements = partialBlock16 ? 16u - remainingAfterBlocks16 : 0u;
472 static_assert(overlapElements < 8u,
"Invalid value!");
474 if (y < tPatchSize - 1u)
476 const __m128i buffer_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)patch), overlapElements);
478 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
482 const __m128i buffer_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(patch - overlapElements)), overlapElements);
484 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
487 patch += remainingAfterBlocks16;
490 if constexpr (partialBlock8)
492 constexpr unsigned int overlapElements = partialBlock8 ? 8u - remainingAfterBlocks16 : 0u;
494 static_assert(overlapElements < 8u,
"Invalid value!");
496 if (y < tPatchSize - 1u)
498 const __m128i buffer_128i = _mm_slli_si128(_mm_loadl_epi64((
const __m128i*)patch), overlapElements + 8);
500 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
504 const __m128i buffer_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(patch - overlapElements)), overlapElements);
506 sum_128i = _mm_add_epi32(sum_128i, _mm_sad_epu8(buffer_128i, _mm_setzero_si128()));
509 patch += remainingAfterBlocks16;
512 if constexpr (blocks1 != 0u)
514 for (
unsigned int n = 0u; n < blocks1; ++n)
516 sumIndividual += patch[n];
522 patch += patchStrideElements - patchWidthElements;
527 meanValues[0] = uint8_t((sum + tPatchSize * tPatchSize / 2u) / (tPatchSize * tPatchSize));
534 static_assert(tPatchSize >= 5u,
"Invalid patch size!");
536 constexpr unsigned int tChannels = 3u;
538 ocean_assert(patch !=
nullptr && meanValues !=
nullptr);
540 ocean_assert(patchStrideElements >= tChannels * tPatchSize);
542 constexpr unsigned int patchWidthElements = tChannels * tPatchSize;
544 constexpr unsigned int blocks48 = patchWidthElements / 48u;
545 constexpr unsigned int remainingAfterFullBlocks48 = patchWidthElements % 48u;
547 constexpr bool partialBlock48 = remainingAfterFullBlocks48 > 2u * 16u;
549 constexpr unsigned int remainingAfterPartialBlock48 = partialBlock48 ? 0u : remainingAfterFullBlocks48;
551 constexpr unsigned int blocks24 = remainingAfterPartialBlock48 / 24u;
553 constexpr unsigned int remainingAfterPartialBlock24 = remainingAfterPartialBlock48 % 24u;
555 constexpr unsigned int blocks21 = remainingAfterPartialBlock24 / 21u;
557 constexpr unsigned int remainingAfterPartialBlock21 = remainingAfterPartialBlock24 % 21u;
559 constexpr unsigned int blocks15 = remainingAfterPartialBlock21 / 15u;
561 constexpr unsigned int remainingAfterPartialBlock15 = remainingAfterPartialBlock21 % 15u;
563 constexpr unsigned int blocks1 = remainingAfterPartialBlock15;
565 static_assert(blocks1 % 3u == 0u,
"Invalid number of single blocks");
567 __m128i sumChannel0_128i = _mm_setzero_si128();
568 __m128i sumChannel1_128i = _mm_setzero_si128();
569 __m128i sumChannel2_128i = _mm_setzero_si128();
571 uint32_t sumIndividual[3] = {0u};
573 for (
unsigned int y = 0u; y < tPatchSize; ++y)
577 for (
unsigned int n = 0u; n < blocks48; ++n)
579 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(patch + 0));
580 const __m128i bufferB_128i = _mm_lddqu_si128((
const __m128i*)(patch + 16));
581 const __m128i bufferC_128i = _mm_lddqu_si128((
const __m128i*)(patch + 32));
588 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_sad_epu8(channel0, _mm_setzero_si128()));
589 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_sad_epu8(channel1, _mm_setzero_si128()));
590 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2, _mm_setzero_si128()));
595 if constexpr (partialBlock48)
597 constexpr int overlappingElements = int(48u - remainingAfterFullBlocks48);
599 const __m128i bufferA_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(patch)), overlappingElements);
600 const __m128i bufferB_128i = _mm_lddqu_si128((
const __m128i*)(patch - overlappingElements + 16));
601 const __m128i bufferC_128i = _mm_lddqu_si128((
const __m128i*)(patch - overlappingElements + 32));
608 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_sad_epu8(channel0, _mm_setzero_si128()));
609 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_sad_epu8(channel1, _mm_setzero_si128()));
610 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2, _mm_setzero_si128()));
612 patch += remainingAfterFullBlocks48;
615 for (
unsigned int n = 0u; n < blocks24; ++n)
617 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(patch + 0));
618 const __m128i bufferB_128i = _mm_loadl_epi64((
const __m128i*)(patch + 16));
620 __m128i channel01_128i;
621 __m128i channel2_128i;
624 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
626 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
627 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
628 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
633 for (
unsigned int n = 0u; n < blocks21; ++n)
635 const __m128i bufferA_128i = _mm_lddqu_si128((
const __m128i*)(patch + 0));
636 const __m128i bufferB_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(patch + 16 - 3)), 3);
638 __m128i channel01_128i;
639 __m128i channel2_128i;
642 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
644 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
645 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
646 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
651 for (
unsigned int n = 0u; n < blocks15; ++n)
653 const __m128i buffer_128i = y < tPatchSize - 1u ? _mm_lddqu_si128((
const __m128i*)(patch)) : _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(patch - 1)), 1);
655 __m128i channel01_128i;
656 __m128i channel2_128i;
659 const __m128i sumChannel01_128i = _mm_sad_epu8(channel01_128i, _mm_setzero_si128());
661 sumChannel0_128i = _mm_add_epi32(sumChannel0_128i, _mm_slli_si128(sumChannel01_128i, 8));
662 sumChannel1_128i = _mm_add_epi32(sumChannel1_128i, _mm_srli_si128(sumChannel01_128i, 8));
663 sumChannel2_128i = _mm_add_epi32(sumChannel2_128i, _mm_sad_epu8(channel2_128i, _mm_setzero_si128()));
668 if constexpr (blocks1 != 0u)
670 constexpr unsigned int pixels = blocks1 / 3u;
672 for (
unsigned int x = 0u; x < pixels; ++x)
674 for (
unsigned int n = 0u; n < 3u; ++n)
676 sumIndividual[n] += patch[x * 3u + n];
683 patch += patchStrideElements - patchWidthElements;
686 meanValues[0] = uint8_t((
SSE::sum_u32_first_third(sumChannel0_128i) + sumIndividual[0] + tPatchSize * tPatchSize / 2u) / (tPatchSize * tPatchSize));
687 meanValues[1] = uint8_t((
SSE::sum_u32_first_third(sumChannel1_128i) + sumIndividual[1] + tPatchSize * tPatchSize / 2u) / (tPatchSize * tPatchSize));
688 meanValues[2] = uint8_t((
SSE::sum_u32_first_third(sumChannel2_128i) + sumIndividual[2] + tPatchSize * tPatchSize / 2u) / (tPatchSize * tPatchSize));
727 static_assert(tPixels >= 8u,
"Invalid pixel number!");
729 constexpr unsigned int tChannels = 1u;
731 ocean_assert(buffer0 !=
nullptr && buffer1 !=
nullptr);
732 ocean_assert(meanValues0 !=
nullptr && meanValues1 !=
nullptr);
734 constexpr unsigned int bufferElements = tChannels * tPixels;
736 constexpr unsigned int blocks16 = bufferElements / 16u;
737 constexpr unsigned int remainingAfterBlocks16 = bufferElements % 16u;
740 constexpr bool partialBlock16 = blocks16 >= 1u && remainingAfterBlocks16 > 8u;
742 constexpr bool fullBlock8 = !partialBlock16 && remainingAfterBlocks16 >= 8u;
744 constexpr unsigned int remainingAfterBlocks8 = fullBlock8 ? remainingAfterBlocks16 - 8u : remainingAfterBlocks16;
746 constexpr bool partialBlock8 = !partialBlock16 && remainingAfterBlocks8 >= 3u;
748 constexpr unsigned int blocks1 = (!partialBlock16 && !partialBlock8) ? remainingAfterBlocks8 : 0u;
750 static_assert(blocks1 <= 2u,
"Invalid block size!");
752 static_assert(std::is_same<short, int16_t>::value,
"Invalid data type!");
754 const __m128i constant_signs_m128i = _mm_set1_epi16(
short(0x1FF));
756 const __m128i mean0_128i = _mm_set1_epi8(meanValues0[0]);
757 const __m128i mean1_128i = _mm_set1_epi8(meanValues1[0]);
759 __m128i sum0_128i = _mm_setzero_si128();
760 __m128i sum1_128i = _mm_setzero_si128();
762 uint32_t sumIndividual = 0u;
764 for (
unsigned int n = 0u; n < blocks16; ++n)
766 const __m128i buffer0_128i = _mm_lddqu_si128((
const __m128i*)buffer0);
767 const __m128i buffer1_128i = _mm_lddqu_si128((
const __m128i*)buffer1);
769 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
770 const __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
772 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
773 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
779 if constexpr (partialBlock16)
781 constexpr unsigned int overlapElements = partialBlock16 ? 16u - remainingAfterBlocks16 : 0u;
783 static_assert(overlapElements < 8u,
"Invalid value!");
785 const __m128i buffer0_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(buffer0 - overlapElements)), overlapElements);
786 const __m128i buffer1_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(buffer1 - overlapElements)), overlapElements);
788 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
789 const __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
791 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
792 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
794 buffer0 += remainingAfterBlocks16;
795 buffer1 += remainingAfterBlocks16;
798 if constexpr (fullBlock8)
800 const __m128i buffer0_128i = _mm_loadl_epi64((
const __m128i*)buffer0);
801 const __m128i buffer1_128i = _mm_loadl_epi64((
const __m128i*)buffer1);
803 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
805 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
811 if constexpr (partialBlock8)
813 constexpr unsigned int overlapElements = partialBlock8 ? 8u - remainingAfterBlocks8 : 0u;
815 static_assert(overlapElements < 8u,
"Invalid value!");
817 const __m128i buffer0_128i = _mm_loadl_epi64((
const __m128i*)(buffer0 - overlapElements));
818 const __m128i buffer1_128i = _mm_loadl_epi64((
const __m128i*)(buffer1 - overlapElements));
820 const __m128i absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
822 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
824 buffer0 += remainingAfterBlocks8;
825 buffer1 += remainingAfterBlocks8;
828 if constexpr (blocks1 != 0u)
830 for (
unsigned int n = 0u; n < blocks1; ++n)
832 sumIndividual +=
sqrDistance(buffer0[n] - meanValues0[0], buffer1[n] - meanValues1[0]);
846 static_assert(tPixels >= 5u,
"Invalid pixel number!");
848 constexpr unsigned int tChannels = 3u;
850 ocean_assert(buffer0 !=
nullptr && buffer1 !=
nullptr);
851 ocean_assert(meanValues0 !=
nullptr && meanValues1 !=
nullptr);
853 constexpr unsigned int bufferElements = tChannels * tPixels;
855 constexpr unsigned int blocks48 = bufferElements / 48u;
856 constexpr unsigned int remainingAfterFullBlocks48 = bufferElements % 48u;
858 constexpr bool partialBlock48 = remainingAfterFullBlocks48 > 2u * 16u;
860 constexpr unsigned int remainingAfterPartialBlock48 = partialBlock48 ? 0u : remainingAfterFullBlocks48;
862 constexpr unsigned int blocks24 = remainingAfterPartialBlock48 / 24u;
864 constexpr unsigned int remainingAfterPartialBlock24 = remainingAfterPartialBlock48 % 24u;
866 constexpr unsigned int blocks21 = remainingAfterPartialBlock24 / 21u;
868 constexpr unsigned int remainingAfterPartialBlock21 = remainingAfterPartialBlock24 % 21u;
870 constexpr unsigned int blocks15 = remainingAfterPartialBlock21 / 15u;
872 constexpr unsigned int remainingAfterPartialBlock15 = remainingAfterPartialBlock21 % 15u;
874 constexpr unsigned int blocks1 = remainingAfterPartialBlock15;
876 static_assert(blocks1 % 3u == 0u,
"Invalid number of single blocks");
878 static_assert(std::is_same<short, int16_t>::value,
"Invalid data type!");
880 const __m128i constant_signs_m128i = _mm_set1_epi16(
short(0x1FF));
882 const __m128i mean0_0_128i = _mm_set1_epi8(meanValues0[0]);
883 const __m128i mean0_1_128i = _mm_set1_epi8(meanValues0[1]);
884 const __m128i mean0_2_128i = _mm_set1_epi8(meanValues0[2]);
886 const __m128i mean1_0_128i = _mm_set1_epi8(meanValues1[0]);
887 const __m128i mean1_1_128i = _mm_set1_epi8(meanValues1[1]);
888 const __m128i mean1_2_128i = _mm_set1_epi8(meanValues1[2]);
890 __m128i sum0_128i = _mm_setzero_si128();
891 __m128i sum1_128i = _mm_setzero_si128();
893 uint32_t sumIndividual = 0u;
895 for (
unsigned int n = 0u; n < blocks48; ++n)
897 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 + 0));
898 const __m128i buffer0B_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 + 16));
899 const __m128i buffer0C_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 + 32));
901 __m128i channel0_0_128i;
902 __m128i channel0_1_128i;
903 __m128i channel0_2_128i;
906 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 + 0));
907 const __m128i buffer1B_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 + 16));
908 const __m128i buffer1C_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 + 32));
910 __m128i channel1_0_128i;
911 __m128i channel1_1_128i;
912 __m128i channel1_2_128i;
915 __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
916 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
918 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
919 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
921 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
922 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
924 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
925 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
927 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
928 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
930 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
931 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
937 if constexpr (partialBlock48)
939 constexpr int overlappingElements = int(48u - remainingAfterFullBlocks48);
940 constexpr int overlappingPixels = overlappingElements / int(tChannels);
942 const __m128i buffer0A_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(buffer0)), overlappingElements);
943 const __m128i buffer0B_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 - overlappingElements + 16));
944 const __m128i buffer0C_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 - overlappingElements + 32));
946 __m128i channel0_0_128i;
947 __m128i channel0_1_128i;
948 __m128i channel0_2_128i;
951 const __m128i buffer1A_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(buffer1)), overlappingElements);
952 const __m128i buffer1B_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 - overlappingElements + 16));
953 const __m128i buffer1C_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 - overlappingElements + 32));
955 __m128i channel1_0_128i;
956 __m128i channel1_1_128i;
957 __m128i channel1_2_128i;
960 __m128i absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i)), overlappingPixels * 2);
961 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
963 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
964 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
966 absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i)), overlappingPixels * 2);
967 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
969 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
970 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
972 absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), overlappingPixels * 2);
973 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
975 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
976 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
978 buffer0 += remainingAfterFullBlocks48;
979 buffer1 += remainingAfterFullBlocks48;
982 for (
unsigned int n = 0u; n < blocks24; ++n)
984 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 + 0));
985 const __m128i buffer0B_128i = _mm_loadl_epi64((
const __m128i*)(buffer0 + 16));
987 __m128i channel0_01_128i;
988 __m128i channel0_2_128i;
991 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 + 0));
992 const __m128i buffer1B_128i = _mm_loadl_epi64((
const __m128i*)(buffer1 + 16));
994 __m128i channel1_01_128i;
995 __m128i channel1_2_128i;
998 __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i));
999 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i));
1001 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1002 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1004 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
1006 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1012 for (
unsigned int n = 0u; n < blocks21; ++n)
1014 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(buffer0 + 0));
1015 const __m128i buffer0B_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(buffer0 + 16 - 3)), 3);
1017 __m128i channel0_01_128i;
1018 __m128i channel0_2_128i;
1021 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(buffer1 + 0));
1022 const __m128i buffer1B_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(buffer1 + 16 - 3)), 3);
1024 __m128i channel1_01_128i;
1025 __m128i channel1_2_128i;
1028 __m128i absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i)), 2);
1029 __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i)), 2);
1031 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1032 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1034 absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), 2);
1036 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1042 for (
unsigned int n = 0u; n < blocks15; ++n)
1044 const __m128i buffer0_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(buffer0 - 1)), 1);
1046 __m128i channel0_01_128i;
1047 __m128i channel0_2_128i;
1050 const __m128i buffer1_128i = _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(buffer1 - 1)), 1);
1052 __m128i channel1_01_128i;
1053 __m128i channel1_2_128i;
1056 __m128i absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i)), 6);
1057 __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i)), 6);
1059 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1060 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1062 absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), 6);
1064 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1070 if constexpr (blocks1 != 0u)
1072 constexpr unsigned int pixels = blocks1 / 3u;
1074 for (
unsigned int x = 0u; x < pixels; ++x)
1076 for (
unsigned int n = 0u; n < 3u; ++n)
1078 sumIndividual +=
sqrDistance(buffer0[x * 3u + n] - meanValues0[n], buffer1[x * 3u + n] - meanValues1[n]);
1116 static_assert(tPatchSize >= 1u,
"Invalid patch size!");
1118 constexpr unsigned int tChannels = 1u;
1120 ocean_assert(patch0 !=
nullptr && patch1 !=
nullptr);
1121 ocean_assert(meanValues0 !=
nullptr && meanValues1 !=
nullptr);
1123 ocean_assert(patch0StrideElements >= tChannels * tPatchSize);
1124 ocean_assert(patch1StrideElements >= tChannels * tPatchSize);
1126 constexpr unsigned int patchWidthElements = tChannels * tPatchSize;
1128 constexpr unsigned int blocks16 = patchWidthElements / 16u;
1129 constexpr unsigned int remainingAfterBlocks16 = patchWidthElements % 16u;
1131 constexpr bool partialBlock16 = remainingAfterBlocks16 > 8u;
1133 constexpr bool fullBlock8 = !partialBlock16 && remainingAfterBlocks16 == 8u;
1135 constexpr bool partialBlock8 = !partialBlock16 && !fullBlock8 && remainingAfterBlocks16 >= 3u;
1137 constexpr unsigned int blocks1 = (!partialBlock16 && !fullBlock8 && !partialBlock8) ? remainingAfterBlocks16 : 0u;
1139 static_assert(blocks1 <= 2u,
"Invalid block size!");
1141 static_assert(std::is_same<short, int16_t>::value,
"Invalid data type!");
1143 const __m128i constant_signs_m128i = _mm_set1_epi16(
short(0x1FF));
1145 const __m128i mean0_128i = _mm_set1_epi8(meanValues0[0]);
1146 const __m128i mean1_128i = _mm_set1_epi8(meanValues1[0]);
1148 __m128i sum0_128i = _mm_setzero_si128();
1149 __m128i sum1_128i = _mm_setzero_si128();
1151 uint32_t sumIndividual = 0u;
1153 for (
unsigned int y = 0u; y < tPatchSize; ++y)
1158 for (
unsigned int n = 0u; n < blocks16; ++n)
1160 const __m128i buffer0_128i = _mm_lddqu_si128((
const __m128i*)patch0);
1161 const __m128i buffer1_128i = _mm_lddqu_si128((
const __m128i*)patch1);
1163 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1164 const __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1166 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1167 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1173 if constexpr (fullBlock8)
1175 const __m128i buffer0_128i = _mm_loadl_epi64((
const __m128i*)patch0);
1176 const __m128i buffer1_128i = _mm_loadl_epi64((
const __m128i*)patch1);
1178 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1179 const __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1181 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1182 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1188 if constexpr (partialBlock16)
1190 constexpr unsigned int overlapElements = partialBlock16 ? 16u - remainingAfterBlocks16 : 0u;
1192 static_assert(overlapElements < 8u,
"Invalid value!");
1194 if (y < tPatchSize - 1u)
1196 const __m128i buffer0_128i = _mm_lddqu_si128((
const __m128i*)patch0);
1197 const __m128i buffer1_128i = _mm_lddqu_si128((
const __m128i*)patch1);
1199 const __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1200 const __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
1202 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1203 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1207 const __m128i buffer0_128i = _mm_lddqu_si128((
const __m128i*)(patch0 - overlapElements));
1208 const __m128i buffer1_128i = _mm_lddqu_si128((
const __m128i*)(patch1 - overlapElements));
1210 const __m128i absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
1211 const __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_128i, buffer1_128i), constant_signs_m128i));
1213 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1214 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1217 patch0 += remainingAfterBlocks16;
1218 patch1 += remainingAfterBlocks16;
1221 if constexpr (partialBlock8)
1223 constexpr unsigned int overlapElements = partialBlock8 ? 8u - remainingAfterBlocks16 : 0u;
1225 static_assert(overlapElements < 8u,
"Invalid value!");
1227 if (y < tPatchSize - 1u)
1229 const __m128i buffer0_128i = _mm_loadl_epi64((
const __m128i*)patch0);
1230 const __m128i buffer1_128i = _mm_loadl_epi64((
const __m128i*)patch1);
1232 const __m128i absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
1234 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1238 const __m128i buffer0_128i = _mm_loadl_epi64((
const __m128i*)(patch0 - overlapElements));
1239 const __m128i buffer1_128i = _mm_loadl_epi64((
const __m128i*)(patch1 - overlapElements));
1241 const __m128i absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_128i, buffer0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_128i, buffer1_128i), constant_signs_m128i)), overlapElements * 2);
1243 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1246 patch0 += remainingAfterBlocks16;
1247 patch1 += remainingAfterBlocks16;
1250 if constexpr (blocks1 != 0u)
1252 for (
unsigned int n = 0u; n < blocks1; ++n)
1254 sumIndividual +=
sqrDistance(patch0[n] - meanValues0[0], patch1[n] - meanValues1[0]);
1261 patch0 += patch0StrideElements - patchWidthElements;
1262 patch1 += patch1StrideElements - patchWidthElements;
1272 static_assert(tPatchSize >= 5u,
"Invalid patch size!");
1274 constexpr unsigned int tChannels = 3u;
1276 ocean_assert(patch0 !=
nullptr && patch1 !=
nullptr);
1277 ocean_assert(meanValues0 !=
nullptr && meanValues1 !=
nullptr);
1279 ocean_assert(patch0StrideElements >= tChannels * tPatchSize);
1280 ocean_assert(patch1StrideElements >= tChannels * tPatchSize);
1282 constexpr unsigned int patchWidthElements = tChannels * tPatchSize;
1284 constexpr unsigned int blocks48 = patchWidthElements / 48u;
1285 constexpr unsigned int remainingAfterFullBlocks48 = patchWidthElements % 48u;
1287 constexpr bool partialBlock48 = remainingAfterFullBlocks48 > 2u * 16u;
1289 constexpr unsigned int remainingAfterPartialBlock48 = partialBlock48 ? 0u : remainingAfterFullBlocks48;
1291 constexpr unsigned int blocks24 = remainingAfterPartialBlock48 / 24u;
1293 constexpr unsigned int remainingAfterPartialBlock24 = remainingAfterPartialBlock48 % 24u;
1295 constexpr unsigned int blocks21 = remainingAfterPartialBlock24 / 21u;
1297 constexpr unsigned int remainingAfterPartialBlock21 = remainingAfterPartialBlock24 % 21u;
1299 constexpr unsigned int blocks15 = remainingAfterPartialBlock21 / 15u;
1301 constexpr unsigned int remainingAfterPartialBlock15 = remainingAfterPartialBlock21 % 15u;
1303 constexpr unsigned int blocks1 = remainingAfterPartialBlock15;
1305 static_assert(blocks1 % 3u == 0u,
"Invalid number of single blocks");
1307 static_assert(std::is_same<short, int16_t>::value,
"Invalid data type!");
1309 const __m128i constant_signs_m128i = _mm_set1_epi16(
short(0x1FF));
1311 const __m128i mean0_0_128i = _mm_set1_epi8(meanValues0[0]);
1312 const __m128i mean0_1_128i = _mm_set1_epi8(meanValues0[1]);
1313 const __m128i mean0_2_128i = _mm_set1_epi8(meanValues0[2]);
1315 const __m128i mean1_0_128i = _mm_set1_epi8(meanValues1[0]);
1316 const __m128i mean1_1_128i = _mm_set1_epi8(meanValues1[1]);
1317 const __m128i mean1_2_128i = _mm_set1_epi8(meanValues1[2]);
1319 __m128i sum0_128i = _mm_setzero_si128();
1320 __m128i sum1_128i = _mm_setzero_si128();
1322 uint32_t sumIndividual = 0u;
1324 for (
unsigned int y = 0u; y < tPatchSize; ++y)
1329 for (
unsigned int n = 0u; n < blocks48; ++n)
1331 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(patch0 + 0));
1332 const __m128i buffer0B_128i = _mm_lddqu_si128((
const __m128i*)(patch0 + 16));
1333 const __m128i buffer0C_128i = _mm_lddqu_si128((
const __m128i*)(patch0 + 32));
1335 __m128i channel0_0_128i;
1336 __m128i channel0_1_128i;
1337 __m128i channel0_2_128i;
1340 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(patch1 + 0));
1341 const __m128i buffer1B_128i = _mm_lddqu_si128((
const __m128i*)(patch1 + 16));
1342 const __m128i buffer1C_128i = _mm_lddqu_si128((
const __m128i*)(patch1 + 32));
1344 __m128i channel1_0_128i;
1345 __m128i channel1_1_128i;
1346 __m128i channel1_2_128i;
1349 __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
1350 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
1352 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1353 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1355 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
1356 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
1358 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1359 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1361 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
1362 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
1364 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1365 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1371 if constexpr (partialBlock48)
1373 constexpr int overlappingElements = int(48u - remainingAfterFullBlocks48);
1374 constexpr int overlappingPixels = overlappingElements / int(tChannels);
1376 const __m128i buffer0A_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(patch0)), overlappingElements);
1377 const __m128i buffer0B_128i = _mm_lddqu_si128((
const __m128i*)(patch0 - overlappingElements + 16));
1378 const __m128i buffer0C_128i = _mm_lddqu_si128((
const __m128i*)(patch0 - overlappingElements + 32));
1380 __m128i channel0_0_128i;
1381 __m128i channel0_1_128i;
1382 __m128i channel0_2_128i;
1385 const __m128i buffer1A_128i = _mm_slli_si128(_mm_lddqu_si128((
const __m128i*)(patch1)), overlappingElements);
1386 const __m128i buffer1B_128i = _mm_lddqu_si128((
const __m128i*)(patch1 - overlappingElements + 16));
1387 const __m128i buffer1C_128i = _mm_lddqu_si128((
const __m128i*)(patch1 - overlappingElements + 32));
1389 __m128i channel1_0_128i;
1390 __m128i channel1_1_128i;
1391 __m128i channel1_2_128i;
1394 __m128i absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i)), overlappingPixels * 2);
1395 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_0_128i, channel0_0_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_0_128i, channel1_0_128i), constant_signs_m128i));
1397 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1398 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1400 absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i)), overlappingPixels * 2);
1401 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_1_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_1_128i), constant_signs_m128i));
1403 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1404 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1406 absDifferencesLow_128i = _mm_srli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), overlappingPixels * 2);
1407 absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
1409 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1410 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1412 patch0 += remainingAfterFullBlocks48;
1413 patch1 += remainingAfterFullBlocks48;
1416 for (
unsigned int n = 0u; n < blocks24; ++n)
1418 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(patch0 + 0));
1419 const __m128i buffer0B_128i = _mm_loadl_epi64((
const __m128i*)(patch0 + 16));
1421 __m128i channel0_01_128i;
1422 __m128i channel0_2_128i;
1425 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(patch1 + 0));
1426 const __m128i buffer1B_128i = _mm_loadl_epi64((
const __m128i*)(patch1 + 16));
1428 __m128i channel1_01_128i;
1429 __m128i channel1_2_128i;
1432 __m128i absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i));
1433 __m128i absDifferencesHigh_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i));
1435 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1436 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1438 absDifferencesLow_128i = _mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i));
1440 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1446 for (
unsigned int n = 0u; n < blocks21; ++n)
1448 const __m128i buffer0A_128i = _mm_lddqu_si128((
const __m128i*)(patch0 + 0));
1449 const __m128i buffer0B_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(patch0 + 16 - 3)), 3);
1451 __m128i channel0_01_128i;
1452 __m128i channel0_2_128i;
1455 const __m128i buffer1A_128i = _mm_lddqu_si128((
const __m128i*)(patch1 + 0));
1456 const __m128i buffer1B_128i = _mm_srli_si128(_mm_loadl_epi64((
const __m128i*)(patch1 + 16 - 3)), 3);
1458 __m128i channel1_01_128i;
1459 __m128i channel1_2_128i;
1462 __m128i absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i)), 2);
1463 __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i)), 2);
1465 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1466 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1468 absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), 2);
1470 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1476 for (
unsigned int n = 0u; n < blocks15; ++n)
1478 const __m128i buffer0_128i = y < tPatchSize - 1u ? _mm_lddqu_si128((
const __m128i*)(patch0)) : _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(patch0 - 1)), 1);
1480 __m128i channel0_01_128i;
1481 __m128i channel0_2_128i;
1484 const __m128i buffer1_128i = y < tPatchSize - 1u ? _mm_lddqu_si128((
const __m128i*)(patch1)) : _mm_srli_si128(_mm_lddqu_si128((
const __m128i*)(patch1 - 1)), 1);
1486 __m128i channel1_01_128i;
1487 __m128i channel1_2_128i;
1490 __m128i absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_0_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_0_128i, channel1_01_128i), constant_signs_m128i)), 6);
1491 __m128i absDifferencesHigh_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpackhi_epi8(mean0_1_128i, channel0_01_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpackhi_epi8(mean1_1_128i, channel1_01_128i), constant_signs_m128i)), 6);
1493 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1494 sum1_128i = _mm_add_epi32(sum1_128i, _mm_madd_epi16(absDifferencesHigh_128i, absDifferencesHigh_128i));
1496 absDifferencesLow_128i = _mm_slli_si128(_mm_sub_epi16(_mm_maddubs_epi16(_mm_unpacklo_epi8(mean0_2_128i, channel0_2_128i), constant_signs_m128i), _mm_maddubs_epi16(_mm_unpacklo_epi8(mean1_2_128i, channel1_2_128i), constant_signs_m128i)), 6);
1498 sum0_128i = _mm_add_epi32(sum0_128i, _mm_madd_epi16(absDifferencesLow_128i, absDifferencesLow_128i));
1504 if constexpr (blocks1 != 0u)
1506 constexpr unsigned int pixels = blocks1 / 3u;
1508 for (
unsigned int x = 0u; x < pixels; ++x)
1510 for (
unsigned int n = 0u; n < 3u; ++n)
1512 sumIndividual +=
sqrDistance(patch0[x * 3u + n] - meanValues0[n], patch1[x * 3u + n] - meanValues1[n]);
1520 patch0 += patch0StrideElements - patchWidthElements;
1521 patch1 += patch1StrideElements - patchWidthElements;