GlPerVertex.cpp 34 KB

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