GlPerVertex.cpp 24 KB

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