GlPerVertex.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  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. /// \brief Returns true if the given decl has a semantic string attached and
  17. /// writes the info to *semanticStr, *semantic, and *semanticIndex.
  18. // TODO: duplication! Same as the one in DeclResultIdMapper.cpp
  19. bool getStageVarSemantic(const NamedDecl *decl, llvm::StringRef *semanticStr,
  20. const hlsl::Semantic **semantic,
  21. uint32_t *semanticIndex) {
  22. for (auto *annotation : decl->getUnusualAnnotations()) {
  23. if (auto *sema = dyn_cast<hlsl::SemanticDecl>(annotation)) {
  24. *semanticStr = sema->SemanticName;
  25. llvm::StringRef semanticName;
  26. hlsl::Semantic::DecomposeNameAndIndex(*semanticStr, &semanticName,
  27. semanticIndex);
  28. *semantic = hlsl::Semantic::GetByName(semanticName);
  29. return true;
  30. }
  31. }
  32. return false;
  33. }
  34. /// Returns the type of the given decl. If the given decl is a FunctionDecl,
  35. /// returns its result type.
  36. inline QualType getTypeOrFnRetType(const DeclaratorDecl *decl) {
  37. if (const auto *funcDecl = dyn_cast<FunctionDecl>(decl)) {
  38. return funcDecl->getReturnType();
  39. }
  40. return decl->getType();
  41. }
  42. /// Returns true if the given declaration has a primitive type qualifier.
  43. /// Returns false otherwise.
  44. inline bool hasGSPrimitiveTypeQualifier(const DeclaratorDecl *decl) {
  45. return decl->hasAttr<HLSLTriangleAttr>() ||
  46. decl->hasAttr<HLSLTriangleAdjAttr>() ||
  47. decl->hasAttr<HLSLPointAttr>() || decl->hasAttr<HLSLLineAttr>() ||
  48. decl->hasAttr<HLSLLineAdjAttr>();
  49. }
  50. } // anonymous namespace
  51. GlPerVertex::GlPerVertex(const hlsl::ShaderModel &sm, ASTContext &context,
  52. ModuleBuilder &builder, TypeTranslator &translator,
  53. bool negateY)
  54. : shaderModel(sm), astContext(context), theBuilder(builder),
  55. typeTranslator(translator), invertY(negateY), inIsGrouped(true),
  56. outIsGrouped(true), inBlockVar(0), outBlockVar(0), inClipVar(0),
  57. inCullVar(0), outClipVar(0), outCullVar(0), inArraySize(0),
  58. outArraySize(0), inClipArraySize(1), outClipArraySize(1),
  59. inCullArraySize(1), outCullArraySize(1) {}
  60. void GlPerVertex::generateVars(uint32_t inArrayLen, uint32_t outArrayLen) {
  61. // Calling this method twice is an internal error.
  62. assert(inBlockVar == 0);
  63. assert(outBlockVar == 0);
  64. inArraySize = inArrayLen;
  65. outArraySize = outArrayLen;
  66. switch (shaderModel.GetKind()) {
  67. case hlsl::ShaderModel::Kind::Vertex:
  68. outBlockVar = createBlockVar(/*asInput=*/false, 0);
  69. break;
  70. case hlsl::ShaderModel::Kind::Hull:
  71. inBlockVar = createBlockVar(/*asInput=*/true, inArraySize);
  72. outBlockVar = createBlockVar(/*asInput=*/false, outArraySize);
  73. break;
  74. case hlsl::ShaderModel::Kind::Domain:
  75. inBlockVar = createBlockVar(/*asInput=*/true, inArraySize);
  76. outBlockVar = createBlockVar(/*asInput=*/false, 0);
  77. break;
  78. case hlsl::ShaderModel::Kind::Geometry:
  79. inBlockVar = createBlockVar(/*asInput=*/true, inArraySize);
  80. if (!outClipType.empty())
  81. outClipVar = createClipDistanceVar(/*asInput=*/false, outClipArraySize);
  82. if (!outCullType.empty())
  83. outCullVar = createCullDistanceVar(/*asInput=*/false, outCullArraySize);
  84. outIsGrouped = false;
  85. break;
  86. case hlsl::ShaderModel::Kind::Pixel:
  87. if (!inClipType.empty())
  88. inClipVar = createClipDistanceVar(/*asInput=*/true, inClipArraySize);
  89. if (!inCullType.empty())
  90. inCullVar = createCullDistanceVar(/*asInput=*/true, inCullArraySize);
  91. inIsGrouped = false;
  92. break;
  93. }
  94. }
  95. llvm::SmallVector<uint32_t, 4> GlPerVertex::getStageInVars() const {
  96. llvm::SmallVector<uint32_t, 4> vars;
  97. if (inIsGrouped) {
  98. if (inBlockVar)
  99. vars.push_back(inBlockVar);
  100. } else {
  101. if (inClipVar)
  102. vars.push_back(inClipVar);
  103. if (inCullVar)
  104. vars.push_back(inCullVar);
  105. }
  106. return vars;
  107. }
  108. llvm::SmallVector<uint32_t, 4> GlPerVertex::getStageOutVars() const {
  109. llvm::SmallVector<uint32_t, 4> vars;
  110. if (outIsGrouped) {
  111. if (outBlockVar)
  112. vars.push_back(outBlockVar);
  113. } else {
  114. if (outClipVar)
  115. vars.push_back(outClipVar);
  116. if (outCullVar)
  117. vars.push_back(outCullVar);
  118. }
  119. return vars;
  120. }
  121. void GlPerVertex::requireCapabilityIfNecessary() {
  122. if (!inClipType.empty() || !outClipType.empty())
  123. theBuilder.requireCapability(spv::Capability::ClipDistance);
  124. if (!inCullType.empty() || !outCullType.empty())
  125. theBuilder.requireCapability(spv::Capability::CullDistance);
  126. }
  127. bool GlPerVertex::recordClipCullDistanceDecl(const DeclaratorDecl *decl,
  128. bool asInput) {
  129. const QualType type = getTypeOrFnRetType(decl);
  130. if (type->isVoidType())
  131. return true;
  132. return doClipCullDistanceDecl(decl, type, asInput);
  133. }
  134. bool GlPerVertex::doClipCullDistanceDecl(const DeclaratorDecl *decl,
  135. QualType baseType, bool asInput) {
  136. llvm::StringRef semanticStr;
  137. const hlsl::Semantic *semantic = {};
  138. uint32_t semanticIndex = {};
  139. if (!getStageVarSemantic(decl, &semanticStr, &semantic, &semanticIndex)) {
  140. if (baseType->isStructureType()) {
  141. const auto *structDecl = baseType->getAs<RecordType>()->getDecl();
  142. // Go through each field to see if there is any usage of
  143. // SV_ClipDistance/SV_CullDistance.
  144. for (const auto *field : structDecl->fields()) {
  145. if (!doClipCullDistanceDecl(field, field->getType(), asInput))
  146. return false;
  147. }
  148. return true;
  149. }
  150. // For these HS/DS/GS specific data types, semantic strings are attached
  151. // to the underlying struct's fields.
  152. if (hlsl::IsHLSLInputPatchType(baseType)) {
  153. return doClipCullDistanceDecl(
  154. decl, hlsl::GetHLSLInputPatchElementType(baseType), asInput);
  155. }
  156. if (hlsl::IsHLSLOutputPatchType(baseType)) {
  157. return doClipCullDistanceDecl(
  158. decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
  159. }
  160. if (hlsl::IsHLSLStreamOutputType(baseType)) {
  161. return doClipCullDistanceDecl(
  162. decl, hlsl::GetHLSLOutputPatchElementType(baseType), asInput);
  163. }
  164. if (hasGSPrimitiveTypeQualifier(decl)) {
  165. // GS inputs have an additional arrayness that we should remove to check
  166. // the underlying type instead.
  167. baseType = astContext.getAsConstantArrayType(baseType)->getElementType();
  168. return doClipCullDistanceDecl(decl, baseType, asInput);
  169. }
  170. emitError("semantic string missing for shader %select{output|input}0 "
  171. "variable '%1'",
  172. decl->getLocation())
  173. << asInput << decl->getName();
  174. return false;
  175. }
  176. // Semantic string is attched to this decl directly
  177. // Select the corresponding data member to update
  178. SemanticIndexToTypeMap *typeMap = nullptr;
  179. uint32_t *blockArraySize = asInput ? &inArraySize : &outArraySize;
  180. bool isCull = false;
  181. switch (semantic->GetKind()) {
  182. case hlsl::Semantic::Kind::ClipDistance:
  183. typeMap = asInput ? &inClipType : &outClipType;
  184. break;
  185. case hlsl::Semantic::Kind::CullDistance:
  186. typeMap = asInput ? &inCullType : &outCullType;
  187. isCull = true;
  188. break;
  189. default:
  190. // Annotated with something other than SV_ClipDistance or SV_CullDistance.
  191. // We don't care about such cases.
  192. return true;
  193. }
  194. // Parameters marked as inout has reference type.
  195. if (baseType->isReferenceType())
  196. baseType = baseType->getPointeeType();
  197. if (baseType->isFloatingType() || hlsl::IsHLSLVecType(baseType)) {
  198. (*typeMap)[semanticIndex] = baseType;
  199. return true;
  200. }
  201. if (baseType->isConstantArrayType()) {
  202. if (shaderModel.IsHS() || shaderModel.IsDS() || shaderModel.IsGS()) {
  203. // Ignore the outermost arrayness and check the inner type to be
  204. // (vector of) floats
  205. const auto *arrayType = astContext.getAsConstantArrayType(baseType);
  206. // TODO: handle extra large array size?
  207. if (*blockArraySize !=
  208. static_cast<uint32_t>(arrayType->getSize().getZExtValue())) {
  209. emitError("inconsistent array size for shader %select{output|input}0 "
  210. "variable '%1'",
  211. decl->getLocStart())
  212. << asInput << decl->getName();
  213. return false;
  214. }
  215. const QualType elemType = arrayType->getElementType();
  216. if (elemType->isFloatingType() || hlsl::IsHLSLVecType(elemType)) {
  217. (*typeMap)[semanticIndex] = elemType;
  218. return true;
  219. }
  220. emitError("elements for %select{SV_ClipDistance|SV_CullDistance}0 "
  221. "variable '%1' must be (vector of) floats",
  222. decl->getLocStart())
  223. << isCull << decl->getName();
  224. return false;
  225. }
  226. emitError("%select{SV_ClipDistance|SV_CullDistance}0 variable '%1' not "
  227. "allowed to be of array type",
  228. decl->getLocStart())
  229. << isCull << decl->getName();
  230. return false;
  231. }
  232. emitError("incorrect type for %select{SV_ClipDistance|SV_CullDistance}0 "
  233. "variable '%1'",
  234. decl->getLocStart())
  235. << isCull << decl->getName();
  236. return false;
  237. }
  238. void GlPerVertex::calculateClipCullDistanceArraySize() {
  239. // Updates the offset map and array size for the given input/output
  240. // SV_ClipDistance/SV_CullDistance.
  241. const auto updateSizeAndOffset = [](const SemanticIndexToTypeMap &typeMap,
  242. SemanticIndexToArrayOffsetMap *offsetMap,
  243. uint32_t *totalSize) {
  244. // If no usage of SV_ClipDistance/SV_CullDistance was recorded,just
  245. // return. This will keep the size defaulted to 1.
  246. if (typeMap.empty())
  247. return;
  248. *totalSize = 0;
  249. // Collect all indices and sort them
  250. llvm::SmallVector<uint32_t, 8> indices;
  251. for (const auto &kv : typeMap)
  252. indices.push_back(kv.first);
  253. std::sort(indices.begin(), indices.end(), std::less<uint32_t>());
  254. for (uint32_t index : indices) {
  255. const auto type = typeMap.find(index)->second;
  256. QualType elemType = {};
  257. uint32_t count = 0;
  258. if (TypeTranslator::isScalarType(type)) {
  259. (*offsetMap)[index] = (*totalSize)++;
  260. } else if (TypeTranslator::isVectorType(type, &elemType, &count)) {
  261. (*offsetMap)[index] = *totalSize;
  262. *totalSize += count;
  263. } else {
  264. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or "
  265. "vector of float case sneaked in");
  266. }
  267. }
  268. };
  269. updateSizeAndOffset(inClipType, &inClipOffset, &inClipArraySize);
  270. updateSizeAndOffset(inCullType, &inCullOffset, &inCullArraySize);
  271. updateSizeAndOffset(outClipType, &outClipOffset, &outClipArraySize);
  272. updateSizeAndOffset(outCullType, &outCullOffset, &outCullArraySize);
  273. }
  274. uint32_t GlPerVertex::createBlockVar(bool asInput, uint32_t arraySize) {
  275. const llvm::StringRef typeName = "type.gl_PerVertex";
  276. spv::StorageClass sc = spv::StorageClass::Input;
  277. llvm::StringRef varName = "gl_PerVertexIn";
  278. uint32_t clipSize = inClipArraySize;
  279. uint32_t cullSize = inCullArraySize;
  280. if (!asInput) {
  281. sc = spv::StorageClass::Output;
  282. varName = "gl_PerVertexOut";
  283. clipSize = outClipArraySize;
  284. cullSize = outCullArraySize;
  285. }
  286. uint32_t typeId =
  287. typeTranslator.getGlPerVertexStruct(clipSize, cullSize, typeName);
  288. // Handle the extra arrayness over the block
  289. if (arraySize != 0) {
  290. const uint32_t arraySizeId = theBuilder.getConstantUint32(arraySize);
  291. typeId = theBuilder.getArrayType(typeId, arraySizeId);
  292. }
  293. return theBuilder.addStageIOVar(typeId, sc, varName);
  294. }
  295. uint32_t GlPerVertex::createPositionVar(bool asInput) {
  296. const uint32_t type = theBuilder.getVecType(theBuilder.getFloat32Type(), 4);
  297. const spv::StorageClass sc =
  298. asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
  299. // Special handling here. Requesting Position for input means we are in
  300. // PS, which should use FragCoord instead of Position.
  301. assert(asInput ? shaderModel.IsPS() : true);
  302. const spv::BuiltIn builtin =
  303. asInput ? spv::BuiltIn::FragCoord : spv::BuiltIn::Position;
  304. return theBuilder.addStageBuiltinVar(type, sc, builtin);
  305. }
  306. uint32_t GlPerVertex::createClipDistanceVar(bool asInput, uint32_t arraySize) {
  307. const uint32_t type = theBuilder.getArrayType(
  308. theBuilder.getFloat32Type(), theBuilder.getConstantUint32(arraySize));
  309. spv::StorageClass sc =
  310. asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
  311. return theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::ClipDistance);
  312. }
  313. uint32_t GlPerVertex::createCullDistanceVar(bool asInput, uint32_t arraySize) {
  314. const uint32_t type = theBuilder.getArrayType(
  315. theBuilder.getFloat32Type(), theBuilder.getConstantUint32(arraySize));
  316. spv::StorageClass sc =
  317. asInput ? spv::StorageClass::Input : spv::StorageClass::Output;
  318. return theBuilder.addStageBuiltinVar(type, sc, spv::BuiltIn::CullDistance);
  319. }
  320. bool GlPerVertex::tryToAccess(hlsl::SigPoint::Kind sigPointKind,
  321. hlsl::Semantic::Kind semanticKind,
  322. uint32_t semanticIndex,
  323. llvm::Optional<uint32_t> invocationId,
  324. uint32_t *value, bool noWriteBack) {
  325. // invocationId should only be used for HSPCOut.
  326. assert(invocationId.hasValue() ? sigPointKind == hlsl::SigPoint::Kind::HSCPOut
  327. : true);
  328. switch (semanticKind) {
  329. case hlsl::Semantic::Kind::Position:
  330. case hlsl::Semantic::Kind::ClipDistance:
  331. case hlsl::Semantic::Kind::CullDistance:
  332. // gl_PerVertex only cares about these builtins.
  333. break;
  334. default:
  335. return false; // Fall back to the normal path
  336. }
  337. switch (sigPointKind) {
  338. case hlsl::SigPoint::Kind::PSIn:
  339. // We don't handle stand-alone Position builtin in this class.
  340. if (semanticKind == hlsl::Semantic::Kind::Position)
  341. return false; // Fall back to the normal path
  342. // Fall through
  343. case hlsl::SigPoint::Kind::HSCPIn:
  344. case hlsl::SigPoint::Kind::DSCPIn:
  345. case hlsl::SigPoint::Kind::GSVIn:
  346. return readField(semanticKind, semanticIndex, value);
  347. case hlsl::SigPoint::Kind::GSOut:
  348. // We don't handle stand-alone Position builtin in this class.
  349. if (semanticKind == hlsl::Semantic::Kind::Position)
  350. return false; // Fall back to the normal path
  351. // Fall through
  352. case hlsl::SigPoint::Kind::VSOut:
  353. case hlsl::SigPoint::Kind::HSCPOut:
  354. case hlsl::SigPoint::Kind::DSOut:
  355. if (noWriteBack)
  356. return true;
  357. return writeField(semanticKind, semanticIndex, invocationId, value);
  358. }
  359. return false;
  360. }
  361. bool GlPerVertex::tryToAccessPointSize(hlsl::SigPoint::Kind sigPointKind,
  362. llvm::Optional<uint32_t> invocation,
  363. uint32_t *value, bool noWriteBack) {
  364. switch (sigPointKind) {
  365. case hlsl::SigPoint::Kind::HSCPIn:
  366. case hlsl::SigPoint::Kind::DSCPIn:
  367. case hlsl::SigPoint::Kind::GSVIn:
  368. *value = readPositionOrPointSize(/*isPosition=*/false);
  369. return true;
  370. case hlsl::SigPoint::Kind::VSOut:
  371. case hlsl::SigPoint::Kind::HSCPOut:
  372. case hlsl::SigPoint::Kind::DSOut:
  373. writePositionOrPointSize(/*isPosition=*/false, invocation, *value);
  374. return true;
  375. }
  376. return false; // Fall back to normal path: GSOut
  377. }
  378. uint32_t GlPerVertex::readPositionOrPointSize(bool isPosition) const {
  379. // We do not handle stand-alone Position/PointSize builtin here.
  380. assert(inIsGrouped);
  381. // The PointSize builtin is always of float type.
  382. // The Position builtin is always of float4 type.
  383. const uint32_t f32Type = theBuilder.getFloat32Type();
  384. const uint32_t fieldType =
  385. isPosition ? theBuilder.getVecType(f32Type, 4) : f32Type;
  386. const uint32_t ptrType =
  387. theBuilder.getPointerType(fieldType, spv::StorageClass::Input);
  388. const uint32_t fieldIndex = theBuilder.getConstantUint32(isPosition ? 0 : 1);
  389. if (inArraySize == 0) {
  390. // The input builtin block is a single block. Only need one index to
  391. // locate the Position/PointSize builtin.
  392. const uint32_t ptr =
  393. theBuilder.createAccessChain(ptrType, inBlockVar, {fieldIndex});
  394. return theBuilder.createLoad(fieldType, ptr);
  395. }
  396. // The input builtin block is an array of blocks, which means we need to
  397. // read an array of float4 from an array of structs.
  398. llvm::SmallVector<uint32_t, 8> elements;
  399. for (uint32_t i = 0; i < inArraySize; ++i) {
  400. const uint32_t arrayIndex = theBuilder.getConstantUint32(i);
  401. // Get pointer into the array of structs. We need two indices to locate
  402. // the Position/PointSize builtin now: the first one is the array index,
  403. // and the second one is the struct index.
  404. const uint32_t ptr = theBuilder.createAccessChain(ptrType, inBlockVar,
  405. {arrayIndex, fieldIndex});
  406. elements.push_back(theBuilder.createLoad(fieldType, ptr));
  407. }
  408. // Construct a new array of float4/float for the Position/PointSize builtins
  409. const uint32_t arrayType = theBuilder.getArrayType(
  410. fieldType, theBuilder.getConstantUint32(inArraySize));
  411. return theBuilder.createCompositeConstruct(arrayType, elements);
  412. }
  413. uint32_t GlPerVertex::readClipCullArrayAsType(bool isClip, uint32_t offset,
  414. QualType asType) const {
  415. const uint32_t clipCullIndex = isClip ? 2 : 3;
  416. // The ClipDistance/CullDistance is always an float array. We are accessing
  417. // it using pointers, which should be of pointer to float type.
  418. const uint32_t f32Type = theBuilder.getFloat32Type();
  419. const uint32_t ptrType =
  420. theBuilder.getPointerType(f32Type, spv::StorageClass::Input);
  421. if (inArraySize == 0) {
  422. // The input builtin block is a single block. Only need two indices to
  423. // locate the array segment for this SV_ClipDistance/SV_CullDistance
  424. // variable: one is the index in the gl_PerVertex struct, the other is
  425. // the start offset within the float array.
  426. QualType elemType = {};
  427. uint32_t count = {};
  428. if (TypeTranslator::isScalarType(asType)) {
  429. const uint32_t offsetId = theBuilder.getConstantUint32(offset);
  430. uint32_t ptr = 0;
  431. if (inIsGrouped) {
  432. ptr = theBuilder.createAccessChain(
  433. ptrType, inBlockVar,
  434. {theBuilder.getConstantUint32(clipCullIndex), offsetId});
  435. } else {
  436. ptr = theBuilder.createAccessChain(
  437. ptrType, clipCullIndex == 2 ? inClipVar : inCullVar, {offsetId});
  438. }
  439. return theBuilder.createLoad(f32Type, ptr);
  440. }
  441. if (TypeTranslator::isVectorType(asType, &elemType, &count)) {
  442. // The target SV_ClipDistance/SV_CullDistance variable is of vector
  443. // type, then we need to construct a vector out of float array elements.
  444. llvm::SmallVector<uint32_t, 4> elements;
  445. for (uint32_t i = 0; i < count; ++i) {
  446. // Read elements sequentially from the float array
  447. const uint32_t offsetId = theBuilder.getConstantUint32(offset + i);
  448. uint32_t ptr = 0;
  449. if (inIsGrouped) {
  450. ptr = theBuilder.createAccessChain(
  451. ptrType, inBlockVar,
  452. {theBuilder.getConstantUint32(clipCullIndex), offsetId});
  453. } else {
  454. ptr = theBuilder.createAccessChain(
  455. ptrType, clipCullIndex == 2 ? inClipVar : inCullVar, {offsetId});
  456. }
  457. elements.push_back(theBuilder.createLoad(f32Type, ptr));
  458. }
  459. return theBuilder.createCompositeConstruct(
  460. theBuilder.getVecType(f32Type, count), elements);
  461. }
  462. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  463. "float case sneaked in");
  464. }
  465. // The input builtin block is an array of block, which means we need to
  466. // return an array of ClipDistance/CullDistance values from an array of
  467. // struct. For this case, we need three indices to locate the element to
  468. // read: the first one for indexing into the block array, the second one
  469. // for indexing into the gl_PerVertex struct, and the third one for reading
  470. // the correct element in the float array for ClipDistance/CullDistance.
  471. assert(inIsGrouped); // Separated builtins won't have the extra arrayness.
  472. llvm::SmallVector<uint32_t, 8> arrayElements;
  473. QualType elemType = {};
  474. uint32_t count = {};
  475. uint32_t arrayType = {};
  476. uint32_t arraySize = theBuilder.getConstantUint32(inArraySize);
  477. if (TypeTranslator::isScalarType(asType)) {
  478. arrayType = theBuilder.getArrayType(f32Type, arraySize);
  479. for (uint32_t i = 0; i < inArraySize; ++i) {
  480. const uint32_t ptr = theBuilder.createAccessChain(
  481. ptrType, inBlockVar,
  482. {theBuilder.getConstantUint32(i), // Block array index
  483. theBuilder.getConstantUint32(clipCullIndex),
  484. theBuilder.getConstantUint32(offset)});
  485. arrayElements.push_back(theBuilder.createLoad(f32Type, ptr));
  486. }
  487. } else if (TypeTranslator::isVectorType(asType, &elemType, &count)) {
  488. arrayType = theBuilder.getArrayType(theBuilder.getVecType(f32Type, count),
  489. arraySize);
  490. for (uint32_t i = 0; i < inArraySize; ++i) {
  491. // For each gl_PerVertex block, we need to read a vector from it.
  492. llvm::SmallVector<uint32_t, 4> vecElements;
  493. for (uint32_t j = 0; j < count; ++j) {
  494. const uint32_t ptr = theBuilder.createAccessChain(
  495. ptrType, inBlockVar,
  496. {theBuilder.getConstantUint32(i), // Block array index
  497. theBuilder.getConstantUint32(clipCullIndex),
  498. // Read elements sequentially from the float array
  499. theBuilder.getConstantUint32(offset + j)});
  500. vecElements.push_back(theBuilder.createLoad(f32Type, ptr));
  501. }
  502. arrayElements.push_back(theBuilder.createCompositeConstruct(
  503. theBuilder.getVecType(f32Type, count), vecElements));
  504. }
  505. } else {
  506. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  507. "float case sneaked in");
  508. }
  509. return theBuilder.createCompositeConstruct(arrayType, arrayElements);
  510. };
  511. bool GlPerVertex::readField(hlsl::Semantic::Kind semanticKind,
  512. uint32_t semanticIndex, uint32_t *value) {
  513. switch (semanticKind) {
  514. case hlsl::Semantic::Kind::Position:
  515. *value = readPositionOrPointSize(/*isPosition=*/true);
  516. return true;
  517. case hlsl::Semantic::Kind::ClipDistance: {
  518. const auto offsetIter = inClipOffset.find(semanticIndex);
  519. const auto typeIter = inClipType.find(semanticIndex);
  520. // We should have recorded all these semantics before.
  521. assert(offsetIter != inClipOffset.end());
  522. assert(typeIter != inClipType.end());
  523. *value = readClipCullArrayAsType(/*isClip=*/true, offsetIter->second,
  524. typeIter->second);
  525. return true;
  526. }
  527. case hlsl::Semantic::Kind::CullDistance: {
  528. const auto offsetIter = inCullOffset.find(semanticIndex);
  529. const auto typeIter = inCullType.find(semanticIndex);
  530. // We should have recorded all these semantics before.
  531. assert(offsetIter != inCullOffset.end());
  532. assert(typeIter != inCullType.end());
  533. *value = readClipCullArrayAsType(/*isClip=*/false, offsetIter->second,
  534. typeIter->second);
  535. return true;
  536. }
  537. }
  538. return false;
  539. }
  540. void GlPerVertex::writePositionOrPointSize(
  541. bool isPosition, llvm::Optional<uint32_t> invocationId, uint32_t value) {
  542. // We do not handle stand-alone Position/PointSize builtin here.
  543. assert(outIsGrouped);
  544. // The Position builtin is always of float4 type.
  545. // The PointSize builtin is always of float type.
  546. const uint32_t f32Type = theBuilder.getFloat32Type();
  547. const uint32_t fieldType =
  548. isPosition ? theBuilder.getVecType(f32Type, 4) : f32Type;
  549. const uint32_t ptrType =
  550. theBuilder.getPointerType(fieldType, spv::StorageClass::Output);
  551. const uint32_t fieldIndex = theBuilder.getConstantUint32(isPosition ? 0 : 1);
  552. if (outArraySize == 0) {
  553. // The input builtin block is a single block. Only need one index to
  554. // locate the Position/PointSize builtin.
  555. const uint32_t ptr =
  556. theBuilder.createAccessChain(ptrType, outBlockVar, {fieldIndex});
  557. if (isPosition && invertY) {
  558. if (shaderModel.IsVS() || shaderModel.IsDS()) {
  559. const auto oldY =
  560. theBuilder.createCompositeExtract(f32Type, value, {1});
  561. const auto newY =
  562. theBuilder.createUnaryOp(spv::Op::OpFNegate, f32Type, oldY);
  563. value = theBuilder.createCompositeInsert(fieldType, value, {1}, newY);
  564. }
  565. }
  566. theBuilder.createStore(ptr, value);
  567. return;
  568. }
  569. // Writing to an array only happens in HSCPOut.
  570. assert(shaderModel.IsHS());
  571. // And we are only writing to the array element with InvocationId as index.
  572. assert(invocationId.hasValue());
  573. // The input builtin block is an array of blocks, which means we need to
  574. // to write a float4 to each gl_PerVertex in the array.
  575. const uint32_t arrayIndex = invocationId.getValue();
  576. // Get pointer into the array of structs. We need two indices to locate
  577. // the Position/PointSize builtin now: the first one is the array index,
  578. // and the second one is the struct index.
  579. const uint32_t ptr = theBuilder.createAccessChain(ptrType, outBlockVar,
  580. {arrayIndex, fieldIndex});
  581. theBuilder.createStore(ptr, value);
  582. }
  583. void GlPerVertex::writeClipCullArrayFromType(
  584. llvm::Optional<uint32_t> invocationId, bool isClip, uint32_t offset,
  585. QualType fromType, uint32_t fromValue) const {
  586. const uint32_t clipCullIndex = isClip ? 2 : 3;
  587. // The ClipDistance/CullDistance is always an float array. We are accessing
  588. // it using pointers, which should be of pointer to float type.
  589. const uint32_t f32Type = theBuilder.getFloat32Type();
  590. const uint32_t ptrType =
  591. theBuilder.getPointerType(f32Type, spv::StorageClass::Output);
  592. if (outArraySize == 0) {
  593. // The input builtin block is a single block. Only need two indices to
  594. // locate the array segment for this SV_ClipDistance/SV_CullDistance
  595. // variable: one is the index in the gl_PerVertex struct, the other is
  596. // the start offset within the float array.
  597. QualType elemType = {};
  598. uint32_t count = {};
  599. if (TypeTranslator::isScalarType(fromType)) {
  600. const uint32_t offsetId = theBuilder.getConstantUint32(offset);
  601. uint32_t ptr = 0;
  602. if (outIsGrouped) {
  603. ptr = theBuilder.createAccessChain(
  604. ptrType, outBlockVar,
  605. {theBuilder.getConstantUint32(clipCullIndex), offsetId});
  606. } else {
  607. ptr = theBuilder.createAccessChain(
  608. ptrType, clipCullIndex == 2 ? outClipVar : outCullVar, {offsetId});
  609. }
  610. theBuilder.createStore(ptr, fromValue);
  611. return;
  612. }
  613. if (TypeTranslator::isVectorType(fromType, &elemType, &count)) {
  614. // The target SV_ClipDistance/SV_CullDistance variable is of vector
  615. // type. We need to write each component in the vector out.
  616. for (uint32_t i = 0; i < count; ++i) {
  617. // Write elements sequentially into the float array
  618. const uint32_t offsetId = theBuilder.getConstantUint32(offset + i);
  619. uint32_t ptr = 0;
  620. if (outIsGrouped) {
  621. ptr = theBuilder.createAccessChain(
  622. ptrType, outBlockVar,
  623. {theBuilder.getConstantUint32(clipCullIndex), offsetId});
  624. } else {
  625. ptr = theBuilder.createAccessChain(
  626. ptrType, clipCullIndex == 2 ? outClipVar : outCullVar,
  627. {offsetId});
  628. }
  629. const uint32_t subValue =
  630. theBuilder.createCompositeExtract(f32Type, fromValue, {i});
  631. theBuilder.createStore(ptr, subValue);
  632. }
  633. return;
  634. }
  635. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  636. "float case sneaked in");
  637. return;
  638. }
  639. assert(outIsGrouped); // Separated builtins won't have the extra arrayness.
  640. // Writing to an array only happens in HSCPOut.
  641. assert(shaderModel.IsHS());
  642. // And we are only writing to the array element with InvocationId as index.
  643. assert(invocationId.hasValue());
  644. // The output builtin block is an array of block, which means we need to
  645. // write an array of ClipDistance/CullDistance values into an array of
  646. // struct. For this case, we need three indices to locate the position to
  647. // write: the first one for indexing into the block array, the second one
  648. // for indexing into the gl_PerVertex struct, and the third one for the
  649. // correct element in the float array for ClipDistance/CullDistance.
  650. uint32_t arrayIndex = invocationId.getValue();
  651. QualType elemType = {};
  652. uint32_t count = {};
  653. if (TypeTranslator::isScalarType(fromType)) {
  654. const uint32_t ptr = theBuilder.createAccessChain(
  655. ptrType, outBlockVar,
  656. {arrayIndex, // Block array index
  657. theBuilder.getConstantUint32(clipCullIndex),
  658. theBuilder.getConstantUint32(offset)});
  659. theBuilder.createStore(ptr, fromValue);
  660. return;
  661. }
  662. if (TypeTranslator::isVectorType(fromType, &elemType, &count)) {
  663. // For each gl_PerVertex block, we need to write a vector into it.
  664. for (uint32_t i = 0; i < count; ++i) {
  665. const uint32_t ptr = theBuilder.createAccessChain(
  666. ptrType, outBlockVar,
  667. {arrayIndex, // Block array index
  668. theBuilder.getConstantUint32(clipCullIndex),
  669. // Write elements sequentially into the float array
  670. theBuilder.getConstantUint32(offset + i)});
  671. const uint32_t subValue =
  672. theBuilder.createCompositeExtract(f32Type, fromValue, {i});
  673. theBuilder.createStore(ptr, subValue);
  674. }
  675. return;
  676. }
  677. llvm_unreachable("SV_ClipDistance/SV_CullDistance not float or vector of "
  678. "float case sneaked in");
  679. };
  680. bool GlPerVertex::writeField(hlsl::Semantic::Kind semanticKind,
  681. uint32_t semanticIndex,
  682. llvm::Optional<uint32_t> invocationId,
  683. uint32_t *value) {
  684. // Similar to the writing logic in DeclResultIdMapper::createStageVars():
  685. //
  686. // Unlike reading, which may require us to read stand-alone builtins and
  687. // stage input variables and compose an array of structs out of them,
  688. // it happens that we don't need to write an array of structs in a bunch
  689. // for all shader stages:
  690. //
  691. // * VS: output is a single struct, without extra arrayness
  692. // * HS: output is an array of structs, with extra arrayness,
  693. // but we only write to the struct at the InvocationID index
  694. // * DS: output is a single struct, without extra arrayness
  695. // * GS: output is controlled by OpEmitVertex, one vertex per time
  696. //
  697. // The interesting shader stage is HS. We need the InvocationID to write
  698. // out the value to the correct array element.
  699. switch (semanticKind) {
  700. case hlsl::Semantic::Kind::Position:
  701. writePositionOrPointSize(/*isPosition=*/true, invocationId, *value);
  702. return true;
  703. case hlsl::Semantic::Kind::ClipDistance: {
  704. const auto offsetIter = outClipOffset.find(semanticIndex);
  705. const auto typeIter = outClipType.find(semanticIndex);
  706. // We should have recorded all these semantics before.
  707. assert(offsetIter != outClipOffset.end());
  708. assert(typeIter != outClipType.end());
  709. writeClipCullArrayFromType(invocationId, /*isClip=*/true,
  710. offsetIter->second, typeIter->second, *value);
  711. return true;
  712. }
  713. case hlsl::Semantic::Kind::CullDistance: {
  714. const auto offsetIter = outCullOffset.find(semanticIndex);
  715. const auto typeIter = outCullType.find(semanticIndex);
  716. // We should have recorded all these semantics before.
  717. assert(offsetIter != outCullOffset.end());
  718. assert(typeIter != outCullType.end());
  719. writeClipCullArrayFromType(invocationId, /*isClip=*/false,
  720. offsetIter->second, typeIter->second, *value);
  721. return true;
  722. }
  723. }
  724. return false;
  725. }
  726. } // end namespace spirv
  727. } // end namespace clang