Home | History | Annotate | Download | only in core
      1 /****************************************************************************
      2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice (including the next
     12 * paragraph) shall be included in all copies or substantial portions of the
     13 * Software.
     14 *
     15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21 * IN THE SOFTWARE.
     22 *
     23 * @file multisample.h
     24 *
     25 ******************************************************************************/
     26 
     27 #pragma once
     28 
     29 #include "context.h"
     30 #include "format_traits.h"
     31 
     32 //////////////////////////////////////////////////////////////////////////
     33 /// @brief convenience typedef for testing for single sample case
     34 typedef std::integral_constant<int, 1> SingleSampleT;
     35 
     36 INLINE
     37 uint32_t GetNumSamples(SWR_MULTISAMPLE_COUNT sampleCount)
     38 {
     39     static const uint32_t sampleCountLUT[SWR_MULTISAMPLE_TYPE_COUNT] {1, 2, 4, 8, 16};
     40     assert(sampleCount < SWR_MULTISAMPLE_TYPE_COUNT);
     41     return sampleCountLUT[sampleCount];
     42 }
     43 
     44 INLINE
     45 SWR_MULTISAMPLE_COUNT GetSampleCount(uint32_t numSamples)
     46 {
     47     switch(numSamples)
     48     {
     49     case 1: return SWR_MULTISAMPLE_1X;
     50     case 2: return SWR_MULTISAMPLE_2X;
     51     case 4: return SWR_MULTISAMPLE_4X;
     52     case 8: return SWR_MULTISAMPLE_8X;
     53     case 16: return SWR_MULTISAMPLE_16X;
     54     default: assert(0); return SWR_MULTISAMPLE_1X;
     55     }
     56 }
     57 
     58 // hardcoded offsets based on Direct3d standard multisample positions
     59 // 8 x 8 pixel grid ranging from (0, 0) to (15, 15), with (0, 0) = UL pixel corner
     60 // coords are 0.8 fixed point offsets from (0, 0)
     61 template<SWR_MULTISAMPLE_COUNT sampleCount, SWR_MSAA_SAMPLE_PATTERN samplePattern = SWR_MSAA_STANDARD_PATTERN>
     62 struct MultisampleTraits
     63 {
     64     INLINE static __m128i vXi(uint32_t sampleNum) = delete;
     65     INLINE static __m128i vYi(uint32_t sampleNum) = delete;
     66     INLINE static simdscalar vX(uint32_t sampleNum) = delete;
     67     INLINE static simdscalar vY(uint32_t sampleNum) = delete;
     68     INLINE static float X(uint32_t sampleNum) = delete;
     69     INLINE static float Y(uint32_t sampleNum) = delete;
     70     INLINE static __m128i TileSampleOffsetsX() = delete;
     71     INLINE static __m128i TileSampleOffsetsY() = delete;
     72     INLINE static simdscalari FullSampleMask() = delete;
     73 
     74     static const uint32_t numSamples = 0;
     75 };
     76 
     77 template<>
     78 struct MultisampleTraits<SWR_MULTISAMPLE_1X, SWR_MSAA_STANDARD_PATTERN>
     79 {
     80     INLINE static __m128i vXi(uint32_t sampleNum)
     81     {
     82         static const __m128i X = _mm_set1_epi32(samplePosXi);
     83         return X;
     84     }
     85 
     86     INLINE static __m128i vYi(uint32_t sampleNum)
     87     {
     88         static const __m128i Y = _mm_set1_epi32(samplePosYi);
     89         return Y;
     90     }
     91 
     92     INLINE static simdscalar vX(uint32_t sampleNum)
     93     {
     94         static const simdscalar X = _simd_set1_ps(0.5f);
     95         return X;
     96     }
     97 
     98     INLINE static simdscalar vY(uint32_t sampleNum)
     99     {
    100         static const simdscalar Y = _simd_set1_ps(0.5f);
    101         return Y;
    102     }
    103 
    104     INLINE static float X(uint32_t sampleNum) {return samplePosX;};
    105     INLINE static float Y(uint32_t sampleNum) {return samplePosY;};
    106 
    107     INLINE static __m128i TileSampleOffsetsX()
    108     {
    109         static const uint32_t bboxLeftEdge = 0x80;
    110         static const uint32_t bboxRightEdge = 0x80;
    111                                                             // BR,            BL,           UR,            UL
    112         static const __m128i tileSampleOffsetX = _mm_set_epi32(bboxRightEdge, bboxLeftEdge, bboxRightEdge, bboxLeftEdge);
    113         return tileSampleOffsetX;
    114     }
    115 
    116     INLINE static __m128i TileSampleOffsetsY()
    117     {
    118         static const uint32_t bboxTopEdge = 0x80;
    119         static const uint32_t bboxBottomEdge = 0x80;
    120                                                             // BR,             BL,             UR,          UL
    121         static const __m128i tileSampleOffsetY = _mm_set_epi32(bboxBottomEdge, bboxBottomEdge, bboxTopEdge, bboxTopEdge);
    122         return tileSampleOffsetY;
    123     }
    124 
    125     INLINE static simdscalari FullSampleMask(){return _simd_set1_epi32(0x1);};
    126 
    127     static const uint32_t samplePosXi;
    128     static const uint32_t samplePosYi;
    129     static const float samplePosX;
    130     static const float samplePosY;
    131     static const uint32_t numSamples = 1;
    132     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_1X;
    133     static const uint32_t numCoverageSamples = 1;
    134 };
    135 
    136 template<>
    137 struct MultisampleTraits<SWR_MULTISAMPLE_1X, SWR_MSAA_CENTER_PATTERN>
    138 {
    139     INLINE static __m128i vXi(uint32_t sampleNum)
    140     {
    141         return _mm_set1_epi32(0x80);
    142     }
    143 
    144     INLINE static __m128i vYi(uint32_t sampleNum)
    145     {
    146         return _mm_set1_epi32(0x80);
    147     }
    148 
    149     INLINE static simdscalar vX(uint32_t sampleNum)
    150     {
    151         return _simd_set1_ps(0.5f);
    152     }
    153 
    154     INLINE static simdscalar vY(uint32_t sampleNum)
    155     {
    156         return _simd_set1_ps(0.5f);
    157     }
    158 
    159     INLINE static float X(uint32_t sampleNum) {return 0.5f;};
    160     INLINE static float Y(uint32_t sampleNum) {return 0.5f;};
    161 
    162     INLINE static __m128i TileSampleOffsetsX()
    163     {
    164         // BR,            BL,           UR,            UL
    165         return _mm_set1_epi32(0x80);
    166     }
    167 
    168     INLINE static __m128i TileSampleOffsetsY()
    169     {
    170         // BR,             BL,             UR,          UL
    171         return _mm_set1_epi32(0x80);
    172     }
    173 
    174     INLINE static simdscalari FullSampleMask(){return _simd_set1_epi32(0x1);};
    175 
    176     static const uint32_t numSamples = 1;
    177     static const float samplePosX;
    178     static const float samplePosY;
    179     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_1X;
    180     static const uint32_t numCoverageSamples = 1;
    181 };
    182 
    183 template<>
    184 struct MultisampleTraits<SWR_MULTISAMPLE_2X, SWR_MSAA_STANDARD_PATTERN>
    185 {
    186     INLINE static __m128i vXi(uint32_t sampleNum)
    187     {
    188         SWR_ASSERT(sampleNum < numSamples);
    189         static const __m128i X[numSamples] {_mm_set1_epi32(samplePosXi[0]), _mm_set1_epi32(samplePosXi[1])};
    190         return X[sampleNum];
    191     }
    192 
    193     INLINE static __m128i vYi(uint32_t sampleNum)
    194     {
    195         SWR_ASSERT(sampleNum < numSamples);
    196         static const __m128i Y[numSamples] {_mm_set1_epi32(samplePosYi[0]), _mm_set1_epi32(samplePosYi[1])};
    197         return Y[sampleNum];
    198     }
    199 
    200     INLINE static simdscalar vX(uint32_t sampleNum)
    201     {
    202         static const simdscalar X[numSamples] {_simd_set1_ps(0.75f), _simd_set1_ps(0.25f)};
    203         assert(sampleNum < numSamples);
    204         return X[sampleNum];
    205     }
    206 
    207     INLINE static simdscalar vY(uint32_t sampleNum)
    208     {
    209         static const simdscalar Y[numSamples] {_simd_set1_ps(0.75f), _simd_set1_ps(0.25f)};
    210         assert(sampleNum < numSamples);
    211         return Y[sampleNum];
    212     }
    213 
    214     INLINE static float X(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosX[sampleNum]; };
    215     INLINE static float Y(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosY[sampleNum]; };
    216 
    217     INLINE static __m128i TileSampleOffsetsX()
    218     {
    219         static const uint32_t bboxLeftEdge = 0x40;
    220         static const uint32_t bboxRightEdge = 0xC0;
    221                                                             // BR,            BL,           UR,            UL
    222         static const __m128i tileSampleOffsetX = _mm_set_epi32(bboxRightEdge, bboxLeftEdge, bboxRightEdge, bboxLeftEdge);
    223         return tileSampleOffsetX;
    224     }
    225 
    226     INLINE static __m128i TileSampleOffsetsY()
    227     {
    228         static const uint32_t bboxTopEdge = 0x40;
    229         static const uint32_t bboxBottomEdge = 0xC0;
    230                                                             // BR,             BL,             UR,          UL
    231         static const __m128i tileSampleOffsetY = _mm_set_epi32(bboxBottomEdge, bboxBottomEdge, bboxTopEdge, bboxTopEdge);
    232         return tileSampleOffsetY;
    233     }
    234 
    235     INLINE static simdscalari FullSampleMask()
    236     {
    237          static const simdscalari mask =_simd_set1_epi32(0x3);
    238          return mask;
    239     }
    240 
    241     static const uint32_t samplePosXi[2];
    242     static const uint32_t samplePosYi[2];
    243     static const float samplePosX[2];
    244     static const float samplePosY[2];
    245     static const uint32_t numSamples = 2;
    246     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_2X;
    247     static const uint32_t numCoverageSamples = 2;
    248 };
    249 
    250 template<>
    251 struct MultisampleTraits<SWR_MULTISAMPLE_2X, SWR_MSAA_CENTER_PATTERN>
    252 {
    253     INLINE static __m128i vXi(uint32_t sampleNum)
    254     {
    255         return _mm_set1_epi32(0x80);
    256     }
    257 
    258     INLINE static __m128i vYi(uint32_t sampleNum)
    259     {
    260         return _mm_set1_epi32(0x80);
    261     }
    262 
    263     INLINE static simdscalar vX(uint32_t sampleNum)
    264     {
    265         return _simd_set1_ps(0.5f);
    266     }
    267 
    268     INLINE static simdscalar vY(uint32_t sampleNum)
    269     {
    270         return _simd_set1_ps(0.5f);
    271     }
    272 
    273     INLINE static float X(uint32_t sampleNum) {return 0.5f;};
    274     INLINE static float Y(uint32_t sampleNum) {return 0.5f;};
    275 
    276     INLINE static __m128i TileSampleOffsetsX()
    277     {
    278         // BR,            BL,           UR,            UL
    279         return _mm_set1_epi32(0x80);
    280     }
    281 
    282     INLINE static __m128i TileSampleOffsetsY()
    283     {
    284         // BR,             BL,             UR,          UL
    285         return _mm_set1_epi32(0x80);
    286     }
    287 
    288     INLINE static simdscalari FullSampleMask()
    289     {
    290          static const simdscalari mask =_simd_set1_epi32(0x3);
    291          return mask;
    292     }
    293     static const uint32_t numSamples = 2;
    294     static const float samplePosX[2];
    295     static const float samplePosY[2];
    296     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_2X;
    297     static const uint32_t numCoverageSamples = 1;
    298 };
    299 
    300 template<>
    301 struct MultisampleTraits<SWR_MULTISAMPLE_4X, SWR_MSAA_STANDARD_PATTERN>
    302 {
    303     INLINE static __m128i vXi(uint32_t sampleNum)
    304     {
    305         static const __m128i X[numSamples]
    306         {_mm_set1_epi32(samplePosXi[0]), _mm_set1_epi32(samplePosXi[1]), _mm_set1_epi32(samplePosXi[2]), _mm_set1_epi32(samplePosXi[3])};
    307         SWR_ASSERT(sampleNum < numSamples);
    308         return X[sampleNum];
    309     }
    310 
    311     INLINE static __m128i vYi(uint32_t sampleNum)
    312     {
    313         static const __m128i Y[numSamples]
    314         {_mm_set1_epi32(samplePosYi[0]), _mm_set1_epi32(samplePosYi[1]), _mm_set1_epi32(samplePosYi[2]), _mm_set1_epi32(samplePosYi[3])};
    315         SWR_ASSERT(sampleNum < numSamples);
    316         return Y[sampleNum];
    317     }
    318 
    319     INLINE static simdscalar vX(uint32_t sampleNum)
    320     {
    321         static const simdscalar X[numSamples]
    322         {_simd_set1_ps(0.375f), _simd_set1_ps(0.875), _simd_set1_ps(0.125), _simd_set1_ps(0.625)};
    323         assert(sampleNum < numSamples);
    324         return X[sampleNum];
    325     }
    326 
    327     INLINE static simdscalar vY(uint32_t sampleNum)
    328     {
    329         static const simdscalar Y[numSamples]
    330         {_simd_set1_ps(0.125), _simd_set1_ps(0.375f), _simd_set1_ps(0.625), _simd_set1_ps(0.875)};
    331         assert(sampleNum < numSamples);
    332         return Y[sampleNum];
    333     }
    334 
    335     INLINE static float X(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosX[sampleNum]; };
    336     INLINE static float Y(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosY[sampleNum]; };
    337 
    338     INLINE static __m128i TileSampleOffsetsX()
    339     {
    340         static const uint32_t bboxLeftEdge = 0x20;
    341         static const uint32_t bboxRightEdge = 0xE0;
    342                                                             // BR,            BL,           UR,            UL
    343         static const __m128i tileSampleOffsetX = _mm_set_epi32(bboxRightEdge, bboxLeftEdge, bboxRightEdge, bboxLeftEdge);
    344         return tileSampleOffsetX;
    345     }
    346 
    347     INLINE static __m128i TileSampleOffsetsY()
    348     {
    349         static const uint32_t bboxTopEdge = 0x20;
    350         static const uint32_t bboxBottomEdge = 0xE0;
    351                                                             // BR,             BL,             UR,          UL
    352         static const __m128i tileSampleOffsetY = _mm_set_epi32(bboxBottomEdge, bboxBottomEdge, bboxTopEdge, bboxTopEdge);
    353         return tileSampleOffsetY;
    354     }
    355 
    356     INLINE static simdscalari FullSampleMask()
    357     {
    358         static const simdscalari mask = _simd_set1_epi32(0xF);
    359         return mask;
    360     }
    361 
    362     static const uint32_t samplePosXi[4];
    363     static const uint32_t samplePosYi[4];
    364     static const float samplePosX[4];
    365     static const float samplePosY[4];
    366     static const uint32_t numSamples = 4;
    367     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_4X;
    368     static const uint32_t numCoverageSamples = 4;
    369 };
    370 
    371 template<>
    372 struct MultisampleTraits<SWR_MULTISAMPLE_4X, SWR_MSAA_CENTER_PATTERN>
    373 {
    374     INLINE static __m128i vXi(uint32_t sampleNum)
    375     {
    376         return _mm_set1_epi32(0x80);
    377     }
    378 
    379     INLINE static __m128i vYi(uint32_t sampleNum)
    380     {
    381         return _mm_set1_epi32(0x80);
    382     }
    383 
    384     INLINE static simdscalar vX(uint32_t sampleNum)
    385     {
    386         return _simd_set1_ps(0.5f);
    387     }
    388 
    389     INLINE static simdscalar vY(uint32_t sampleNum)
    390     {
    391         return _simd_set1_ps(0.5f);
    392     }
    393 
    394     INLINE static float X(uint32_t sampleNum) {return 0.5f;};
    395     INLINE static float Y(uint32_t sampleNum) {return 0.5f;};
    396 
    397     INLINE static __m128i TileSampleOffsetsX()
    398     {
    399         // BR,            BL,           UR,            UL
    400         return _mm_set1_epi32(0x80);
    401     }
    402 
    403     INLINE static __m128i TileSampleOffsetsY()
    404     {
    405         // BR,             BL,             UR,          UL
    406         return _mm_set1_epi32(0x80);
    407     }
    408 
    409     INLINE static simdscalari FullSampleMask()
    410     {
    411         static const simdscalari mask = _simd_set1_epi32(0xF);
    412         return mask;
    413     }
    414     static const uint32_t numSamples = 4;
    415     static const float samplePosX[4];
    416     static const float samplePosY[4];
    417     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_4X;
    418     static const uint32_t numCoverageSamples = 1;
    419 };
    420 
    421 template<>
    422 struct MultisampleTraits<SWR_MULTISAMPLE_8X, SWR_MSAA_STANDARD_PATTERN>
    423 {
    424     INLINE static __m128i vXi(uint32_t sampleNum)
    425     {
    426         static const __m128i X[numSamples]
    427         {_mm_set1_epi32(samplePosXi[0]), _mm_set1_epi32(samplePosXi[1]), _mm_set1_epi32(samplePosXi[2]), _mm_set1_epi32(samplePosXi[3]),
    428          _mm_set1_epi32(samplePosXi[4]), _mm_set1_epi32(samplePosXi[5]), _mm_set1_epi32(samplePosXi[6]), _mm_set1_epi32(samplePosXi[7])};
    429         SWR_ASSERT(sampleNum < numSamples);
    430         return X[sampleNum];
    431     }
    432 
    433     INLINE static __m128i vYi(uint32_t sampleNum)
    434     {
    435         static const __m128i Y[numSamples]
    436         {_mm_set1_epi32(samplePosYi[0]), _mm_set1_epi32(samplePosYi[1]), _mm_set1_epi32(samplePosYi[2]), _mm_set1_epi32(samplePosYi[3]),
    437          _mm_set1_epi32(samplePosYi[4]), _mm_set1_epi32(samplePosYi[5]), _mm_set1_epi32(samplePosYi[6]), _mm_set1_epi32(samplePosYi[7])};
    438         SWR_ASSERT(sampleNum < numSamples);
    439         return Y[sampleNum];
    440     }
    441 
    442     INLINE static simdscalar vX(uint32_t sampleNum)
    443     {
    444         static const simdscalar X[numSamples]
    445         {_simd_set1_ps(0.5625), _simd_set1_ps(0.4375), _simd_set1_ps(0.8125), _simd_set1_ps(0.3125),
    446          _simd_set1_ps(0.1875), _simd_set1_ps(0.0625), _simd_set1_ps(0.6875), _simd_set1_ps(0.9375)};
    447         assert(sampleNum < numSamples);
    448         return X[sampleNum];
    449     }
    450 
    451     INLINE static simdscalar vY(uint32_t sampleNum)
    452     {
    453         static const simdscalar Y[numSamples]
    454         {_simd_set1_ps(0.3125), _simd_set1_ps(0.6875), _simd_set1_ps(0.5625), _simd_set1_ps(0.1875),
    455          _simd_set1_ps(0.8125), _simd_set1_ps(0.4375), _simd_set1_ps(0.9375), _simd_set1_ps(0.0625)};
    456         assert(sampleNum < numSamples);
    457         return Y[sampleNum];
    458     }
    459 
    460     INLINE static float X(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosX[sampleNum]; };
    461     INLINE static float Y(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosY[sampleNum]; };
    462 
    463     INLINE static __m128i TileSampleOffsetsX()
    464     {
    465         static const uint32_t bboxLeftEdge = 0x10;
    466         static const uint32_t bboxRightEdge = 0xF0;
    467                                                             // BR,            BL,           UR,            UL
    468         static const __m128i tileSampleOffsetX = _mm_set_epi32(bboxRightEdge, bboxLeftEdge, bboxRightEdge, bboxLeftEdge);
    469         return tileSampleOffsetX;
    470     }
    471 
    472     INLINE static __m128i TileSampleOffsetsY()
    473     {
    474         static const uint32_t bboxTopEdge = 0x10;
    475         static const uint32_t bboxBottomEdge = 0xF0;
    476                                                             // BR,             BL,             UR,          UL
    477         static const __m128i tileSampleOffsetY = _mm_set_epi32(bboxBottomEdge, bboxBottomEdge, bboxTopEdge, bboxTopEdge);
    478         return tileSampleOffsetY;
    479     }
    480 
    481     INLINE static simdscalari FullSampleMask()
    482     {
    483         static const simdscalari mask = _simd_set1_epi32(0xFF);
    484         return mask;
    485     }
    486 
    487     static const uint32_t samplePosXi[8];
    488     static const uint32_t samplePosYi[8];
    489     static const float samplePosX[8];
    490     static const float samplePosY[8];
    491     static const uint32_t numSamples = 8;
    492     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_8X;
    493     static const uint32_t numCoverageSamples = 8;
    494 };
    495 
    496 template<>
    497 struct MultisampleTraits<SWR_MULTISAMPLE_8X, SWR_MSAA_CENTER_PATTERN>
    498 {
    499     INLINE static __m128i vXi(uint32_t sampleNum)
    500     {
    501         return _mm_set1_epi32(0x80);
    502     }
    503 
    504     INLINE static __m128i vYi(uint32_t sampleNum)
    505     {
    506         return _mm_set1_epi32(0x80);
    507     }
    508 
    509     INLINE static simdscalar vX(uint32_t sampleNum)
    510     {
    511         return _simd_set1_ps(0.5f);
    512     }
    513 
    514     INLINE static simdscalar vY(uint32_t sampleNum)
    515     {
    516         return _simd_set1_ps(0.5f);
    517     }
    518 
    519     INLINE static float X(uint32_t sampleNum) {return 0.5f;};
    520     INLINE static float Y(uint32_t sampleNum) {return 0.5f;};
    521 
    522     INLINE static __m128i TileSampleOffsetsX()
    523     {
    524         // BR,            BL,           UR,            UL
    525         return _mm_set1_epi32(0x80);
    526     }
    527 
    528     INLINE static __m128i TileSampleOffsetsY()
    529     {
    530         // BR,             BL,             UR,          UL
    531         return _mm_set1_epi32(0x80);
    532     }
    533 
    534     INLINE static simdscalari FullSampleMask()
    535     {
    536         static const simdscalari mask = _simd_set1_epi32(0xFF);
    537         return mask;
    538     }
    539     static const uint32_t numSamples = 8;
    540     static const float samplePosX[8];
    541     static const float samplePosY[8];
    542     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_8X;
    543     static const uint32_t numCoverageSamples = 1;
    544 };
    545 
    546 template<>
    547 struct MultisampleTraits<SWR_MULTISAMPLE_16X, SWR_MSAA_STANDARD_PATTERN>
    548 {
    549     INLINE static __m128i vXi(uint32_t sampleNum)
    550     {
    551         static const __m128i X[numSamples]
    552         {_mm_set1_epi32(samplePosXi[0]), _mm_set1_epi32(samplePosXi[1]), _mm_set1_epi32(samplePosXi[2]), _mm_set1_epi32(samplePosXi[3]),
    553          _mm_set1_epi32(samplePosXi[4]), _mm_set1_epi32(samplePosXi[5]), _mm_set1_epi32(samplePosXi[6]), _mm_set1_epi32(samplePosXi[7]),
    554          _mm_set1_epi32(samplePosXi[8]), _mm_set1_epi32(samplePosXi[9]), _mm_set1_epi32(samplePosXi[10]), _mm_set1_epi32(samplePosXi[11]),
    555          _mm_set1_epi32(samplePosXi[12]), _mm_set1_epi32(samplePosXi[13]), _mm_set1_epi32(samplePosXi[14]), _mm_set1_epi32(samplePosXi[15])};
    556         SWR_ASSERT(sampleNum < numSamples);
    557         return X[sampleNum];
    558     }
    559 
    560     INLINE static __m128i vYi(uint32_t sampleNum)
    561     {
    562         static const __m128i Y[numSamples]
    563         {_mm_set1_epi32(samplePosYi[0]), _mm_set1_epi32(samplePosYi[1]), _mm_set1_epi32(samplePosYi[2]), _mm_set1_epi32(samplePosYi[3]),
    564          _mm_set1_epi32(samplePosYi[4]), _mm_set1_epi32(samplePosYi[5]), _mm_set1_epi32(samplePosYi[6]), _mm_set1_epi32(samplePosYi[7]),
    565          _mm_set1_epi32(samplePosYi[8]), _mm_set1_epi32(samplePosYi[9]), _mm_set1_epi32(samplePosYi[10]), _mm_set1_epi32(samplePosYi[11]),
    566          _mm_set1_epi32(samplePosYi[12]), _mm_set1_epi32(samplePosYi[13]), _mm_set1_epi32(samplePosYi[14]), _mm_set1_epi32(samplePosYi[15])};
    567         SWR_ASSERT(sampleNum < numSamples);
    568         return Y[sampleNum];
    569     }
    570 
    571     INLINE static simdscalar vX(uint32_t sampleNum)
    572     {
    573         static const simdscalar X[numSamples]
    574         {_simd_set1_ps(0.5625), _simd_set1_ps(0.4375), _simd_set1_ps(0.3125), _simd_set1_ps(0.7500),
    575          _simd_set1_ps(0.1875), _simd_set1_ps(0.6250), _simd_set1_ps(0.8125), _simd_set1_ps(0.6875),
    576          _simd_set1_ps(0.3750), _simd_set1_ps(0.5000), _simd_set1_ps(0.2500), _simd_set1_ps(0.1250),
    577          _simd_set1_ps(0.0000), _simd_set1_ps(0.9375), _simd_set1_ps(0.8750), _simd_set1_ps(0.0625)};
    578         assert(sampleNum < numSamples);
    579         return X[sampleNum];
    580     }
    581 
    582     INLINE static simdscalar vY(uint32_t sampleNum)
    583     {
    584         static const simdscalar Y[numSamples]
    585         {_simd_set1_ps(0.5625), _simd_set1_ps(0.3125), _simd_set1_ps(0.6250), _simd_set1_ps(0.4375),
    586          _simd_set1_ps(0.3750), _simd_set1_ps(0.8125), _simd_set1_ps(0.6875), _simd_set1_ps(0.1875),
    587          _simd_set1_ps(0.8750), _simd_set1_ps(0.0625), _simd_set1_ps(0.1250), _simd_set1_ps(0.7500),
    588          _simd_set1_ps(0.5000), _simd_set1_ps(0.2500), _simd_set1_ps(0.9375), _simd_set1_ps(0.0000)};
    589         assert(sampleNum < numSamples);
    590         return Y[sampleNum];
    591     }
    592 
    593     INLINE static float X(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosX[sampleNum]; };
    594     INLINE static float Y(uint32_t sampleNum) { SWR_ASSERT(sampleNum < numSamples); return samplePosY[sampleNum]; };
    595 
    596     INLINE static __m128i TileSampleOffsetsX()
    597     {
    598         static const uint32_t bboxLeftEdge = 0x00;
    599         static const uint32_t bboxRightEdge = 0xF0;
    600                                                             // BR,            BL,           UR,            UL
    601         static const __m128i tileSampleOffsetX = _mm_set_epi32(bboxRightEdge, bboxLeftEdge, bboxRightEdge, bboxLeftEdge);
    602         return tileSampleOffsetX;
    603     }
    604 
    605     INLINE static __m128i TileSampleOffsetsY()
    606     {
    607         static const uint32_t bboxTopEdge = 0x00;
    608         static const uint32_t bboxBottomEdge = 0xF0;
    609                                                             // BR,             BL,             UR,          UL
    610         static const __m128i tileSampleOffsetY = _mm_set_epi32(bboxBottomEdge, bboxBottomEdge, bboxTopEdge, bboxTopEdge);
    611         return tileSampleOffsetY;
    612     }
    613 
    614     INLINE static simdscalari FullSampleMask()
    615     {
    616         static const simdscalari mask = _simd_set1_epi32(0xFFFF);
    617         return mask;
    618     }
    619 
    620     static const uint32_t samplePosXi[16];
    621     static const uint32_t samplePosYi[16];
    622     static const float samplePosX[16];
    623     static const float samplePosY[16];
    624     static const uint32_t numSamples = 16;
    625     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_16X;
    626     static const uint32_t numCoverageSamples = 16;
    627 };
    628 
    629 template<>
    630 struct MultisampleTraits<SWR_MULTISAMPLE_16X, SWR_MSAA_CENTER_PATTERN>
    631 {
    632     INLINE static __m128i vXi(uint32_t sampleNum)
    633     {
    634         return _mm_set1_epi32(0x80);
    635     }
    636 
    637     INLINE static __m128i vYi(uint32_t sampleNum)
    638     {
    639         return _mm_set1_epi32(0x80);
    640     }
    641 
    642     INLINE static simdscalar vX(uint32_t sampleNum)
    643     {
    644         return _simd_set1_ps(0.5f);
    645     }
    646 
    647     INLINE static simdscalar vY(uint32_t sampleNum)
    648     {
    649         return _simd_set1_ps(0.5f);
    650     }
    651 
    652     INLINE static float X(uint32_t sampleNum) {return 0.5f;};
    653     INLINE static float Y(uint32_t sampleNum) {return 0.5f;};
    654 
    655     INLINE static __m128i TileSampleOffsetsX()
    656     {
    657         // BR,            BL,           UR,            UL
    658         return _mm_set1_epi32(0x80);
    659     }
    660 
    661     INLINE static __m128i TileSampleOffsetsY()
    662     {
    663         // BR,             BL,             UR,          UL
    664         return _mm_set1_epi32(0x80);
    665     }
    666 
    667     INLINE static simdscalari FullSampleMask()
    668     {
    669         static const simdscalari mask = _simd_set1_epi32(0xFFFF);
    670         return mask;
    671     }
    672     static const uint32_t numSamples = 16;
    673     static const float samplePosX[16];
    674     static const float samplePosY[16];
    675     static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_16X;
    676     static const uint32_t numCoverageSamples = 1;
    677 };
    678