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 rasterizer.cpp
24 *
25 * @brief Implementation for the rasterizer.
26 *
27 ******************************************************************************/
28
29 #include <vector>
30 #include <algorithm>
31
32 #include "rasterizer.h"
33 #include "backends/gen_rasterizer.hpp"
34 #include "rdtsc_core.h"
35 #include "backend.h"
36 #include "utils.h"
37 #include "frontend.h"
38 #include "tilemgr.h"
39 #include "memory/tilingtraits.h"
40 #include "rasterizer_impl.h"
41
42 PFN_WORK_FUNC gRasterizerFuncs[SWR_MULTISAMPLE_TYPE_COUNT][2][2][SWR_INPUT_COVERAGE_COUNT][STATE_VALID_TRI_EDGE_COUNT][2];
43
RasterizeLine(DRAW_CONTEXT * pDC,uint32_t workerId,uint32_t macroTile,void * pData)44 void RasterizeLine(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void *pData)
45 {
46 SWR_CONTEXT *pContext = pDC->pContext;
47 const TRIANGLE_WORK_DESC &workDesc = *((TRIANGLE_WORK_DESC*)pData);
48 #if KNOB_ENABLE_TOSS_POINTS
49 if (KNOB_TOSS_BIN_TRIS)
50 {
51 return;
52 }
53 #endif
54
55 // bloat line to two tris and call the triangle rasterizer twice
56 AR_BEGIN(BERasterizeLine, pDC->drawId);
57
58 const API_STATE &state = GetApiState(pDC);
59 const SWR_RASTSTATE &rastState = state.rastState;
60
61 // macrotile dimensioning
62 uint32_t macroX, macroY;
63 MacroTileMgr::getTileIndices(macroTile, macroX, macroY);
64 int32_t macroBoxLeft = macroX * KNOB_MACROTILE_X_DIM_FIXED;
65 int32_t macroBoxRight = macroBoxLeft + KNOB_MACROTILE_X_DIM_FIXED - 1;
66 int32_t macroBoxTop = macroY * KNOB_MACROTILE_Y_DIM_FIXED;
67 int32_t macroBoxBottom = macroBoxTop + KNOB_MACROTILE_Y_DIM_FIXED - 1;
68
69 const SWR_RECT &scissorInFixedPoint = state.scissorsInFixedPoint[workDesc.triFlags.viewportIndex];
70
71 // create a copy of the triangle buffer to write our adjusted vertices to
72 OSALIGNSIMD(float) newTriBuffer[4 * 4];
73 TRIANGLE_WORK_DESC newWorkDesc = workDesc;
74 newWorkDesc.pTriBuffer = &newTriBuffer[0];
75
76 // create a copy of the attrib buffer to write our adjusted attribs to
77 OSALIGNSIMD(float) newAttribBuffer[4 * 3 * SWR_VTX_NUM_SLOTS];
78 newWorkDesc.pAttribs = &newAttribBuffer[0];
79
80 const __m128 vBloat0 = _mm_set_ps(0.5f, -0.5f, -0.5f, 0.5f);
81 const __m128 vBloat1 = _mm_set_ps(0.5f, 0.5f, 0.5f, -0.5f);
82
83 __m128 vX, vY, vZ, vRecipW;
84
85 vX = _mm_load_ps(workDesc.pTriBuffer);
86 vY = _mm_load_ps(workDesc.pTriBuffer + 4);
87 vZ = _mm_load_ps(workDesc.pTriBuffer + 8);
88 vRecipW = _mm_load_ps(workDesc.pTriBuffer + 12);
89
90 // triangle 0
91 // v0,v1 -> v0,v0,v1
92 __m128 vXa = _mm_shuffle_ps(vX, vX, _MM_SHUFFLE(1, 1, 0, 0));
93 __m128 vYa = _mm_shuffle_ps(vY, vY, _MM_SHUFFLE(1, 1, 0, 0));
94 __m128 vZa = _mm_shuffle_ps(vZ, vZ, _MM_SHUFFLE(1, 1, 0, 0));
95 __m128 vRecipWa = _mm_shuffle_ps(vRecipW, vRecipW, _MM_SHUFFLE(1, 1, 0, 0));
96
97 __m128 vLineWidth = _mm_set1_ps(pDC->pState->state.rastState.lineWidth);
98 __m128 vAdjust = _mm_mul_ps(vLineWidth, vBloat0);
99 if (workDesc.triFlags.yMajor)
100 {
101 vXa = _mm_add_ps(vAdjust, vXa);
102 }
103 else
104 {
105 vYa = _mm_add_ps(vAdjust, vYa);
106 }
107
108 // Store triangle description for rasterizer
109 _mm_store_ps((float*)&newTriBuffer[0], vXa);
110 _mm_store_ps((float*)&newTriBuffer[4], vYa);
111 _mm_store_ps((float*)&newTriBuffer[8], vZa);
112 _mm_store_ps((float*)&newTriBuffer[12], vRecipWa);
113
114 // binner bins 3 edges for lines as v0, v1, v1
115 // tri0 needs v0, v0, v1
116 for (uint32_t a = 0; a < workDesc.numAttribs; ++a)
117 {
118 __m128 vAttrib0 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 0]);
119 __m128 vAttrib1 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 4]);
120
121 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 0], vAttrib0);
122 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 4], vAttrib0);
123 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 8], vAttrib1);
124 }
125
126 // Store user clip distances for triangle 0
127 float newClipBuffer[3 * 8];
128 uint32_t numClipDist = _mm_popcnt_u32(state.backendState.clipDistanceMask);
129 if (numClipDist)
130 {
131 newWorkDesc.pUserClipBuffer = newClipBuffer;
132
133 float* pOldBuffer = workDesc.pUserClipBuffer;
134 float* pNewBuffer = newClipBuffer;
135 for (uint32_t i = 0; i < numClipDist; ++i)
136 {
137 // read barycentric coeffs from binner
138 float a = *(pOldBuffer++);
139 float b = *(pOldBuffer++);
140
141 // reconstruct original clip distance at vertices
142 float c0 = a + b;
143 float c1 = b;
144
145 // construct triangle barycentrics
146 *(pNewBuffer++) = c0 - c1;
147 *(pNewBuffer++) = c0 - c1;
148 *(pNewBuffer++) = c1;
149 }
150 }
151
152 // setup triangle rasterizer function
153 PFN_WORK_FUNC pfnTriRast;
154 // conservative rast not supported for points/lines
155 pfnTriRast = GetRasterizerFunc(rastState.sampleCount, rastState.bIsCenterPattern, false,
156 SWR_INPUT_COVERAGE_NONE, EdgeValToEdgeState(ALL_EDGES_VALID), (pDC->pState->state.scissorsTileAligned == false));
157
158 // make sure this macrotile intersects the triangle
159 __m128i vXai = fpToFixedPoint(vXa);
160 __m128i vYai = fpToFixedPoint(vYa);
161 OSALIGNSIMD(SWR_RECT) bboxA;
162 calcBoundingBoxInt(vXai, vYai, bboxA);
163
164 if (!(bboxA.xmin > macroBoxRight ||
165 bboxA.xmin > scissorInFixedPoint.xmax ||
166 bboxA.xmax - 1 < macroBoxLeft ||
167 bboxA.xmax - 1 < scissorInFixedPoint.xmin ||
168 bboxA.ymin > macroBoxBottom ||
169 bboxA.ymin > scissorInFixedPoint.ymax ||
170 bboxA.ymax - 1 < macroBoxTop ||
171 bboxA.ymax - 1 < scissorInFixedPoint.ymin)) {
172 // rasterize triangle
173 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
174 }
175
176 // triangle 1
177 // v0,v1 -> v1,v1,v0
178 vXa = _mm_shuffle_ps(vX, vX, _MM_SHUFFLE(1, 0, 1, 1));
179 vYa = _mm_shuffle_ps(vY, vY, _MM_SHUFFLE(1, 0, 1, 1));
180 vZa = _mm_shuffle_ps(vZ, vZ, _MM_SHUFFLE(1, 0, 1, 1));
181 vRecipWa = _mm_shuffle_ps(vRecipW, vRecipW, _MM_SHUFFLE(1, 0, 1, 1));
182
183 vAdjust = _mm_mul_ps(vLineWidth, vBloat1);
184 if (workDesc.triFlags.yMajor)
185 {
186 vXa = _mm_add_ps(vAdjust, vXa);
187 }
188 else
189 {
190 vYa = _mm_add_ps(vAdjust, vYa);
191 }
192
193 // Store triangle description for rasterizer
194 _mm_store_ps((float*)&newTriBuffer[0], vXa);
195 _mm_store_ps((float*)&newTriBuffer[4], vYa);
196 _mm_store_ps((float*)&newTriBuffer[8], vZa);
197 _mm_store_ps((float*)&newTriBuffer[12], vRecipWa);
198
199 // binner bins 3 edges for lines as v0, v1, v1
200 // tri1 needs v1, v1, v0
201 for (uint32_t a = 0; a < workDesc.numAttribs; ++a)
202 {
203 __m128 vAttrib0 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 0]);
204 __m128 vAttrib1 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 4]);
205
206 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 0], vAttrib1);
207 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 4], vAttrib1);
208 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 8], vAttrib0);
209 }
210
211 // store user clip distance for triangle 1
212 if (numClipDist)
213 {
214 float* pOldBuffer = workDesc.pUserClipBuffer;
215 float* pNewBuffer = newClipBuffer;
216 for (uint32_t i = 0; i < numClipDist; ++i)
217 {
218 // read barycentric coeffs from binner
219 float a = *(pOldBuffer++);
220 float b = *(pOldBuffer++);
221
222 // reconstruct original clip distance at vertices
223 float c0 = a + b;
224 float c1 = b;
225
226 // construct triangle barycentrics
227 *(pNewBuffer++) = c1 - c0;
228 *(pNewBuffer++) = c1 - c0;
229 *(pNewBuffer++) = c0;
230 }
231 }
232
233 vXai = fpToFixedPoint(vXa);
234 vYai = fpToFixedPoint(vYa);
235 calcBoundingBoxInt(vXai, vYai, bboxA);
236
237 if (!(bboxA.xmin > macroBoxRight ||
238 bboxA.xmin > scissorInFixedPoint.xmax ||
239 bboxA.xmax - 1 < macroBoxLeft ||
240 bboxA.xmax - 1 < scissorInFixedPoint.xmin ||
241 bboxA.ymin > macroBoxBottom ||
242 bboxA.ymin > scissorInFixedPoint.ymax ||
243 bboxA.ymax - 1 < macroBoxTop ||
244 bboxA.ymax - 1 < scissorInFixedPoint.ymin)) {
245 // rasterize triangle
246 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
247 }
248
249 AR_END(BERasterizeLine, 1);
250 }
251
RasterizeSimplePoint(DRAW_CONTEXT * pDC,uint32_t workerId,uint32_t macroTile,void * pData)252 void RasterizeSimplePoint(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void* pData)
253 {
254 SWR_CONTEXT *pContext = pDC->pContext;
255
256 #if KNOB_ENABLE_TOSS_POINTS
257 if (KNOB_TOSS_BIN_TRIS)
258 {
259 return;
260 }
261 #endif
262
263 const TRIANGLE_WORK_DESC& workDesc = *(const TRIANGLE_WORK_DESC*)pData;
264 const BACKEND_FUNCS& backendFuncs = pDC->pState->backendFuncs;
265
266 // map x,y relative offsets from start of raster tile to bit position in
267 // coverage mask for the point
268 static const uint32_t coverageMap[8][8] = {
269 { 0, 1, 4, 5, 8, 9, 12, 13 },
270 { 2, 3, 6, 7, 10, 11, 14, 15 },
271 { 16, 17, 20, 21, 24, 25, 28, 29 },
272 { 18, 19, 22, 23, 26, 27, 30, 31 },
273 { 32, 33, 36, 37, 40, 41, 44, 45 },
274 { 34, 35, 38, 39, 42, 43, 46, 47 },
275 { 48, 49, 52, 53, 56, 57, 60, 61 },
276 { 50, 51, 54, 55, 58, 59, 62, 63 }
277 };
278
279 OSALIGNSIMD(SWR_TRIANGLE_DESC) triDesc;
280
281 // pull point information from triangle buffer
282 // @todo use structs for readability
283 uint32_t tileAlignedX = *(uint32_t*)workDesc.pTriBuffer;
284 uint32_t tileAlignedY = *(uint32_t*)(workDesc.pTriBuffer + 1);
285 float z = *(workDesc.pTriBuffer + 2);
286
287 // construct triangle descriptor for point
288 // no interpolation, set up i,j for constant interpolation of z and attribs
289 // @todo implement an optimized backend that doesn't require triangle information
290
291 // compute coverage mask from x,y packed into the coverageMask flag
292 // mask indices by the maximum valid index for x/y of coveragemap.
293 uint32_t tX = workDesc.triFlags.coverageMask & 0x7;
294 uint32_t tY = (workDesc.triFlags.coverageMask >> 4) & 0x7;
295 // todo: multisample points?
296 triDesc.coverageMask[0] = 1ULL << coverageMap[tY][tX];
297
298 // no persp divide needed for points
299 triDesc.pAttribs = triDesc.pPerspAttribs = workDesc.pAttribs;
300 triDesc.triFlags = workDesc.triFlags;
301 triDesc.recipDet = 1.0f;
302 triDesc.OneOverW[0] = triDesc.OneOverW[1] = triDesc.OneOverW[2] = 1.0f;
303 triDesc.I[0] = triDesc.I[1] = triDesc.I[2] = 0.0f;
304 triDesc.J[0] = triDesc.J[1] = triDesc.J[2] = 0.0f;
305 triDesc.Z[0] = triDesc.Z[1] = triDesc.Z[2] = z;
306
307 RenderOutputBuffers renderBuffers;
308 GetRenderHotTiles(pDC, macroTile, tileAlignedX >> KNOB_TILE_X_DIM_SHIFT , tileAlignedY >> KNOB_TILE_Y_DIM_SHIFT,
309 renderBuffers, triDesc.triFlags.renderTargetArrayIndex);
310
311 AR_BEGIN(BEPixelBackend, pDC->drawId);
312 backendFuncs.pfnBackend(pDC, workerId, tileAlignedX, tileAlignedY, triDesc, renderBuffers);
313 AR_END(BEPixelBackend, 0);
314 }
315
RasterizeTriPoint(DRAW_CONTEXT * pDC,uint32_t workerId,uint32_t macroTile,void * pData)316 void RasterizeTriPoint(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void* pData)
317 {
318 const TRIANGLE_WORK_DESC& workDesc = *(const TRIANGLE_WORK_DESC*)pData;
319 const SWR_RASTSTATE& rastState = pDC->pState->state.rastState;
320 const SWR_BACKEND_STATE& backendState = pDC->pState->state.backendState;
321
322 bool isPointSpriteTexCoordEnabled = backendState.pointSpriteTexCoordMask != 0;
323
324 // load point vertex
325 float x = *workDesc.pTriBuffer;
326 float y = *(workDesc.pTriBuffer + 1);
327 float z = *(workDesc.pTriBuffer + 2);
328
329 // create a copy of the triangle buffer to write our adjusted vertices to
330 OSALIGNSIMD(float) newTriBuffer[4 * 4];
331 TRIANGLE_WORK_DESC newWorkDesc = workDesc;
332 newWorkDesc.pTriBuffer = &newTriBuffer[0];
333
334 // create a copy of the attrib buffer to write our adjusted attribs to
335 OSALIGNSIMD(float) newAttribBuffer[4 * 3 * SWR_VTX_NUM_SLOTS];
336 newWorkDesc.pAttribs = &newAttribBuffer[0];
337
338 newWorkDesc.pUserClipBuffer = workDesc.pUserClipBuffer;
339 newWorkDesc.numAttribs = workDesc.numAttribs;
340 newWorkDesc.triFlags = workDesc.triFlags;
341
342 // construct two tris by bloating point by point size
343 float halfPointSize = workDesc.triFlags.pointSize * 0.5f;
344 float lowerX = x - halfPointSize;
345 float upperX = x + halfPointSize;
346 float lowerY = y - halfPointSize;
347 float upperY = y + halfPointSize;
348
349 // tri 0
350 float *pBuf = &newTriBuffer[0];
351 *pBuf++ = lowerX;
352 *pBuf++ = lowerX;
353 *pBuf++ = upperX;
354 pBuf++;
355 *pBuf++ = lowerY;
356 *pBuf++ = upperY;
357 *pBuf++ = upperY;
358 pBuf++;
359 _mm_store_ps(pBuf, _mm_set1_ps(z));
360 _mm_store_ps(pBuf += 4, _mm_set1_ps(1.0f));
361
362 // setup triangle rasterizer function
363 PFN_WORK_FUNC pfnTriRast;
364 // conservative rast not supported for points/lines
365 pfnTriRast = GetRasterizerFunc(rastState.sampleCount, rastState.bIsCenterPattern, false,
366 SWR_INPUT_COVERAGE_NONE, EdgeValToEdgeState(ALL_EDGES_VALID), (pDC->pState->state.scissorsTileAligned == false));
367
368 // overwrite texcoords for point sprites
369 if (isPointSpriteTexCoordEnabled)
370 {
371 // copy original attribs
372 memcpy(&newAttribBuffer[0], workDesc.pAttribs, 4 * 3 * workDesc.numAttribs * sizeof(float));
373 newWorkDesc.pAttribs = &newAttribBuffer[0];
374
375 // overwrite texcoord for point sprites
376 uint32_t texCoordMask = backendState.pointSpriteTexCoordMask;
377 DWORD texCoordAttrib = 0;
378
379 while (_BitScanForward(&texCoordAttrib, texCoordMask))
380 {
381 texCoordMask &= ~(1 << texCoordAttrib);
382 __m128* pTexAttrib = (__m128*)&newAttribBuffer[0] + 3 * texCoordAttrib;
383 if (rastState.pointSpriteTopOrigin)
384 {
385 pTexAttrib[0] = _mm_set_ps(1, 0, 0, 0);
386 pTexAttrib[1] = _mm_set_ps(1, 0, 1, 0);
387 pTexAttrib[2] = _mm_set_ps(1, 0, 1, 1);
388 }
389 else
390 {
391 pTexAttrib[0] = _mm_set_ps(1, 0, 1, 0);
392 pTexAttrib[1] = _mm_set_ps(1, 0, 0, 0);
393 pTexAttrib[2] = _mm_set_ps(1, 0, 0, 1);
394 }
395 }
396 }
397 else
398 {
399 // no texcoord overwrite, can reuse the attrib buffer from frontend
400 newWorkDesc.pAttribs = workDesc.pAttribs;
401 }
402
403 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
404
405 // tri 1
406 pBuf = &newTriBuffer[0];
407 *pBuf++ = lowerX;
408 *pBuf++ = upperX;
409 *pBuf++ = upperX;
410 pBuf++;
411 *pBuf++ = lowerY;
412 *pBuf++ = upperY;
413 *pBuf++ = lowerY;
414 // z, w unchanged
415
416 if (isPointSpriteTexCoordEnabled)
417 {
418 uint32_t texCoordMask = backendState.pointSpriteTexCoordMask;
419 DWORD texCoordAttrib = 0;
420
421 while (_BitScanForward(&texCoordAttrib, texCoordMask))
422 {
423 texCoordMask &= ~(1 << texCoordAttrib);
424 __m128* pTexAttrib = (__m128*)&newAttribBuffer[0] + 3 * texCoordAttrib;
425 if (rastState.pointSpriteTopOrigin)
426 {
427 pTexAttrib[0] = _mm_set_ps(1, 0, 0, 0);
428 pTexAttrib[1] = _mm_set_ps(1, 0, 1, 1);
429 pTexAttrib[2] = _mm_set_ps(1, 0, 0, 1);
430
431 }
432 else
433 {
434 pTexAttrib[0] = _mm_set_ps(1, 0, 1, 0);
435 pTexAttrib[1] = _mm_set_ps(1, 0, 0, 1);
436 pTexAttrib[2] = _mm_set_ps(1, 0, 1, 1);
437 }
438 }
439 }
440
441 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
442 }
443
InitRasterizerFunctions()444 void InitRasterizerFunctions()
445 {
446 InitRasterizerFuncs();
447 }
448
449 // Selector for correct templated RasterizeTriangle function
GetRasterizerFunc(SWR_MULTISAMPLE_COUNT numSamples,bool IsCenter,bool IsConservative,SWR_INPUT_COVERAGE InputCoverage,uint32_t EdgeEnable,bool RasterizeScissorEdges)450 PFN_WORK_FUNC GetRasterizerFunc(
451 SWR_MULTISAMPLE_COUNT numSamples,
452 bool IsCenter,
453 bool IsConservative,
454 SWR_INPUT_COVERAGE InputCoverage,
455 uint32_t EdgeEnable,
456 bool RasterizeScissorEdges
457 )
458 {
459 SWR_ASSERT(numSamples >= 0 && numSamples < SWR_MULTISAMPLE_TYPE_COUNT);
460 SWR_ASSERT(InputCoverage >= 0 && InputCoverage < SWR_INPUT_COVERAGE_COUNT);
461 SWR_ASSERT(EdgeEnable < STATE_VALID_TRI_EDGE_COUNT);
462
463 PFN_WORK_FUNC func = gRasterizerFuncs[numSamples][IsCenter][IsConservative][InputCoverage][EdgeEnable][RasterizeScissorEdges];
464 SWR_ASSERT(func);
465
466 return func;
467 }
468