validate_builtins.cpp 168 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953
  1. // Copyright (c) 2018 Google LLC.
  2. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
  3. // reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // Validates correctness of built-in variables.
  17. #include <array>
  18. #include <functional>
  19. #include <list>
  20. #include <map>
  21. #include <set>
  22. #include <sstream>
  23. #include <stack>
  24. #include <string>
  25. #include <unordered_map>
  26. #include <vector>
  27. #include "source/diagnostic.h"
  28. #include "source/opcode.h"
  29. #include "source/spirv_target_env.h"
  30. #include "source/util/bitutils.h"
  31. #include "source/val/instruction.h"
  32. #include "source/val/validate.h"
  33. #include "source/val/validation_state.h"
  34. namespace spvtools {
  35. namespace val {
  36. namespace {
  37. // Returns a short textual description of the id defined by the given
  38. // instruction.
  39. std::string GetIdDesc(const Instruction& inst) {
  40. std::ostringstream ss;
  41. ss << "ID <" << inst.id() << "> (Op" << spvOpcodeString(inst.opcode()) << ")";
  42. return ss.str();
  43. }
  44. // Gets underlying data type which is
  45. // - member type if instruction is OpTypeStruct
  46. // (member index is taken from decoration).
  47. // - data type if id creates a pointer.
  48. // - type of the constant if instruction is OpConst or OpSpecConst.
  49. //
  50. // Fails in any other case. The function is based on built-ins allowed by
  51. // the Vulkan spec.
  52. // TODO: If non-Vulkan validation rules are added then it might need
  53. // to be refactored.
  54. spv_result_t GetUnderlyingType(ValidationState_t& _,
  55. const Decoration& decoration,
  56. const Instruction& inst,
  57. uint32_t* underlying_type) {
  58. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  59. if (inst.opcode() != SpvOpTypeStruct) {
  60. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  61. << GetIdDesc(inst)
  62. << "Attempted to get underlying data type via member index for "
  63. "non-struct type.";
  64. }
  65. *underlying_type = inst.word(decoration.struct_member_index() + 2);
  66. return SPV_SUCCESS;
  67. }
  68. if (inst.opcode() == SpvOpTypeStruct) {
  69. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  70. << GetIdDesc(inst)
  71. << " did not find an member index to get underlying data type for "
  72. "struct type.";
  73. }
  74. if (spvOpcodeIsConstant(inst.opcode())) {
  75. *underlying_type = inst.type_id();
  76. return SPV_SUCCESS;
  77. }
  78. uint32_t storage_class = 0;
  79. if (!_.GetPointerTypeInfo(inst.type_id(), underlying_type, &storage_class)) {
  80. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  81. << GetIdDesc(inst)
  82. << " is decorated with BuiltIn. BuiltIn decoration should only be "
  83. "applied to struct types, variables and constants.";
  84. }
  85. return SPV_SUCCESS;
  86. }
  87. // Returns Storage Class used by the instruction if applicable.
  88. // Returns SpvStorageClassMax if not.
  89. SpvStorageClass GetStorageClass(const Instruction& inst) {
  90. switch (inst.opcode()) {
  91. case SpvOpTypePointer:
  92. case SpvOpTypeForwardPointer: {
  93. return SpvStorageClass(inst.word(2));
  94. }
  95. case SpvOpVariable: {
  96. return SpvStorageClass(inst.word(3));
  97. }
  98. case SpvOpGenericCastToPtrExplicit: {
  99. return SpvStorageClass(inst.word(4));
  100. }
  101. default: { break; }
  102. }
  103. return SpvStorageClassMax;
  104. }
  105. typedef enum VUIDError_ {
  106. VUIDErrorExecutionModel = 0,
  107. VUIDErrorStorageClass = 1,
  108. VUIDErrorType = 2,
  109. VUIDErrorMax,
  110. } VUIDError;
  111. const static uint32_t NumVUIDBuiltins = 29;
  112. typedef struct {
  113. SpvBuiltIn builtIn;
  114. uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
  115. } BuiltinVUIDMapping;
  116. std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
  117. // clang-format off
  118. {SpvBuiltInSubgroupEqMask, {0, 4370, 4371}},
  119. {SpvBuiltInSubgroupGeMask, {0, 4372, 4373}},
  120. {SpvBuiltInSubgroupGtMask, {0, 4374, 4375}},
  121. {SpvBuiltInSubgroupLeMask, {0, 4376, 4377}},
  122. {SpvBuiltInSubgroupLtMask, {0, 4378, 4379}},
  123. {SpvBuiltInSubgroupLocalInvocationId, {0, 4380, 4381}},
  124. {SpvBuiltInSubgroupSize, {0, 4382, 4383}},
  125. {SpvBuiltInGlobalInvocationId, {4236, 4237, 4238}},
  126. {SpvBuiltInLocalInvocationId, {4281, 4282, 4283}},
  127. {SpvBuiltInNumWorkgroups, {4296, 4297, 4298}},
  128. {SpvBuiltInNumSubgroups, {4293, 4294, 4295}},
  129. {SpvBuiltInSubgroupId, {4367, 4368, 4369}},
  130. {SpvBuiltInWorkgroupId, {4422, 4423, 4424}},
  131. {SpvBuiltInHitKindKHR, {4242, 4243, 4244}},
  132. {SpvBuiltInHitTNV, {4245, 4246, 4247}},
  133. {SpvBuiltInInstanceCustomIndexKHR, {4251, 4252, 4253}},
  134. {SpvBuiltInInstanceId, {4254, 4255, 4256}},
  135. {SpvBuiltInRayGeometryIndexKHR, {4345, 4346, 4347}},
  136. {SpvBuiltInObjectRayDirectionKHR, {4299, 4300, 4301}},
  137. {SpvBuiltInObjectRayOriginKHR, {4302, 4303, 4304}},
  138. {SpvBuiltInObjectToWorldKHR, {4305, 4306, 4307}},
  139. {SpvBuiltInWorldToObjectKHR, {4434, 4435, 4436}},
  140. {SpvBuiltInIncomingRayFlagsKHR, {4248, 4249, 4250}},
  141. {SpvBuiltInRayTminKHR, {4351, 4352, 4353}},
  142. {SpvBuiltInRayTmaxKHR, {4348, 4349, 4350}},
  143. {SpvBuiltInWorldRayDirectionKHR, {4428, 4429, 4430}},
  144. {SpvBuiltInWorldRayOriginKHR, {4431, 4432, 4433}},
  145. {SpvBuiltInLaunchIdKHR, {4266, 4267, 4268}},
  146. {SpvBuiltInLaunchSizeKHR, {4269, 4270, 4271}},
  147. // clang-format off
  148. } };
  149. uint32_t GetVUIDForBuiltin(SpvBuiltIn builtIn, VUIDError type) {
  150. uint32_t vuid = 0;
  151. for (const auto& iter: builtinVUIDInfo) {
  152. if (iter.builtIn == builtIn) {
  153. assert(type < VUIDErrorMax);
  154. vuid = iter.vuid[type];
  155. break;
  156. }
  157. }
  158. return vuid;
  159. }
  160. bool IsExecutionModelValidForRtBuiltIn(SpvBuiltIn builtin,
  161. SpvExecutionModel stage) {
  162. switch (builtin) {
  163. case SpvBuiltInHitKindKHR:
  164. case SpvBuiltInHitTNV:
  165. if (stage == SpvExecutionModelAnyHitKHR ||
  166. stage == SpvExecutionModelClosestHitKHR) {
  167. return true;
  168. }
  169. break;
  170. case SpvBuiltInInstanceCustomIndexKHR:
  171. case SpvBuiltInInstanceId:
  172. case SpvBuiltInRayGeometryIndexKHR:
  173. case SpvBuiltInObjectRayDirectionKHR:
  174. case SpvBuiltInObjectRayOriginKHR:
  175. case SpvBuiltInObjectToWorldKHR:
  176. case SpvBuiltInWorldToObjectKHR:
  177. switch (stage) {
  178. case SpvExecutionModelIntersectionKHR:
  179. case SpvExecutionModelAnyHitKHR:
  180. case SpvExecutionModelClosestHitKHR:
  181. return true;
  182. default:
  183. return false;
  184. }
  185. break;
  186. case SpvBuiltInIncomingRayFlagsKHR:
  187. case SpvBuiltInRayTminKHR:
  188. case SpvBuiltInRayTmaxKHR:
  189. case SpvBuiltInWorldRayDirectionKHR:
  190. case SpvBuiltInWorldRayOriginKHR:
  191. switch (stage) {
  192. case SpvExecutionModelIntersectionKHR:
  193. case SpvExecutionModelAnyHitKHR:
  194. case SpvExecutionModelClosestHitKHR:
  195. case SpvExecutionModelMissKHR:
  196. return true;
  197. default:
  198. return false;
  199. }
  200. break;
  201. case SpvBuiltInLaunchIdKHR:
  202. case SpvBuiltInLaunchSizeKHR:
  203. switch (stage) {
  204. case SpvExecutionModelRayGenerationKHR:
  205. case SpvExecutionModelIntersectionKHR:
  206. case SpvExecutionModelAnyHitKHR:
  207. case SpvExecutionModelClosestHitKHR:
  208. case SpvExecutionModelMissKHR:
  209. case SpvExecutionModelCallableKHR:
  210. return true;
  211. default:
  212. return false;
  213. }
  214. break;
  215. default:
  216. break;
  217. }
  218. return false;
  219. }
  220. // Helper class managing validation of built-ins.
  221. // TODO: Generic functionality of this class can be moved into
  222. // ValidationState_t to be made available to other users.
  223. class BuiltInsValidator {
  224. public:
  225. BuiltInsValidator(ValidationState_t& vstate) : _(vstate) {}
  226. // Run validation.
  227. spv_result_t Run();
  228. private:
  229. // Goes through all decorations in the module, if decoration is BuiltIn
  230. // calls ValidateSingleBuiltInAtDefinition().
  231. spv_result_t ValidateBuiltInsAtDefinition();
  232. // Validates the instruction defining an id with built-in decoration.
  233. // Can be called multiple times for the same id, if multiple built-ins are
  234. // specified. Seeds id_to_at_reference_checks_ with decorated ids if needed.
  235. spv_result_t ValidateSingleBuiltInAtDefinition(const Decoration& decoration,
  236. const Instruction& inst);
  237. // The following section contains functions which are called when id defined
  238. // by |inst| is decorated with BuiltIn |decoration|.
  239. // Most functions are specific to a single built-in and have naming scheme:
  240. // ValidateXYZAtDefinition. Some functions are common to multiple kinds of
  241. // BuiltIn.
  242. spv_result_t ValidateClipOrCullDistanceAtDefinition(
  243. const Decoration& decoration, const Instruction& inst);
  244. spv_result_t ValidateFragCoordAtDefinition(const Decoration& decoration,
  245. const Instruction& inst);
  246. spv_result_t ValidateFragDepthAtDefinition(const Decoration& decoration,
  247. const Instruction& inst);
  248. spv_result_t ValidateFrontFacingAtDefinition(const Decoration& decoration,
  249. const Instruction& inst);
  250. spv_result_t ValidateHelperInvocationAtDefinition(
  251. const Decoration& decoration, const Instruction& inst);
  252. spv_result_t ValidateInvocationIdAtDefinition(const Decoration& decoration,
  253. const Instruction& inst);
  254. spv_result_t ValidateInstanceIndexAtDefinition(const Decoration& decoration,
  255. const Instruction& inst);
  256. spv_result_t ValidateLayerOrViewportIndexAtDefinition(
  257. const Decoration& decoration, const Instruction& inst);
  258. spv_result_t ValidatePatchVerticesAtDefinition(const Decoration& decoration,
  259. const Instruction& inst);
  260. spv_result_t ValidatePointCoordAtDefinition(const Decoration& decoration,
  261. const Instruction& inst);
  262. spv_result_t ValidatePointSizeAtDefinition(const Decoration& decoration,
  263. const Instruction& inst);
  264. spv_result_t ValidatePositionAtDefinition(const Decoration& decoration,
  265. const Instruction& inst);
  266. spv_result_t ValidatePrimitiveIdAtDefinition(const Decoration& decoration,
  267. const Instruction& inst);
  268. spv_result_t ValidateSampleIdAtDefinition(const Decoration& decoration,
  269. const Instruction& inst);
  270. spv_result_t ValidateSampleMaskAtDefinition(const Decoration& decoration,
  271. const Instruction& inst);
  272. spv_result_t ValidateSamplePositionAtDefinition(const Decoration& decoration,
  273. const Instruction& inst);
  274. spv_result_t ValidateTessCoordAtDefinition(const Decoration& decoration,
  275. const Instruction& inst);
  276. spv_result_t ValidateTessLevelOuterAtDefinition(const Decoration& decoration,
  277. const Instruction& inst);
  278. spv_result_t ValidateTessLevelInnerAtDefinition(const Decoration& decoration,
  279. const Instruction& inst);
  280. spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
  281. const Instruction& inst);
  282. spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
  283. const Instruction& inst);
  284. spv_result_t ValidateLocalInvocationIndexAtDefinition(
  285. const Decoration& decoration, const Instruction& inst);
  286. spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
  287. const Instruction& inst);
  288. spv_result_t ValidateBaseInstanceOrVertexAtDefinition(
  289. const Decoration& decoration, const Instruction& inst);
  290. spv_result_t ValidateDrawIndexAtDefinition(const Decoration& decoration,
  291. const Instruction& inst);
  292. spv_result_t ValidateViewIndexAtDefinition(const Decoration& decoration,
  293. const Instruction& inst);
  294. spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration,
  295. const Instruction& inst);
  296. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  297. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
  298. const Decoration& decoration, const Instruction& inst);
  299. spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration,
  300. const Instruction& inst);
  301. // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
  302. // SubgroupLeMask.
  303. spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
  304. const Instruction& inst);
  305. // Used for SubgroupLocalInvocationId, SubgroupSize.
  306. spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
  307. const Instruction& inst);
  308. // Used for SubgroupId, NumSubgroups.
  309. spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
  310. const Instruction& inst);
  311. spv_result_t ValidatePrimitiveShadingRateAtDefinition(
  312. const Decoration& decoration, const Instruction& inst);
  313. spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
  314. const Instruction& inst);
  315. spv_result_t ValidateRayTracingBuiltinsAtDefinition(
  316. const Decoration& decoration, const Instruction& inst);
  317. // The following section contains functions which are called when id defined
  318. // by |referenced_inst| is
  319. // 1. referenced by |referenced_from_inst|
  320. // 2. dependent on |built_in_inst| which is decorated with BuiltIn
  321. // |decoration|. Most functions are specific to a single built-in and have
  322. // naming scheme: ValidateXYZAtReference. Some functions are common to
  323. // multiple kinds of BuiltIn.
  324. spv_result_t ValidateFragCoordAtReference(
  325. const Decoration& decoration, const Instruction& built_in_inst,
  326. const Instruction& referenced_inst,
  327. const Instruction& referenced_from_inst);
  328. spv_result_t ValidateFragDepthAtReference(
  329. const Decoration& decoration, const Instruction& built_in_inst,
  330. const Instruction& referenced_inst,
  331. const Instruction& referenced_from_inst);
  332. spv_result_t ValidateFrontFacingAtReference(
  333. const Decoration& decoration, const Instruction& built_in_inst,
  334. const Instruction& referenced_inst,
  335. const Instruction& referenced_from_inst);
  336. spv_result_t ValidateHelperInvocationAtReference(
  337. const Decoration& decoration, const Instruction& built_in_inst,
  338. const Instruction& referenced_inst,
  339. const Instruction& referenced_from_inst);
  340. spv_result_t ValidateInvocationIdAtReference(
  341. const Decoration& decoration, const Instruction& built_in_inst,
  342. const Instruction& referenced_inst,
  343. const Instruction& referenced_from_inst);
  344. spv_result_t ValidateInstanceIndexAtReference(
  345. const Decoration& decoration, const Instruction& built_in_inst,
  346. const Instruction& referenced_inst,
  347. const Instruction& referenced_from_inst);
  348. spv_result_t ValidatePatchVerticesAtReference(
  349. const Decoration& decoration, const Instruction& built_in_inst,
  350. const Instruction& referenced_inst,
  351. const Instruction& referenced_from_inst);
  352. spv_result_t ValidatePointCoordAtReference(
  353. const Decoration& decoration, const Instruction& built_in_inst,
  354. const Instruction& referenced_inst,
  355. const Instruction& referenced_from_inst);
  356. spv_result_t ValidatePointSizeAtReference(
  357. const Decoration& decoration, const Instruction& built_in_inst,
  358. const Instruction& referenced_inst,
  359. const Instruction& referenced_from_inst);
  360. spv_result_t ValidatePositionAtReference(
  361. const Decoration& decoration, const Instruction& built_in_inst,
  362. const Instruction& referenced_inst,
  363. const Instruction& referenced_from_inst);
  364. spv_result_t ValidatePrimitiveIdAtReference(
  365. const Decoration& decoration, const Instruction& built_in_inst,
  366. const Instruction& referenced_inst,
  367. const Instruction& referenced_from_inst);
  368. spv_result_t ValidateSampleIdAtReference(
  369. const Decoration& decoration, const Instruction& built_in_inst,
  370. const Instruction& referenced_inst,
  371. const Instruction& referenced_from_inst);
  372. spv_result_t ValidateSampleMaskAtReference(
  373. const Decoration& decoration, const Instruction& built_in_inst,
  374. const Instruction& referenced_inst,
  375. const Instruction& referenced_from_inst);
  376. spv_result_t ValidateSamplePositionAtReference(
  377. const Decoration& decoration, const Instruction& built_in_inst,
  378. const Instruction& referenced_inst,
  379. const Instruction& referenced_from_inst);
  380. spv_result_t ValidateTessCoordAtReference(
  381. const Decoration& decoration, const Instruction& built_in_inst,
  382. const Instruction& referenced_inst,
  383. const Instruction& referenced_from_inst);
  384. spv_result_t ValidateTessLevelAtReference(
  385. const Decoration& decoration, const Instruction& built_in_inst,
  386. const Instruction& referenced_inst,
  387. const Instruction& referenced_from_inst);
  388. spv_result_t ValidateLocalInvocationIndexAtReference(
  389. const Decoration& decoration, const Instruction& built_in_inst,
  390. const Instruction& referenced_inst,
  391. const Instruction& referenced_from_inst);
  392. spv_result_t ValidateVertexIndexAtReference(
  393. const Decoration& decoration, const Instruction& built_in_inst,
  394. const Instruction& referenced_inst,
  395. const Instruction& referenced_from_inst);
  396. spv_result_t ValidateLayerOrViewportIndexAtReference(
  397. const Decoration& decoration, const Instruction& built_in_inst,
  398. const Instruction& referenced_inst,
  399. const Instruction& referenced_from_inst);
  400. spv_result_t ValidateWorkgroupSizeAtReference(
  401. const Decoration& decoration, const Instruction& built_in_inst,
  402. const Instruction& referenced_inst,
  403. const Instruction& referenced_from_inst);
  404. spv_result_t ValidateClipOrCullDistanceAtReference(
  405. const Decoration& decoration, const Instruction& built_in_inst,
  406. const Instruction& referenced_inst,
  407. const Instruction& referenced_from_inst);
  408. spv_result_t ValidateBaseInstanceOrVertexAtReference(
  409. const Decoration& decoration, const Instruction& built_in_inst,
  410. const Instruction& referenced_inst,
  411. const Instruction& referenced_from_inst);
  412. spv_result_t ValidateDrawIndexAtReference(
  413. const Decoration& decoration, const Instruction& built_in_inst,
  414. const Instruction& referenced_inst,
  415. const Instruction& referenced_from_inst);
  416. spv_result_t ValidateViewIndexAtReference(
  417. const Decoration& decoration, const Instruction& built_in_inst,
  418. const Instruction& referenced_inst,
  419. const Instruction& referenced_from_inst);
  420. spv_result_t ValidateDeviceIndexAtReference(
  421. const Decoration& decoration, const Instruction& built_in_inst,
  422. const Instruction& referenced_inst,
  423. const Instruction& referenced_from_inst);
  424. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  425. spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
  426. const Decoration& decoration, const Instruction& built_in_inst,
  427. const Instruction& referenced_inst,
  428. const Instruction& referenced_from_inst);
  429. // Used for SubgroupId and NumSubgroups.
  430. spv_result_t ValidateComputeI32InputAtReference(
  431. const Decoration& decoration, const Instruction& built_in_inst,
  432. const Instruction& referenced_inst,
  433. const Instruction& referenced_from_inst);
  434. spv_result_t ValidateSMBuiltinsAtReference(
  435. const Decoration& decoration, const Instruction& built_in_inst,
  436. const Instruction& referenced_inst,
  437. const Instruction& referenced_from_inst);
  438. spv_result_t ValidatePrimitiveShadingRateAtReference(
  439. const Decoration& decoration, const Instruction& built_in_inst,
  440. const Instruction& referenced_inst,
  441. const Instruction& referenced_from_inst);
  442. spv_result_t ValidateShadingRateAtReference(
  443. const Decoration& decoration, const Instruction& built_in_inst,
  444. const Instruction& referenced_inst,
  445. const Instruction& referenced_from_inst);
  446. spv_result_t ValidateRayTracingBuiltinsAtReference(
  447. const Decoration& decoration, const Instruction& built_in_inst,
  448. const Instruction& referenced_inst,
  449. const Instruction& referenced_from_inst);
  450. // Validates that |built_in_inst| is not (even indirectly) referenced from
  451. // within a function which can be called with |execution_model|.
  452. //
  453. // |vuid| - Vulkan ID for the error, or a negative value if none.
  454. // |comment| - text explaining why the restriction was imposed.
  455. // |decoration| - BuiltIn decoration which causes the restriction.
  456. // |referenced_inst| - instruction which is dependent on |built_in_inst| and
  457. // defines the id which was referenced.
  458. // |referenced_from_inst| - instruction which references id defined by
  459. // |referenced_inst| from within a function.
  460. spv_result_t ValidateNotCalledWithExecutionModel(
  461. int vuid, const char* comment, SpvExecutionModel execution_model,
  462. const Decoration& decoration, const Instruction& built_in_inst,
  463. const Instruction& referenced_inst,
  464. const Instruction& referenced_from_inst);
  465. // The following section contains functions which check that the decorated
  466. // variable has the type specified in the function name. |diag| would be
  467. // called with a corresponding error message, if validation is not successful.
  468. spv_result_t ValidateBool(
  469. const Decoration& decoration, const Instruction& inst,
  470. const std::function<spv_result_t(const std::string& message)>& diag);
  471. spv_result_t ValidateI32(
  472. const Decoration& decoration, const Instruction& inst,
  473. const std::function<spv_result_t(const std::string& message)>& diag);
  474. spv_result_t ValidateI32Vec(
  475. const Decoration& decoration, const Instruction& inst,
  476. uint32_t num_components,
  477. const std::function<spv_result_t(const std::string& message)>& diag);
  478. spv_result_t ValidateI32Arr(
  479. const Decoration& decoration, const Instruction& inst,
  480. const std::function<spv_result_t(const std::string& message)>& diag);
  481. spv_result_t ValidateOptionalArrayedI32(
  482. const Decoration& decoration, const Instruction& inst,
  483. const std::function<spv_result_t(const std::string& message)>& diag);
  484. spv_result_t ValidateI32Helper(
  485. const Decoration& decoration, const Instruction& inst,
  486. const std::function<spv_result_t(const std::string& message)>& diag,
  487. uint32_t underlying_type);
  488. spv_result_t ValidateF32(
  489. const Decoration& decoration, const Instruction& inst,
  490. const std::function<spv_result_t(const std::string& message)>& diag);
  491. spv_result_t ValidateOptionalArrayedF32(
  492. const Decoration& decoration, const Instruction& inst,
  493. const std::function<spv_result_t(const std::string& message)>& diag);
  494. spv_result_t ValidateF32Helper(
  495. const Decoration& decoration, const Instruction& inst,
  496. const std::function<spv_result_t(const std::string& message)>& diag,
  497. uint32_t underlying_type);
  498. spv_result_t ValidateF32Vec(
  499. const Decoration& decoration, const Instruction& inst,
  500. uint32_t num_components,
  501. const std::function<spv_result_t(const std::string& message)>& diag);
  502. spv_result_t ValidateOptionalArrayedF32Vec(
  503. const Decoration& decoration, const Instruction& inst,
  504. uint32_t num_components,
  505. const std::function<spv_result_t(const std::string& message)>& diag);
  506. spv_result_t ValidateF32VecHelper(
  507. const Decoration& decoration, const Instruction& inst,
  508. uint32_t num_components,
  509. const std::function<spv_result_t(const std::string& message)>& diag,
  510. uint32_t underlying_type);
  511. // If |num_components| is zero, the number of components is not checked.
  512. spv_result_t ValidateF32Arr(
  513. const Decoration& decoration, const Instruction& inst,
  514. uint32_t num_components,
  515. const std::function<spv_result_t(const std::string& message)>& diag);
  516. spv_result_t ValidateOptionalArrayedF32Arr(
  517. const Decoration& decoration, const Instruction& inst,
  518. uint32_t num_components,
  519. const std::function<spv_result_t(const std::string& message)>& diag);
  520. spv_result_t ValidateF32ArrHelper(
  521. const Decoration& decoration, const Instruction& inst,
  522. uint32_t num_components,
  523. const std::function<spv_result_t(const std::string& message)>& diag,
  524. uint32_t underlying_type);
  525. spv_result_t ValidateF32Mat(
  526. const Decoration& decoration, const Instruction& inst,
  527. uint32_t req_num_rows, uint32_t req_num_columns,
  528. const std::function<spv_result_t(const std::string& message)>& diag);
  529. // Generates strings like "Member #0 of struct ID <2>".
  530. std::string GetDefinitionDesc(const Decoration& decoration,
  531. const Instruction& inst) const;
  532. // Generates strings like "ID <51> (OpTypePointer) is referencing ID <2>
  533. // (OpTypeStruct) which is decorated with BuiltIn Position".
  534. std::string GetReferenceDesc(
  535. const Decoration& decoration, const Instruction& built_in_inst,
  536. const Instruction& referenced_inst,
  537. const Instruction& referenced_from_inst,
  538. SpvExecutionModel execution_model = SpvExecutionModelMax) const;
  539. // Generates strings like "ID <51> (OpTypePointer) uses storage class
  540. // UniformConstant".
  541. std::string GetStorageClassDesc(const Instruction& inst) const;
  542. // Updates inner working of the class. Is called sequentially for every
  543. // instruction.
  544. void Update(const Instruction& inst);
  545. ValidationState_t& _;
  546. // Mapping id -> list of rules which validate instruction referencing the
  547. // id. Rules can create new rules and add them to this container.
  548. // Using std::map, and not std::unordered_map to avoid iterator invalidation
  549. // during rehashing.
  550. std::map<uint32_t, std::list<std::function<spv_result_t(const Instruction&)>>>
  551. id_to_at_reference_checks_;
  552. // Id of the function we are currently inside. 0 if not inside a function.
  553. uint32_t function_id_ = 0;
  554. // Entry points which can (indirectly) call the current function.
  555. // The pointer either points to a vector inside to function_to_entry_points_
  556. // or to no_entry_points_. The pointer is guaranteed to never be null.
  557. const std::vector<uint32_t> no_entry_points;
  558. const std::vector<uint32_t>* entry_points_ = &no_entry_points;
  559. // Execution models with which the current function can be called.
  560. std::set<SpvExecutionModel> execution_models_;
  561. };
  562. void BuiltInsValidator::Update(const Instruction& inst) {
  563. const SpvOp opcode = inst.opcode();
  564. if (opcode == SpvOpFunction) {
  565. // Entering a function.
  566. assert(function_id_ == 0);
  567. function_id_ = inst.id();
  568. execution_models_.clear();
  569. entry_points_ = &_.FunctionEntryPoints(function_id_);
  570. // Collect execution models from all entry points from which the current
  571. // function can be called.
  572. for (const uint32_t entry_point : *entry_points_) {
  573. if (const auto* models = _.GetExecutionModels(entry_point)) {
  574. execution_models_.insert(models->begin(), models->end());
  575. }
  576. }
  577. }
  578. if (opcode == SpvOpFunctionEnd) {
  579. // Exiting a function.
  580. assert(function_id_ != 0);
  581. function_id_ = 0;
  582. entry_points_ = &no_entry_points;
  583. execution_models_.clear();
  584. }
  585. }
  586. std::string BuiltInsValidator::GetDefinitionDesc(
  587. const Decoration& decoration, const Instruction& inst) const {
  588. std::ostringstream ss;
  589. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  590. assert(inst.opcode() == SpvOpTypeStruct);
  591. ss << "Member #" << decoration.struct_member_index();
  592. ss << " of struct ID <" << inst.id() << ">";
  593. } else {
  594. ss << GetIdDesc(inst);
  595. }
  596. return ss.str();
  597. }
  598. std::string BuiltInsValidator::GetReferenceDesc(
  599. const Decoration& decoration, const Instruction& built_in_inst,
  600. const Instruction& referenced_inst, const Instruction& referenced_from_inst,
  601. SpvExecutionModel execution_model) const {
  602. std::ostringstream ss;
  603. ss << GetIdDesc(referenced_from_inst) << " is referencing "
  604. << GetIdDesc(referenced_inst);
  605. if (built_in_inst.id() != referenced_inst.id()) {
  606. ss << " which is dependent on " << GetIdDesc(built_in_inst);
  607. }
  608. ss << " which is decorated with BuiltIn ";
  609. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  610. decoration.params()[0]);
  611. if (function_id_) {
  612. ss << " in function <" << function_id_ << ">";
  613. if (execution_model != SpvExecutionModelMax) {
  614. ss << " called with execution model ";
  615. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
  616. execution_model);
  617. }
  618. }
  619. ss << ".";
  620. return ss.str();
  621. }
  622. std::string BuiltInsValidator::GetStorageClassDesc(
  623. const Instruction& inst) const {
  624. std::ostringstream ss;
  625. ss << GetIdDesc(inst) << " uses storage class ";
  626. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_STORAGE_CLASS,
  627. GetStorageClass(inst));
  628. ss << ".";
  629. return ss.str();
  630. }
  631. spv_result_t BuiltInsValidator::ValidateBool(
  632. const Decoration& decoration, const Instruction& inst,
  633. const std::function<spv_result_t(const std::string& message)>& diag) {
  634. uint32_t underlying_type = 0;
  635. if (spv_result_t error =
  636. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  637. return error;
  638. }
  639. if (!_.IsBoolScalarType(underlying_type)) {
  640. return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
  641. }
  642. return SPV_SUCCESS;
  643. }
  644. spv_result_t BuiltInsValidator::ValidateI32(
  645. const Decoration& decoration, const Instruction& inst,
  646. const std::function<spv_result_t(const std::string& message)>& diag) {
  647. uint32_t underlying_type = 0;
  648. if (spv_result_t error =
  649. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  650. return error;
  651. }
  652. return ValidateI32Helper(decoration, inst, diag, underlying_type);
  653. }
  654. spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32(
  655. const Decoration& decoration, const Instruction& inst,
  656. const std::function<spv_result_t(const std::string& message)>& diag) {
  657. uint32_t underlying_type = 0;
  658. if (spv_result_t error =
  659. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  660. return error;
  661. }
  662. // Strip the array, if present.
  663. if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) {
  664. underlying_type = _.FindDef(underlying_type)->word(2u);
  665. }
  666. return ValidateI32Helper(decoration, inst, diag, underlying_type);
  667. }
  668. spv_result_t BuiltInsValidator::ValidateI32Helper(
  669. const Decoration& decoration, const Instruction& inst,
  670. const std::function<spv_result_t(const std::string& message)>& diag,
  671. uint32_t underlying_type) {
  672. if (!_.IsIntScalarType(underlying_type)) {
  673. return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
  674. }
  675. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  676. if (bit_width != 32) {
  677. std::ostringstream ss;
  678. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  679. << ".";
  680. return diag(ss.str());
  681. }
  682. return SPV_SUCCESS;
  683. }
  684. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32(
  685. const Decoration& decoration, const Instruction& inst,
  686. const std::function<spv_result_t(const std::string& message)>& diag) {
  687. uint32_t underlying_type = 0;
  688. if (spv_result_t error =
  689. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  690. return error;
  691. }
  692. // Strip the array, if present.
  693. if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) {
  694. underlying_type = _.FindDef(underlying_type)->word(2u);
  695. }
  696. return ValidateF32Helper(decoration, inst, diag, underlying_type);
  697. }
  698. spv_result_t BuiltInsValidator::ValidateF32(
  699. const Decoration& decoration, const Instruction& inst,
  700. const std::function<spv_result_t(const std::string& message)>& diag) {
  701. uint32_t underlying_type = 0;
  702. if (spv_result_t error =
  703. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  704. return error;
  705. }
  706. return ValidateF32Helper(decoration, inst, diag, underlying_type);
  707. }
  708. spv_result_t BuiltInsValidator::ValidateF32Helper(
  709. const Decoration& decoration, const Instruction& inst,
  710. const std::function<spv_result_t(const std::string& message)>& diag,
  711. uint32_t underlying_type) {
  712. if (!_.IsFloatScalarType(underlying_type)) {
  713. return diag(GetDefinitionDesc(decoration, inst) +
  714. " is not a float scalar.");
  715. }
  716. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  717. if (bit_width != 32) {
  718. std::ostringstream ss;
  719. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  720. << ".";
  721. return diag(ss.str());
  722. }
  723. return SPV_SUCCESS;
  724. }
  725. spv_result_t BuiltInsValidator::ValidateI32Vec(
  726. const Decoration& decoration, const Instruction& inst,
  727. uint32_t num_components,
  728. const std::function<spv_result_t(const std::string& message)>& diag) {
  729. uint32_t underlying_type = 0;
  730. if (spv_result_t error =
  731. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  732. return error;
  733. }
  734. if (!_.IsIntVectorType(underlying_type)) {
  735. return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
  736. }
  737. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  738. if (_.GetDimension(underlying_type) != num_components) {
  739. std::ostringstream ss;
  740. ss << GetDefinitionDesc(decoration, inst) << " has "
  741. << actual_num_components << " components.";
  742. return diag(ss.str());
  743. }
  744. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  745. if (bit_width != 32) {
  746. std::ostringstream ss;
  747. ss << GetDefinitionDesc(decoration, inst)
  748. << " has components with bit width " << bit_width << ".";
  749. return diag(ss.str());
  750. }
  751. return SPV_SUCCESS;
  752. }
  753. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
  754. const Decoration& decoration, const Instruction& inst,
  755. uint32_t num_components,
  756. const std::function<spv_result_t(const std::string& message)>& diag) {
  757. uint32_t underlying_type = 0;
  758. if (spv_result_t error =
  759. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  760. return error;
  761. }
  762. // Strip the array, if present.
  763. if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) {
  764. underlying_type = _.FindDef(underlying_type)->word(2u);
  765. }
  766. return ValidateF32VecHelper(decoration, inst, num_components, diag,
  767. underlying_type);
  768. }
  769. spv_result_t BuiltInsValidator::ValidateF32Vec(
  770. const Decoration& decoration, const Instruction& inst,
  771. uint32_t num_components,
  772. const std::function<spv_result_t(const std::string& message)>& diag) {
  773. uint32_t underlying_type = 0;
  774. if (spv_result_t error =
  775. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  776. return error;
  777. }
  778. return ValidateF32VecHelper(decoration, inst, num_components, diag,
  779. underlying_type);
  780. }
  781. spv_result_t BuiltInsValidator::ValidateF32VecHelper(
  782. const Decoration& decoration, const Instruction& inst,
  783. uint32_t num_components,
  784. const std::function<spv_result_t(const std::string& message)>& diag,
  785. uint32_t underlying_type) {
  786. if (!_.IsFloatVectorType(underlying_type)) {
  787. return diag(GetDefinitionDesc(decoration, inst) +
  788. " is not a float vector.");
  789. }
  790. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  791. if (_.GetDimension(underlying_type) != num_components) {
  792. std::ostringstream ss;
  793. ss << GetDefinitionDesc(decoration, inst) << " has "
  794. << actual_num_components << " components.";
  795. return diag(ss.str());
  796. }
  797. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  798. if (bit_width != 32) {
  799. std::ostringstream ss;
  800. ss << GetDefinitionDesc(decoration, inst)
  801. << " has components with bit width " << bit_width << ".";
  802. return diag(ss.str());
  803. }
  804. return SPV_SUCCESS;
  805. }
  806. spv_result_t BuiltInsValidator::ValidateI32Arr(
  807. const Decoration& decoration, const Instruction& inst,
  808. const std::function<spv_result_t(const std::string& message)>& diag) {
  809. uint32_t underlying_type = 0;
  810. if (spv_result_t error =
  811. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  812. return error;
  813. }
  814. const Instruction* const type_inst = _.FindDef(underlying_type);
  815. if (type_inst->opcode() != SpvOpTypeArray) {
  816. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  817. }
  818. const uint32_t component_type = type_inst->word(2);
  819. if (!_.IsIntScalarType(component_type)) {
  820. return diag(GetDefinitionDesc(decoration, inst) +
  821. " components are not int scalar.");
  822. }
  823. const uint32_t bit_width = _.GetBitWidth(component_type);
  824. if (bit_width != 32) {
  825. std::ostringstream ss;
  826. ss << GetDefinitionDesc(decoration, inst)
  827. << " has components with bit width " << bit_width << ".";
  828. return diag(ss.str());
  829. }
  830. return SPV_SUCCESS;
  831. }
  832. spv_result_t BuiltInsValidator::ValidateF32Arr(
  833. const Decoration& decoration, const Instruction& inst,
  834. uint32_t num_components,
  835. const std::function<spv_result_t(const std::string& message)>& diag) {
  836. uint32_t underlying_type = 0;
  837. if (spv_result_t error =
  838. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  839. return error;
  840. }
  841. return ValidateF32ArrHelper(decoration, inst, num_components, diag,
  842. underlying_type);
  843. }
  844. spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Arr(
  845. const Decoration& decoration, const Instruction& inst,
  846. uint32_t num_components,
  847. const std::function<spv_result_t(const std::string& message)>& diag) {
  848. uint32_t underlying_type = 0;
  849. if (spv_result_t error =
  850. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  851. return error;
  852. }
  853. // Strip an extra layer of arraying if present.
  854. if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) {
  855. uint32_t subtype = _.FindDef(underlying_type)->word(2u);
  856. if (_.GetIdOpcode(subtype) == SpvOpTypeArray) {
  857. underlying_type = subtype;
  858. }
  859. }
  860. return ValidateF32ArrHelper(decoration, inst, num_components, diag,
  861. underlying_type);
  862. }
  863. spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
  864. const Decoration& decoration, const Instruction& inst,
  865. uint32_t num_components,
  866. const std::function<spv_result_t(const std::string& message)>& diag,
  867. uint32_t underlying_type) {
  868. const Instruction* const type_inst = _.FindDef(underlying_type);
  869. if (type_inst->opcode() != SpvOpTypeArray) {
  870. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  871. }
  872. const uint32_t component_type = type_inst->word(2);
  873. if (!_.IsFloatScalarType(component_type)) {
  874. return diag(GetDefinitionDesc(decoration, inst) +
  875. " components are not float scalar.");
  876. }
  877. const uint32_t bit_width = _.GetBitWidth(component_type);
  878. if (bit_width != 32) {
  879. std::ostringstream ss;
  880. ss << GetDefinitionDesc(decoration, inst)
  881. << " has components with bit width " << bit_width << ".";
  882. return diag(ss.str());
  883. }
  884. if (num_components != 0) {
  885. uint64_t actual_num_components = 0;
  886. if (!_.GetConstantValUint64(type_inst->word(3), &actual_num_components)) {
  887. assert(0 && "Array type definition is corrupt");
  888. }
  889. if (actual_num_components != num_components) {
  890. std::ostringstream ss;
  891. ss << GetDefinitionDesc(decoration, inst) << " has "
  892. << actual_num_components << " components.";
  893. return diag(ss.str());
  894. }
  895. }
  896. return SPV_SUCCESS;
  897. }
  898. spv_result_t BuiltInsValidator::ValidateF32Mat(
  899. const Decoration& decoration, const Instruction& inst,
  900. uint32_t req_num_rows, uint32_t req_num_columns,
  901. const std::function<spv_result_t(const std::string& message)>& diag) {
  902. uint32_t underlying_type = 0;
  903. uint32_t num_rows = 0;
  904. uint32_t num_cols = 0;
  905. uint32_t col_type = 0;
  906. uint32_t component_type = 0;
  907. if (spv_result_t error =
  908. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  909. return error;
  910. }
  911. if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
  912. &component_type) ||
  913. num_rows != req_num_rows || num_cols != req_num_columns) {
  914. std::ostringstream ss;
  915. ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
  916. << " and rows " << num_rows << " not equal to expected "
  917. << req_num_columns << "x" << req_num_rows << ".";
  918. return diag(ss.str());
  919. }
  920. return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
  921. }
  922. spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
  923. int vuid, const char* comment, SpvExecutionModel execution_model,
  924. const Decoration& decoration, const Instruction& built_in_inst,
  925. const Instruction& referenced_inst,
  926. const Instruction& referenced_from_inst) {
  927. if (function_id_) {
  928. if (execution_models_.count(execution_model)) {
  929. const char* execution_model_str = _.grammar().lookupOperandName(
  930. SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model);
  931. const char* built_in_str = _.grammar().lookupOperandName(
  932. SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]);
  933. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  934. << (vuid < 0 ? std::string("") : _.VkErrorID(vuid)) << comment
  935. << " " << GetIdDesc(referenced_inst) << " depends on "
  936. << GetIdDesc(built_in_inst) << " which is decorated with BuiltIn "
  937. << built_in_str << "."
  938. << " Id <" << referenced_inst.id() << "> is later referenced by "
  939. << GetIdDesc(referenced_from_inst) << " in function <"
  940. << function_id_ << "> which is called with execution model "
  941. << execution_model_str << ".";
  942. }
  943. } else {
  944. // Propagate this rule to all dependant ids in the global scope.
  945. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  946. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  947. vuid, comment, execution_model, decoration, built_in_inst,
  948. referenced_from_inst, std::placeholders::_1));
  949. }
  950. return SPV_SUCCESS;
  951. }
  952. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtDefinition(
  953. const Decoration& decoration, const Instruction& inst) {
  954. // Seed at reference checks with this built-in.
  955. return ValidateClipOrCullDistanceAtReference(decoration, inst, inst, inst);
  956. }
  957. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
  958. const Decoration& decoration, const Instruction& built_in_inst,
  959. const Instruction& referenced_inst,
  960. const Instruction& referenced_from_inst) {
  961. uint32_t operand = decoration.params()[0];
  962. if (spvIsVulkanEnv(_.context()->target_env)) {
  963. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  964. if (storage_class != SpvStorageClassMax &&
  965. storage_class != SpvStorageClassInput &&
  966. storage_class != SpvStorageClassOutput) {
  967. uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4190 : 4199;
  968. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  969. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  970. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  971. operand)
  972. << " to be only used for variables with Input or Output storage "
  973. "class. "
  974. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  975. referenced_from_inst)
  976. << " " << GetStorageClassDesc(referenced_from_inst);
  977. }
  978. if (storage_class == SpvStorageClassInput) {
  979. assert(function_id_ == 0);
  980. uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4188 : 4197;
  981. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  982. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  983. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  984. "used for variables with Input storage class if execution model is "
  985. "Vertex.",
  986. SpvExecutionModelVertex, decoration, built_in_inst,
  987. referenced_from_inst, std::placeholders::_1));
  988. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  989. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  990. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  991. "used for variables with Input storage class if execution model is "
  992. "Vertex.",
  993. SpvExecutionModelMeshNV, decoration, built_in_inst,
  994. referenced_from_inst, std::placeholders::_1));
  995. }
  996. if (storage_class == SpvStorageClassOutput) {
  997. assert(function_id_ == 0);
  998. uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4189 : 4198;
  999. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1000. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  1001. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  1002. "used for variables with Output storage class if execution model is "
  1003. "Fragment.",
  1004. SpvExecutionModelFragment, decoration, built_in_inst,
  1005. referenced_from_inst, std::placeholders::_1));
  1006. }
  1007. for (const SpvExecutionModel execution_model : execution_models_) {
  1008. switch (execution_model) {
  1009. case SpvExecutionModelFragment:
  1010. case SpvExecutionModelVertex: {
  1011. if (spv_result_t error = ValidateF32Arr(
  1012. decoration, built_in_inst, /* Any number of components */ 0,
  1013. [this, &decoration, &referenced_from_inst](
  1014. const std::string& message) -> spv_result_t {
  1015. uint32_t vuid =
  1016. (decoration.params()[0] == SpvBuiltInClipDistance)
  1017. ? 4191
  1018. : 4200;
  1019. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1020. << _.VkErrorID(vuid)
  1021. << "According to the Vulkan spec BuiltIn "
  1022. << _.grammar().lookupOperandName(
  1023. SPV_OPERAND_TYPE_BUILT_IN,
  1024. decoration.params()[0])
  1025. << " variable needs to be a 32-bit float array. "
  1026. << message;
  1027. })) {
  1028. return error;
  1029. }
  1030. break;
  1031. }
  1032. case SpvExecutionModelTessellationControl:
  1033. case SpvExecutionModelTessellationEvaluation:
  1034. case SpvExecutionModelGeometry:
  1035. case SpvExecutionModelMeshNV: {
  1036. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1037. // The outer level of array is applied on the variable.
  1038. if (spv_result_t error = ValidateF32Arr(
  1039. decoration, built_in_inst, /* Any number of components */ 0,
  1040. [this, &decoration, &referenced_from_inst](
  1041. const std::string& message) -> spv_result_t {
  1042. uint32_t vuid =
  1043. (decoration.params()[0] == SpvBuiltInClipDistance)
  1044. ? 4191
  1045. : 4200;
  1046. return _.diag(SPV_ERROR_INVALID_DATA,
  1047. &referenced_from_inst)
  1048. << _.VkErrorID(vuid)
  1049. << "According to the Vulkan spec BuiltIn "
  1050. << _.grammar().lookupOperandName(
  1051. SPV_OPERAND_TYPE_BUILT_IN,
  1052. decoration.params()[0])
  1053. << " variable needs to be a 32-bit float array. "
  1054. << message;
  1055. })) {
  1056. return error;
  1057. }
  1058. } else {
  1059. if (spv_result_t error = ValidateOptionalArrayedF32Arr(
  1060. decoration, built_in_inst, /* Any number of components */ 0,
  1061. [this, &decoration, &referenced_from_inst](
  1062. const std::string& message) -> spv_result_t {
  1063. uint32_t vuid =
  1064. (decoration.params()[0] == SpvBuiltInClipDistance)
  1065. ? 4191
  1066. : 4200;
  1067. return _.diag(SPV_ERROR_INVALID_DATA,
  1068. &referenced_from_inst)
  1069. << _.VkErrorID(vuid)
  1070. << "According to the Vulkan spec BuiltIn "
  1071. << _.grammar().lookupOperandName(
  1072. SPV_OPERAND_TYPE_BUILT_IN,
  1073. decoration.params()[0])
  1074. << " variable needs to be a 32-bit float array. "
  1075. << message;
  1076. })) {
  1077. return error;
  1078. }
  1079. }
  1080. break;
  1081. }
  1082. default: {
  1083. uint32_t vuid =
  1084. (decoration.params()[0] == SpvBuiltInClipDistance) ? 4187 : 4196;
  1085. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1086. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  1087. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1088. operand)
  1089. << " to be used only with Fragment, Vertex, "
  1090. "TessellationControl, TessellationEvaluation or Geometry "
  1091. "execution models. "
  1092. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1093. referenced_from_inst, execution_model);
  1094. }
  1095. }
  1096. }
  1097. }
  1098. if (function_id_ == 0) {
  1099. // Propagate this rule to all dependant ids in the global scope.
  1100. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1101. std::bind(&BuiltInsValidator::ValidateClipOrCullDistanceAtReference,
  1102. this, decoration, built_in_inst, referenced_from_inst,
  1103. std::placeholders::_1));
  1104. }
  1105. return SPV_SUCCESS;
  1106. }
  1107. spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
  1108. const Decoration& decoration, const Instruction& inst) {
  1109. if (spvIsVulkanEnv(_.context()->target_env)) {
  1110. if (spv_result_t error = ValidateF32Vec(
  1111. decoration, inst, 4,
  1112. [this, &inst](const std::string& message) -> spv_result_t {
  1113. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1114. << _.VkErrorID(4212) << "According to the "
  1115. << spvLogStringForEnv(_.context()->target_env)
  1116. << " spec BuiltIn FragCoord "
  1117. "variable needs to be a 4-component 32-bit float "
  1118. "vector. "
  1119. << message;
  1120. })) {
  1121. return error;
  1122. }
  1123. }
  1124. // Seed at reference checks with this built-in.
  1125. return ValidateFragCoordAtReference(decoration, inst, inst, inst);
  1126. }
  1127. spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
  1128. const Decoration& decoration, const Instruction& built_in_inst,
  1129. const Instruction& referenced_inst,
  1130. const Instruction& referenced_from_inst) {
  1131. if (spvIsVulkanEnv(_.context()->target_env)) {
  1132. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1133. if (storage_class != SpvStorageClassMax &&
  1134. storage_class != SpvStorageClassInput) {
  1135. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1136. << _.VkErrorID(4211) << spvLogStringForEnv(_.context()->target_env)
  1137. << " spec allows BuiltIn FragCoord to be only used for "
  1138. "variables with Input storage class. "
  1139. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1140. referenced_from_inst)
  1141. << " " << GetStorageClassDesc(referenced_from_inst);
  1142. }
  1143. for (const SpvExecutionModel execution_model : execution_models_) {
  1144. if (execution_model != SpvExecutionModelFragment) {
  1145. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1146. << _.VkErrorID(4210)
  1147. << spvLogStringForEnv(_.context()->target_env)
  1148. << " spec allows BuiltIn FragCoord to be used only with "
  1149. "Fragment execution model. "
  1150. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1151. referenced_from_inst, execution_model);
  1152. }
  1153. }
  1154. }
  1155. if (function_id_ == 0) {
  1156. // Propagate this rule to all dependant ids in the global scope.
  1157. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1158. &BuiltInsValidator::ValidateFragCoordAtReference, this, decoration,
  1159. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1160. }
  1161. return SPV_SUCCESS;
  1162. }
  1163. spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
  1164. const Decoration& decoration, const Instruction& inst) {
  1165. if (spvIsVulkanEnv(_.context()->target_env)) {
  1166. if (spv_result_t error = ValidateF32(
  1167. decoration, inst,
  1168. [this, &inst](const std::string& message) -> spv_result_t {
  1169. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1170. << _.VkErrorID(4215) << "According to the "
  1171. << spvLogStringForEnv(_.context()->target_env)
  1172. << " spec BuiltIn FragDepth "
  1173. "variable needs to be a 32-bit float scalar. "
  1174. << message;
  1175. })) {
  1176. return error;
  1177. }
  1178. }
  1179. // Seed at reference checks with this built-in.
  1180. return ValidateFragDepthAtReference(decoration, inst, inst, inst);
  1181. }
  1182. spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
  1183. const Decoration& decoration, const Instruction& built_in_inst,
  1184. const Instruction& referenced_inst,
  1185. const Instruction& referenced_from_inst) {
  1186. if (spvIsVulkanEnv(_.context()->target_env)) {
  1187. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1188. if (storage_class != SpvStorageClassMax &&
  1189. storage_class != SpvStorageClassOutput) {
  1190. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1191. << _.VkErrorID(4214) << spvLogStringForEnv(_.context()->target_env)
  1192. << " spec allows BuiltIn FragDepth to be only used for "
  1193. "variables with Output storage class. "
  1194. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1195. referenced_from_inst)
  1196. << " " << GetStorageClassDesc(referenced_from_inst);
  1197. }
  1198. for (const SpvExecutionModel execution_model : execution_models_) {
  1199. if (execution_model != SpvExecutionModelFragment) {
  1200. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1201. << _.VkErrorID(4213)
  1202. << spvLogStringForEnv(_.context()->target_env)
  1203. << " spec allows BuiltIn FragDepth to be used only with "
  1204. "Fragment execution model. "
  1205. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1206. referenced_from_inst, execution_model);
  1207. }
  1208. }
  1209. for (const uint32_t entry_point : *entry_points_) {
  1210. // Every entry point from which this function is called needs to have
  1211. // Execution Mode DepthReplacing.
  1212. const auto* modes = _.GetExecutionModes(entry_point);
  1213. if (!modes || !modes->count(SpvExecutionModeDepthReplacing)) {
  1214. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1215. << _.VkErrorID(4216)
  1216. << spvLogStringForEnv(_.context()->target_env)
  1217. << " spec requires DepthReplacing execution mode to be "
  1218. "declared when using BuiltIn FragDepth. "
  1219. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1220. referenced_from_inst);
  1221. }
  1222. }
  1223. }
  1224. if (function_id_ == 0) {
  1225. // Propagate this rule to all dependant ids in the global scope.
  1226. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1227. &BuiltInsValidator::ValidateFragDepthAtReference, this, decoration,
  1228. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1229. }
  1230. return SPV_SUCCESS;
  1231. }
  1232. spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
  1233. const Decoration& decoration, const Instruction& inst) {
  1234. if (spvIsVulkanEnv(_.context()->target_env)) {
  1235. if (spv_result_t error = ValidateBool(
  1236. decoration, inst,
  1237. [this, &inst](const std::string& message) -> spv_result_t {
  1238. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1239. << _.VkErrorID(4231) << "According to the "
  1240. << spvLogStringForEnv(_.context()->target_env)
  1241. << " spec BuiltIn FrontFacing "
  1242. "variable needs to be a bool scalar. "
  1243. << message;
  1244. })) {
  1245. return error;
  1246. }
  1247. }
  1248. // Seed at reference checks with this built-in.
  1249. return ValidateFrontFacingAtReference(decoration, inst, inst, inst);
  1250. }
  1251. spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
  1252. const Decoration& decoration, const Instruction& built_in_inst,
  1253. const Instruction& referenced_inst,
  1254. const Instruction& referenced_from_inst) {
  1255. if (spvIsVulkanEnv(_.context()->target_env)) {
  1256. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1257. if (storage_class != SpvStorageClassMax &&
  1258. storage_class != SpvStorageClassInput) {
  1259. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1260. << _.VkErrorID(4230) << spvLogStringForEnv(_.context()->target_env)
  1261. << " spec allows BuiltIn FrontFacing to be only used for "
  1262. "variables with Input storage class. "
  1263. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1264. referenced_from_inst)
  1265. << " " << GetStorageClassDesc(referenced_from_inst);
  1266. }
  1267. for (const SpvExecutionModel execution_model : execution_models_) {
  1268. if (execution_model != SpvExecutionModelFragment) {
  1269. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1270. << _.VkErrorID(4229)
  1271. << spvLogStringForEnv(_.context()->target_env)
  1272. << " spec allows BuiltIn FrontFacing to be used only with "
  1273. "Fragment execution model. "
  1274. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1275. referenced_from_inst, execution_model);
  1276. }
  1277. }
  1278. }
  1279. if (function_id_ == 0) {
  1280. // Propagate this rule to all dependant ids in the global scope.
  1281. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1282. &BuiltInsValidator::ValidateFrontFacingAtReference, this, decoration,
  1283. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1284. }
  1285. return SPV_SUCCESS;
  1286. }
  1287. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition(
  1288. const Decoration& decoration, const Instruction& inst) {
  1289. if (spvIsVulkanEnv(_.context()->target_env)) {
  1290. if (spv_result_t error = ValidateBool(
  1291. decoration, inst,
  1292. [this, &inst](const std::string& message) -> spv_result_t {
  1293. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1294. << _.VkErrorID(4241)
  1295. << "According to the Vulkan spec BuiltIn HelperInvocation "
  1296. "variable needs to be a bool scalar. "
  1297. << message;
  1298. })) {
  1299. return error;
  1300. }
  1301. }
  1302. // Seed at reference checks with this built-in.
  1303. return ValidateHelperInvocationAtReference(decoration, inst, inst, inst);
  1304. }
  1305. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference(
  1306. const Decoration& decoration, const Instruction& built_in_inst,
  1307. const Instruction& referenced_inst,
  1308. const Instruction& referenced_from_inst) {
  1309. if (spvIsVulkanEnv(_.context()->target_env)) {
  1310. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1311. if (storage_class != SpvStorageClassMax &&
  1312. storage_class != SpvStorageClassInput) {
  1313. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1314. << _.VkErrorID(4240)
  1315. << "Vulkan spec allows BuiltIn HelperInvocation to be only used "
  1316. "for variables with Input storage class. "
  1317. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1318. referenced_from_inst)
  1319. << " " << GetStorageClassDesc(referenced_from_inst);
  1320. }
  1321. for (const SpvExecutionModel execution_model : execution_models_) {
  1322. if (execution_model != SpvExecutionModelFragment) {
  1323. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1324. << _.VkErrorID(4239)
  1325. << "Vulkan spec allows BuiltIn HelperInvocation to be used only "
  1326. "with Fragment execution model. "
  1327. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1328. referenced_from_inst, execution_model);
  1329. }
  1330. }
  1331. }
  1332. if (function_id_ == 0) {
  1333. // Propagate this rule to all dependant ids in the global scope.
  1334. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1335. std::bind(&BuiltInsValidator::ValidateHelperInvocationAtReference, this,
  1336. decoration, built_in_inst, referenced_from_inst,
  1337. std::placeholders::_1));
  1338. }
  1339. return SPV_SUCCESS;
  1340. }
  1341. spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition(
  1342. const Decoration& decoration, const Instruction& inst) {
  1343. if (spvIsVulkanEnv(_.context()->target_env)) {
  1344. if (spv_result_t error = ValidateI32(
  1345. decoration, inst,
  1346. [this, &inst](const std::string& message) -> spv_result_t {
  1347. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1348. << _.VkErrorID(4259)
  1349. << "According to the Vulkan spec BuiltIn InvocationId "
  1350. "variable needs to be a 32-bit int scalar. "
  1351. << message;
  1352. })) {
  1353. return error;
  1354. }
  1355. }
  1356. // Seed at reference checks with this built-in.
  1357. return ValidateInvocationIdAtReference(decoration, inst, inst, inst);
  1358. }
  1359. spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
  1360. const Decoration& decoration, const Instruction& built_in_inst,
  1361. const Instruction& referenced_inst,
  1362. const Instruction& referenced_from_inst) {
  1363. if (spvIsVulkanEnv(_.context()->target_env)) {
  1364. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1365. if (storage_class != SpvStorageClassMax &&
  1366. storage_class != SpvStorageClassInput) {
  1367. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1368. << _.VkErrorID(4258)
  1369. << "Vulkan spec allows BuiltIn InvocationId to be only used for "
  1370. "variables with Input storage class. "
  1371. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1372. referenced_from_inst)
  1373. << " " << GetStorageClassDesc(referenced_from_inst);
  1374. }
  1375. for (const SpvExecutionModel execution_model : execution_models_) {
  1376. if (execution_model != SpvExecutionModelTessellationControl &&
  1377. execution_model != SpvExecutionModelGeometry) {
  1378. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1379. << _.VkErrorID(4257)
  1380. << "Vulkan spec allows BuiltIn InvocationId to be used only "
  1381. "with TessellationControl or Geometry execution models. "
  1382. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1383. referenced_from_inst, execution_model);
  1384. }
  1385. }
  1386. }
  1387. if (function_id_ == 0) {
  1388. // Propagate this rule to all dependant ids in the global scope.
  1389. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1390. &BuiltInsValidator::ValidateInvocationIdAtReference, this, decoration,
  1391. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1392. }
  1393. return SPV_SUCCESS;
  1394. }
  1395. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
  1396. const Decoration& decoration, const Instruction& inst) {
  1397. if (spvIsVulkanEnv(_.context()->target_env)) {
  1398. if (spv_result_t error = ValidateI32(
  1399. decoration, inst,
  1400. [this, &inst](const std::string& message) -> spv_result_t {
  1401. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1402. << _.VkErrorID(4265) << "According to the "
  1403. << spvLogStringForEnv(_.context()->target_env)
  1404. << " spec BuiltIn InstanceIndex "
  1405. "variable needs to be a 32-bit int scalar. "
  1406. << message;
  1407. })) {
  1408. return error;
  1409. }
  1410. }
  1411. // Seed at reference checks with this built-in.
  1412. return ValidateInstanceIndexAtReference(decoration, inst, inst, inst);
  1413. }
  1414. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
  1415. const Decoration& decoration, const Instruction& built_in_inst,
  1416. const Instruction& referenced_inst,
  1417. const Instruction& referenced_from_inst) {
  1418. if (spvIsVulkanEnv(_.context()->target_env)) {
  1419. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1420. if (storage_class != SpvStorageClassMax &&
  1421. storage_class != SpvStorageClassInput) {
  1422. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1423. << _.VkErrorID(4264) << spvLogStringForEnv(_.context()->target_env)
  1424. << " spec allows BuiltIn InstanceIndex to be only used for "
  1425. "variables with Input storage class. "
  1426. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1427. referenced_from_inst)
  1428. << " " << GetStorageClassDesc(referenced_from_inst);
  1429. }
  1430. for (const SpvExecutionModel execution_model : execution_models_) {
  1431. if (execution_model != SpvExecutionModelVertex) {
  1432. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1433. << _.VkErrorID(4263)
  1434. << spvLogStringForEnv(_.context()->target_env)
  1435. << " spec allows BuiltIn InstanceIndex to be used only "
  1436. "with Vertex execution model. "
  1437. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1438. referenced_from_inst, execution_model);
  1439. }
  1440. }
  1441. }
  1442. if (function_id_ == 0) {
  1443. // Propagate this rule to all dependant ids in the global scope.
  1444. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1445. &BuiltInsValidator::ValidateInstanceIndexAtReference, this, decoration,
  1446. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1447. }
  1448. return SPV_SUCCESS;
  1449. }
  1450. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition(
  1451. const Decoration& decoration, const Instruction& inst) {
  1452. if (spvIsVulkanEnv(_.context()->target_env)) {
  1453. if (spv_result_t error = ValidateI32(
  1454. decoration, inst,
  1455. [this, &inst](const std::string& message) -> spv_result_t {
  1456. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1457. << _.VkErrorID(4310)
  1458. << "According to the Vulkan spec BuiltIn PatchVertices "
  1459. "variable needs to be a 32-bit int scalar. "
  1460. << message;
  1461. })) {
  1462. return error;
  1463. }
  1464. }
  1465. // Seed at reference checks with this built-in.
  1466. return ValidatePatchVerticesAtReference(decoration, inst, inst, inst);
  1467. }
  1468. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference(
  1469. const Decoration& decoration, const Instruction& built_in_inst,
  1470. const Instruction& referenced_inst,
  1471. const Instruction& referenced_from_inst) {
  1472. if (spvIsVulkanEnv(_.context()->target_env)) {
  1473. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1474. if (storage_class != SpvStorageClassMax &&
  1475. storage_class != SpvStorageClassInput) {
  1476. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1477. << _.VkErrorID(4309)
  1478. << "Vulkan spec allows BuiltIn PatchVertices to be only used for "
  1479. "variables with Input storage class. "
  1480. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1481. referenced_from_inst)
  1482. << " " << GetStorageClassDesc(referenced_from_inst);
  1483. }
  1484. for (const SpvExecutionModel execution_model : execution_models_) {
  1485. if (execution_model != SpvExecutionModelTessellationControl &&
  1486. execution_model != SpvExecutionModelTessellationEvaluation) {
  1487. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1488. << _.VkErrorID(4308)
  1489. << "Vulkan spec allows BuiltIn PatchVertices to be used only "
  1490. "with TessellationControl or TessellationEvaluation "
  1491. "execution models. "
  1492. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1493. referenced_from_inst, execution_model);
  1494. }
  1495. }
  1496. }
  1497. if (function_id_ == 0) {
  1498. // Propagate this rule to all dependant ids in the global scope.
  1499. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1500. &BuiltInsValidator::ValidatePatchVerticesAtReference, this, decoration,
  1501. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1502. }
  1503. return SPV_SUCCESS;
  1504. }
  1505. spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition(
  1506. const Decoration& decoration, const Instruction& inst) {
  1507. if (spvIsVulkanEnv(_.context()->target_env)) {
  1508. if (spv_result_t error = ValidateF32Vec(
  1509. decoration, inst, 2,
  1510. [this, &inst](const std::string& message) -> spv_result_t {
  1511. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1512. << _.VkErrorID(4313)
  1513. << "According to the Vulkan spec BuiltIn PointCoord "
  1514. "variable needs to be a 2-component 32-bit float "
  1515. "vector. "
  1516. << message;
  1517. })) {
  1518. return error;
  1519. }
  1520. }
  1521. // Seed at reference checks with this built-in.
  1522. return ValidatePointCoordAtReference(decoration, inst, inst, inst);
  1523. }
  1524. spv_result_t BuiltInsValidator::ValidatePointCoordAtReference(
  1525. const Decoration& decoration, const Instruction& built_in_inst,
  1526. const Instruction& referenced_inst,
  1527. const Instruction& referenced_from_inst) {
  1528. if (spvIsVulkanEnv(_.context()->target_env)) {
  1529. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1530. if (storage_class != SpvStorageClassMax &&
  1531. storage_class != SpvStorageClassInput) {
  1532. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1533. << _.VkErrorID(4312)
  1534. << "Vulkan spec allows BuiltIn PointCoord to be only used for "
  1535. "variables with Input storage class. "
  1536. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1537. referenced_from_inst)
  1538. << " " << GetStorageClassDesc(referenced_from_inst);
  1539. }
  1540. for (const SpvExecutionModel execution_model : execution_models_) {
  1541. if (execution_model != SpvExecutionModelFragment) {
  1542. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1543. << _.VkErrorID(4311)
  1544. << "Vulkan spec allows BuiltIn PointCoord to be used only with "
  1545. "Fragment execution model. "
  1546. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1547. referenced_from_inst, execution_model);
  1548. }
  1549. }
  1550. }
  1551. if (function_id_ == 0) {
  1552. // Propagate this rule to all dependant ids in the global scope.
  1553. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1554. &BuiltInsValidator::ValidatePointCoordAtReference, this, decoration,
  1555. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1556. }
  1557. return SPV_SUCCESS;
  1558. }
  1559. spv_result_t BuiltInsValidator::ValidatePointSizeAtDefinition(
  1560. const Decoration& decoration, const Instruction& inst) {
  1561. // Seed at reference checks with this built-in.
  1562. return ValidatePointSizeAtReference(decoration, inst, inst, inst);
  1563. }
  1564. spv_result_t BuiltInsValidator::ValidatePointSizeAtReference(
  1565. const Decoration& decoration, const Instruction& built_in_inst,
  1566. const Instruction& referenced_inst,
  1567. const Instruction& referenced_from_inst) {
  1568. if (spvIsVulkanEnv(_.context()->target_env)) {
  1569. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1570. if (storage_class != SpvStorageClassMax &&
  1571. storage_class != SpvStorageClassInput &&
  1572. storage_class != SpvStorageClassOutput) {
  1573. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1574. << _.VkErrorID(4316)
  1575. << "Vulkan spec allows BuiltIn PointSize to be only used for "
  1576. "variables with Input or Output storage class. "
  1577. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1578. referenced_from_inst)
  1579. << " " << GetStorageClassDesc(referenced_from_inst);
  1580. }
  1581. if (storage_class == SpvStorageClassInput) {
  1582. assert(function_id_ == 0);
  1583. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1584. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4315,
  1585. "Vulkan spec doesn't allow BuiltIn PointSize to be used for "
  1586. "variables with Input storage class if execution model is "
  1587. "Vertex.",
  1588. SpvExecutionModelVertex, decoration, built_in_inst,
  1589. referenced_from_inst, std::placeholders::_1));
  1590. }
  1591. for (const SpvExecutionModel execution_model : execution_models_) {
  1592. switch (execution_model) {
  1593. case SpvExecutionModelVertex: {
  1594. if (spv_result_t error = ValidateF32(
  1595. decoration, built_in_inst,
  1596. [this, &referenced_from_inst](
  1597. const std::string& message) -> spv_result_t {
  1598. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1599. << _.VkErrorID(4317)
  1600. << "According to the Vulkan spec BuiltIn PointSize "
  1601. "variable needs to be a 32-bit float scalar. "
  1602. << message;
  1603. })) {
  1604. return error;
  1605. }
  1606. break;
  1607. }
  1608. case SpvExecutionModelTessellationControl:
  1609. case SpvExecutionModelTessellationEvaluation:
  1610. case SpvExecutionModelGeometry:
  1611. case SpvExecutionModelMeshNV: {
  1612. // PointSize can be a per-vertex variable for tessellation control,
  1613. // tessellation evaluation and geometry shader stages. In such cases
  1614. // variables will have an array of 32-bit floats.
  1615. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1616. // The array is on the variable, so this must be a 32-bit float.
  1617. if (spv_result_t error = ValidateF32(
  1618. decoration, built_in_inst,
  1619. [this, &referenced_from_inst](
  1620. const std::string& message) -> spv_result_t {
  1621. return _.diag(SPV_ERROR_INVALID_DATA,
  1622. &referenced_from_inst)
  1623. << _.VkErrorID(4317)
  1624. << "According to the Vulkan spec BuiltIn "
  1625. "PointSize variable needs to be a 32-bit "
  1626. "float scalar. "
  1627. << message;
  1628. })) {
  1629. return error;
  1630. }
  1631. } else {
  1632. if (spv_result_t error = ValidateOptionalArrayedF32(
  1633. decoration, built_in_inst,
  1634. [this, &referenced_from_inst](
  1635. const std::string& message) -> spv_result_t {
  1636. return _.diag(SPV_ERROR_INVALID_DATA,
  1637. &referenced_from_inst)
  1638. << _.VkErrorID(4317)
  1639. << "According to the Vulkan spec BuiltIn "
  1640. "PointSize variable needs to be a 32-bit "
  1641. "float scalar. "
  1642. << message;
  1643. })) {
  1644. return error;
  1645. }
  1646. }
  1647. break;
  1648. }
  1649. default: {
  1650. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1651. << _.VkErrorID(4314)
  1652. << "Vulkan spec allows BuiltIn PointSize to be used only with "
  1653. "Vertex, TessellationControl, TessellationEvaluation or "
  1654. "Geometry execution models. "
  1655. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1656. referenced_from_inst, execution_model);
  1657. }
  1658. }
  1659. }
  1660. }
  1661. if (function_id_ == 0) {
  1662. // Propagate this rule to all dependant ids in the global scope.
  1663. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1664. &BuiltInsValidator::ValidatePointSizeAtReference, this, decoration,
  1665. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1666. }
  1667. return SPV_SUCCESS;
  1668. }
  1669. spv_result_t BuiltInsValidator::ValidatePositionAtDefinition(
  1670. const Decoration& decoration, const Instruction& inst) {
  1671. // Seed at reference checks with this built-in.
  1672. return ValidatePositionAtReference(decoration, inst, inst, inst);
  1673. }
  1674. spv_result_t BuiltInsValidator::ValidatePositionAtReference(
  1675. const Decoration& decoration, const Instruction& built_in_inst,
  1676. const Instruction& referenced_inst,
  1677. const Instruction& referenced_from_inst) {
  1678. if (spvIsVulkanEnv(_.context()->target_env)) {
  1679. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1680. if (storage_class != SpvStorageClassMax &&
  1681. storage_class != SpvStorageClassInput &&
  1682. storage_class != SpvStorageClassOutput) {
  1683. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1684. << _.VkErrorID(4320) << "Vulkan spec allows BuiltIn Position to be only used for "
  1685. "variables with Input or Output storage class. "
  1686. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1687. referenced_from_inst)
  1688. << " " << GetStorageClassDesc(referenced_from_inst);
  1689. }
  1690. if (storage_class == SpvStorageClassInput) {
  1691. assert(function_id_ == 0);
  1692. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1693. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
  1694. "Vulkan spec doesn't allow BuiltIn Position to be used "
  1695. "for variables "
  1696. "with Input storage class if execution model is Vertex.",
  1697. SpvExecutionModelVertex, decoration, built_in_inst,
  1698. referenced_from_inst, std::placeholders::_1));
  1699. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1700. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
  1701. "Vulkan spec doesn't allow BuiltIn Position to be used "
  1702. "for variables "
  1703. "with Input storage class if execution model is MeshNV.",
  1704. SpvExecutionModelMeshNV, decoration, built_in_inst,
  1705. referenced_from_inst, std::placeholders::_1));
  1706. }
  1707. for (const SpvExecutionModel execution_model : execution_models_) {
  1708. switch (execution_model) {
  1709. case SpvExecutionModelVertex: {
  1710. if (spv_result_t error = ValidateF32Vec(
  1711. decoration, built_in_inst, 4,
  1712. [this, &referenced_from_inst](
  1713. const std::string& message) -> spv_result_t {
  1714. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1715. << _.VkErrorID(4321)
  1716. << "According to the Vulkan spec BuiltIn Position "
  1717. "variable needs to be a 4-component 32-bit float "
  1718. "vector. "
  1719. << message;
  1720. })) {
  1721. return error;
  1722. }
  1723. break;
  1724. }
  1725. case SpvExecutionModelGeometry:
  1726. case SpvExecutionModelTessellationControl:
  1727. case SpvExecutionModelTessellationEvaluation:
  1728. case SpvExecutionModelMeshNV: {
  1729. // Position can be a per-vertex variable for tessellation control,
  1730. // tessellation evaluation, geometry and mesh shader stages. In such
  1731. // cases variables will have an array of 4-component 32-bit float
  1732. // vectors.
  1733. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1734. // The array is on the variable, so this must be a 4-component
  1735. // 32-bit float vector.
  1736. if (spv_result_t error = ValidateF32Vec(
  1737. decoration, built_in_inst, 4,
  1738. [this, &referenced_from_inst](
  1739. const std::string& message) -> spv_result_t {
  1740. return _.diag(SPV_ERROR_INVALID_DATA,
  1741. &referenced_from_inst)
  1742. << _.VkErrorID(4321)
  1743. << "According to the Vulkan spec BuiltIn Position "
  1744. "variable needs to be a 4-component 32-bit "
  1745. "float vector. "
  1746. << message;
  1747. })) {
  1748. return error;
  1749. }
  1750. } else {
  1751. if (spv_result_t error = ValidateOptionalArrayedF32Vec(
  1752. decoration, built_in_inst, 4,
  1753. [this, &referenced_from_inst](
  1754. const std::string& message) -> spv_result_t {
  1755. return _.diag(SPV_ERROR_INVALID_DATA,
  1756. &referenced_from_inst)
  1757. << _.VkErrorID(4321)
  1758. << "According to the Vulkan spec BuiltIn Position "
  1759. "variable needs to be a 4-component 32-bit "
  1760. "float vector. "
  1761. << message;
  1762. })) {
  1763. return error;
  1764. }
  1765. }
  1766. break;
  1767. }
  1768. default: {
  1769. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1770. << _.VkErrorID(4318)
  1771. << "Vulkan spec allows BuiltIn Position to be used only "
  1772. "with Vertex, TessellationControl, TessellationEvaluation"
  1773. " or Geometry execution models. "
  1774. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1775. referenced_from_inst, execution_model);
  1776. }
  1777. }
  1778. }
  1779. }
  1780. if (function_id_ == 0) {
  1781. // Propagate this rule to all dependant ids in the global scope.
  1782. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1783. &BuiltInsValidator::ValidatePositionAtReference, this, decoration,
  1784. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1785. }
  1786. return SPV_SUCCESS;
  1787. }
  1788. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
  1789. const Decoration& decoration, const Instruction& inst) {
  1790. if (spvIsVulkanEnv(_.context()->target_env)) {
  1791. // PrimitiveId can be a per-primitive variable for mesh shader stage.
  1792. // In such cases variable will have an array of 32-bit integers.
  1793. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  1794. // This must be a 32-bit int scalar.
  1795. if (spv_result_t error = ValidateI32(
  1796. decoration, inst,
  1797. [this, &inst](const std::string& message) -> spv_result_t {
  1798. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1799. << _.VkErrorID(4337)
  1800. << "According to the Vulkan spec BuiltIn PrimitiveId "
  1801. "variable needs to be a 32-bit int scalar. "
  1802. << message;
  1803. })) {
  1804. return error;
  1805. }
  1806. } else {
  1807. if (spv_result_t error = ValidateOptionalArrayedI32(
  1808. decoration, inst,
  1809. [this, &inst](const std::string& message) -> spv_result_t {
  1810. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1811. << _.VkErrorID(4337)
  1812. << "According to the Vulkan spec BuiltIn PrimitiveId "
  1813. "variable needs to be a 32-bit int scalar. "
  1814. << message;
  1815. })) {
  1816. return error;
  1817. }
  1818. }
  1819. }
  1820. // Seed at reference checks with this built-in.
  1821. return ValidatePrimitiveIdAtReference(decoration, inst, inst, inst);
  1822. }
  1823. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
  1824. const Decoration& decoration, const Instruction& built_in_inst,
  1825. const Instruction& referenced_inst,
  1826. const Instruction& referenced_from_inst) {
  1827. if (spvIsVulkanEnv(_.context()->target_env)) {
  1828. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1829. if (storage_class != SpvStorageClassMax &&
  1830. storage_class != SpvStorageClassInput &&
  1831. storage_class != SpvStorageClassOutput) {
  1832. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1833. << "Vulkan spec allows BuiltIn PrimitiveId to be only used for "
  1834. "variables with Input or Output storage class. "
  1835. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1836. referenced_from_inst)
  1837. << " " << GetStorageClassDesc(referenced_from_inst);
  1838. }
  1839. if (storage_class == SpvStorageClassOutput) {
  1840. assert(function_id_ == 0);
  1841. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1842. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1843. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1844. "variables with Output storage class if execution model is "
  1845. "TessellationControl.",
  1846. SpvExecutionModelTessellationControl, decoration, built_in_inst,
  1847. referenced_from_inst, std::placeholders::_1));
  1848. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1849. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1850. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1851. "variables with Output storage class if execution model is "
  1852. "TessellationEvaluation.",
  1853. SpvExecutionModelTessellationEvaluation, decoration, built_in_inst,
  1854. referenced_from_inst, std::placeholders::_1));
  1855. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1856. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1857. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1858. "variables with Output storage class if execution model is "
  1859. "Fragment.",
  1860. SpvExecutionModelFragment, decoration, built_in_inst,
  1861. referenced_from_inst, std::placeholders::_1));
  1862. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1863. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1864. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1865. "variables with Output storage class if execution model is "
  1866. "IntersectionKHR.",
  1867. SpvExecutionModelIntersectionKHR, decoration, built_in_inst,
  1868. referenced_from_inst, std::placeholders::_1));
  1869. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1870. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1871. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1872. "variables with Output storage class if execution model is "
  1873. "AnyHitKHR.",
  1874. SpvExecutionModelAnyHitKHR, decoration, built_in_inst,
  1875. referenced_from_inst, std::placeholders::_1));
  1876. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1877. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
  1878. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1879. "variables with Output storage class if execution model is "
  1880. "ClosestHitKHR.",
  1881. SpvExecutionModelClosestHitKHR, decoration, built_in_inst,
  1882. referenced_from_inst, std::placeholders::_1));
  1883. }
  1884. for (const SpvExecutionModel execution_model : execution_models_) {
  1885. switch (execution_model) {
  1886. case SpvExecutionModelFragment:
  1887. case SpvExecutionModelTessellationControl:
  1888. case SpvExecutionModelTessellationEvaluation:
  1889. case SpvExecutionModelGeometry:
  1890. case SpvExecutionModelMeshNV:
  1891. case SpvExecutionModelIntersectionKHR:
  1892. case SpvExecutionModelAnyHitKHR:
  1893. case SpvExecutionModelClosestHitKHR: {
  1894. // Ok.
  1895. break;
  1896. }
  1897. default: {
  1898. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1899. << _.VkErrorID(4330)
  1900. << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
  1901. "with Fragment, TessellationControl, "
  1902. "TessellationEvaluation, Geometry, MeshNV, "
  1903. "IntersectionKHR, "
  1904. "AnyHitKHR, and ClosestHitKHR execution models. "
  1905. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1906. referenced_from_inst, execution_model);
  1907. }
  1908. }
  1909. }
  1910. }
  1911. if (function_id_ == 0) {
  1912. // Propagate this rule to all dependant ids in the global scope.
  1913. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1914. &BuiltInsValidator::ValidatePrimitiveIdAtReference, this, decoration,
  1915. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1916. }
  1917. return SPV_SUCCESS;
  1918. }
  1919. spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition(
  1920. const Decoration& decoration, const Instruction& inst) {
  1921. if (spvIsVulkanEnv(_.context()->target_env)) {
  1922. if (spv_result_t error = ValidateI32(
  1923. decoration, inst,
  1924. [this, &inst](const std::string& message) -> spv_result_t {
  1925. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1926. << _.VkErrorID(4356)
  1927. << "According to the Vulkan spec BuiltIn SampleId "
  1928. "variable needs to be a 32-bit int scalar. "
  1929. << message;
  1930. })) {
  1931. return error;
  1932. }
  1933. }
  1934. // Seed at reference checks with this built-in.
  1935. return ValidateSampleIdAtReference(decoration, inst, inst, inst);
  1936. }
  1937. spv_result_t BuiltInsValidator::ValidateSampleIdAtReference(
  1938. const Decoration& decoration, const Instruction& built_in_inst,
  1939. const Instruction& referenced_inst,
  1940. const Instruction& referenced_from_inst) {
  1941. if (spvIsVulkanEnv(_.context()->target_env)) {
  1942. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1943. if (storage_class != SpvStorageClassMax &&
  1944. storage_class != SpvStorageClassInput) {
  1945. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1946. << _.VkErrorID(4355)
  1947. << "Vulkan spec allows BuiltIn SampleId to be only used for "
  1948. "variables with Input storage class. "
  1949. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1950. referenced_from_inst)
  1951. << " " << GetStorageClassDesc(referenced_from_inst);
  1952. }
  1953. for (const SpvExecutionModel execution_model : execution_models_) {
  1954. if (execution_model != SpvExecutionModelFragment) {
  1955. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  1956. << _.VkErrorID(4354)
  1957. << "Vulkan spec allows BuiltIn SampleId to be used only with "
  1958. "Fragment execution model. "
  1959. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1960. referenced_from_inst, execution_model);
  1961. }
  1962. }
  1963. }
  1964. if (function_id_ == 0) {
  1965. // Propagate this rule to all dependant ids in the global scope.
  1966. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1967. &BuiltInsValidator::ValidateSampleIdAtReference, this, decoration,
  1968. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1969. }
  1970. return SPV_SUCCESS;
  1971. }
  1972. spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition(
  1973. const Decoration& decoration, const Instruction& inst) {
  1974. if (spvIsVulkanEnv(_.context()->target_env)) {
  1975. if (spv_result_t error = ValidateI32Arr(
  1976. decoration, inst,
  1977. [this, &inst](const std::string& message) -> spv_result_t {
  1978. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  1979. << _.VkErrorID(4359)
  1980. << "According to the Vulkan spec BuiltIn SampleMask "
  1981. "variable needs to be a 32-bit int array. "
  1982. << message;
  1983. })) {
  1984. return error;
  1985. }
  1986. }
  1987. // Seed at reference checks with this built-in.
  1988. return ValidateSampleMaskAtReference(decoration, inst, inst, inst);
  1989. }
  1990. spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference(
  1991. const Decoration& decoration, const Instruction& built_in_inst,
  1992. const Instruction& referenced_inst,
  1993. const Instruction& referenced_from_inst) {
  1994. if (spvIsVulkanEnv(_.context()->target_env)) {
  1995. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1996. if (storage_class != SpvStorageClassMax &&
  1997. storage_class != SpvStorageClassInput &&
  1998. storage_class != SpvStorageClassOutput) {
  1999. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2000. << _.VkErrorID(4358)
  2001. << "Vulkan spec allows BuiltIn SampleMask to be only used for "
  2002. "variables with Input or Output storage class. "
  2003. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2004. referenced_from_inst)
  2005. << " " << GetStorageClassDesc(referenced_from_inst);
  2006. }
  2007. for (const SpvExecutionModel execution_model : execution_models_) {
  2008. if (execution_model != SpvExecutionModelFragment) {
  2009. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2010. << _.VkErrorID(4357)
  2011. << "Vulkan spec allows BuiltIn SampleMask to be used only "
  2012. "with "
  2013. "Fragment execution model. "
  2014. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2015. referenced_from_inst, execution_model);
  2016. }
  2017. }
  2018. }
  2019. if (function_id_ == 0) {
  2020. // Propagate this rule to all dependant ids in the global scope.
  2021. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2022. &BuiltInsValidator::ValidateSampleMaskAtReference, this, decoration,
  2023. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2024. }
  2025. return SPV_SUCCESS;
  2026. }
  2027. spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition(
  2028. const Decoration& decoration, const Instruction& inst) {
  2029. if (spvIsVulkanEnv(_.context()->target_env)) {
  2030. if (spv_result_t error = ValidateF32Vec(
  2031. decoration, inst, 2,
  2032. [this, &inst](const std::string& message) -> spv_result_t {
  2033. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2034. << _.VkErrorID(4362)
  2035. << "According to the Vulkan spec BuiltIn SamplePosition "
  2036. "variable needs to be a 2-component 32-bit float "
  2037. "vector. "
  2038. << message;
  2039. })) {
  2040. return error;
  2041. }
  2042. }
  2043. // Seed at reference checks with this built-in.
  2044. return ValidateSamplePositionAtReference(decoration, inst, inst, inst);
  2045. }
  2046. spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference(
  2047. const Decoration& decoration, const Instruction& built_in_inst,
  2048. const Instruction& referenced_inst,
  2049. const Instruction& referenced_from_inst) {
  2050. if (spvIsVulkanEnv(_.context()->target_env)) {
  2051. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2052. if (storage_class != SpvStorageClassMax &&
  2053. storage_class != SpvStorageClassInput) {
  2054. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2055. << _.VkErrorID(4361)
  2056. << "Vulkan spec allows BuiltIn SamplePosition to be only used "
  2057. "for "
  2058. "variables with Input storage class. "
  2059. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2060. referenced_from_inst)
  2061. << " " << GetStorageClassDesc(referenced_from_inst);
  2062. }
  2063. for (const SpvExecutionModel execution_model : execution_models_) {
  2064. if (execution_model != SpvExecutionModelFragment) {
  2065. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2066. << _.VkErrorID(4360)
  2067. << "Vulkan spec allows BuiltIn SamplePosition to be used only "
  2068. "with "
  2069. "Fragment execution model. "
  2070. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2071. referenced_from_inst, execution_model);
  2072. }
  2073. }
  2074. }
  2075. if (function_id_ == 0) {
  2076. // Propagate this rule to all dependant ids in the global scope.
  2077. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2078. &BuiltInsValidator::ValidateSamplePositionAtReference, this, decoration,
  2079. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2080. }
  2081. return SPV_SUCCESS;
  2082. }
  2083. spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition(
  2084. const Decoration& decoration, const Instruction& inst) {
  2085. if (spvIsVulkanEnv(_.context()->target_env)) {
  2086. if (spv_result_t error = ValidateF32Vec(
  2087. decoration, inst, 3,
  2088. [this, &inst](const std::string& message) -> spv_result_t {
  2089. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2090. << _.VkErrorID(4389)
  2091. << "According to the Vulkan spec BuiltIn TessCoord "
  2092. "variable needs to be a 3-component 32-bit float "
  2093. "vector. "
  2094. << message;
  2095. })) {
  2096. return error;
  2097. }
  2098. }
  2099. // Seed at reference checks with this built-in.
  2100. return ValidateTessCoordAtReference(decoration, inst, inst, inst);
  2101. }
  2102. spv_result_t BuiltInsValidator::ValidateTessCoordAtReference(
  2103. const Decoration& decoration, const Instruction& built_in_inst,
  2104. const Instruction& referenced_inst,
  2105. const Instruction& referenced_from_inst) {
  2106. if (spvIsVulkanEnv(_.context()->target_env)) {
  2107. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2108. if (storage_class != SpvStorageClassMax &&
  2109. storage_class != SpvStorageClassInput) {
  2110. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2111. << _.VkErrorID(4388)
  2112. << "Vulkan spec allows BuiltIn TessCoord to be only used for "
  2113. "variables with Input storage class. "
  2114. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2115. referenced_from_inst)
  2116. << " " << GetStorageClassDesc(referenced_from_inst);
  2117. }
  2118. for (const SpvExecutionModel execution_model : execution_models_) {
  2119. if (execution_model != SpvExecutionModelTessellationEvaluation) {
  2120. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2121. << _.VkErrorID(4387)
  2122. << "Vulkan spec allows BuiltIn TessCoord to be used only with "
  2123. "TessellationEvaluation execution model. "
  2124. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2125. referenced_from_inst, execution_model);
  2126. }
  2127. }
  2128. }
  2129. if (function_id_ == 0) {
  2130. // Propagate this rule to all dependant ids in the global scope.
  2131. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2132. &BuiltInsValidator::ValidateTessCoordAtReference, this, decoration,
  2133. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2134. }
  2135. return SPV_SUCCESS;
  2136. }
  2137. spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
  2138. const Decoration& decoration, const Instruction& inst) {
  2139. if (spvIsVulkanEnv(_.context()->target_env)) {
  2140. if (spv_result_t error = ValidateF32Arr(
  2141. decoration, inst, 4,
  2142. [this, &inst](const std::string& message) -> spv_result_t {
  2143. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2144. << _.VkErrorID(4393)
  2145. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  2146. "variable needs to be a 4-component 32-bit float "
  2147. "array. "
  2148. << message;
  2149. })) {
  2150. return error;
  2151. }
  2152. }
  2153. // Seed at reference checks with this built-in.
  2154. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  2155. }
  2156. spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
  2157. const Decoration& decoration, const Instruction& inst) {
  2158. if (spvIsVulkanEnv(_.context()->target_env)) {
  2159. if (spv_result_t error = ValidateF32Arr(
  2160. decoration, inst, 2,
  2161. [this, &inst](const std::string& message) -> spv_result_t {
  2162. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2163. << _.VkErrorID(4397)
  2164. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  2165. "variable needs to be a 2-component 32-bit float "
  2166. "array. "
  2167. << message;
  2168. })) {
  2169. return error;
  2170. }
  2171. }
  2172. // Seed at reference checks with this built-in.
  2173. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  2174. }
  2175. spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
  2176. const Decoration& decoration, const Instruction& built_in_inst,
  2177. const Instruction& referenced_inst,
  2178. const Instruction& referenced_from_inst) {
  2179. uint32_t operand = decoration.params()[0];
  2180. if (spvIsVulkanEnv(_.context()->target_env)) {
  2181. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2182. if (storage_class != SpvStorageClassMax &&
  2183. storage_class != SpvStorageClassInput &&
  2184. storage_class != SpvStorageClassOutput) {
  2185. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2186. << "Vulkan spec allows BuiltIn "
  2187. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2188. operand)
  2189. << " to be only used for variables with Input or Output storage "
  2190. "class. "
  2191. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2192. referenced_from_inst)
  2193. << " " << GetStorageClassDesc(referenced_from_inst);
  2194. }
  2195. if (storage_class == SpvStorageClassInput) {
  2196. assert(function_id_ == 0);
  2197. uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4391 : 4395;
  2198. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2199. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  2200. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
  2201. "used "
  2202. "for variables with Input storage class if execution model is "
  2203. "TessellationControl.",
  2204. SpvExecutionModelTessellationControl, decoration, built_in_inst,
  2205. referenced_from_inst, std::placeholders::_1));
  2206. }
  2207. if (storage_class == SpvStorageClassOutput) {
  2208. assert(function_id_ == 0);
  2209. uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4392 : 4396;
  2210. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2211. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
  2212. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
  2213. "used "
  2214. "for variables with Output storage class if execution model is "
  2215. "TessellationEvaluation.",
  2216. SpvExecutionModelTessellationEvaluation, decoration, built_in_inst,
  2217. referenced_from_inst, std::placeholders::_1));
  2218. }
  2219. for (const SpvExecutionModel execution_model : execution_models_) {
  2220. switch (execution_model) {
  2221. case SpvExecutionModelTessellationControl:
  2222. case SpvExecutionModelTessellationEvaluation: {
  2223. // Ok.
  2224. break;
  2225. }
  2226. default: {
  2227. uint32_t vuid = (operand == SpvBuiltInTessLevelOuter) ? 4390 : 4394;
  2228. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2229. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2230. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2231. operand)
  2232. << " to be used only with TessellationControl or "
  2233. "TessellationEvaluation execution models. "
  2234. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2235. referenced_from_inst, execution_model);
  2236. }
  2237. }
  2238. }
  2239. }
  2240. if (function_id_ == 0) {
  2241. // Propagate this rule to all dependant ids in the global scope.
  2242. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2243. &BuiltInsValidator::ValidateTessLevelAtReference, this, decoration,
  2244. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2245. }
  2246. return SPV_SUCCESS;
  2247. }
  2248. spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
  2249. const Decoration& decoration, const Instruction& inst) {
  2250. if (spvIsVulkanEnv(_.context()->target_env)) {
  2251. if (spv_result_t error = ValidateI32(
  2252. decoration, inst,
  2253. [this, &inst](const std::string& message) -> spv_result_t {
  2254. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2255. << _.VkErrorID(4400) << "According to the "
  2256. << spvLogStringForEnv(_.context()->target_env)
  2257. << " spec BuiltIn VertexIndex variable needs to be a "
  2258. "32-bit int scalar. "
  2259. << message;
  2260. })) {
  2261. return error;
  2262. }
  2263. }
  2264. // Seed at reference checks with this built-in.
  2265. return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
  2266. }
  2267. spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
  2268. const Decoration& decoration, const Instruction& inst) {
  2269. (void)decoration;
  2270. if (spvIsVulkanEnv(_.context()->target_env)) {
  2271. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2272. << "Vulkan spec doesn't allow BuiltIn VertexId "
  2273. "to be used.";
  2274. }
  2275. return SPV_SUCCESS;
  2276. }
  2277. spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
  2278. const Decoration& decoration, const Instruction& inst) {
  2279. // Seed at reference checks with this built-in.
  2280. return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst);
  2281. }
  2282. spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
  2283. const Decoration& decoration, const Instruction& built_in_inst,
  2284. const Instruction&,
  2285. const Instruction& referenced_from_inst) {
  2286. if (function_id_ == 0) {
  2287. // Propagate this rule to all dependant ids in the global scope.
  2288. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2289. std::bind(&BuiltInsValidator::ValidateLocalInvocationIndexAtReference,
  2290. this, decoration, built_in_inst, referenced_from_inst,
  2291. std::placeholders::_1));
  2292. }
  2293. return SPV_SUCCESS;
  2294. }
  2295. spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
  2296. const Decoration& decoration, const Instruction& built_in_inst,
  2297. const Instruction& referenced_inst,
  2298. const Instruction& referenced_from_inst) {
  2299. if (spvIsVulkanEnv(_.context()->target_env)) {
  2300. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2301. if (storage_class != SpvStorageClassMax &&
  2302. storage_class != SpvStorageClassInput) {
  2303. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2304. << _.VkErrorID(4399) << spvLogStringForEnv(_.context()->target_env)
  2305. << " spec allows BuiltIn VertexIndex to be only used for "
  2306. "variables with Input storage class. "
  2307. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2308. referenced_from_inst)
  2309. << " " << GetStorageClassDesc(referenced_from_inst);
  2310. }
  2311. for (const SpvExecutionModel execution_model : execution_models_) {
  2312. if (execution_model != SpvExecutionModelVertex) {
  2313. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2314. << _.VkErrorID(4398)
  2315. << spvLogStringForEnv(_.context()->target_env)
  2316. << " spec allows BuiltIn VertexIndex to be used only with "
  2317. "Vertex execution model. "
  2318. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2319. referenced_from_inst, execution_model);
  2320. }
  2321. }
  2322. }
  2323. if (function_id_ == 0) {
  2324. // Propagate this rule to all dependant ids in the global scope.
  2325. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2326. &BuiltInsValidator::ValidateVertexIndexAtReference, this, decoration,
  2327. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2328. }
  2329. return SPV_SUCCESS;
  2330. }
  2331. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
  2332. const Decoration& decoration, const Instruction& inst) {
  2333. if (spvIsVulkanEnv(_.context()->target_env)) {
  2334. // This can be a per-primitive variable for mesh shader stage.
  2335. // In such cases variable will have an array of 32-bit integers.
  2336. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2337. // This must be a 32-bit int scalar.
  2338. if (spv_result_t error = ValidateI32(
  2339. decoration, inst,
  2340. [this, &decoration,
  2341. &inst](const std::string& message) -> spv_result_t {
  2342. uint32_t vuid =
  2343. (decoration.params()[0] == SpvBuiltInLayer) ? 4276 : 4408;
  2344. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2345. << _.VkErrorID(vuid)
  2346. << "According to the Vulkan spec BuiltIn "
  2347. << _.grammar().lookupOperandName(
  2348. SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
  2349. << "variable needs to be a 32-bit int scalar. "
  2350. << message;
  2351. })) {
  2352. return error;
  2353. }
  2354. } else {
  2355. if (spv_result_t error = ValidateOptionalArrayedI32(
  2356. decoration, inst,
  2357. [this, &decoration,
  2358. &inst](const std::string& message) -> spv_result_t {
  2359. uint32_t vuid =
  2360. (decoration.params()[0] == SpvBuiltInLayer) ? 4276 : 4408;
  2361. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2362. << _.VkErrorID(vuid)
  2363. << "According to the Vulkan spec BuiltIn "
  2364. << _.grammar().lookupOperandName(
  2365. SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0])
  2366. << "variable needs to be a 32-bit int scalar. "
  2367. << message;
  2368. })) {
  2369. return error;
  2370. }
  2371. }
  2372. }
  2373. // Seed at reference checks with this built-in.
  2374. return ValidateLayerOrViewportIndexAtReference(decoration, inst, inst, inst);
  2375. }
  2376. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
  2377. const Decoration& decoration, const Instruction& built_in_inst,
  2378. const Instruction& referenced_inst,
  2379. const Instruction& referenced_from_inst) {
  2380. uint32_t operand = decoration.params()[0];
  2381. if (spvIsVulkanEnv(_.context()->target_env)) {
  2382. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2383. if (storage_class != SpvStorageClassMax &&
  2384. storage_class != SpvStorageClassInput &&
  2385. storage_class != SpvStorageClassOutput) {
  2386. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2387. << "Vulkan spec allows BuiltIn "
  2388. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2389. operand)
  2390. << " to be only used for variables with Input or Output storage "
  2391. "class. "
  2392. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2393. referenced_from_inst)
  2394. << " " << GetStorageClassDesc(referenced_from_inst);
  2395. }
  2396. if (storage_class == SpvStorageClassInput) {
  2397. assert(function_id_ == 0);
  2398. for (const auto em :
  2399. {SpvExecutionModelVertex, SpvExecutionModelTessellationEvaluation,
  2400. SpvExecutionModelGeometry, SpvExecutionModelMeshNV}) {
  2401. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2402. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
  2403. this, ((operand == SpvBuiltInLayer) ? 4274 : 4406),
  2404. "Vulkan spec doesn't allow BuiltIn Layer and "
  2405. "ViewportIndex to be "
  2406. "used for variables with Input storage class if "
  2407. "execution model is Vertex, TessellationEvaluation, "
  2408. "Geometry, or MeshNV.",
  2409. em, decoration, built_in_inst, referenced_from_inst,
  2410. std::placeholders::_1));
  2411. }
  2412. }
  2413. if (storage_class == SpvStorageClassOutput) {
  2414. assert(function_id_ == 0);
  2415. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2416. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
  2417. this, ((operand == SpvBuiltInLayer) ? 4275 : 4407),
  2418. "Vulkan spec doesn't allow BuiltIn Layer and "
  2419. "ViewportIndex to be "
  2420. "used for variables with Output storage class if "
  2421. "execution model is "
  2422. "Fragment.",
  2423. SpvExecutionModelFragment, decoration, built_in_inst,
  2424. referenced_from_inst, std::placeholders::_1));
  2425. }
  2426. for (const SpvExecutionModel execution_model : execution_models_) {
  2427. switch (execution_model) {
  2428. case SpvExecutionModelGeometry:
  2429. case SpvExecutionModelFragment:
  2430. case SpvExecutionModelMeshNV:
  2431. // Ok.
  2432. break;
  2433. case SpvExecutionModelVertex:
  2434. case SpvExecutionModelTessellationEvaluation: {
  2435. if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) {
  2436. if (operand == SpvBuiltInViewportIndex &&
  2437. _.HasCapability(SpvCapabilityShaderViewportIndex))
  2438. break; // Ok
  2439. if (operand == SpvBuiltInLayer &&
  2440. _.HasCapability(SpvCapabilityShaderLayer))
  2441. break; // Ok
  2442. const char* capability = "ShaderViewportIndexLayerEXT";
  2443. if (operand == SpvBuiltInViewportIndex)
  2444. capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex";
  2445. if (operand == SpvBuiltInLayer)
  2446. capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
  2447. uint32_t vuid = (operand == SpvBuiltInLayer) ? 4273 : 4405;
  2448. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2449. << _.VkErrorID(vuid) << "Using BuiltIn "
  2450. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2451. operand)
  2452. << " in Vertex or Tessellation execution model requires the "
  2453. << capability << " capability.";
  2454. }
  2455. break;
  2456. }
  2457. default: {
  2458. uint32_t vuid = (operand == SpvBuiltInLayer) ? 4272 : 4404;
  2459. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2460. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2461. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2462. operand)
  2463. << " to be used only with Vertex, TessellationEvaluation, "
  2464. "Geometry, or Fragment execution models. "
  2465. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2466. referenced_from_inst, execution_model);
  2467. }
  2468. }
  2469. }
  2470. }
  2471. if (function_id_ == 0) {
  2472. // Propagate this rule to all dependant ids in the global scope.
  2473. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2474. std::bind(&BuiltInsValidator::ValidateLayerOrViewportIndexAtReference,
  2475. this, decoration, built_in_inst, referenced_from_inst,
  2476. std::placeholders::_1));
  2477. }
  2478. return SPV_SUCCESS;
  2479. }
  2480. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
  2481. const Decoration& decoration, const Instruction& inst) {
  2482. if (spvIsVulkanEnv(_.context()->target_env)) {
  2483. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2484. if (spv_result_t error = ValidateI32Vec(
  2485. decoration, inst, 3,
  2486. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2487. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2488. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2489. << _.VkErrorID(vuid) << "According to the "
  2490. << spvLogStringForEnv(_.context()->target_env)
  2491. << " spec BuiltIn "
  2492. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2493. builtin)
  2494. << " variable needs to be a 3-component 32-bit int "
  2495. "vector. "
  2496. << message;
  2497. })) {
  2498. return error;
  2499. }
  2500. }
  2501. // Seed at reference checks with this built-in.
  2502. return ValidateComputeShaderI32Vec3InputAtReference(decoration, inst, inst,
  2503. inst);
  2504. }
  2505. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
  2506. const Decoration& decoration, const Instruction& built_in_inst,
  2507. const Instruction& referenced_inst,
  2508. const Instruction& referenced_from_inst) {
  2509. if (spvIsVulkanEnv(_.context()->target_env)) {
  2510. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2511. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2512. if (storage_class != SpvStorageClassMax &&
  2513. storage_class != SpvStorageClassInput) {
  2514. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2515. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2516. << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
  2517. << " spec allows BuiltIn "
  2518. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2519. << " to be only used for variables with Input storage class. "
  2520. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2521. referenced_from_inst)
  2522. << " " << GetStorageClassDesc(referenced_from_inst);
  2523. }
  2524. for (const SpvExecutionModel execution_model : execution_models_) {
  2525. bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
  2526. execution_model == SpvExecutionModelTaskNV ||
  2527. execution_model == SpvExecutionModelMeshNV;
  2528. if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
  2529. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  2530. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2531. << _.VkErrorID(vuid)
  2532. << spvLogStringForEnv(_.context()->target_env)
  2533. << " spec allows BuiltIn "
  2534. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2535. << " to be used only with GLCompute execution model. "
  2536. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2537. referenced_from_inst, execution_model);
  2538. }
  2539. }
  2540. }
  2541. if (function_id_ == 0) {
  2542. // Propagate this rule to all dependant ids in the global scope.
  2543. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2544. &BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference, this,
  2545. decoration, built_in_inst, referenced_from_inst,
  2546. std::placeholders::_1));
  2547. }
  2548. return SPV_SUCCESS;
  2549. }
  2550. spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
  2551. const Decoration& decoration, const Instruction& inst) {
  2552. if (spvIsVulkanEnv(_.context()->target_env)) {
  2553. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2554. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2555. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2556. << "BuiltIn "
  2557. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2558. << " cannot be used as a member decoration ";
  2559. }
  2560. if (spv_result_t error = ValidateI32(
  2561. decoration, inst,
  2562. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2563. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2564. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2565. << _.VkErrorID(vuid)
  2566. << "According to the "
  2567. << spvLogStringForEnv(_.context()->target_env)
  2568. << " spec BuiltIn "
  2569. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2570. << " variable needs to be a 32-bit int "
  2571. "vector. "
  2572. << message;
  2573. })) {
  2574. return error;
  2575. }
  2576. }
  2577. // Seed at reference checks with this built-in.
  2578. return ValidateComputeI32InputAtReference(decoration, inst, inst, inst);
  2579. }
  2580. spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
  2581. const Decoration& decoration, const Instruction& built_in_inst,
  2582. const Instruction& referenced_inst,
  2583. const Instruction& referenced_from_inst) {
  2584. if (spvIsVulkanEnv(_.context()->target_env)) {
  2585. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2586. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2587. if (storage_class != SpvStorageClassMax &&
  2588. storage_class != SpvStorageClassInput) {
  2589. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2590. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2591. << _.VkErrorID(vuid)
  2592. << spvLogStringForEnv(_.context()->target_env)
  2593. << " spec allows BuiltIn "
  2594. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2595. << " to be only used for variables with Input storage class. "
  2596. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2597. referenced_from_inst)
  2598. << " " << GetStorageClassDesc(referenced_from_inst);
  2599. }
  2600. for (const SpvExecutionModel execution_model : execution_models_) {
  2601. bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
  2602. execution_model == SpvExecutionModelTaskNV ||
  2603. execution_model == SpvExecutionModelMeshNV;
  2604. if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
  2605. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  2606. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2607. << _.VkErrorID(vuid)
  2608. << spvLogStringForEnv(_.context()->target_env)
  2609. << " spec allows BuiltIn "
  2610. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2611. << " to be used only with GLCompute execution model. "
  2612. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2613. referenced_from_inst, execution_model);
  2614. }
  2615. }
  2616. }
  2617. if (function_id_ == 0) {
  2618. // Propagate this rule to all dependant ids in the global scope.
  2619. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2620. std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this,
  2621. decoration, built_in_inst, referenced_from_inst,
  2622. std::placeholders::_1));
  2623. }
  2624. return SPV_SUCCESS;
  2625. }
  2626. spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
  2627. const Decoration& decoration, const Instruction& inst) {
  2628. if (spvIsVulkanEnv(_.context()->target_env)) {
  2629. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2630. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2631. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2632. << "BuiltIn "
  2633. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2634. << " cannot be used as a member decoration ";
  2635. }
  2636. if (spv_result_t error = ValidateI32(
  2637. decoration, inst,
  2638. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2639. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2640. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2641. << _.VkErrorID(vuid)
  2642. << "According to the "
  2643. << spvLogStringForEnv(_.context()->target_env)
  2644. << " spec BuiltIn "
  2645. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2646. << " variable needs to be a 32-bit int. " << message;
  2647. })) {
  2648. return error;
  2649. }
  2650. const SpvStorageClass storage_class = GetStorageClass(inst);
  2651. if (storage_class != SpvStorageClassMax &&
  2652. storage_class != SpvStorageClassInput) {
  2653. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2654. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2655. << _.VkErrorID(vuid)
  2656. << spvLogStringForEnv(_.context()->target_env)
  2657. << " spec allows BuiltIn "
  2658. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2659. << " to be only used for variables with Input storage class. "
  2660. << GetReferenceDesc(decoration, inst, inst, inst) << " "
  2661. << GetStorageClassDesc(inst);
  2662. }
  2663. }
  2664. return SPV_SUCCESS;
  2665. }
  2666. spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
  2667. const Decoration& decoration, const Instruction& inst) {
  2668. if (spvIsVulkanEnv(_.context()->target_env)) {
  2669. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  2670. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  2671. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2672. << "BuiltIn "
  2673. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2674. << " cannot be used as a member decoration ";
  2675. }
  2676. if (spv_result_t error = ValidateI32Vec(
  2677. decoration, inst, 4,
  2678. [this, &inst, builtin](const std::string& message) -> spv_result_t {
  2679. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  2680. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2681. << _.VkErrorID(vuid)
  2682. << "According to the "
  2683. << spvLogStringForEnv(_.context()->target_env)
  2684. << " spec BuiltIn "
  2685. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2686. << " variable needs to be a 4-component 32-bit int "
  2687. "vector. "
  2688. << message;
  2689. })) {
  2690. return error;
  2691. }
  2692. const SpvStorageClass storage_class = GetStorageClass(inst);
  2693. if (storage_class != SpvStorageClassMax &&
  2694. storage_class != SpvStorageClassInput) {
  2695. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  2696. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2697. << _.VkErrorID(vuid)
  2698. << spvLogStringForEnv(_.context()->target_env)
  2699. << " spec allows BuiltIn "
  2700. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin)
  2701. << " to be only used for variables with Input storage class. "
  2702. << GetReferenceDesc(decoration, inst, inst, inst) << " "
  2703. << GetStorageClassDesc(inst);
  2704. }
  2705. }
  2706. return SPV_SUCCESS;
  2707. }
  2708. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
  2709. const Decoration& decoration, const Instruction& inst) {
  2710. if (spvIsVulkanEnv(_.context()->target_env)) {
  2711. if (spvIsVulkanEnv(_.context()->target_env) &&
  2712. !spvOpcodeIsConstant(inst.opcode())) {
  2713. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2714. << _.VkErrorID(4426)
  2715. << "Vulkan spec requires BuiltIn WorkgroupSize to be a "
  2716. "constant. "
  2717. << GetIdDesc(inst) << " is not a constant.";
  2718. }
  2719. if (spv_result_t error = ValidateI32Vec(
  2720. decoration, inst, 3,
  2721. [this, &inst](const std::string& message) -> spv_result_t {
  2722. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2723. << _.VkErrorID(4427) << "According to the "
  2724. << spvLogStringForEnv(_.context()->target_env)
  2725. << " spec BuiltIn WorkgroupSize variable needs to be a "
  2726. "3-component 32-bit int vector. "
  2727. << message;
  2728. })) {
  2729. return error;
  2730. }
  2731. }
  2732. // Seed at reference checks with this built-in.
  2733. return ValidateWorkgroupSizeAtReference(decoration, inst, inst, inst);
  2734. }
  2735. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
  2736. const Decoration& decoration, const Instruction& built_in_inst,
  2737. const Instruction& referenced_inst,
  2738. const Instruction& referenced_from_inst) {
  2739. if (spvIsVulkanEnv(_.context()->target_env)) {
  2740. for (const SpvExecutionModel execution_model : execution_models_) {
  2741. if (execution_model != SpvExecutionModelGLCompute) {
  2742. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2743. << _.VkErrorID(4425)
  2744. << spvLogStringForEnv(_.context()->target_env)
  2745. << " spec allows BuiltIn "
  2746. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2747. decoration.params()[0])
  2748. << " to be used only with GLCompute execution model. "
  2749. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2750. referenced_from_inst, execution_model);
  2751. }
  2752. }
  2753. }
  2754. if (function_id_ == 0) {
  2755. // Propagate this rule to all dependant ids in the global scope.
  2756. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2757. &BuiltInsValidator::ValidateWorkgroupSizeAtReference, this, decoration,
  2758. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2759. }
  2760. return SPV_SUCCESS;
  2761. }
  2762. spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtDefinition(
  2763. const Decoration& decoration, const Instruction& inst) {
  2764. if (spvIsVulkanEnv(_.context()->target_env)) {
  2765. if (spv_result_t error = ValidateI32(
  2766. decoration, inst,
  2767. [this, &inst,
  2768. &decoration](const std::string& message) -> spv_result_t {
  2769. uint32_t vuid = (decoration.params()[0] == SpvBuiltInBaseInstance)
  2770. ? 4183
  2771. : 4186;
  2772. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2773. << _.VkErrorID(vuid)
  2774. << "According to the Vulkan spec BuiltIn "
  2775. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2776. decoration.params()[0])
  2777. << " variable needs to be a 32-bit int scalar. "
  2778. << message;
  2779. })) {
  2780. return error;
  2781. }
  2782. }
  2783. return ValidateBaseInstanceOrVertexAtReference(decoration, inst, inst, inst);
  2784. }
  2785. spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference(
  2786. const Decoration& decoration, const Instruction& built_in_inst,
  2787. const Instruction& referenced_inst,
  2788. const Instruction& referenced_from_inst) {
  2789. uint32_t operand = decoration.params()[0];
  2790. if (spvIsVulkanEnv(_.context()->target_env)) {
  2791. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2792. if (storage_class != SpvStorageClassMax &&
  2793. storage_class != SpvStorageClassInput) {
  2794. uint32_t vuid = (operand == SpvBuiltInBaseInstance) ? 4182 : 4185;
  2795. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2796. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2797. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2798. operand)
  2799. << " to be only used for variables with Input storage class. "
  2800. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2801. referenced_from_inst)
  2802. << " " << GetStorageClassDesc(referenced_from_inst);
  2803. }
  2804. for (const SpvExecutionModel execution_model : execution_models_) {
  2805. if (execution_model != SpvExecutionModelVertex) {
  2806. uint32_t vuid = (operand == SpvBuiltInBaseInstance) ? 4181 : 4184;
  2807. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2808. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  2809. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2810. operand)
  2811. << " to be used only with Vertex execution model. "
  2812. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2813. referenced_from_inst, execution_model);
  2814. }
  2815. }
  2816. }
  2817. if (function_id_ == 0) {
  2818. // Propagate this rule to all dependant ids in the global scope.
  2819. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  2820. std::bind(&BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference,
  2821. this, decoration, built_in_inst, referenced_from_inst,
  2822. std::placeholders::_1));
  2823. }
  2824. return SPV_SUCCESS;
  2825. }
  2826. spv_result_t BuiltInsValidator::ValidateDrawIndexAtDefinition(
  2827. const Decoration& decoration, const Instruction& inst) {
  2828. if (spvIsVulkanEnv(_.context()->target_env)) {
  2829. if (spv_result_t error = ValidateI32(
  2830. decoration, inst,
  2831. [this, &inst,
  2832. &decoration](const std::string& message) -> spv_result_t {
  2833. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2834. << _.VkErrorID(4209)
  2835. << "According to the Vulkan spec BuiltIn "
  2836. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2837. decoration.params()[0])
  2838. << " variable needs to be a 32-bit int scalar. "
  2839. << message;
  2840. })) {
  2841. return error;
  2842. }
  2843. }
  2844. return ValidateDrawIndexAtReference(decoration, inst, inst, inst);
  2845. }
  2846. spv_result_t BuiltInsValidator::ValidateDrawIndexAtReference(
  2847. const Decoration& decoration, const Instruction& built_in_inst,
  2848. const Instruction& referenced_inst,
  2849. const Instruction& referenced_from_inst) {
  2850. uint32_t operand = decoration.params()[0];
  2851. if (spvIsVulkanEnv(_.context()->target_env)) {
  2852. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2853. if (storage_class != SpvStorageClassMax &&
  2854. storage_class != SpvStorageClassInput) {
  2855. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2856. << _.VkErrorID(4208) << "Vulkan spec allows BuiltIn "
  2857. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2858. operand)
  2859. << " to be only used for variables with Input storage class. "
  2860. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2861. referenced_from_inst)
  2862. << " " << GetStorageClassDesc(referenced_from_inst);
  2863. }
  2864. for (const SpvExecutionModel execution_model : execution_models_) {
  2865. if (execution_model != SpvExecutionModelVertex &&
  2866. execution_model != SpvExecutionModelMeshNV &&
  2867. execution_model != SpvExecutionModelTaskNV) {
  2868. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2869. << _.VkErrorID(4207) << "Vulkan spec allows BuiltIn "
  2870. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2871. operand)
  2872. << " to be used only with Vertex, MeshNV, or TaskNV execution "
  2873. "model. "
  2874. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2875. referenced_from_inst, execution_model);
  2876. }
  2877. }
  2878. }
  2879. if (function_id_ == 0) {
  2880. // Propagate this rule to all dependant ids in the global scope.
  2881. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2882. &BuiltInsValidator::ValidateDrawIndexAtReference, this, decoration,
  2883. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2884. }
  2885. return SPV_SUCCESS;
  2886. }
  2887. spv_result_t BuiltInsValidator::ValidateViewIndexAtDefinition(
  2888. const Decoration& decoration, const Instruction& inst) {
  2889. if (spvIsVulkanEnv(_.context()->target_env)) {
  2890. if (spv_result_t error = ValidateI32(
  2891. decoration, inst,
  2892. [this, &inst,
  2893. &decoration](const std::string& message) -> spv_result_t {
  2894. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2895. << _.VkErrorID(4403)
  2896. << "According to the Vulkan spec BuiltIn "
  2897. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2898. decoration.params()[0])
  2899. << " variable needs to be a 32-bit int scalar. "
  2900. << message;
  2901. })) {
  2902. return error;
  2903. }
  2904. }
  2905. return ValidateViewIndexAtReference(decoration, inst, inst, inst);
  2906. }
  2907. spv_result_t BuiltInsValidator::ValidateViewIndexAtReference(
  2908. const Decoration& decoration, const Instruction& built_in_inst,
  2909. const Instruction& referenced_inst,
  2910. const Instruction& referenced_from_inst) {
  2911. uint32_t operand = decoration.params()[0];
  2912. if (spvIsVulkanEnv(_.context()->target_env)) {
  2913. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2914. if (storage_class != SpvStorageClassMax &&
  2915. storage_class != SpvStorageClassInput) {
  2916. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2917. << _.VkErrorID(4402) << "Vulkan spec allows BuiltIn "
  2918. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2919. operand)
  2920. << " to be only used for variables with Input storage class. "
  2921. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2922. referenced_from_inst)
  2923. << " " << GetStorageClassDesc(referenced_from_inst);
  2924. }
  2925. for (const SpvExecutionModel execution_model : execution_models_) {
  2926. if (execution_model == SpvExecutionModelGLCompute) {
  2927. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2928. << _.VkErrorID(4401) << "Vulkan spec allows BuiltIn "
  2929. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2930. operand)
  2931. << " to be not be used with GLCompute execution model. "
  2932. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2933. referenced_from_inst, execution_model);
  2934. }
  2935. }
  2936. }
  2937. if (function_id_ == 0) {
  2938. // Propagate this rule to all dependant ids in the global scope.
  2939. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2940. &BuiltInsValidator::ValidateViewIndexAtReference, this, decoration,
  2941. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2942. }
  2943. return SPV_SUCCESS;
  2944. }
  2945. spv_result_t BuiltInsValidator::ValidateDeviceIndexAtDefinition(
  2946. const Decoration& decoration, const Instruction& inst) {
  2947. if (spvIsVulkanEnv(_.context()->target_env)) {
  2948. if (spv_result_t error = ValidateI32(
  2949. decoration, inst,
  2950. [this, &inst,
  2951. &decoration](const std::string& message) -> spv_result_t {
  2952. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  2953. << _.VkErrorID(4206)
  2954. << "According to the Vulkan spec BuiltIn "
  2955. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2956. decoration.params()[0])
  2957. << " variable needs to be a 32-bit int scalar. "
  2958. << message;
  2959. })) {
  2960. return error;
  2961. }
  2962. }
  2963. return ValidateDeviceIndexAtReference(decoration, inst, inst, inst);
  2964. }
  2965. spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference(
  2966. const Decoration& decoration, const Instruction& built_in_inst,
  2967. const Instruction& referenced_inst,
  2968. const Instruction& referenced_from_inst) {
  2969. uint32_t operand = decoration.params()[0];
  2970. if (spvIsVulkanEnv(_.context()->target_env)) {
  2971. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  2972. if (storage_class != SpvStorageClassMax &&
  2973. storage_class != SpvStorageClassInput) {
  2974. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  2975. << _.VkErrorID(4205) << "Vulkan spec allows BuiltIn "
  2976. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  2977. operand)
  2978. << " to be only used for variables with Input storage class. "
  2979. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  2980. referenced_from_inst)
  2981. << " " << GetStorageClassDesc(referenced_from_inst);
  2982. }
  2983. }
  2984. if (function_id_ == 0) {
  2985. // Propagate this rule to all dependant ids in the global scope.
  2986. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  2987. &BuiltInsValidator::ValidateDeviceIndexAtReference, this, decoration,
  2988. built_in_inst, referenced_from_inst, std::placeholders::_1));
  2989. }
  2990. return SPV_SUCCESS;
  2991. }
  2992. spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition(
  2993. const Decoration& decoration, const Instruction& inst) {
  2994. if (spvIsVulkanEnv(_.context()->target_env)) {
  2995. if (spv_result_t error = ValidateI32(
  2996. decoration, inst,
  2997. [this, &inst,
  2998. &decoration](const std::string& message) -> spv_result_t {
  2999. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3000. << "According to the "
  3001. << spvLogStringForEnv(_.context()->target_env)
  3002. << " spec BuiltIn "
  3003. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3004. decoration.params()[0])
  3005. << " variable needs to be a 32-bit int scalar. "
  3006. << message;
  3007. })) {
  3008. return error;
  3009. }
  3010. }
  3011. // Seed at reference checks with this built-in.
  3012. return ValidateSMBuiltinsAtReference(decoration, inst, inst, inst);
  3013. }
  3014. spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference(
  3015. const Decoration& decoration, const Instruction& built_in_inst,
  3016. const Instruction& referenced_inst,
  3017. const Instruction& referenced_from_inst) {
  3018. if (spvIsVulkanEnv(_.context()->target_env)) {
  3019. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  3020. if (storage_class != SpvStorageClassMax &&
  3021. storage_class != SpvStorageClassInput) {
  3022. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3023. << spvLogStringForEnv(_.context()->target_env)
  3024. << " spec allows BuiltIn "
  3025. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3026. decoration.params()[0])
  3027. << " to be only used for "
  3028. "variables with Input storage class. "
  3029. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3030. referenced_from_inst)
  3031. << " " << GetStorageClassDesc(referenced_from_inst);
  3032. }
  3033. }
  3034. if (function_id_ == 0) {
  3035. // Propagate this rule to all dependant ids in the global scope.
  3036. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3037. &BuiltInsValidator::ValidateSMBuiltinsAtReference, this, decoration,
  3038. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3039. }
  3040. return SPV_SUCCESS;
  3041. }
  3042. spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition(
  3043. const Decoration& decoration, const Instruction& inst) {
  3044. if (spvIsVulkanEnv(_.context()->target_env)) {
  3045. if (spv_result_t error = ValidateI32(
  3046. decoration, inst,
  3047. [this, &inst,
  3048. &decoration](const std::string& message) -> spv_result_t {
  3049. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3050. << _.VkErrorID(4486)
  3051. << "According to the Vulkan spec BuiltIn "
  3052. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3053. decoration.params()[0])
  3054. << " variable needs to be a 32-bit int scalar. "
  3055. << message;
  3056. })) {
  3057. return error;
  3058. }
  3059. }
  3060. // Seed at reference checks with this built-in.
  3061. return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst);
  3062. }
  3063. spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference(
  3064. const Decoration& decoration, const Instruction& built_in_inst,
  3065. const Instruction& referenced_inst,
  3066. const Instruction& referenced_from_inst) {
  3067. if (spvIsVulkanEnv(_.context()->target_env)) {
  3068. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  3069. if (storage_class != SpvStorageClassMax &&
  3070. storage_class != SpvStorageClassOutput) {
  3071. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3072. << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn "
  3073. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3074. decoration.params()[0])
  3075. << " to be only used for variables with Output storage class. "
  3076. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3077. referenced_from_inst)
  3078. << " " << GetStorageClassDesc(referenced_from_inst);
  3079. }
  3080. for (const SpvExecutionModel execution_model : execution_models_) {
  3081. switch (execution_model) {
  3082. case SpvExecutionModelVertex:
  3083. case SpvExecutionModelGeometry:
  3084. case SpvExecutionModelMeshNV:
  3085. break;
  3086. default: {
  3087. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3088. << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn "
  3089. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3090. decoration.params()[0])
  3091. << " to be used only with Vertex, Geometry, or MeshNV "
  3092. "execution models. "
  3093. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3094. referenced_from_inst, execution_model);
  3095. }
  3096. }
  3097. }
  3098. }
  3099. if (function_id_ == 0) {
  3100. // Propagate this rule to all dependant ids in the global scope.
  3101. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  3102. std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference,
  3103. this, decoration, built_in_inst, referenced_from_inst,
  3104. std::placeholders::_1));
  3105. }
  3106. return SPV_SUCCESS;
  3107. }
  3108. spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition(
  3109. const Decoration& decoration, const Instruction& inst) {
  3110. if (spvIsVulkanEnv(_.context()->target_env)) {
  3111. if (spv_result_t error = ValidateI32(
  3112. decoration, inst,
  3113. [this, &inst,
  3114. &decoration](const std::string& message) -> spv_result_t {
  3115. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3116. << _.VkErrorID(4492)
  3117. << "According to the Vulkan spec BuiltIn "
  3118. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3119. decoration.params()[0])
  3120. << " variable needs to be a 32-bit int scalar. "
  3121. << message;
  3122. })) {
  3123. return error;
  3124. }
  3125. }
  3126. // Seed at reference checks with this built-in.
  3127. return ValidateShadingRateAtReference(decoration, inst, inst, inst);
  3128. }
  3129. spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
  3130. const Decoration& decoration, const Instruction& built_in_inst,
  3131. const Instruction& referenced_inst,
  3132. const Instruction& referenced_from_inst) {
  3133. if (spvIsVulkanEnv(_.context()->target_env)) {
  3134. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  3135. if (storage_class != SpvStorageClassMax &&
  3136. storage_class != SpvStorageClassInput) {
  3137. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3138. << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn "
  3139. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3140. decoration.params()[0])
  3141. << " to be only used for variables with Input storage class. "
  3142. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3143. referenced_from_inst)
  3144. << " " << GetStorageClassDesc(referenced_from_inst);
  3145. }
  3146. for (const SpvExecutionModel execution_model : execution_models_) {
  3147. if (execution_model != SpvExecutionModelFragment) {
  3148. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3149. << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn "
  3150. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3151. decoration.params()[0])
  3152. << " to be used only with the Fragment execution model. "
  3153. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3154. referenced_from_inst, execution_model);
  3155. }
  3156. }
  3157. }
  3158. if (function_id_ == 0) {
  3159. // Propagate this rule to all dependant ids in the global scope.
  3160. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  3161. &BuiltInsValidator::ValidateShadingRateAtReference, this, decoration,
  3162. built_in_inst, referenced_from_inst, std::placeholders::_1));
  3163. }
  3164. return SPV_SUCCESS;
  3165. }
  3166. spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
  3167. const Decoration& decoration, const Instruction& inst) {
  3168. if (spvIsVulkanEnv(_.context()->target_env)) {
  3169. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  3170. switch (builtin) {
  3171. case SpvBuiltInHitTNV:
  3172. case SpvBuiltInRayTminKHR:
  3173. case SpvBuiltInRayTmaxKHR:
  3174. // f32 scalar
  3175. if (spv_result_t error = ValidateF32(
  3176. decoration, inst,
  3177. [this, &inst,
  3178. builtin](const std::string& message) -> spv_result_t {
  3179. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3180. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3181. << _.VkErrorID(vuid)
  3182. << "According to the Vulkan spec BuiltIn "
  3183. << _.grammar().lookupOperandName(
  3184. SPV_OPERAND_TYPE_BUILT_IN, builtin)
  3185. << " variable needs to be a 32-bit float scalar. "
  3186. << message;
  3187. })) {
  3188. return error;
  3189. }
  3190. break;
  3191. case SpvBuiltInHitKindKHR:
  3192. case SpvBuiltInInstanceCustomIndexKHR:
  3193. case SpvBuiltInInstanceId:
  3194. case SpvBuiltInRayGeometryIndexKHR:
  3195. case SpvBuiltInIncomingRayFlagsKHR:
  3196. // i32 scalar
  3197. if (spv_result_t error = ValidateI32(
  3198. decoration, inst,
  3199. [this, &inst,
  3200. builtin](const std::string& message) -> spv_result_t {
  3201. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3202. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3203. << _.VkErrorID(vuid)
  3204. << "According to the Vulkan spec BuiltIn "
  3205. << _.grammar().lookupOperandName(
  3206. SPV_OPERAND_TYPE_BUILT_IN, builtin)
  3207. << " variable needs to be a 32-bit int scalar. "
  3208. << message;
  3209. })) {
  3210. return error;
  3211. }
  3212. break;
  3213. case SpvBuiltInObjectRayDirectionKHR:
  3214. case SpvBuiltInObjectRayOriginKHR:
  3215. case SpvBuiltInWorldRayDirectionKHR:
  3216. case SpvBuiltInWorldRayOriginKHR:
  3217. // f32 vec3
  3218. if (spv_result_t error = ValidateF32Vec(
  3219. decoration, inst, 3,
  3220. [this, &inst,
  3221. builtin](const std::string& message) -> spv_result_t {
  3222. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3223. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3224. << _.VkErrorID(vuid)
  3225. << "According to the Vulkan spec BuiltIn "
  3226. << _.grammar().lookupOperandName(
  3227. SPV_OPERAND_TYPE_BUILT_IN, builtin)
  3228. << " variable needs to be a 3-component 32-bit float "
  3229. "vector. "
  3230. << message;
  3231. })) {
  3232. return error;
  3233. }
  3234. break;
  3235. case SpvBuiltInLaunchIdKHR:
  3236. case SpvBuiltInLaunchSizeKHR:
  3237. // i32 vec3
  3238. if (spv_result_t error = ValidateI32Vec(
  3239. decoration, inst, 3,
  3240. [this, &inst,
  3241. builtin](const std::string& message) -> spv_result_t {
  3242. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3243. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3244. << _.VkErrorID(vuid)
  3245. << "According to the Vulkan spec BuiltIn "
  3246. << _.grammar().lookupOperandName(
  3247. SPV_OPERAND_TYPE_BUILT_IN, builtin)
  3248. << " variable needs to be a 3-component 32-bit int "
  3249. "vector. "
  3250. << message;
  3251. })) {
  3252. return error;
  3253. }
  3254. break;
  3255. case SpvBuiltInObjectToWorldKHR:
  3256. case SpvBuiltInWorldToObjectKHR:
  3257. // f32 mat4x3
  3258. if (spv_result_t error = ValidateF32Mat(
  3259. decoration, inst, 3, 4,
  3260. [this, &inst,
  3261. builtin](const std::string& message) -> spv_result_t {
  3262. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
  3263. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3264. << _.VkErrorID(vuid)
  3265. << "According to the Vulkan spec BuiltIn "
  3266. << _.grammar().lookupOperandName(
  3267. SPV_OPERAND_TYPE_BUILT_IN, builtin)
  3268. << " variable needs to be a matrix with"
  3269. << " 4 columns of 3-component vectors of 32-bit "
  3270. "floats. "
  3271. << message;
  3272. })) {
  3273. return error;
  3274. }
  3275. break;
  3276. default:
  3277. assert(0 && "Unexpected ray tracing builtin");
  3278. break;
  3279. }
  3280. }
  3281. // Seed at reference checks with this built-in.
  3282. return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
  3283. }
  3284. spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
  3285. const Decoration& decoration, const Instruction& built_in_inst,
  3286. const Instruction& referenced_inst,
  3287. const Instruction& referenced_from_inst) {
  3288. if (spvIsVulkanEnv(_.context()->target_env)) {
  3289. const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
  3290. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  3291. if (storage_class != SpvStorageClassMax &&
  3292. storage_class != SpvStorageClassInput) {
  3293. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
  3294. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3295. << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
  3296. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3297. decoration.params()[0])
  3298. << " to be only used for variables with Input storage class. "
  3299. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3300. referenced_from_inst)
  3301. << " " << GetStorageClassDesc(referenced_from_inst);
  3302. }
  3303. for (const SpvExecutionModel execution_model : execution_models_) {
  3304. if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
  3305. uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
  3306. return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
  3307. << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
  3308. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  3309. decoration.params()[0])
  3310. << " to be used with the execution model "
  3311. << _.grammar().lookupOperandName(
  3312. SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model)
  3313. << ".\n"
  3314. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  3315. referenced_from_inst, execution_model);
  3316. }
  3317. }
  3318. }
  3319. if (function_id_ == 0) {
  3320. // Propagate this rule to all dependant ids in the global scope.
  3321. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  3322. std::bind(&BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
  3323. this, decoration, built_in_inst, referenced_from_inst,
  3324. std::placeholders::_1));
  3325. }
  3326. return SPV_SUCCESS;
  3327. }
  3328. spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
  3329. const Decoration& decoration, const Instruction& inst) {
  3330. const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
  3331. // Builtins can only be applied to variables, structures or constants.
  3332. auto target_opcode = inst.opcode();
  3333. if (target_opcode != SpvOpTypeStruct && target_opcode != SpvOpVariable &&
  3334. !spvOpcodeIsConstant(target_opcode)) {
  3335. return _.diag(SPV_ERROR_INVALID_DATA, &inst)
  3336. << "BuiltIns can only target variables, structs or constants";
  3337. }
  3338. if (!spvIsVulkanEnv(_.context()->target_env)) {
  3339. // Early return. All currently implemented rules are based on Vulkan spec.
  3340. //
  3341. // TODO: If you are adding validation rules for environments other than
  3342. // Vulkan (or general rules which are not environment independent), then
  3343. // you need to modify or remove this condition. Consider also adding early
  3344. // returns into BuiltIn-specific rules, so that the system doesn't spawn new
  3345. // rules which don't do anything.
  3346. return SPV_SUCCESS;
  3347. }
  3348. // If you are adding a new BuiltIn enum, please register it here.
  3349. // If the newly added enum has validation rules associated with it
  3350. // consider leaving a TODO and/or creating an issue.
  3351. switch (label) {
  3352. case SpvBuiltInClipDistance:
  3353. case SpvBuiltInCullDistance: {
  3354. return ValidateClipOrCullDistanceAtDefinition(decoration, inst);
  3355. }
  3356. case SpvBuiltInFragCoord: {
  3357. return ValidateFragCoordAtDefinition(decoration, inst);
  3358. }
  3359. case SpvBuiltInFragDepth: {
  3360. return ValidateFragDepthAtDefinition(decoration, inst);
  3361. }
  3362. case SpvBuiltInFrontFacing: {
  3363. return ValidateFrontFacingAtDefinition(decoration, inst);
  3364. }
  3365. case SpvBuiltInGlobalInvocationId:
  3366. case SpvBuiltInLocalInvocationId:
  3367. case SpvBuiltInNumWorkgroups:
  3368. case SpvBuiltInWorkgroupId: {
  3369. return ValidateComputeShaderI32Vec3InputAtDefinition(decoration, inst);
  3370. }
  3371. case SpvBuiltInHelperInvocation: {
  3372. return ValidateHelperInvocationAtDefinition(decoration, inst);
  3373. }
  3374. case SpvBuiltInInvocationId: {
  3375. return ValidateInvocationIdAtDefinition(decoration, inst);
  3376. }
  3377. case SpvBuiltInInstanceIndex: {
  3378. return ValidateInstanceIndexAtDefinition(decoration, inst);
  3379. }
  3380. case SpvBuiltInLayer:
  3381. case SpvBuiltInViewportIndex: {
  3382. return ValidateLayerOrViewportIndexAtDefinition(decoration, inst);
  3383. }
  3384. case SpvBuiltInPatchVertices: {
  3385. return ValidatePatchVerticesAtDefinition(decoration, inst);
  3386. }
  3387. case SpvBuiltInPointCoord: {
  3388. return ValidatePointCoordAtDefinition(decoration, inst);
  3389. }
  3390. case SpvBuiltInPointSize: {
  3391. return ValidatePointSizeAtDefinition(decoration, inst);
  3392. }
  3393. case SpvBuiltInPosition: {
  3394. return ValidatePositionAtDefinition(decoration, inst);
  3395. }
  3396. case SpvBuiltInPrimitiveId: {
  3397. return ValidatePrimitiveIdAtDefinition(decoration, inst);
  3398. }
  3399. case SpvBuiltInSampleId: {
  3400. return ValidateSampleIdAtDefinition(decoration, inst);
  3401. }
  3402. case SpvBuiltInSampleMask: {
  3403. return ValidateSampleMaskAtDefinition(decoration, inst);
  3404. }
  3405. case SpvBuiltInSamplePosition: {
  3406. return ValidateSamplePositionAtDefinition(decoration, inst);
  3407. }
  3408. case SpvBuiltInSubgroupId:
  3409. case SpvBuiltInNumSubgroups: {
  3410. return ValidateComputeI32InputAtDefinition(decoration, inst);
  3411. }
  3412. case SpvBuiltInSubgroupLocalInvocationId:
  3413. case SpvBuiltInSubgroupSize: {
  3414. return ValidateI32InputAtDefinition(decoration, inst);
  3415. }
  3416. case SpvBuiltInSubgroupEqMask:
  3417. case SpvBuiltInSubgroupGeMask:
  3418. case SpvBuiltInSubgroupGtMask:
  3419. case SpvBuiltInSubgroupLeMask:
  3420. case SpvBuiltInSubgroupLtMask: {
  3421. return ValidateI32Vec4InputAtDefinition(decoration, inst);
  3422. }
  3423. case SpvBuiltInTessCoord: {
  3424. return ValidateTessCoordAtDefinition(decoration, inst);
  3425. }
  3426. case SpvBuiltInTessLevelOuter: {
  3427. return ValidateTessLevelOuterAtDefinition(decoration, inst);
  3428. }
  3429. case SpvBuiltInTessLevelInner: {
  3430. return ValidateTessLevelInnerAtDefinition(decoration, inst);
  3431. }
  3432. case SpvBuiltInVertexIndex: {
  3433. return ValidateVertexIndexAtDefinition(decoration, inst);
  3434. }
  3435. case SpvBuiltInWorkgroupSize: {
  3436. return ValidateWorkgroupSizeAtDefinition(decoration, inst);
  3437. }
  3438. case SpvBuiltInVertexId: {
  3439. return ValidateVertexIdAtDefinition(decoration, inst);
  3440. }
  3441. case SpvBuiltInLocalInvocationIndex: {
  3442. return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
  3443. }
  3444. case SpvBuiltInWarpsPerSMNV:
  3445. case SpvBuiltInSMCountNV:
  3446. case SpvBuiltInWarpIDNV:
  3447. case SpvBuiltInSMIDNV: {
  3448. return ValidateSMBuiltinsAtDefinition(decoration, inst);
  3449. }
  3450. case SpvBuiltInBaseInstance:
  3451. case SpvBuiltInBaseVertex: {
  3452. return ValidateBaseInstanceOrVertexAtDefinition(decoration, inst);
  3453. }
  3454. case SpvBuiltInDrawIndex: {
  3455. return ValidateDrawIndexAtDefinition(decoration, inst);
  3456. }
  3457. case SpvBuiltInViewIndex: {
  3458. return ValidateViewIndexAtDefinition(decoration, inst);
  3459. }
  3460. case SpvBuiltInDeviceIndex: {
  3461. return ValidateDeviceIndexAtDefinition(decoration, inst);
  3462. }
  3463. // Ray tracing builtins
  3464. case SpvBuiltInHitKindKHR: // alias SpvBuiltInHitKindNV
  3465. case SpvBuiltInHitTNV: // NOT present in KHR
  3466. case SpvBuiltInInstanceId:
  3467. case SpvBuiltInLaunchIdKHR: // alias SpvBuiltInLaunchIdNV
  3468. case SpvBuiltInLaunchSizeKHR: // alias SpvBuiltInLaunchSizeNV
  3469. case SpvBuiltInWorldRayOriginKHR: // alias SpvBuiltInWorldRayOriginNV
  3470. case SpvBuiltInWorldRayDirectionKHR: // alias SpvBuiltInWorldRayDirectionNV
  3471. case SpvBuiltInObjectRayOriginKHR: // alias SpvBuiltInObjectRayOriginNV
  3472. case SpvBuiltInObjectRayDirectionKHR: // alias
  3473. // SpvBuiltInObjectRayDirectionNV
  3474. case SpvBuiltInRayTminKHR: // alias SpvBuiltInRayTminNV
  3475. case SpvBuiltInRayTmaxKHR: // alias SpvBuiltInRayTmaxNV
  3476. case SpvBuiltInInstanceCustomIndexKHR: // alias
  3477. // SpvBuiltInInstanceCustomIndexNV
  3478. case SpvBuiltInObjectToWorldKHR: // alias SpvBuiltInObjectToWorldNV
  3479. case SpvBuiltInWorldToObjectKHR: // alias SpvBuiltInWorldToObjectNV
  3480. case SpvBuiltInIncomingRayFlagsKHR: // alias SpvBuiltInIncomingRayFlagsNV
  3481. case SpvBuiltInRayGeometryIndexKHR: { // NOT present in NV
  3482. return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
  3483. }
  3484. case SpvBuiltInWorkDim:
  3485. case SpvBuiltInGlobalSize:
  3486. case SpvBuiltInEnqueuedWorkgroupSize:
  3487. case SpvBuiltInGlobalOffset:
  3488. case SpvBuiltInGlobalLinearId:
  3489. case SpvBuiltInSubgroupMaxSize:
  3490. case SpvBuiltInNumEnqueuedSubgroups:
  3491. case SpvBuiltInBaryCoordNoPerspAMD:
  3492. case SpvBuiltInBaryCoordNoPerspCentroidAMD:
  3493. case SpvBuiltInBaryCoordNoPerspSampleAMD:
  3494. case SpvBuiltInBaryCoordSmoothAMD:
  3495. case SpvBuiltInBaryCoordSmoothCentroidAMD:
  3496. case SpvBuiltInBaryCoordSmoothSampleAMD:
  3497. case SpvBuiltInBaryCoordPullModelAMD:
  3498. case SpvBuiltInFragStencilRefEXT:
  3499. case SpvBuiltInViewportMaskNV:
  3500. case SpvBuiltInSecondaryPositionNV:
  3501. case SpvBuiltInSecondaryViewportMaskNV:
  3502. case SpvBuiltInPositionPerViewNV:
  3503. case SpvBuiltInViewportMaskPerViewNV:
  3504. case SpvBuiltInFullyCoveredEXT:
  3505. case SpvBuiltInMax:
  3506. case SpvBuiltInTaskCountNV:
  3507. case SpvBuiltInPrimitiveCountNV:
  3508. case SpvBuiltInPrimitiveIndicesNV:
  3509. case SpvBuiltInClipDistancePerViewNV:
  3510. case SpvBuiltInCullDistancePerViewNV:
  3511. case SpvBuiltInLayerPerViewNV:
  3512. case SpvBuiltInMeshViewCountNV:
  3513. case SpvBuiltInMeshViewIndicesNV:
  3514. case SpvBuiltInBaryCoordNV:
  3515. case SpvBuiltInBaryCoordNoPerspNV:
  3516. case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT
  3517. case SpvBuiltInInvocationsPerPixelNV: // alias
  3518. // SpvBuiltInFragInvocationCountEXT
  3519. // No validation rules (for the moment).
  3520. break;
  3521. case SpvBuiltInPrimitiveShadingRateKHR: {
  3522. return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
  3523. }
  3524. case SpvBuiltInShadingRateKHR: {
  3525. return ValidateShadingRateAtDefinition(decoration, inst);
  3526. }
  3527. }
  3528. return SPV_SUCCESS;
  3529. }
  3530. spv_result_t BuiltInsValidator::ValidateBuiltInsAtDefinition() {
  3531. for (const auto& kv : _.id_decorations()) {
  3532. const uint32_t id = kv.first;
  3533. const auto& decorations = kv.second;
  3534. if (decorations.empty()) {
  3535. continue;
  3536. }
  3537. const Instruction* inst = _.FindDef(id);
  3538. assert(inst);
  3539. for (const auto& decoration : kv.second) {
  3540. if (decoration.dec_type() != SpvDecorationBuiltIn) {
  3541. continue;
  3542. }
  3543. if (spv_result_t error =
  3544. ValidateSingleBuiltInAtDefinition(decoration, *inst)) {
  3545. return error;
  3546. }
  3547. }
  3548. }
  3549. return SPV_SUCCESS;
  3550. }
  3551. spv_result_t BuiltInsValidator::Run() {
  3552. // First pass: validate all built-ins at definition and seed
  3553. // id_to_at_reference_checks_ with built-ins.
  3554. if (auto error = ValidateBuiltInsAtDefinition()) {
  3555. return error;
  3556. }
  3557. if (id_to_at_reference_checks_.empty()) {
  3558. // No validation tasks were seeded. Nothing else to do.
  3559. return SPV_SUCCESS;
  3560. }
  3561. // Second pass: validate every id reference in the module using
  3562. // rules in id_to_at_reference_checks_.
  3563. for (const Instruction& inst : _.ordered_instructions()) {
  3564. Update(inst);
  3565. std::set<uint32_t> already_checked;
  3566. for (const auto& operand : inst.operands()) {
  3567. if (!spvIsIdType(operand.type)) {
  3568. // Not id.
  3569. continue;
  3570. }
  3571. const uint32_t id = inst.word(operand.offset);
  3572. if (id == inst.id()) {
  3573. // No need to check result id.
  3574. continue;
  3575. }
  3576. if (!already_checked.insert(id).second) {
  3577. // The instruction has already referenced this id.
  3578. continue;
  3579. }
  3580. // Instruction references the id. Run all checks associated with the id
  3581. // on the instruction. id_to_at_reference_checks_ can be modified in the
  3582. // process, iterators are safe because it's a tree-based map.
  3583. const auto it = id_to_at_reference_checks_.find(id);
  3584. if (it != id_to_at_reference_checks_.end()) {
  3585. for (const auto& check : it->second) {
  3586. if (spv_result_t error = check(inst)) {
  3587. return error;
  3588. }
  3589. }
  3590. }
  3591. }
  3592. }
  3593. return SPV_SUCCESS;
  3594. }
  3595. } // namespace
  3596. // Validates correctness of built-in variables.
  3597. spv_result_t ValidateBuiltIns(ValidationState_t& _) {
  3598. BuiltInsValidator validator(_);
  3599. return validator.Run();
  3600. }
  3601. } // namespace val
  3602. } // namespace spvtools