swr: [rasterizer core/sim] 8x2 backend + 16-wide tile clear/load/store
authorTim Rowley <timothy.o.rowley@intel.com>
Tue, 11 Oct 2016 17:57:29 +0000 (12:57 -0500)
committerTim Rowley <timothy.o.rowley@intel.com>
Fri, 14 Oct 2016 04:39:14 +0000 (23:39 -0500)
Work in progress (disabled).

USE_8x2_TILE_BACKEND define in knobs.h enables AVX512 code paths
(emulated on non-AVX512 HW).

Signed-off-by: Tim Rowley <timothy.o.rowley@intel.com>
13 files changed:
src/gallium/drivers/swr/rasterizer/common/os.h
src/gallium/drivers/swr/rasterizer/common/simd16intrin.h
src/gallium/drivers/swr/rasterizer/common/simdintrin.h
src/gallium/drivers/swr/rasterizer/core/backend.cpp
src/gallium/drivers/swr/rasterizer/core/backend.h
src/gallium/drivers/swr/rasterizer/core/format_conversion.h
src/gallium/drivers/swr/rasterizer/core/format_types.h
src/gallium/drivers/swr/rasterizer/core/knobs.h
src/gallium/drivers/swr/rasterizer/core/tilemgr.cpp
src/gallium/drivers/swr/rasterizer/core/utils.h
src/gallium/drivers/swr/rasterizer/memory/LoadTile.h
src/gallium/drivers/swr/rasterizer/memory/StoreTile.h
src/gallium/drivers/swr/rasterizer/memory/TilingFunctions.h

index 0671c5a56eee426d48337f0b42917acdaeccbf3b..ac52b605cc202a036aa342dba7493ec966be2e2f 100644 (file)
@@ -246,6 +246,9 @@ typedef MEGABYTE    GIGABYTE[1024];
 
 #define OSALIGNLINE(RWORD) OSALIGN(RWORD, 64)
 #define OSALIGNSIMD(RWORD) OSALIGN(RWORD, KNOB_SIMD_BYTES)
+#if ENABLE_AVX512_SIMD16
+#define OSALIGNSIMD16(RWORD) OSALIGN(RWORD, KNOB_SIMD16_BYTES)
+#endif
 
 #include "common/swr_assert.h"
 
index 8a1714ad1ea696902b222a42fd91cbcb41095db2..56ecf5bfd3d4d6699a3320835f0c0a0b0fdce234 100644 (file)
@@ -151,12 +151,12 @@ INLINE simd16scalari _simd16_set1_epi32(int a)
     return result;
 }
 
-INLINE simd16scalari _simd16_set_epi32(int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
+INLINE simd16scalar _simd16_set_ps(float e15, float e14, float e13, float e12, float e11, float e10, float e9, float e8, float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
 {
-    simd16scalari result;
+    simd16scalar result;
 
-    result.lo = _mm256_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0);
-    result.hi = _mm256_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0);
+    result.lo = _mm256_set_ps(e7, e6, e5, e4, e3, e2, e1, e0);
+    result.hi = _mm256_set_ps(e15, e14, e13, e12, e11, e10, e9, e8);
 
     return result;
 }
@@ -171,6 +171,26 @@ INLINE simd16scalari _simd16_set_epi32(int e15, int e14, int e13, int e12, int e
     return result;
 }
 
+INLINE simd16scalar _simd16_set_ps(float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
+{
+    simd16scalar result;
+
+    result.lo = _mm256_set_ps(e7, e6, e5, e4, e3, e2, e1, e0);
+    result.hi = _mm256_set_ps(e7, e6, e5, e4, e3, e2, e1, e0);
+
+    return result;
+}
+
+INLINE simd16scalari _simd16_set_epi32(int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
+{
+    simd16scalari result;
+
+    result.lo = _mm256_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0);
+    result.hi = _mm256_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0);
+
+    return result;
+}
+
 INLINE simd16scalar _simd16_load_ps(float const *m)
 {
     simd16scalar result;
@@ -267,6 +287,58 @@ INLINE void _simd16_store_si(simd16scalari *m, simd16scalari a)
     _mm256_store_si256(&m[0].hi, a.hi);
 }
 
+INLINE simdscalar _simd16_extract_ps(simd16scalar a, int imm8)
+{
+    switch (imm8)
+    {
+    case 0:
+        return a.lo;
+    case 1:
+        return a.hi;
+    }
+    return _simd_set1_ps(0.0f);
+}
+
+INLINE simdscalari _simd16_extract_si(simd16scalari a, int imm8)
+{
+    switch (imm8)
+    {
+    case 0:
+        return a.lo;
+    case 1:
+        return a.hi;
+    }
+    return _simd_set1_epi32(0);
+}
+
+INLINE simd16scalar _simd16_insert_ps(simd16scalar a, simdscalar b, int imm8)
+{
+    switch (imm8)
+    {
+    case 0:
+        a.lo = b;
+        break;
+    case 1:
+        a.hi = b;
+        break;
+    }
+    return a;
+}
+
+INLINE simd16scalari _simd16_insert_si(simd16scalari a, simdscalari b, int imm8)
+{
+    switch (imm8)
+    {
+    case 0:
+        a.lo = b;
+        break;
+    case 1:
+        a.hi = b;
+        break;
+    }
+    return a;
+}
+
 template <simd16mask mask>
 INLINE simd16scalar _simd16_blend_ps_temp(simd16scalar a, simd16scalar b)
 {
@@ -446,10 +518,10 @@ SIMD16_EMU_AVX512_2(simd16scalari, _simd16_max_epi32, _mm256_max_epi32)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_min_epu32, _mm256_min_epu32)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_max_epu32, _mm256_max_epu32)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_add_epi32, _mm256_add_epi32)
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_and_si, _mm256_and_si256)
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_andnot_si, _mm256_andnot_si256)
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_or_si, _mm256_or_si256)
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_xor_si, _mm256_xor_si256)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_and_si, _simd_and_si)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_andnot_si, _simd_andnot_si)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_or_si, _simd_or_si)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_xor_si, _simd_xor_si)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_cmpeq_epi32, _mm256_cmpeq_epi32)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_cmpgt_epi32, _mm256_cmpgt_epi32)
 
@@ -463,16 +535,18 @@ INLINE int _simd16_testz_ps(simd16scalar a, simd16scalar b)
 
 #define _simd16_cmplt_epi32(a, b) _simd16_cmpgt_epi32(b, a)
 
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpacklo_epi32, _mm256_unpacklo_epi32)
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpackhi_epi32, _mm256_unpackhi_epi32)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpacklo_epi32, _simd_unpacklo_epi32)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpackhi_epi32, _simd_unpackhi_epi32)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpacklo_epi64, _simd_unpacklo_epi64)
+SIMD16_EMU_AVX512_2(simd16scalari, _simd16_unpackhi_epi64, _simd_unpackhi_epi64)
 
 template <int imm8>
 INLINE simd16scalari _simd16_slli_epi32_temp(simd16scalari a)
 {
     simd16scalari result;
 
-    result.lo = _mm256_slli_epi32(a.lo, imm8);
-    result.hi = _mm256_slli_epi32(a.hi, imm8);
+    result.lo = _simd_slli_epi32(a.lo, imm8);
+    result.hi = _simd_slli_epi32(a.hi, imm8);
 
     return result;
 }
@@ -484,8 +558,8 @@ INLINE simd16scalari _simd16_srai_epi32_temp(simd16scalari a)
 {
     simd16scalari result;
 
-    result.lo = _mm256_srai_epi32(a.lo, imm8);
-    result.hi = _mm256_srai_epi32(a.hi, imm8);
+    result.lo = _simd_srai_epi32(a.lo, imm8);
+    result.hi = _simd_srai_epi32(a.hi, imm8);
 
     return result;
 }
@@ -497,8 +571,8 @@ INLINE simd16scalari _simd16_srli_epi32_temp(simd16scalari a)
 {
     simd16scalari result;
 
-    result.lo = _mm256_srli_epi32(a.lo, imm8);
-    result.hi = _mm256_srli_epi32(a.hi, imm8);
+    result.lo = _simd_srli_epi32(a.lo, imm8);
+    result.hi = _simd_srli_epi32(a.hi, imm8);
 
     return result;
 }
@@ -534,28 +608,78 @@ SIMD16_EMU_AVX512_2(simd16scalari, _simd16_cmpgt_epi16, _mm256_cmpgt_epi16)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_cmpeq_epi8, _mm256_cmpeq_epi8)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_cmpgt_epi8, _mm256_cmpgt_epi8)
 
-INLINE simd16scalar _simd16_permute_ps(simd16scalar a, simd16scalari b)
+INLINE simd16scalar _simd16_permute_ps(simd16scalar a, simd16scalari i)
 {
     simd16scalar result;
 
-    result.lo = _mm256_permutevar8x32_ps(a.lo, b.lo);
-    result.hi = _mm256_permutevar8x32_ps(a.hi, b.hi);
+    const simdscalari mask = _simd_set1_epi32(7);
+
+    simdscalar lolo = _simd_permute_ps(a.lo, _simd_and_si(i.lo, mask));
+    simdscalar lohi = _simd_permute_ps(a.hi, _simd_and_si(i.lo, mask));
+
+    simdscalar hilo = _simd_permute_ps(a.lo, _simd_and_si(i.hi, mask));
+    simdscalar hihi = _simd_permute_ps(a.hi, _simd_and_si(i.hi, mask));
+
+    result.lo = _simd_blendv_ps(lolo, lohi, _simd_castsi_ps(_simd_cmpgt_epi32(i.lo, mask)));
+    result.hi = _simd_blendv_ps(hilo, hihi, _simd_castsi_ps(_simd_cmpgt_epi32(i.hi, mask)));
 
     return result;
 }
 
-SIMD16_EMU_AVX512_2(simd16scalari, _simd16_permute_epi32, _mm256_permutevar8x32_epi32)
+INLINE simd16scalari _simd16_permute_epi32(simd16scalari a, simd16scalari i)
+{
+    return _simd16_castps_si(_simd16_permute_ps(_simd16_castsi_ps(a), i));
+}
 
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_srlv_epi32, _mm256_srlv_epi32)
 SIMD16_EMU_AVX512_2(simd16scalari, _simd16_sllv_epi32, _mm256_sllv_epi32)
 
+template <int imm8>
+INLINE simd16scalar _simd16_permute2f128_ps_temp(simd16scalar a, simd16scalar b)
+{
+    simd16scalar result;
+
+    result.lo = _simd_permute2f128_ps(a.lo, a.hi, ((imm8 & 0x03) << 0) | ((imm8 & 0x0C) << 2));
+    result.hi = _simd_permute2f128_ps(b.lo, b.hi, ((imm8 & 0x30) >> 4) | ((imm8 & 0xC0) >> 2));
+
+    return result;
+}
+
+#define _simd16_permute2f128_ps(a, b, imm8) _simd16_permute2f128_ps_temp<imm8>(a, b)
+
+template <int imm8>
+INLINE simd16scalard _simd16_permute2f128_pd_temp(simd16scalard a, simd16scalard b)
+{
+    simd16scalard result;
+
+    result.lo = _simd_permute2f128_pd(a.lo, a.hi, ((imm8 & 0x03) << 0) | ((imm8 & 0x0C) << 2));
+    result.hi = _simd_permute2f128_pd(b.lo, b.hi, ((imm8 & 0x30) >> 4) | ((imm8 & 0xC0) >> 2));
+
+    return result;
+}
+
+#define _simd16_permute2f128_pd(a, b, imm8) _simd16_permute2f128_pd_temp<imm8>(a, b)
+
+template <int imm8>
+INLINE simd16scalari _simd16_permute2f128_si_temp(simd16scalari a, simd16scalari b)
+{
+    simd16scalari result;
+
+    result.lo = _simd_permute2f128_si(a.lo, a.hi, ((imm8 & 0x03) << 0) | ((imm8 & 0x0C) << 2));
+    result.hi = _simd_permute2f128_si(b.lo, b.hi, ((imm8 & 0x30) >> 4) | ((imm8 & 0xC0) >> 2));
+
+    return result;
+}
+
+#define _simd16_permute2f128_si(a, b, imm8) _simd16_permute2f128_si_temp<imm8>(a, b)
+
 template <int imm8>
 INLINE simd16scalar _simd16_shuffle_ps_temp(simd16scalar a, simd16scalar b)
 {
     simd16scalar result;
 
-    result.lo = _mm256_shuffle_ps(a.lo, b.lo, imm8);
-    result.hi = _mm256_shuffle_ps(a.hi, b.hi, imm8);
+    result.lo = _simd_shuffle_ps(a.lo, b.lo, imm8);
+    result.hi = _simd_shuffle_ps(a.hi, b.hi, imm8);
 
     return result;
 }
@@ -563,17 +687,48 @@ INLINE simd16scalar _simd16_shuffle_ps_temp(simd16scalar a, simd16scalar b)
 #define _simd16_shuffle_ps(a, b, imm8) _simd16_shuffle_ps_temp<imm8>(a, b)
 
 template <int imm8>
-INLINE simd16scalari _simd16_permute_128_temp(simd16scalari a, simd16scalari b)
+INLINE simd16scalard _simd16_shuffle_pd_temp(simd16scalard a, simd16scalard b)
 {
-    simd16scalari result;
+    simd16scalard result;
 
-    result.lo = _mm256_permute2x128_si256(a.lo, b.lo, imm8);
-    result.hi = _mm256_permute2x128_si256(a.hi, b.hi, imm8);
+    result.lo = _simd_shuffle_pd(a.lo, b.lo, (imm8 & 15));
+    result.hi = _simd_shuffle_pd(a.hi, b.hi, (imm8 >> 4));
 
     return result;
 }
 
-#define _simd16_permute_128(a, b, imm8) _simd16_permute_128_temp<imm8>(a, b)
+#define _simd16_shuffle_pd(a, b, imm8) _simd16_shuffle_pd_temp<imm8>(a, b)
+
+template <int imm8>
+INLINE simd16scalari _simd16_shuffle_epi32_temp(simd16scalari a, simd16scalari b)
+{
+    return _simd16_castps_si(_simd16_shuffle_ps(_simd16_castsi_ps(a), _simd16_castsi_ps(b), imm8));
+}
+
+#define _simd16_shuffle_epi32(a, b, imm8) _simd16_shuffle_epi32_temp<imm8>(a, b)
+
+template <int imm8>
+INLINE simd16scalari _simd16_shuffle_epi64_temp(simd16scalari a, simd16scalari b)
+{
+    return _simd16_castpd_si(_simd16_shuffle_pd(_simd16_castsi_pd(a), _simd16_castsi_pd(b), imm8));
+}
+
+#define _simd16_shuffle_epi64(a, b, imm8) _simd16_shuffle_epi64_temp<imm8>(a, b)
+
+INLINE simd16mask _simd16_int2mask(int mask)
+{
+    return mask;
+}
+
+INLINE int _simd16_mask2int(simd16mask mask)
+{
+    return mask;
+}
+
+INLINE simd16mask _simd16_cmplt_ps_mask(simd16scalar a, simd16scalar b)
+{
+    return _simd16_movemask_ps(_simd16_cmplt_ps(a, b));
+}
 
 // convert bitmask to vector mask
 INLINE simd16scalar vMask16(int32_t mask)
@@ -591,21 +746,13 @@ INLINE simd16scalar vMask16(int32_t mask)
 
 INLINE simd16mask _simd16_scalari2mask(simd16scalari mask)
 {
-    __m512i flag = _mm512_set1_epi32(0x80000000);
-
-    __m512i temp = _mm512_and_epi32(mask, flag);
-
-    return _mm512_cmpeq_epu32_mask(temp, flag);
+    return _mm512_cmpneq_epu32_mask(mask, _mm512_setzero_epi32());
 }
 
 #if 0
 INLINE simd16mask _simd16_scalard2mask(simd16scalard mask)
 {
-    __m512i flag = _mm512_set1_epi64(0x8000000000000000);
-
-    __m512 tempi = _mm512_and_epi64(_mm512_castpd_si512(mask), flag);
-
-    return _mm512_cmpeq_epu64_mask(temp, flag);
+    return _mm512_cmpneq_epu64_mask(mask, _mm512_setzero_epi64());
 }
 #endif
 
@@ -615,22 +762,24 @@ INLINE simd16mask _simd16_scalard2mask(simd16scalard mask)
 #define _simd16_set1_epi8       _mm512_set1_epi8
 #define _simd16_set1_epi32      _mm512_set1_epi32
 
-INLINE simd16scalari _simd16_set_epi32(int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
+INLINE simd16scalar _simd16_set_ps(float e15, float e14, float e13, float e12, float e11, float e10, float e9, float e8, float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
 {
-    simd16scalari result;
-
-    result = _mm512_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0, e7, e6, e5, e4, e3, e2, e1, e0);
-
-    return result;
+    return _mm512_set_ps(e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0);
 }
 
 INLINE simd16scalari _simd16_set_epi32(int e15, int e14, int e13, int e12, int e11, int e10, int e9, int e8, int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
 {
-    simd16scalari result;
+    return _mm512_set_epi32(e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0);
+}
 
-    result = _mm512_set_epi32(e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0);
+INLINE simd16scalar _simd16_set_ps(float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
+{
+    return _mm512_set_ps(e7, e6, e5, e4, e3, e2, e1, e0, e7, e6, e5, e4, e3, e2, e1, e0);
+}
 
-    return result;
+INLINE simd16scalari _simd16_set_epi32(int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
+{
+    return _mm512_set_epi32(e7, e6, e5, e4, e3, e2, e1, e0, e7, e6, e5, e4, e3, e2, e1, e0);
 }
 
 #define _simd16_load_ps         _mm512_load_ps
@@ -638,12 +787,16 @@ INLINE simd16scalari _simd16_set_epi32(int e15, int e14, int e13, int e12, int e
 #if 1
 #define _simd16_load1_ps        _simd16_broadcast_ss
 #endif
-#define _simd16_load_si         _mm256_load_si256
-#define _simd16_loadu_si        _mm256_loadu_si256
+#define _simd16_load_si         _mm512_load_si512
+#define _simd16_loadu_si        _mm512_loadu_si512
 #define _simd16_broadcast_ss(m) _mm512_extload_ps(m, _MM_UPCONV_PS_NONE, _MM_BROADCAST_1X16, 0)
 #define _simd16_broadcast_ps(m) _mm512_extload_ps(m, _MM_UPCONV_PS_NONE, _MM_BROADCAST_4X16, 0)
 #define _simd16_store_ps        _mm512_store_ps
 #define _simd16_store_si        _mm512_store_si512
+#define _simd16_extract_ps      _mm512_extractf32x8_ps
+#define _simd16_extract_si      _mm512_extracti32x8_epi32
+#define _simd16_insert_ps       _mm512_insertf32x8
+#define _simd16_insert_si       _mm512_inserti32x8
 
 INLINE void _simd16_maskstore_ps(float *m, simd16scalari mask, simd16scalar a)
 {
@@ -678,7 +831,7 @@ INLINE simd16scalari _simd16_blendv_epi32(simd16scalari a, simd16scalari b, cons
 #define _simd16_mul_ps          _mm512_mul_ps
 #define _simd16_add_ps          _mm512_add_ps
 #define _simd16_sub_ps          _mm512_sub_ps
-#define _simd16_rsqrt_ps        _mm512_rsqrt23_ps
+#define _simd16_rsqrt_ps        _mm512_rsqrt14_ps
 #define _simd16_min_ps          _mm512_min_ps
 #define _simd16_max_ps          _mm512_max_ps
 
@@ -710,7 +863,7 @@ INLINE simd16scalar _simd16_cmp_ps_temp(simd16scalar a, simd16scalar b)
 {
     simd16mask k = _mm512_cmpeq_ps_mask(a, b);
 
-    return _mm512_castsi256_ps(_mm512_mask_blend_epi32(k, _mm512_setzero_epi32(), _mm512_set1_epi32(0xFFFFFFFF)));
+    return _mm512_castsi512_ps(_mm512_mask_blend_epi32(k, _mm512_setzero_epi32(), _mm512_set1_epi32(0xFFFFFFFF)));
 }
 
 #define _simd16_cmp_ps(a, b, comp)  _simd16_cmp_ps_temp<comp>(a, b)
@@ -787,6 +940,8 @@ INLINE int _simd16_testz_ps(simd16scalar a, simd16scalar b)
 
 #define _simd16_unpacklo_epi32    _mm512_unpacklo_epi32
 #define _simd16_unpackhi_epi32    _mm512_unpackhi_epi32
+#define _simd16_unpacklo_epi64    _mm512_unpacklo_epi64
+#define _simd16_unpackhi_epi64    _mm512_unpackhi_epi64
 #define _simd16_slli_epi32        _mm512_slli_epi32
 #define _simd16_srli_epi32        _mm512_srli_epi32
 #define _simd16_srai_epi32        _mm512_srai_epi32
@@ -844,33 +999,46 @@ INLINE simd16scalari _simd16_cmpgt_epi8(simd16scalari a, simd16scalari b)
     return _mm512_mask_blend_epi8(k, _mm512_setzero_si512(), _mm512_set1_epi32(0xFFFFFFFF));
 }
 
-#if 0
-INLINE simd16scalar _simd16_permute_ps(simd16scalar a, simd16scalari b)
-{
-    simd16scalar result;
+#define _simd16_permute_ps(a, i)        _mm512_permutexvar_ps(i, a)
+#define _simd16_permute_epi32(a, i)     _mm512_permutexvar_epi32(i, a)
+#define _simd16_sllv_epi32              _mm512_srlv_epi32
+#define _simd16_srlv_epi32              _mm512_sllv_epi32
+#define _simd16_permute2f128_ps         _mm512_shuffle_f32x4
+#define _simd16_permute2f128_pd         _mm512_shuffle_f64x2
+#define _simd16_permute2f128_si         _mm512_shuffle_i32x4
+#define _simd16_shuffle_ps              _mm512_shuffle_ps
+#define _simd16_shuffle_pd              _mm512_shuffle_pd
 
-    result.lo = _mm256_permutevar8x32_ps(a.lo, b.lo);
-    result.hi = _mm256_permutevar8x32_ps(a.hi, b.hi);
-
-    return result;
+template <int imm8>
+INLINE simd16scalari _simd16_shuffle_epi32_temp(simd16scalari a, simd16scalari b)
+{
+    return _simd16_castps_si(_simd16_shuffle_ps(_simd16_castsi_ps(a), _simd16_castsi_ps(b), imm8));
 }
 
-INLINE (simd16scalari _simd16_permute_epi32(simd16scalari a, simd16scalari b)
+#define _simd16_shuffle_epi32(a, b, imm8) _simd16_shuffle_epi32_temp<imm8>(a, b)
+
+template <int imm8>
+INLINE simd16scalari _simd16_shuffle_epi64_temp(simd16scalari a, simd16scalari b)
 {
-    simd16scalar result;
+    return _simd16_castpd_si(_simd16_shuffle_pd(_simd16_castsi_pd(a), _simd16_castsi_pd(b), imm8));
+}
 
-    result.lo = _mm256_permutevar8x32_epi32(a.lo, b.lo);
-    result.hi = _mm256_permutevar8x32_epi32(a.hi, b.hi);
+#define _simd16_shuffle_epi64(a, b, imm8) _simd16_shuffle_epi64_temp<imm8>(a, b)
 
-    return result;
+INLINE simd16mask _simd16_int2mask(int mask)
+{
+    return _mm512_int2mask(mask);
 }
 
-#endif
+INLINE int _simd16_mask2int(simd16mask mask)
+{
+    return _mm512_mask2int(mask);
+}
 
-#define _simd16_sllv_epi32        _mm512_srlv_epi32
-#define _simd16_srlv_epi32        _mm512_sllv_epi32
-#define _simd16_shuffle_ps        _mm512_shuffle_ps
-#define _simd16_permute_128       _mm512_permute4f128_epi32
+INLINE simd16mask _simd16_cmplt_ps_mask(simd16scalar a, simd16scalar b)
+{
+    return _mm512_cmplt_ps_mask(a, b);
+}
 
 // convert bitmask to vector mask
 INLINE simd16scalar vMask16(int32_t mask)
index 3ad37de3d49c58e7c307de464dfcc8323206600f..7671031cee874e0c12cf6ca6b0b383deb0ac8509 100644 (file)
@@ -296,6 +296,7 @@ __m256i _simdemu_sllv_epi32(__m256i vA, __m256i vCount)
 #define _simd_cmplt_epi32 _simdemu_cmplt_epi32
 #define _simd_cmpgt_epi32 _simdemu_cmpgt_epi32
 #define _simd_or_si _simdemu_or_si
+#define _simd_xor_si _simdemu_xor_si
 #define _simd_castps_si _mm256_castps_si256
 #define _simd_adds_epu8 _simdemu_adds_epu8
 #define _simd_subs_epu8 _simdemu_subs_epu8
@@ -327,6 +328,7 @@ SIMD_EMU_EPI(_simdemu_cmpeq_epi32, _mm_cmpeq_epi32)
 SIMD_EMU_EPI(_simdemu_cmplt_epi32, _mm_cmplt_epi32)
 SIMD_EMU_EPI(_simdemu_cmpgt_epi32, _mm_cmpgt_epi32)
 SIMD_EMU_EPI(_simdemu_or_si, _mm_or_si128)
+SIMD_EMU_EPI(_simdemu_xor_si, _mm_xor_si128)
 SIMD_EMU_EPI(_simdemu_adds_epu8, _mm_adds_epu8)
 SIMD_EMU_EPI(_simdemu_subs_epu8, _mm_subs_epu8)
 SIMD_EMU_EPI(_simdemu_add_epi8, _mm_add_epi8)
@@ -339,6 +341,8 @@ SIMD_EMU_EPI(_simdemu_cmpeq_epi16, _mm_cmpeq_epi16)
 
 #define _simd_unpacklo_epi32(a, b) _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)))
 #define _simd_unpackhi_epi32(a, b) _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b)))
+#define _simd_unpacklo_epi64(a, b) _mm256_castpd_si256(_mm256_unpacklo_pd(_mm256_castsi256_pd(a), _mm256_castsi256_pd(b)))
+#define _simd_unpackhi_epi64(a, b) _mm256_castpd_si256(_mm256_unpackhi_pd(_mm256_castsi256_pd(a), _mm256_castsi256_pd(b)))
 
 #define _simd_slli_epi32(a,i) _simdemu_slli_epi32(a,i)
 #define _simd_srai_epi32(a,i) _simdemu_srai_epi32(a,i)
@@ -433,6 +437,63 @@ int _simdemu_movemask_epi8(__m256i a)
 
     return (resHi << 16) | resLo;
 }
+
+INLINE
+__m256i _simd_cvtepu8_epi32(__m128i a)
+{
+    __m128i resultlo = _mm_cvtepu8_epi32(a);
+    __m128i resulthi = _mm_shuffle_epi8(a, _mm_set_epi32(0x80808007, 0x80808006, 0x80808005, 0x80808004));
+
+    __m256i result = _mm256_castsi128_si256(resultlo);
+
+    return _mm256_insertf128_si256(result, resulthi, 1);
+}
+
+INLINE
+__m256i _simd_cvtepu16_epi32(__m128i a)
+{
+    __m128i resultlo = _mm_cvtepu16_epi32(a);
+    __m128i resulthi = _mm_shuffle_epi8(a, _mm_set_epi32(0x80800F0E, 0x80800D0C, 0x80800B0A, 0x80800908));
+
+    __m256i result = _mm256_castsi128_si256(resultlo);
+
+    return _mm256_insertf128_si256(result, resulthi, 1);
+}
+
+INLINE
+__m256i _simd_packus_epi32(__m256i a, __m256i b)
+{
+    __m128i alo = _mm256_extractf128_si256(a, 0);
+    __m128i ahi = _mm256_extractf128_si256(a, 1);
+
+    __m128i blo = _mm256_extractf128_si256(b, 0);
+    __m128i bhi = _mm256_extractf128_si256(b, 1);
+
+    __m128i resultlo = _mm_packus_epi32(alo, blo);
+    __m128i resulthi = _mm_packus_epi32(ahi, bhi);
+
+    __m256i result = _mm256_castsi128_si256(resultlo);
+
+    return _mm256_insertf128_si256(result, resulthi, 1);
+}
+
+INLINE
+__m256i _simd_packs_epi32(__m256i a, __m256i b)
+{
+    __m128i alo = _mm256_extractf128_si256(a, 0);
+    __m128i ahi = _mm256_extractf128_si256(a, 1);
+
+    __m128i blo = _mm256_extractf128_si256(b, 0);
+    __m128i bhi = _mm256_extractf128_si256(b, 1);
+
+    __m128i resultlo = _mm_packs_epi32(alo, blo);
+    __m128i resulthi = _mm_packs_epi32(ahi, bhi);
+
+    __m256i result = _mm256_castsi128_si256(resultlo);
+
+    return _mm256_insertf128_si256(result, resulthi, 1);
+}
+
 #else
 
 #define _simd_mul_epi32 _mm256_mul_epi32
@@ -450,10 +511,13 @@ int _simdemu_movemask_epi8(__m256i a)
 #define _simd_cmplt_epi32(a,b) _mm256_cmpgt_epi32(b,a)
 #define _simd_cmpgt_epi32(a,b) _mm256_cmpgt_epi32(a,b)
 #define _simd_or_si _mm256_or_si256
+#define _simd_xor_si _mm256_xor_si256
 #define _simd_castps_si _mm256_castps_si256
 
 #define _simd_unpacklo_epi32 _mm256_unpacklo_epi32
 #define _simd_unpackhi_epi32 _mm256_unpackhi_epi32
+#define _simd_unpacklo_epi64 _mm256_unpacklo_epi64
+#define _simd_unpackhi_epi64 _mm256_unpackhi_epi64
 
 #define _simd_srli_si(a,i) _simdemu_srli_si128<i>(a)
 #define _simd_slli_epi32 _mm256_slli_epi32
@@ -479,19 +543,23 @@ int _simdemu_movemask_epi8(__m256i a)
 #define _simd_cmpeq_epi16  _mm256_cmpeq_epi16
 #define _simd_movemask_epi8 _mm256_movemask_epi8
 #define _simd_permute_ps _mm256_permutevar8x32_ps
+#define _simd_permute_epi32 _mm256_permutevar8x32_epi32
 #define _simd_srlv_epi32 _mm256_srlv_epi32
 #define _simd_sllv_epi32 _mm256_sllv_epi32
+#define _simd_cvtepu8_epi32 _mm256_cvtepu8_epi32
+#define _simd_cvtepu16_epi32 _mm256_cvtepu16_epi32
+#define _simd_packus_epi32 _mm256_packus_epi32
+#define _simd_packs_epi32 _mm256_packs_epi32
 
-INLINE
-simdscalari _simd_permute_epi32(simdscalari a, simdscalari index)
-{
-    return _simd_castps_si(_mm256_permutevar8x32_ps(_mm256_castsi256_ps(a), index));
-}
 #endif
 
-#define _simd_permute_128 _mm256_permute2f128_si256
-#define _simd_shuffleps_epi32(vA, vB, imm) _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(vA), _mm256_castsi256_ps(vB), imm))
+#define _simd_permute2f128_ps _mm256_permute2f128_ps
+#define _simd_permute2f128_pd _mm256_permute2f128_pd
+#define _simd_permute2f128_si _mm256_permute2f128_si256
 #define _simd_shuffle_ps _mm256_shuffle_ps
+#define _simd_shuffle_pd _mm256_shuffle_pd
+#define _simd_shuffle_epi32(a, b, imm8) _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), imm8))
+#define _simd_shuffle_epi64(a, b, imm8) _mm256_castps_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a), _mm256_castsi256_pd(b), imm8))
 #define _simd_set1_epi32 _mm256_set1_epi32
 #define _simd_set_epi32 _mm256_set_epi32
 #define _simd_set1_epi8 _mm256_set1_epi8
@@ -506,7 +574,6 @@ simdscalari _simd_permute_epi32(simdscalari a, simdscalari index)
 #define _simd_testz_ps _mm256_testz_ps
 #define _simd_xor_ps _mm256_xor_ps
 
-
 INLINE
 simdscalari _simd_blendv_epi32(simdscalari a, simdscalari b, simdscalar mask)
 {
@@ -1060,16 +1127,6 @@ INLINE simdscalar _simd_shuffle_ps(simdscalar a, simdscalar b, const int imm8)
     return result;
 }
 
-INLINE simdscalari _simd_permute_128(simdscalari a, simdscalari b, const int imm8)
-{
-    simdscalari result;
-
-    result.lo = _mm256_permute2x128_si256(a.lo, b.lo, imm8);
-    result.hi = _mm256_permute2x128_si256(a.hi, b.hi, imm8);
-
-    return result;
-}
-
 // convert bitmask to vector mask
 INLINE simdscalar vMask(int32_t mask)
 {
index 143bd258afd5a30c05d393993e00f0f74dedd10c..f71c2b2d3452ef10d6afd590aef4debcaa5740a7 100644 (file)
@@ -101,21 +101,59 @@ void ClearRasterTile(uint8_t *pTileBuffer, simdvector &value)
     auto lambda = [&](int32_t comp)
     {
         FormatTraits<format>::storeSOA(comp, pTileBuffer, value.v[comp]);
+
         pTileBuffer += (KNOB_SIMD_WIDTH * FormatTraits<format>::GetBPC(comp) / 8);
     };
 
     const uint32_t numIter = (KNOB_TILE_Y_DIM / SIMD_TILE_Y_DIM) * (KNOB_TILE_X_DIM / SIMD_TILE_X_DIM);
+
     for (uint32_t i = 0; i < numIter; ++i)
     {
         UnrollerL<0, FormatTraits<format>::numComps, 1>::step(lambda);
     }
 }
 
+#if USE_8x2_TILE_BACKEND
+template<SWR_FORMAT format>
+void ClearRasterTile(uint8_t *pTileBuffer, simd16vector &value)
+{
+    auto lambda = [&](int32_t comp)
+    {
+        FormatTraits<format>::storeSOA(comp, pTileBuffer, value.v[comp]);
+
+        pTileBuffer += (KNOB_SIMD16_WIDTH * FormatTraits<format>::GetBPC(comp) / 8);
+    };
+
+    const uint32_t numIter = (KNOB_TILE_Y_DIM / SIMD16_TILE_Y_DIM) * (KNOB_TILE_X_DIM / SIMD16_TILE_X_DIM);
+
+    for (uint32_t i = 0; i < numIter; ++i)
+    {
+        UnrollerL<0, FormatTraits<format>::numComps, 1>::step(lambda);
+    }
+}
+
+#endif
 template<SWR_FORMAT format>
 INLINE void ClearMacroTile(DRAW_CONTEXT *pDC, SWR_RENDERTARGET_ATTACHMENT rt, uint32_t macroTile, DWORD clear[4], const SWR_RECT& rect)
 {
     // convert clear color to hottile format
     // clear color is in RGBA float/uint32
+#if USE_8x2_TILE_BACKEND
+    simd16vector vClear;
+    for (uint32_t comp = 0; comp < FormatTraits<format>::numComps; ++comp)
+    {
+        simd16scalar vComp;
+        vComp = _simd16_load1_ps((const float*)&clear[comp]);
+        if (FormatTraits<format>::isNormalized(comp))
+        {
+            vComp = _simd16_mul_ps(vComp, _simd16_set1_ps(FormatTraits<format>::fromFloat(comp)));
+            vComp = _simd16_castsi_ps(_simd16_cvtps_epi32(vComp));
+        }
+        vComp = FormatTraits<format>::pack(comp, vComp);
+        vClear.v[FormatTraits<format>::swizzle(comp)] = vComp;
+    }
+
+#else
     simdvector vClear;
     for (uint32_t comp = 0; comp < FormatTraits<format>::numComps; ++comp)
     {
@@ -130,6 +168,7 @@ INLINE void ClearMacroTile(DRAW_CONTEXT *pDC, SWR_RENDERTARGET_ATTACHMENT rt, ui
         vClear.v[FormatTraits<format>::swizzle(comp)] = vComp;
     }
 
+#endif
     uint32_t tileX, tileY;
     MacroTileMgr::getTileIndices(macroTile, tileX, tileY);
 
@@ -471,6 +510,10 @@ void BackendSingleSample(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint3
 
         for(uint32_t xx = x; xx < x + KNOB_TILE_X_DIM; xx += SIMD_TILE_X_DIM)
         {
+#if USE_8x2_TILE_BACKEND
+            const bool useAlternateOffset = ((xx & SIMD_TILE_X_DIM) != 0);
+
+#endif
             if(coverageMask & MASK)
             {
                 psContext.vX.UL = _simd_add_ps(vULOffsetsX, _simd_set1_ps((float)xx));
@@ -578,7 +621,11 @@ void BackendSingleSample(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint3
 
                 // output merger
                 AR_BEGIN(BEOutputMerger, pDC->drawId);
+#if USE_8x2_TILE_BACKEND
+                OutputMerger(psContext, pColorBase, 0, pBlendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, pPSState->numRenderTargets, useAlternateOffset);
+#else
                 OutputMerger(psContext, pColorBase, 0, pBlendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, pPSState->numRenderTargets);
+#endif
 
                 // do final depth write after all pixel kills
                 if (!pPSState->forceEarlyZ)
@@ -599,10 +646,20 @@ Endtile:
             pDepthBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp) / 8;
             pStencilBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp) / 8;
 
-            for(uint32_t rt = 0; rt < NumRT; ++rt)
+#if USE_8x2_TILE_BACKEND
+            if (useAlternateOffset)
+            {
+                for (uint32_t rt = 0; rt < NumRT; ++rt)
+                {
+                    pColorBase[rt] += (2 * KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
+                }
+            }
+#else
+            for (uint32_t rt = 0; rt < NumRT; ++rt)
             {
                 pColorBase[rt] += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
             }
+#endif
             AR_END(BEEndTile, 0);
         }
     }
@@ -675,6 +732,10 @@ void BackendSampleRate(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint32_
         
         for (uint32_t xx = x; xx < x + KNOB_TILE_X_DIM; xx += SIMD_TILE_X_DIM)
         {
+#if USE_8x2_TILE_BACKEND
+            const bool useAlternateOffset = ((xx & SIMD_TILE_X_DIM) != 0);
+
+#endif
             psContext.vX.UL = _simd_add_ps(vULOffsetsX, _simd_set1_ps((float)xx));
             // pixel center
             psContext.vX.center = _simd_add_ps(vCenterOffsetsX, _simd_set1_ps((float)xx));
@@ -814,7 +875,11 @@ void BackendSampleRate(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint32_
 
                     // output merger
                     AR_BEGIN(BEOutputMerger, pDC->drawId);
+#if USE_8x2_TILE_BACKEND
+                    OutputMerger(psContext, pColorBase, sample, pBlendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, pPSState->numRenderTargets, useAlternateOffset);
+#else
                     OutputMerger(psContext, pColorBase, sample, pBlendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, pPSState->numRenderTargets);
+#endif
 
                     // do final depth write after all pixel kills
                     if (!pPSState->forceEarlyZ)
@@ -837,10 +902,20 @@ Endtile:
             pDepthBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp) / 8;
             pStencilBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp) / 8;
 
+#if USE_8x2_TILE_BACKEND
+            if (useAlternateOffset)
+            {
+                for (uint32_t rt = 0; rt < NumRT; ++rt)
+                {
+                    pColorBase[rt] += (2 * KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
+                }
+            }
+#else
             for (uint32_t rt = 0; rt < NumRT; ++rt)
             {
                 pColorBase[rt] += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
             }
+#endif
             AR_END(BEEndTile, 0);
         }
     }
@@ -913,6 +988,10 @@ void BackendPixelRate(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint32_t
         psContext.vY.center = _simd_add_ps(vCenterOffsetsY, _simd_set1_ps((float)yy));
         for(uint32_t xx = x; xx < x + KNOB_TILE_X_DIM; xx += SIMD_TILE_X_DIM)
         {
+#if USE_8x2_TILE_BACKEND
+            const bool useAlternateOffset = ((xx & SIMD_TILE_X_DIM) != 0);
+
+#endif
             simdscalar activeLanes;
             if(!(work.anyCoveredSamples & MASK)) {goto Endtile;};
             activeLanes = vMask(work.anyCoveredSamples & MASK);
@@ -1030,7 +1109,11 @@ void BackendPixelRate(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint32_t
                 }
                 
                 // broadcast the results of the PS to all passing pixels
+#if USE_8x2_TILE_BACKEND
+                OutputMerger(psContext, pColorBase, sample, pBlendState, state.pfnBlendFunc, coverageMask, depthMask, pPSState->numRenderTargets, useAlternateOffset);
+#else
                 OutputMerger(psContext, pColorBase, sample, pBlendState, state.pfnBlendFunc, coverageMask, depthMask, pPSState->numRenderTargets);
+#endif
 
                 if(!pPSState->forceEarlyZ && !T::bForcedSampleCount)
                 {
@@ -1057,10 +1140,20 @@ Endtile:
             pDepthBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp) / 8;
             pStencilBase += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp) / 8;
 
+#if USE_8x2_TILE_BACKEND
+            if (useAlternateOffset)
+            {
+                for (uint32_t rt = 0; rt < NumRT; ++rt)
+                {
+                    pColorBase[rt] += (2 * KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
+                }
+            }
+#else
             for(uint32_t rt = 0; rt < NumRT; ++rt)
             {
                 pColorBase[rt] += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
             }
+#endif
             AR_END(BEEndTile, 0);
         }
     }
index fcc78f71afdee77c589e0a9b3d38806b118613a3..53222eabccd03f11d7d0efc5d036a121b0187e8c 100644 (file)
@@ -643,6 +643,78 @@ INLINE void OutputMerger(SWR_PS_CONTEXT &psContext, uint8_t* (&pColorBase)[SWR_N
     }
 }
 
+#if USE_8x2_TILE_BACKEND
+INLINE void OutputMerger(SWR_PS_CONTEXT &psContext, uint8_t* (&pColorBase)[SWR_NUM_RENDERTARGETS], uint32_t sample, const SWR_BLEND_STATE *pBlendState,
+    const PFN_BLEND_JIT_FUNC(&pfnBlendFunc)[SWR_NUM_RENDERTARGETS], simdscalar &coverageMask, simdscalar depthPassMask, const uint32_t NumRT, bool useAlternateOffset)
+{
+    assert(sample == 0); // will need up upate Raster Tile Color Offsets to support more than single sample here..
+
+    // type safety guaranteed from template instantiation in BEChooser<>::GetFunc
+    uint32_t rasterTileColorOffset = RasterTileColorOffset(sample);
+
+    if (useAlternateOffset)
+    {
+        rasterTileColorOffset += sizeof(simdscalar);
+    }
+
+    simdvector blendSrc;
+    simdvector blendOut;
+
+    for (uint32_t rt = 0; rt < NumRT; ++rt)
+    {
+        simdscalar *pColorSample = reinterpret_cast<simdscalar *>(pColorBase[rt] + rasterTileColorOffset);
+
+        const SWR_RENDER_TARGET_BLEND_STATE *pRTBlend = &pBlendState->renderTarget[rt];
+        // pfnBlendFunc may not update all channels.  Initialize with PS output.
+        /// TODO: move this into the blend JIT.
+        blendOut = psContext.shaded[rt];
+
+        blendSrc[0] = pColorSample[0];
+        blendSrc[1] = pColorSample[2];
+        blendSrc[2] = pColorSample[4];
+        blendSrc[3] = pColorSample[6];
+
+        // Blend outputs and update coverage mask for alpha test
+        if (pfnBlendFunc[rt] != nullptr)
+        {
+            pfnBlendFunc[rt](
+                pBlendState,
+                psContext.shaded[rt],
+                psContext.shaded[1],
+                sample,
+                reinterpret_cast<uint8_t *>(&blendSrc),
+                blendOut,
+                &psContext.oMask,
+                reinterpret_cast<simdscalari *>(&coverageMask));
+        }
+
+        // final write mask 
+        simdscalari outputMask = _simd_castps_si(_simd_and_ps(coverageMask, depthPassMask));
+
+        ///@todo can only use maskstore fast path if bpc is 32. Assuming hot tile is RGBA32_FLOAT.
+        static_assert(KNOB_COLOR_HOT_TILE_FORMAT == R32G32B32A32_FLOAT, "Unsupported hot tile format");
+
+        // store with color mask
+        if (!pRTBlend->writeDisableRed)
+        {
+            _simd_maskstore_ps(reinterpret_cast<float *>(&pColorSample[0]), outputMask, blendOut.x);
+        }
+        if (!pRTBlend->writeDisableGreen)
+        {
+            _simd_maskstore_ps(reinterpret_cast<float *>(&pColorSample[2]), outputMask, blendOut.y);
+        }
+        if (!pRTBlend->writeDisableBlue)
+        {
+            _simd_maskstore_ps(reinterpret_cast<float *>(&pColorSample[4]), outputMask, blendOut.z);
+        }
+        if (!pRTBlend->writeDisableAlpha)
+        {
+            _simd_maskstore_ps(reinterpret_cast<float *>(&pColorSample[6]), outputMask, blendOut.w);
+        }
+    }
+}
+
+#endif
 template<uint32_t sampleCountT = SWR_MULTISAMPLE_1X, uint32_t samplePattern = SWR_MSAA_STANDARD_PATTERN,
          uint32_t coverage = 0, uint32_t centroid = 0, uint32_t forced = 0, uint32_t canEarlyZ = 0>
 struct SwrBackendTraits
index 344758eefe52ef092a3b029ba3ddbac8981eb904..63df2ab29108e594c71fd51ea92669fe370b77bd 100644 (file)
@@ -194,3 +194,173 @@ INLINE void StoreSOA(const simdvector &src, uint8_t *pDst)
 
     UnrollerL<0, FormatTraits<DstFormat>::numComps, 1>::step(lambda);
 }
+
+#if ENABLE_AVX512_SIMD16
+//////////////////////////////////////////////////////////////////////////
+/// @brief Load SIMD packed pixels in SOA format and converts to
+///        SOA RGBA32_FLOAT format.
+/// @param pSrc - source data in SOA form
+/// @param dst - output data in SOA form
+template<SWR_FORMAT SrcFormat>
+INLINE void LoadSOA(const uint8_t *pSrc, simd16vector &dst)
+{
+    // fast path for float32
+    if ((FormatTraits<SrcFormat>::GetType(0) == SWR_TYPE_FLOAT) && (FormatTraits<SrcFormat>::GetBPC(0) == 32))
+    {
+        auto lambda = [&](int comp)
+        {
+            simd16scalar vComp = _simd16_load_ps(reinterpret_cast<const float *>(pSrc + comp * sizeof(simd16scalar)));
+
+            dst.v[FormatTraits<SrcFormat>::swizzle(comp)] = vComp;
+        };
+
+        UnrollerL<0, FormatTraits<SrcFormat>::numComps, 1>::step(lambda);
+        return;
+    }
+
+    auto lambda = [&](int comp)
+    {
+        // load SIMD components
+        simd16scalar vComp = FormatTraits<SrcFormat>::loadSOA_16(comp, pSrc);
+
+        // unpack
+        vComp = FormatTraits<SrcFormat>::unpack(comp, vComp);
+
+        // convert
+        if (FormatTraits<SrcFormat>::isNormalized(comp))
+        {
+            vComp = _simd16_cvtepi32_ps(_simd16_castps_si(vComp));
+            vComp = _simd16_mul_ps(vComp, _simd16_set1_ps(FormatTraits<SrcFormat>::toFloat(comp)));
+        }
+
+        dst.v[FormatTraits<SrcFormat>::swizzle(comp)] = vComp;
+
+        pSrc += (FormatTraits<SrcFormat>::GetBPC(comp) * KNOB_SIMD16_WIDTH) / 8;
+    };
+
+    UnrollerL<0, FormatTraits<SrcFormat>::numComps, 1>::step(lambda);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief Clamps the given component based on the requirements on the 
+///        Format template arg
+/// @param vComp - SIMD vector of floats
+/// @param Component - component
+template<SWR_FORMAT Format>
+INLINE simd16scalar Clamp(simd16scalar vComp, uint32_t Component)
+{
+    if (FormatTraits<Format>::isNormalized(Component))
+    {
+        if (FormatTraits<Format>::GetType(Component) == SWR_TYPE_UNORM)
+        {
+            vComp = _simd16_max_ps(vComp, _simd16_setzero_ps());
+        }
+
+        if (FormatTraits<Format>::GetType(Component) == SWR_TYPE_SNORM)
+        {
+            vComp = _simd16_max_ps(vComp, _simd16_set1_ps(-1.0f));
+        }
+        vComp = _simd16_min_ps(vComp, _simd16_set1_ps(1.0f));
+    }
+    else if (FormatTraits<Format>::GetBPC(Component) < 32)
+    {
+        if (FormatTraits<Format>::GetType(Component) == SWR_TYPE_UINT)
+        {
+            int iMax = (1 << FormatTraits<Format>::GetBPC(Component)) - 1;
+            int iMin = 0;
+            simd16scalari vCompi = _simd16_castps_si(vComp);
+            vCompi = _simd16_max_epu32(vCompi, _simd16_set1_epi32(iMin));
+            vCompi = _simd16_min_epu32(vCompi, _simd16_set1_epi32(iMax));
+            vComp = _simd16_castsi_ps(vCompi);
+        }
+        else if (FormatTraits<Format>::GetType(Component) == SWR_TYPE_SINT)
+        {
+            int iMax = (1 << (FormatTraits<Format>::GetBPC(Component) - 1)) - 1;
+            int iMin = -1 - iMax;
+            simd16scalari vCompi = _simd16_castps_si(vComp);
+            vCompi = _simd16_max_epi32(vCompi, _simd16_set1_epi32(iMin));
+            vCompi = _simd16_min_epi32(vCompi, _simd16_set1_epi32(iMax));
+            vComp = _simd16_castsi_ps(vCompi);
+        }
+    }
+
+    return vComp;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief Normalize the given component based on the requirements on the
+///        Format template arg
+/// @param vComp - SIMD vector of floats
+/// @param Component - component
+template<SWR_FORMAT Format>
+INLINE simd16scalar Normalize(simd16scalar vComp, uint32_t Component)
+{
+    if (FormatTraits<Format>::isNormalized(Component))
+    {
+        vComp = _simd16_mul_ps(vComp, _simd16_set1_ps(FormatTraits<Format>::fromFloat(Component)));
+        vComp = _simd16_castsi_ps(_simd16_cvtps_epi32(vComp));
+    }
+    return vComp;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief Convert and store simdvector of pixels in SOA
+///        RGBA32_FLOAT to SOA format
+/// @param src - source data in SOA form
+/// @param dst - output data in SOA form
+template<SWR_FORMAT DstFormat>
+INLINE void StoreSOA(const simd16vector &src, uint8_t *pDst)
+{
+    // fast path for float32
+    if ((FormatTraits<DstFormat>::GetType(0) == SWR_TYPE_FLOAT) && (FormatTraits<DstFormat>::GetBPC(0) == 32))
+    {
+        for (uint32_t comp = 0; comp < FormatTraits<DstFormat>::numComps; ++comp)
+        {
+            simd16scalar vComp = src.v[FormatTraits<DstFormat>::swizzle(comp)];
+
+            // Gamma-correct
+            if (FormatTraits<DstFormat>::isSRGB)
+            {
+                if (comp < 3)  // Input format is always RGBA32_FLOAT.
+                {
+                    vComp = FormatTraits<R32G32B32A32_FLOAT>::convertSrgb(comp, vComp);
+                }
+            }
+
+            _simd16_store_ps(reinterpret_cast<float *>(pDst + comp * sizeof(simd16scalar)), vComp);
+        }
+        return;
+    }
+
+    auto lambda = [&](int comp)
+    {
+        simd16scalar vComp = src.v[FormatTraits<DstFormat>::swizzle(comp)];
+
+        // Gamma-correct
+        if (FormatTraits<DstFormat>::isSRGB)
+        {
+            if (comp < 3)  // Input format is always RGBA32_FLOAT.
+            {
+                vComp = FormatTraits<R32G32B32A32_FLOAT>::convertSrgb(comp, vComp);
+            }
+        }
+
+        // clamp
+        vComp = Clamp<DstFormat>(vComp, comp);
+
+        // normalize
+        vComp = Normalize<DstFormat>(vComp, comp);
+
+        // pack
+        vComp = FormatTraits<DstFormat>::pack(comp, vComp);
+
+        // store
+        FormatTraits<DstFormat>::storeSOA(comp, pDst, vComp);
+
+        pDst += (FormatTraits<DstFormat>::GetBPC(comp) * KNOB_SIMD16_WIDTH) / 8;
+    };
+
+    UnrollerL<0, FormatTraits<DstFormat>::numComps, 1>::step(lambda);
+}
+
+#endif
index 5deed2e8f2061d28f95be6589967c0ee20f9cf7d..fcb137d52df7c6048e2f5999d8fa3d9228c36b0f 100644 (file)
@@ -40,6 +40,12 @@ struct PackTraits
     static void storeSOA(uint8_t *pDst, simdscalar src) = delete;
     static simdscalar unpack(simdscalar &in) = delete;
     static simdscalar pack(simdscalar &in) = delete;
+#if ENABLE_AVX512_SIMD16
+    static simd16scalar loadSOA_16(const uint8_t *pSrc) = delete;
+    static void storeSOA(uint8_t *pDst, simd16scalar src) = delete;
+    static simd16scalar unpack(simd16scalar &in) = delete;
+    static simd16scalar pack(simd16scalar &in) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -54,9 +60,14 @@ struct PackTraits<0, false>
     static void storeSOA(uint8_t *pDst, simdscalar src) { return; }
     static simdscalar unpack(simdscalar &in) { return _simd_setzero_ps(); }
     static simdscalar pack(simdscalar &in) { return _simd_setzero_ps(); }
+#if ENABLE_AVX512_SIMD16
+    static simd16scalar loadSOA_16(const uint8_t *pSrc) { return _simd16_setzero_ps(); }
+    static void storeSOA(uint8_t *pDst, simd16scalar src) { return; }
+    static simd16scalar unpack(simd16scalar &in) { return _simd16_setzero_ps(); }
+    static simd16scalar pack(simd16scalar &in) { return _simd16_setzero_ps(); }
+#endif
 };
 
-
 //////////////////////////////////////////////////////////////////////////
 /// PackTraits - Helpers for packing / unpacking 8 bit unsigned channels
 //////////////////////////////////////////////////////////////////////////
@@ -123,7 +134,7 @@ struct PackTraits<8, false>
 
         result.lo = _mm256_cvtepu8_epi32(src);
 
-        result.hi = _mm256_cvtepu8_epi32(_mm_bsrli_si128(src, 8));
+        result.hi = _mm256_cvtepu8_epi32(_mm_srli_si128(src, 8));
 
         return _simd_castsi_ps(result);
 #endif
@@ -157,6 +168,55 @@ struct PackTraits<8, false>
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar loadSOA_16(const uint8_t *pSrc)
+    {
+        simd16scalar result = _simd16_setzero_ps();
+        simdscalar resultlo = _simd_setzero_ps();
+
+        const __m128 src = _mm_load_ps(reinterpret_cast<const float *>(pSrc));
+
+        resultlo = _mm256_insertf128_ps(resultlo, src, 0);
+        result = _simd16_insert_ps(result, resultlo, 0);
+
+        return result;
+    }
+
+    static void storeSOA(uint8_t *pDst, simd16scalar src)
+    {
+        // store simd16 bytes
+        _mm_store_ps(reinterpret_cast<float *>(pDst), _mm256_castps256_ps128(_simd16_extract_ps(src, 0)));
+    }
+
+    static simd16scalar unpack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        __m128i src = _mm_castps_si128(_mm256_castps256_ps128(_simd16_extract_ps(in, 0)));
+
+        result = _simd16_insert_si(result, _simd_cvtepu8_epi32(src), 0);
+        result = _simd16_insert_si(result, _simd_cvtepu8_epi32(_mm_srli_si128(src, 8)), 1);
+
+        return _simd16_castsi_ps(result);
+    }
+
+    static simd16scalar pack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+        simdscalari resultlo = _simd_setzero_si();
+
+        __m128i templo = _mm_packus_epi32(_mm256_castsi256_si128(_mm256_castps_si256(_simd16_extract_ps(in, 0))), _mm256_extractf128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 1));
+        __m128i temphi = _mm_packus_epi32(_mm256_castsi256_si128(_mm256_castps_si256(_simd16_extract_ps(in, 1))), _mm256_extractf128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 1)), 1));
+
+        __m128i temp = _mm_packus_epi16(templo, temphi);
+
+        resultlo = _mm256_inserti128_si256(resultlo, temp, 0);
+        result = _simd16_insert_si(result, resultlo, 0);
+
+        return _simd16_castsi_ps(result);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -226,7 +286,7 @@ struct PackTraits<8, true>
 
         result.lo = _mm256_cvtepu8_epi32(src);
 
-        result.hi = _mm256_cvtepu8_epi32(_mm_bsrli_si128(src, 8));
+        result.hi = _mm256_cvtepu8_epi32(_mm_srli_si128(src, 8));
 
         return _simd_castsi_ps(result);
 #endif
@@ -260,6 +320,55 @@ struct PackTraits<8, true>
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar loadSOA_16(const uint8_t *pSrc)
+    {
+        simd16scalar result = _simd16_setzero_ps();
+        simdscalar resultlo = _simd_setzero_ps();
+
+        const __m128 src = _mm_load_ps(reinterpret_cast<const float *>(pSrc));
+
+        resultlo = _mm256_insertf128_ps(resultlo, src, 0);
+        result = _simd16_insert_ps(result, resultlo, 0);
+
+        return result;
+    }
+
+    static void storeSOA(uint8_t *pDst, simd16scalar src)
+    {
+        // store simd16 bytes
+        _mm_store_ps(reinterpret_cast<float *>(pDst), _mm256_castps256_ps128(_simd16_extract_ps(src, 0)));
+    }
+
+    static simd16scalar unpack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        __m128i src = _mm_castps_si128(_mm256_castps256_ps128(_simd16_extract_ps(in, 0)));
+
+        result = _simd16_insert_si(result, _simd_cvtepu8_epi32(src), 0);
+        result = _simd16_insert_si(result, _simd_cvtepu8_epi32(_mm_srli_si128(src, 8)), 1);
+
+        return _simd16_castsi_ps(result);
+    }
+
+    static simd16scalar pack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+        simdscalari resultlo = _simd_setzero_si();
+
+        __m128i templo = _mm_packs_epi32(_mm256_castsi256_si128(_mm256_castps_si256(_simd16_extract_ps(in, 0))), _mm256_extractf128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 1));
+        __m128i temphi = _mm_packs_epi32(_mm256_castsi256_si128(_mm256_castps_si256(_simd16_extract_ps(in, 1))), _mm256_extractf128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 1)), 1));
+
+        __m128i temp = _mm_packs_epi16(templo, temphi);
+
+        resultlo = _mm256_inserti128_si256(resultlo, temp, 0);
+        result = _simd16_insert_si(result, resultlo, 0);
+
+        return _simd16_castsi_ps(result);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -360,6 +469,49 @@ struct PackTraits<16, false>
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar loadSOA_16(const uint8_t *pSrc)
+    {
+        simd16scalar result = _simd16_setzero_ps();
+
+        simdscalar resultlo = _simd_load_ps(reinterpret_cast<const float *>(pSrc));
+
+        result = _simd16_insert_ps(result, resultlo, 0);
+
+        return result;
+    }
+
+    static void storeSOA(uint8_t *pDst, simd16scalar src)
+    {
+        _simd_store_ps(reinterpret_cast<float *>(pDst), _simd16_extract_ps(src, 0));
+    }
+
+    static simd16scalar unpack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        result = _simd16_insert_si(result, _simd_cvtepu16_epi32(_mm256_extracti128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 0)), 0);
+        result = _simd16_insert_si(result, _simd_cvtepu16_epi32(_mm256_extracti128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 1)), 1);
+
+        return _simd16_castsi_ps(result);
+    }
+
+    static simd16scalar pack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        simdscalari inlo = _simd_castps_si(_simd16_extract_ps(in, 0));
+        simdscalari inhi = _simd_castps_si(_simd16_extract_ps(in, 1));
+
+        simdscalari templo = _simd_permute2f128_si(inlo, inhi, 0x20);
+        simdscalari temphi = _simd_permute2f128_si(inlo, inhi, 0x31);
+
+        result = _simd16_insert_si(result, _simd_packus_epi32(templo, temphi), 0);
+
+        return _simd16_castsi_ps(result);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -461,6 +613,49 @@ struct PackTraits<16, true>
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar loadSOA_16(const uint8_t *pSrc)
+    {
+        simd16scalar result = _simd16_setzero_ps();
+
+        simdscalar resultlo = _simd_load_ps(reinterpret_cast<const float *>(pSrc));
+
+        result = _simd16_insert_ps(result, resultlo, 0);
+
+        return result;
+    }
+
+    static void storeSOA(uint8_t *pDst, simd16scalar src)
+    {
+        _simd_store_ps(reinterpret_cast<float *>(pDst), _simd16_extract_ps(src, 0));
+    }
+
+    static simd16scalar unpack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        result = _simd16_insert_si(result, _simd_cvtepu16_epi32(_mm256_extracti128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 0)), 0);
+        result = _simd16_insert_si(result, _simd_cvtepu16_epi32(_mm256_extracti128_si256(_mm256_castps_si256(_simd16_extract_ps(in, 0)), 1)), 1);
+
+        return _simd16_castsi_ps(result);
+    }
+
+    static simd16scalar pack(simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        simdscalari inlo = _simd_castps_si(_simd16_extract_ps(in, 0));
+        simdscalari inhi = _simd_castps_si(_simd16_extract_ps(in, 1));
+
+        simdscalari templo = _simd_permute2f128_si(inlo, inhi, 0x20);
+        simdscalari temphi = _simd_permute2f128_si(inlo, inhi, 0x31);
+
+        result = _simd16_insert_si(result, _simd_packus_epi32(templo, temphi), 0);
+
+        return _simd16_castsi_ps(result);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -475,6 +670,28 @@ struct PackTraits<32, false>
     static void storeSOA(uint8_t *pDst, simdscalar src) { _simd_store_ps((float*)pDst, src); }
     static simdscalar unpack(simdscalar &in) { return in; }
     static simdscalar pack(simdscalar &in) { return in; }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar loadSOA_16(const uint8_t *pSrc)
+    {
+        return _simd16_load_ps(reinterpret_cast<const float *>(pSrc));
+    }
+
+    static void storeSOA(uint8_t *pDst, simd16scalar src)
+    {
+        _simd16_store_ps(reinterpret_cast<float *>(pDst), src);
+    }
+
+    static simd16scalar unpack(simd16scalar &in)
+    {
+        return in;
+    }
+
+    static simd16scalar pack(simd16scalar &in)
+    {
+        return in;
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -689,10 +906,10 @@ inline static __m128 powf_wrapper(__m128 Base, float Exp)
 {
     float *f = (float *)(&Base);
 
-    return _mm_set_ps(powf(f[0], Exp),
-                      powf(f[1], Exp),
+    return _mm_set_ps(powf(f[3], Exp),
                       powf(f[2], Exp),
-                      powf(f[3], Exp));
+                      powf(f[1], Exp),
+                      powf(f[0], Exp));
 }
 
 static inline __m128 ConvertFloatToSRGB2(__m128& Src)
@@ -756,6 +973,115 @@ static inline __m128 ConvertFloatToSRGB2(__m128& Src)
     return Result;
 }
 
+#if ENABLE_AVX512_SIMD16
+template< unsigned expnum, unsigned expden, unsigned coeffnum, unsigned coeffden >
+inline static simd16scalar fastpow(simd16scalar value)
+{
+    static const float factor1 = exp2(127.0f * expden / expnum - 127.0f)
+        * powf(1.0f * coeffnum / coeffden, 1.0f * expden / expnum);
+
+    // Apply a constant pre-correction factor.
+    simd16scalar result = _simd16_mul_ps(value, _simd16_set1_ps(factor1));
+
+    // Reinterpret arg as integer to obtain logarithm.
+    //asm("cvtdq2ps %1, %0" : "=x" (result) : "x" (result));
+    result = _simd16_cvtepi32_ps(_simd16_castps_si(result));
+
+    // Multiply logarithm by power.
+    result = _simd16_mul_ps(result, _simd16_set1_ps(1.0f * expnum / expden));
+
+    // Convert back to "integer" to exponentiate.
+    //asm("cvtps2dq %1, %0" : "=x" (result) : "x" (result));
+    result = _simd16_castsi_ps(_simd16_cvtps_epi32(result));
+
+    return result;
+}
+
+inline static simd16scalar pow512_4(simd16scalar arg)
+{
+    // 5/12 is too small, so compute the 4th root of 20/12 instead.
+    // 20/12 = 5/3 = 1 + 2/3 = 2 - 1/3. 2/3 is a suitable argument for fastpow.
+    // weighting coefficient: a^-1/2 = 2 a; a = 2^-2/3
+    simd16scalar xf = fastpow< 2, 3, int(0.629960524947437 * 1e9), int(1e9) >(arg);
+    simd16scalar xover = _simd16_mul_ps(arg, xf);
+
+    simd16scalar xfm1 = _simd16_rsqrt_ps(xf);
+    simd16scalar x2 = _simd16_mul_ps(arg, arg);
+    simd16scalar xunder = _simd16_mul_ps(x2, xfm1);
+
+    // sqrt2 * over + 2 * sqrt2 * under
+    simd16scalar xavg = _simd16_mul_ps(_simd16_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f), _simd16_add_ps(xover, xunder));
+
+    xavg = _simd16_mul_ps(xavg, _simd16_rsqrt_ps(xavg));
+    xavg = _simd16_mul_ps(xavg, _simd16_rsqrt_ps(xavg));
+
+    return xavg;
+}
+
+inline static simd16scalar powf_wrapper(const simd16scalar base, float exp)
+{
+    const float *f = reinterpret_cast<const float *>(&base);
+
+    return _simd16_set_ps(
+        powf(f[15], exp),
+        powf(f[14], exp),
+        powf(f[13], exp),
+        powf(f[12], exp),
+        powf(f[11], exp),
+        powf(f[10], exp),
+        powf(f[ 9], exp),
+        powf(f[ 8], exp),
+        powf(f[ 7], exp),
+        powf(f[ 6], exp),
+        powf(f[ 5], exp),
+        powf(f[ 4], exp),
+        powf(f[ 3], exp),
+        powf(f[ 2], exp),
+        powf(f[ 1], exp),
+        powf(f[ 0], exp)
+    );
+}
+
+// float to SRGB conversion formula
+//
+// if (value < 0.0031308f)
+//     value *= 12.92f;
+// else
+//     value = 1.055f * pow(value, 1.0f / 2.4f) - 0.055f;
+//
+static inline simd16scalar ConvertFloatToSRGB2(const simd16scalar &value)
+{
+    // create a mask where the source is < the minimal SRGB float value
+    const simd16mask mask = _simd16_cmplt_ps_mask(value, _simd16_set1_ps(0.0031308f));
+
+    // if all elements are < the threshold, result = value * 12.92
+    simd16scalar result = _simd16_mul_ps(value, _simd16_set1_ps(12.92f));
+
+    if (_simd16_mask2int(mask) != 0xFFFF)
+    {
+        // some elements are >= threshold, result = 1.055 * power(value, 1.0 / 2.4) - 0.055
+#if KNOB_USE_FAST_SRGB == TRUE
+        // 1.0f / 2.4f is 5.0f / 12.0f which is used for approximation.
+        simd16scalar result2 = pow512_4(value);
+#else
+        simd16scalar result2 = powf_wrapper(value, 1.0f / 2.4f);
+#endif
+
+        result2 = _simd16_mul_ps(result2, _simd16_set1_ps(1.055f));
+        result2 = _simd16_sub_ps(result2, _simd16_set1_ps(0.055f));
+
+#if (KNOB_ARCH == KNOB_ARCH_AVX512)
+        // only native AVX512 can directly use the computed mask for the blend operation
+        result = _mm512_mask_blend_ps(mask, result2, result);
+#else
+        result = _simd16_blendv_ps(result2, result, _simd16_cmplt_ps(value, _simd16_set1_ps(0.0031308f)));
+#endif
+    }
+
+    return result;
+}
+
+#endif
 //////////////////////////////////////////////////////////////////////////
 /// TypeTraits - Format type traits specialization for FLOAT16
 //////////////////////////////////////////////////////////////////////////
@@ -892,6 +1218,40 @@ simdscalari result;
         SWR_ASSERT(0); // @todo
         return _simd_setzero_ps();
     }
+#if ENABLE_AVX512_SIMD16
+
+    static simd16scalar pack(const simd16scalar &in)
+    {
+        simd16scalari result = _simd16_setzero_si();
+        simdscalari resultlo = _simd_setzero_si();
+
+#if (KNOB_ARCH == KNOB_ARCH_AVX)
+        simdscalar simdlo = pack(_simd16_extract_ps(in, 0));
+        simdscalar simdhi = pack(_simd16_extract_ps(in, 1));
+
+        __m128i templo = _mm256_extractf128_si256(_simd_castps_si(simdlo), 0);
+        __m128i temphi = _mm256_extractf128_si256(_simd_castps_si(simdhi), 0);
+
+#else
+        __m128i templo = _mm256_cvtps_ph(_simd16_extract_ps(in, 0), _MM_FROUND_TRUNC);
+        __m128i temphi = _mm256_cvtps_ph(_simd16_extract_ps(in, 1), _MM_FROUND_TRUNC);
+
+#endif
+        resultlo = _mm256_insertf128_si256(resultlo, templo, 0);
+        resultlo = _mm256_insertf128_si256(resultlo, temphi, 1);
+
+        result = _simd16_insert_si(result, resultlo, 0);
+
+        return _simd16_castsi_ps(result);
+    }
+
+    static simd16scalar unpack(const simd16scalar &in)
+    {
+        // input is 16 packed float16, output is 16 packed float32
+        SWR_ASSERT(0); // @todo
+        return _simd16_setzero_ps();
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -937,6 +1297,13 @@ template<> struct TypeTraits<SWR_TYPE_FLOAT, 32> : PackTraits<32>
 #endif
         return in;
     }
+#if ENABLE_AVX512_SIMD16
+
+    static inline simd16scalar convertSrgb(simd16scalar &in)
+    {
+        return ConvertFloatToSRGB2(in);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -1265,4 +1632,95 @@ struct ComponentTraits
         SWR_ASSERT(0);
         return TypeTraits<X, NumBitsX>::convertSrgb(in);
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static simd16scalar loadSOA_16(uint32_t comp, const uint8_t* pSrc)
+    {
+        switch (comp)
+        {
+        case 0:
+            return TypeTraits<X, NumBitsX>::loadSOA_16(pSrc);
+        case 1:
+            return TypeTraits<Y, NumBitsY>::loadSOA_16(pSrc);
+        case 2:
+            return TypeTraits<Z, NumBitsZ>::loadSOA_16(pSrc);
+        case 3:
+            return TypeTraits<W, NumBitsW>::loadSOA_16(pSrc);
+        }
+        SWR_ASSERT(0);
+        return TypeTraits<X, NumBitsX>::loadSOA_16(pSrc);
+    }
+
+    INLINE static void storeSOA(uint32_t comp, uint8_t *pDst, simd16scalar src)
+    {
+        switch (comp)
+        {
+        case 0:
+            TypeTraits<X, NumBitsX>::storeSOA(pDst, src);
+            return;
+        case 1:
+            TypeTraits<Y, NumBitsY>::storeSOA(pDst, src);
+            return;
+        case 2:
+            TypeTraits<Z, NumBitsZ>::storeSOA(pDst, src);
+            return;
+        case 3:
+            TypeTraits<W, NumBitsW>::storeSOA(pDst, src);
+            return;
+        }
+        SWR_ASSERT(0);
+        TypeTraits<X, NumBitsX>::storeSOA(pDst, src);
+    }
+
+    INLINE static simd16scalar unpack(uint32_t comp, simd16scalar &in)
+    {
+        switch (comp)
+        {
+        case 0:
+            return TypeTraits<X, NumBitsX>::unpack(in);
+        case 1:
+            return TypeTraits<Y, NumBitsY>::unpack(in);
+        case 2:
+            return TypeTraits<Z, NumBitsZ>::unpack(in);
+        case 3:
+            return TypeTraits<W, NumBitsW>::unpack(in);
+        }
+        SWR_ASSERT(0);
+        return TypeTraits<X, NumBitsX>::unpack(in);
+    }
+
+    INLINE static simd16scalar pack(uint32_t comp, simd16scalar &in)
+    {
+        switch (comp)
+        {
+        case 0:
+            return TypeTraits<X, NumBitsX>::pack(in);
+        case 1:
+            return TypeTraits<Y, NumBitsY>::pack(in);
+        case 2:
+            return TypeTraits<Z, NumBitsZ>::pack(in);
+        case 3:
+            return TypeTraits<W, NumBitsW>::pack(in);
+        }
+        SWR_ASSERT(0);
+        return TypeTraits<X, NumBitsX>::pack(in);
+    }
+
+    INLINE static simd16scalar convertSrgb(uint32_t comp, simd16scalar &in)
+    {
+        switch (comp)
+        {
+        case 0:
+            return TypeTraits<X, NumBitsX>::convertSrgb(in);
+        case 1:
+            return TypeTraits<Y, NumBitsY>::convertSrgb(in);
+        case 2:
+            return TypeTraits<Z, NumBitsZ>::convertSrgb(in);
+        case 3:
+            return TypeTraits<W, NumBitsW>::convertSrgb(in);
+        }
+        SWR_ASSERT(0);
+        return TypeTraits<X, NumBitsX>::convertSrgb(in);
+    }
+#endif
 };
index c01ad67f7c40ab0b21564730c758e6b44d576f31..b1085268247a30e008b852f122a28f68746d7105 100644 (file)
@@ -39,6 +39,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #define ENABLE_AVX512_SIMD16    0
+#define USE_8x2_TILE_BACKEND    0
 
 ///////////////////////////////////////////////////////////////////////////////
 // Architecture validation
 #endif
 
 #if ENABLE_AVX512_SIMD16
-#if KNOB_SIMD16_WIDTH==16 && KNOB_TILE_X_DIM < 4
+#if KNOB_SIMD16_WIDTH == 16 && KNOB_TILE_X_DIM < 8
 #error "incompatible width/tile dimensions"
 #endif
 #endif
 
 #if ENABLE_AVX512_SIMD16
 #if KNOB_SIMD16_WIDTH == 16
-#define SIMD16_TILE_X_DIM 4
-#define SIMD16_TILE_Y_DIM 4
+#define SIMD16_TILE_X_DIM 8
+#define SIMD16_TILE_Y_DIM 2
 #else
 #error "Invalid simd width"
 #endif
index bd189abb1a8a82ec650dcd3f8f190f41f49551c1..804fc4f26999beb7f2f042334418c610ba701960 100644 (file)
@@ -196,6 +196,88 @@ HOTTILE* HotTileMgr::GetHotTileNoLoad(
     return &hotTile;
 }
 
+#if USE_8x2_TILE_BACKEND
+void HotTileMgr::ClearColorHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
+{
+    // Load clear color into SIMD register...
+    float *pClearData = (float *)(pHotTile->clearData);
+    simd16scalar valR = _simd16_broadcast_ss(&pClearData[0]);
+    simd16scalar valG = _simd16_broadcast_ss(&pClearData[1]);
+    simd16scalar valB = _simd16_broadcast_ss(&pClearData[2]);
+    simd16scalar valA = _simd16_broadcast_ss(&pClearData[3]);
+
+    float *pfBuf = (float *)pHotTile->pBuffer;
+    uint32_t numSamples = pHotTile->numSamples;
+
+    for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
+    {
+        for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
+        {
+            for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM)
+            {
+                _simd16_store_ps(pfBuf, valR);
+                pfBuf += KNOB_SIMD16_WIDTH;
+
+                _simd16_store_ps(pfBuf, valG);
+                pfBuf += KNOB_SIMD16_WIDTH;
+
+                _simd16_store_ps(pfBuf, valB);
+                pfBuf += KNOB_SIMD16_WIDTH;
+
+                _simd16_store_ps(pfBuf, valA);
+                pfBuf += KNOB_SIMD16_WIDTH;
+            }
+        }
+    }
+}
+
+void HotTileMgr::ClearDepthHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
+{
+    // Load clear color into SIMD register...
+    float *pClearData = (float *)(pHotTile->clearData);
+    simd16scalar valZ = _simd16_broadcast_ss(&pClearData[0]);
+
+    float *pfBuf = (float *)pHotTile->pBuffer;
+    uint32_t numSamples = pHotTile->numSamples;
+
+    for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
+    {
+        for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
+        {
+            for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM)
+            {
+                _simd16_store_ps(pfBuf, valZ);
+                pfBuf += KNOB_SIMD16_WIDTH;
+            }
+        }
+    }
+}
+
+void HotTileMgr::ClearStencilHotTile(const HOTTILE* pHotTile)
+{
+    // convert from F32 to U8.
+    uint8_t clearVal = (uint8_t)(pHotTile->clearData[0]);
+    //broadcast 32x into __m256i...
+    simd16scalari valS = _simd16_set1_epi8(clearVal);
+
+    simd16scalari *pBuf = (simd16scalari *)pHotTile->pBuffer;
+    uint32_t numSamples = pHotTile->numSamples;
+
+    for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
+    {
+        for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
+        {
+            // We're putting 4 pixels in each of the 32-bit slots, so increment 4 times as quickly.
+            for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM * 4)
+            {
+                _simd16_store_si(pBuf, valS);
+                pBuf += 1;
+            }
+        }
+    }
+}
+
+#else
 void HotTileMgr::ClearColorHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
 {
     // Load clear color into SIMD register...
@@ -273,6 +355,7 @@ void HotTileMgr::ClearStencilHotTile(const HOTTILE* pHotTile)
     }
 }
 
+#endif
 //////////////////////////////////////////////////////////////////////////
 /// @brief InitializeHotTiles
 /// for draw calls, we initialize the active hot tiles and perform deferred
index 96f061a78aff562301595e472cb87b04424d47d7..dd4fa3e74c024f488dbdc1866661a3a4fe345d90 100644 (file)
@@ -245,6 +245,13 @@ struct TransposeSingleComponent
     {
         memcpy(pDst, pSrc, (bpp * KNOB_SIMD_WIDTH) / 8);
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        memcpy(pDst, pSrc, (bpp * KNOB_SIMD16_WIDTH) / 8);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -299,6 +306,27 @@ struct Transpose8_8_8_8
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalari src = _simd16_load_si(reinterpret_cast<const simd16scalari *>(pSrc));
+
+        simd16scalari mask0 = _simd16_set_epi32(0x0f078080, 0x0e068080, 0x0d058080, 0x0c048080, 0x80800b03, 0x80800a02, 0x80800901, 0x80800800);
+
+        simd16scalari dst01 = _simd16_shuffle_epi8(src, mask0);
+
+        simd16scalari perm1 = _simd16_permute2f128_si(src, src, 1);
+
+        simd16scalari mask1 = _simd16_set_epi32(0x80800f07, 0x80800e06, 0x80800d05, 0x80800c04, 0x0b038080, 0x0a028080, 0x09018080, 0x08008080);
+
+        simd16scalari dst23 = _simd16_shuffle_epi8(perm1, mask1);
+
+        simd16scalari dst = _simd16_or_si(dst01, dst23);
+
+        _simd16_store_si(reinterpret_cast<simd16scalari *>(pDst), dst);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -311,6 +339,10 @@ struct Transpose8_8_8
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     INLINE static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -345,6 +377,21 @@ struct Transpose8_8
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        __m256i src = _mm256_load_si256(reinterpret_cast<const __m256i *>(pSrc));   // rrrrrrrrrrrrrrrrgggggggggggggggg
+
+        __m256i r = _mm256_permute4x64_epi64(src, 0x50);    // 0x50 = 01010000b     // rrrrrrrrxxxxxxxxrrrrrrrrxxxxxxxx
+
+        __m256i g = _mm256_permute4x64_epi64(src, 0xFA);    // 0xFA = 11111010b     // ggggggggxxxxxxxxggggggggxxxxxxxx
+
+        __m256i dst = _mm256_unpacklo_epi8(r, g);                                   // rgrgrgrgrgrgrgrgrgrgrgrgrgrgrgrg
+
+        _mm256_store_si256(reinterpret_cast<__m256i *>(pDst), dst);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -409,6 +456,50 @@ struct Transpose32_32_32_32
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalar src0 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc));
+        simd16scalar src1 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc) + 16);
+        simd16scalar src2 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc) + 32);
+        simd16scalar src3 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc) + 48);
+
+        __m128 vDst[8];
+
+        vTranspose4x8(vDst, _simd16_extract_ps(src0, 0), _simd16_extract_ps(src1, 0), _simd16_extract_ps(src2, 0), _simd16_extract_ps(src3, 0));
+
+#if 1
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) +  0, reinterpret_cast<simd16scalar *>(vDst)[0]);
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 16, reinterpret_cast<simd16scalar *>(vDst)[1]);
+#else
+        _mm_store_ps(reinterpret_cast<float *>(pDst), vDst[0]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 4, vDst[1]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 8, vDst[2]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 12, vDst[3]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 16, vDst[4]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 20, vDst[5]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 24, vDst[6]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 28, vDst[7]);
+#endif
+
+        vTranspose4x8(vDst, _simd16_extract_ps(src0, 1), _simd16_extract_ps(src1, 1), _simd16_extract_ps(src2, 1), _simd16_extract_ps(src3, 1));
+
+#if 1
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 32, reinterpret_cast<simd16scalar *>(vDst)[2]);
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 48, reinterpret_cast<simd16scalar *>(vDst)[3]);
+#else
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 32, vDst[0]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 36, vDst[1]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 40, vDst[2]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 44, vDst[3]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 48, vDst[4]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 52, vDst[5]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 56, vDst[6]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 60, vDst[7]);
+#endif
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -471,6 +562,49 @@ struct Transpose32_32_32
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalar src0 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc));
+        simd16scalar src1 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc) + 16);
+        simd16scalar src2 = _simd16_load_ps(reinterpret_cast<const float *>(pSrc) + 32);
+
+        __m128 vDst[8];
+
+        vTranspose3x8(vDst, _simd16_extract_ps(src0, 0), _simd16_extract_ps(src1, 0), _simd16_extract_ps(src2, 0));
+
+#if 1
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) +  0, reinterpret_cast<simd16scalar *>(vDst)[0]);
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 16, reinterpret_cast<simd16scalar *>(vDst)[1]);
+#else
+        _mm_store_ps(reinterpret_cast<float *>(pDst), vDst[0]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 4, vDst[1]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 8, vDst[2]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 12, vDst[3]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 16, vDst[4]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 20, vDst[5]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 24, vDst[6]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 28, vDst[7]);
+#endif
+
+        vTranspose3x8(vDst, _simd16_extract_ps(src0, 1), _simd16_extract_ps(src1, 1), _simd16_extract_ps(src2, 1));
+
+#if 1
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 32, reinterpret_cast<simd16scalar *>(vDst)[2]);
+        _simd16_store_ps(reinterpret_cast<float *>(pDst) + 48, reinterpret_cast<simd16scalar *>(vDst)[3]);
+#else
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 32, vDst[0]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 36, vDst[1]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 40, vDst[2]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 44, vDst[3]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 48, vDst[4]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 52, vDst[5]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 56, vDst[6]);
+        _mm_store_ps(reinterpret_cast<float *>(pDst) + 60, vDst[7]);
+#endif
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -522,6 +656,30 @@ struct Transpose32_32
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        const float *pfSrc = reinterpret_cast<const float *>(pSrc);
+
+        __m256 src_r0 = _mm256_load_ps(pfSrc +  0);
+        __m256 src_r1 = _mm256_load_ps(pfSrc +  8);
+        __m256 src_g0 = _mm256_load_ps(pfSrc + 16);
+        __m256 src_g1 = _mm256_load_ps(pfSrc + 24);
+
+        __m256 dst0 = _mm256_unpacklo_ps(src_r0, src_g0);
+        __m256 dst1 = _mm256_unpackhi_ps(src_r0, src_g0);
+        __m256 dst2 = _mm256_unpacklo_ps(src_r1, src_g1);
+        __m256 dst3 = _mm256_unpackhi_ps(src_r1, src_g1);
+
+        float *pfDst = reinterpret_cast<float *>(pDst);
+
+        _mm256_store_ps(pfDst +  0, dst0);
+        _mm256_store_ps(pfDst +  8, dst1);
+        _mm256_store_ps(pfDst + 16, dst2);
+        _mm256_store_ps(pfDst + 24, dst3);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -587,6 +745,34 @@ struct Transpose16_16_16_16
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalari src_rg = _simd16_load_si(reinterpret_cast<const simd16scalari *>(pSrc));
+        simd16scalari src_ba = _simd16_load_si(reinterpret_cast<const simd16scalari *>(pSrc + sizeof(simd16scalari)));
+
+        __m256i src_r = _simd16_extract_si(src_rg, 0);
+        __m256i src_g = _simd16_extract_si(src_rg, 1);
+        __m256i src_b = _simd16_extract_si(src_ba, 0);
+        __m256i src_a = _simd16_extract_si(src_ba, 1);
+
+        __m256i rg0 = _mm256_unpacklo_epi16(src_r, src_g);
+        __m256i rg1 = _mm256_unpackhi_epi16(src_r, src_g);
+        __m256i ba0 = _mm256_unpacklo_epi16(src_b, src_a);
+        __m256i ba1 = _mm256_unpackhi_epi16(src_b, src_a);
+
+        __m256i dst0 = _mm256_unpacklo_epi32(rg0, ba0);
+        __m256i dst1 = _mm256_unpackhi_epi32(rg0, ba0);
+        __m256i dst2 = _mm256_unpacklo_epi32(rg1, ba1);
+        __m256i dst3 = _mm256_unpackhi_epi32(rg1, ba1);
+
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 0, dst0);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 1, dst1);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 2, dst2);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 3, dst3);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -650,6 +836,33 @@ struct Transpose16_16_16
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalari src_rg = _simd16_load_si(reinterpret_cast<const simd16scalari *>(pSrc));
+
+        __m256i src_r = _simd16_extract_si(src_rg, 0);
+        __m256i src_g = _simd16_extract_si(src_rg, 1);
+        __m256i src_b = _mm256_load_si256(reinterpret_cast<const __m256i *>(pSrc + sizeof(simd16scalari)));
+        __m256i src_a = _mm256_undefined_si256();
+
+        __m256i rg0 = _mm256_unpacklo_epi16(src_r, src_g);
+        __m256i rg1 = _mm256_unpackhi_epi16(src_r, src_g);
+        __m256i ba0 = _mm256_unpacklo_epi16(src_b, src_a);
+        __m256i ba1 = _mm256_unpackhi_epi16(src_b, src_a);
+
+        __m256i dst0 = _mm256_unpacklo_epi32(rg0, ba0);
+        __m256i dst1 = _mm256_unpackhi_epi32(rg0, ba0);
+        __m256i dst2 = _mm256_unpacklo_epi32(rg1, ba1);
+        __m256i dst3 = _mm256_unpackhi_epi32(rg1, ba1);
+
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 0, dst0);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 1, dst1);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 2, dst2);
+        _mm256_store_si256(reinterpret_cast<__m256i*>(pDst) + 3, dst3);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -692,6 +905,23 @@ struct Transpose16_16
 #error Unsupported vector width
 #endif
     }
+#if ENABLE_AVX512_SIMD16
+
+    INLINE static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst)
+    {
+        simd16scalari result = _simd16_setzero_si();
+
+        simd16scalari src = _simd16_castps_si(_simd16_load_ps(reinterpret_cast<const float *>(pSrc)));
+
+        simdscalari srclo = _simd16_extract_si(src, 0);
+        simdscalari srchi = _simd16_extract_si(src, 1);
+
+        result = _simd16_insert_si(result, _mm256_unpacklo_epi16(srclo, srchi), 0);
+        result = _simd16_insert_si(result, _mm256_unpackhi_epi16(srclo, srchi), 1);
+
+        _simd16_store_si(reinterpret_cast<simd16scalari *>(pDst), result);
+    }
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -704,6 +934,10 @@ struct Transpose24_8
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -716,9 +950,11 @@ struct Transpose32_8_24
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
-};
-
+#if ENABLE_AVX512_SIMD16
 
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
+};
 
 //////////////////////////////////////////////////////////////////////////
 /// Transpose4_4_4_4
@@ -730,6 +966,10 @@ struct Transpose4_4_4_4
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -742,6 +982,10 @@ struct Transpose5_6_5
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -754,6 +998,10 @@ struct Transpose9_9_9_5
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -766,6 +1014,10 @@ struct Transpose5_5_5_1
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -790,6 +1042,10 @@ struct Transpose10_10_10_2
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -802,6 +1058,10 @@ struct Transpose11_11_10
     /// @param pSrc - source data in SOA form
     /// @param pDst - output data in AOS form
     static void Transpose(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#if ENABLE_AVX512_SIMD16
+
+    static void Transpose_16(const uint8_t* pSrc, uint8_t* pDst) = delete;
+#endif
 };
 
 // helper function to unroll loops
index a0ac3fec07e5a2dd29858b53fec1533737ba40fd..858f16266e967837fe93a55098dd77f47ea904db 100644 (file)
@@ -67,6 +67,21 @@ struct LoadRasterTile
         uint32_t x, uint32_t y,
         uint8_t* pDst)
     {
+#if USE_8x2_TILE_BACKEND
+        typedef SimdTile_16<DstFormat, SrcFormat> SimdT;
+
+        SimdT* pDstSimdTiles = (SimdT*)pDst;
+
+        // Compute which simd tile we're accessing within 8x8 tile.
+        //   i.e. Compute linear simd tile coordinate given (x, y) in pixel coordinates.
+        uint32_t simdIndex = (y / SIMD16_TILE_Y_DIM) * (KNOB_TILE_X_DIM / SIMD16_TILE_X_DIM) + (x / SIMD16_TILE_X_DIM);
+
+        SimdT* pSimdTile = &pDstSimdTiles[simdIndex];
+
+        uint32_t simdOffset = (y % SIMD16_TILE_Y_DIM) * SIMD16_TILE_X_DIM + (x % SIMD16_TILE_X_DIM);
+
+        pSimdTile->SetSwizzledColor(simdOffset, srcColor);
+#else
         typedef SimdTile<DstFormat, SrcFormat> SimdT;
 
         SimdT* pDstSimdTiles = (SimdT*)pDst;
@@ -80,6 +95,7 @@ struct LoadRasterTile
         uint32_t simdOffset = (y % SIMD_TILE_Y_DIM) * SIMD_TILE_X_DIM + (x % SIMD_TILE_X_DIM);
 
         pSimdTile->SetSwizzledColor(simdOffset, srcColor);
+#endif
     }
 
     //////////////////////////////////////////////////////////////////////////
index 95a1adbc8db09c4b6eff94330e5178e177f71497..21ee443841ce863119c5e6ff1560be4dbe900f99 100644 (file)
@@ -158,6 +158,25 @@ struct StorePixels<32, 2>
     }
 };
 
+#if USE_8x2_TILE_BACKEND
+template <>
+struct StorePixels<32, 4>
+{
+    static void Store(const uint8_t* pSrc, uint8_t* (&ppDsts)[4])
+    {
+        __m128i quad0 = _mm_load_si128(&reinterpret_cast<const __m128i *>(pSrc)[0]);
+        __m128i quad1 = _mm_load_si128(&reinterpret_cast<const __m128i *>(pSrc)[1]);
+        __m128i quad2 = _mm_load_si128(&reinterpret_cast<const __m128i *>(pSrc)[2]);
+        __m128i quad3 = _mm_load_si128(&reinterpret_cast<const __m128i *>(pSrc)[3]);
+
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(ppDsts[0]), _mm_unpacklo_epi64(quad0, quad1));
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(ppDsts[1]), _mm_unpackhi_epi64(quad0, quad1));
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(ppDsts[2]), _mm_unpacklo_epi64(quad2, quad3));
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(ppDsts[3]), _mm_unpackhi_epi64(quad2, quad3));
+    }
+};
+
+#endif
 //////////////////////////////////////////////////////////////////////////
 /// StorePixels (32-bit pixel specialization)
 /// @brief Stores a 4x2 (AVX) raster-tile to two rows.
@@ -228,6 +247,21 @@ struct ConvertPixelsSOAtoAOS
     template <size_t NumDests>
     INLINE static void Convert(const uint8_t* pSrc, uint8_t* (&ppDsts)[NumDests])
     {
+#if USE_8x2_TILE_BACKEND
+        static const uint32_t MAX_RASTER_TILE_BYTES = 16 * 16; // 16 pixels * 16 bytes per pixel
+
+        OSALIGNSIMD16(uint8_t) soaTile[MAX_RASTER_TILE_BYTES];
+        OSALIGNSIMD16(uint8_t) aosTile[MAX_RASTER_TILE_BYTES];
+
+        // Convert from SrcFormat --> DstFormat
+        simd16vector src;
+        LoadSOA<SrcFormat>(pSrc, src);
+        StoreSOA<DstFormat>(src, soaTile);
+
+        // Convert from SOA --> AOS
+        FormatTraits<DstFormat>::TransposeT::Transpose_16(soaTile, aosTile);
+
+#else
         static const uint32_t MAX_RASTER_TILE_BYTES = 128; // 8 pixels * 16 bytes per pixel
 
         OSALIGNSIMD(uint8_t) soaTile[MAX_RASTER_TILE_BYTES];
@@ -241,6 +275,7 @@ struct ConvertPixelsSOAtoAOS
         // Convert from SOA --> AOS
         FormatTraits<DstFormat>::TransposeT::Transpose(soaTile, aosTile);
 
+#endif
         // Store data into destination
         StorePixels<FormatTraits<DstFormat>::bpp, NumDests>::Store(aosTile, ppDsts);
     }
@@ -261,6 +296,15 @@ struct ConvertPixelsSOAtoAOS<Format, Format>
     template <size_t NumDests>
     INLINE static void Convert(const uint8_t* pSrc, uint8_t* (&ppDsts)[NumDests])
     {
+#if USE_8x2_TILE_BACKEND
+        static const uint32_t MAX_RASTER_TILE_BYTES = 16 * 16; // 16 pixels * 16 bytes per pixel
+
+        OSALIGNSIMD16(uint8_t) aosTile[MAX_RASTER_TILE_BYTES];
+
+        // Convert from SOA --> AOS
+        FormatTraits<Format>::TransposeT::Transpose_16(pSrc, aosTile);
+
+#else
         static const uint32_t MAX_RASTER_TILE_BYTES = 128; // 8 pixels * 16 bytes per pixel
 
         OSALIGNSIMD(uint8_t) aosTile[MAX_RASTER_TILE_BYTES];
@@ -268,6 +312,7 @@ struct ConvertPixelsSOAtoAOS<Format, Format>
         // Convert from SOA --> AOS
         FormatTraits<Format>::TransposeT::Transpose(pSrc, aosTile);
 
+#endif
         // Store data into destination
         StorePixels<FormatTraits<Format>::bpp, NumDests>::Store(aosTile, ppDsts);
     }
@@ -348,6 +393,73 @@ struct ConvertPixelsSOAtoAOS<R32_FLOAT, R24_UNORM_X8_TYPELESS>
     template <size_t NumDests>
     INLINE static void Convert(const uint8_t* pSrc, uint8_t* (&ppDsts)[NumDests])
     {
+#if USE_8x2_TILE_BACKEND
+        static const uint32_t MAX_RASTER_TILE_BYTES = 16 * 4; // 16 pixels * 4 bytes per pixel
+
+        OSALIGNSIMD16(uint8_t) soaTile[MAX_RASTER_TILE_BYTES];
+        OSALIGNSIMD16(uint8_t) aosTile[MAX_RASTER_TILE_BYTES];
+
+        // Convert from SrcFormat --> DstFormat
+        simd16vector src;
+        LoadSOA<SrcFormat>(pSrc, src);
+        StoreSOA<DstFormat>(src, soaTile);
+
+        // Convert from SOA --> AOS
+        FormatTraits<DstFormat>::TransposeT::Transpose_16(soaTile, aosTile);
+
+        // Store data into destination but don't overwrite the X8 bits
+        // Each 4-pixel row is 16-bytes
+#if 1
+        simdscalari loadlo = _simd_load_si(reinterpret_cast<simdscalari *>(aosTile));
+        simdscalari loadhi = _simd_load_si(reinterpret_cast<simdscalari *>(aosTile + sizeof(simdscalari)));
+
+        simdscalari templo = _simd_unpacklo_epi64(loadlo, loadhi);
+        simdscalari temphi = _simd_unpackhi_epi64(loadlo, loadhi);
+
+        simdscalari destlo = _mm256_loadu2_m128i(reinterpret_cast<__m128i *>(ppDsts[1]), reinterpret_cast<__m128i *>(ppDsts[0]));
+        simdscalari desthi = _mm256_loadu2_m128i(reinterpret_cast<__m128i *>(ppDsts[3]), reinterpret_cast<__m128i *>(ppDsts[2]));
+
+        simdscalari mask = _simd_set1_epi32(0xFFFFFF);
+
+        destlo = _simd_or_si(_simd_andnot_si(mask, destlo), _simd_and_si(mask, templo));
+        desthi = _simd_or_si(_simd_andnot_si(mask, desthi), _simd_and_si(mask, templo));
+
+        _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(ppDsts[1]), reinterpret_cast<__m128i *>(ppDsts[0]), destlo);
+        _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(ppDsts[3]), reinterpret_cast<__m128i *>(ppDsts[2]), desthi);
+#else
+        __m128i *pZRow01 = (__m128i*)aosTile;
+        __m128i vQuad00 = _mm_load_si128(pZRow01);
+        __m128i vQuad01 = _mm_load_si128(pZRow01 + 1);
+        __m128i vQuad02 = _mm_load_si128(pZRow01 + 2);
+        __m128i vQuad03 = _mm_load_si128(pZRow01 + 3);
+
+        __m128i vRow00 = _mm_unpacklo_epi64(vQuad00, vQuad01);
+        __m128i vRow10 = _mm_unpackhi_epi64(vQuad00, vQuad01);
+        __m128i vRow20 = _mm_unpacklo_epi64(vQuad02, vQuad03);
+        __m128i vRow30 = _mm_unpackhi_epi64(vQuad02, vQuad03);
+
+        __m128i vDst0 = _mm_loadu_si128((const __m128i*)ppDsts[0]);
+        __m128i vDst1 = _mm_loadu_si128((const __m128i*)ppDsts[1]);
+        __m128i vDst2 = _mm_loadu_si128((const __m128i*)ppDsts[2]);
+        __m128i vDst3 = _mm_loadu_si128((const __m128i*)ppDsts[3]);
+
+        __m128i vMask = _mm_set1_epi32(0xFFFFFF);
+
+        vDst0 = _mm_andnot_si128(vMask, vDst0);
+        vDst0 = _mm_or_si128(vDst0, _mm_and_si128(vRow00, vMask));
+        vDst1 = _mm_andnot_si128(vMask, vDst1);
+        vDst1 = _mm_or_si128(vDst1, _mm_and_si128(vRow10, vMask));
+        vDst2 = _mm_andnot_si128(vMask, vDst2);
+        vDst2 = _mm_or_si128(vDst2, _mm_and_si128(vRow20, vMask));
+        vDst3 = _mm_andnot_si128(vMask, vDst3);
+        vDst3 = _mm_or_si128(vDst3, _mm_and_si128(vRow10, vMask));
+
+        _mm_storeu_si128((__m128i*)ppDsts[0], vDst0);
+        _mm_storeu_si128((__m128i*)ppDsts[1], vDst1);
+        _mm_storeu_si128((__m128i*)ppDsts[2], vDst2);
+        _mm_storeu_si128((__m128i*)ppDsts[3], vDst3);
+#endif
+#else
         static const uint32_t MAX_RASTER_TILE_BYTES = 128; // 8 pixels * 16 bytes per pixel
 
         OSALIGNSIMD(uint8_t) soaTile[MAX_RASTER_TILE_BYTES];
@@ -382,9 +494,138 @@ struct ConvertPixelsSOAtoAOS<R32_FLOAT, R24_UNORM_X8_TYPELESS>
 
         _mm_storeu_si128((__m128i*)ppDsts[0], vDst0);
         _mm_storeu_si128((__m128i*)ppDsts[1], vDst1);
+#endif
     }
 };
 
+#if USE_8x2_TILE_BACKEND
+template<SWR_FORMAT DstFormat>
+INLINE static void FlatConvert(const uint8_t* pSrc, uint8_t* pDst0, uint8_t* pDst1, uint8_t* pDst2, uint8_t* pDst3)
+{
+    // swizzle rgba -> bgra while we load
+    simd16scalar comp0 = _simd16_load_ps(reinterpret_cast<const float*>(pSrc + FormatTraits<DstFormat>::swizzle(0) * sizeof(simd16scalar))); // float32 rrrrrrrrrrrrrrrr
+    simd16scalar comp1 = _simd16_load_ps(reinterpret_cast<const float*>(pSrc + FormatTraits<DstFormat>::swizzle(1) * sizeof(simd16scalar))); // float32 gggggggggggggggg
+    simd16scalar comp2 = _simd16_load_ps(reinterpret_cast<const float*>(pSrc + FormatTraits<DstFormat>::swizzle(2) * sizeof(simd16scalar))); // float32 bbbbbbbbbbbbbbbb
+    simd16scalar comp3 = _simd16_load_ps(reinterpret_cast<const float*>(pSrc + FormatTraits<DstFormat>::swizzle(3) * sizeof(simd16scalar))); // float32 aaaaaaaaaaaaaaaa
+
+                                                                                                                                             // clamp
+    const simd16scalar zero = _simd16_setzero_ps();
+    const simd16scalar ones = _simd16_set1_ps(1.0f);
+
+    comp0 = _simd16_max_ps(comp0, zero);
+    comp0 = _simd16_min_ps(comp0, ones);
+
+    comp1 = _simd16_max_ps(comp1, zero);
+    comp1 = _simd16_min_ps(comp1, ones);
+
+    comp2 = _simd16_max_ps(comp2, zero);
+    comp2 = _simd16_min_ps(comp2, ones);
+
+    comp3 = _simd16_max_ps(comp3, zero);
+    comp3 = _simd16_min_ps(comp3, ones);
+
+    if (FormatTraits<DstFormat>::isSRGB)
+    {
+        // Gamma-correct only rgb
+        comp0 = FormatTraits<R32G32B32A32_FLOAT>::convertSrgb(0, comp0);
+        comp1 = FormatTraits<R32G32B32A32_FLOAT>::convertSrgb(1, comp1);
+        comp2 = FormatTraits<R32G32B32A32_FLOAT>::convertSrgb(2, comp2);
+    }
+
+    // convert float components from 0.0f .. 1.0f to correct scale for 0 .. 255 dest format
+    comp0 = _simd16_mul_ps(comp0, _simd16_set1_ps(FormatTraits<DstFormat>::fromFloat(0)));
+    comp1 = _simd16_mul_ps(comp1, _simd16_set1_ps(FormatTraits<DstFormat>::fromFloat(1)));
+    comp2 = _simd16_mul_ps(comp2, _simd16_set1_ps(FormatTraits<DstFormat>::fromFloat(2)));
+    comp3 = _simd16_mul_ps(comp3, _simd16_set1_ps(FormatTraits<DstFormat>::fromFloat(3)));
+
+    // moving to 16 wide integer vector types
+    simd16scalari src0 = _simd16_cvtps_epi32(comp0); // padded byte rrrrrrrrrrrrrrrr
+    simd16scalari src1 = _simd16_cvtps_epi32(comp1); // padded byte gggggggggggggggg
+    simd16scalari src2 = _simd16_cvtps_epi32(comp2); // padded byte bbbbbbbbbbbbbbbb
+    simd16scalari src3 = _simd16_cvtps_epi32(comp3); // padded byte aaaaaaaaaaaaaaaa
+
+#if 1
+                                                     // SOA to AOS conversion
+    src1 = _simd16_slli_epi32(src1, 8);
+    src2 = _simd16_slli_epi32(src2, 16);
+    src3 = _simd16_slli_epi32(src3, 24);
+
+    simd16scalari final = _simd16_or_si(_simd16_or_si(src0, src1), _simd16_or_si(src2, src3));  // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+
+                                                                                                // de-swizzle conversion
+#if 1
+    simd16scalari final0 = _simd16_permute2f128_si(final, final, 0xA0); // (2, 2, 0, 0)         // 0 1 2 3 0 1 2 3 8 9 A B 8 9 A B
+    simd16scalari final1 = _simd16_permute2f128_si(final, final, 0xF5); // (3, 3, 1, 1)         // 4 5 6 7 4 5 6 7 C D E F C D E F
+
+    final = _simd16_shuffle_epi64(final0, final1, 0xCC); // (1 1 0 0 1 1 0 0)                   // 0 1 4 5 2 3 6 7 8 9 C D A B E F
+
+#else
+    final = _simd16_permute_epi32(final, _simd16_set_epi32(15, 14, 11, 10, 13, 12, 9, 8, 7, 6, 3, 2, 5, 4, 1, 0));
+
+#endif
+#endif
+#if KNOB_ARCH == KNOB_ARCH_AVX
+
+    // splitting into two sets of 4 wide integer vector types
+    // because AVX doesn't have instructions to support this operation at 8 wide
+#if 0
+    __m128i srcLo0 = _mm256_castsi256_si128(src0); // 000r000r000r000r
+    __m128i srcLo1 = _mm256_castsi256_si128(src1); // 000g000g000g000g
+    __m128i srcLo2 = _mm256_castsi256_si128(src2); // 000b000b000b000b
+    __m128i srcLo3 = _mm256_castsi256_si128(src3); // 000a000a000a000a
+
+    __m128i srcHi0 = _mm256_extractf128_si256(src0, 1); // 000r000r000r000r
+    __m128i srcHi1 = _mm256_extractf128_si256(src1, 1); // 000g000g000g000g
+    __m128i srcHi2 = _mm256_extractf128_si256(src2, 1); // 000b000b000b000b
+    __m128i srcHi3 = _mm256_extractf128_si256(src3, 1); // 000a000a000a000a
+
+    srcLo1 = _mm_slli_si128(srcLo1, 1); // 00g000g000g000g0
+    srcHi1 = _mm_slli_si128(srcHi1, 1); // 00g000g000g000g0
+    srcLo2 = _mm_slli_si128(srcLo2, 2); // 0b000b000b000b00
+    srcHi2 = _mm_slli_si128(srcHi2, 2); // 0b000b000b000b00
+    srcLo3 = _mm_slli_si128(srcLo3, 3); // a000a000a000a000
+    srcHi3 = _mm_slli_si128(srcHi3, 3); // a000a000a000a000
+
+    srcLo0 = _mm_or_si128(srcLo0, srcLo1); // 00gr00gr00gr00gr
+    srcLo2 = _mm_or_si128(srcLo2, srcLo3); // ab00ab00ab00ab00
+
+    srcHi0 = _mm_or_si128(srcHi0, srcHi1); // 00gr00gr00gr00gr
+    srcHi2 = _mm_or_si128(srcHi2, srcHi3); // ab00ab00ab00ab00
+
+    srcLo0 = _mm_or_si128(srcLo0, srcLo2); // abgrabgrabgrabgr
+    srcHi0 = _mm_or_si128(srcHi0, srcHi2); // abgrabgrabgrabgr
+
+                                           // unpack into rows that get the tiling order correct
+    __m128i vRow00 = _mm_unpacklo_epi64(srcLo0, srcHi0);  // abgrabgrabgrabgrabgrabgrabgrabgr
+    __m128i vRow10 = _mm_unpackhi_epi64(srcLo0, srcHi0);
+
+    __m256i final = _mm256_castsi128_si256(vRow00);
+    final = _mm256_insertf128_si256(final, vRow10, 1);
+
+#else
+#if 0
+    simd16scalari final = _simd16_setzero_si();
+
+#endif
+#endif
+#elif KNOB_ARCH >= KNOB_ARCH_AVX2
+    // logic is as above, only wider
+#if 0
+    src1 = _simd16_slli_epi32(src1, 8);
+    src2 = _simd16_slli_epi32(src2, 16);
+    src3 = _simd16_slli_epi32(src3, 24);
+
+    simd16scalari final = _simd16_or_si(_simd16_or_si(src0, src1), _simd16_or_si(src2, src3));
+
+    final = _simd16_permute_epi32(final, _simd16_set_epi32(15, 14, 11, 10, 13, 12, 9, 8, 7, 6, 3, 2, 5, 4, 1, 0));
+
+#endif
+#endif
+    _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(pDst1), reinterpret_cast<__m128i *>(pDst0), _simd16_extract_si(final, 0));
+    _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(pDst3), reinterpret_cast<__m128i *>(pDst2), _simd16_extract_si(final, 1));
+}
+
+#endif
 template<SWR_FORMAT DstFormat>
 INLINE static void FlatConvert(const uint8_t* pSrc, uint8_t* pDst, uint8_t* pDst1)
 {
@@ -477,10 +718,16 @@ INLINE static void FlatConvert(const uint8_t* pSrc, uint8_t* pDst, uint8_t* pDst
     src2 = _mm256_or_si256(src2, src3);
 
     __m256i final = _mm256_or_si256(src0, src2);
-        
+#if 0
+
+    __m256i perm = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0);
+
+    final = _mm256_permutevar8x32_epi32(final, perm);
+#else
+
     // adjust the data to get the tiling order correct 0 1 2 3 -> 0 2 1 3
     final = _mm256_permute4x64_epi64(final, 0xD8);
-
+#endif
 #endif
 
     _mm256_storeu2_m128i((__m128i*)pDst1, (__m128i*)pDst, final);
@@ -618,7 +865,11 @@ struct ConvertPixelsSOAtoAOS < R32G32B32A32_FLOAT, R8G8B8A8_UNORM >
     template <size_t NumDests>
     INLINE static void Convert(const uint8_t* pSrc, uint8_t* (&ppDsts)[NumDests])
     {
+#if USE_8x2_TILE_BACKEND
+        FlatConvert<R8G8B8A8_UNORM>(pSrc, ppDsts[0], ppDsts[1], ppDsts[2], ppDsts[3]);
+#else
         FlatConvert<R8G8B8A8_UNORM>(pSrc, ppDsts[0], ppDsts[1]);
+#endif
     }
 };
 
@@ -638,7 +889,11 @@ struct ConvertPixelsSOAtoAOS < R32G32B32A32_FLOAT, R8G8B8A8_UNORM_SRGB >
     template <size_t NumDests>
     INLINE static void Convert(const uint8_t* pSrc, uint8_t* (&ppDsts)[NumDests])
     {
+#if USE_8x2_TILE_BACKEND
+        FlatConvert<R8G8B8A8_UNORM_SRGB>(pSrc, ppDsts[0], ppDsts[1], ppDsts[2], ppDsts[3]);
+#else
         FlatConvert<R8G8B8A8_UNORM_SRGB>(pSrc, ppDsts[0], ppDsts[1]);
+#endif
     }
 };
 
@@ -668,6 +923,21 @@ struct StoreRasterTile
         uint32_t x, uint32_t y,
         float outputColor[4])
     {
+#if USE_8x2_TILE_BACKEND
+        typedef SimdTile_16<SrcFormat, DstFormat> SimdT;
+
+        SimdT* pSrcSimdTiles = (SimdT*)pSrc;
+
+        // Compute which simd tile we're accessing within 8x8 tile.
+        //   i.e. Compute linear simd tile coordinate given (x, y) in pixel coordinates.
+        uint32_t simdIndex = (y / SIMD16_TILE_Y_DIM) * (KNOB_TILE_X_DIM / SIMD16_TILE_X_DIM) + (x / SIMD16_TILE_X_DIM);
+
+        SimdT* pSimdTile = &pSrcSimdTiles[simdIndex];
+
+        uint32_t simdOffset = (y % SIMD16_TILE_Y_DIM) * SIMD16_TILE_X_DIM + (x % SIMD16_TILE_X_DIM);
+
+        pSimdTile->GetSwizzledColor(simdOffset, outputColor);
+#else
         typedef SimdTile<SrcFormat, DstFormat> SimdT;
 
         SimdT* pSrcSimdTiles = (SimdT*)pSrc;
@@ -681,6 +951,7 @@ struct StoreRasterTile
         uint32_t simdOffset = (y % SIMD_TILE_Y_DIM) * SIMD_TILE_X_DIM + (x % SIMD_TILE_X_DIM);
 
         pSimdTile->GetSwizzledColor(simdOffset, outputColor);
+#endif
     }
 
     //////////////////////////////////////////////////////////////////////////
@@ -861,6 +1132,32 @@ struct OptStoreRasterTile< TilingTraits<SWR_TILE_NONE, 32>, SrcFormat, DstFormat
 
         uint8_t* pDst = (uint8_t*)ComputeSurfaceAddress<false, false>(x, y, pDstSurface->arrayIndex + renderTargetArrayIndex,
             pDstSurface->arrayIndex + renderTargetArrayIndex, sampleNum, pDstSurface->lod, pDstSurface);
+#if USE_8x2_TILE_BACKEND
+        uint8_t* ppRows[] = { pDst, pDst + pDstSurface->pitch, pDst + (SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL) / 2, pDst + pDstSurface->pitch + (SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL) / 2 };
+
+        for (uint32_t row = 0; row < KNOB_TILE_Y_DIM / SIMD16_TILE_Y_DIM; ++row)
+        {
+            uint8_t* ppStartRows[] = { ppRows[0], ppRows[1], ppRows[2], ppRows[3] };
+
+            for (uint32_t col = 0; col < KNOB_TILE_X_DIM / SIMD16_TILE_X_DIM; ++col)
+            {
+                // Format conversion and convert from SOA to AOS, and store the rows.
+                ConvertPixelsSOAtoAOS<SrcFormat, DstFormat>::Convert(pSrc, ppRows);
+
+                ppRows[0] += SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL;
+                ppRows[1] += SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL;
+                ppRows[2] += SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL;
+                ppRows[3] += SIMD16_TILE_X_DIM * DST_BYTES_PER_PIXEL;
+
+                pSrc += KNOB_SIMD16_WIDTH * SRC_BYTES_PER_PIXEL;
+            }
+
+            ppRows[0] = ppStartRows[0] + SIMD16_TILE_Y_DIM * pDstSurface->pitch;
+            ppRows[1] = ppStartRows[1] + SIMD16_TILE_Y_DIM * pDstSurface->pitch;
+            ppRows[2] = ppStartRows[2] + SIMD16_TILE_Y_DIM * pDstSurface->pitch;
+            ppRows[3] = ppStartRows[3] + SIMD16_TILE_Y_DIM * pDstSurface->pitch;
+        }
+#else
         uint8_t* ppRows[] = { pDst, pDst + pDstSurface->pitch };
 
         for (uint32_t row = 0; row < KNOB_TILE_Y_DIM / SIMD_TILE_Y_DIM; ++row)
@@ -880,6 +1177,7 @@ struct OptStoreRasterTile< TilingTraits<SWR_TILE_NONE, 32>, SrcFormat, DstFormat
             ppRows[0] = ppStartRows[0] + 2 * pDstSurface->pitch;
             ppRows[1] = ppStartRows[1] + 2 * pDstSurface->pitch;
         }
+#endif
     }
 };
 
@@ -1212,6 +1510,7 @@ template<SWR_FORMAT SrcFormat, SWR_FORMAT DstFormat>
 struct OptStoreRasterTile< TilingTraits<SWR_TILE_MODE_YMAJOR, 32>, SrcFormat, DstFormat>
 {
     typedef StoreRasterTile<TilingTraits<SWR_TILE_MODE_YMAJOR, 32>, SrcFormat, DstFormat> GenericStoreTile;
+    static const size_t SRC_BYTES_PER_PIXEL = FormatTraits<SrcFormat>::bpp / 8;
 
     //////////////////////////////////////////////////////////////////////////
     /// @brief Stores an 8x8 raster tile to the destination surface.
@@ -1241,6 +1540,19 @@ struct OptStoreRasterTile< TilingTraits<SWR_TILE_MODE_YMAJOR, 32>, SrcFormat, Ds
         uint8_t* pCol0 = (uint8_t*)ComputeSurfaceAddress<false, false>(x, y, pDstSurface->arrayIndex + renderTargetArrayIndex, 
             pDstSurface->arrayIndex + renderTargetArrayIndex, sampleNum, pDstSurface->lod, pDstSurface);
 
+#if USE_8x2_TILE_BACKEND
+        // The Hot Tile uses a row-major tiling mode and has a larger memory footprint. So we iterate in a row-major pattern.
+        for (uint32_t row = 0; row < KNOB_TILE_Y_DIM; row += SIMD16_TILE_Y_DIM)
+        {
+            uint8_t *pRow = pCol0 + row * DestRowWidthBytes;
+
+            uint8_t *ppDsts[] = { pRow, pRow + DestRowWidthBytes, pRow + DestColumnBytes, pRow + DestColumnBytes + DestRowWidthBytes };
+
+            ConvertPixelsSOAtoAOS<SrcFormat, DstFormat>::Convert(pSrc, ppDsts);
+
+            pSrc += KNOB_SIMD16_WIDTH * SRC_BYTES_PER_PIXEL;
+        }
+#else
         // Increment by a whole SIMD. 4x2 for AVX. 2x2 for SSE.
         uint32_t pSrcInc = (FormatTraits<SrcFormat>::bpp * KNOB_SIMD_WIDTH) / 8;
 
@@ -1261,6 +1573,7 @@ struct OptStoreRasterTile< TilingTraits<SWR_TILE_MODE_YMAJOR, 32>, SrcFormat, Ds
             ConvertPixelsSOAtoAOS<SrcFormat, DstFormat>::Convert(pSrc, ppDsts);
             pSrc += pSrcInc;
         }
+#endif
     }
 };
 
index 9b412f8b344cd9db8b23ea1b6099d7dcc06a74bb..0694a99808f6351ca106f58d4710e7ef060325a4 100644 (file)
@@ -153,6 +153,107 @@ struct SimdTile <R8_UINT,R8_UINT>
     }
 };
 
+#if ENABLE_AVX512_SIMD16
+//////////////////////////////////////////////////////////////////////////
+/// SimdTile 8x2 for AVX-512
+//////////////////////////////////////////////////////////////////////////
+
+template<SWR_FORMAT HotTileFormat, SWR_FORMAT SrcOrDstFormat>
+struct SimdTile_16
+{
+    // SimdTile is SOA (e.g. rrrrrrrrrrrrrrrr gggggggggggggggg bbbbbbbbbbbbbbbb aaaaaaaaaaaaaaaa )
+    float color[FormatTraits<HotTileFormat>::numComps][KNOB_SIMD16_WIDTH];
+
+    //////////////////////////////////////////////////////////////////////////
+    /// @brief Retrieve color from simd.
+    /// @param index - linear index to color within simd.
+    /// @param outputColor - output color
+    INLINE void GetSwizzledColor(
+        uint32_t index,
+        float outputColor[4])
+    {
+        // SOA pattern for 8x2..
+        //   0 1 4 5 8 9 C D
+        //   2 3 6 7 A B E F
+        // The offset converts pattern to linear
+        static const uint32_t offset[KNOB_SIMD16_WIDTH] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
+
+        for (uint32_t i = 0; i < FormatTraits<SrcOrDstFormat>::numComps; ++i)
+        {
+            outputColor[i] = this->color[FormatTraits<SrcOrDstFormat>::swizzle(i)][offset[index]];
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    /// @brief Retrieve color from simd.
+    /// @param index - linear index to color within simd.
+    /// @param outputColor - output color
+    INLINE void SetSwizzledColor(
+        uint32_t index,
+        const float src[4])
+    {
+        // SOA pattern for 8x2..
+        //   0 1 4 5 8 9 C D
+        //   2 3 6 7 A B E F
+        // The offset converts pattern to linear
+        static const uint32_t offset[KNOB_SIMD16_WIDTH] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
+
+        for (uint32_t i = 0; i < FormatTraits<SrcOrDstFormat>::numComps; ++i)
+        {
+            this->color[i][offset[index]] = src[i];
+        }
+    }
+};
+
+template<>
+struct SimdTile_16 <R8_UINT, R8_UINT>
+{
+    // SimdTile is SOA (e.g. rrrrrrrrrrrrrrrr gggggggggggggggg bbbbbbbbbbbbbbbb aaaaaaaaaaaaaaaa )
+    uint8_t color[FormatTraits<R8_UINT>::numComps][KNOB_SIMD16_WIDTH];
+
+    //////////////////////////////////////////////////////////////////////////
+    /// @brief Retrieve color from simd.
+    /// @param index - linear index to color within simd.
+    /// @param outputColor - output color
+    INLINE void GetSwizzledColor(
+        uint32_t index,
+        float outputColor[4])
+    {
+        // SOA pattern for 8x2..
+        //   0 1 4 5 8 9 C D
+        //   2 3 6 7 A B E F
+        // The offset converts pattern to linear
+        static const uint32_t offset[KNOB_SIMD16_WIDTH] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
+
+        for (uint32_t i = 0; i < FormatTraits<R8_UINT>::numComps; ++i)
+        {
+            uint32_t src = this->color[FormatTraits<R8_UINT>::swizzle(i)][offset[index]];
+            outputColor[i] = *(float*)&src;
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    /// @brief Retrieve color from simd.
+    /// @param index - linear index to color within simd.
+    /// @param outputColor - output color
+    INLINE void SetSwizzledColor(
+        uint32_t index,
+        const float src[4])
+    {
+        // SOA pattern for 8x2..
+        //   0 1 4 5 8 9 C D
+        //   2 3 6 7 A B E F
+        // The offset converts pattern to linear
+        static const uint32_t offset[KNOB_SIMD16_WIDTH] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
+
+        for (uint32_t i = 0; i < FormatTraits<R8_UINT>::numComps; ++i)
+        {
+            this->color[i][offset[index]] = *(uint8_t*)&src[i];
+        }
+    }
+};
+
+#endif
 //////////////////////////////////////////////////////////////////////////
 /// @brief Computes lod offset for 1D surface at specified lod.
 /// @param baseWidth - width of basemip (mip 0).