1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913 |
- =====================================
- HLSL to SPIR-V Feature Mapping Manual
- =====================================
- .. contents::
- :local:
- :depth: 3
- Introduction
- ============
- This document describes the mappings from HLSL features to SPIR-V for Vulkan
- adopted by the SPIR-V codegen. For how to build, use, or contribute to the
- SPIR-V codegen and its internals, please see the
- `wiki <https://github.com/Microsoft/DirectXShaderCompiler/wiki/SPIR%E2%80%90V-CodeGen>`_
- page.
- `SPIR-V <https://www.khronos.org/registry/spir-v/>`_ is a binary intermediate
- language for representing graphical-shader stages and compute kernels for
- multiple Khronos APIs, such as Vulkan, OpenGL, and OpenCL. At the moment we
- only intend to support the Vulkan flavor of SPIR-V.
- DirectXShaderCompiler is the reference compiler for HLSL. Adding SPIR-V codegen
- in DirectXShaderCompiler will enable the usage of HLSL as a frontend language
- for Vulkan shader programming. Sharing the same code base also means we can
- track the evolution of HLSL more closely and always deliver the best of HLSL to
- developers. Moreover, developers will also have a unified compiler toolchain for
- targeting both DirectX and Vulkan. We believe this effort will benefit the
- general graphics ecosystem.
- Note that this document is expected to be an ongoing effort and grow as we
- implement more and more HLSL features.
- Overview
- ========
- Although they share the same basic concepts, DirectX and Vulkan are still
- different graphics APIs with semantic gaps. HLSL is the native shading language
- for DirectX, so certain HLSL features do not have corresponding mappings in
- Vulkan, and certain Vulkan specific information does not have native ways to
- express in HLSL source code. This section describes the general translation
- paradigms and how we close some of the major semantic gaps.
- Note that the term "semantic" is overloaded. In HLSL, it can mean the string
- attached to shader input or output. For such cases, we refer it as "HLSL
- semantic" or "semantic string". For other cases, we just use the normal
- "semantic" term.
- Shader entry function
- ---------------------
- HLSL entry functions can read data from the previous shader stage and write
- data to the next shader stage via function parameters and return value. On the
- contrary, Vulkan requires all SPIR-V entry functions taking no parameters and
- returning void. All data passing between stages should use global variables
- in the ``Input`` and ``Output`` storage class.
- To handle this difference, we emit a wrapper function as the SPIR-V entry
- function around the HLSL source code entry function. The wrapper function is
- responsible to read data from SPIR-V ``Input`` global variables and prepare
- them to the types required in the source code entry function signature, call
- the source code entry function, and then decompose the contents in return value
- (and ``out``/``inout`` parameters) to the types required by the SPIR-V
- ``Output`` global variables, and then write out. For details about the wrapper
- function, please refer to the `entry function wrapper`_ section.
- Shader stage IO interface matching
- ----------------------------------
- HLSL leverages semantic strings to link variables and pass data between shader
- stages. Great flexibility is allowed as for how to use the semantic strings.
- They can appear on function parameters, function returns, and struct members.
- In Vulkan, linking variables and passing data between shader stages is done via
- numeric ``Location`` decorations on SPIR-V global variables in the ``Input`` and
- ``Output`` storage class.
- To help handling such differences, we provide `Vulkan specific attributes`_ to
- let the developer to express precisely their intents. The compiler will also try
- its best to deduce the mapping from semantic strings to SPIR-V ``Location``
- numbers when such explicit Vulkan specific attributes are absent. Please see the
- `HLSL semantic and Vulkan Location`_ section for more details about the mapping
- and ``Location`` assignment.
- What makes the story complicated is Vulkan's strict requirements on interface
- matching. Basically, a variable in the previous stage is considered a match to
- a variable in the next stage if and only if they are decorated with the same
- ``Location`` number and with the exact same type, except for the outermost
- arrayness in hull/domain/geometry shader, which can be ignored regarding
- interface matching. This is causing problems together with the flexibility of
- HLSL semantic strings.
- Some HLSL system-value (SV) semantic strings will be mapped into SPIR-V
- variables with builtin decorations, some are not. HLSL non-SV semantic strings
- should all be mapped to SPIR-V variables without builtin decorations (but with
- ``Location`` decorations).
- With these complications, if we are grouping multiple semantic strings in a
- struct in the HLSL source code, that struct should be flattened and each of
- its members should be mapped separately. For example, for the following:
- .. code:: hlsl
- struct T {
- float2 clip0 : SV_ClipDistance0;
- float3 cull0 : SV_CullDistance0;
- float4 foo : FOO;
- };
- struct S {
- float4 pos : SV_Position;
- float2 clip1 : SV_ClipDistance1;
- float3 cull1 : SV_CullDistance1;
- float4 bar : BAR;
- T t;
- };
- If we have an ``S`` input parameter in pixel shader, we should flatten it
- recursively to generate five SPIR-V ``Input`` variables. Three of them are
- decorated by the ``Position``, ``ClipDistance``, ``CullDistance`` builtin,
- and two of them are decorated by the ``Location`` decoration. (Note that
- ``clip0`` and ``clip1`` are concatenated, also ``cull0`` and ``cull1``.
- The ``ClipDistance`` and ``CullDistance`` builtins are special and explained
- in the `ClipDistance & CullDistance`_ section.)
- Flattening is infective because of Vulkan interface matching rules. If we
- flatten a struct in the output of a previous stage, which may create multiple
- variables decorated with different ``Location`` numbers, we also need to
- flatten it in the input of the next stage. otherwise we may have ``Location``
- mismatch even if we share the same definition of the struct. Because
- hull/domain/geometry shader is optional, we can have different chains of shader
- stages, which means we need to flatten all shader stage interfaces. For
- hull/domain/geometry shader, their inputs/outputs have an additional arrayness.
- So if we are seeing an array of structs in these shaders, we need to flatten
- them into arrays of its fields.
- Vulkan specific features
- ------------------------
- We try to implement Vulkan specific features using the most intuitive and
- non-intrusive ways in HLSL, which means we will prefer native language
- constructs when possible. If that is inadequate, we then consider attaching
- `Vulkan specific attributes`_ to them, or introducing new syntax.
- Descriptors
- ~~~~~~~~~~~
- The compiler provides multiple mechanisms to specify which Vulkan descriptor
- a particular resource binds to.
- In the source code, you can use the ``[[vk::binding(X[, Y])]]`` and
- ``[[vk::counter_binding(X)]]`` attribute. The native ``:register()`` attribute
- is also respected.
- On the command-line, you can use the ``-fvk-{b|s|t|u}-shift`` or
- ``-fvk-bind-register`` option.
- If you can modify the source code, the ``[[vk::binding(X[, Y])]]`` and
- ``[[vk::counter_binding(X)]]`` attribute gives you find-grained control over
- descriptor assignment.
- If you cannot modify the source code, you can use command-line options to change
- how ``:register()`` attribute is handled by the compiler. ``-fvk-bind-register``
- lets you to specify the descriptor for the source at a certain register.
- ``-fvk-{b|s|t|u}-shift`` lets you to apply shifts to all register numbers
- of a certain register type. They cannot be used together, though.
- Without attribute and command-line option, ``:register(xX, spaceY)`` will be
- mapped to binding ``X`` in descriptor set ``Y``. Note that register type ``x``
- is ignored, so this may cause overlap.
- The more specific a mechanism is, the higher precedence it has, and command-line
- option has higher precedence over source code attribute.
- For more details, see `HLSL register and Vulkan binding`_, `Vulkan specific
- attributes`_, and `Vulkan-specific options`_.
- Subpass inputs
- ~~~~~~~~~~~~~~
- Within a Vulkan `rendering pass <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#renderpass>`_,
- a subpass can write results to an output target that can then be read by the
- next subpass as an input subpass. The "Subpass Input" feature regards the
- ability to read an output target.
- Subpasses are read through two new builtin resource types, available only in
- pixel shader:
- .. code:: hlsl
- class SubpassInput<T> {
- T SubpassLoad();
- };
- class SubpassInputMS<T> {
- T SubpassLoad(int sampleIndex);
- };
- In the above, ``T`` is a scalar or vector type. If omitted, it will defaults to
- ``float4``.
- Subpass inputs are implicitly addressed by the pixel's (x, y, layer) coordinate.
- These objects support reading the subpass input through the methods as shown
- in the above.
- A subpass input is selected by using a new attribute ``vk::input_attachment_index``.
- For example:
- .. code:: hlsl
- [[vk::input_attachment_index(i)]] SubpassInput input;
- An ``vk::input_attachment_index`` of ``i`` selects the ith entry in the input
- pass list. (See Vulkan API spec for more information.)
- Push constants
- ~~~~~~~~~~~~~~
- Vulkan push constant blocks are represented using normal global variables of
- struct types in HLSL. The variables (not the underlying struct types) should be
- annotated with the ``[[vk::push_constant]]`` attribute.
- Please note as per the requirements of Vulkan, "there must be no more than one
- push constant block statically used per shader entry point."
- Specialization constants
- ~~~~~~~~~~~~~~~~~~~~~~~~
- To use Vulkan specialization constants, annotate global constants with the
- ``[[vk::constant_id(X)]]`` attribute. For example,
- .. code:: hlsl
- [[vk::constant_id(1)]] const bool specConstBool = true;
- [[vk::constant_id(2)]] const int specConstInt = 42;
- [[vk::constant_id(3)]] const float specConstFloat = 1.5;
- Shader Record Buffer
- ~~~~~~~~~~~~~~~~~~~~
- SPV_NV_ray_tracing exposes user managed buffer in shader binding table by
- using storage class ShaderRecordBufferNV. ConstantBuffer or cbuffer blocks
- can now be mapped to this storage class under HLSL by using
- ``[[vk::shader_record_nv]]`` annotation. It is applicable only on ConstantBuffer
- and cbuffer declarations.
- Please note as per the requirements of VK_NV_ray_tracing, "there must be no
- more than one shader_record_nv block statically used per shader entry point
- otherwise results are undefined."
- The official Khronos ray tracing extension also comes with a SPIR-V storage class
- that has the same functionality. The ``[[vk::shader_record_ext]]`` annotation can
- be used when targeting the SPV_KHR_ray_tracing extension.
- Builtin variables
- ~~~~~~~~~~~~~~~~~
- Some of the Vulkan builtin variables have no equivalents in native HLSL
- language. To support them, ``[[vk::builtin("<builtin>")]]`` is introduced.
- Right now the following ``<builtin>`` are supported:
- * ``PointSize``: The GLSL equivalent is ``gl_PointSize``.
- * ``HelperInvocation``: The GLSL equivalent is ``gl_HelperInvocation``.
- * ``BaseVertex``: The GLSL equivalent is ``gl_BaseVertexARB``.
- Need ``SPV_KHR_shader_draw_parameters`` extension.
- * ``BaseInstance``: The GLSL equivalent is ``gl_BaseInstanceARB``.
- Need ``SPV_KHR_shader_draw_parameters`` extension.
- * ``DrawIndex``: The GLSL equivalent is ``gl_DrawIDARB``.
- Need ``SPV_KHR_shader_draw_parameters`` extension.
- * ``DeviceIndex``: The GLSL equivalent is ``gl_DeviceIndex``.
- Need ``SPV_KHR_device_group`` extension.
- * ``ViewportMaskNV``: The GLSL equivalent is ``gl_ViewportMask``.
- Please see Vulkan spec. `14.6. Built-In Variables <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-builtin-variables>`_
- for detailed explanation of these builtins.
- Supported extensions
- ~~~~~~~~~~~~~~~~~~~~
- * SPV_KHR_16bit_storage
- * SPV_KHR_device_group
- * SPV_KHR_multivew
- * SPV_KHR_post_depth_coverage
- * SPV_KHR_shader_draw_parameters
- * SPV_EXT_descriptor_indexing
- * SPV_EXT_fragment_fully_covered
- * SPV_KHR_fragment_shading_rate
- * SPV_EXT_shader_stencil_support
- * SPV_AMD_shader_explicit_vertex_parameter
- * SPV_GOOGLE_hlsl_functionality1
- * SPV_NV_mesh_shader
- Vulkan specific attributes
- --------------------------
- `C++ attribute specifier sequence <http://en.cppreference.com/w/cpp/language/attributes>`_
- is a non-intrusive way of providing Vulkan specific information in HLSL.
- The namespace ``vk`` will be used for all Vulkan attributes:
- - ``location(X)``: For specifying the location (``X``) numbers for stage
- input/output variables. Allowed on function parameters, function returns,
- and struct fields.
- - ``binding(X[, Y])``: For specifying the descriptor set (``Y``) and binding
- (``X``) numbers for resource variables. The descriptor set (``Y``) is
- optional; if missing, it will be set to 0. Allowed on global variables.
- - ``counter_binding(X)``: For specifying the binding number (``X``) for the
- associated counter for RW/Append/Consume structured buffer. The descriptor
- set number for the associated counter is always the same as the main resource.
- - ``push_constant``: For marking a variable as the push constant block. Allowed
- on global variables of struct type. At most one variable can be marked as
- ``push_constant`` in a shader.
- - ``offset(X)``: For manually layout struct members. Annotating a struct member
- with this attribute will force the compiler to put the member at offset ``X``
- w.r.t. the beginning of the struct. Only allowed on struct members.
- - ``constant_id(X)``: For marking a global constant as a specialization constant.
- Allowed on global variables of boolean/integer/float types.
- - ``input_attachment_index(X)``: To associate the Xth entry in the input pass
- list to the annotated object. Only allowed on objects whose type are
- ``SubpassInput`` or ``SubpassInputMS``.
- - ``builtin("X")``: For specifying an entity should be translated into a certain
- Vulkan builtin variable. Allowed on function parameters, function returns,
- and struct fields.
- - ``index(X)``: For specifying the index at a specific pixel shader output
- location. Used for dual-source blending.
- - ``post_depth_coverage``: The input variable decorated with SampleMask will
- reflect the result of the EarlyFragmentTests. Only valid on pixel shader entry points.
- Only ``vk::`` attributes in the above list are supported. Other attributes will
- result in warnings and be ignored by the compiler. All C++11 attributes will
- only trigger warnings and be ignored if not compiling towards SPIR-V.
- For example, to specify the layout of resource variables and the location of
- interface variables:
- .. code:: hlsl
- struct S { ... };
- [[vk::binding(X, Y), vk::counter_binding(Z)]]
- RWStructuredBuffer<S> mySBuffer;
- [[vk::location(M)]] float4
- main([[vk::location(N)]] float4 input: A) : B
- { ... }
- SPIR-V version and extension
- ----------------------------
- SPIR-V CodeGen provides two command-line options for fine-grained SPIR-V target
- environment (hence SPIR-V version) and SPIR-V extension control:
- - ``-fspv-target-env=``: for specifying SPIR-V target environment
- - ``-fspv-extension=``: for specifying allowed SPIR-V extensions
- ``-fspv-target-env=`` only accepts ``vulkan1.0`` and ``vulkan1.1`` right now.
- If such an option is not given, the CodeGen defaults to ``vulkan1.0``. When
- targeting ``vulkan1.0``, trying to use features that are only available
- in Vulkan 1.1 (SPIR-V 1.3), like `Shader Model 6.0 wave intrinsics`_, will
- trigger a compiler error.
- If ``-fspv-extension=`` is not specified, the CodeGen will select suitable
- SPIR-V extensions to translate the source code. Otherwise, only extensions
- supplied via ``-fspv-extension=`` will be used. If that does not suffice, errors
- will be emitted explaining what additional extensions are required to translate
- what specific feature in the source code. If you want to allow all KHR
- extensions, you can use ``-fspv-extension=KHR``.
- Legalization, optimization, validation
- --------------------------------------
- After initial translation of the HLSL source code, SPIR-V CodeGen will further
- conduct legalization (if needed), optimization (if requested), and validation
- (if not turned off). All these three stages are outsourced to `SPIRV-Tools <https://github.com/KhronosGroup/SPIRV-Tools>`_.
- Here are the options controlling these stages:
- * ``-fcgl``: turn off legalization and optimization
- * ``-Od``: turn off optimization
- * ``-Vd``: turn off validation
- Legalization
- ~~~~~~~~~~~~
- HLSL is a fairly permissive language considering the flexibility it provides for
- manipulating resource objects. The developer can create local copies, pass
- them around as function parameters and return values, as long as after certain
- transformations (function inlining, constant evaluation and propagating, dead
- code elimination, etc.), the compiler can remove all temporary copies and
- pinpoint all uses to unique global resource objects.
- Resulting from the above property of HLSL, if we translate into SPIR-V for
- Vulkan literally from the input HLSL source code, we will sometimes generate
- illegal SPIR-V. Certain transformations are needed to legalize the literally
- translated SPIR-V. Performing such transformations at the frontend AST level
- is cumbersome or impossible (e.g., function inlining). They are better to be
- conducted at SPIR-V level. Therefore, legalization is delegated to SPIRV-Tools.
- Specifically, we need to legalize the following HLSL source code patterns:
- * Using resource types in struct types
- * Creating aliases of global resource objects
- * Control flows invovling the above cases
- Legalization transformations will not run unless the above patterns are
- encountered in the source code.
- For more details, please see the `SPIR-V cookbook <https://github.com/Microsoft/DirectXShaderCompiler/tree/master/docs/SPIRV-Cookbook.rst>`_,
- which contains examples of what HLSL code patterns will be accepted and
- generate valid SPIR-V for Vulkan.
- Optimization
- ~~~~~~~~~~~~
- Optimization is also delegated to SPIRV-Tools. Right now there are no difference
- between optimization levels greater than zero; they will all invoke the same
- optimization recipe. That is, the recipe behind ``spirv-opt -O``. If you want to
- run a custom optimization recipe, you can do so using the command line option
- ``-Oconfig=`` and specifying a comma-separated list of your desired passes.
- The passes are invoked in the specified order.
- For example, you can specify ``-Oconfig=--loop-unroll,--scalar-replacement=300,--eliminate-dead-code-aggressive``
- to firstly invoke loop unrolling, then invoke scalar replacement of aggregates,
- lastly invoke aggressive dead code elimination. All valid options to
- ``spirv-opt`` are accepted as components to the comma-separated list.
- Here are the typical passes in alphabetical order:
- * ``--ccp``
- * ``--cfg-cleanup``
- * ``--convert-local-access-chains``
- * ``--copy-propagate-arrays``
- * ``--eliminate-dead-branches``
- * ``--eliminate-dead-code-aggressive``
- * ``--eliminate-dead-functions``
- * ``--eliminate-local-multi-store``
- * ``--eliminate-local-single-block``
- * ``--eliminate-local-single-store``
- * ``--flatten-decorations``
- * ``--if-conversion``
- * ``--inline-entry-points-exhaustive``
- * ``--local-redundancy-elimination``
- * ``--loop-fission``
- * ``--loop-fusion``
- * ``--loop-unroll``
- * ``--loop-unroll-partial=[<n>]``
- * ``--loop-peeling`` (requires ``--loop-peeling-threshold``)
- * ``--merge-blocks``
- * ``--merge-return``
- * ``--loop-unswitch``
- * ``--private-to-local``
- * ``--reduce-load-size``
- * ``--redundancy-elimination``
- * ``--remove-duplicates``
- * ``--replace-invalid-opcode``
- * ``--ssa-rewrite``
- * ``--scalar-replacement[=<n>]``
- * ``--simplify-instructions``
- * ``--vector-dce``
- Besides, there are two special batch options; each stands for a recommended
- recipe by itself:
- * ``-O``: A bunch of passes in an appropriate order that attempt to improve
- performance of generated code. Same as ``spirv-opt -O``. Also same as SPIR-V
- CodeGen's default recipe.
- * ``-Os``: A bunch of passes in an appropriate order that attempt to reduce the
- size of the generated code. Same as ``spirv-opt -Os``.
- So if you want to run loop unrolling additionally after the default optimization
- recipe, you can specify ``-Oconfig=-O,--loop-unroll``.
- For the whole list of accepted passes and details about each one, please see
- ``spirv-opt``'s help manual (``spirv-opt --help``), or the SPIRV-Tools `optimizer header file <https://github.com/KhronosGroup/SPIRV-Tools/blob/master/include/spirv-tools/optimizer.hpp>`_.
- Validation
- ~~~~~~~~~~
- Validation is turned on by default as the last stage of SPIR-V CodeGen. Failing
- validation, which indicates there is a CodeGen bug, will trigger a fatal error.
- Please file an issue if you see that.
- Debugging
- ---------
- By default, the compiler will only emit names for types and variables as debug
- information, to aid reading of the generated SPIR-V. The ``-Zi`` option will
- let the compiler emit the following additional debug information:
- * Full path of the main source file using ``OpSource``
- * Preprocessed source code using ``OpSource`` and ``OpSourceContinued``
- * Line information for certain instructions using ``OpLine`` (WIP)
- * DXC Git commit hash using ``OpModuleProcessed`` (requires Vulkan 1.1)
- * DXC command-line options used to compile the shader using ``OpModuleProcessed``
- (requires Vulkan 1.1)
- We chose to embed preprocessed source code instead of original source code to
- avoid pulling in lots of contents unrelated to the current entry point, and
- boilerplate contents generated by engines. We may add a mode for selecting
- between preprocessed single source code and original separated source code in
- the future.
- One thing to note is that to keep the line numbers in consistent with the
- embedded source, the compiler is invoked twice; the first time is for
- preprocessing the source code, and the second time is for feeding the
- preprocessed source code as input for a whole compilation. So using ``-Zi``
- means performance penality.
- If you want to have fine-grained control over the categories of emitted debug
- information, you can use ``-fspv-debug=``. It accepts:
- * ``file``: for emitting full path of the main source file
- * ``source``: for emitting preprocessed source code (turns on ``file`` implicitly)
- * ``line``: for emitting line information (turns on ``source`` implicitly)
- * ``tool``: for emitting DXC Git commit hash and command-line options
- ``-fspv-debug=`` overrules ``-Zi``. And you can provide multiple instances of
- ``-fspv-debug=``. For example, you can use ``-fspv-debug=file -fspv-debug=tool``
- to turn on emitting file path and DXC information; source code and line
- information will not be emitted.
- Reflection
- ----------
- Making reflection easier is one of the goals of SPIR-V CodeGen. This section
- provides guidelines about how to reflect on certain facts.
- Note that we generate ``OpName``/``OpMemberName`` instructions for various
- types/variables both explicitly defined in the source code and interally created
- by the compiler. These names are primarily for debugging purposes in the
- compiler. They have "no semantic impact and can safely be removed" according
- to the SPIR-V spec. And they are subject to changes without notice. So we do
- not suggest to use them for reflection.
- Source code shader profile
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- The source code shader profile version can be re-discovered by the "Version"
- operand in ``OpSource`` instruction. For ``*s_<major>_<minor>``, the "Verison"
- operand in ``OpSource`` will be set as ``<major>`` * 100 + ``<minor>`` * 10.
- For example, ``vs_5_1`` will have 510, ``ps_6_2`` will have 620.
- HLSL Semantic
- ~~~~~~~~~~~~~
- HLSL semantic strings are by default not emitted into the SPIR-V binary module.
- If you need them, by specifying ``-fspv-reflect``, the compiler will use
- the ``Op*DecorateStringGOOGLE`` instruction in `SPV_GOOGLE_hlsl_funtionality1 <https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/GOOGLE/SPV_GOOGLE_hlsl_functionality1.asciidoc>`_
- extension to emit them.
- Counter buffers for RW/Append/Consume StructuredBuffer
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The association between a counter buffer and its main RW/Append/Consume
- StructuredBuffer is conveyed by ``OpDecorateId <structured-buffer-id>
- HLSLCounterBufferGOOGLE <counter-buffer-id>`` instruction from the
- `SPV_GOOGLE_hlsl_funtionality1 <https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/GOOGLE/SPV_GOOGLE_hlsl_functionality1.asciidoc>`_
- extension. This information is by default missing; you need to specify
- ``-fspv-reflect`` to direct the compiler to emit them.
- Read-only vs. read-write resource types
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- There are no clear and consistent decorations in the SPIR-V to show whether a
- resource type is translated from a read-only (RO) or read-write (RW) HLSL
- resource type. Instead, you need to use different checks for reflecting different
- resource types:
- * HLSL samplers: RO.
- * HLSL ``Buffer``/``RWBuffer``/``Texture*``/``RWTexture*``: Check the "Sampled"
- operand in the ``OpTypeImage`` instruction they translated into. "2" means RW,
- "1" means RO.
- * HLSL constant/texture/structured/byte buffers: Check both ``Block``/``BufferBlock``
- and ``NonWritable`` decoration. If decorated with ``Block`` (``cbuffer`` &
- ``ConstantBuffer``), then RO; if decorated with ``BufferBlock`` and ``NonWritable``
- (``tbuffer``, ``TextureBuffer``, ``StructuredBuffer``), then RO; Otherwise, RW.
- HLSL Types
- ==========
- This section lists how various HLSL types are mapped.
- Normal scalar types
- -------------------
- `Normal scalar types <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509646(v=vs.85).aspx>`_
- in HLSL are relatively easy to handle and can be mapped directly to SPIR-V
- type instructions:
- ============================== ======================= ================== =========== =================================
- HLSL Command Line Option SPIR-V Capability Extension
- ============================== ======================= ================== =========== =================================
- ``bool`` ``OpTypeBool``
- ``int``/``int32_t`` ``OpTypeInt 32 1``
- ``int16_t`` ``-enable-16bit-types`` ``OpTypeInt 16 1`` ``Int16``
- ``uint``/``dword``/``uin32_t`` ``OpTypeInt 32 0``
- ``uint16_t`` ``-enable-16bit-types`` ``OpTypeInt 16 0`` ``Int16``
- ``half`` ``OpTypeFloat 32``
- ``half``/``float16_t`` ``-enable-16bit-types`` ``OpTypeFloat 16`` ``SPV_AMD_gpu_shader_half_float``
- ``float``/``float32_t`` ``OpTypeFloat 32``
- ``snorm float`` ``OpTypeFloat 32``
- ``unorm float`` ``OpTypeFloat 32``
- ``double``/``float64_t`` ``OpTypeFloat 64`` ``Float64``
- ============================== ======================= ================== =========== =================================
- Please note that ``half`` is translated into 32-bit floating point numbers
- if without ``-enable-16bit-types`` because MSDN says that "this data type
- is provided only for language compatibility. Direct3D 10 shader targets map
- all ``half`` data types to ``float`` data types."
- Minimal precision scalar types
- ------------------------------
- HLSL also supports various
- `minimal precision scalar types <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509646(v=vs.85).aspx>`_,
- which graphics drivers can implement by using any precision greater than or
- equal to their specified bit precision.
- There are no direct mappings in SPIR-V for these types. We translate them into
- the corresponding 16-bit or 32-bit scalar types with the ``RelaxedPrecision`` decoration.
- We use the 16-bit variants if '-enable-16bit-types' command line option is present.
- For more information on these types, please refer to:
- https://github.com/Microsoft/DirectXShaderCompiler/wiki/16-Bit-Scalar-Types
- ============== ======================= ================== ==================== ============ =================================
- HLSL Command Line Option SPIR-V Decoration Capability Extension
- ============== ======================= ================== ==================== ============ =================================
- ``min16float`` ``OpTypeFloat 32`` ``RelaxedPrecision``
- ``min10float`` ``OpTypeFloat 32`` ``RelaxedPrecision``
- ``min16int`` ``OpTypeInt 32 1`` ``RelaxedPrecision``
- ``min12int`` ``OpTypeInt 32 1`` ``RelaxedPrecision``
- ``min16uint`` ``OpTypeInt 32 0`` ``RelaxedPrecision``
- ``min16float`` ``-enable-16bit-types`` ``OpTypeFloat 16`` ``SPV_AMD_gpu_shader_half_float``
- ``min10float`` ``-enable-16bit-types`` ``OpTypeFloat 16`` ``SPV_AMD_gpu_shader_half_float``
- ``min16int`` ``-enable-16bit-types`` ``OpTypeInt 16 1`` ``Int16``
- ``min12int`` ``-enable-16bit-types`` ``OpTypeInt 16 1`` ``Int16``
- ``min16uint`` ``-enable-16bit-types`` ``OpTypeInt 16 0`` ``Int16``
- ============== ======================= ================== ==================== ============ =================================
- Vectors and matrices
- --------------------
- `Vectors <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509707(v=vs.85).aspx>`_
- and `matrices <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509623(v=vs.85).aspx>`_
- are translated into:
- ==================================== ====================================================
- HLSL SPIR-V
- ==================================== ====================================================
- ``|type|N`` (``N`` > 1) ``OpTypeVector |type| N``
- ``|type|1`` The scalar type for ``|type|``
- ``|type|MxN`` (``M`` > 1, ``N`` > 1) ``%v = OpTypeVector |type| N`` ``OpTypeMatrix %v M``
- ``|type|Mx1`` (``M`` > 1) ``OpTypeVector |type| M``
- ``|type|1xN`` (``N`` > 1) ``OpTypeVector |type| N``
- ``|type|1x1`` The scalar type for ``|type|``
- ==================================== ====================================================
- The above table is for float matrices.
- A MxN HLSL float matrix is translated into a SPIR-V matrix with M vectors, each with
- N elements. Conceptually HLSL matrices are row-major while SPIR-V matrices are
- column-major, thus all HLSL matrices are represented by their transposes.
- Doing so may require special handling of certain matrix operations:
- - **Indexing**: no special handling required. ``matrix[m][n]`` will still access
- the correct element since ``m``/``n`` means the ``m``-th/``n``-th row/column
- in HLSL but ``m``-th/``n``-th vector/element in SPIR-V.
- - **Per-element operation**: no special handling required.
- - **Matrix multiplication**: need to swap the operands. ``mat1 x mat2`` should
- be translated as ``transpose(mat2) x transpose(mat1)``. Then the result is
- ``transpose(mat1 x mat2)``.
- - **Storage layout**: ``row_major``/``column_major`` will be translated into
- SPIR-V ``ColMajor``/``RowMajor`` decoration. This is because HLSL matrix
- row/column becomes SPIR-V matrix column/row. If elements in a row/column are
- packed together, they should be loaded into a column/row correspondingly.
- See `Appendix A. Matrix Representation`_ for further explanation regarding these design choices.
- Since the ``Shader`` capability in SPIR-V does not allow to parameterize matrix
- types with non-floating-point types, a non-floating-point MxN matrix is translated
- into an array with M elements, with each element being a vector with N elements.
- Structs
- -------
- `Structs <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509668(v=vs.85).aspx>`_
- in HLSL are defined in the a format similar to C structs. They are translated
- into SPIR-V ``OpTypeStruct``. Depending on the storage classes of the instances,
- a single struct definition may generate multiple ``OpTypeStruct`` instructions
- in SPIR-V. For example, for the following HLSL source code:
- .. code:: hlsl
- struct S { ... }
- ConstantBuffer<S> myCBuffer;
- StructuredBuffer<S> mySBuffer;
- float4 main() : A {
- S myLocalVar;
- ...
- }
- There will be three different ``OpTypeStruct`` generated, one for each variable
- defined in the above source code. This is because the ``OpTypeStruct`` for
- both ``myCBuffer`` and ``mySBuffer`` will have layout decorations (``Offset``,
- ``MatrixStride``, ``ArrayStride``, ``RowMajor``, ``ColMajor``). However, their
- layout rules are different (by default); ``myCBuffer`` will use vector-relaxed
- OpenGL ``std140`` while ``mySBuffer`` will use vector-relaxed OpenGL ``std430``.
- ``myLocalVar`` will have its ``OpTypeStruct`` without layout decorations.
- Read more about storage classes in the `Constant/Texture/Structured/Byte Buffers`_
- section.
- Structs used as stage inputs/outputs will have semantics attached to their
- members. These semantics are handled in the `entry function wrapper`_.
- Structs used as pixel shader inputs can have optional interpolation modifiers
- for their members, which will be translated according to the following table:
- =========================== ================= =====================
- HLSL Interpolation Modifier SPIR-V Decoration SPIR-V Capability
- =========================== ================= =====================
- ``linear`` <none>
- ``centroid`` ``Centroid``
- ``nointerpolation`` ``Flat``
- ``noperspective`` ``NoPerspective``
- ``sample`` ``Sample`` ``SampleRateShading``
- =========================== ================= =====================
- Arrays
- ------
- Sized (either explicitly or implicitly) arrays are translated into SPIR-V
- `OpTypeArray`. Unsized arrays are translated into `OpTypeRuntimeArray`.
- Arrays, if used for external resources (residing in SPIR-V `Uniform` or
- `UniformConstant` storage class), will need layout decorations like SPIR-V
- `ArrayStride` decoration. For arrays of opaque types, e.g., HLSL textures
- or samplers, we don't decorate with `ArrayStride` decorations since there is
- no meaningful strides. Similarly for arrays of structured/byte buffers.
- User-defined types
- ------------------
- `User-defined types <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509702(v=vs.85).aspx>`_
- are type aliases introduced by typedef. No new types are introduced and we can
- rely on Clang to resolve to the original types.
- Samplers
- --------
- All `sampler types <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509644(v=vs.85).aspx>`_
- will be translated into SPIR-V ``OpTypeSampler``.
- SPIR-V ``OpTypeSampler`` is an opaque type that cannot be parameterized;
- therefore state assignments on sampler types is not supported (yet).
- Textures
- --------
- `Texture types <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509700(v=vs.85).aspx>`_
- are translated into SPIR-V ``OpTypeImage``, with parameters:
- ======================= ==================== ===== =================== ========== ===== ======= == ======= ================ =================
- HLSL Vulkan SPIR-V
- ----------------------- -------------------------- ------------------------------------------------------------------------------------------
- Texture Type Descriptor Type RO/RW Storage Class Dim Depth Arrayed MS Sampled Image Format Capability
- ======================= ==================== ===== =================== ========== ===== ======= == ======= ================ =================
- ``Texture1D`` Sampled Image RO ``UniformConstant`` ``1D`` 2 0 0 1 ``Unknown``
- ``Texture2D`` Sampled Image RO ``UniformConstant`` ``2D`` 2 0 0 1 ``Unknown``
- ``Texture3D`` Sampled Image RO ``UniformConstant`` ``3D`` 2 0 0 1 ``Unknown``
- ``TextureCube`` Sampled Image RO ``UniformConstant`` ``Cube`` 2 0 0 1 ``Unknown``
- ``Texture1DArray`` Sampled Image RO ``UniformConstant`` ``1D`` 2 1 0 1 ``Unknown``
- ``Texture2DArray`` Sampled Image RO ``UniformConstant`` ``2D`` 2 1 0 1 ``Unknown``
- ``Texture2DMS`` Sampled Image RO ``UniformConstant`` ``2D`` 2 0 1 1 ``Unknown``
- ``Texture2DMSArray`` Sampled Image RO ``UniformConstant`` ``2D`` 2 1 1 1 ``Unknown`` ``ImageMSArray``
- ``TextureCubeArray`` Sampled Image RO ``UniformConstant`` ``3D`` 2 1 0 1 ``Unknown``
- ``Buffer<T>`` Uniform Texel Buffer RO ``UniformConstant`` ``Buffer`` 2 0 0 1 Depends on ``T`` ``SampledBuffer``
- ``RWBuffer<T>`` Storage Texel Buffer RW ``UniformConstant`` ``Buffer`` 2 0 0 2 Depends on ``T`` ``SampledBuffer``
- ``RWTexture1D<T>`` Storage Image RW ``UniformConstant`` ``1D`` 2 0 0 2 Depends on ``T``
- ``RWTexture2D<T>`` Storage Image RW ``UniformConstant`` ``2D`` 2 0 0 2 Depends on ``T``
- ``RWTexture3D<T>`` Storage Image RW ``UniformConstant`` ``3D`` 2 0 0 2 Depends on ``T``
- ``RWTexture1DArray<T>`` Storage Image RW ``UniformConstant`` ``1D`` 2 1 0 2 Depends on ``T``
- ``RWTexture2DArray<T>`` Storage Image RW ``UniformConstant`` ``2D`` 2 1 0 2 Depends on ``T``
- ======================= ==================== ===== =================== ========== ===== ======= == ======= ================ =================
- The meanings of the headers in the above table is explained in ``OpTypeImage``
- of the SPIR-V spec.
- Vulkan specific Image Formats
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Since HLSL lacks the syntax for fully specifying image formats for textures in
- SPIR-V, we introduce ``[[vk::image_format("FORMAT")]]`` attribute for texture types.
- For example,
- .. code:: hlsl
- [[vk::image_format("rgba8")]]
- RWBuffer<float4> Buf;
- [[vk::image_format("rg16f")]]
- RWTexture2D<float2> Tex;
- RWTexture2D<float2> Tex2; // Works like before
- ``rgba8`` means ``Rgba8`` `SPIR-V Image Format <https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_image_format_a_image_format>`_.
- The following table lists the mapping between ``FORMAT`` of
- ``[[vk::image_format("FORMAT")]]`` and its corresponding SPIR-V Image Format.
- ======================= ============================================
- FORMAT SPIR-V Image Format
- ======================= ============================================
- ``unknown`` ``Unknown``
- ``rgba32f`` ``Rgba32f``
- ``rgba16f`` ``Rgba16f``
- ``r32f`` ``R32f``
- ``rgba8`` ``Rgba8``
- ``rgba8snorm`` ``Rgba8Snorm``
- ``rg32f`` ``Rg32f``
- ``rg16f`` ``Rg16f``
- ``r11g11b10f`` ``R11fG11fB10f``
- ``r16f`` ``R16f``
- ``rgba16`` ``Rgba16``
- ``rgb10a2`` ``Rgb10A2``
- ``rg16`` ``Rg16``
- ``rg8`` ``Rg8``
- ``r16`` ``R16``
- ``r8`` ``R8``
- ``rgba16snorm`` ``Rgba16Snorm``
- ``rg16snorm`` ``Rg16Snorm``
- ``rg8snorm`` ``Rg8Snorm``
- ``r16snorm`` ``R16Snorm``
- ``r8snorm`` ``R8Snorm``
- ``rgba32i`` ``Rgba32i``
- ``rgba16i`` ``Rgba16i``
- ``rgba8i`` ``Rgba8i``
- ``r32i`` ``R32i``
- ``rg32i`` ``Rg32i``
- ``rg16i`` ``Rg16i``
- ``rg8i`` ``Rg8i``
- ``r16i`` ``R16i``
- ``r8i`` ``R8i``
- ``rgba32ui`` ``Rgba32ui``
- ``rgba16ui`` ``Rgba16ui``
- ``rgba8ui`` ``Rgba8ui``
- ``r32ui`` ``R32ui``
- ``rgb10a2ui`` ``Rgb10a2ui``
- ``rg32ui`` ``Rg32ui``
- ``rg16ui`` ``Rg16ui``
- ``rg8ui`` ``Rg8ui``
- ``r16ui`` ``R16ui``
- ``r8ui`` ``R8ui``
- ``r64ui`` ``R64ui``
- ``r64i`` ``R64i``
- ======================= ============================================
- Constant/Texture/Structured/Byte Buffers
- ----------------------------------------
- There are serveral buffer types in HLSL:
- - ``cbuffer`` and ``ConstantBuffer``
- - ``tbuffer`` and ``TextureBuffer``
- - ``StructuredBuffer`` and ``RWStructuredBuffer``
- - ``AppendStructuredBuffer`` and ``ConsumeStructuredBuffer``
- - ``ByteAddressBuffer`` and ``RWByteAddressBuffer``
- Note that ``Buffer`` and ``RWBuffer`` are considered as texture object in HLSL.
- They are listed in the above section.
- Please see the following sections for the details of each type. As a summary:
- =========================== ================== ================================ ==================== =================
- HLSL Type Vulkan Buffer Type Default Memory Layout Rule SPIR-V Storage Class SPIR-V Decoration
- =========================== ================== ================================ ==================== =================
- ``cbuffer`` Uniform Buffer Vector-relaxed OpenGL ``std140`` ``Uniform`` ``Block``
- ``ConstantBuffer`` Uniform Buffer Vector-relaxed OpenGL ``std140`` ``Uniform`` ``Block``
- ``tbuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``TextureBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``StructuredBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``RWStructuredBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``AppendStructuredBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``ConsumeStructuredBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``ByteAddressBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- ``RWByteAddressBuffer`` Storage Buffer Vector-relaxed OpenGL ``std430`` ``Uniform`` ``BufferBlock``
- =========================== ================== ================================ ==================== =================
- To know more about the Vulkan buffer types, please refer to the Vulkan spec
- `13.1 Descriptor Types <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#descriptorsets-types>`_.
- Memory layout rules
- ~~~~~~~~~~~~~~~~~~~
- SPIR-V CodeGen supports four sets of memory layout rules for buffer resources
- right now:
- 1. Vector-relaxed OpenGL ``std140`` for uniform buffers and vector-relaxed
- OpenGL ``std430`` for storage buffers: these rules satisfy Vulkan `"Standard
- Uniform Buffer Layout" and "Standard Storage Buffer Layout" <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-resources-layout>`_,
- respectively.
- They are the default.
- 2. DirectX memory layout rules for uniform buffers and storage buffers:
- they allow packing data on the application side that can be shared with
- DirectX. They can be enabled by ``-fvk-use-dx-layout``.
- 3. Strict OpenGL ``std140`` for uniform buffers and strict OpenGL ``std430``
- for storage buffers: they allow packing data on the application side that
- can be shared with OpenGL. They can be enabled by ``-fvk-use-gl-layout``.
- 4. Scalar layout rules introduced via `VK_EXT_scalar_block_layout`, which
- basically aligns all aggregrate types according to their elements'
- natural alignment. They can be enabled by ``-fvk-use-scalar-layout``.
- To use scalar layout, the application side need to request
- ``VK_EXT_scalar_block_layout``. This is also true for using DirectX memory
- layout since there is no dedicated DirectX layout extension for Vulkan
- (at least for now). So we must request something more permissive.
- In the above, "vector-relaxed OpenGL ``std140``/``std430``" rules mean OpenGL
- ``std140``/``std430`` rules with the following modification for vector type
- alignment:
- 1. The alignment of a vector type is set to be the alignment of its element type
- 2. If the above causes an `improper straddle <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-resources-layout>`_,
- the alignment will be set to 16 bytes.
- As an exmaple, for the following HLSL definition:
- .. code:: hlsl
- struct S {
- float3 f;
- };
- struct T {
- float a_float;
- float3 b_float3;
- S c_S_float3;
- float2x3 d_float2x3;
- row_major float2x3 e_float2x3;
- int f_int_3[3];
- float2 g_float2_2[2];
- };
- We will have the following offsets for each member:
- ============== ====== ====== ====== ========== ====== ====== ====== ==========
- HLSL Uniform Buffer Storage Buffer
- -------------- ------------------------------- -------------------------------
- Member 1 (VK) 2 (DX) 3 (GL) 4 (Scalar) 1 (VK) 2 (DX) 3 (GL) 4 (Scalar)
- ============== ====== ====== ====== ========== ====== ====== ====== ==========
- ``a_float`` 0 0 0 0 0 0 0 0
- ``b_float3`` 4 4 16 4 4 4 16 4
- ``c_S_float3`` 16 16 32 16 16 16 32 16
- ``d_float2x3`` 32 32 48 28 32 28 48 28
- ``e_float2x3`` 80 80 96 52 64 52 80 52
- ``f_int_3`` 112 112 128 76 96 76 112 76
- ``g_float2_2`` 160 160 176 88 112 88 128 88
- ============== ====== ====== ====== ========== ====== ====== ====== ==========
- If the above layout rules do not satisfy your needs and you want to manually
- control the layout of struct members, you can use either
- * The native HLSL ``:packoffset()`` attribute: only available for cbuffers; or
- * The Vulkan-specific ``[[vk::offset()]]`` attribute: applies to all resources.
- ``[[vk::offset]]`` overrules ``:packoffset``. Attaching ``[[vk::offset]]``
- to a struct memeber affects all variables of the struct type in question. So
- sharing the same struct definition having ``[[vk::offset]]`` annotations means
- also sharing the layout.
- For global variables (which are collected into the ``$Globals`` cbuffer), you
- can use the native HLSL ``:register(c#)`` attribute. Note that ``[[vk::offset]]``
- and ``:packoffset`` cannot be applied to these variables.
- If ``register(cX)`` is used on any global variable, the offset for that variable
- is set to ``X * 16``, and the offset for all other global variables without the
- ``register(c#)`` annotation will be set to the next available address after
- the highest explicit address. For example:
- .. code:: hlsl
- float x : register(c10); // Offset = 160 (10 * 16)
- float y; // Offset = 164 (160 + 4)
- float z: register(c1); // Offset = 16 (1 * 16)
- These attributes give great flexibility but also responsibility to the
- developer; the compiler will just take in what is specified in the source code
- and emit it to SPIR-V with no error checking.
- ``cbuffer`` and ``ConstantBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- These two buffer types are treated as uniform buffers using Vulkan's
- terminology. They are translated into an ``OpTypeStruct`` with the
- necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
- ``RowMajor``, ``ColMajor``) and the ``Block`` decoration. The layout rule
- used is vector-relaxed OpenGL ``std140`` (by default). A variable declared as
- one of these types will be placed in the ``Uniform`` storage class.
- For example, for the following HLSL source code:
- .. code:: hlsl
- struct T {
- float a;
- float3 b;
- };
- ConstantBuffer<T> myCBuffer;
- will be translated into
- .. code:: spirv
- ; Layout decoration
- OpMemberDecorate %type_ConstantBuffer_T 0 Offset 0
- OpMemberDecorate %type_ConstantBuffer_T 0 Offset 4
- ; Block decoration
- OpDecorate %type_ConstantBuffer_T Block
- ; Types
- %type_ConstantBuffer_T = OpTypeStruct %float %v3float
- %_ptr_Uniform_type_ConstantBuffer_T = OpTypePointer Uniform %type_ConstantBuffer_T
- ; Variable
- %myCbuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
- ``tbuffer`` and ``TextureBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- These two buffer types are treated as storage buffers using Vulkan's
- terminology. They are translated into an ``OpTypeStruct`` with the
- necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
- ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. All the struct
- members are also decorated with ``NonWritable`` decoration. The layout rule
- used is vector-relaxed OpenGL ``std430`` (by default). A variable declared as
- one of these types will be placed in the ``Uniform`` storage class.
- ``StructuredBuffer`` and ``RWStructuredBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``StructuredBuffer<T>``/``RWStructuredBuffer<T>`` is treated as storage buffer
- using Vulkan's terminology. It is translated into an ``OpTypeStruct`` containing
- an ``OpTypeRuntimeArray`` of type ``T``, with necessary layout decorations
- (``Offset``, ``ArrayStride``, ``MatrixStride``, ``RowMajor``, ``ColMajor``) and
- the ``BufferBlock`` decoration. The default layout rule used is vector-relaxed
- OpenGL ``std430``. A variable declared as one of these types will be placed in
- the ``Uniform`` storage class.
- For ``RWStructuredBuffer<T>``, each variable will have an associated counter
- variable generated. The counter variable will be of ``OpTypeStruct`` type, which
- only contains a 32-bit integer. The counter variable takes its own binding
- number. ``.IncrementCounter()``/``.DecrementCounter()`` will modify this counter
- variable.
- For example, for the following HLSL source code:
- .. code:: hlsl
- struct T {
- float a;
- float3 b;
- };
- StructuredBuffer<T> mySBuffer;
- will be translated into
- .. code:: spirv
- ; Layout decoration
- OpMemberDecorate %T 0 Offset 0
- OpMemberDecorate %T 1 Offset 4
- OpDecorate %_runtimearr_T ArrayStride 16
- OpMemberDecorate %type_StructuredBuffer_T 0 Offset 0
- OpMemberDecorate %type_StructuredBuffer_T 0 NoWritable
- ; BufferBlock decoration
- OpDecorate %type_StructuredBuffer_T BufferBlock
- ; Types
- %T = OpTypeStruct %float %v3float
- %_runtimearr_T = OpTypeRuntimeArray %T
- %type_StructuredBuffer_T = OpTypeStruct %_runtimearr_T
- %_ptr_Uniform_type_StructuredBuffer_T = OpTypePointer Uniform %type_StructuredBuffer_T
- ; Variable
- %myCbuffer = OpVariable %_ptr_Uniform_type_ConstantBuffer_T Uniform
- ``AppendStructuredBuffer`` and ``ConsumeStructuredBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``AppendStructuredBuffer<T>``/``ConsumeStructuredBuffer<T>`` is treated as
- storage buffer using Vulkan's terminology. It is translated into an
- ``OpTypeStruct`` containing an ``OpTypeRuntimeArray`` of type ``T``, with
- necessary layout decorations (``Offset``, ``ArrayStride``, ``MatrixStride``,
- ``RowMajor``, ``ColMajor``) and the ``BufferBlock`` decoration. The default
- layout rule used is vector-relaxed OpenGL ``std430``.
- A variable declared as one of these types will be placed in the ``Uniform``
- storage class. Besides, each variable will have an associated counter variable
- generated. The counter variable will be of ``OpTypeStruct`` type, which only
- contains a 32-bit integer. The integer is the total number of elements in the
- buffer. The counter variable takes its own binding number.
- ``.Append()``/``.Consume()`` will use the counter variable as the index and
- adjust it accordingly.
- For example, for the following HLSL source code:
- .. code:: hlsl
- struct T {
- float a;
- float3 b;
- };
- AppendStructuredBuffer<T> mySBuffer;
- will be translated into
- .. code:: spirv
- ; Layout decorations
- OpMemberDecorate %T 0 Offset 0
- OpMemberDecorate %T 1 Offset 4
- OpDecorate %_runtimearr_T ArrayStride 16
- OpMemberDecorate %type_AppendStructuredBuffer_T 0 Offset 0
- OpDecorate %type_AppendStructuredBuffer_T BufferBlock
- OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0
- OpDecorate %type_ACSBuffer_counter BufferBlock
- ; Binding numbers
- OpDecorate %myASbuffer DescriptorSet 0
- OpDecorate %myASbuffer Binding 0
- OpDecorate %counter_var_myASbuffer DescriptorSet 0
- OpDecorate %counter_var_myASbuffer Binding 1
- ; Types
- %T = OpTypeStruct %float %v3float
- %_runtimearr_T = OpTypeRuntimeArray %T
- %type_AppendStructuredBuffer_T = OpTypeStruct %_runtimearr_T
- %_ptr_Uniform_type_AppendStructuredBuffer_T = OpTypePointer Uniform %type_AppendStructuredBuffer_T
- %type_ACSBuffer_counter = OpTypeStruct %int
- %_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
- ; Variables
- %myASbuffer = OpVariable %_ptr_Uniform_type_AppendStructuredBuffer_T Uniform
- %counter_var_myASbuffer = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
- ``ByteAddressBuffer`` and ``RWByteAddressBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``ByteAddressBuffer``/``RWByteAddressBuffer`` is treated as storage buffer using
- Vulkan's terminology. It is translated into an ``OpTypeStruct`` containing an
- ``OpTypeRuntimeArray`` of 32-bit unsigned integers, with ``BufferBlock``
- decoration.
- A variable declared as one of these types will be placed in the ``Uniform``
- storage class.
- For example, for the following HLSL source code:
- .. code:: hlsl
- ByteAddressBuffer myBuffer1;
- RWByteAddressBuffer myBuffer2;
- will be translated into
- .. code:: spirv
- ; Layout decorations
- OpDecorate %_runtimearr_uint ArrayStride 4
- OpDecorate %type_ByteAddressBuffer BufferBlock
- OpMemberDecorate %type_ByteAddressBuffer 0 Offset 0
- OpMemberDecorate %type_ByteAddressBuffer 0 NonWritable
- OpDecorate %type_RWByteAddressBuffer BufferBlock
- OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0
- ; Types
- %_runtimearr_uint = OpTypeRuntimeArray %uint
- %type_ByteAddressBuffer = OpTypeStruct %_runtimearr_uint
- %_ptr_Uniform_type_ByteAddressBuffer = OpTypePointer Uniform %type_ByteAddressBuffer
- %type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint
- %_ptr_Uniform_type_RWByteAddressBuffer = OpTypePointer Uniform %type_RWByteAddressBuffer
- ; Variables
- %myBuffer1 = OpVariable %_ptr_Uniform_type_ByteAddressBuffer Uniform
- %myBuffer2 = OpVariable %_ptr_Uniform_type_RWByteAddressBuffer Uniform
- HLSL Variables and Resources
- ============================
- This section lists how various HLSL variables and resources are mapped.
- According to `Shader Constants <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509581(v=vs.85).aspx>`_,
- There are two default constant buffers available, $Global and $Param. Variables
- that are placed in the global scope are added implicitly to the $Global cbuffer,
- using the same packing method that is used for cbuffers. Uniform parameters in
- the parameter list of a function appear in the $Param constant buffer when a
- shader is compiled outside of the effects framework.
- So all global externally-visible non-resource-type stand-alone variables will
- be collected into a cbuffer named as ``$Globals``, no matter whether they are
- statically referenced by the entry point or not. The ``$Globals`` cbuffer
- follows the layout rules like normal cbuffer.
- Storage class
- -------------
- Normal local variables (without any modifier) will be placed in the ``Function``
- SPIR-V storage class. Normal global variables (without any modifer) will be
- placed in the ``Uniform`` or ``UniformConstant`` storage class.
- - ``static``
- - Global variables with ``static`` modifier will be placed in the ``Private``
- SPIR-V storage class. Initalizers of such global variables will be translated
- into SPIR-V ``OpVariable`` initializers if possible; otherwise, they will be
- initialized at the very beginning of the `entry function wrapper`_ using
- SPIR-V ``OpStore``.
- - Local variables with ``static`` modifier will also be placed in the
- ``Private`` SPIR-V storage class. initializers of such local variables will
- also be translated into SPIR-V ``OpVariable`` initializers if possible;
- otherwise, they will be initialized at the very beginning of the enclosing
- function. To make sure that such a local variable is only initialized once,
- a second boolean variable of the ``Private`` SPIR-V storage class will be
- generated to mark its initialization status.
- - ``groupshared``
- - Global variables with ``groupshared`` modifier will be placed in the
- ``Workgroup`` storage class.
- - Note that this modifier overrules ``static``; if both ``groupshared`` and
- ``static`` are applied to a variable, ``static`` will be ignored.
- - ``uinform``
- - This does not affect codegen. Variables will be treated like normal global
- variables.
- - ``extern``
- - This does not affect codegen. Variables will be treated like normal global
- variables.
- - ``shared``
- - This is a hint to the compiler. It will be ingored.
- - ``volatile``
- - This is a hint to the compiler. It will be ingored.
- HLSL semantic and Vulkan ``Location``
- -------------------------------------
- Direct3D uses HLSL "`semantics <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx>`_"
- to compose and match the interfaces between subsequent stages. These semantic
- strings can appear after struct members, function parameters and return
- values. E.g.,
- .. code:: hlsl
- struct VSInput {
- float4 pos : POSITION;
- float3 norm : NORMAL;
- };
- float4 VSMain(in VSInput input,
- in float4 tex : TEXCOORD,
- out float4 pos : SV_Position) : TEXCOORD {
- pos = input.pos;
- return tex;
- }
- In contrary, Vulkan stage input and output interface matching is via explicit
- ``Location`` numbers. Details can be found `here <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#interfaces-iointerfaces>`_.
- To translate HLSL to SPIR-V for Vulkan, semantic strings need to be mapped to
- Vulkan ``Location`` numbers properly. This can be done either explicitly via
- information provided by the developer or implicitly by the compiler.
- Explicit ``Location`` number assignment
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``[[vk::location(X)]]`` can be attached to the entities where semantic are
- allowed to attach (struct fields, function parameters, and function returns).
- For the above exmaple we can have:
- .. code:: hlsl
- struct VSInput {
- [[vk::location(0)]] float4 pos : POSITION;
- [[vk::location(1)]] float3 norm : NORMAL;
- };
- [[vk::location(1)]]
- float4 VSMain(in VSInput input,
- [[vk::location(2)]]
- in float4 tex : TEXCOORD,
- out float4 pos : SV_Position) : TEXCOORD {
- pos = input.pos;
- return tex;
- }
- In the above, input ``POSITION``, ``NORMAL``, and ``TEXCOORD`` will be mapped to
- ``Location`` 0, 1, and 2, respectively, and output ``TEXCOORD`` will be mapped
- to ``Location`` 1.
- [TODO] Another explicit way: using command-line options
- Please note that the compiler prohibits mixing the explicit and implicit
- approach for the same SigPoint to avoid complexity and fallibility. However,
- for a certain shader stage, one SigPoint using the explicit approach while the
- other adopting the implicit approach is permitted.
- Implicit ``Location`` number assignment
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Without hints from the developer, the compiler will try its best to map
- semantics to ``Location`` numbers. However, there is no single rule for this
- mapping; semantic strings should be handled case by case.
- Firstly, under certain `SigPoints <https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#hlsl-signatures-and-semantics>`_,
- some system-value (SV) semantic strings will be translated into SPIR-V
- ``BuiltIn`` decorations:
- .. table:: Mapping from HLSL SV semantic to SPIR-V builtin and execution mode
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | HLSL Semantic | SigPoint | SPIR-V ``BuiltIn`` | SPIR-V Execution Mode | SPIR-V Capability |
- +===========================+=============+========================================+=======================+=============================+
- | | VSOut | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPIn | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPOut | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSCPIn | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_Position | DSOut | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSVIn | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``Position`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``FragCoord`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``Position`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | VSOut | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPIn | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPOut | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSCPIn | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_ClipDistance | DSOut | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSVIn | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``ClipDistance`` | N/A | ``ClipDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``ClipDistance`` | N/A | ``ClipDistance`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | VSOut | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPIn | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSCPOut | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSCPIn | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_CullDistance | DSOut | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSVIn | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``CullDistance`` | N/A | ``CullDistance`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``CullDistance`` | N/A | ``CullDistance`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_VertexID | VSIn | ``VertexIndex`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_InstanceID | VSIn | ``InstanceIndex`` or | N/A | ``Shader`` |
- | | | ``InstanceIndex - BaseInstance`` | | |
- | | | with | | |
- | | | ``-fvk-support-nonzero-base-instance`` | | |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_Depth | PSOut | ``FragDepth`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_DepthGreaterEqual | PSOut | ``FragDepth`` | ``DepthGreater`` | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_DepthLessEqual | PSOut | ``FragDepth`` | ``DepthLess`` | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_IsFrontFace | PSIn | ``FrontFacing`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | CSIn | ``GlobalInvocationId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_DispatchThreadID | MSIn | ``GlobalInvocationId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | ASIn | ``GlobalInvocationId`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | CSIn | ``WorkgroupId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_GroupID | MSIn | ``WorkgroupId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | ASIn | ``WorkgroupId`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | CSIn | ``LocalInvocationId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_GroupThreadID | MSIn | ``LocalInvocationId`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | ASIn | ``LocalInvocationId`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | CSIn | ``LocalInvocationIndex`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_GroupIndex | MSIn | ``LocalInvocationIndex`` | N/A | ``Shader`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | ASIn | ``LocalInvocationIndex`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_OutputControlPointID | HSIn | ``InvocationId`` | N/A | ``Tessellation`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_GSInstanceID | GSIn | ``InvocationId`` | N/A | ``Geometry`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_DomainLocation | DSIn | ``TessCoord`` | N/A | ``Tessellation`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSIn | ``PrimitiveId`` | N/A | ``Tessellation`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PCIn | ``PrimitiveId`` | N/A | ``Tessellation`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DsIn | ``PrimitiveId`` | N/A | ``Tessellation`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_PrimitiveID | GSIn | ``PrimitiveId`` | N/A | ``Geometry`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``PrimitiveId`` | N/A | ``Geometry`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``PrimitiveId`` | N/A | ``Geometry`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``PrimitiveId`` | N/A | ``MeshShadingNV`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PCOut | ``TessLevelOuter`` | N/A | ``Tessellation`` |
- | SV_TessFactor +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSIn | ``TessLevelOuter`` | N/A | ``Tessellation`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PCOut | ``TessLevelInner`` | N/A | ``Tessellation`` |
- | SV_InsideTessFactor +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSIn | ``TessLevelInner`` | N/A | ``Tessellation`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_SampleIndex | PSIn | ``SampleId`` | N/A | ``SampleRateShading`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_StencilRef | PSOut | ``FragStencilRefEXT`` | N/A | ``StencilExportEXT`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_Barycentrics | PSIn | ``BaryCoord*AMD`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``Layer`` | N/A | ``Geometry`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_RenderTargetArrayIndex | PSIn | ``Layer`` | N/A | ``Geometry`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``Layer`` | N/A | ``MeshShadingNV`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``ViewportIndex`` | N/A | ``MultiViewport`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_ViewportArrayIndex | PSIn | ``ViewportIndex`` | N/A | ``MultiViewport`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``ViewportIndex`` | N/A | ``MeshShadingNV`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``SampleMask`` | N/A | ``Shader`` |
- | SV_Coverage +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSOut | ``SampleMask`` | N/A | ``Shader`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | SV_InnerCoverage | PSIn | ``FullyCoveredEXT`` | N/A | ``FragmentFullyCoveredEXT`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | VSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | HSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | DSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- | SV_ViewID +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSIn | ``ViewIndex`` | N/A | ``MultiView`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- | | VSOut | ``PrimitiveShadingRateKHR`` | N/A | ``FragmentShadingRate`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | GSOut | ``PrimitiveShadingRateKHR`` | N/A | ``FragmentShadingRate`` |
- | SV_ShadingRate +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | PSIn | ``ShadingRateKHR`` | N/A | ``FragmentShadingRate`` |
- | +-------------+----------------------------------------+-----------------------+-----------------------------+
- | | MSOut | ``PrimitiveShadingRateKHR`` | N/A | ``FragmentShadingRate`` |
- +---------------------------+-------------+----------------------------------------+-----------------------+-----------------------------+
- For entities (function parameters, function return values, struct fields) with
- the above SV semantic strings attached, SPIR-V variables of the
- ``Input``/``Output`` storage class will be created. They will have the
- corresponding SPIR-V ``Builtin`` decorations according to the above table.
- SV semantic strings not translated into SPIR-V ``BuiltIn`` decorations will be
- handled similarly as non-SV (arbitrary) semantic strings: a SPIR-V variable
- of the ``Input``/``Output`` storage class will be created for each entity with
- such semantic string. Then sort all semantic strings according to declaration
- (the default, or if ``-fvk-stage-io-order=decl`` is given) or alphabetical
- (if ``-fvk-stage-io-order=alpha`` is given) order, and assign ``Location``
- numbers sequentially to the corresponding SPIR-V variables. Note that this means
- flattening all structs if structs are used as function parameters or returns.
- There is an exception to the above rule for SV_Target[N]. It will always be
- mapped to ``Location`` number N.
- ``ClipDistance & CullDistance``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Variables decorated with ``SV_ClipDistanceX`` can be float or vector of float
- type. To map them into one float array in the struct, we firstly sort them
- asecendingly according to ``X``, and then concatenate them tightly. For example,
- .. code:: hlsl
- struct T {
- float clip0: SV_ClipDistance0,
- };
- struct S {
- float3 clip5: SV_ClipDistance5;
- ...
- };
- void main(T t, S s, float2 clip2 : SV_ClipDistance2) { ... }
- Then we have an float array of size (1 + 2 + 3 =) 6 for ``ClipDistance``, with
- ``clip0`` at offset 0, ``clip2`` at offset 1, ``clip5`` at offset 3.
- Decorating a variable or struct member with the ``ClipDistance`` builtin but not
- requiring the ``ClipDistance`` capability is legal as long as we don't read or
- write the variable or struct member. But as per the way we handle `shader entry
- function`_, this is not satisfied because we need to read their contents to
- prepare for the source code entry function call or write back them after the
- call. So annotating a variable or struct member with ``SV_ClipDistanceX`` means
- requiring the ``ClipDistance`` capability in the generated SPIR-V.
- Variables decorated with ``SV_CullDistanceX`` are mapped similarly as above.
- HLSL register and Vulkan binding
- --------------------------------
- In shaders for DirectX, resources are accessed via registers; while in shaders
- for Vulkan, it is done via descriptor set and binding numbers. The developer
- can explicitly annotate variables in HLSL to specify descriptor set and binding
- numbers, or leave it to the compiler to derive implicitly from registers.
- Explicit binding number assignment
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``[[vk::binding(X[, Y])]]`` can be attached to global variables to specify the
- descriptor set as ``Y`` and binding number as ``X``. The descriptor set number
- is optional; if missing, it will be zero (If ``-auto-binding-space N`` command
- line option is used, then descriptor set #N will be used instead of descriptor
- set #0). RW/append/consume structured buffers have associated counters, which
- will occupy their own Vulkan descriptors. ``[vk::counter_binding(Z)]`` can be
- attached to a RW/append/consume structured buffers to specify the binding number
- for the associated counter to ``Z``. Note that the set number of the counter is
- always the same as the main buffer.
- Implicit binding number assignment
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Without explicit annotations, the compiler will try to deduce descriptor sets
- and binding numbers in the following way:
- If there is ``:register(xX, spaceY)`` specified for the given global variable,
- the corresponding resource will be assigned to descriptor set ``Y`` and binding
- number ``X``, regardless of the register type ``x``. Note that this will cause
- binding number collision if, say, two resources are of different register
- type but the same register number. To solve this problem, four command-line
- options, ``-fvk-b-shift N M``, ``-fvk-s-shift N M``, ``-fvk-t-shift N M``, and
- ``-fvk-u-shift N M``, are provided to shift by ``N`` all binding numbers
- inferred for register type ``b``, ``s``, ``t``, and ``u`` in space ``M``,
- respectively.
- If there is no register specification, the corresponding resource will be
- assigned to the next available binding number, starting from 0, in descriptor
- set #0 (If ``-auto-binding-space N`` command line option is used, then
- descriptor set #N will be used instead of descriptor set #0).
- If there is no register specification AND ``-fvk-auto-shift-bindings`` is specified,
- then the register type will be automatically identified based on the resource
- type (according to the following table), and the appropriate shift will
- automatically be applied according to ``-fvk-*shift N M``.
- .. code:: spirv
- t - for shader resource views (SRV)
- TEXTURE1D
- TEXTURE1DARRAY
- TEXTURE2D
- TEXTURE2DARRAY
- TEXTURE3D
- TEXTURECUBE
- TEXTURECUBEARRAY
- TEXTURE2DMS
- TEXTURE2DMSARRAY
- STRUCTUREDBUFFER
- BYTEADDRESSBUFFER
- BUFFER
- TBUFFER
- s - for samplers
- SAMPLER
- SAMPLER1D
- SAMPLER2D
- SAMPLER3D
- SAMPLERCUBE
- SAMPLERSTATE
- SAMPLERCOMPARISONSTATE
- u - for unordered access views (UAV)
- RWBYTEADDRESSBUFFER
- RWSTRUCTUREDBUFFER
- APPENDSTRUCTUREDBUFFER
- CONSUMESTRUCTUREDBUFFER
- RWBUFFER
- RWTEXTURE1D
- RWTEXTURE1DARRAY
- RWTEXTURE2D
- RWTEXTURE2DARRAY
- RWTEXTURE3D
- b - for constant buffer views (CBV)
- CBUFFER
- CONSTANTBUFFER
- Summary
- ~~~~~~~
- In summary, the compiler essentially assigns binding numbers in three passes.
- - Firstly it handles all declarations with explicit ``[[vk::binding(X[, Y])]]``
- annotation.
- - Then the compiler processes all remaining declarations with
- ``:register(xX, spaceY)`` annotation, by applying the shift passed in using
- command-line option ``-fvk-{b|s|t|u}-shift N M``, if provided.
- - If ``:register`` assignment is missing and ``-fvk-auto-shift-bindings`` is
- specified, the register type will be automatically detected based on the
- resource type, and the ``-fvk-{b|s|t|u}-shift N M`` will be applied.
- - Finally, the compiler assigns next available binding numbers to the rest in
- the declaration order.
- As an example, for the following code:
- .. code:: hlsl
- struct S { ... };
- ConstantBuffer<S> cbuffer1 : register(b0);
- Texture2D<float4> texture1 : register(t0);
- Texture2D<float4> texture2 : register(t1, space1);
- SamplerState sampler1;
- [[vk::binding(3)]]
- RWBuffer<float4> rwbuffer1 : register(u5, space2);
- If we compile with ``-fvk-t-shift 10 0 -fvk-t-shift 20 1``:
- - ``rwbuffer1`` will take binding #3 in set #0, since explicit binding
- assignment has precedence over the rest.
- - ``cbuffer1`` will take binding #0 in set #0, since that's what deduced from
- the register assignment, and there is no shift requested from command line.
- - ``texture1`` will take binding #10 in set #0, and ``texture2`` will take
- binding #21 in set #1, since we requested an 10 shift on t-type registers.
- - ``sampler1`` will take binding 1 in set #0, since that's the next available
- binding number in set #0.
- HLSL global variables and Vulkan binding
- ----------------------------------------
- As mentioned above, all global externally-visible non-resource-type stand-alone
- variables will be collected into a cbuffer named ``$Globals``. By default,
- the ``$Globals`` cbuffer is placed in descriptor set #0, and the binding number
- would be the next available binding number in that set. Meaning, the binding number
- depends on where the very first global variable is in the code.
- Example 1:
- .. code:: hlsl
- float4 someColors;
- // $Globals cbuffer placed at DescriptorSet #0, Binding #0
- Texture2D<float4> texture1;
- // texture1 placed at DescriptorSet #0, Binding #1
- Example 2:
- .. code:: hlsl
- Texture2D<float4> texture1;
- // texture1 placed at DescriptorSet #0, Binding #0
- float4 someColors;
- // $Globals cbuffer placed at DescriptorSet #0, Binding #1
- In order provide more control over the descriptor set and binding number of the
- ``$Globals`` cbuffer, you can use the ``-fvk-bind-globals B S`` command line
- option, which will place this cbuffer at descriptor set ``S``, and binding number ``B``.
- Example 3: (compiled with ``-fvk-bind-globals 2 1``)
- .. code:: hlsl
- Texture2D<float4> texture1;
- // texture1 placed at DescriptorSet #0, Binding #0
- float4 someColors;
- // $Globals cbuffer placed at DescriptorSet #1, Binding #2
- Note that if the developer chooses to use this command line option, it is their
- responsibility to provide proper numbers and avoid binding overlaps.
- HLSL Expressions
- ================
- Unless explicitly noted, matrix per-element operations will be conducted on
- each component vector and then collected into the result matrix. The following
- sections lists the SPIR-V opcodes for scalars and vectors.
- Arithmetic operators
- --------------------
- `Arithmetic operators <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx#Additive_and_Multiplicative_Operators>`_
- (``+``, ``-``, ``*``, ``/``, ``%``) are translated into their corresponding
- SPIR-V opcodes according to the following table.
- +-------+-----------------------------+-------------------------------+--------------------+
- | | (Vector of) Signed Integers | (Vector of) Unsigned Integers | (Vector of) Floats |
- +=======+=============================+===============================+====================+
- | ``+`` | ``OpIAdd`` | ``OpFAdd`` |
- +-------+-------------------------------------------------------------+--------------------+
- | ``-`` | ``OpISub`` | ``OpFSub`` |
- +-------+-------------------------------------------------------------+--------------------+
- | ``*`` | ``OpIMul`` | ``OpFMul`` |
- +-------+-----------------------------+-------------------------------+--------------------+
- | ``/`` | ``OpSDiv`` | ``OpUDiv`` | ``OpFDiv`` |
- +-------+-----------------------------+-------------------------------+--------------------+
- | ``%`` | ``OpSRem`` | ``OpUMod`` | ``OpFRem`` |
- +-------+-----------------------------+-------------------------------+--------------------+
- Note that for modulo operation, SPIR-V has two sets of instructions: ``Op*Rem``
- and ``Op*Mod``. For ``Op*Rem``, the sign of a non-0 result comes from the first
- operand; while for ``Op*Mod``, the sign of a non-0 result comes from the second
- operand. HLSL doc does not mandate which set of instructions modulo operations
- should be translated into; it only says "the % operator is defined only in cases
- where either both sides are positive or both sides are negative." So technically
- it's undefined behavior to use the modulo operation with operands of different
- signs. But considering HLSL's C heritage and the behavior of Clang frontend, we
- translate modulo operators into ``Op*Rem`` (there is no ``OpURem``).
- For multiplications of float vectors and float scalars, the dedicated SPIR-V
- operation ``OpVectorTimesScalar`` will be used. Similarly, for multiplications
- of float matrices and float scalars, ``OpMatrixTimesScalar`` will be generated.
- Bitwise operators
- -----------------
- `Bitwise operators <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx#Bitwise_Operators>`_
- (``~``, ``&``, ``|``, ``^``, ``<<``, ``>>``) are translated into their
- corresponding SPIR-V opcodes according to the following table.
- +--------+-----------------------------+-------------------------------+
- | | (Vector of) Signed Integers | (Vector of) Unsigned Integers |
- +========+=============================+===============================+
- | ``~`` | ``OpNot`` |
- +--------+-------------------------------------------------------------+
- | ``&`` | ``OpBitwiseAnd`` |
- +--------+-------------------------------------------------------------+
- | ``|`` | ``OpBitwiseOr`` |
- +--------+-----------------------------+-------------------------------+
- | ``^`` | ``OpBitwiseXor`` |
- +--------+-----------------------------+-------------------------------+
- | ``<<`` | ``OpShiftLeftLogical`` |
- +--------+-----------------------------+-------------------------------+
- | ``>>`` | ``OpShiftRightArithmetic`` | ``OpShiftRightLogical`` |
- +--------+-----------------------------+-------------------------------+
- Note that for ``<<``/``>>``, the right hand side will be culled: only the ``n``
- - 1 least significant bits are considered, where ``n`` is the bitwidth of the
- left hand side.
- Comparison operators
- --------------------
- `Comparison operators <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx#Comparison_Operators>`_
- (``<``, ``<=``, ``>``, ``>=``, ``==``, ``!=``) are translated into their
- corresponding SPIR-V opcodes according to the following table.
- +--------+-----------------------------+-------------------------------+------------------------------+
- | | (Vector of) Signed Integers | (Vector of) Unsigned Integers | (Vector of) Floats |
- +========+=============================+===============================+==============================+
- | ``<`` | ``OpSLessThan`` | ``OpULessThan`` | ``OpFOrdLessThan`` |
- +--------+-----------------------------+-------------------------------+------------------------------+
- | ``<=`` | ``OpSLessThanEqual`` | ``OpULessThanEqual`` | ``OpFOrdLessThanEqual`` |
- +--------+-----------------------------+-------------------------------+------------------------------+
- | ``>`` | ``OpSGreaterThan`` | ``OpUGreaterThan`` | ``OpFOrdGreaterThan`` |
- +--------+-----------------------------+-------------------------------+------------------------------+
- | ``>=`` | ``OpSGreaterThanEqual`` | ``OpUGreaterThanEqual`` | ``OpFOrdGreaterThanEqual`` |
- +--------+-----------------------------+-------------------------------+------------------------------+
- | ``==`` | ``OpIEqual`` | ``OpFOrdEqual`` |
- +--------+-------------------------------------------------------------+------------------------------+
- | ``!=`` | ``OpINotEqual`` | ``OpFOrdNotEqual`` |
- +--------+-------------------------------------------------------------+------------------------------+
- Note that for comparison of (vectors of) floats, SPIR-V has two sets of
- instructions: ``OpFOrd*``, ``OpFUnord*``. We translate into ``OpFOrd*`` ones.
- Boolean math operators
- ----------------------
- `Boolean match operators <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx#Boolean_Math_Operators>`_
- (``&&``, ``||``, ``?:``) are translated into their corresponding SPIR-V opcodes
- according to the following table.
- +--------+----------------------+
- | | (Vector of) Booleans |
- +========+======================+
- | ``&&`` | ``OpLogicalAnd`` |
- +--------+----------------------+
- | ``||`` | ``OpLogicalOr`` |
- +--------+----------------------+
- | ``?:`` | ``OpSelect`` |
- +--------+----------------------+
- Please note that "unlike short-circuit evaluation of ``&&``, ``||``, and ``?:``
- in C, HLSL expressions never short-circuit an evaluation because they are vector
- operations. All sides of the expression are always evaluated."
- Unary operators
- ---------------
- For `unary operators <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509631(v=vs.85).aspx#Unary_Operators>`_:
- - ``!`` is translated into ``OpLogicalNot``. Parsing will gurantee the operands
- are of boolean types by inserting necessary casts.
- - ``+`` requires no additional SPIR-V instructions.
- - ``-`` is translated into ``OpSNegate`` and ``OpFNegate`` for (vectors of)
- integers and floats, respectively.
- Casts
- -----
- Casting between (vectors) of scalar types is translated according to the following table:
- +------------+-------------------+-------------------+-------------------+-------------------+
- | From \\ To | Bool | SInt | UInt | Float |
- +============+===================+===================+===================+===================+
- | Bool | no-op | select between one and zero |
- +------------+-------------------+-------------------+-------------------+-------------------+
- | SInt | | no-op | ``OpBitcast`` | ``OpConvertSToF`` |
- +------------+ +-------------------+-------------------+-------------------+
- | UInt | compare with zero | ``OpBitcast`` | no-op | ``OpConvertUToF`` |
- +------------+ +-------------------+-------------------+-------------------+
- | Float | | ``OpConvertFToS`` | ``OpConvertFToU`` | no-op |
- +------------+-------------------+-------------------+-------------------+-------------------+
- It is also feasible in HLSL to cast a float matrix to another float matrix with a smaller size.
- This is known as matrix truncation cast. For instance, the following code casts a 3x4 matrix
- into a 2x3 matrix.
- .. code:: hlsl
- float3x4 m = { 1, 2, 3, 4,
- 5, 6, 7, 8,
- 9, 10, 11, 12 };
- float2x3 a = (float2x3)m;
- Such casting takes the upper-left most corner of the original matrix to generate the result.
- In the above example, matrix ``a`` will have 2 rows, with 3 columns each. First row will be
- ``1, 2, 3`` and the second row will be ``5, 6, 7``.
- Indexing operator
- -----------------
- The ``[]`` operator can also be used to access elements in a matrix or vector.
- A matrix whose row and/or column count is 1 will be translated into a vector or
- scalar. If a variable is used as the index for the dimension whose count is 1,
- that variable will be ignored in the generated SPIR-V code. This is because
- out-of-bound indexing triggers undefined behavior anyway. For example, for a
- 1xN matrix ``mat``, ``mat[index][0]`` will be translated into
- ``OpAccessChain ... %mat %uint_0``. Similarly, variable index into a size 1
- vector will also be ignored and the only element will be always returned.
- Assignment operators
- --------------------
- Assigning to struct object may involve decomposing the source struct object and
- assign each element separately and recursively. This happens when the source
- struct object is of different memory layout from the destination struct object.
- For example, for the following source code:
- .. code:: hlsl
- struct S {
- float a;
- float2 b;
- float2x3 c;
- };
- ConstantBuffer<S> cbuf;
- RWStructuredBuffer<S> sbuf;
- ...
- sbuf[0] = cbuf[0];
- ...
- We need to assign each element because ``ConstantBuffer`` and
- ``RWStructuredBuffer`` has different memory layout.
- HLSL Control Flows
- ==================
- This section lists how various HLSL control flows are mapped.
- Switch statement
- ----------------
- HLSL `switch statements <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509669(v=vs.85).aspx>`_
- are translated into SPIR-V using:
- - **OpSwitch**: if (all case values are integer literals or constant integer
- variables) and (no attribute or the ``forcecase`` attribute is specified)
- - **A series of if statements**: for all other scenarios (e.g., when
- ``flatten``, ``branch``, or ``call`` attribute is specified)
- Loops (for, while, do)
- ----------------------
- HLSL `for statements <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509602(v=vs.85).aspx>`_,
- `while statements <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509708(v=vs.85).aspx>`_,
- and `do statements <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509593(v=vs.85).aspx>`_
- are translated into SPIR-V by constructing all necessary basic blocks and using
- ``OpLoopMerge`` to organize as structured loops.
- The HLSL attributes for these statements are translated into SPIR-V loop control
- masks according to the following table:
- +-------------------------+--------------------------------------------------+
- | HLSL loop attribute | SPIR-V Loop Control Mask |
- +=========================+==================================================+
- | ``unroll(x)`` | ``Unroll`` |
- +-------------------------+--------------------------------------------------+
- | ``loop`` | ``DontUnroll`` |
- +-------------------------+--------------------------------------------------+
- | ``fastopt`` | ``DontUnroll`` |
- +-------------------------+--------------------------------------------------+
- | ``allow_uav_condition`` | Currently Unimplemented |
- +-------------------------+--------------------------------------------------+
- HLSL Functions
- ==============
- All functions reachable from the entry-point function will be translated into
- SPIR-V code. Functions not reachable from the entry-point function will be
- ignored.
- Entry function wrapper
- ----------------------
- HLSL entry functions takes in parameters and returns values. These parameters
- and return values can have semantics attached or if they are struct type,
- the struct fields can have semantics attached. However, in Vulkan, the entry
- function must be of the ``void(void)`` signature. To handle this difference,
- for a given entry function ``main``, we will emit a wrapper function for it.
- The wrapper function will take the name of the source code entry function,
- while the source code entry function will have its name prefixed with "src.".
- The wrapper function reads in stage input/builtin variables created according
- to semantics and groups them into composites meeting the requirements of the
- source code entry point. Then the wrapper calls the source code entry point.
- The return value is extracted and components of it will be written to stage
- output/builtin variables created according to semantics. For example:
- .. code:: hlsl
- // HLSL source code
- struct S {
- bool a : A;
- uint2 b: B;
- float2x3 c: C;
- };
- struct T {
- S x;
- int y: D;
- };
- T main(T input) {
- return input;
- }
- .. code:: spirv
- ; SPIR-V code
- %in_var_A = OpVariable %_ptr_Input_bool Input
- %in_var_B = OpVariable %_ptr_Input_v2uint Input
- %in_var_C = OpVariable %_ptr_Input_mat2v3float Input
- %in_var_D = OpVariable %_ptr_Input_int Input
- %out_var_A = OpVariable %_ptr_Output_bool Output
- %out_var_B = OpVariable %_ptr_Output_v2uint Output
- %out_var_C = OpVariable %_ptr_Output_mat2v3float Output
- %out_var_D = OpVariable %_ptr_Output_int Output
- ; Wrapper function starts
- %main = OpFunction %void None ...
- ... = OpLabel
- %param_var_input = OpVariable %_ptr_Function_T Function
- ; Load stage input variables and group into the expected composite
- %inA = OpLoad %bool %in_var_A
- %inB = OpLoad %v2uint %in_var_B
- %inC = OpLoad %mat2v3float %in_var_C
- %inS = OpCompositeConstruct %S %inA %inB %inC
- %inD = OpLoad %int %in_var_D
- %inT = OpCompositeConstruct %T %inS %inD
- OpStore %param_var_input %inT
- %ret = OpFunctionCall %T %src_main %param_var_input
- ; Extract component values from the composite and store into stage output variables
- %outS = OpCompositeExtract %S %ret 0
- %outA = OpCompositeExtract %bool %outS 0
- OpStore %out_var_A %outA
- %outB = OpCompositeExtract %v2uint %outS 1
- OpStore %out_var_B %outB
- %outC = OpCompositeExtract %mat2v3float %outS 2
- OpStore %out_var_C %outC
- %outD = OpCompositeExtract %int %ret 1
- OpStore %out_var_D %outD
- OpReturn
- OpFunctionEnd
- ; Source code entry point starts
- %src_main = OpFunction %T None ...
- In this way, we can concentrate all stage input/output/builtin variable
- manipulation in the wrapper function and handle the source code entry function
- just like other nomal functions.
- Function parameter
- ------------------
- For a function ``f`` which has a parameter of type ``T``, the generated SPIR-V
- signature will use type ``T*`` for the parameter. At every call site of ``f``,
- additional local variables will be allocated to hold the actual arguments.
- The local variables are passed in as direct function arguments. For example:
- .. code:: hlsl
- // HLSL source code
- float4 f(float a, int b) { ... }
- void caller(...) {
- ...
- float4 result = f(...);
- ...
- }
- .. code:: spirv
- ; SPIR-V code
- ...
- %i32PtrType = OpTypePointer Function %int
- %f32PtrType = OpTypePointer Function %float
- %fnType = OpTypeFunction %v4float %f32PtrType %i32PtrType
- ...
- %f = OpFunction %v4float None %fnType
- %a = OpFunctionParameter %f32PtrType
- %b = OpFunctionParameter %i32PtrType
- ...
- %caller = OpFunction ...
- ...
- %aAlloca = OpVariable %_ptr_Function_float Function
- %bAlloca = OpVariable %_ptr_Function_int Function
- ...
- OpStore %aAlloca ...
- OpStore %bAlloca ...
- %result = OpFunctioncall %v4float %f %aAlloca %bAlloca
- ...
- This approach gives us unified handling of function parameters and local
- variables: both of them are accessed via load/store instructions.
- Intrinsic functions
- -------------------
- The following intrinsic HLSL functions have no direct SPIR-V opcode or GLSL
- extended instruction mapping, so they are handled with additional steps:
- - ``dot`` : performs dot product of two vectors, each containing floats or
- integers. If the two parameters are vectors of floats, we use SPIR-V's
- ``OpDot`` instruction to perform the translation. If the two parameters are
- vectors of integers, we multiply corresponding vector elements using
- ``OpIMul`` and accumulate the results using ``OpIAdd`` to compute the dot
- product.
- - ``mul``: performs multiplications. Each argument may be a scalar, vector,
- or matrix. Depending on the argument type, this will be translated into
- one of the multiplication instructions.
- - ``all``: returns true if all components of the given scalar, vector, or
- matrix are true. Performs conversions to boolean where necessary. Uses SPIR-V
- ``OpAll`` for scalar arguments and vector arguments. For matrix arguments,
- performs ``OpAll`` on each row, and then again on the vector containing the
- results of all rows.
- - ``any``: returns true if any component of the given scalar, vector, or matrix
- is true. Performs conversions to boolean where necessary. Uses SPIR-V
- ``OpAny`` for scalar arguments and vector arguments. For matrix arguments,
- performs ``OpAny`` on each row, and then again on the vector containing the
- results of all rows.
- - ``asfloat``: converts the component type of a scalar/vector/matrix from float,
- uint, or int into float. Uses ``OpBitcast``. This method currently does not
- support taking non-float matrix arguments.
- - ``asint``: converts the component type of a scalar/vector/matrix from float or
- uint into int. Uses ``OpBitcast``. This method currently does not support
- conversion into integer matrices.
- - ``asuint``: converts the component type of a scalar/vector/matrix from float
- or int into uint. Uses ``OpBitcast``. This method currently does not support
- - ``asuint``: Converts a double into two 32-bit unsigned integers. Uses SPIR-V ``OpBitCast``.
- - ``asdouble``: Converts two 32-bit unsigned integers into a double, or four 32-bit unsigned
- integers into two doubles. Uses SPIR-V ``OpVectorShuffle`` and ``OpBitCast``.
- conversion into unsigned integer matrices.
- - ``isfinite`` : Determines if the specified value is finite. Since ``OpIsFinite``
- requires the ``Kernel`` capability, translation is done using ``OpIsNan`` and
- ``OpIsInf``. A given value is finite iff it is not NaN and not infinite.
- - ``clip``: Discards the current pixel if the specified value is less than zero.
- Uses conditional control flow as well as SPIR-V ``OpKill``.
- - ``rcp``: Calculates a fast, approximate, per-component reciprocal.
- Uses SIR-V ``OpFDiv``.
- - ``lit``: Returns a lighting coefficient vector. This vector is a float4 with
- components of (ambient, diffuse, specular, 1). How ``diffuse`` and ``specular``
- are calculated are explained `here <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509619(v=vs.85).aspx>`_.
- - ``D3DCOLORtoUBYTE4``: Converts a floating-point, 4D vector set by a D3DCOLOR to a UBYTE4.
- This is achieved by performing ``int4(input.zyxw * 255.002)`` using SPIR-V ``OpVectorShuffle``,
- ``OpVectorTimesScalar``, and ``OpConvertFToS``, respectively.
- - ``dst``: Calculates a distance vector. The resulting vector, ``dest``, has the following specifications:
- ``dest.x = 1.0``, ``dest.y = src0.y * src1.y``, ``dest.z = src0.z``, and ``dest.w = src1.w``.
- Uses SPIR-V ``OpCompositeExtract`` and ``OpFMul``.
- Using SPIR-V opcode
- ~~~~~~~~~~~~~~~~~~~
- The following intrinsic HLSL functions have direct SPIR-V opcodes for them:
- ==================================== =================================
- HLSL Intrinsic Function SPIR-V Opcode
- ==================================== =================================
- ``AllMemoryBarrier`` ``OpMemoryBarrier``
- ``AllMemoryBarrierWithGroupSync`` ``OpControlBarrier``
- ``countbits`` ``OpBitCount``
- ``DeviceMemoryBarrier`` ``OpMemoryBarrier``
- ``DeviceMemoryBarrierWithGroupSync`` ``OpControlBarrier``
- ``ddx`` ``OpDPdx``
- ``ddy`` ``OpDPdy``
- ``ddx_coarse`` ``OpDPdxCoarse``
- ``ddy_coarse`` ``OpDPdyCoarse``
- ``ddx_fine`` ``OpDPdxFine``
- ``ddy_fine`` ``OpDPdyFine``
- ``fmod`` ``OpFRem``
- ``fwidth`` ``OpFwidth``
- ``GroupMemoryBarrier`` ``OpMemoryBarrier``
- ``GroupMemoryBarrierWithGroupSync`` ``OpControlBarrier``
- ``InterlockedAdd`` ``OpAtomicIAdd``
- ``InterlockedAnd`` ``OpAtomicAnd``
- ``InterlockedOr`` ``OpAtomicOr``
- ``InterlockedXor`` ``OpAtomicXor``
- ``InterlockedMin`` ``OpAtomicUMin``/``OpAtomicSMin``
- ``InterlockedMax`` ``OpAtomicUMax``/``OpAtomicSMax``
- ``InterlockedExchange`` ``OpAtomicExchange``
- ``InterlockedCompareExchange`` ``OpAtomicCompareExchange``
- ``InterlockedCompareStore`` ``OpAtomicCompareExchange``
- ``isnan`` ``OpIsNan``
- ``isInf`` ``OpIsInf``
- ``reversebits`` ``OpBitReverse``
- ``transpose`` ``OpTranspose``
- ``CheckAccessFullyMapped`` ``OpImageSparseTexelsResident``
- ==================================== =================================
- Using GLSL extended instructions
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The following intrinsic HLSL functions are translated using their equivalent
- instruction in the `GLSL extended instruction set <https://www.khronos.org/registry/spir-v/specs/1.0/GLSL.std.450.html>`_.
- ======================= ===================================
- HLSL Intrinsic Function GLSL Extended Instruction
- ======================= ===================================
- ``abs`` ``SAbs``/``FAbs``
- ``acos`` ``Acos``
- ``asin`` ``Asin``
- ``atan`` ``Atan``
- ``atan2`` ``Atan2``
- ``ceil`` ``Ceil``
- ``clamp`` ``SClamp``/``UClamp``/``FClamp``
- ``cos`` ``Cos``
- ``cosh`` ``Cosh``
- ``cross`` ``Cross``
- ``degrees`` ``Degrees``
- ``distance`` ``Distance``
- ``radians`` ``Radian``
- ``determinant`` ``Determinant``
- ``exp`` ``Exp``
- ``exp2`` ``exp2``
- ``f16tof32`` ``UnpackHalf2x16``
- ``f32tof16`` ``PackHalf2x16``
- ``faceforward`` ``FaceForward``
- ``firstbithigh`` ``FindSMsb`` / ``FindUMsb``
- ``firstbitlow`` ``FindILsb``
- ``floor`` ``Floor``
- ``fma`` ``Fma``
- ``frac`` ``Fract``
- ``frexp`` ``FrexpStruct``
- ``ldexp`` ``Ldexp``
- ``length`` ``Length``
- ``lerp`` ``FMix``
- ``log`` ``Log``
- ``log10`` ``Log2`` (scaled by ``1/log2(10)``)
- ``log2`` ``Log2``
- ``mad`` ``Fma``
- ``max`` ``SMax``/``UMax``/``FMax``
- ``min`` ``SMin``/``UMin``/``FMin``
- ``modf`` ``ModfStruct``
- ``normalize`` ``Normalize``
- ``pow`` ``Pow``
- ``reflect`` ``Reflect``
- ``refract`` ``Refract``
- ``round`` ``Round``
- ``rsqrt`` ``InverseSqrt``
- ``saturate`` ``FClamp``
- ``sign`` ``SSign``/``FSign``
- ``sin`` ``Sin``
- ``sincos`` ``Sin`` and ``Cos``
- ``sinh`` ``Sinh``
- ``smoothstep`` ``SmoothStep``
- ``sqrt`` ``Sqrt``
- ``step`` ``Step``
- ``tan`` ``Tan``
- ``tanh`` ``Tanh``
- ``trunc`` ``Trunc``
- ======================= ===================================
- Synchronization intrinsics
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Synchronization intrinsics are translated into ``OpMemoryBarrier`` (for those
- non-``WithGroupSync`` variants) or ``OpControlBarrier`` (for those ``WithGroupSync``
- variants) instructions with parameters:
- ======================= ============ ===== ======= ========= ==============
- HLSL SPIR-V SPIR-V Memory Semantics
- ----------------------- ------------ --------------------------------------
- Intrinsic Memory Scope Image Uniform Workgroup AcquireRelease
- ======================= ============ ===== ======= ========= ==============
- ``AllMemoryBarrier`` Device ✓ ✓ ✓ ✓
- ``DeviceMemoryBarrier`` Device ✓ ✓ ✓
- ``GroupMemoryBarrier`` Workgroup ✓ ✓
- ======================= ============ ===== ======= ========= ==============
- For the ``*WithGroupSync`` intrinsics, SPIR-V memory scope and semantics are the
- same as their counterparts in the above. They have an additional execution
- scope:
- ==================================== ======================
- HLSL Intrinsic SPIR-V Execution Scope
- ==================================== ======================
- ``AllMemoryBarrierWithGroupSync`` Workgroup
- ``DeviceMemoryBarrierWithGroupSync`` Workgroup
- ``GroupMemoryBarrierWithGroupSync`` Workgroup
- ==================================== ======================
- HLSL OO features
- ================
- A HLSL struct/class member method is translated into a normal SPIR-V function,
- whose signature has an additional first parameter for the struct/class called
- upon. Every calling site of the method is generated to pass in the object as
- the first argument.
- HLSL struct/class static member variables are translated into SPIR-V variables
- in the ``Private`` storage class.
- HLSL Methods
- ============
- This section lists how various HLSL methods are mapped.
- Buffers
- -------
- ``Buffer``
- ~~~~~~~~~~
- ``.Load()``
- +++++++++++
- Since Buffers are represented as ``OpTypeImage`` with ``Sampled`` set to 1
- (meaning to be used with a sampler), ``OpImageFetch`` is used to perform this
- operation. The return value of ``OpImageFetch`` is always a four-component
- vector; so proper additional instructions are generated to truncate the vector
- and return the desired number of elements.
- If an output unsigned integer ``status`` argument is present, ``OpImageSparseFetch``
- is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
- ``operator[]``
- ++++++++++++++
- Handled similarly as ``.Load()``.
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since Buffers are represented as ``OpTypeImage`` with dimension of ``Buffer``,
- ``OpImageQuerySize`` is used to perform this operation.
- ``RWBuffer``
- ~~~~~~~~~~~~
- ``.Load()``
- +++++++++++
- Since RWBuffers are represented as ``OpTypeImage`` with ``Sampled`` set to 2
- (meaning to be used without a sampler), ``OpImageRead`` is used to perform this
- operation. If an output unsigned integer ``status`` argument is present, ``OpImageSparseRead``
- is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
- ``operator[]``
- ++++++++++++++
- Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for
- writing, the ``OpImageWrite`` instruction is generated.
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since RWBuffers are represented as ``OpTypeImage`` with dimension of ``Buffer``,
- ``OpImageQuerySize`` is used to perform this operation.
- ``StructuredBuffer`` and ``RWStructuredBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since StructuredBuffers/RWStructuredBuffers are represented as a struct with one
- member that is a runtime array of structures, ``OpArrayLength`` is invoked on
- the runtime array in order to find the dimension.
- ``ByteAddressBuffer``
- ~~~~~~~~~~~~~~~~~~~~~
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since ByteAddressBuffers are represented as a struct with one member that is a
- runtime array of unsigned integers, ``OpArrayLength`` is invoked on the runtime array
- in order to find the number of unsigned integers. This is then multiplied by 4 to find
- the number of bytes.
- ``.Load()``, ``.Load2()``, ``.Load3()``, ``.Load4()``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++
- ByteAddressBuffers are represented as a struct with one member that is a runtime array of
- unsigned integers. The ``address`` argument passed to the function is first divided by 4
- in order to find the offset into the array (because each array element is 4 bytes). The
- SPIR-V ``OpAccessChain`` instruction is then used to access that offset, and ``OpLoad`` is
- used to load a 32-bit unsigned integer. For ``Load2``, ``Load3``, and ``Load4``, this is
- done 2, 3, and 4 times, respectively. Each time the word offset is incremented by 1 before
- performing ``OpAccessChain``. After all ``OpLoad`` operations are performed, a vector is
- constructed with all the resulting values.
- ``RWByteAddressBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since RWByteAddressBuffers are represented as a struct with one member that is a
- runtime array of unsigned integers, ``OpArrayLength`` is invoked on the runtime array
- in order to find the number of unsigned integers. This is then multiplied by 4 to find
- the number of bytes.
- ``.Load()``, ``.Load2()``, ``.Load3()``, ``.Load4()``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++
- RWByteAddressBuffers are represented as a struct with one member that is a runtime array of
- unsigned integers. The ``address`` argument passed to the function is first divided by 4
- in order to find the offset into the array (because each array element is 4 bytes). The
- SPIR-V ``OpAccessChain`` instruction is then used to access that offset, and ``OpLoad`` is
- used to load a 32-bit unsigned integer. For ``Load2``, ``Load3``, and ``Load4``, this is
- done 2, 3, and 4 times, respectively. Each time the word offset is incremented by 1 before
- performing ``OpAccessChain``. After all ``OpLoad`` operations are performed, a vector is
- constructed with all the resulting values.
- ``.Store()``, ``.Store2()``, ``.Store3()``, ``.Store4()``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- RWByteAddressBuffers are represented as a struct with one member that is a runtime array of
- unsigned integers. The ``address`` argument passed to the function is first divided by 4
- in order to find the offset into the array (because each array element is 4 bytes). The
- SPIR-V ``OpAccessChain`` instruction is then used to access that offset, and ``OpStore`` is
- used to store a 32-bit unsigned integer. For ``Store2``, ``Store3``, and ``Store4``, this is
- done 2, 3, and 4 times, respectively. Each time the word offset is incremented by 1 before
- performing ``OpAccessChain``.
- ``.Interlocked*()``
- +++++++++++++++++++
- ================================= =================================
- HLSL Intrinsic Method SPIR-V Opcode
- ================================= =================================
- ``.InterlockedAdd()`` ``OpAtomicIAdd``
- ``.InterlockedAnd()`` ``OpAtomicAnd``
- ``.InterlockedOr()`` ``OpAtomicOr``
- ``.InterlockedXor()`` ``OpAtomicXor``
- ``.InterlockedMin()`` ``OpAtomicUMin``/``OpAtomicSMin``
- ``.InterlockedMax()`` ``OpAtomicUMax``/``OpAtomicSMax``
- ``.InterlockedExchange()`` ``OpAtomicExchange``
- ``.InterlockedCompareExchange()`` ``OpAtomicCompareExchange``
- ``.InterlockedCompareStore()`` ``OpAtomicCompareExchange``
- ================================= =================================
- ``AppendStructuredBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``.Append()``
- +++++++++++++
- The associated counter number will be increased by 1 using ``OpAtomicIAdd``.
- The return value of ``OpAtomicIAdd``, which is the original count number, will
- be used as the index for storing the new element. E.g., for ``buf.Append(vec)``:
- .. code:: spirv
- %counter = OpAccessChain %_ptr_Uniform_int %counter_var_buf %uint_0
- %index = OpAtomicIAdd %uint %counter %uint_1 %uint_0 %uint_1
- %ptr = OpAccessChain %_ptr_Uniform_v4float %buf %uint_0 %index
- %val = OpLoad %v4float %vec
- OpStore %ptr %val
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since AppendStructuredBuffers are represented as a struct with one member that
- is a runtime array, ``OpArrayLength`` is invoked on the runtime array in order
- to find the number of elements. The stride is also calculated based on GLSL
- ``std430`` as explained above.
- ``ConsumeStructuredBuffer``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``.Consume()``
- ++++++++++++++
- The associated counter number will be decreased by 1 using ``OpAtomicISub``.
- The return value of ``OpAtomicISub`` minus 1, which is the new count number,
- will be used as the index for reading the new element. E.g., for
- ``buf.Consume(vec)``:
- .. code:: spirv
- %counter = OpAccessChain %_ptr_Uniform_int %counter_var_buf %uint_0
- %prev = OpAtomicISub %uint %counter %uint_1 %uint_0 %uint_1
- %index = OpISub %uint %prev %uint_1
- %ptr = OpAccessChain %_ptr_Uniform_v4float %buf %uint_0 %index
- %val = OpLoad %v4float %vec
- OpStore %ptr %val
- ``.GetDimensions()``
- ++++++++++++++++++++
- Since ConsumeStructuredBuffers are represented as a struct with one member that
- is a runtime array, ``OpArrayLength`` is invoked on the runtime array in order
- to find the number of elements. The stride is also calculated based on GLSL
- ``std430`` as explained above.
- Read-only textures
- ------------------
- Methods common to all texture types are explained in the "common texture methods"
- section. Methods unique to a specific texture type is explained in the section
- for that texture type.
- Common texture methods
- ~~~~~~~~~~~~~~~~~~~~~~
- ``.Sample(sampler, location[, offset][, clamp][, Status])``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
- The ``OpImageSampleImplicitLod`` instruction is used to translate ``.Sample()``
- since texture types are represented as ``OpTypeImage``. An ``OpSampledImage`` is
- created based on the ``sampler`` passed to the function. The resulting sampled
- image and the ``location`` passed to the function are used as arguments to
- ``OpImageSampleImplicitLod``, with the optional ``offset`` tranlated into
- addtional SPIR-V image operands ``ConstOffset`` or ``Offset`` on it. The optional
- ``clamp`` argument will be translated to the ``MinLod`` image operand.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.SampleLevel(sampler, location, lod[, offset][, Status])``
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
- The ``OpImageSampleExplicitLod`` instruction is used to translate this method.
- An ``OpSampledImage`` is created based on the ``sampler`` passed to the function.
- The resulting sampled image and the ``location`` passed to the function are used
- as arguments to ``OpImageSampleExplicitLod``. The ``lod`` passed to the function
- is attached to the instruction as an SPIR-V image operands ``Lod``. The optional
- ``offset`` is also tranlated into addtional SPIR-V image operands ``ConstOffset``
- or ``Offset`` on it.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.SampleGrad(sampler, location, ddx, ddy[, offset][, clamp][, Status])``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
- Similarly to ``.SampleLevel``, the ``ddx`` and ``ddy`` parameter are attached to
- the ``OpImageSampleExplicitLod`` instruction as an SPIR-V image operands
- ``Grad``. The optional ``clamp`` argument will be translated into the ``MinLod``
- image operand.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.SampleBias(sampler, location, bias[, offset][, clamp][, Status])``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
- The translation is similar to ``.Sample()``, with the ``bias`` parameter
- attached to the ``OpImageSampleImplicitLod`` instruction as an SPIR-V image
- operands ``Bias``.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.SampleCmp(sampler, location, comparator[, offset][, clamp][, Status])``
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
- The translation is similar to ``.Sample()``, but the
- ``OpImageSampleDrefImplicitLod`` instruction are used.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleDrefImplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.SampleCmpLevelZero(sampler, location, comparator[, offset][, Status])``
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
- The translation is similar to ``.Sample()``, but the
- ``OpImageSampleDrefExplicitLod`` instruction are used, with the additional
- ``Lod`` image operands set to 0.0.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseSampleDrefExplicitLod`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.Gather()``
- +++++++++++++
- Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
- ``TextureCubeArray``.
- The translation is similar to ``.Sample()``, but the ``OpImageGather``
- instruction is used, with component setting to 0.
- If an output unsigned integer ``status`` argument is present,
- ``OpImageSparseGather`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.GatherRed()``, ``.GatherGreen()``, ``.GatherBlue()``, ``.GatherAlpha()``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
- ``TextureCubeArray``.
- The ``OpImageGather`` instruction is used to translate these functions, with
- component setting to 0, 1, 2, and 3 respectively.
- There are a few overloads for these functions:
- - For those overloads taking 4 offset parameters, those offset parameters will
- be conveyed as an additional ``ConstOffsets`` image operands to the
- instruction if those offset parameters are all constants. Otherwise,
- 4 separate ``OpImageGather`` instructions will be emitted to get each texel
- from each offset, using the ``Offset`` image operands.
- - For those overloads with the ``status`` parameter, ``OpImageSparseGather``
- is used instead, and the resulting SPIR-V ``Residency Code`` will be
- written to ``status``.
- ``.GatherCmp()``
- ++++++++++++++++
- Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
- ``TextureCubeArray``.
- The translation is similar to ``.Sample()``, but the ``OpImageDrefGather``
- instruction is used.
- For the overload with the output unsigned integer ``status`` argument,
- ``OpImageSparseDrefGather`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``.GatherCmpRed()``
- +++++++++++++++++++
- Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
- ``TextureCubeArray``.
- The translation is the same as ``.GatherCmp()``.
- ``.Load(location[, sampleIndex][, offset])``
- ++++++++++++++++++++++++++++++++++++++++++++
- The ``OpImageFetch`` instruction is used for translation because texture types
- are represented as ``OpTypeImage``. The last element in the ``location``
- parameter will be used as arguments to the ``Lod`` SPIR-V image operand attached
- to the ``OpImageFetch`` instruction, and the rest are used as the coordinate
- argument to the instruction. ``offset`` is handled similarly to ``.Sample()``.
- The return value of ``OpImageFetch`` is always a four-component vector; so
- proper additional instructions are generated to truncate the vector and return
- the desired number of elements.
- For the overload with the output unsigned integer ``status`` argument,
- ``OpImageSparseFetch`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``operator[]``
- ++++++++++++++
- Handled similarly as ``.Load()``.
- ``.mips[lod][position]``
- ++++++++++++++++++++++++
- Not available to ``TextureCube``, ``TextureCubeArray``, ``Texture2DMS``, and
- ``Texture2DMSArray``.
- This method is translated into the ``OpImageFetch`` instruction. The ``lod``
- parameter is attached to the instruction as the parameter to the ``Lod`` SPIR-V
- image operands. The ``position`` parameter are used as the coordinate to the
- instruction directly.
- ``.CalculateLevelOfDetail()`` and ``.CalculateLevelOfDetailUnclamped()``
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
- Since texture types are represented as ``OpTypeImage``, the ``OpImageQueryLod``
- instruction is used for translation. An ``OpSampledImage`` is created based on
- the ``SamplerState`` passed to the function. The resulting sampled image and
- the coordinate passed to the function are used to invoke ``OpImageQueryLod``.
- The result of ``OpImageQueryLod`` is a ``float2``. The first element contains
- the mipmap array layer. The second element contains the unclamped level of detail.
- ``Texture1D``
- ~~~~~~~~~~~~~
- ``.GetDimensions(width)`` or ``.GetDimensions(MipLevel, width, NumLevels)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture1D is represented as ``OpTypeImage``, the ``OpImageQuerySizeLod`` instruction
- is used for translation. If a ``MipLevel`` argument is passed to ``GetDimensions``, it will
- be used as the ``Lod`` parameter of the query instruction. Otherwise, ``Lod`` of ``0`` be used.
- ``Texture1DArray``
- ~~~~~~~~~~~~~~~~~~
- ``.GetDimensions(width, elements)`` or ``.GetDimensions(MipLevel, width, elements, NumLevels)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture1DArray is represented as ``OpTypeImage``, the ``OpImageQuerySizeLod`` instruction
- is used for translation. If a ``MipLevel`` argument is present, it will be used as the
- ``Lod`` parameter of the query instruction. Otherwise, ``Lod`` of ``0`` be used.
- ``Texture2D``
- ~~~~~~~~~~~~~
- ``.GetDimensions(width, height)`` or ``.GetDimensions(MipLevel, width, height, NumLevels)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture2D is represented as ``OpTypeImage``, the ``OpImageQuerySizeLod`` instruction
- is used for translation. If a ``MipLevel`` argument is present, it will be used as the
- ``Lod`` parameter of the query instruction. Otherwise, ``Lod`` of ``0`` be used.
- ``Texture2DArray``
- ~~~~~~~~~~~~~~~~~~
- ``.GetDimensions(width, height, elements)`` or ``.GetDimensions(MipLevel, width, height, elements, NumLevels)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture2DArray is represented as ``OpTypeImage``, the ``OpImageQuerySizeLod`` instruction
- is used for translation. If a ``MipLevel`` argument is present, it will be used as the
- ``Lod`` parameter of the query instruction. Otherwise, ``Lod`` of ``0`` be used.
- ``Texture3D``
- ~~~~~~~~~~~~~
- ``.GetDimensions(width, height, depth)`` or ``.GetDimensions(MipLevel, width, height, depth, NumLevels)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture3D is represented as ``OpTypeImage``, the ``OpImageQuerySizeLod`` instruction
- is used for translation. If a ``MipLevel`` argument is present, it will be used as the
- ``Lod`` parameter of the query instruction. Otherwise, ``Lod`` of ``0`` be used.
- ``Texture2DMS``
- ~~~~~~~~~~~~~~~
- ``.sample[sample][position]``
- +++++++++++++++++++++++++++++
- This method is translated into the ``OpImageFetch`` instruction. The ``sample``
- parameter is attached to the instruction as the parameter to the ``Sample``
- SPIR-V image operands. The ``position`` parameter are used as the coordinate to
- the instruction directly.
- ``.GetDimensions(width, height, numSamples)``
- +++++++++++++++++++++++++++++++++++++++++++++
- Since Texture2DMS is represented as ``OpTypeImage`` with ``MS`` of ``1``, the ``OpImageQuerySize`` instruction
- is used to get the width and the height. Furthermore, ``OpImageQuerySamples`` is used to get the numSamples.
- ``.GetSamplePosition(index)``
- +++++++++++++++++++++++++++++
- There are no direct mapping SPIR-V instructions for this method. Right now, it
- is translated into the SPIR-V code for the following HLSL source code:
- .. code:: hlsl
- // count is the number of samples in the Texture2DMS(Array)
- // index is the index of the sample we are trying to get the position
- static const float2 pos2[] = {
- { 4.0/16.0, 4.0/16.0 }, {-4.0/16.0, -4.0/16.0 },
- };
- static const float2 pos4[] = {
- {-2.0/16.0, -6.0/16.0 }, { 6.0/16.0, -2.0/16.0 }, {-6.0/16.0, 2.0/16.0 }, { 2.0/16.0, 6.0/16.0 },
- };
- static const float2 pos8[] = {
- { 1.0/16.0, -3.0/16.0 }, {-1.0/16.0, 3.0/16.0 }, { 5.0/16.0, 1.0/16.0 }, {-3.0/16.0, -5.0/16.0 },
- {-5.0/16.0, 5.0/16.0 }, {-7.0/16.0, -1.0/16.0 }, { 3.0/16.0, 7.0/16.0 }, { 7.0/16.0, -7.0/16.0 },
- };
- static const float2 pos16[] = {
- { 1.0/16.0, 1.0/16.0 }, {-1.0/16.0, -3.0/16.0 }, {-3.0/16.0, 2.0/16.0 }, { 4.0/16.0, -1.0/16.0 },
- {-5.0/16.0, -2.0/16.0 }, { 2.0/16.0, 5.0/16.0 }, { 5.0/16.0, 3.0/16.0 }, { 3.0/16.0, -5.0/16.0 },
- {-2.0/16.0, 6.0/16.0 }, { 0.0/16.0, -7.0/16.0 }, {-4.0/16.0, -6.0/16.0 }, {-6.0/16.0, 4.0/16.0 },
- {-8.0/16.0, 0.0/16.0 }, { 7.0/16.0, -4.0/16.0 }, { 6.0/16.0, 7.0/16.0 }, {-7.0/16.0, -8.0/16.0 },
- };
- float2 position = float2(0.0f, 0.0f);
- if (count == 2) {
- position = pos2[index];
- } else if (count == 4) {
- position = pos4[index];
- } else if (count == 8) {
- position = pos8[index];
- } else if (count == 16) {
- position = pos16[index];
- }
- From the above, it's clear that the current implementation only supports standard
- sample settings, i.e., with 1, 2, 4, 8, or 16 samples. For other cases, the
- implementation will just return `(float2)0`.
- ``Texture2DMSArray``
- ~~~~~~~~~~~~~~~~~~~~
- ``.sample[sample][position]``
- +++++++++++++++++++++++++++++
- This method is translated into the ``OpImageFetch`` instruction. The ``sample``
- parameter is attached to the instruction as the parameter to the ``Sample``
- SPIR-V image operands. The ``position`` parameter are used as the coordinate to
- the instruction directly.
- ``.GetDimensions(width, height, elements, numSamples)``
- +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Since Texture2DMS is represented as ``OpTypeImage`` with ``MS`` of ``1``, the ``OpImageQuerySize`` instruction
- is used to get the width, the height, and the elements. Furthermore, ``OpImageQuerySamples`` is used to get the numSamples.
- ``.GetSamplePosition(index)``
- +++++++++++++++++++++++++++++
- Similar to Texture2D.
- ``TextureCube``
- ~~~~~~~~~~~~~~~
- ``TextureCubeArray``
- ~~~~~~~~~~~~~~~~~~~~
- Read-write textures
- -------------------
- Methods common to all texture types are explained in the "common texture methods"
- section. Methods unique to a specific texture type is explained in the section
- for that texture type.
- Common texture methods
- ~~~~~~~~~~~~~~~~~~~~~~
- ``.Load()``
- +++++++++++
- Since read-write texture types are represented as ``OpTypeImage`` with
- ``Sampled`` set to 2 (meaning to be used without a sampler), ``OpImageRead`` is
- used to perform this operation.
- For the overload with the output unsigned integer ``status`` argument,
- ``OpImageSparseRead`` is used instead. The resulting SPIR-V
- ``Residency Code`` will be written to ``status``.
- ``operator[]``
- ++++++++++++++
- Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for
- writing, the ``OpImageWrite`` instruction is generated.
- ``RWTexture1D``
- ~~~~~~~~~~~~~~~
- ``.GetDimensions(width)``
- +++++++++++++++++++++++++
- The ``OpImageQuerySize`` instruction is used to find the width.
- ``RWTexture1DArray``
- ~~~~~~~~~~~~~~~~~~~~
- ``.GetDimensions(width, elements)``
- +++++++++++++++++++++++++++++++++++
- The ``OpImageQuerySize`` instruction is used to get a uint2. The first element
- is the width, and the second is the elements.
- ``RWTexture2D``
- ~~~~~~~~~~~~~~~
- ``.GetDimensions(width, height)``
- +++++++++++++++++++++++++++++++++
- The ``OpImageQuerySize`` instruction is used to get a uint2. The first element is the width, and the second
- element is the height.
- ``RWTexture2DArray``
- ~~~~~~~~~~~~~~~~~~~~
- ``.GetDimensions(width, height, elements)``
- +++++++++++++++++++++++++++++++++++++++++++
- The ``OpImageQuerySize`` instruction is used to get a uint3. The first element is the width, the second
- element is the height, and the third is the elements.
- ``RWTexture3D``
- ~~~~~~~~~~~~~~~
- ``.GetDimensions(width, height, depth)``
- ++++++++++++++++++++++++++++++++++++++++
- The ``OpImageQuerySize`` instruction is used to get a uint3. The first element is the width, the second
- element is the height, and the third element is the depth.
- HLSL Shader Stages
- ==================
- Hull Shaders
- ------------
- Hull shaders corresponds to Tessellation Control Shaders (TCS) in Vulkan.
- This section describes how Hull shaders are translated to SPIR-V for Vulkan.
- Hull Entry Point Attributes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The following HLSL attributes are attached to the main entry point of hull shaders
- and are translated to SPIR-V execution modes according to the table below:
- .. table:: Mapping from HLSL attribute to SPIR-V execution mode
- +-------------------------+---------------------+--------------------------+
- | HLSL Attribute | value | SPIR-V Execution Mode |
- +=========================+=====================+==========================+
- | | ``quad`` | ``Quads`` |
- | +---------------------+--------------------------+
- | ``domain`` | ``tri`` | ``Triangles`` |
- | +---------------------+--------------------------+
- | | ``isoline`` | ``Isoline`` |
- +-------------------------+---------------------+--------------------------+
- | | ``integer`` | ``SpacingEqual`` |
- | +---------------------+--------------------------+
- | | ``fractional_even`` | ``SpacingFractionalEven``|
- | ``partitioning`` +---------------------+--------------------------+
- | | ``fractional_odd`` | ``SpacingFractionalOdd`` |
- | +---------------------+--------------------------+
- | | ``pow2`` | N/A |
- +-------------------------+---------------------+--------------------------+
- | | ``point`` | ``PointMode`` |
- | +---------------------+--------------------------+
- | | ``line`` | N/A |
- | ``outputtopology`` +---------------------+--------------------------+
- | | ``triangle_cw`` | ``VertexOrderCw`` |
- | +---------------------+--------------------------+
- | | ``triangle_ccw`` | ``VertexOrderCcw`` |
- +-------------------------+---------------------+--------------------------+
- |``outputcontrolpoints`` | ``n`` | ``OutputVertices n`` |
- +-------------------------+---------------------+--------------------------+
- The ``patchconstfunc`` attribute does not have a direct equivalent in SPIR-V.
- It specifies the name of the Patch Constant Function. This function is run only
- once per patch. This is further described below.
- InputPatch and OutputPatch
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Both of ``InputPatch<T, N>`` and ``OutputPatch<T, N>`` are translated to an array
- of constant size ``N`` where each element is of type ``T``.
- InputPatch can be passed to the Hull shader main entry function as well as the
- patch constant function. This would include information about each of the ``N``
- vertices that are input to the tessellation control shader.
- OutputPatch is an array containing ``N`` elements (where ``N`` is the number of
- output vertices). Each element of the array contains information about an
- output vertex. OutputPatch may also be passed to the patch constant function.
- The SPIR-V ``InvocationID`` (``SV_OutputControlPointID`` in HLSL) is used to index
- into the InputPatch and OutputPatch arrays to read/write information for the given
- vertex.
- The hull main entry function in HLSL returns only one value (say, of type ``T``), but
- that function is in fact executed once for each control point. The Vulkan spec requires that
- "Tessellation control shader per-vertex output variables and blocks, and tessellation control,
- tessellation evaluation, and geometry shader per-vertex input variables and blocks are required
- to be declared as arrays, with each element representing input or output values for a single vertex
- of a multi-vertex primitive". Therefore, we need to create a stage output variable that is an array
- with elements of type ``T``. The number of elements of the array is equal to the number of
- output control points. Each final output control point is written into the corresponding element in
- the array using SV_OutputControlPointID as the index.
- Patch Constant Function
- ~~~~~~~~~~~~~~~~~~~~~~~
- As mentioned above, the patch constant function is to be invoked only once per patch.
- As a result, in the SPIR-V module, the `entry function wrapper`_ will first invoke the
- main entry function, and then use an ``OpControlBarrier`` to wait for all vertex
- processing to finish. After the barrier, *only* the first thread (with InvocationID of 0)
- will invoke the patch constant function.
- The information resulting from the patch constant function will also be returned
- as stage output variables. The output struct of the patch constant function must include
- ``SV_TessFactor`` and ``SV_InsideTessFactor`` fields which will translate to
- ``TessLevelOuter`` and ``TessLevelInner`` builtin variables, respectively. And the rest
- will be flattened and translated into normal stage output variables, one for each field.
- Geometry Shaders
- ----------------
- This section describes how geometry shaders are translated to SPIR-V for Vulkan.
- Geometry Shader Entry Point Attributes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The following HLSL attribute is attached to the main entry point of geometry shaders
- and is translated to SPIR-V execution mode as follows:
- .. table:: Mapping from geometry shader HLSL attribute to SPIR-V execution mode
- +-------------------------+---------------------+--------------------------+
- | HLSL Attribute | value | SPIR-V Execution Mode |
- +=========================+=====================+==========================+
- |``maxvertexcount`` | ``n`` | ``OutputVertices n`` |
- +-------------------------+---------------------+--------------------------+
- |``instance`` | ``n`` | ``Invocations n`` |
- +-------------------------+---------------------+--------------------------+
- Translation for Primitive Types
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Geometry shader vertex inputs may be qualified with primitive types. Only one primitive type
- is allowed to be used in a given geometry shader. The following table shows the SPIR-V execution
- mode that is used in order to represent the given primitive type.
- .. table:: Mapping from geometry shader primitive type to SPIR-V execution mode
- +---------------------+-----------------------------+
- | HLSL Primitive Type | SPIR-V Execution Mode |
- +=====================+=============================+
- |``point`` | ``InputPoints`` |
- +---------------------+-----------------------------+
- |``line`` | ``InputLines`` |
- +---------------------+-----------------------------+
- |``triangle`` | ``Triangles`` |
- +---------------------+-----------------------------+
- |``lineadj`` | ``InputLinesAdjacency`` |
- +---------------------+-----------------------------+
- |``triangleadj`` | ``InputTrianglesAdjacency`` |
- +---------------------+-----------------------------+
- Translation of Output Stream Types
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Supported output stream types in geometry shaders are: ``PointStream<T>``,
- ``LineStream<T>``, and ``TriangleStream<T>``. These types are translated as the underlying
- type ``T``, which is recursively flattened into stand-alone variables for each field.
- Furthermore, output stream objects passed to geometry shader entry points are
- required to be annotated with ``inout``, but the generated SPIR-V only contains
- stage output variables for them.
- The following table shows the SPIR-V execution mode that is used in order to represent the
- given output stream.
- .. table:: Mapping from geometry shader output stream type to SPIR-V execution mode
- +---------------------+-----------------------------+
- | HLSL Output Stream | SPIR-V Execution Mode |
- +=====================+=============================+
- |``PointStream`` | ``OutputPoints`` |
- +---------------------+-----------------------------+
- |``LineStream`` | ``OutputLineStrip`` |
- +---------------------+-----------------------------+
- |``TriangleStream`` | ``OutputTriangleStrip`` |
- +---------------------+-----------------------------+
- In other shader stages, stage output variables are only written in the `entry
- function wrapper`_ after calling the source code entry function. However,
- geometry shaders can output as many vertices as they wish, by calling the
- ``.Append()`` method on the output stream object. Therefore, it is incorrect to
- have only one flush in the entry function wrapper like other stages. Instead,
- each time a ``*Stream<T>::Append()`` is encountered, all stage output variables
- behind ``T`` will be flushed before SPIR-V ``OpEmitVertex`` instruction is
- generated. ``.RestartStrip()`` method calls will be translated into the SPIR-V
- ``OpEndPrimitive`` instruction.
- Raytracing Shader Stages
- ------------------------
- DirectX Raytracing adds six new shader stages for raytracing namely ray generation, intersection, closest-hit,
- any-hit, miss and callable.
- | Refer to following pages for details:
- | https://docs.microsoft.com/en-us/windows/desktop/direct3d12/direct3d-12-raytracing
- | https://docs.microsoft.com/en-us/windows/desktop/direct3d12/direct3d-12-raytracing-hlsl-reference
- Flow chart for various stages in a raytracing pipeline is as follows:
- ::
- +---------------------+
- | Ray generation |
- +---------------------+
- |
- TraceRay() | +--------------+
- | _ _ _ _ _ _ _ _ | Any Hit |
- | | +--------------+
- V V ^
- +---------------------+ |
- | Acceleration | +--------------+
- | Structure | | Intersection |
- | Traversal | +--------------+
- +---------------------+ ^
- | | |
- | |_ _ _ _ _ _ _ _ _ _ _|
- |
- |
- V
- +--------------------+ +-------------+
- | Is Hit ? | | Callable |
- +--------------------+ +-------------+
- | |
- Yes | | No
- V V
- +---------+ +------+
- | Closest | | Miss |
- | Hit | | |
- +---------+ +------+
- | *Note : DXC does not add special shader profiles for raytracing under -T option.*
- | *All raytracing shaders must be compiled as library using lib_6_3/lib_6_4 profile option.*
- | *Note : DXC now targets SPV_KHR_ray_tracing extension by default.*
- | *This extension is provisional and subject to change*.
- | *To compile for NV extension use -fspv-extension=SPV_NV_ray_tracing.*
- Ray Generation Stage
- ~~~~~~~~~~~~~~~~~~~~
- | Ray generation shaders start ray tracing work and work on a compute-like 3D grid of threads.
- | Entry functions of this stage type are annotated with **[shader("raygeneration")]** in HLSL source.
- | Such entry functions must return void and do not accept any arguments.
- | For example:
- .. code:: hlsl
- RaytracingAccelerationStructure rs;
- struct Payload
- {
- float4 color;
- };
- [shader("raygeneration")]
- void main() {
- Payload myPayload = { float4(0.0f,0.0f,0.0f,0.0f) };
- RayDesc rayDesc;
- rayDesc.Origin = float3(0.0f, 0.0f, 0.0f);
- rayDesc.Direction = float3(0.0f, 0.0f, -1.0f);
- rayDesc.TMin = 0.0f;
- rayDesc.TMax = 1000.0f;
- TraceRay(rs, 0x0, 0xff, 0, 1, 0, rayDesc, myPayload);
- }
- Intersection Stage
- ~~~~~~~~~~~~~~~~~~
- | Intersection shader stage is used to implement arbitrary ray-primitive intersections such spheres or axis-aligned bounding boxes (AABB). Triangle primitives do not require a custom intersection shader.
- | Entry functions of this stage are annotated with **[shader("intersection")]** in HLSL source.
- | Such entry functions must return void and do not accept any arguments.
- | For example:
- .. code:: hlsl
- struct Attribute
- {
- float2 bary;
- };
- [shader("intersection")]
- void main() {
- Attribute myHitAttribute = { float2(0.0f,0.0f) };
- ReportHit(0.0f, 0U, myHitAttribute);
- }
- Closest-Hit Stage
- ~~~~~~~~~~~~~~~~~
- | Hit shaders are invoked when a ray primitive intersection is found. A closest-hit shader
- | is invoked for the closest intersection point along a ray and can be used to compute interactions
- | at intersection point or spawn secondary rays.
- | Entry functions of this stage are annotated with **[shader("closesthit")]** in HLSL source.
- | Such entry functions must return void and accept exactly two arguments. First argument must be an inout
- | variable of user defined structure type and second argument must be a in variable of user defined structure type.
- | For example:
- .. code:: hlsl
- struct Attribute
- {
- float2 bary;
- };
- struct Payload {
- float4 color;
- };
- [shader("closesthit")]
- void main(inout Payload a, in Attribute b) {
- a.color = float4(0.0f,1.0f,0.0f,0.0f);
- }
- Any-Hit Stage
- ~~~~~~~~~~~~~~~~~
- | Hit shaders are invoked when a ray primitive intersection is found. An any-hit shader
- | is invoked for all intersections along a ray with a primitive.
- | Entry functions of this stage are annotated with **[shader("anyhit")]** in HLSL source.
- | Such entry functions must return void and accept exactly two arguments. First argument must be an inout
- | variable of user defined structure type and second argument must be an in variable of user defined structure type.
- | For example:
- .. code:: hlsl
- struct Attribute
- {
- float2 bary;
- };
- struct Payload {
- float4 color;
- };
- [shader("anyhit")]
- void main(inout Payload a, in Attribute b) {
- a.color = float4(0.0f,1.0f,0.0f,0.0f);
- }
- Miss Stage
- ~~~~~~~~~~
- | Miss shaders are invoked when no intersection is found.
- | Entry functions of this stage are annotated with **[shader("miss")]** in HLSL source.
- | Such entry functions return void and accept exactly one argument. First argument must be an inout variable of user defined structure type.
- | For example:
- .. code:: hlsl
- struct Payload {
- float4 color;
- };
- [shader("miss")]
- void main(inout Payload a) {
- a.color = float4(0.0f,1.0f,0.0f,0.0f);
- }
- Callable Stage
- ~~~~~~~~~~~~~~
- | Callables are generic function calls which can be invoked from either raygeneration, closest-hit,
- | miss or callable shader stages.
- | Entry functions of this stage are annotated with **[shader("callable")]** in HLSL source.
- | Such entry functions must return void and accept exactly one argument. First argument must be an inout
- | variable of user defined structure type.
- | For example:
- .. code:: hlsl
- struct CallData {
- float4 data;
- };
- [shader("callable")]
- void main(inout CallData a) {
- a.color = float4(0.0f,1.0f,0.0f,0.0f);
- }
- Mesh and Amplification Shaders
- ------------------------------
- | DirectX adds 2 new shader stages for using MeshShading pipeline namely Mesh and Amplification.
- | Amplification shaders corresponds to Task Shaders in Vulkan.
- |
- | Refer to following HLSL and SPIR-V specs for details:
- | https://docs.microsoft.com/<TBD>
- | https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/NV/SPV_NV_mesh_shader.asciidoc
- |
- | This section describes how Mesh and Amplification shaders are translated to SPIR-V for Vulkan.
- Entry Point Attributes
- ~~~~~~~~~~~~~~~~~~~~~~
- The following HLSL attributes are attached to the main entry point of Mesh and/or Amplification
- shaders and are translated to SPIR-V execution modes according to the table below:
- .. table:: Mapping from HLSL attribute to SPIR-V execution mode
- +-------------------+--------------------+-------------------------+
- | HLSL Attribute | Value | SPIR-V Execution Mode |
- +===================+====================+=========================+
- |``outputtopology`` | ``point`` | ``OutputPoints`` |
- | +--------------------+-------------------------+
- |``(Mesh shader)`` | ``line`` | ``OutputLinesNV`` |
- | +--------------------+-------------------------+
- | | ``triangle`` | ``OutputTrianglesNV`` |
- +-------------------+--------------------+-------------------------+
- | ``numthreads`` | ``X, Y, Z`` | ``LocalSize X, Y, Z`` |
- | | | |
- | | ``(X*Y*Z <= 128)`` | |
- +-------------------+--------------------+-------------------------+
- Intrinsics
- ~~~~~~~~~~
- The following HLSL intrinsics are used in Mesh or Amplification shaders
- and are translated to SPIR-V intrinsics according to the table below:
- .. table:: Mapping from HLSL intrinsics to SPIR-V intrinsics
- +---------------------------+--------------------+-----------------------------------------+
- | HLSL Intrinsic | Parameters | SPIR-V Intrinsic |
- +===========================+====================+=========================================+
- | ``SetMeshOutputCounts`` | ``numVertices`` | ``PrimitiveCountNV numPrimitives`` |
- | | | |
- | ``(Mesh shader)`` | ``numPrimitives`` | |
- +---------------------------+--------------------+-----------------------------------------+
- | ``DispatchMesh`` | ``ThreadX`` | ``OpControlBarrier`` |
- | | | |
- | ``(Amplification shader)``| ``ThreadY`` | ``TaskCountNV ThreadX*ThreadY*ThreadZ`` |
- | | | |
- | | ``ThreadZ`` | |
- | | | |
- | | ``MeshPayload`` | |
- +---------------------------+--------------------+-----------------------------------------+
- | Note : For ``DispatchMesh`` intrinsic, we also emit ``MeshPayload`` as output block with ``PerTaskNV`` decoration
- Mesh Interface Variables
- ~~~~~~~~~~~~~~~~~~~~~~~~
- | Interface variables are defined for Mesh shaders using HLSL modifiers.
- | Following table gives high level overview of the mapping:
- |
- .. table:: Mapping from HLSL modifiers to SPIR-V definitions
- +-----------------+-------------------------------------------------------------------------+
- | HLSL modifier | SPIR-V definition |
- +=================+=========================================================================+
- | ``indices`` | Maps to SPIR-V intrinsic ``PrimitiveIndicesNV`` |
- | | |
- | | Defines SPIR-V Execution Mode ``OutputPrimitivesNV <array-size>`` |
- +-----------------+-------------------------------------------------------------------------+
- | ``vertices`` | Maps to per-vertex out attributes |
- | | |
- | | Defines existing SPIR-V Execution Mode ``OutputVertices <array-size>`` |
- +-----------------+-------------------------------------------------------------------------+
- | ``primitives`` | Maps to per-primitive out attributes with ``PerPrimitiveNV`` decoration |
- +-----------------+-------------------------------------------------------------------------+
- | ``payload`` | Maps to per-task in attributes with ``PerTaskNV`` decoration |
- +-----------------+-------------------------------------------------------------------------+
- Raytracing in Vulkan and SPIRV
- ==============================
- | SPIR-V codegen is currently supported for NVIDIA platforms via SPV_NV_ray_tracing extension or
- | on other platforms via provisional cross vendor SPV_KHR_ray_tracing extension.
- | SPIR-V specification for reference:
- | https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/NV/SPV_NV_ray_tracing.asciidoc
- | https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/KHR/SPV_KHR_ray_tracing.asciidoc
- | Vulkan ray tracing samples:
- | https://developer.nvidia.com/rtx/raytracing/vkray
- Raytracing Mapping to SPIR-V
- ----------------------------
- Intrinsics
- ~~~~~~~~~~
- | Following table provides mapping for system value intrinsics along with supported shader stages.
- ============================ =============================== ====== ============ =========== ======= ======== ========
- HLSL SPIR-V HLSL Shader Stage
- ---------------------------- ------------------------------- ---------------------------------------------------------
- System Value Intrinsic Builtin Raygen Intersection Closest Hit Any Hit Miss Callable
- ============================ =============================== ====== ============ =========== ======= ======== ========
- ``DispatchRaysIndex()`` ``LaunchId{NV/KHR}`` ✓ ✓ ✓ ✓ ✓ ✓
- ``DispatchRaysDimensions()`` ``LaunchSize{NV/KHR}`` ✓ ✓ ✓ ✓ ✓ ✓
- ``WorldRayOrigin()`` ``WorldRayOrigin{NV/KHR}`` ✓ ✓ ✓ ✓
- ``WorldRayDirection()`` ``WorldRayDirection{NV/KHR}`` ✓ ✓ ✓ ✓
- ``RayTMin()`` ``RayTmin{NV/KHR}`` ✓ ✓ ✓ ✓
- ``RayTCurrent()`` ``HitT{NV/KHR}`` ✓ ✓ ✓ ✓
- ``RayFlags()`` ``IncomingRayFlags{NV/KHR}`` ✓ ✓ ✓ ✓
- ``InstanceIndex()`` ``InstanceId`` ✓ ✓ ✓
- ``GeometryIndex()`` ``RayGeometryIndexKHR`` ✓ ✓ ✓
- ``InstanceID()`` ``InstanceCustomIndex{NV/KHR}`` ✓ ✓ ✓
- ``PrimitiveIndex()`` ``PrimitiveId`` ✓ ✓ ✓
- ``ObjectRayOrigin()`` ``ObjectRayOrigin{NV/KHR}`` ✓ ✓ ✓
- ``ObjectRayDirection()`` ``ObjectRayDirection{NV/KHR}`` ✓ ✓ ✓
- ``ObjectToWorld3x4()`` ``ObjectToWorld{NV/KHR}`` ✓ ✓ ✓
- ``ObjectToWorld4x3()`` ``ObjectToWorld{NV/KHR}`` ✓ ✓ ✓
- ``WorldToObject3x4()`` ``WorldToObject{NV/KHR}`` ✓ ✓ ✓
- ``WorldToObject4x3()`` ``WorldToObject{NV/KHR}`` ✓ ✓ ✓
- ``HitKind()`` ``HitKind{NV/KHR}`` ✓ ✓ ✓
- ============================ =============================== ====== ============ =========== ======= ======== ========
- | *There is no separate builtin for transposed matrices ObjectToWorld3x4 and WorldToObject3x4 in SPIR-V hence we internally transpose during translation*
- | *GeometryIndex() is only supported under SPV_KHR_ray_tracing extension.*
- | Following table provides mapping for other intrinsics along with supported shader stages.
- =========================== ================================= ====== ============ =========== ======= ===== ========
- HLSL SPIR-V HLSL Shader Stage
- --------------------------- --------------------------------- ------------------------------------------------------
- Intrinsic Opcode Raygen Intersection Closest Hit Any Hit Miss Callable
- =========================== ================================= ====== ============ =========== ======= ===== ========
- ``TraceRay`` ``OpTrace{NV/KHR}`` ✓ ✓ ✓
- ``ReportHit`` ``OpReportIntersection{NV/KHR}`` ✓ ✓
- ``IgnoreHit`` ``OpIgnoreIntersection{NV/KHR}`` ✓ ✓
- ``AcceptHitAndEndSearch`` ``OpTerminateRay{NV/KHR}`` ✓ ✓
- ``CallShader`` ``OpExecuteCallable{NV/KHR}`` ✓ ✓ ✓ ✓
- =========================== ================================= ====== ============ =========== ======= ===== ========
- Resource Types
- ~~~~~~~~~~~~~~
- | Following table provides mapping for new resource types supported in all raytracing shaders.
- =================================== =======================================
- HLSL Type SPIR-V Opcode
- ----------------------------------- ---------------------------------------
- ``RaytracingAccelerationStructure`` ``OpTypeAccelerationStructure{NV/KHR}``
- =================================== =======================================
- Interface Variables
- ~~~~~~~~~~~~~~~~~~~
- | Interface variables are created for various ray tracing storage classes based on intrinsic/shader stage
- | Following table gives high level overview of the mapping.
- ================================= ===========================================================
- SPIR-V Storage Class Created For
- --------------------------------- -----------------------------------------------------------
- ``RayPayload{NV/KHR}`` Last argument to TraceRay
- ``IncomingRayPayload{NV/KHR}`` First argument of entry for AnyHit/ClosestHit & Miss stage
- ``HitAttribute{NV/KHR}`` Last argument to ReportHit
- ``CallableData{NV/KHR}`` Last argument to CallShader
- ``IncomingCallableData{NV/KHR}`` First argument of entry for Callable stage
- ================================= ===========================================================
- RayQuery
- --------
- Ray Query is subfeature of the DirectX ray tracing and belongs to the DirectX ray tracing spec 1.1 (DXR 1.1).
- DirectX add RayQuery object type and its member TraceRayInline() to do the TraceRay() that doesn't
- use any seperate ray-tracing shader stages.
- Shaders can instantiate RayQuery objects as local variables, the RayQuery object acts as a state
- machine for ray query. The shader interacts with the RayQuery object's methods to advance the
- query through an acceleration structure and query traversal information
- Refer to following pages for details:
- https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html
- A flow chart for a simple ray query process
- ::
- +------------------------------+
- | RayQuery<RAY_FLAG_NONE> q |
- +------------------------------+
- |
- V
- +------------------------------+
- | q.TraceRayInline() |
- +------------------------------+
- | — — — — — — — — — — — — —
- | | |
- | | +------------------------+
- | | | Your intersection code |
- | | +------------------------+
- | | ^
- V V |
- +------------------------------+ +---------------------+
- | q.Proceed() // AS traversal | | q.CandidateType() |
- +------------------------------+ +---------------------+
- | | ^
- No | | Yes |
- | |_ _ _ _ _ _ _ _ _ _ _ _|
- V
- +------------------------------+
- | q.CommittedStatus() |
- +------------------------------+
- |
- V
- +----------------------------------+
- | Your Intersection/shader code |
- +----------------------------------+
- Example:
- .. code:: hlsl
- void main() {
- RayQuery<RAY_FLAG_CULL_NON_OPAQUE | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> q;
- q.TraceRayInline(myAccelerationStructure, 0 , 0xff, myRay);
- // Proceed() is AccelerationStructure traversal loop take places
- while(q.Proceed()) {
- switch(q.CandidateType()) {
- // retrieve intersection information/Do the shadering
- }
- }
- // AccelerationStructure traversal end
- // Get the Committed status
- switch(q.CommittedStatus()) {
- // retrieve intersection information/ Do the shadering
- }
- }
- Ray Query in SPIRV
- ~~~~~~~~~~~~~~~~~~
- RayQuery SPIR-V codegen is currently supported via SPV_KHR_ray_query extension
- SPIR-V specification for reference:
- https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/KHR/SPV_KHR_ray_query.asciidoc
- Object Type
- ~~~~~~~~~~~
- RayQuery<RAY_FLAGS>
- RayQuery represents the state of an inline ray tracing call into an acceleration structure.
- ============ ================================
- HLSL Type SPIR-V Opcode
- ------------ --------------------------------
- ``RayQuery`` ``OpTypeRayQueryKHR``
- ============ ================================
- RayQuery Mapping to SPIR-V
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- +---------------------------------------------------+-------------------------------------------------------------------------+
- | HLSL RayQuery member Intrinsic | SPIR-V Opcode |
- +===================================================+=========================================================================+
- |``.Abort`` | ``OpRayQueryTerminateKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateType`` | ``OpRayQueryGetIntersectionTypeKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateProceduralPrimitiveNonOpaque`` | ``OpRayQueryGetIntersectionCandidateAABBOpaqueKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateInstanceIndex`` | ``OpRayQueryGetIntersectionInstanceIdKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateInstanceID`` | ``OpRayQueryGetIntersectionInstanceCustomIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- | ``.CandidateInstanceContributionToHitGroupIndex`` | ``OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateGeometryIndex`` | ``OpRayQueryGetIntersectionGeometryIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidatePrimitiveIndex`` | ``OpRayQueryGetIntersectionPrimitiveIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateObjectRayOrigin`` | ``OpRayQueryGetIntersectionObjectRayOriginKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateObjectRayDirection`` | ``OpRayQueryGetIntersectionObjectRayDirectionKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateObjectToWorld3x4`` | ``OpRayQueryGetIntersectionObjectToWorldKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateObjectToWorld4x3`` | ``OpRayQueryGetIntersectionObjectToWorldKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateWorldToObject3x4`` | ``OpRayQueryGetIntersectionWorldToObjectKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateWorldToObject4x3`` | ``OpRayQueryGetIntersectionWorldToObjectKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateTriangleBarycentrics`` | ``OpRayQueryGetIntersectionBarycentricsKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CandidateTriangleFrontFace`` | ``OpRayQueryGetIntersectionFrontFaceKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedStatus`` | ``OpRayQueryGetIntersectionTypeKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedInstanceIndex`` | ``OpRayQueryGetIntersectionInstanceIdKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedInstanceID`` | ``OpRayQueryGetIntersectionInstanceCustomIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- | ``.CommittedInstanceContributionToHitGroupIndex`` | ``OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedGeometryIndex`` | ``OpRayQueryGetIntersectionGeometryIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedPrimitiveIndex`` | ``OpRayQueryGetIntersectionPrimitiveIndexKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedRayT`` | ``OpRayQueryGetIntersectionTKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedObjectRayOrigin`` | ``OpRayQueryGetIntersectionObjectRayOriginKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedObjectRayDirection`` | ``OpRayQueryGetIntersectionObjectRayDirectionKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedObjectToWorld3x4`` | ``OpRayQueryGetIntersectionObjectToWorldKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedObjectToWorld4x3`` | ``OpRayQueryGetIntersectionObjectToWorldKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedWorldToObject3x4`` | ``OpRayQueryGetIntersectionWorldToObjectKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedWorldToObject4x3`` | ``OpRayQueryGetIntersectionWorldToObjectKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedTriangleBarycentrics`` | ``OpRayQueryGetIntersectionBarycentricsKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommittedTriangleFrontFace`` | ``OpRayQueryGetIntersectionFrontFaceKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommitNonOpaqueTriangleHit`` | ``OpRayQueryConfirmIntersectionKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.CommitProceduralPrimitiveHit`` | ``OpRayQueryGenerateIntersectionKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.Proceed`` | ``OpRayQueryProceedKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.RayFlags`` | ``OpRayQueryGetRayFlagsKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.RayTMin`` | ``OpRayQueryGetRayTMinKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.TraceRayInline`` | ``OpRayQueryInitializeKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.WorldRayDirection`` | ``OpRayQueryGetWorldRayDirectionKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- |``.WorldRayOrigin` | ``OpRayQueryGetWorldRayOriginKHR`` |
- +---------------------------------------------------+-------------------------------------------------------------------------+
- Shader Model 6.0 Wave Intrinsics
- ================================
- Note that Wave intrinsics requires SPIR-V 1.3, which is supported by Vulkan 1.1.
- If you use wave intrinsics in your source code, you will need to specify
- -fspv-target-env=vulkan1.1 via the command line to target Vulkan 1.1.
- Shader model 6.0 introduces a set of wave operations. Apart from
- ``WaveGetLaneCount()`` and ``WaveGetLaneIndex()``, which are translated into
- loading from SPIR-V builtin variable ``SubgroupSize`` and
- ``SubgroupLocalInvocationId`` respectively, the rest are translated into SPIR-V
- group operations with ``Subgroup`` scope according to the following chart:
- ============= ============================ =================================== ======================
- Wave Category Wave Intrinsics SPIR-V Opcode SPIR-V Group Operation
- ============= ============================ =================================== ======================
- Query ``WaveIsFirstLane()`` ``OpGroupNonUniformElect``
- Vote ``WaveActiveAnyTrue()`` ``OpGroupNonUniformAny``
- Vote ``WaveActiveAllTrue()`` ``OpGroupNonUniformAll``
- Vote ``WaveActiveBallot()`` ``OpGroupNonUniformBallot``
- Reduction ``WaveActiveAllEqual()`` ``OpGroupNonUniformAllEqual`` ``Reduction``
- Reduction ``WaveActiveCountBits()`` ``OpGroupNonUniformBallotBitCount`` ``Reduction``
- Reduction ``WaveActiveSum()`` ``OpGroupNonUniform*Add`` ``Reduction``
- Reduction ``WaveActiveProduct()`` ``OpGroupNonUniform*Mul`` ``Reduction``
- Reduction ``WaveActiveBitAdd()`` ``OpGroupNonUniformBitwiseAnd`` ``Reduction``
- Reduction ``WaveActiveBitOr()`` ``OpGroupNonUniformBitwiseOr`` ``Reduction``
- Reduction ``WaveActiveBitXor()`` ``OpGroupNonUniformBitwiseXor`` ``Reduction``
- Reduction ``WaveActiveMin()`` ``OpGroupNonUniform*Min`` ``Reduction``
- Reduction ``WaveActiveMax()`` ``OpGroupNonUniform*Max`` ``Reduction``
- Scan/Prefix ``WavePrefixSum()`` ``OpGroupNonUniform*Add`` ``ExclusiveScan``
- Scan/Prefix ``WavePrefixProduct()`` ``OpGroupNonUniform*Mul`` ``ExclusiveScan``
- Scan/Prefix ``WavePrefixCountBits()`` ``OpGroupNonUniformBallotBitCount`` ``ExclusiveScan``
- Broadcast ``WaveReadLaneAt()`` ``OpGroupNonUniformBroadcast``
- Broadcast ``WaveReadLaneFirst()`` ``OpGroupNonUniformBroadcastFirst``
- Quad ``QuadReadAcrossX()`` ``OpGroupNonUniformQuadSwap``
- Quad ``QuadReadAcrossY()`` ``OpGroupNonUniformQuadSwap``
- Quad ``QuadReadAcrossDiagonal()`` ``OpGroupNonUniformQuadSwap``
- Quad ``QuadReadLaneAt()`` ``OpGroupNonUniformQuadBroadcast``
- ============= ============================ =================================== ======================
- The Implicit ``vk`` Namespace
- =============================
- Overview
- --------
- We have introduced an implicit namepace (called ``vk``) that will be home to all
- Vulkan-specific functions, enums, etc. Given the similarity between HLSL and
- C++, developers are likely familiar with namespaces -- and implicit namespaces
- (e.g. ``std::`` in C++). The ``vk`` namespace provides an interface for expressing
- Vulkan-specific features (core spec and KHR extensions).
- **The compiler will generate the proper error message (** ``unknown 'vk' identifier`` **)
- if** ``vk::`` **is used for compiling to DXIL.**
- Any intrinsic function or enum in the vk namespace will be deprecated if an
- equivalent one is added to the default namepsace.
- Current Features
- ----------------
- The following intrinsic functions and constants are currently defined in the
- implicit ``vk`` namepsace.
- .. code:: hlsl
- // Implicitly defined when compiling to SPIR-V.
- namespace vk {
-
- const uint CrossDeviceScope = 0;
- const uint DeviceScope = 1;
- const uint WorkgroupScope = 2;
- const uint SubgroupScope = 3;
- const uint InvocationScope = 4;
- const uint QueueFamilyScope = 5;
-
- uint64_t ReadClock(in uint scope);
- } // end namespace
- Intrinsic Constants
- -------------------
- The following constants are currently defined:
- ======================== ============================================
- Constant value (SPIR-V constant equivalent, if any)
- ======================== ============================================
- ``vk::CrossDeviceScope`` ``0`` (``CrossDevice``)
- ``vk::DeviceScope`` ``1`` (``Device``)
- ``vk::WorkgroupScope`` ``2`` (``Workgroup``)
- ``vk::SubgroupScope`` ``3`` (``Subgroup``)
- ``vk::InvocationScope`` ``4`` (``Invocation``)
- ``vk::QueueFamilyScope`` ``5`` (``QueueFamily``)
- ======================== ============================================
- Intrinsic Functions
- -------------------
- ReadClock
- ~~~~~~~~~
- This intrinsic funcion has the following signature:
- .. code:: hlsl
- uint64_t ReadClock(in uint scope);
- It translates to performing ``OpReadClockKHR`` defined in `VK_KHR_shader_clock <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_clock.html>`_.
- One can use the predefined scopes in the ``vk`` namepsace to specify the scope argument.
- For example:
- .. code:: hlsl
- uint64_t clock = vk::ReadClock(vk::SubgroupScope);
- Supported Command-line Options
- ==============================
- Command-line options supported by SPIR-V CodeGen are listed below. They are
- also recognized by the library API calls.
- General options
- ---------------
- - ``-T``: specifies shader profile
- - ``-E``: specifies entry point
- - ``-D``: Defines macro
- - ``-I``: Adds directory to include search path
- - ``-O{|0|1|2|3}``: Specifies optimization level
- - ``-enable-16bit-types``: enables 16-bit types and disables min precision types
- - ``-Zpc``: Packs matrices in column-major order by deafult
- - ``-Zpr``: Packs matrices in row-major order by deafult
- - ``-Fc``: outputs SPIR-V disassembly to the given file
- - ``-Fe``: outputs warnings and errors to the given file
- - ``-Fo``: outputs SPIR-V code to the given file
- - ``-Fh``: outputs SPIR-V code as a header file
- - ``-Vn``: specifies the variable name for SPIR-V code in generated header file
- - ``-Zi``: Emits more debug information (see `Debugging`_)
- - ``-Cc``: colorizes SPIR-V disassembly
- - ``-No``: adds instruction byte offsets to SPIR-V disassembly
- - ``-H``: Shows header includes and nesting depth
- - ``-Vi``: Shows details about the include process
- - ``-Vd``: Disables SPIR-V verification
- - ``-WX``: Treats warnings as errors
- - ``-no-warnings``: Suppresses all warnings
- - ``-flegacy-macro-expansion``: expands the operands before performing
- token-pasting operation (fxc behavior)
- Vulkan-specific options
- -----------------------
- The following command line options are added into ``dxc`` to support SPIR-V
- codegen for Vulkan:
- - ``-spirv``: Generates SPIR-V code.
- - ``-fvk-b-shift N M``: Shifts by ``N`` the inferred binding numbers for all
- resources in b-type registers of space ``M``. Specifically, for a resouce
- attached with ``:register(bX, spaceM)`` but not ``[vk::binding(...)]``,
- sets its Vulkan descriptor set to ``M`` and binding number to ``X + N``. If
- you need to shift the inferred binding numbers for more than one space,
- provide more than one such option. If more than one such option is provided
- for the same space, the last one takes effect. If you need to shift the
- inferred binding numbers for all sets, use ``all`` as ``M``.
- See `HLSL register and Vulkan binding`_ for explanation and examples.
- - ``-fvk-t-shift N M``, similar to ``-fvk-b-shift``, but for t-type registers.
- - ``-fvk-s-shift N M``, similar to ``-fvk-b-shift``, but for s-type registers.
- - ``-fvk-u-shift N M``, similar to ``-fvk-b-shift``, but for u-type registers.
- - ``-fvk-auto-shift-bindings``: Automatically detects the register type for
- resources that are missing the ``:register`` assignment, so the above shifts
- can be applied to them if needed.
- - ``-fvk-bind-register xX Y N M`` (short alias: ``-vkbr``): Binds the resouce
- at ``register(xX, spaceY)`` to descriptor set ``M`` and binding ``N``. This
- option cannot be used together with other binding assignment options.
- It requires all source code resources have ``:register()`` attribute and
- all registers have corresponding Vulkan descriptors specified using this
- option.
- - ``-fvk-bind-globals N M``: Places the ``$Globals`` cbuffer at
- descriptor set #M and binding #N. See `HLSL global variables and Vulkan binding`_
- for explanation and examples.
- - ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
- layout rules for resources.
- - ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
- - ``-fvk-invert-y``: Negates (additively inverts) SV_Position.y before writing
- to stage output. Used to accommodate the difference between Vulkan's
- coordinate system and DirectX's. Only allowed in VS/DS/GS.
- - ``-fvk-use-dx-position-w``: Reciprocates (multiplicatively inverts)
- SV_Position.w after reading from stage input. Used to accommodate the
- difference between Vulkan DirectX: the w component of SV_Position in PS is
- stored as 1/w in Vulkan. Only recognized in PS; applying to other stages
- is no-op.
- - ``-fvk-stage-io-order={alpha|decl}``: Assigns the stage input/output variable
- location number according to alphabetical order or declaration order. See
- `HLSL semantic and Vulkan Location`_ for more details.
- - ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
- - ``-fspv-debug=<category>``: Controls what category of debug information
- should be emitted. Accepted values are ``file``, ``source``, ``line``, and
- ``tool``. See `Debugging`_ for more details.
- - ``-fspv-extension=<extension>``: Only allows using ``<extension>`` in CodeGen.
- If you want to allow multiple extensions, provide more than one such option. If you
- want to allow *all* KHR extensions, use ``-fspv-extension=KHR``.
- - ``-fspv-target-env=<env>``: Specifies the target environment for this compilation.
- The current valid options are ``vulkan1.0`` and ``vulkan1.1``. If no target
- environment is provided, ``vulkan1.0`` is used as default.
- - ``-fspv-flatten-resource-arrays``: Flattens arrays of textures and samplers
- into individual resources, each taking one binding number. For example, an
- array of 3 textures will become 3 texture resources taking 3 binding numbers.
- This makes the behavior similar to DX. Without this option, you would get 1
- array object taking 1 binding number. Note that arrays of
- {RW|Append|Consume}StructuredBuffers are currently not supported in the
- SPIR-V backend. Also note that this requires the optimizer to be able to
- resolve all array accesses with constant indeces. Therefore, all loops using
- the resource arrays must be marked with ``[unroll]``.
- - ``-Wno-vk-ignored-features``: Does not emit warnings on ignored features
- resulting from no Vulkan support, e.g., cbuffer member initializer.
- Unsupported HLSL Features
- =========================
- The following HLSL language features are not supported in SPIR-V codegen,
- either because of no Vulkan equivalents at the moment, or because of deprecation.
- * Literal/immediate sampler state: deprecated feature. The compiler will
- emit a warning and ignore it.
- * ``abort()`` intrinsic function: no Vulkan equivalent. The compiler will emit
- an error.
- * ``GetRenderTargetSampleCount()`` intrinsic function: no Vulkan equivalent.
- (Its GLSL counterpart is ``gl_NumSamples``, which is not available in GLSL for
- Vulkan.) The compiler will emit an error.
- * ``GetRenderTargetSamplePosition()`` intrinsic function: no Vulkan equivalent.
- (``gl_SamplePosition`` provides similar functionality but it's only for the
- sample currently being processed.) The compiler will emit an error.
- * ``tex*()`` intrinsic functions: deprecated features. The compiler will
- emit errors.
- * ``.GatherCmpGreen()``, ``.GatherCmpBlue()``, ``.GatherCmpAlpha()`` intrinsic
- method: no Vulkan equivalent. (SPIR-V ``OpImageDrefGather`` instruction does
- not take component as input.) The compiler will emit an error.
- * Since ``StructuredBuffer``, ``RWStructuredBuffer``, ``ByteAddressBuffer``, and
- ``RWByteAddressBuffer`` are not represented as image types in SPIR-V, using the
- output unsigned integer ``status`` argument in their ``Load*`` methods is not
- supported. Using these methods with the ``status`` argument will cause a compiler error.
- * Applying ``row_major`` or ``column_major`` attributes to a stand-alone matrix will be
- ignored by the compiler because ``RowMajor`` and ``ColMajor`` decorations in SPIR-V are
- only allowed to be applied to members of structures. A warning will be issued by the compiler.
- * The Hull shader ``partitioning`` attribute may not have the ``pow2`` value. The compiler
- will emit an error. Other attribute values are supported and described in the
- `Hull Entry Point Attributes`_ section.
- * ``cbuffer``/``tbuffer`` member initializer: no Vulkan equivalent. The compiler
- will emit an warning and ignore it.
- Appendix
- ==========
- Appendix A. Matrix Representation
- ---------------------------------
- Consider a matrix in HLSL defined as ``float2x3 m;``. Conceptually, this is a matrix with 2 rows and 3 columns.
- This means that you can access its elements via expressions such as ``m[i][j]``, where ``i`` can be ``{0, 1}`` and ``j`` can be ``{0, 1, 2}``.
- Now let's look how matrices are defined in SPIR-V:
- .. code:: spirv
- %columnType = OpTypeVector %float <number of rows>
- %matType = OpTypeMatrix %columnType <number of columns>
- As you can see, SPIR-V conceptually represents matrices as a collection of vectors where each vector is a *column*.
- Now, let's represent our float2x3 matrix in SPIR-V. If we choose a naive translation (3 columns, each of which is a vector of size 2), we get:
- .. code:: spirv
- %v2float = OpTypeVector %float 2
- %mat3v2float = OpTypeMatrix %v2float 3
- Now, let's use this naive translation to access into the matrix (e.g. ``m[0][2]``). This is evaluated by first finding ``n = m[0]``, and then finding ``n[2]``.
- Notice that in HLSL, ``m[0]`` represents a row, which is a vector of size 3. But accessing the first dimension of the SPIR-V matrix give us
- the first column which is a vector of size 2.
- .. code:: spirv
- ; n is a vector of size 2
- %n = OpAccessChain %v2float %m %int_0
- Notice that in HLSL access ``m[i][j]``, ``i`` can be ``{0, 1}`` and ``j`` can be ``{0, 1, 2}``.
- But in SPIR-V OpAccessChain access, the first index (``i``) can be ``{0, 1, 2}`` and the second index (``j``) can be ``{1, 0}``.
- Therefore, the naive translation does not work well with indexing.
- As a result, we must translate a given HLSL float2x3 matrix (with 2 rows and 3 columns) as a SPIR-V matrix with 3 rows and 2 columns:
- .. code:: spirv
- %v3float = OpTypeVector %float 3
- %mat2v3float = OpTypeMatrix %v3float 2
- This way, all accesses into the matrix can be naturally handled correctly.
- Packing
- ~~~~~~~
- The HLSL ``row_major`` and ``column_major`` type modifiers change the way packing is done.
- The following table provides an example which should make our translation more clear:
- +------------------+---------------------------+---------------------------+-----------------------------+-------------------+
- | Host CPU Data | HLSL Variable | GPU (HLSL Representation) | GPU (SPIR-V Representation) | SPIR-V Decoration |
- +==================+===========================+===========================+=============================+===================+
- |``{1,2,3,4,5,6}`` | ``float2x3`` | ``[1 3 5]`` | ``[1 2]`` | |
- | | | | | |
- | | | ``[2 4 6]`` | ``[3 4]`` | ``RowMajor`` |
- | | | | | |
- | | | | ``[5 6]`` | |
- +------------------+---------------------------+---------------------------+-----------------------------+-------------------+
- |``{1,2,3,4,5,6}`` | ``column_major float2x3`` | ``[1 3 5]`` | ``[1 2]`` | |
- | | | | | |
- | | | ``[2 4 6]`` | ``[3 4]`` | ``RowMajor`` |
- | | | | | |
- | | | | ``[5 6]`` | |
- +------------------+---------------------------+---------------------------+-----------------------------+-------------------+
- |``{1,2,3,4,5,6}`` | ``row_major float2x3`` | ``[1 2 3]`` | ``[1 4]`` | |
- | | | | | |
- | | | ``[4 5 6]`` | ``[2 5]`` | ``ColMajor`` |
- | | | | | |
- | | | | ``[3 6]`` | |
- +------------------+---------------------------+---------------------------+-----------------------------+-------------------+
|