const simdscalar vMask = _mm256_set_ps(0, -1, -1, -1, -1, -1, -1, -1);
uint32_t numClippedPrims = 0;
+#if USE_SIMD16_FRONTEND
+ const uint32_t numPrims = pa.NumPrims();
+ const uint32_t numPrims_lo = std::min<uint32_t>(numPrims, KNOB_SIMD_WIDTH);
+
+ SWR_ASSERT(numPrims <= numPrims_lo);
+
+ for (uint32_t inputPrim = 0; inputPrim < numPrims_lo; ++inputPrim)
+#else
for (uint32_t inputPrim = 0; inputPrim < pa.NumPrims(); ++inputPrim)
+#endif
{
uint32_t numEmittedVerts = pVertexCount[inputPrim];
if (numEmittedVerts < NumVertsPerPrim)
// tranpose clipper output so that each lane's vertices are in SIMD order
// set aside space for 2 vertices, as the PA will try to read up to 16 verts
// for triangle fan
+#if USE_SIMD16_FRONTEND
+ simd16vertex transposedPrims[2];
+#else
simdvertex transposedPrims[2];
+#endif
// transpose pos
uint8_t* pBase = (uint8_t*)(&vertices[0].attrib[VERTEX_POSITION_SLOT]) + sizeof(float) * inputPrim;
+
+#if USE_SIMD16_FRONTEND
+ // TEMPORARY WORKAROUND for bizarre VS2015 code-gen bug - use dx11_clipping_03-09 failures to check for existence of bug
+ static const float *dummy = reinterpret_cast<const float *>(pBase);
+#endif
+
for (uint32_t c = 0; c < 4; ++c)
{
+#if USE_SIMD16_FRONTEND
+ simdscalar temp = _simd_mask_i32gather_ps(_simd_setzero_ps(), (const float *)pBase, vOffsets, vMask, 1);
+ transposedPrims[0].attrib[VERTEX_POSITION_SLOT][c] = _simd16_insert_ps(_simd16_setzero_ps(), temp, 0);
+#else
transposedPrims[0].attrib[VERTEX_POSITION_SLOT][c] = _simd_mask_i32gather_ps(_mm256_undefined_ps(), (const float*)pBase, vOffsets, vMask, 1);
+#endif
pBase += sizeof(simdscalar);
}
uint32_t attribSlot = VERTEX_ATTRIB_START_SLOT + attrib;
for (uint32_t c = 0; c < 4; ++c)
{
+#if USE_SIMD16_FRONTEND
+ simdscalar temp = _simd_mask_i32gather_ps(_simd_setzero_ps(), (const float *)pBase, vOffsets, vMask, 1);
+ transposedPrims[0].attrib[attribSlot][c] = _simd16_insert_ps(_simd16_setzero_ps(), temp, 0);
+#else
transposedPrims[0].attrib[attribSlot][c] = _simd_mask_i32gather_ps(_mm256_undefined_ps(), (const float*)pBase, vOffsets, vMask, 1);
+#endif
pBase += sizeof(simdscalar);
}
}
pBase = (uint8_t*)(&vertices[0].attrib[VERTEX_CLIPCULL_DIST_LO_SLOT]) + sizeof(float) * inputPrim;
for (uint32_t c = 0; c < 4; ++c)
{
+#if USE_SIMD16_FRONTEND
+ simdscalar temp = _simd_mask_i32gather_ps(_simd_setzero_ps(), (const float *)pBase, vOffsets, vMask, 1);
+ transposedPrims[0].attrib[VERTEX_CLIPCULL_DIST_LO_SLOT][c] = _simd16_insert_ps(_simd16_setzero_ps(), temp, 0);
+#else
transposedPrims[0].attrib[VERTEX_CLIPCULL_DIST_LO_SLOT][c] = _simd_mask_i32gather_ps(_mm256_undefined_ps(), (const float*)pBase, vOffsets, vMask, 1);
+#endif
pBase += sizeof(simdscalar);
}
}
pBase = (uint8_t*)(&vertices[0].attrib[VERTEX_CLIPCULL_DIST_HI_SLOT]) + sizeof(float) * inputPrim;
for (uint32_t c = 0; c < 4; ++c)
{
+#if USE_SIMD16_FRONTEND
+ simdscalar temp = _simd_mask_i32gather_ps(_simd_setzero_ps(), (const float *)pBase, vOffsets, vMask, 1);
+ transposedPrims[0].attrib[VERTEX_CLIPCULL_DIST_HI_SLOT][c] = _simd16_insert_ps(_simd16_setzero_ps(), temp, 0);
+#else
transposedPrims[0].attrib[VERTEX_CLIPCULL_DIST_HI_SLOT][c] = _simd_mask_i32gather_ps(_mm256_undefined_ps(), (const float*)pBase, vOffsets, vMask, 1);
+#endif
pBase += sizeof(simdscalar);
}
}
{
do
{
+#if USE_SIMD16_FRONTEND
+ simd16vector attrib_simd16[NumVertsPerPrim];
+ bool assemble = clipPa.Assemble_simd16(VERTEX_POSITION_SLOT, attrib_simd16);
+
+ if (assemble)
+ {
+ static const uint32_t primMaskMap[] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
+
+ simdvector attrib[NumVertsPerPrim];
+ for (uint32_t i = 0; i < NumVertsPerPrim; i += 1)
+ {
+ for (uint32_t j = 0; j < 4; j += 1)
+ {
+ attrib[i][j] = _simd16_extract_ps(attrib_simd16[i][j], 0);
+ }
+ }
+
+ clipPa.useAlternateOffset = false;
+ pfnBinFunc(this->pDC, clipPa, this->workerId, attrib, primMaskMap[numEmittedPrims], _simd_set1_epi32(pPrimitiveId[inputPrim]), _simd_set1_epi32(pViewportIdx[inputPrim]));
+ }
+#else
simdvector attrib[NumVertsPerPrim];
bool assemble = clipPa.Assemble(VERTEX_POSITION_SLOT, attrib);
if (assemble)
static const uint32_t primMaskMap[] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
pfnBinFunc(this->pDC, clipPa, this->workerId, attrib, primMaskMap[numEmittedPrims], _simd_set1_epi32(pPrimitiveId[inputPrim]), _simd_set1_epi32(pViewportIdx[inputPrim]));
}
+#endif
} while (clipPa.NextPrim());
}
}
PA_STATE& pa,
uint32_t workerId,
uint32_t* pPrimData,
+#if USE_SIMD16_FRONTEND
+ uint32_t numPrims_simd8,
+#endif
uint32_t streamIndex)
{
SWR_CONTEXT *pContext = pDC->pContext;
soContext.pBuffer[i] = &state.soBuffer[i];
}
+#if USE_SIMD16_FRONTEND
+ uint32_t numPrims = numPrims_simd8;
+#else
uint32_t numPrims = pa.NumPrims();
+#endif
+
for (uint32_t primIndex = 0; primIndex < numPrims; ++primIndex)
{
DWORD slot = 0;
}
//////////////////////////////////////////////////////////////////////////
-/// Pack pairs of simdvertexes into simd16vertexes, in-place
+/// Pack pairs of simdvertexes into simd16vertexes, assume non-overlapping
///
/// vertexCount is in terms of the source simdvertexes and must be even
///
///
/// note: the stride between vertexes is determinded by KNOB_NUM_ATTRIBUTES
///
-void PackPairsOfSimdVertexIntoSimd16VertexInPlace(simdvertex *vertex, uint32_t vertexCount, uint32_t attribCount)
+void PackPairsOfSimdVertexIntoSimd16Vertex(simd16vertex *vertex_simd16, const simdvertex *vertex, uint32_t vertexCount, uint32_t attribCount)
{
SWR_ASSERT(vertex);
- SWR_ASSERT(IsEven(vertexCount));
+ SWR_ASSERT(vertex_simd16);
SWR_ASSERT(attribCount <= KNOB_NUM_ATTRIBUTES);
simd16vertex temp;
{
for (uint32_t k = 0; k < 4; k += 1)
{
- temp.attrib[j][k] = _simd16_insert_ps(_simd16_setzero_ps(), vertex[i].attrib[j][k], 0);
- temp.attrib[j][k] = _simd16_insert_ps(temp.attrib[j][k], vertex[i + 1].attrib[j][k], 1);
+ temp.attrib[j][k] = _simd16_insert_ps(_simd16_setzero_ps(), vertex[i].attrib[j][k], 0);
+
+ if ((i + 1) < vertexCount)
+ {
+ temp.attrib[j][k] = _simd16_insert_ps(temp.attrib[j][k], vertex[i + 1].attrib[j][k], 1);
+ }
}
}
for (uint32_t j = 0; j < attribCount; j += 1)
{
- reinterpret_cast<simd16vertex *>(vertex)[i >> 1].attrib[j] = temp.attrib[j];
+ vertex_simd16[i >> 1].attrib[j] = temp.attrib[j];
}
}
}
THREAD SWR_GS_CONTEXT tlsGsContext;
+#if USE_SIMD16_FRONTEND
+THREAD simd16vertex tempVertex_simd16[128];
+
+#endif
template<typename SIMDVERTEX, uint32_t SIMD_WIDTH>
struct GsBufferInfo
{
GsBufferInfo(const SWR_GS_STATE &gsState)
{
-#if USE_SIMD16_FRONTEND
- // TEMPORARY: pad up to multiple of two, to support in-place conversion from simdvertex to simd16vertex
- const uint32_t vertexCount = RoundUpEven(gsState.maxNumVerts);
-#else
const uint32_t vertexCount = gsState.maxNumVerts;
-#endif
const uint32_t vertexStride = sizeof(SIMDVERTEX);
const uint32_t numSimdBatches = (vertexCount + SIMD_WIDTH - 1) / SIMD_WIDTH;
}
#if USE_SIMD16_FRONTEND
- // TEMPORARY: GS outputs simdvertex, PA inputs simd16vertex, so convert simdvertex to simd16vertex, in-place
+ // TEMPORARY: GS outputs simdvertex, PA inputs simd16vertex, so convert simdvertex to simd16vertex
- const uint32_t attribCount = VERTEX_ATTRIB_START_SLOT + pState->numInputAttribs;
+ SWR_ASSERT(numEmittedVerts <= 256);
- PackPairsOfSimdVertexIntoSimd16VertexInPlace(
- reinterpret_cast<simdvertex *>(pBase),
- RoundUpEven(numEmittedVerts), // simd8 -> simd16
- attribCount);
+ PackPairsOfSimdVertexIntoSimd16Vertex(
+ tempVertex_simd16,
+ reinterpret_cast<const simdvertex *>(pBase),
+ numEmittedVerts,
+ KNOB_NUM_ATTRIBUTES);
#endif
#if USE_SIMD16_FRONTEND
- PA_STATE_CUT gsPa(pDC, pBase, numEmittedVerts, reinterpret_cast<simd16mask *>(pCutBuffer), numEmittedVerts, numAttribs, pState->outputTopology, processCutVerts);
+ PA_STATE_CUT gsPa(pDC, reinterpret_cast<uint8_t *>(tempVertex_simd16), numEmittedVerts, reinterpret_cast<simd16mask *>(pCutBuffer), numEmittedVerts, numAttribs, pState->outputTopology, processCutVerts);
#else
PA_STATE_CUT gsPa(pDC, pBase, numEmittedVerts, pCutBuffer, numEmittedVerts, numAttribs, pState->outputTopology, processCutVerts);
if (HasStreamOutT::value)
{
+#if USE_SIMD16_FRONTEND
+ const uint32_t numPrims = gsPa.NumPrims();
+ const uint32_t numPrims_lo = std::min<uint32_t>(numPrims, KNOB_SIMD_WIDTH);
+ const uint32_t numPrims_hi = std::max<uint32_t>(numPrims, KNOB_SIMD_WIDTH) - KNOB_SIMD_WIDTH;
+
+ gsPa.useAlternateOffset = false;
+ StreamOut(pDC, gsPa, workerId, pSoPrimData, numPrims_lo, stream);
+
+ if (numPrims_hi)
+ {
+ gsPa.useAlternateOffset = true;
+ StreamOut(pDC, gsPa, workerId, pSoPrimData, numPrims_hi, stream);
+ }
+#else
StreamOut(pDC, gsPa, workerId, pSoPrimData, stream);
+#endif
}
if (HasRastT::value && state.soState.streamToRasterizer == stream)
{
if (HasStreamOutT::value)
{
+#if USE_SIMD16_FRONTEND
+ tessPa.useAlternateOffset = false;
+ StreamOut(pDC, tessPa, workerId, pSoPrimData, numPrims_lo, 0);
+
+ if (numPrims_hi)
+ {
+ tessPa.useAlternateOffset = true;
+ StreamOut(pDC, tessPa, workerId, pSoPrimData, numPrims_hi, 0);
+ }
+#else
StreamOut(pDC, tessPa, workerId, pSoPrimData, 0);
+#endif
}
if (HasRastT::value)
void* pStreamCutBuffer = nullptr;
if (HasGeometryShaderT::value)
{
+#if USE_SIMD16_FRONTEND
+ AllocateGsBuffers<simd16vertex, KNOB_SIMD16_WIDTH>(pDC, state, &pGsOut, &pCutBuffer, &pStreamCutBuffer);
+#else
AllocateGsBuffers<simdvertex, KNOB_SIMD_WIDTH>(pDC, state, &pGsOut, &pCutBuffer, &pStreamCutBuffer);
+#endif
}
if (HasTessellationT::value)
// copy SIMD vout_lo to lo part of SIMD16 vout
{
- const uint32_t voutNumSlots = VERTEX_ATTRIB_START_SLOT + state.feNumAttributes;
+ const uint32_t attribCount = sizeof(vout.attrib) / sizeof(vout.attrib[0]);
- for (uint32_t i = 0; i < voutNumSlots; i += 1)
+ for (uint32_t i = 0; i < attribCount; i += 1)
{
for (uint32_t j = 0; j < 4; j += 1)
{
// copy SIMD vout_hi to hi part of SIMD16 vout
{
- const uint32_t voutNumSlots = VERTEX_ATTRIB_START_SLOT + state.feNumAttributes;
+ const uint32_t attribCount = sizeof(vout.attrib) / sizeof(vout.attrib[0]);
- for (uint32_t i = 0; i < voutNumSlots; i += 1)
+ for (uint32_t i = 0; i < attribCount; i += 1)
{
for (uint32_t j = 0; j < 4; j += 1)
{
// If streamout is enabled then stream vertices out to memory.
if (HasStreamOutT::value)
{
+#if 1
+ pa.useAlternateOffset = false;
+ StreamOut(pDC, pa, workerId, pSoPrimData, numPrims_lo, 0);
+
+ if (numPrims_hi)
+ {
+ pa.useAlternateOffset = true;
+ StreamOut(pDC, pa, workerId, pSoPrimData, numPrims_hi, 0);
+ }
+#else
pa.useAlternateOffset = false; // StreamOut() is SIMD16-compatible..
StreamOut(pDC, pa, workerId, pSoPrimData, 0);
+#endif
}
if (HasRastT::value)