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
GetSampleCount(uint32_t numSamples)37 SWR_MULTISAMPLE_COUNT GetSampleCount(uint32_t numSamples)
38 {
39 switch (numSamples)
40 {
41 case 1:
42 return SWR_MULTISAMPLE_1X;
43 case 2:
44 return SWR_MULTISAMPLE_2X;
45 case 4:
46 return SWR_MULTISAMPLE_4X;
47 case 8:
48 return SWR_MULTISAMPLE_8X;
49 case 16:
50 return SWR_MULTISAMPLE_16X;
51 default:
52 assert(0);
53 return SWR_MULTISAMPLE_1X;
54 }
55 }
56
57 // hardcoded offsets based on Direct3d standard multisample positions
58 // 8 x 8 pixel grid ranging from (0, 0) to (15, 15), with (0, 0) = UL pixel corner
59 // coords are 0.8 fixed point offsets from (0, 0)
60 template <SWR_MULTISAMPLE_COUNT sampleCount, bool isCenter = false>
61 struct MultisampleTraits
62 {
63 INLINE static float X(uint32_t sampleNum) = delete;
64 INLINE static float Y(uint32_t sampleNum) = delete;
65 INLINE static simdscalari FullSampleMask() = delete;
66
67 static const uint32_t numSamples = 0;
68 };
69
70 template <>
71 struct MultisampleTraits<SWR_MULTISAMPLE_1X, false>
72 {
73 INLINE static float X(uint32_t sampleNum) { return samplePosX[sampleNum]; };
74 INLINE static float Y(uint32_t sampleNum) { return samplePosY[sampleNum]; };
75 INLINE static simdscalari FullSampleMask() { return _simd_set1_epi32(0x1); };
76
77 static const uint32_t numSamples = 1;
78 static const uint32_t numCoverageSamples = 1;
79 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_1X;
80 static constexpr uint32_t samplePosXi[1] = {0x80};
81 static constexpr uint32_t samplePosYi[1] = {0x80};
82 static constexpr float samplePosX[1] = {0.5f};
83 static constexpr float samplePosY[1] = {0.5f};
84 };
85
86 template <>
87 struct MultisampleTraits<SWR_MULTISAMPLE_1X, true>
88 {
89 INLINE static float X(uint32_t sampleNum) { return 0.5f; };
90 INLINE static float Y(uint32_t sampleNum) { return 0.5f; };
91 INLINE static simdscalari FullSampleMask() { return _simd_set1_epi32(0x1); };
92
93 static const uint32_t numSamples = 1;
94 static const uint32_t numCoverageSamples = 1;
95 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_1X;
96 static constexpr uint32_t samplePosXi[1] = {0x80};
97 static constexpr uint32_t samplePosYi[1] = {0x80};
98 static constexpr float samplePosX[1] = {0.5f};
99 static constexpr float samplePosY[1] = {0.5f};
100 };
101
102 template <>
103 struct MultisampleTraits<SWR_MULTISAMPLE_2X, false>
104 {
105 INLINE static float X(uint32_t sampleNum)
106 {
107 SWR_ASSERT(sampleNum < numSamples);
108 return samplePosX[sampleNum];
109 };
110 INLINE static float Y(uint32_t sampleNum)
111 {
112 SWR_ASSERT(sampleNum < numSamples);
113 return samplePosY[sampleNum];
114 };
115 INLINE static simdscalari FullSampleMask()
116 {
117 static const simdscalari mask = _simd_set1_epi32(0x3);
118 return mask;
119 }
120
121 static const uint32_t numSamples = 2;
122 static const uint32_t numCoverageSamples = 2;
123 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_2X;
124 static constexpr uint32_t samplePosXi[2] = {0xC0, 0x40};
125 static constexpr uint32_t samplePosYi[2] = {0xC0, 0x40};
126 static constexpr float samplePosX[2] = {0.75f, 0.25f};
127 static constexpr float samplePosY[2] = {0.75f, 0.25f};
128 };
129
130 template <>
131 struct MultisampleTraits<SWR_MULTISAMPLE_2X, true>
132 {
133 INLINE static float X(uint32_t sampleNum) { return 0.5f; };
134 INLINE static float Y(uint32_t sampleNum) { return 0.5f; };
135 INLINE static simdscalari FullSampleMask()
136 {
137 static const simdscalari mask = _simd_set1_epi32(0x3);
138 return mask;
139 }
140 static const uint32_t numSamples = 2;
141 static const uint32_t numCoverageSamples = 1;
142 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_2X;
143 static constexpr uint32_t samplePosXi[2] = {0x80, 0x80};
144 static constexpr uint32_t samplePosYi[2] = {0x80, 0x80};
145 static constexpr float samplePosX[2] = {0.5f, 0.5f};
146 static constexpr float samplePosY[2] = {0.5f, 0.5f};
147 };
148
149 template <>
150 struct MultisampleTraits<SWR_MULTISAMPLE_4X, false>
151 {
152 INLINE static float X(uint32_t sampleNum)
153 {
154 SWR_ASSERT(sampleNum < numSamples);
155 return samplePosX[sampleNum];
156 };
157 INLINE static float Y(uint32_t sampleNum)
158 {
159 SWR_ASSERT(sampleNum < numSamples);
160 return samplePosY[sampleNum];
161 };
162 INLINE static simdscalari FullSampleMask()
163 {
164 static const simdscalari mask = _simd_set1_epi32(0xF);
165 return mask;
166 }
167
168 static const uint32_t numSamples = 4;
169 static const uint32_t numCoverageSamples = 4;
170 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_4X;
171 static constexpr uint32_t samplePosXi[4] = {0x60, 0xE0, 0x20, 0xA0};
172 static constexpr uint32_t samplePosYi[4] = {0x20, 0x60, 0xA0, 0xE0};
173 static constexpr float samplePosX[4] = {0.375f, 0.875f, 0.125f, 0.625f};
174 static constexpr float samplePosY[4] = {0.125f, 0.375f, 0.625f, 0.875f};
175 };
176
177 template <>
178 struct MultisampleTraits<SWR_MULTISAMPLE_4X, true>
179 {
180 INLINE static float X(uint32_t sampleNum) { return 0.5f; };
181 INLINE static float Y(uint32_t sampleNum) { return 0.5f; };
182 INLINE static simdscalari FullSampleMask()
183 {
184 static const simdscalari mask = _simd_set1_epi32(0xF);
185 return mask;
186 }
187
188 static const uint32_t numSamples = 4;
189 static const uint32_t numCoverageSamples = 1;
190 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_4X;
191 static constexpr uint32_t samplePosXi[4] = {0x80, 0x80, 0x80, 0x80};
192 static constexpr uint32_t samplePosYi[4] = {0x80, 0x80, 0x80, 0x80};
193 static constexpr float samplePosX[4] = {0.5f, 0.5f, 0.5f, 0.5f};
194 static constexpr float samplePosY[4] = {0.5f, 0.5f, 0.5f, 0.5f};
195 };
196
197 template <>
198 struct MultisampleTraits<SWR_MULTISAMPLE_8X, false>
199 {
200 INLINE static float X(uint32_t sampleNum)
201 {
202 SWR_ASSERT(sampleNum < numSamples);
203 return samplePosX[sampleNum];
204 };
205 INLINE static float Y(uint32_t sampleNum)
206 {
207 SWR_ASSERT(sampleNum < numSamples);
208 return samplePosY[sampleNum];
209 };
210 INLINE static simdscalari FullSampleMask()
211 {
212 static const simdscalari mask = _simd_set1_epi32(0xFF);
213 return mask;
214 }
215
216 static const uint32_t numSamples = 8;
217 static const uint32_t numCoverageSamples = 8;
218 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_8X;
219 static constexpr uint32_t samplePosXi[8] = {0x90, 0x70, 0xD0, 0x50, 0x30, 0x10, 0xB0, 0xF0};
220 static constexpr uint32_t samplePosYi[8] = {0x50, 0xB0, 0x90, 0x30, 0xD0, 0x70, 0xF0, 0x10};
221 static constexpr float samplePosX[8] = {
222 0.5625f, 0.4375f, 0.8125f, 0.3125f, 0.1875f, 0.0625f, 0.6875f, 0.9375f};
223 static constexpr float samplePosY[8] = {
224 0.3125f, 0.6875f, 0.5625f, 0.1875f, 0.8125f, 0.4375f, 0.9375f, 0.0625f};
225 };
226
227 template <>
228 struct MultisampleTraits<SWR_MULTISAMPLE_8X, true>
229 {
230 INLINE static float X(uint32_t sampleNum) { return 0.5f; };
231 INLINE static float Y(uint32_t sampleNum) { return 0.5f; };
232 INLINE static simdscalari FullSampleMask()
233 {
234 static const simdscalari mask = _simd_set1_epi32(0xFF);
235 return mask;
236 }
237 static const uint32_t numSamples = 8;
238 static const uint32_t numCoverageSamples = 1;
239 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_8X;
240 static constexpr uint32_t samplePosXi[8] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
241 static constexpr uint32_t samplePosYi[8] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
242 static constexpr float samplePosX[8] = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
243 static constexpr float samplePosY[8] = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
244 };
245
246 template <>
247 struct MultisampleTraits<SWR_MULTISAMPLE_16X, false>
248 {
249 INLINE static float X(uint32_t sampleNum)
250 {
251 SWR_ASSERT(sampleNum < numSamples);
252 return samplePosX[sampleNum];
253 };
254 INLINE static float Y(uint32_t sampleNum)
255 {
256 SWR_ASSERT(sampleNum < numSamples);
257 return samplePosY[sampleNum];
258 };
259 INLINE static simdscalari FullSampleMask()
260 {
261 static const simdscalari mask = _simd_set1_epi32(0xFFFF);
262 return mask;
263 }
264
265 static const uint32_t numSamples = 16;
266 static const uint32_t numCoverageSamples = 16;
267 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_16X;
268 static constexpr uint32_t samplePosXi[16] = {0x90,
269 0x70,
270 0x50,
271 0xC0,
272 0x30,
273 0xA0,
274 0xD0,
275 0xB0,
276 0x60,
277 0x80,
278 0x40,
279 0x20,
280 0x00,
281 0xF0,
282 0xE0,
283 0x10};
284 static constexpr uint32_t samplePosYi[16] = {0x90,
285 0x50,
286 0xA0,
287 0x70,
288 0x60,
289 0xD0,
290 0xB0,
291 0x30,
292 0xE0,
293 0x10,
294 0x20,
295 0xC0,
296 0x80,
297 0x40,
298 0xF0,
299 0x00};
300 static constexpr float samplePosX[16] = {0.5625f,
301 0.4375f,
302 0.3125f,
303 0.7500f,
304 0.1875f,
305 0.6250f,
306 0.8125f,
307 0.6875f,
308 0.3750f,
309 0.5000f,
310 0.2500f,
311 0.1250f,
312 0.0000f,
313 0.9375f,
314 0.8750f,
315 0.0625f};
316 static constexpr float samplePosY[16] = {0.5625f,
317 0.3125f,
318 0.6250f,
319 0.4375f,
320 0.3750f,
321 0.8125f,
322 0.6875f,
323 0.1875f,
324 0.8750f,
325 0.0625f,
326 0.1250f,
327 0.7500f,
328 0.5000f,
329 0.2500f,
330 0.9375f,
331 0.0000f};
332 };
333
334 template <>
335 struct MultisampleTraits<SWR_MULTISAMPLE_16X, true>
336 {
337 INLINE static float X(uint32_t sampleNum) { return 0.5f; };
338 INLINE static float Y(uint32_t sampleNum) { return 0.5f; };
339 INLINE static simdscalari FullSampleMask()
340 {
341 static const simdscalari mask = _simd_set1_epi32(0xFFFF);
342 return mask;
343 }
344 static const uint32_t numSamples = 16;
345 static const uint32_t numCoverageSamples = 1;
346 static const SWR_MULTISAMPLE_COUNT sampleCount = SWR_MULTISAMPLE_16X;
347 static constexpr uint32_t samplePosXi[16] = {0x80,
348 0x80,
349 0x80,
350 0x80,
351 0x80,
352 0x80,
353 0x80,
354 0x80,
355 0x80,
356 0x80,
357 0x80,
358 0x80,
359 0x80,
360 0x80,
361 0x80,
362 0x80};
363 static constexpr uint32_t samplePosYi[16] = {0x80,
364 0x80,
365 0x80,
366 0x80,
367 0x80,
368 0x80,
369 0x80,
370 0x80,
371 0x80,
372 0x80,
373 0x80,
374 0x80,
375 0x80,
376 0x80,
377 0x80,
378 0x80};
379 static constexpr float samplePosX[16] = {0.5f,
380 0.5f,
381 0.5f,
382 0.5f,
383 0.5f,
384 0.5f,
385 0.5f,
386 0.5f,
387 0.5f,
388 0.5f,
389 0.5f,
390 0.5f,
391 0.5f,
392 0.5f,
393 0.5f,
394 0.5f};
395 static constexpr float samplePosY[16] = {0.5f,
396 0.5f,
397 0.5f,
398 0.5f,
399 0.5f,
400 0.5f,
401 0.5f,
402 0.5f,
403 0.5f,
404 0.5f,
405 0.5f,
406 0.5f,
407 0.5f,
408 0.5f,
409 0.5f,
410 0.5f};
411 };
412
413 INLINE
414 bool isNonStandardPattern(const SWR_MULTISAMPLE_COUNT sampleCount,
415 const SWR_MULTISAMPLE_POS& samplePos)
416 {
417 // detect if we're using standard or center sample patterns
418 const uint32_t *standardPosX, *standardPosY;
419 switch (sampleCount)
420 {
421 case SWR_MULTISAMPLE_1X:
422 standardPosX = MultisampleTraits<SWR_MULTISAMPLE_1X>::samplePosXi;
423 standardPosY = MultisampleTraits<SWR_MULTISAMPLE_1X>::samplePosYi;
424 break;
425 case SWR_MULTISAMPLE_2X:
426 standardPosX = MultisampleTraits<SWR_MULTISAMPLE_2X>::samplePosXi;
427 standardPosY = MultisampleTraits<SWR_MULTISAMPLE_2X>::samplePosYi;
428 break;
429 case SWR_MULTISAMPLE_4X:
430 standardPosX = MultisampleTraits<SWR_MULTISAMPLE_4X>::samplePosXi;
431 standardPosY = MultisampleTraits<SWR_MULTISAMPLE_4X>::samplePosYi;
432 break;
433 case SWR_MULTISAMPLE_8X:
434 standardPosX = MultisampleTraits<SWR_MULTISAMPLE_8X>::samplePosXi;
435 standardPosY = MultisampleTraits<SWR_MULTISAMPLE_8X>::samplePosYi;
436 break;
437 case SWR_MULTISAMPLE_16X:
438 standardPosX = MultisampleTraits<SWR_MULTISAMPLE_16X>::samplePosXi;
439 standardPosY = MultisampleTraits<SWR_MULTISAMPLE_16X>::samplePosYi;
440 break;
441 default:
442 break;
443 }
444
445 // scan sample pattern for standard or center
446 uint32_t numSamples = GetNumSamples(sampleCount);
447 bool bIsStandard = true;
448 if (numSamples > 1)
449 {
450 for (uint32_t i = 0; i < numSamples; i++)
451 {
452 bIsStandard =
453 (standardPosX[i] == samplePos.Xi(i)) || (standardPosY[i] == samplePos.Yi(i));
454 if (!bIsStandard)
455 break;
456 }
457 }
458 return !bIsStandard;
459 }
460