+ iface->pBuilder->swr_gs_llvm_emit_vertex(gs_base, bld_base,
+ outputs,
+ emitted_vertices_vec);
+}
+
+static void
+swr_gs_llvm_end_primitive(const struct lp_build_tgsi_gs_iface *gs_base,
+ struct lp_build_tgsi_context * bld_base,
+ LLVMValueRef verts_per_prim_vec,
+ LLVMValueRef emitted_prims_vec)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_base;
+
+ iface->pBuilder->swr_gs_llvm_end_primitive(gs_base, bld_base,
+ verts_per_prim_vec,
+ emitted_prims_vec);
+}
+
+static void
+swr_gs_llvm_epilogue(const struct lp_build_tgsi_gs_iface *gs_base,
+ struct lp_build_tgsi_context * bld_base,
+ LLVMValueRef total_emitted_vertices_vec,
+ LLVMValueRef emitted_prims_vec)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_base;
+
+ iface->pBuilder->swr_gs_llvm_epilogue(gs_base, bld_base,
+ total_emitted_vertices_vec,
+ emitted_prims_vec);
+}
+
+LLVMValueRef
+BuilderSWR::swr_gs_llvm_fetch_input(const struct lp_build_tgsi_gs_iface *gs_iface,
+ struct lp_build_tgsi_context * bld_base,
+ boolean is_vindex_indirect,
+ LLVMValueRef vertex_index,
+ boolean is_aindex_indirect,
+ LLVMValueRef attrib_index,
+ LLVMValueRef swizzle_index)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_iface;
+ Value *vert_index = unwrap(vertex_index);
+ Value *attr_index = unwrap(attrib_index);
+
+ IRB()->SetInsertPoint(unwrap(LLVMGetInsertBlock(gallivm->builder)));
+
+ if (is_vindex_indirect || is_aindex_indirect) {
+ int i;
+ Value *res = unwrap(bld_base->base.zero);
+ struct lp_type type = bld_base->base.type;
+
+ for (i = 0; i < type.length; i++) {
+ Value *vert_chan_index = vert_index;
+ Value *attr_chan_index = attr_index;
+
+ if (is_vindex_indirect) {
+ vert_chan_index = VEXTRACT(vert_index, C(i));
+ }
+ if (is_aindex_indirect) {
+ attr_chan_index = VEXTRACT(attr_index, C(i));
+ }
+
+ Value *attrib =
+ LOAD(GEP(iface->pVtxAttribMap, {C(0), attr_chan_index}));
+
+ Value *pVertex = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_pVerts});
+ Value *pInputVertStride = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_inputVertStride});
+
+ Value *pVector = ADD(MUL(vert_chan_index, pInputVertStride), attrib);
+ Value *pInput = LOAD(GEP(pVertex, {pVector, unwrap(swizzle_index)}));
+
+ Value *value = VEXTRACT(pInput, C(i));
+ res = VINSERT(res, value, C(i));
+ }
+
+ return wrap(res);
+ } else {
+ Value *attrib = LOAD(GEP(iface->pVtxAttribMap, {C(0), attr_index}));
+
+ Value *pVertex = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_pVerts});
+ Value *pInputVertStride = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_inputVertStride});
+
+ Value *pVector = ADD(MUL(vert_index, pInputVertStride), attrib);
+
+ Value *pInput = LOAD(GEP(pVertex, {pVector, unwrap(swizzle_index)}));
+
+ return wrap(pInput);
+ }
+}
+
+// GS output stream layout
+#define VERTEX_COUNT_SIZE 32
+#define CONTROL_HEADER_SIZE (8*32)
+
+void
+BuilderSWR::swr_gs_llvm_emit_vertex(const struct lp_build_tgsi_gs_iface *gs_base,
+ struct lp_build_tgsi_context * bld_base,
+ LLVMValueRef (*outputs)[4],
+ LLVMValueRef emitted_vertices_vec)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_base;
+
+ IRB()->SetInsertPoint(unwrap(LLVMGetInsertBlock(gallivm->builder)));
+
+ const uint32_t headerSize = VERTEX_COUNT_SIZE + CONTROL_HEADER_SIZE;
+ const uint32_t attribSize = 4 * sizeof(float);
+ const uint32_t vertSize = attribSize * SWR_VTX_NUM_SLOTS;
+ Value *pVertexOffset = MUL(unwrap(emitted_vertices_vec), VIMMED1(vertSize));
+
+ Value *vMask = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_mask});
+ Value *vMask1 = TRUNC(vMask, VectorType::get(mInt1Ty, mVWidth));
+
+ Value *pStack = STACKSAVE();
+ Value *pTmpPtr = ALLOCA(mFP32Ty, C(4)); // used for dummy write for lane masking
+
+ for (uint32_t attrib = 0; attrib < iface->num_outputs; ++attrib) {
+ uint32_t attribSlot = attrib;
+ uint32_t sgvChannel = 0;
+ if (iface->info->output_semantic_name[attrib] == TGSI_SEMANTIC_PSIZE) {
+ attribSlot = VERTEX_SGV_SLOT;
+ sgvChannel = VERTEX_SGV_POINT_SIZE_COMP;
+ } else if (iface->info->output_semantic_name[attrib] == TGSI_SEMANTIC_LAYER) {
+ attribSlot = VERTEX_SGV_SLOT;
+ sgvChannel = VERTEX_SGV_RTAI_COMP;
+ } else if (iface->info->output_semantic_name[attrib] == TGSI_SEMANTIC_VIEWPORT_INDEX) {
+ attribSlot = VERTEX_SGV_SLOT;
+ sgvChannel = VERTEX_SGV_VAI_COMP;
+ } else if (iface->info->output_semantic_name[attrib] == TGSI_SEMANTIC_POSITION) {
+ attribSlot = VERTEX_POSITION_SLOT;
+ } else {
+ attribSlot = VERTEX_ATTRIB_START_SLOT + attrib;
+ if (iface->info->writes_position) {
+ attribSlot--;
+ }
+ }
+
+ Value *pOutputOffset = ADD(pVertexOffset, VIMMED1(headerSize + attribSize * attribSlot)); // + sgvChannel ?
+
+ for (uint32_t lane = 0; lane < mVWidth; ++lane) {
+ Value *pLaneOffset = VEXTRACT(pOutputOffset, C(lane));
+ Value *pStream = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_pStreams, lane});
+ Value *pStreamOffset = GEP(pStream, pLaneOffset);
+ pStreamOffset = BITCAST(pStreamOffset, mFP32PtrTy);
+
+ Value *pLaneMask = VEXTRACT(vMask1, C(lane));
+ pStreamOffset = SELECT(pLaneMask, pStreamOffset, pTmpPtr);
+
+ for (uint32_t channel = 0; channel < 4; ++channel) {
+ Value *vData;
+
+ if (attribSlot == VERTEX_SGV_SLOT)
+ vData = LOAD(unwrap(outputs[attrib][0]));
+ else
+ vData = LOAD(unwrap(outputs[attrib][channel]));
+
+ if (attribSlot != VERTEX_SGV_SLOT ||
+ sgvChannel == channel) {
+ vData = VEXTRACT(vData, C(lane));
+ STORE(vData, pStreamOffset);
+ }
+ pStreamOffset = GEP(pStreamOffset, C(1));
+ }
+ }
+ }
+
+ STACKRESTORE(pStack);
+}
+
+void
+BuilderSWR::swr_gs_llvm_end_primitive(const struct lp_build_tgsi_gs_iface *gs_base,
+ struct lp_build_tgsi_context * bld_base,
+ LLVMValueRef verts_per_prim_vec,
+ LLVMValueRef emitted_prims_vec)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_base;
+
+ IRB()->SetInsertPoint(unwrap(LLVMGetInsertBlock(gallivm->builder)));
+
+ Value *vMask = LOAD(iface->pGsCtx, { 0, SWR_GS_CONTEXT_mask });
+ Value *vMask1 = TRUNC(vMask, VectorType::get(mInt1Ty, 8));
+
+ uint32_t vertsPerPrim = iface->num_verts_per_prim;
+
+ Value *vCount =
+ ADD(MUL(unwrap(emitted_prims_vec), VIMMED1(vertsPerPrim)),
+ unwrap(verts_per_prim_vec));
+
+ struct lp_build_tgsi_soa_context *bld = lp_soa_context(bld_base);
+ vCount = LOAD(unwrap(bld->total_emitted_vertices_vec_ptr));
+
+ struct lp_exec_mask *exec_mask = &bld->exec_mask;
+ Value *mask = unwrap(lp_build_mask_value(bld->mask));
+ if (exec_mask->has_mask)
+ mask = AND(mask, unwrap(exec_mask->exec_mask));
+
+ Value *cmpMask = VMASK(ICMP_NE(unwrap(verts_per_prim_vec), VIMMED1(0)));
+ mask = AND(mask, cmpMask);
+ vMask1 = TRUNC(mask, VectorType::get(mInt1Ty, 8));
+
+ vCount = SUB(vCount, VIMMED1(1));
+ Value *vOffset = ADD(UDIV(vCount, VIMMED1(8)), VIMMED1(VERTEX_COUNT_SIZE));
+ Value *vValue = SHL(VIMMED1(1), UREM(vCount, VIMMED1(8)));
+
+ vValue = TRUNC(vValue, VectorType::get(mInt8Ty, 8));
+
+ Value *pStack = STACKSAVE();
+ Value *pTmpPtr = ALLOCA(mInt8Ty, C(4)); // used for dummy read/write for lane masking
+
+ for (uint32_t lane = 0; lane < mVWidth; ++lane) {
+ Value *vLaneOffset = VEXTRACT(vOffset, C(lane));
+ Value *pStream = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_pStreams, lane});
+ Value *pStreamOffset = GEP(pStream, vLaneOffset);
+
+ Value *pLaneMask = VEXTRACT(vMask1, C(lane));
+ pStreamOffset = SELECT(pLaneMask, pStreamOffset, pTmpPtr);
+
+ Value *vVal = LOAD(pStreamOffset);
+ vVal = OR(vVal, VEXTRACT(vValue, C(lane)));
+ STORE(vVal, pStreamOffset);
+ }
+
+ STACKRESTORE(pStack);
+}
+
+void
+BuilderSWR::swr_gs_llvm_epilogue(const struct lp_build_tgsi_gs_iface *gs_base,
+ struct lp_build_tgsi_context * bld_base,
+ LLVMValueRef total_emitted_vertices_vec,
+ LLVMValueRef emitted_prims_vec)
+{
+ swr_gs_llvm_iface *iface = (swr_gs_llvm_iface*)gs_base;
+
+ IRB()->SetInsertPoint(unwrap(LLVMGetInsertBlock(gallivm->builder)));
+
+ // Store emit count to each output stream in the first DWORD
+ for (uint32_t lane = 0; lane < mVWidth; ++lane)
+ {
+ Value* pStream = LOAD(iface->pGsCtx, {0, SWR_GS_CONTEXT_pStreams, lane});
+ pStream = BITCAST(pStream, mInt32PtrTy);
+ Value* pLaneCount = VEXTRACT(unwrap(total_emitted_vertices_vec), C(lane));
+ STORE(pLaneCount, pStream);