GlPerVertex.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. //===--- GlPerVertex.cpp - GlPerVertex implementation ------------*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "GlPerVertex.h"
  10. #include <algorithm>
  11. #include "clang/AST/Attr.h"
  12. #include "clang/AST/HlslTypes.h"
  13. #include "clang/SPIRV/AstTypeProbe.h"
  14. namespace clang {
  15. namespace spirv {
  16. namespace {
  17. constexpr uint32_t gClipDistanceIndex = 0;
  18. constexpr uint32_t gCullDistanceIndex = 1;
  19. /// \brief Returns true if the given decl has a semantic string attached and
  20. /// writes the info to *semanticStr, *semantic, and *semanticIndex.
  21. // TODO: duplication! Same as the one in DeclResultIdMapper.cpp
  22. bool getStageVarSemantic(const NamedDecl *decl, llvm::StringRef *semanticStr,
  23. const hlsl::Semantic **semantic,
  24. uint32_t *semanticIndex) {
  25. for (auto *annotation : decl->getUnusualAnnotations()) {
  26. if (auto *sema = dyn_cast<hlsl::SemanticDecl>(annotation)) {
  27. *semanticStr = sema->SemanticName;
  28. llvm::StringRef semanticName;
  29. hlsl::Semantic::DecomposeNameAndIndex(*semanticStr, &semanticName,
  30. semanticIndex);
  31. *semantic = hlsl::Semantic::GetByName(semanticName);
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. /// Returns the type of the given decl. If the given decl is a FunctionDecl,
  38. /// returns its result type.
  39. inline QualType getTypeOrFnRetType(const DeclaratorDecl *decl) {
  40. if (const auto *funcDecl = dyn_cast<FunctionDecl>(decl)) {
  41. return funcDecl->getReturnType();
  42. }
  43. return decl->getType();
  44. }
  45. /// Returns true if the given declaration has a primitive type qualifier.
  46. /// Returns false otherwise.
  47. inline bool hasGSPrimitiveTypeQualifier(const DeclaratorDecl *decl) {
  48. return decl->hasAttr<HLSLTriangleAttr>() ||
  49. decl->hasAttr<HLSLTriangleAdjAttr>() ||
  50. decl->hasAttr<HLSLPointAttr>() || decl->hasAttr<HLSLLineAttr>() ||
  51. decl->hasAttr<HLSLLineAdjAttr>();
  52. }
  53. } // anonymous namespace
  54. GlPerVertex::GlPerVertex(ASTContext &context, SpirvContext &spirvContext,
  55. SpirvBuilder &spirvBuilder)
  56. : astContext(context), spvContext(spirvContext), spvBuilder(spirvBuilder),
  57. inClipVar(nullptr), inCullVar(nullptr), outClipVar(nullptr),
  58. outCullVar(nullptr), inClipPrecise(false), outClipPrecise(false),
  59. inCullPrecise(false), outCullPrecise(false), inArraySize(0),
  60. outArraySize(0), inClipArraySize(1), outClipArraySize(1),
  61. inCullArraySize(1), outCullArraySize(1), inSemanticStrs(2, ""),
  62. outSemanticStrs(2, "") {}
  63. void GlPerVertex::generateVars(uint32_t inArrayLen, uint32_t outArrayLen) {
  64. inArraySize = inArrayLen;
  65. outArraySize = outArrayLen;
  66. if (!inClipType.empty())
  67. inClipVar = createClipCullDistanceVar(/*asInput=*/true, /*isClip=*/true,
  68. inClipArraySize, inClipPrecise);
  69. if (!inCullType.empty())
  70. inCullVar = createClipCullDistanceVar(/*asInput=*/true, /*isClip=*/false,
  71. inCullArraySize, inCullPrecise);
  72. if (!outClipType.empty())
  73. outClipVar = createClipCullDistanceVar(/*asInput=*/false, /*isClip=*/true,
  74. outClipArraySize, outClipPrecise);
  75. if (!outCullType.empty())
  76. outCullVar = createClipCullDistanceVar(/*asInput=*/false, /*isClip=*/false,
  77. outCullArraySize, outCullPrecise);
  78. }
  79. llvm::SmallVector<SpirvVariable *, 2> GlPerVertex::getStageInVars() const {
  80. llvm::SmallVector<SpirvVariable *, 2> vars;
  81. if (inClipVar)
  82. vars.push_back(inClipVar);
  83. if (inCullVar)
  84. vars.push_back(inCullVar);
  85. return vars;
  86. }
  87. llvm::SmallVector<SpirvVariable *, 2> GlPerVertex::getStageOutVars() const {
  88. llvm::SmallVector<SpirvVariable *, 2> vars;
  89. if (outClipVar)
  90. vars.push_back(outClipVar);
  91. if (outCullVar)
  92. vars.push_back(outCullVar);
  93. return vars;
  94. }
  95. bool GlPerVertex::recordGlPerVertexDeclFacts(const DeclaratorDecl *decl,
  96. bool asInput) {
  97. const QualType type = getTypeOrFnRetType(decl);
  98. if (type->isVoidType())
  99. return true;
  100. // Indices or payload mesh shader param objects don't contain any
  101. // builtin variables or semantic strings. So early return.
  102. if (decl->hasAttr<HLSLIndicesAttr>() || decl->hasAttr<HLSLPayloadAttr>()) {
  103. return true;
  104. }
  105. return doGlPerVertexFacts(decl, type, asInput);
  106. }
  107. bool GlPerVertex::doGlPerVertexFacts(const DeclaratorDecl *decl,
  108. QualType baseType, bool asInput) {
  109. llvm::StringRef semanticStr;
  110. const hlsl::Semantic *semantic = {};
  111. uint32_t semanticIndex = {};
  112. bool isPrecise = decl->hasAttr<HLSLPreciseAttr>();
  113. if (!getStageVarSemantic(decl, &semanticStr, &semantic, &semanticIndex)) {
  114. if (baseType->isStructureType()) {
  115. const auto *structDecl = baseType->getAs<RecordType>()->getDecl();
  116. // Go through each field to see if there is any usage of
  117. // SV_ClipDistance/SV_CullDistance.
  118. for (const auto *field : structDecl->fields()) {
  119. if (!doGlPerVertexFacts(field, field->getType(), asInput))
  120. return false;
  121. }
  122. return true;
  123. }
  124. // For these HS/DS/GS specific data types, semantic strings are attached
  125. // to the underlying struct's fields.
  126. if (hlsl::IsHLSLInputPatchType(baseType)) {
  127. return doGlPerVertexFacts(
  128. decl, hlsl::GetHLSLInputPatchElementType(baseType), asInput);
  129. }
  130. if (hlsl::IsHLSLOutputPatchType(baseType) ||
  131. hlsl::IsHLSLStreamOutputType(baseType)) {
  132. return doGlPerVertexFacts(
  133. decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
  134. }
  135. if (hasGSPrimitiveTypeQualifier(decl) ||
  136. decl->hasAttr<HLSLVerticesAttr>() ||
  137. decl->hasAttr<HLSLPrimitivesAttr>()) {
  138. // GS inputs and MS output attribute have an additional arrayness that we
  139. // should remove to check the underlying type instead.
  140. baseType = astContext.getAsConstantArrayType(baseType)->getElementType();
  141. return doGlPerVertexFacts(decl, baseType, asInput);
  142. }
  143. emitError("semantic string missing for shader %select{output|input}0 "
  144. "variable '%1'",
  145. decl->getLocation())
  146. << asInput << decl->getName();
  147. return false;
  148. }
  149. // Semantic string is attached to this decl directly
  150. // Select the corresponding data member to update
  151. SemanticIndexToTypeMap *typeMap = nullptr;
  152. uint32_t *blockArraySize = asInput ? &inArraySize : &outArraySize;
  153. bool isCull = false;
  154. auto *semanticStrs = asInput ? &inSemanticStrs : &outSemanticStrs;
  155. uint32_t index = kSemanticStrCount;
  156. switch (semantic->GetKind()) {
  157. case hlsl::Semantic::Kind::ClipDistance:
  158. typeMap = asInput ? &inClipType : &outClipType;
  159. index = gClipDistanceIndex;
  160. break;
  161. case hlsl::Semantic::Kind::CullDistance:
  162. typeMap = asInput ? &inCullType : &outCullType;
  163. isCull = true;
  164. index = gCullDistanceIndex;
  165. break;
  166. default:
  167. // Only Cull or Clip apply.
  168. break;
  169. }
  170. if (isCull) {
  171. if (asInput)
  172. inCullPrecise = isPrecise;
  173. else
  174. outCullPrecise = isPrecise;
  175. } else {
  176. if (asInput)
  177. inClipPrecise = isPrecise;
  178. else
  179. outClipPrecise = isPrecise;
  180. }
  181. // Remember the semantic strings provided by the developer so that we can
  182. // emit OpDecorate* instructions properly for them
  183. if (index < kSemanticStrCount) {
  184. if ((*semanticStrs)[index].empty())
  185. (*semanticStrs)[index] = semanticStr;
  186. // We can have multiple ClipDistance/CullDistance semantics mapping to the
  187. // same variable. For those cases, it is not appropriate to use any one of
  188. // them as the semantic. Use the standard one without index.
  189. else if (index == gClipDistanceIndex)
  190. (*semanticStrs)[index] = "SV_ClipDistance";
  191. else if (index == gCullDistanceIndex)
  192. (*semanticStrs)[index] = "SV_CullDistance";
  193. }
  194. if (index > gCullDistanceIndex) {
  195. // Annotated with something other than SV_ClipDistance or SV_CullDistance.
  196. // We don't care about such cases.
  197. return true;
  198. }
  199. // Parameters marked as inout has reference type.
  200. if (baseType->isReferenceType())
  201. baseType = baseType->getPointeeType();
  202. if (baseType->isFloatingType() || hlsl::IsHLSLVecType(baseType)) {
  203. (*typeMap)[semanticIndex] = baseType;
  204. return true;
  205. }
  206. if (baseType->isConstantArrayType()) {
  207. if (spvContext.isHS() || spvContext.isDS() || spvContext.isGS() ||
  208. spvContext.isMS()) {
  209. // Ignore the outermost arrayness and check the inner type to be
  210. // (vector of) floats
  211. const auto *arrayType = astContext.getAsConstantArrayType(baseType);
  212. // TODO: handle extra large array size?
  213. if (*blockArraySize !=
  214. static_cast<uint32_t>(arrayType->getSize().getZExtValue())) {
  215. emitError("inconsistent array size for shader %select{output|input}0 "
  216. "variable '%1'",
  217. decl->getLocStart())
  218. << asInput << decl->getName();
  219. return false;
  220. }
  221. const QualType elemType = arrayType->getElementType();
  222. if (elemType->isFloatingType() || hlsl::IsHLSLVecType(elemType)) {
  223. (*typeMap)[semanticIndex] = elemType;
  224. return true;
  225. }
  226. emitError("elements for %select{SV_ClipDistance|SV_CullDistance}0 "
  227. "variable '%1' must be (vector of) floats",
  228. decl->getLocStart())
  229. << isCull << decl->getName();
  230. return false;
  231. }
  232. emitError("%select{SV_ClipDistance|SV_CullDistance}0 variable '%1' not "
  233. "allowed to be of array type",
  234. decl->getLocStart())
  235. << isCull << decl->getName();
  236. return false;
  237. }
  238. emitError("incorrect type for %select{SV_ClipDistance|SV_CullDistance}0 "
  239. "variable '%1'",
  240. decl->getLocStart())
  241. << isCull << decl->getName();
  242. return false;
  243. }
  244. void GlPerVertex::calculateClipCullDistanceArraySize() {
  245. // Updates the offset map and array size for the given input/output
  246. // SV_ClipDistance/SV_CullDistance.
  247. const auto updateSizeAndOffset = [](const SemanticIndexToTypeMap &typeMap,
  248. SemanticIndexToArrayOffsetMap *offsetMap,
  249. uint32_t *totalSize) {
  250. // If no usage of SV_ClipDistance/SV_CullDistance was recorded,just
  251. // return. This will keep the size defaulted to 1.
  252. if (typeMap.empty())
  253. return;
  254. *totalSize = 0;
  255. // Collect all indices and sort them
  256. llvm::SmallVector<uint32_t, 8> indices;
  257. for (const auto &kv : typeMap)
  258. indices.push_back(kv.first);
  259. std::sort(indices.begin(), indices.end(), std::less<uint32_t>());
  260. for (uint32_t index : indices) {
  261. const auto type = typeMap.find(index)->second;
  262. QualType elemType = {};
  263. uint32_t count = 0;
  264. if (isScalarType(type)) {
  265. (*offsetMap)[index] = (*totalSize)++;
  266. } else if (isVectorType(type, &elemType, &count)) {
  267. (*offsetMap)[index] = *totalSize;
  268. *totalSize += count;
  269. } else {
  270. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or "
  271. "vector of float case sneaked in");
  272. }
  273. }
  274. };
  275. updateSizeAndOffset(inClipType, &inClipOffset, &inClipArraySize);
  276. updateSizeAndOffset(inCullType, &inCullOffset, &inCullArraySize);
  277. updateSizeAndOffset(outClipType, &outClipOffset, &outClipArraySize);
  278. updateSizeAndOffset(outCullType, &outCullOffset, &outCullArraySize);
  279. }
  280. SpirvVariable *GlPerVertex::createClipCullDistanceVar(bool asInput, bool isClip,
  281. uint32_t arraySize,
  282. bool isPrecise) {
  283. QualType type = astContext.getConstantArrayType(astContext.FloatTy,
  284. llvm::APInt(32, arraySize),
  285. clang::ArrayType::Normal, 0);
  286. if (asInput && inArraySize != 0) {
  287. type = astContext.getConstantArrayType(type, llvm::APInt(32, inArraySize),
  288. clang::ArrayType::Normal, 0);
  289. } else if (!asInput && outArraySize != 0) {
  290. type = astContext.getConstantArrayType(type, llvm::APInt(32, outArraySize),
  291. clang::ArrayType::Normal, 0);
  292. }
  293. spv::StorageClass sc =
  294. asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
  295. SpirvVariable *var = spvBuilder.addStageBuiltinVar(
  296. type, sc,
  297. isClip ? spv::BuiltIn::ClipDistance : spv::BuiltIn::CullDistance,
  298. isPrecise, /*SourceLocation*/ {});
  299. const auto index = isClip ? gClipDistanceIndex : gCullDistanceIndex;
  300. spvBuilder.decorateHlslSemantic(var, asInput ? inSemanticStrs[index]
  301. : outSemanticStrs[index]);
  302. return var;
  303. }
  304. bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
  305. hlsl::Semantic::Kind semanticKind,
  306. uint32_t semanticIndex,
  307. llvm::Optional<SpirvInstruction *> invocationId,
  308. SpirvInstruction **value, bool noWriteBack,
  309. SpirvInstruction *vecComponent,
  310. SourceLocation loc) {
  311. assert(value);
  312. // invocationId should only be used for HSPCOut or MSOut.
  313. assert(invocationId.hasValue()
  314. ? (sigPointKind == hlsl::SigPoint::Kind::HSCPOut ||
  315. sigPointKind == hlsl::SigPoint::Kind::MSOut)
  316. : true);
  317. switch (semanticKind) {
  318. case hlsl::Semantic::Kind::ClipDistance:
  319. case hlsl::Semantic::Kind::CullDistance:
  320. // gl_PerVertex only cares about these builtins.
  321. break;
  322. default:
  323. return false; // Fall back to the normal path
  324. }
  325. switch (sigPointKind) {
  326. case hlsl::SigPoint::Kind::PSIn:
  327. case hlsl::SigPoint::Kind::HSCPIn:
  328. case hlsl::SigPoint::Kind::DSCPIn:
  329. case hlsl::SigPoint::Kind::GSVIn:
  330. return readField(semanticKind, semanticIndex, value, loc);
  331. case hlsl::SigPoint::Kind::GSOut:
  332. case hlsl::SigPoint::Kind::VSOut:
  333. case hlsl::SigPoint::Kind::HSCPOut:
  334. case hlsl::SigPoint::Kind::DSOut:
  335. case hlsl::SigPoint::Kind::MSOut:
  336. if (noWriteBack)
  337. return true;
  338. return writeField(semanticKind, semanticIndex, invocationId, value,
  339. vecComponent, loc);
  340. default:
  341. // Only interfaces that involve gl_PerVertex are needed.
  342. break;
  343. }
  344. return false;
  345. }
  346. SpirvInstruction *GlPerVertex::readClipCullArrayAsType(
  347. bool isClip, uint32_t offset, QualType asType, SourceLocation loc) const {
  348. SpirvVariable *clipCullVar = isClip ? inClipVar : inCullVar;
  349. // The ClipDistance/CullDistance is always an float array. We are accessing
  350. // it using pointers, which should be of pointer to float type.
  351. const QualType f32Type = astContext.FloatTy;
  352. if (inArraySize == 0) {
  353. // The input builtin does not have extra arrayness. Only need one index
  354. // to locate the array segment for this SV_ClipDistance/SV_CullDistance
  355. // variable: the start offset within the float array.
  356. QualType elemType = {};
  357. uint32_t count = {};
  358. if (isScalarType(asType)) {
  359. auto *spirvConstant = spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  360. llvm::APInt(32, offset));
  361. auto *ptr = spvBuilder.createAccessChain(f32Type, clipCullVar,
  362. {spirvConstant}, loc);
  363. return spvBuilder.createLoad(f32Type, ptr, loc);
  364. }
  365. if (isVectorType(asType, &elemType, &count)) {
  366. // The target SV_ClipDistance/SV_CullDistance variable is of vector
  367. // type, then we need to construct a vector out of float array elements.
  368. llvm::SmallVector<SpirvInstruction *, 4> elements;
  369. for (uint32_t i = 0; i < count; ++i) {
  370. // Read elements sequentially from the float array
  371. auto *spirvConstant = spvBuilder.getConstantInt(
  372. astContext.UnsignedIntTy, llvm::APInt(32, offset + i));
  373. auto *ptr = spvBuilder.createAccessChain(f32Type, clipCullVar,
  374. {spirvConstant}, loc);
  375. elements.push_back(spvBuilder.createLoad(f32Type, ptr, loc));
  376. }
  377. return spvBuilder.createCompositeConstruct(
  378. astContext.getExtVectorType(f32Type, count), elements, loc);
  379. }
  380. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  381. "float case sneaked in");
  382. }
  383. // The input builtin block is an array of block, which means we need to
  384. // return an array of ClipDistance/CullDistance values from an array of
  385. // struct. For this case, we need three indices to locate the element to
  386. // read: the first one for indexing into the block array, the second one
  387. // for indexing into the gl_PerVertex struct, and the third one for reading
  388. // the correct element in the float array for ClipDistance/CullDistance.
  389. llvm::SmallVector<SpirvInstruction *, 8> arrayElements;
  390. QualType elemType = {};
  391. uint32_t count = {};
  392. QualType arrayType = {};
  393. if (isScalarType(asType)) {
  394. arrayType = astContext.getConstantArrayType(
  395. f32Type, llvm::APInt(32, inArraySize), clang::ArrayType::Normal, 0);
  396. for (uint32_t i = 0; i < inArraySize; ++i) {
  397. auto *ptr = spvBuilder.createAccessChain(
  398. f32Type, clipCullVar,
  399. {spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  400. llvm::APInt(32, i)), // Block array index
  401. spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  402. llvm::APInt(32, offset))},
  403. loc);
  404. arrayElements.push_back(spvBuilder.createLoad(f32Type, ptr, loc));
  405. }
  406. } else if (isVectorType(asType, &elemType, &count)) {
  407. arrayType = astContext.getConstantArrayType(
  408. astContext.getExtVectorType(f32Type, count),
  409. llvm::APInt(32, inArraySize), clang::ArrayType::Normal, 0);
  410. for (uint32_t i = 0; i < inArraySize; ++i) {
  411. // For each gl_PerVertex block, we need to read a vector from it.
  412. llvm::SmallVector<SpirvInstruction *, 4> vecElements;
  413. for (uint32_t j = 0; j < count; ++j) {
  414. auto *ptr = spvBuilder.createAccessChain(
  415. f32Type, clipCullVar,
  416. // Block array index
  417. {spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  418. llvm::APInt(32, i)),
  419. // Read elements sequentially from the float array
  420. spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  421. llvm::APInt(32, offset + j))},
  422. loc);
  423. vecElements.push_back(spvBuilder.createLoad(f32Type, ptr, loc));
  424. }
  425. arrayElements.push_back(spvBuilder.createCompositeConstruct(
  426. astContext.getExtVectorType(f32Type, count), vecElements, loc));
  427. }
  428. } else {
  429. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  430. "float case sneaked in");
  431. }
  432. return spvBuilder.createCompositeConstruct(arrayType, arrayElements, loc);
  433. }
  434. bool GlPerVertex::readField(hlsl::Semantic::Kind semanticKind,
  435. uint32_t semanticIndex, SpirvInstruction **value,
  436. SourceLocation loc) {
  437. assert(value);
  438. switch (semanticKind) {
  439. case hlsl::Semantic::Kind::ClipDistance: {
  440. const auto offsetIter = inClipOffset.find(semanticIndex);
  441. const auto typeIter = inClipType.find(semanticIndex);
  442. // We should have recorded all these semantics before.
  443. assert(offsetIter != inClipOffset.end());
  444. assert(typeIter != inClipType.end());
  445. *value = readClipCullArrayAsType(/*isClip=*/true, offsetIter->second,
  446. typeIter->second, loc);
  447. return true;
  448. }
  449. case hlsl::Semantic::Kind::CullDistance: {
  450. const auto offsetIter = inCullOffset.find(semanticIndex);
  451. const auto typeIter = inCullType.find(semanticIndex);
  452. // We should have recorded all these semantics before.
  453. assert(offsetIter != inCullOffset.end());
  454. assert(typeIter != inCullType.end());
  455. *value = readClipCullArrayAsType(/*isClip=*/false, offsetIter->second,
  456. typeIter->second, loc);
  457. return true;
  458. }
  459. default:
  460. // Only Cull or Clip apply.
  461. break;
  462. }
  463. return false;
  464. }
  465. void GlPerVertex::writeClipCullArrayFromType(
  466. llvm::Optional<SpirvInstruction *> invocationId, bool isClip,
  467. SpirvInstruction *offset, QualType fromType, SpirvInstruction *fromValue,
  468. SourceLocation loc) const {
  469. auto *clipCullVar = isClip ? outClipVar : outCullVar;
  470. // The ClipDistance/CullDistance is always an float array. We are accessing
  471. // it using pointers, which should be of pointer to float type.
  472. const QualType f32Type = astContext.FloatTy;
  473. if (outArraySize == 0) {
  474. // The output builtin does not have extra arrayness. Only need one index
  475. // to locate the array segment for this SV_ClipDistance/SV_CullDistance
  476. // variable: the start offset within the float array.
  477. QualType elemType = {};
  478. uint32_t count = {};
  479. if (isScalarType(fromType)) {
  480. auto *ptr =
  481. spvBuilder.createAccessChain(f32Type, clipCullVar, {offset}, loc);
  482. spvBuilder.createStore(ptr, fromValue, loc);
  483. return;
  484. }
  485. if (isVectorType(fromType, &elemType, &count)) {
  486. // The target SV_ClipDistance/SV_CullDistance variable is of vector
  487. // type. We need to write each component in the vector out.
  488. for (uint32_t i = 0; i < count; ++i) {
  489. // Write elements sequentially into the float array
  490. auto *constant = spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  491. llvm::APInt(32, i));
  492. auto *ptr = spvBuilder.createAccessChain(
  493. f32Type, clipCullVar,
  494. {spvBuilder.createBinaryOp(spv::Op::OpIAdd,
  495. astContext.UnsignedIntTy, offset,
  496. constant, loc)},
  497. loc);
  498. auto *subValue =
  499. spvBuilder.createCompositeExtract(f32Type, fromValue, {i}, loc);
  500. spvBuilder.createStore(ptr, subValue, loc);
  501. }
  502. return;
  503. }
  504. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  505. "float case sneaked in");
  506. return;
  507. }
  508. // Writing to an array only happens in HSCPOut or MSOut.
  509. assert(spvContext.isHS() || spvContext.isMS());
  510. // And we are only writing to the array element with InvocationId as index.
  511. assert(invocationId.hasValue());
  512. // The output builtin block is an array of block, which means we need to
  513. // write an array of ClipDistance/CullDistance values into an array of
  514. // struct. For this case, we need three indices to locate the position to
  515. // write: the first one for indexing into the block array, the second one
  516. // for indexing into the gl_PerVertex struct, and the third one for the
  517. // correct element in the float array for ClipDistance/CullDistance.
  518. SpirvInstruction *arrayIndex = invocationId.getValue();
  519. QualType elemType = {};
  520. uint32_t count = {};
  521. if (isScalarType(fromType)) {
  522. auto *ptr = spvBuilder.createAccessChain(f32Type, clipCullVar,
  523. {arrayIndex, offset}, loc);
  524. spvBuilder.createStore(ptr, fromValue, loc);
  525. return;
  526. }
  527. if (isVectorType(fromType, &elemType, &count)) {
  528. // For each gl_PerVertex block, we need to write a vector into it.
  529. for (uint32_t i = 0; i < count; ++i) {
  530. auto *ptr = spvBuilder.createAccessChain(
  531. f32Type, clipCullVar,
  532. // Block array index
  533. {arrayIndex,
  534. // Write elements sequentially into the float array
  535. spvBuilder.createBinaryOp(
  536. spv::Op::OpIAdd, astContext.UnsignedIntTy, offset,
  537. spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  538. llvm::APInt(32, i)),
  539. loc)},
  540. loc);
  541. auto *subValue =
  542. spvBuilder.createCompositeExtract(f32Type, fromValue, {i}, loc);
  543. spvBuilder.createStore(ptr, subValue, loc);
  544. }
  545. return;
  546. }
  547. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  548. "float case sneaked in");
  549. }
  550. bool GlPerVertex::writeField(hlsl::Semantic::Kind semanticKind,
  551. uint32_t semanticIndex,
  552. llvm::Optional<SpirvInstruction *> invocationId,
  553. SpirvInstruction **value,
  554. SpirvInstruction *vecComponent,
  555. SourceLocation loc) {
  556. // Similar to the writing logic in DeclResultIdMapper::createStageVars():
  557. //
  558. // Unlike reading, which may require us to read stand-alone builtins and
  559. // stage input variables and compose an array of structs out of them,
  560. // it happens that we don't need to write an array of structs in a bunch
  561. // for all shader stages:
  562. //
  563. // * VS: output is a single struct, without extra arrayness
  564. // * HS: output is an array of structs, with extra arrayness,
  565. // but we only write to the struct at the InvocationID index
  566. // * DS: output is a single struct, without extra arrayness
  567. // * GS: output is controlled by OpEmitVertex, one vertex per time
  568. // * MS: output is an array of structs, with extra arrayness
  569. //
  570. // The interesting shader stage is HS. We need the InvocationID to write
  571. // out the value to the correct array element.
  572. SpirvInstruction *offset = nullptr;
  573. QualType type = {};
  574. bool isClip = false;
  575. switch (semanticKind) {
  576. case hlsl::Semantic::Kind::ClipDistance: {
  577. const auto offsetIter = outClipOffset.find(semanticIndex);
  578. const auto typeIter = outClipType.find(semanticIndex);
  579. // We should have recorded all these semantics before.
  580. assert(offsetIter != outClipOffset.end());
  581. assert(typeIter != outClipType.end());
  582. offset = spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  583. llvm::APInt(32, offsetIter->second));
  584. type = typeIter->second;
  585. isClip = true;
  586. break;
  587. }
  588. case hlsl::Semantic::Kind::CullDistance: {
  589. const auto offsetIter = outCullOffset.find(semanticIndex);
  590. const auto typeIter = outCullType.find(semanticIndex);
  591. // We should have recorded all these semantics before.
  592. assert(offsetIter != outCullOffset.end());
  593. assert(typeIter != outCullType.end());
  594. offset = spvBuilder.getConstantInt(astContext.UnsignedIntTy,
  595. llvm::APInt(32, offsetIter->second));
  596. type = typeIter->second;
  597. break;
  598. }
  599. default:
  600. // Only Cull or Clip apply.
  601. return false;
  602. }
  603. if (vecComponent) {
  604. QualType elemType = {};
  605. if (!isVectorType(type, &elemType)) {
  606. assert(false && "expected vector type");
  607. }
  608. type = elemType;
  609. offset = spvBuilder.createBinaryOp(
  610. spv::Op::OpIAdd, astContext.UnsignedIntTy, vecComponent, offset, loc);
  611. }
  612. writeClipCullArrayFromType(invocationId, isClip, offset, type, *value, loc);
  613. return true;
  614. }
  615. } // end namespace spirv
  616. } // end namespace clang