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 backend.cpp
24 *
25 * @brief Backend handles rasterization, pixel shading and output merger
26 * operations.
27 *
28 ******************************************************************************/
29
30 #include <smmintrin.h>
31
32 #include "backend.h"
33 #include "backend_impl.h"
34 #include "tilemgr.h"
35 #include "memory/tilingtraits.h"
36 #include "core/multisample.h"
37
38 #include <algorithm>
39
40 template<typename T>
BackendSingleSample(DRAW_CONTEXT * pDC,uint32_t workerId,uint32_t x,uint32_t y,SWR_TRIANGLE_DESC & work,RenderOutputBuffers & renderBuffers)41 void BackendSingleSample(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t x, uint32_t y, SWR_TRIANGLE_DESC &work, RenderOutputBuffers &renderBuffers)
42 {
43 SWR_CONTEXT *pContext = pDC->pContext;
44
45 AR_BEGIN(BESingleSampleBackend, pDC->drawId);
46 AR_BEGIN(BESetup, pDC->drawId);
47
48 const API_STATE &state = GetApiState(pDC);
49
50 BarycentricCoeffs coeffs;
51 SetupBarycentricCoeffs(&coeffs, work);
52
53 SWR_PS_CONTEXT psContext;
54 const SWR_MULTISAMPLE_POS& samplePos = state.rastState.samplePositions;
55 SetupPixelShaderContext<T>(&psContext, samplePos, work);
56
57 uint8_t *pDepthBuffer, *pStencilBuffer;
58 SetupRenderBuffers(psContext.pColorBuffer, &pDepthBuffer, &pStencilBuffer, state.colorHottileEnable, renderBuffers);
59
60 AR_END(BESetup, 1);
61
62 psContext.vY.UL = _simd_add_ps(vULOffsetsY, _simd_set1_ps(static_cast<float>(y)));
63 psContext.vY.center = _simd_add_ps(vCenterOffsetsY, _simd_set1_ps(static_cast<float>(y)));
64
65 const simdscalar dy = _simd_set1_ps(static_cast<float>(SIMD_TILE_Y_DIM));
66
67 for (uint32_t yy = y; yy < y + KNOB_TILE_Y_DIM; yy += SIMD_TILE_Y_DIM)
68 {
69 psContext.vX.UL = _simd_add_ps(vULOffsetsX, _simd_set1_ps(static_cast<float>(x)));
70 psContext.vX.center = _simd_add_ps(vCenterOffsetsX, _simd_set1_ps(static_cast<float>(x)));
71
72 const simdscalar dx = _simd_set1_ps(static_cast<float>(SIMD_TILE_X_DIM));
73
74 for (uint32_t xx = x; xx < x + KNOB_TILE_X_DIM; xx += SIMD_TILE_X_DIM)
75 {
76 #if USE_8x2_TILE_BACKEND
77 const bool useAlternateOffset = ((xx & SIMD_TILE_X_DIM) != 0);
78 #endif
79 simdmask coverageMask = work.coverageMask[0] & MASK;
80
81 if (coverageMask)
82 {
83 if (state.depthHottileEnable && state.depthBoundsState.depthBoundsTestEnable)
84 {
85 static_assert(KNOB_DEPTH_HOT_TILE_FORMAT == R32_FLOAT, "Unsupported depth hot tile format");
86
87 const simdscalar z = _simd_load_ps(reinterpret_cast<const float *>(pDepthBuffer));
88
89 const float minz = state.depthBoundsState.depthBoundsTestMinValue;
90 const float maxz = state.depthBoundsState.depthBoundsTestMaxValue;
91
92 coverageMask &= CalcDepthBoundsAcceptMask(z, minz, maxz);
93 }
94
95 if (T::InputCoverage != SWR_INPUT_COVERAGE_NONE)
96 {
97 const uint64_t* pCoverageMask = (T::InputCoverage == SWR_INPUT_COVERAGE_INNER_CONSERVATIVE) ? &work.innerCoverageMask : &work.coverageMask[0];
98
99 generateInputCoverage<T, T::InputCoverage>(pCoverageMask, psContext.inputMask, state.blendState.sampleMask);
100 }
101
102 AR_BEGIN(BEBarycentric, pDC->drawId);
103
104 CalcPixelBarycentrics(coeffs, psContext);
105
106 CalcCentroid<T, true>(&psContext, samplePos, coeffs, work.coverageMask, state.blendState.sampleMask);
107
108 // interpolate and quantize z
109 psContext.vZ = vplaneps(coeffs.vZa, coeffs.vZb, coeffs.vZc, psContext.vI.center, psContext.vJ.center);
110 psContext.vZ = state.pfnQuantizeDepth(psContext.vZ);
111
112 AR_END(BEBarycentric, 1);
113
114 // interpolate user clip distance if available
115 if (state.backendState.clipDistanceMask)
116 {
117 coverageMask &= ~ComputeUserClipMask(state.backendState.clipDistanceMask, work.pUserClipBuffer, psContext.vI.center, psContext.vJ.center);
118 }
119
120 simdscalar vCoverageMask = _simd_vmask_ps(coverageMask);
121 simdscalar depthPassMask = vCoverageMask;
122 simdscalar stencilPassMask = vCoverageMask;
123
124 // Early-Z?
125 if (T::bCanEarlyZ)
126 {
127 AR_BEGIN(BEEarlyDepthTest, pDC->drawId);
128 depthPassMask = DepthStencilTest(&state, work.triFlags.frontFacing, work.triFlags.viewportIndex,
129 psContext.vZ, pDepthBuffer, vCoverageMask, pStencilBuffer, &stencilPassMask);
130 AR_EVENT(EarlyDepthStencilInfoSingleSample(_simd_movemask_ps(depthPassMask), _simd_movemask_ps(stencilPassMask), _simd_movemask_ps(vCoverageMask)));
131 AR_END(BEEarlyDepthTest, 0);
132
133 // early-exit if no pixels passed depth or earlyZ is forced on
134 if (state.psState.forceEarlyZ || !_simd_movemask_ps(depthPassMask))
135 {
136 DepthStencilWrite(&state.vp[work.triFlags.viewportIndex], &state.depthStencilState, work.triFlags.frontFacing, psContext.vZ,
137 pDepthBuffer, depthPassMask, vCoverageMask, pStencilBuffer, stencilPassMask);
138
139 if (!_simd_movemask_ps(depthPassMask))
140 {
141 goto Endtile;
142 }
143 }
144 }
145
146 psContext.sampleIndex = 0;
147 psContext.activeMask = _simd_castps_si(vCoverageMask);
148
149 // execute pixel shader
150 AR_BEGIN(BEPixelShader, pDC->drawId);
151 UPDATE_STAT_BE(PsInvocations, _mm_popcnt_u32(_simd_movemask_ps(vCoverageMask)));
152 state.psState.pfnPixelShader(GetPrivateState(pDC), &psContext);
153 AR_END(BEPixelShader, 0);
154
155 vCoverageMask = _simd_castsi_ps(psContext.activeMask);
156
157 // late-Z
158 if (!T::bCanEarlyZ)
159 {
160 AR_BEGIN(BELateDepthTest, pDC->drawId);
161 depthPassMask = DepthStencilTest(&state, work.triFlags.frontFacing, work.triFlags.viewportIndex,
162 psContext.vZ, pDepthBuffer, vCoverageMask, pStencilBuffer, &stencilPassMask);
163 AR_EVENT(LateDepthStencilInfoSingleSample(_simd_movemask_ps(depthPassMask), _simd_movemask_ps(stencilPassMask), _simd_movemask_ps(vCoverageMask)));
164 AR_END(BELateDepthTest, 0);
165
166 if (!_simd_movemask_ps(depthPassMask))
167 {
168 // need to call depth/stencil write for stencil write
169 DepthStencilWrite(&state.vp[work.triFlags.viewportIndex], &state.depthStencilState, work.triFlags.frontFacing, psContext.vZ,
170 pDepthBuffer, depthPassMask, vCoverageMask, pStencilBuffer, stencilPassMask);
171 goto Endtile;
172 }
173 } else {
174 // for early z, consolidate discards from shader
175 // into depthPassMask
176 depthPassMask = _simd_and_ps(depthPassMask, vCoverageMask);
177 }
178
179 uint32_t statMask = _simd_movemask_ps(depthPassMask);
180 uint32_t statCount = _mm_popcnt_u32(statMask);
181 UPDATE_STAT_BE(DepthPassCount, statCount);
182
183 // output merger
184 AR_BEGIN(BEOutputMerger, pDC->drawId);
185 #if USE_8x2_TILE_BACKEND
186 OutputMerger8x2(psContext, psContext.pColorBuffer, 0, &state.blendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, state.psState.renderTargetMask, useAlternateOffset);
187 #else
188 OutputMerger4x2(psContext, psContext.pColorBuffer, 0, &state.blendState, state.pfnBlendFunc, vCoverageMask, depthPassMask, state.psState.renderTargetMask);
189 #endif
190
191 // do final depth write after all pixel kills
192 if (!state.psState.forceEarlyZ)
193 {
194 DepthStencilWrite(&state.vp[work.triFlags.viewportIndex], &state.depthStencilState, work.triFlags.frontFacing, psContext.vZ,
195 pDepthBuffer, depthPassMask, vCoverageMask, pStencilBuffer, stencilPassMask);
196 }
197 AR_END(BEOutputMerger, 0);
198 }
199
200 Endtile:
201 AR_BEGIN(BEEndTile, pDC->drawId);
202
203 work.coverageMask[0] >>= (SIMD_TILE_Y_DIM * SIMD_TILE_X_DIM);
204 if(T::InputCoverage == SWR_INPUT_COVERAGE_INNER_CONSERVATIVE)
205 {
206 work.innerCoverageMask >>= (SIMD_TILE_Y_DIM * SIMD_TILE_X_DIM);
207 }
208
209 #if USE_8x2_TILE_BACKEND
210 if (useAlternateOffset)
211 {
212 DWORD rt;
213 uint32_t rtMask = state.colorHottileEnable;
214 while(_BitScanForward(&rt, rtMask))
215 {
216 rtMask &= ~(1 << rt);
217 psContext.pColorBuffer[rt] += (2 * KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
218 }
219 }
220 #else
221 DWORD rt;
222 uint32_t rtMask = state.colorHottileEnable;
223 while (_BitScanForward(&rt, rtMask))
224 {
225 rtMask &= ~(1 << rt);
226 psContext.pColorBuffer[rt] += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp) / 8;
227 }
228 #endif
229 pDepthBuffer += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp) / 8;
230 pStencilBuffer += (KNOB_SIMD_WIDTH * FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp) / 8;
231
232 AR_END(BEEndTile, 0);
233
234 psContext.vX.UL = _simd_add_ps(psContext.vX.UL, dx);
235 psContext.vX.center = _simd_add_ps(psContext.vX.center, dx);
236 }
237
238 psContext.vY.UL = _simd_add_ps(psContext.vY.UL, dy);
239 psContext.vY.center = _simd_add_ps(psContext.vY.center, dy);
240 }
241
242 AR_END(BESingleSampleBackend, 0);
243 }
244
245 // Recursive template used to auto-nest conditionals. Converts dynamic enum function
246 // arguments to static template arguments.
247 template <uint32_t... ArgsT>
248 struct BEChooserSingleSample
249 {
250 // Last Arg Terminator
GetFuncBEChooserSingleSample251 static PFN_BACKEND_FUNC GetFunc(SWR_BACKEND_FUNCS tArg)
252 {
253 switch(tArg)
254 {
255 case SWR_BACKEND_SINGLE_SAMPLE: return BackendSingleSample<SwrBackendTraits<ArgsT...>>; break;
256 case SWR_BACKEND_MSAA_PIXEL_RATE:
257 case SWR_BACKEND_MSAA_SAMPLE_RATE:
258 default:
259 SWR_ASSERT(0 && "Invalid backend func\n");
260 return nullptr;
261 break;
262 }
263 }
264
265 // Recursively parse args
266 template <typename... TArgsT>
GetFuncBEChooserSingleSample267 static PFN_BACKEND_FUNC GetFunc(SWR_INPUT_COVERAGE tArg, TArgsT... remainingArgs)
268 {
269 switch(tArg)
270 {
271 case SWR_INPUT_COVERAGE_NONE: return BEChooserSingleSample<ArgsT..., SWR_INPUT_COVERAGE_NONE>::GetFunc(remainingArgs...); break;
272 case SWR_INPUT_COVERAGE_NORMAL: return BEChooserSingleSample<ArgsT..., SWR_INPUT_COVERAGE_NORMAL>::GetFunc(remainingArgs...); break;
273 case SWR_INPUT_COVERAGE_INNER_CONSERVATIVE: return BEChooserSingleSample<ArgsT..., SWR_INPUT_COVERAGE_INNER_CONSERVATIVE>::GetFunc(remainingArgs...); break;
274 default:
275 SWR_ASSERT(0 && "Invalid sample pattern\n");
276 return BEChooserSingleSample<ArgsT..., SWR_INPUT_COVERAGE_NONE>::GetFunc(remainingArgs...);
277 break;
278 }
279 }
280
281 // Recursively parse args
282 template <typename... TArgsT>
GetFuncBEChooserSingleSample283 static PFN_BACKEND_FUNC GetFunc(SWR_MULTISAMPLE_COUNT tArg, TArgsT... remainingArgs)
284 {
285 switch(tArg)
286 {
287 case SWR_MULTISAMPLE_1X: return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_1X>::GetFunc(remainingArgs...); break;
288 case SWR_MULTISAMPLE_2X: return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_2X>::GetFunc(remainingArgs...); break;
289 case SWR_MULTISAMPLE_4X: return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_4X>::GetFunc(remainingArgs...); break;
290 case SWR_MULTISAMPLE_8X: return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_8X>::GetFunc(remainingArgs...); break;
291 case SWR_MULTISAMPLE_16X: return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_16X>::GetFunc(remainingArgs...); break;
292 default:
293 SWR_ASSERT(0 && "Invalid sample count\n");
294 return BEChooserSingleSample<ArgsT..., SWR_MULTISAMPLE_1X>::GetFunc(remainingArgs...);
295 break;
296 }
297 }
298
299 // Recursively parse args
300 template <typename... TArgsT>
GetFuncBEChooserSingleSample301 static PFN_BACKEND_FUNC GetFunc(bool tArg, TArgsT... remainingArgs)
302 {
303 if(tArg == true)
304 {
305 return BEChooserSingleSample<ArgsT..., 1>::GetFunc(remainingArgs...);
306 }
307
308 return BEChooserSingleSample<ArgsT..., 0>::GetFunc(remainingArgs...);
309 }
310 };
311
InitBackendSingleFuncTable(PFN_BACKEND_FUNC (& table)[SWR_INPUT_COVERAGE_COUNT][2][2])312 void InitBackendSingleFuncTable(PFN_BACKEND_FUNC (&table)[SWR_INPUT_COVERAGE_COUNT][2][2])
313 {
314 for(uint32_t inputCoverage = 0; inputCoverage < SWR_INPUT_COVERAGE_COUNT; inputCoverage++)
315 {
316 for(uint32_t isCentroid = 0; isCentroid < 2; isCentroid++)
317 {
318 for(uint32_t canEarlyZ = 0; canEarlyZ < 2; canEarlyZ++)
319 {
320 table[inputCoverage][isCentroid][canEarlyZ] =
321 BEChooserSingleSample<>::GetFunc(SWR_MULTISAMPLE_1X, false, (SWR_INPUT_COVERAGE)inputCoverage,
322 (isCentroid > 0), false, (canEarlyZ > 0), SWR_BACKEND_SINGLE_SAMPLE);
323 }
324 }
325 }
326 }
327