| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="generator" content="Asciidoctor 1.5.7.1"> |
| <meta name="author" content="Robert J. Simpson, Qualcomm (Editor), John Kessenich, Google (Editor), Dave Baldwin and Randi Rost (Version 1.1 Authors)"> |
| <title>The OpenGL ES® Shading Language, Version 3.20.6</title> |
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> |
| <style> |
| /* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */ |
| /* Uncomment @import statement below to use as custom stylesheet */ |
| /*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/ |
| article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block} |
| audio,canvas,video{display:inline-block} |
| audio:not([controls]){display:none;height:0} |
| script{display:none!important} |
| html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} |
| a{background:transparent} |
| a:focus{outline:thin dotted} |
| a:active,a:hover{outline:0} |
| h1{font-size:2em;margin:.67em 0} |
| abbr[title]{border-bottom:1px dotted} |
| b,strong{font-weight:bold} |
| dfn{font-style:italic} |
| hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} |
| mark{background:#ff0;color:#000} |
| code,kbd,pre,samp{font-family:monospace;font-size:1em} |
| pre{white-space:pre-wrap} |
| q{quotes:"\201C" "\201D" "\2018" "\2019"} |
| small{font-size:80%} |
| sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} |
| sup{top:-.5em} |
| sub{bottom:-.25em} |
| img{border:0} |
| svg:not(:root){overflow:hidden} |
| figure{margin:0} |
| fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} |
| legend{border:0;padding:0} |
| button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} |
| button,input{line-height:normal} |
| button,select{text-transform:none} |
| button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} |
| button[disabled],html input[disabled]{cursor:default} |
| input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} |
| button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} |
| textarea{overflow:auto;vertical-align:top} |
| table{border-collapse:collapse;border-spacing:0} |
| *,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} |
| html,body{font-size:100%} |
| body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} |
| a:hover{cursor:pointer} |
| img,object,embed{max-width:100%;height:auto} |
| object,embed{height:100%} |
| img{-ms-interpolation-mode:bicubic} |
| .left{float:left!important} |
| .right{float:right!important} |
| .text-left{text-align:left!important} |
| .text-right{text-align:right!important} |
| .text-center{text-align:center!important} |
| .text-justify{text-align:justify!important} |
| .hide{display:none} |
| img,object,svg{display:inline-block;vertical-align:middle} |
| textarea{height:auto;min-height:50px} |
| select{width:100%} |
| .center{margin-left:auto;margin-right:auto} |
| .stretch{width:100%} |
| .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} |
| div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr} |
| a{color:#2156a5;text-decoration:underline;line-height:inherit} |
| a:hover,a:focus{color:#1d4b8f} |
| a img{border:none} |
| p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} |
| p aside{font-size:.875em;line-height:1.35;font-style:italic} |
| h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} |
| h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} |
| h1{font-size:2.125em} |
| h2{font-size:1.6875em} |
| h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} |
| h4,h5{font-size:1.125em} |
| h6{font-size:1em} |
| hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} |
| em,i{font-style:italic;line-height:inherit} |
| strong,b{font-weight:bold;line-height:inherit} |
| small{font-size:60%;line-height:inherit} |
| code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} |
| ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} |
| ul,ol{margin-left:1.5em} |
| ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} |
| ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} |
| ul.square{list-style-type:square} |
| ul.circle{list-style-type:circle} |
| ul.disc{list-style-type:disc} |
| ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} |
| dl dt{margin-bottom:.3125em;font-weight:bold} |
| dl dd{margin-bottom:1.25em} |
| abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} |
| abbr{text-transform:none} |
| blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} |
| blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} |
| blockquote cite::before{content:"\2014 \0020"} |
| blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} |
| blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} |
| @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} |
| h1{font-size:2.75em} |
| h2{font-size:2.3125em} |
| h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} |
| h4{font-size:1.4375em}} |
| table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede} |
| table thead,table tfoot{background:#f7f8f7} |
| table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} |
| table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} |
| table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7} |
| table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6} |
| h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} |
| h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} |
| .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} |
| .clearfix::after,.float-group::after{clear:both} |
| *:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word} |
| *:not(pre)>code.nobreak{word-wrap:normal} |
| *:not(pre)>code.nowrap{white-space:nowrap} |
| pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed} |
| em em{font-style:normal} |
| strong strong{font-weight:400} |
| .keyseq{color:rgba(51,51,51,.8)} |
| kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} |
| .keyseq kbd:first-child{margin-left:0} |
| .keyseq kbd:last-child{margin-right:0} |
| .menuseq,.menuref{color:#000} |
| .menuseq b:not(.caret),.menuref{font-weight:inherit} |
| .menuseq{word-spacing:-.02em} |
| .menuseq b.caret{font-size:1.25em;line-height:.8} |
| .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} |
| b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} |
| b.button::before{content:"[";padding:0 3px 0 2px} |
| b.button::after{content:"]";padding:0 2px 0 3px} |
| p a>code:hover{color:rgba(0,0,0,.9)} |
| #header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} |
| #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} |
| #header::after,#content::after,#footnotes::after,#footer::after{clear:both} |
| #content{margin-top:1.25em} |
| #content::before{content:none} |
| #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} |
| #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8} |
| #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px} |
| #header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} |
| #header .details span:first-child{margin-left:-.125em} |
| #header .details span.email a{color:rgba(0,0,0,.85)} |
| #header .details br{display:none} |
| #header .details br+span::before{content:"\00a0\2013\00a0"} |
| #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} |
| #header .details br+span#revremark::before{content:"\00a0|\00a0"} |
| #header #revnumber{text-transform:capitalize} |
| #header #revnumber::after{content:"\00a0"} |
| #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} |
| #toc{border-bottom:1px solid #efefed;padding-bottom:.5em} |
| #toc>ul{margin-left:.125em} |
| #toc ul.sectlevel0>li>a{font-style:italic} |
| #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} |
| #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} |
| #toc li{line-height:1.3334;margin-top:.3334em} |
| #toc a{text-decoration:none} |
| #toc a:active{text-decoration:underline} |
| #toctitle{color:#7a2518;font-size:1.2em} |
| @media screen and (min-width:768px){#toctitle{font-size:1.375em} |
| body.toc2{padding-left:15em;padding-right:0} |
| #toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} |
| #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} |
| #toc.toc2>ul{font-size:.9em;margin-bottom:0} |
| #toc.toc2 ul ul{margin-left:0;padding-left:1em} |
| #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} |
| body.toc2.toc-right{padding-left:0;padding-right:15em} |
| body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}} |
| @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} |
| #toc.toc2{width:20em} |
| #toc.toc2 #toctitle{font-size:1.375em} |
| #toc.toc2>ul{font-size:.95em} |
| #toc.toc2 ul ul{padding-left:1.25em} |
| body.toc2.toc-right{padding-left:0;padding-right:20em}} |
| #content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} |
| #content #toc>:first-child{margin-top:0} |
| #content #toc>:last-child{margin-bottom:0} |
| #footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em} |
| #footer-text{color:rgba(255,255,255,.8);line-height:1.44} |
| #content{margin-bottom:.625em} |
| .sect1{padding-bottom:.625em} |
| @media screen and (min-width:768px){#content{margin-bottom:1.25em} |
| .sect1{padding-bottom:1.25em}} |
| .sect1:last-child{padding-bottom:0} |
| .sect1+.sect1{border-top:1px solid #efefed} |
| #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} |
| #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} |
| #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} |
| #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} |
| #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} |
| .audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} |
| .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} |
| table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} |
| .paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} |
| table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit} |
| .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} |
| .admonitionblock>table td.icon{text-align:center;width:80px} |
| .admonitionblock>table td.icon img{max-width:none} |
| .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} |
| .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)} |
| .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} |
| .exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} |
| .exampleblock>.content>:first-child{margin-top:0} |
| .exampleblock>.content>:last-child{margin-bottom:0} |
| .sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} |
| .sidebarblock>:first-child{margin-top:0} |
| .sidebarblock>:last-child{margin-bottom:0} |
| .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} |
| .exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} |
| .literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8} |
| .sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1} |
| .literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em} |
| .literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal} |
| @media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}} |
| @media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}} |
| .literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)} |
| .listingblock pre.highlightjs{padding:0} |
| .listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} |
| .listingblock pre.prettyprint{border-width:0} |
| .listingblock>.content{position:relative} |
| .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999} |
| .listingblock:hover code[data-lang]::before{display:block} |
| .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999} |
| .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} |
| table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none} |
| table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45} |
| table.pyhltable td.code{padding-left:.75em;padding-right:0} |
| pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8} |
| pre.pygments .lineno{display:inline-block;margin-right:.25em} |
| table.pyhltable .linenodiv{background:none!important;padding-right:0!important} |
| .quoteblock{margin:0 1em 1.25em 1.5em;display:table} |
| .quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em} |
| .quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} |
| .quoteblock blockquote{margin:0;padding:0;border:0} |
| .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} |
| .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} |
| .quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right} |
| .quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)} |
| .quoteblock .quoteblock blockquote{padding:0 0 0 .75em} |
| .quoteblock .quoteblock blockquote::before{display:none} |
| .verseblock{margin:0 1em 1.25em} |
| .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} |
| .verseblock pre strong{font-weight:400} |
| .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} |
| .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} |
| .quoteblock .attribution br,.verseblock .attribution br{display:none} |
| .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} |
| .quoteblock.abstract{margin:0 1em 1.25em;display:block} |
| .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} |
| .quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{word-spacing:0;line-height:1.6} |
| .quoteblock.abstract blockquote::before,.quoteblock.abstract p::before{display:none} |
| table.tableblock{max-width:100%;border-collapse:separate} |
| p.tableblock:last-child{margin-bottom:0} |
| td.tableblock>.content{margin-bottom:-1.25em} |
| table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} |
| table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0} |
| table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0} |
| table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0} |
| table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px} |
| table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0} |
| table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0} |
| table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0} |
| table.frame-all{border-width:1px} |
| table.frame-sides{border-width:0 1px} |
| table.frame-topbot,table.frame-ends{border-width:1px 0} |
| table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7} |
| table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none} |
| th.halign-left,td.halign-left{text-align:left} |
| th.halign-right,td.halign-right{text-align:right} |
| th.halign-center,td.halign-center{text-align:center} |
| th.valign-top,td.valign-top{vertical-align:top} |
| th.valign-bottom,td.valign-bottom{vertical-align:bottom} |
| th.valign-middle,td.valign-middle{vertical-align:middle} |
| table thead th,table tfoot th{font-weight:bold} |
| tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7} |
| tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} |
| p.tableblock>code:only-child{background:none;padding:0} |
| p.tableblock{font-size:1em} |
| td>div.verse{white-space:pre} |
| ol{margin-left:1.75em} |
| ul li ol{margin-left:1.5em} |
| dl dd{margin-left:1.125em} |
| dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} |
| ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} |
| ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} |
| ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} |
| ul.unstyled,ol.unstyled{margin-left:0} |
| ul.checklist{margin-left:.625em} |
| ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} |
| ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} |
| ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} |
| ul.inline>li{margin-left:1.25em} |
| .unstyled dl dt{font-weight:400;font-style:normal} |
| ol.arabic{list-style-type:decimal} |
| ol.decimal{list-style-type:decimal-leading-zero} |
| ol.loweralpha{list-style-type:lower-alpha} |
| ol.upperalpha{list-style-type:upper-alpha} |
| ol.lowerroman{list-style-type:lower-roman} |
| ol.upperroman{list-style-type:upper-roman} |
| ol.lowergreek{list-style-type:lower-greek} |
| .hdlist>table,.colist>table{border:0;background:none} |
| .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} |
| td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} |
| td.hdlist1{font-weight:bold;padding-bottom:1.25em} |
| .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} |
| .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} |
| .colist td:not([class]):first-child img{max-width:none} |
| .colist td:not([class]):last-child{padding:.25em 0} |
| .thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} |
| .imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0} |
| .imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em} |
| .imageblock>.title{margin-bottom:0} |
| .imageblock.thumb,.imageblock.th{border-width:6px} |
| .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} |
| .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} |
| .image.left{margin-right:.625em} |
| .image.right{margin-left:.625em} |
| a.image{text-decoration:none;display:inline-block} |
| a.image object{pointer-events:none} |
| sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} |
| sup.footnote a,sup.footnoteref a{text-decoration:none} |
| sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} |
| #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} |
| #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} |
| #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} |
| #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} |
| #footnotes .footnote:last-of-type{margin-bottom:0} |
| #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} |
| .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} |
| .gist .file-data>table td.line-data{width:99%} |
| div.unbreakable{page-break-inside:avoid} |
| .big{font-size:larger} |
| .small{font-size:smaller} |
| .underline{text-decoration:underline} |
| .overline{text-decoration:overline} |
| .line-through{text-decoration:line-through} |
| .aqua{color:#00bfbf} |
| .aqua-background{background-color:#00fafa} |
| .black{color:#000} |
| .black-background{background-color:#000} |
| .blue{color:#0000bf} |
| .blue-background{background-color:#0000fa} |
| .fuchsia{color:#bf00bf} |
| .fuchsia-background{background-color:#fa00fa} |
| .gray{color:#606060} |
| .gray-background{background-color:#7d7d7d} |
| .green{color:#006000} |
| .green-background{background-color:#007d00} |
| .lime{color:#00bf00} |
| .lime-background{background-color:#00fa00} |
| .maroon{color:#600000} |
| .maroon-background{background-color:#7d0000} |
| .navy{color:#000060} |
| .navy-background{background-color:#00007d} |
| .olive{color:#606000} |
| .olive-background{background-color:#7d7d00} |
| .purple{color:#600060} |
| .purple-background{background-color:#7d007d} |
| .red{color:#bf0000} |
| .red-background{background-color:#fa0000} |
| .silver{color:#909090} |
| .silver-background{background-color:#bcbcbc} |
| .teal{color:#006060} |
| .teal-background{background-color:#007d7d} |
| .white{color:#bfbfbf} |
| .white-background{background-color:#fafafa} |
| .yellow{color:#bfbf00} |
| .yellow-background{background-color:#fafa00} |
| span.icon>.fa{cursor:default} |
| a span.icon>.fa{cursor:inherit} |
| .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} |
| .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} |
| .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} |
| .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} |
| .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} |
| .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} |
| .conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} |
| .conum[data-value] *{color:#fff!important} |
| .conum[data-value]+b{display:none} |
| .conum[data-value]::after{content:attr(data-value)} |
| pre .conum[data-value]{position:relative;top:-.125em} |
| b.conum *{color:inherit!important} |
| .conum:not([data-value]):empty{display:none} |
| dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} |
| h1,h2,p,td.content,span.alt{letter-spacing:-.01em} |
| p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} |
| p,blockquote,dt,td.content,span.alt{font-size:1.0625rem} |
| p{margin-bottom:1.25rem} |
| .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} |
| .exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} |
| .print-only{display:none!important} |
| @page{margin:1.25cm .75cm} |
| @media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} |
| html{font-size:80%} |
| a{color:inherit!important;text-decoration:underline!important} |
| a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} |
| a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} |
| abbr[title]::after{content:" (" attr(title) ")"} |
| pre,blockquote,tr,img,object,svg{page-break-inside:avoid} |
| thead{display:table-header-group} |
| svg{max-width:100%} |
| p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} |
| h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} |
| #toc,.sidebarblock,.exampleblock>.content{background:none!important} |
| #toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important} |
| body.book #header{text-align:center} |
| body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} |
| body.book #header .details{border:0!important;display:block;padding:0!important} |
| body.book #header .details span:first-child{margin-left:0!important} |
| body.book #header .details br{display:block} |
| body.book #header .details br+span::before{content:none!important} |
| body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} |
| body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} |
| .listingblock code[data-lang]::before{display:block} |
| #footer{padding:0 .9375em} |
| .hide-on-print{display:none!important} |
| .print-only{display:block!important} |
| .hide-for-print{display:none!important} |
| .show-for-print{display:inherit!important}} |
| @media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem} |
| .sect1{padding:0!important} |
| .sect1+.sect1{border:0} |
| #footer{background:none} |
| #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} |
| @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} |
| </style> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> |
| <style> |
| /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ |
| /*pre.CodeRay {background-color:#f7f7f8;}*/ |
| .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} |
| .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} |
| .CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} |
| table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} |
| table.CodeRay td{vertical-align: top;line-height:1.45} |
| table.CodeRay td.line-numbers{text-align:right} |
| table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} |
| table.CodeRay td.code{padding:0 0 0 .5em} |
| table.CodeRay td.code>pre{padding:0} |
| .CodeRay .debug{color:#fff !important;background:#000080 !important} |
| .CodeRay .annotation{color:#007} |
| .CodeRay .attribute-name{color:#000080} |
| .CodeRay .attribute-value{color:#700} |
| .CodeRay .binary{color:#509} |
| .CodeRay .comment{color:#998;font-style:italic} |
| .CodeRay .char{color:#04d} |
| .CodeRay .char .content{color:#04d} |
| .CodeRay .char .delimiter{color:#039} |
| .CodeRay .class{color:#458;font-weight:bold} |
| .CodeRay .complex{color:#a08} |
| .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} |
| .CodeRay .color{color:#099} |
| .CodeRay .class-variable{color:#369} |
| .CodeRay .decorator{color:#b0b} |
| .CodeRay .definition{color:#099} |
| .CodeRay .delimiter{color:#000} |
| .CodeRay .doc{color:#970} |
| .CodeRay .doctype{color:#34b} |
| .CodeRay .doc-string{color:#d42} |
| .CodeRay .escape{color:#666} |
| .CodeRay .entity{color:#800} |
| .CodeRay .error{color:#808} |
| .CodeRay .exception{color:inherit} |
| .CodeRay .filename{color:#099} |
| .CodeRay .function{color:#900;font-weight:bold} |
| .CodeRay .global-variable{color:#008080} |
| .CodeRay .hex{color:#058} |
| .CodeRay .integer,.CodeRay .float{color:#099} |
| .CodeRay .include{color:#555} |
| .CodeRay .inline{color:#000} |
| .CodeRay .inline .inline{background:#ccc} |
| .CodeRay .inline .inline .inline{background:#bbb} |
| .CodeRay .inline .inline-delimiter{color:#d14} |
| .CodeRay .inline-delimiter{color:#d14} |
| .CodeRay .important{color:#555;font-weight:bold} |
| .CodeRay .interpreted{color:#b2b} |
| .CodeRay .instance-variable{color:#008080} |
| .CodeRay .label{color:#970} |
| .CodeRay .local-variable{color:#963} |
| .CodeRay .octal{color:#40e} |
| .CodeRay .predefined{color:#369} |
| .CodeRay .preprocessor{color:#579} |
| .CodeRay .pseudo-class{color:#555} |
| .CodeRay .directive{font-weight:bold} |
| .CodeRay .type{font-weight:bold} |
| .CodeRay .predefined-type{color:inherit} |
| .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} |
| .CodeRay .key{color:#808} |
| .CodeRay .key .delimiter{color:#606} |
| .CodeRay .key .char{color:#80f} |
| .CodeRay .value{color:#088} |
| .CodeRay .regexp .delimiter{color:#808} |
| .CodeRay .regexp .content{color:#808} |
| .CodeRay .regexp .modifier{color:#808} |
| .CodeRay .regexp .char{color:#d14} |
| .CodeRay .regexp .function{color:#404;font-weight:bold} |
| .CodeRay .string{color:#d20} |
| .CodeRay .string .string .string{background:#ffd0d0} |
| .CodeRay .string .content{color:#d14} |
| .CodeRay .string .char{color:#d14} |
| .CodeRay .string .delimiter{color:#d14} |
| .CodeRay .shell{color:#d14} |
| .CodeRay .shell .delimiter{color:#d14} |
| .CodeRay .symbol{color:#990073} |
| .CodeRay .symbol .content{color:#a60} |
| .CodeRay .symbol .delimiter{color:#630} |
| .CodeRay .tag{color:#008080} |
| .CodeRay .tag-special{color:#d70} |
| .CodeRay .variable{color:#036} |
| .CodeRay .insert{background:#afa} |
| .CodeRay .delete{background:#faa} |
| .CodeRay .change{color:#aaf;background:#007} |
| .CodeRay .head{color:#f8f;background:#505} |
| .CodeRay .insert .insert{color:#080} |
| .CodeRay .delete .delete{color:#800} |
| .CodeRay .change .change{color:#66f} |
| .CodeRay .head .head{color:#f4f} |
| </style> |
| <link rel="stylesheet" href="../katex/katex.min.css"> |
| <script src="../katex/katex.min.js"></script> |
| <script src="../katex/contrib/auto-render.min.js"></script> |
| <!-- Use KaTeX to render math once document is loaded, see |
| https://github.com/Khan/KaTeX/tree/master/contrib/auto-render --> |
| <script> |
| document.addEventListener("DOMContentLoaded", function () { |
| renderMathInElement( |
| document.body, |
| { |
| delimiters: [ |
| { left: "$$", right: "$$", display: true}, |
| { left: "\\[", right: "\\]", display: true}, |
| { left: "$", right: "$", display: false}, |
| { left: "\\(", right: "\\)", display: false} |
| ] |
| } |
| ); |
| }); |
| </script></head> |
| <body class="book toc2 toc-left" style="max-width: 100;"> |
| <div id="header"> |
| <h1>The OpenGL ES<sup>®</sup> Shading Language, Version 3.20.6</h1> |
| <div class="details"> |
| <span id="author" class="author">Robert J. Simpson, Qualcomm (Editor), John Kessenich, Google (Editor), Dave Baldwin and Randi Rost (Version 1.1 Authors)</span><br> |
| <span id="revnumber">version 3.20.6,</span> |
| <span id="revdate">Wed, 10 Jul 2019 20:42:56 +0000</span> |
| <br><span id="revremark">Git branch information not available</span> |
| </div> |
| <div id="toc" class="toc2"> |
| <div id="toctitle">Table of Contents</div> |
| <ul class="sectlevel1"> |
| <li><a href="#introduction">1. Introduction</a> |
| <ul class="sectlevel2"> |
| <li><a href="#changes">1.1. Changes</a></li> |
| <li><a href="#overview">1.2. Overview</a></li> |
| <li><a href="#error-handling">1.3. Error Handling</a></li> |
| <li><a href="#typographical-conventions">1.4. Typographical Conventions</a></li> |
| <li><a href="#compatibility">1.5. Compatibility</a></li> |
| </ul> |
| </li> |
| <li><a href="#overview-of-opengl-shading">2. Overview of Shading</a> |
| <ul class="sectlevel2"> |
| <li><a href="#vertex-processor">2.1. Vertex Processor</a></li> |
| <li><a href="#tessellation-control-processor">2.2. Tessellation Control Processor</a></li> |
| <li><a href="#tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</a></li> |
| <li><a href="#geometry-processor">2.4. Geometry Processor</a></li> |
| <li><a href="#fragment-processor">2.5. Fragment Processor</a></li> |
| <li><a href="#compute-processor">2.6. Compute Processor</a></li> |
| </ul> |
| </li> |
| <li><a href="#basics">3. Basics</a> |
| <ul class="sectlevel2"> |
| <li><a href="#character-set">3.1. Character Set</a></li> |
| <li><a href="#source-strings">3.2. Source Strings</a></li> |
| <li><a href="#version-declaration">3.3. Version Declaration</a></li> |
| <li><a href="#preprocessor">3.4. Preprocessor</a></li> |
| <li><a href="#comments">3.5. Comments</a></li> |
| <li><a href="#tokens">3.6. Tokens</a></li> |
| <li><a href="#keywords">3.7. Keywords</a></li> |
| <li><a href="#identifiers">3.8. Identifiers</a></li> |
| <li><a href="#definitions">3.9. Definitions</a></li> |
| <li><a href="#logical-phases-of-compilation">3.10. Logical Phases of Compilation</a></li> |
| </ul> |
| </li> |
| <li><a href="#variables-and-types">4. Variables and Types</a> |
| <ul class="sectlevel2"> |
| <li><a href="#basic-types">4.1. Basic Types</a></li> |
| <li><a href="#scoping">4.2. Scoping</a></li> |
| <li><a href="#storage-qualifiers">4.3. Storage Qualifiers</a></li> |
| <li><a href="#layout-qualifiers">4.4. Layout Qualifiers</a></li> |
| <li><a href="#interpolation-qualifiers">4.5. Interpolation Qualifiers</a></li> |
| <li><a href="#parameter-qualifiers">4.6. Parameter Qualifiers</a></li> |
| <li><a href="#precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</a></li> |
| <li><a href="#variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</a></li> |
| <li><a href="#the-precise-qualifier">4.9. The Precise Qualifier</a></li> |
| <li><a href="#memory-qualifiers">4.10. Memory Qualifiers</a></li> |
| <li><a href="#specialization-constant-qualifier">4.11. Specialization-Constant Qualifier</a></li> |
| <li><a href="#order-of-qualification">4.12. Order and Repetition of Qualification</a></li> |
| <li><a href="#empty-declarations">4.13. Empty Declarations</a></li> |
| </ul> |
| </li> |
| <li><a href="#operators-and-expressions">5. Operators and Expressions</a> |
| <ul class="sectlevel2"> |
| <li><a href="#operators">5.1. Operators</a></li> |
| <li><a href="#array-operations">5.2. Array Operations</a></li> |
| <li><a href="#function-calls">5.3. Function Calls</a></li> |
| <li><a href="#constructors">5.4. Constructors</a></li> |
| <li><a href="#vector-components">5.5. Vector Components</a></li> |
| <li><a href="#matrix-components">5.6. Matrix Components</a></li> |
| <li><a href="#structure-and-array-operations">5.7. Structure and Array Operations</a></li> |
| <li><a href="#assignments">5.8. Assignments</a></li> |
| <li><a href="#expressions">5.9. Expressions</a></li> |
| <li><a href="#vector-and-matrix-operations">5.10. Vector and Matrix Operations</a></li> |
| <li><a href="#specialization-constant-operations">5.11. Specialization-Constant Operations</a></li> |
| <li><a href="#evaluation-of-expressions">5.12. Evaluation of Expressions</a></li> |
| </ul> |
| </li> |
| <li><a href="#statements-and-structure">6. Statements and Structure</a> |
| <ul class="sectlevel2"> |
| <li><a href="#function-definitions">6.1. Function Definitions</a></li> |
| <li><a href="#selection">6.2. Selection</a></li> |
| <li><a href="#iteration">6.3. Iteration</a></li> |
| <li><a href="#jumps">6.4. Jumps</a></li> |
| </ul> |
| </li> |
| <li><a href="#built-in-variables">7. Built-In Variables</a> |
| <ul class="sectlevel2"> |
| <li><a href="#built-in-language-variables">7.1. Built-In Language Variables</a></li> |
| <li><a href="#built-in-constants">7.2. Built-In Constants</a></li> |
| <li><a href="#built-in-uniform-state">7.3. Built-In Uniform State</a></li> |
| <li><a href="#redeclaring-built-in-blocks">7.4. Redeclaring Built-In Blocks</a></li> |
| </ul> |
| </li> |
| <li><a href="#built-in-functions">8. Built-In Functions</a> |
| <ul class="sectlevel2"> |
| <li><a href="#angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</a></li> |
| <li><a href="#exponential-functions">8.2. Exponential Functions</a></li> |
| <li><a href="#common-functions">8.3. Common Functions</a></li> |
| <li><a href="#floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</a></li> |
| <li><a href="#geometric-functions">8.5. Geometric Functions</a></li> |
| <li><a href="#matrix-functions">8.6. Matrix Functions</a></li> |
| <li><a href="#vector-relational-functions">8.7. Vector Relational Functions</a></li> |
| <li><a href="#integer-functions">8.8. Integer Functions</a></li> |
| <li><a href="#texture-functions">8.9. Texture Functions</a></li> |
| <li><a href="#atomic-counter-functions">8.10. Atomic Counter Functions</a></li> |
| <li><a href="#atomic-memory-functions">8.11. Atomic Memory Functions</a></li> |
| <li><a href="#image-functions">8.12. Image Functions</a></li> |
| <li><a href="#geometry-shader-functions">8.13. Geometry Shader Functions</a></li> |
| <li><a href="#fragment-processing-functions">8.14. Fragment Processing Functions</a></li> |
| <li><a href="#shader-invocation-control-functions">8.15. Shader Invocation Control Functions</a></li> |
| <li><a href="#shader-memory-control-functions">8.16. Shader Memory Control Functions</a></li> |
| <li><a href="#_subpass_input_functions">8.17. Subpass-Input Functions</a></li> |
| </ul> |
| </li> |
| <li><a href="#shader-interface-matching">9. Shader Interface Matching</a> |
| <ul class="sectlevel2"> |
| <li><a href="#input-output-matching-by-name-in-linked-programs">9.1. Input Output Matching by Name in Linked Programs</a></li> |
| <li><a href="#matching-of-qualifiers">9.2. Matching of Qualifiers</a></li> |
| </ul> |
| </li> |
| <li><a href="#shading-language-grammar">10. Shading Language Grammar</a></li> |
| <li><a href="#counting-of-inputs-and-outputs">11. Counting of Inputs and Outputs</a></li> |
| <li><a href="#acknowledgments">12. Acknowledgments</a></li> |
| <li><a href="#references">13. Normative References</a></li> |
| <li><a href="#_non_normative_spir_v_mappings">14. Non-Normative SPIR-V Mappings</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_feature_comparisons">14.1. Feature Comparisons</a></li> |
| <li><a href="#_mapping_from_glsl_to_spir_v">14.2. Mapping from GLSL to SPIR-V</a></li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div id="content"> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div style="page-break-after: always;"></div> |
| <div class="paragraph"> |
| <p>Copyright © 2008-2018 The Khronos Group Inc. All Rights Reserved.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This specification is protected by copyright laws and contains material |
| proprietary to the Khronos Group, Inc. It or any components may not be |
| reproduced, republished, distributed, transmitted, displayed, broadcast, |
| or otherwise exploited in any manner without the express prior written |
| permission of Khronos Group. You may use this specification for |
| implementing the functionality therein, without altering or removing any |
| trademark, copyright or other notice from the specification, but the |
| receipt or possession of this specification does not convey any rights |
| to reproduce, disclose, or distribute its contents, or to manufacture, |
| use, or sell anything that it may describe, in whole or in part.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Khronos Group grants express permission to any current Promoter, |
| Contributor or Adopter member of Khronos to copy and redistribute |
| UNMODIFIED versions of this specification in any fashion, provided that |
| NO CHARGE is made for the specification and the latest available update |
| of the specification for any version of the API is used whenever |
| possible. Such distributed specification may be reformatted AS LONG AS |
| the contents of the specification are not changed in any way. The |
| specification may be incorporated into a product that is sold as long as |
| such product includes significant independent work developed by the |
| seller. A link to the current version of this specification on the |
| Khronos Group website should be included whenever possible with |
| specification distributions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Khronos Group makes no, and expressly disclaims any, representations or |
| warranties, express or implied, regarding this specification, including, |
| without limitation, any implied warranties of merchantability or fitness |
| for a particular purpose or noninfringement of any intellectual |
| property. Khronos Group makes no, and expressly disclaims any, |
| warranties, express or implied, regarding the correctness, accuracy, |
| completeness, timeliness, and reliability of the specification. Under no |
| circumstances will the Khronos Group, or any of its Promoters, |
| Contributors or Members or their respective partners, officers, |
| directors, employees, agents, or representatives be liable for any |
| damages, whether direct, indirect, special or consequential damages for |
| lost revenues, lost profits, or otherwise, arising from or in connection |
| with these materials.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Khronos, Vulkan, SYCL, SPIR, WebGL, EGL, COLLADA, StreamInput, OpenVX, |
| OpenKCam, glTF, OpenKODE, OpenVG, OpenWF, OpenSL ES, OpenMAX, OpenMAX |
| AL, OpenMAX IL and OpenMAX DL are trademarks and WebCL is a |
| certification mark of the Khronos Group Inc. OpenCL is a trademark of |
| Apple Inc. and OpenGL and OpenML are registered trademarks and the |
| OpenGL ES and OpenGL SC logos are trademarks of Silicon Graphics |
| International used under license by Khronos. All other product names, |
| trademarks, and/or company names are used solely for identification and |
| belong to their respective owners.</p> |
| </div> |
| <div style="page-break-after: always;"></div> |
| <!-- toc disabled --> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="introduction">1. Introduction</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This document specifies only version 3.20 of the OpenGL ES Shading Language (GLSL ES). |
| It requires __VERSION__ to substitute 320, and requires |
| <strong>#version</strong> to accept only |
| <code>320 es</code>. |
| If <strong>#version</strong> is declared with a smaller number, the language accepted is a |
| previous version of the shading language, which will be supported depending |
| on the version and type of context in the API. |
| See the <a href="#references">normative references</a> for details on what language |
| versions are supported.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Throughout, when generating SPIR-V for consumption by the Vulkan API |
| (see <a href="#references">normative references</a>), this will be said to be |
| <em>targeting Vulkan</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>While this specification and the OpenGL ES Specification are normative for OpenGL ES Shading Language, for |
| SPIR-V generation it is still the SPIR-V specification and the SPIR-V client |
| API specification that are normative for the generated SPIR-V. |
| See the <a href="#references">normative references</a> for further detail.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For SPIR-V generation, the SPIR-V client API specifies the commands used to |
| manipulate SPIR-V shaders.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Independent offline tool chains will compile GLSL ES down to the SPIR-V |
| intermediate language. |
| SPIR-V generation is not enabled with a <strong>#extension</strong>, <strong>#version</strong>, or a |
| profile. |
| Instead, use of GLSL ES for SPIR-V is determined by offline tool-chain use. |
| See the documentation of such tools to see how to request generation of |
| SPIR-V for its client API.</p> |
| </div> |
| <div class="paragraph"> |
| <p>GLSL ES → SPIR-V compilers must be directed as to what SPIR-V <strong>Capabilities</strong> |
| are legal at run-time and give errors for GLSL ES feature use outside those |
| capabilities. |
| This is also true for implementation-dependent limits that can be error |
| checked by the front-end against built-in constants present in the GLSL ES |
| source: the front-end can be informed of such limits, and report errors when |
| they are exceeded.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All references in this specification to the <a href="#references">OpenGL ES Specification</a> are to |
| version 3.2.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="changes">1.1. Changes</h3> |
| <div class="sect3"> |
| <h4 id="_changes_from_glsl_es_3_2_revision_5">1.1.1. Changes from GLSL ES 3.2 revision 5</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Incorporated the GL_KHR_vulkan_glsl specification.</p> |
| </li> |
| <li> |
| <p>Clarify it is same location that triggers default-uniform block matching |
| rules. |
| See <a href="#uniform-variable-layout-qualifiers">Uniform Variable Layout Qualifiers</a>.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="changes-from-glsl-es-3.2-revision-4">1.1.2. Changes from GLSL ES 3.2 revision 4</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Clarified that this specification completely defines the OpenGL ES Shading Language. |
| Normatively reference C++ only for the preprocessor.</p> |
| </li> |
| <li> |
| <p>Private GLSL issues 7, 38: Corrected the values of some builtin constants. |
| The values were given correctly in the OpenGL ES Specification.</p> |
| </li> |
| <li> |
| <p>Private GLSL issue 30: Clarify that output packing rules apply to the last |
| vertex pipeline stage, not necessarily the vertex stage.</p> |
| </li> |
| <li> |
| <p>Private GLSL issue 15: Clarify the ordering of bindings for arrays of arrays.</p> |
| </li> |
| <li> |
| <p>Private GLSL issue 14: Uniform variables need only match at link time if they |
| are statically used.</p> |
| </li> |
| <li> |
| <p>For <strong>precise</strong> computations, the controlling expressions for |
| control flow and ternary operators (<strong>?:</strong>) are not included.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="changes-from-glsl-es-3.2-revision-3">1.1.3. Changes from GLSL ES 3.2 revision 3</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Matching of default uniforms when shaders are linked.</p> |
| </li> |
| <li> |
| <p><em>gl_DepthRange</em> is only guaranteed to be available in the fragment |
| stage.</p> |
| </li> |
| <li> |
| <p>Clarification of definition of static use.</p> |
| </li> |
| <li> |
| <p>Sampling behavior in the absence of <strong>sample</strong> and <strong>centroid</strong>.</p> |
| </li> |
| <li> |
| <p>Clarified the requirements when the specification uses the terms |
| <em>should</em>/<em>should not</em> and <em>undefined behavior</em>.</p> |
| </li> |
| <li> |
| <p>Arrayed blocks cannot have layout location qualifiers on members</p> |
| </li> |
| <li> |
| <p><strong>barrier</strong>() defines a partial order which includes tessellation control |
| shader outputs.</p> |
| </li> |
| <li> |
| <p>Vertex shader integer output qualification.</p> |
| </li> |
| <li> |
| <p>Incorrect use of predefined pragmas.</p> |
| </li> |
| <li> |
| <p>Clarified use of <strong>readonly</strong> and <strong>writeonly</strong> qualifiers.</p> |
| </li> |
| <li> |
| <p>USAMPLERBUFFER added to grammar.</p> |
| </li> |
| <li> |
| <p>Clarified precision qualifiers can be used in interface blocks.</p> |
| </li> |
| <li> |
| <p>Clarified <strong>memoryBarrierShared</strong> only applies to the current workgroup.</p> |
| </li> |
| <li> |
| <p>The layout qualifier <em>invocations</em> must not be zero.</p> |
| </li> |
| <li> |
| <p>The layout qualifier <em>local_size</em> must not be zero.</p> |
| </li> |
| <li> |
| <p>Clarified the definition of static assignment.</p> |
| </li> |
| <li> |
| <p>Removed list of types with no default precision.</p> |
| </li> |
| <li> |
| <p>Removed scoping rules from the grammar. Refer instead to the <a href="#scoping">scoping</a> section.</p> |
| </li> |
| <li> |
| <p>Require a statement after the final label of a switch.</p> |
| </li> |
| <li> |
| <p>Define <strong>gl_BoundingBox</strong>.</p> |
| </li> |
| <li> |
| <p><strong>length</strong>() expressions returning a constant-value may not include side effects.</p> |
| </li> |
| <li> |
| <p>Clarified that variables may be declared <strong>readonly writeonly</strong>.</p> |
| </li> |
| <li> |
| <p>Use of constant expressions within <strong>#line</strong> directives is undefined.</p> |
| </li> |
| <li> |
| <p><strong>gl_in</strong> can be redeclared using unsized-array syntax.</p> |
| </li> |
| <li> |
| <p>Clarified which sampler types may be used for depth and stencil textures.</p> |
| </li> |
| <li> |
| <p>Added order-of-operation and other explanations to the |
| <a href="#the-precise-qualifier">Precise Qualifier</a> section.</p> |
| </li> |
| <li> |
| <p>The <strong>precise</strong> qualifier applied to a block/struct applies recursively to the members.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="changes-from-glsl-es-3.2-revision-2">1.1.4. Changes from GLSL ES 3.2 revision 2</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Updated value for <em>gl_MaxTessControlTotalOutputComponents</em></p> |
| </li> |
| <li> |
| <p>Clarified the allowed character set for pre-processing</p> |
| </li> |
| <li> |
| <p>Integer division wrapping behavior</p> |
| </li> |
| <li> |
| <p>Clarified pre-processor expressions (<em>pp-constant-expression</em>)</p> |
| </li> |
| <li> |
| <p>UBO and SSBO precisions do not need to match for linked shaders |
| (consistent with GLSL ES 3.1)</p> |
| </li> |
| <li> |
| <p><strong>modf</strong> function</p> |
| </li> |
| <li> |
| <p>Sequence and ternary operators with <strong>void</strong> type</p> |
| </li> |
| <li> |
| <p>Sequence and ternary operators with array types</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="changes-from-glsl-es-3.2-revision-1">1.1.5. Changes from GLSL ES 3.2 revision 1</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Signed zeros must be supported</p> |
| </li> |
| <li> |
| <p>Layout qualifier table</p> |
| </li> |
| <li> |
| <p>Allowed optimizations when evaluating expressions</p> |
| </li> |
| <li> |
| <p>Updated value for <em>gl_MaxTessControlInputComponents</em></p> |
| </li> |
| <li> |
| <p>Updated value for <em>gl_MaxTessControlOutputComponents</em></p> |
| </li> |
| <li> |
| <p>Updated value for <em>gl_MaxTessEvaluationInputComponents</em></p> |
| </li> |
| <li> |
| <p>Updated value for <em>gl_MaxTessEvaluationOutputComponents</em></p> |
| </li> |
| <li> |
| <p>Updated value for <em>gl_MaxGeometryOutputComponents</em></p> |
| </li> |
| <li> |
| <p>Require precisions in blocks to match when linking</p> |
| </li> |
| <li> |
| <p>Updated conclusions in issues section</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="changes-from-glsl-es-3.1-revision-4">1.1.6. Changes from GLSL ES 3.1 revision 4</h4> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Added the following extensions:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="https://www.opengl.org/registry/specs/KHR/blend_equation_advanced.txt">KHR_blend_equation_advanced</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_sample_variables.txt">OES_sample_variables</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_image_atomic.txt">OES_shader_image_atomic</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_multisample_interpolation.txt">OES_shader_multisample_interpolation</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_storage_multisample_2d_array.txt">OES_texture_storage_multisample_2d_array</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_geometry_shader.txt">OES_geometry_shader</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_gpu_shader5.txt">OES_gpu_shader5</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_primitive_bounding_box.txt">OES_primitive_bounding_box</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_io_blocks.txt">OES_shader_io_blocks</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_tessellation_shader.txt">OES_tessellation_shader</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_buffer.txt">OES_texture_buffer</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map_array.txt">OES_texture_cube_map_array</a></p> |
| </li> |
| <li> |
| <p><a href="https://www.opengl.org/registry/specs/KHR/robustness.txt">KHR_robustness</a></p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="overview">1.2. Overview</h3> |
| <div class="paragraph"> |
| <p>This document describes <em>The OpenGL ES Shading Language, version 3.20</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Independent compilation units written in this language are called <em>shaders</em>. |
| A <em>program</em> is a set of shaders that are compiled and linked |
| together. |
| The aim of this document is to thoroughly specify the programming language. |
| The <a href="#references">normative references</a> will specify the API entry points |
| used to manipulate and communicate with programs and shaders.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="error-handling">1.3. Error Handling</h3> |
| <div class="paragraph"> |
| <p>Compilers, in general, accept programs that are ill-formed, due to the |
| impossibility of detecting all ill-formed programs. |
| Portability is only ensured for well-formed programs, which this |
| specification describes. |
| Compilers are encouraged to detect ill-formed programs and issue diagnostic |
| messages, but are not required to do so for all cases.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The compilation process is implementation-dependent but is generally split |
| into a number of stages, each of which occurs at one of the following times:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A call to <em>glCompileShader</em></p> |
| </li> |
| <li> |
| <p>A call to <em>glLinkProgram</em></p> |
| </li> |
| <li> |
| <p>A draw call or a call to <em>glValidateProgram</em></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The implementation should report errors as early a possible but in any case |
| must satisfy the following:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>All lexical, grammatical and semantic errors must have been detected |
| following a call to <em>glLinkProgram</em></p> |
| </li> |
| <li> |
| <p>Errors due to mismatch between the shaders (link-time errors) must have |
| been detected following a call to <em>glLinkProgram</em></p> |
| </li> |
| <li> |
| <p>Errors due to exceeding resource limits must have been detected |
| following any draw call or a call to <em>glValidateProgram</em></p> |
| </li> |
| <li> |
| <p>A call to <em>glValidateProgram</em> must report all errors associated with a |
| program object given the current GL state.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Where the specification uses the terms <em>required</em>, <em>must</em>/<em>must</em> <em>not</em>, |
| <em>does</em>/<em>does</em> <em>not</em>, <em>disallowed</em>, or <em>not</em> <em>supported</em>, the compiler or |
| linker is required to detect and report any violations. |
| Similarly when a condition or situation is an <strong>error</strong>, it must be reported. |
| Use of any feature marked as <em>reserved</em> is an error. |
| Where the specification uses the terms <em>should</em>/<em>should</em> <em>not</em>, <em>undefined</em> |
| <em>behavior</em>, <em>undefined</em> <em>value</em> or <em>undefined</em> <em>*results*</em>, implementations |
| will not produce a compile-time error but are encouraged to issue a warning |
| for violations. |
| The run-time behavior of the program in these cases is not constrained (and |
| so may include termination or system instability). |
| It is expected that systems will be designed to handle these cases |
| gracefully but specification of this is outside the scope of this |
| specification.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Implementations may not in general support functionality beyond the mandated |
| parts of the specification without use of the relevant extension. |
| The only exceptions are:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>If a feature is marked as optional.</p> |
| </li> |
| <li> |
| <p>Where a maximum value is stated (e.g. the maximum number of vertex |
| outputs), the implementation may support a higher value than that |
| specified.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Where the implementation supports more than the mandated specification, |
| off-target compilers are encouraged to issue warnings if these features are |
| used.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The compilation process is split between the compiler and linker. |
| The allocation of tasks between the compiler and linker is implementation |
| dependent. |
| Consequently there are many errors which may be detected either at compile |
| or link time, depending on the implementation.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="typographical-conventions">1.4. Typographical Conventions</h3> |
| <div class="paragraph"> |
| <p>Italic, bold, and font choices have been used in this specification |
| primarily to improve readability. |
| Code fragments use a fixed width font. |
| Identifiers embedded in text are italicized. |
| Keywords embedded in text are bold. |
| Operators are called by their name, followed by their symbol in bold in |
| parentheses. |
| The clarifying grammar fragments in the text use bold for literals and |
| italics for non-terminals. |
| The official grammar in “<a href="#shading-language-grammar">Shading Language |
| Grammar</a>” uses all capitals for terminals and lower case for |
| non-terminals.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="compatibility">1.5. Compatibility</h3> |
| <div class="paragraph"> |
| <p>The OpenGL ES 3.2 API is designed to work with GLSL ES v1.00, |
| GLSL ES 3.00, GLSL ES 3.10 and GLSL ES 3.20. |
| In general a shader written for versions prior to OpenGL ES 3.2 |
| should work without modification in OpenGL ES 3.2.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When porting applications from an earlier to later version of the GLSL ES, |
| the following points should be noted:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Not all language constructs present in earlier versions of the language |
| are available in later versions e.g. attribute and varying qualifiers |
| are present in v1.00 but not v3.00. |
| However, the functionality of GLSL ES 3.20 is a super-set of |
| GLSL ES 3.10.</p> |
| </li> |
| <li> |
| <p>Some features of later versions of the API require language features |
| that are not present in earlier version of the language.</p> |
| </li> |
| <li> |
| <p>It is an error to link shaders if they are written in different versions |
| of the language.</p> |
| </li> |
| <li> |
| <p>The OpenGL ES 2.0 and 3.0 APIs do not support shaders written in GLSL ES |
| 3.20.</p> |
| </li> |
| <li> |
| <p>Using GLSL ES 1.00 shaders within OpenGL ES 3.x may extend the resources |
| available beyond the minima specified in GLSL ES 1.0. |
| Shaders which make use of this will not necessarily run on an OpenGL ES |
| 2.0 implementation: Similarly for GLSL ES 3.00 shaders running within |
| OpenGL ES 3.2.</p> |
| </li> |
| <li> |
| <p>Support of line continuation and support of UTF-8 characters within |
| comments is optional in GLSL ES 1.00 when used with the OpenGL ES 2.0 |
| API. |
| However, support is mandated for both of these when a GLSL ES 1.00 |
| shader is used with the OpenGL ES 3.x APIs.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="overview-of-opengl-shading">2. Overview of Shading</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language is actually several closely related languages. |
| These languages are used to create shaders for each of the programmable |
| processors contained in the API’s processing pipeline. |
| Currently, these processors are the vertex, tessellation control, |
| tessellation evaluation, geometry, fragment, and compute processors.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Compilation units for these processors are referred to as <em>shaders</em> and the |
| processors themselves are also referred to as <em>shader stages</em>. |
| Only one shader can be run on a processor at any one time; there is no |
| support for linking multiple compilation units together for a single shader |
| stage. |
| One or more shaders are linked together to form a single program and each |
| program contains shader <em>executables</em> for one or more consecutive shader |
| stages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Unless otherwise noted in this paper, a language feature applies to all |
| languages, and common usage will refer to these languages as a single |
| language. |
| The specific languages will be referred to by the name of the processor they |
| target: vertex, tessellation control, tessellation evaluation, geometry, |
| fragment, or compute.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Most API state is not tracked or made available to shaders. |
| Typically, user-defined variables will be used for communicating between |
| different stages of the API pipeline. |
| However, a small amount of state is still tracked and automatically made |
| available to shaders, and there are a few built-in variables for interfaces |
| between different stages of the API pipeline.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="vertex-processor">2.1. Vertex Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>vertex processor</em> is a programmable unit that operates on incoming |
| vertices and their associated data. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| <em>vertex shaders</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The vertex processor operates on one vertex at a time. |
| It does not replace graphics operations that require knowledge of several |
| vertices at a time.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="tessellation-control-processor">2.2. Tessellation Control Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>tessellation control processor</em> is a programmable unit that operates on |
| a patch of incoming vertices and their associated data, emitting a new |
| output patch. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| tessellation control shaders.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The tessellation control shader is invoked for each vertex of the output |
| patch. |
| Each invocation can read the attributes of any vertex in the input or output |
| patches, but can only write per-vertex attributes for the corresponding |
| output patch vertex. |
| The shader invocations collectively produce a set of per-patch attributes |
| for the output patch.</p> |
| </div> |
| <div class="paragraph"> |
| <p>After all tessellation control shader invocations have completed, the output |
| vertices and per-patch attributes are assembled to form a patch to be used |
| by subsequent pipeline stages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Tessellation control shader invocations run mostly independently, with |
| undefined relative execution order. |
| However, the built-in function <strong>barrier</strong>() can be used to control execution |
| order by synchronizing invocations, effectively dividing tessellation |
| control shader execution into a set of phases. |
| Tessellation control shaders will get undefined results if one invocation |
| reads from a per-vertex or per-patch attribute written by another invocation |
| at any point during the same phase, or if two invocations attempt to write |
| different values to the same per-patch output |
| in a single phase.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>tessellation evaluation processor</em> is a programmable unit that |
| evaluates the position and other attributes of a vertex generated by the |
| tessellation primitive generator, using a patch of incoming vertices and |
| their associated data. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| tessellation evaluation shaders.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Each invocation of the tessellation evaluation executable computes the |
| position and attributes of a single vertex generated by the tessellation |
| primitive generator. |
| The executable can read the attributes of any vertex in the input patch, |
| plus the tessellation coordinate, which is the relative location of the |
| vertex in the primitive being tessellated. |
| The executable writes the position and other attributes of the vertex.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="geometry-processor">2.4. Geometry Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>geometry processor</em> is a programmable unit that operates on data for |
| incoming vertices for a primitive assembled after vertex processing and |
| outputs a sequence of vertices forming output primitives. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| <em>geometry shaders</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A single invocation of the geometry shader executable on the geometry |
| processor will operate on a declared input primitive with a fixed number of |
| vertices. |
| This single invocation can emit a variable number of vertices that are |
| assembled into primitives of a declared output primitive type and passed to |
| subsequent pipeline stages.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="fragment-processor">2.5. Fragment Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>fragment processor</em> is a programmable unit that operates on fragment |
| values and their associated data. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| <em>fragment shaders</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A fragment shader cannot change a fragment’s (<em>x</em>, <em>y</em>) position. |
| Access to neighboring fragments is not allowed. |
| The values computed by the fragment shader are ultimately used to update |
| framebuffer memory or texture memory, depending on the current API |
| state and the API command that caused the fragments to be generated.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="compute-processor">2.6. Compute Processor</h3> |
| <div class="paragraph"> |
| <p>The <em>compute processor</em> is a programmable unit that operates independently |
| from the other shader processors. |
| Compilation units written in the OpenGL ES Shading Language to run on this processor are called |
| <em>compute shaders</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A compute shader has access to many of the same resources as fragment and |
| other shader processors, such as textures, buffers, image variables, and |
| atomic counters. |
| It does not have fixed-function outputs. |
| It is not part of the graphics pipeline and its visible side effects are |
| through changes to images, storage buffers, and atomic counters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A compute shader operates on a group of work items called a <em>workgroup</em>. |
| A workgroup is a collection of shader invocations that execute the same |
| code, potentially in parallel. |
| An invocation within a workgroup may share data with other members of the |
| same workgroup through shared variables and issue memory and control flow |
| barriers to synchronize with other members of the same workgroup.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="basics">3. Basics</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="character-set">3.1. Character Set</h3> |
| <div class="paragraph"> |
| <p>The source character set used for the OpenGL ES Shading Language is Unicode in the UTF-8 |
| encoding scheme. |
| Invalid UTF-8 characters are ignored. |
| During pre-processing, the following applies:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A byte with the value zero is always interpreted as the end of the |
| string</p> |
| </li> |
| <li> |
| <p>Backslash ('\'), is used to indicate line continuation when immediately |
| preceding a new-line.</p> |
| </li> |
| <li> |
| <p>White space consists of one or more of the following characters: the |
| space character, horizontal tab, vertical tab, form feed, |
| carriage-return, line-feed.</p> |
| </li> |
| <li> |
| <p>The number sign (<strong>#</strong>) is used for preprocessor directives</p> |
| </li> |
| <li> |
| <p>Macro names are restricted to:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The letters <strong>a-z</strong>, <strong>A-Z</strong>, and the underscore (<strong>_</strong>).</p> |
| </li> |
| <li> |
| <p>The numbers <strong>0-9</strong>, except for the first character of a macro name.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>After preprocessing, only the following characters are allowed in the |
| resulting stream of GLSL ES tokens:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The letters <strong>a-z</strong>, <strong>A-Z</strong>, and the underscore (<strong>_</strong>).</p> |
| </li> |
| <li> |
| <p>The numbers <strong>0-9</strong>.</p> |
| </li> |
| <li> |
| <p>The symbols period (<strong>.</strong>), plus (<strong>+</strong>), dash (<strong>-</strong>), slash (<strong>/</strong>), asterisk |
| (<strong>*</strong>), percent (<strong>%</strong>), angled brackets (<strong><</strong> and <strong>></strong>), square brackets |
| (<strong>[</strong> and <strong>]</strong>), parentheses (<strong>(</strong> and <strong>)</strong>), braces (<strong>{</strong> and <strong>}</strong>), caret |
| (<strong>^</strong>), vertical bar (<strong>|</strong>), ampersand (<strong>&</strong>), tilde (<strong>~</strong>), equals (<strong>=</strong>), |
| exclamation point (<strong>!</strong>), colon (<strong>:</strong>), semicolon (<strong>;</strong>), comma (<strong>,</strong>), and |
| question mark (<strong>?</strong>).</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>There are no digraphs or trigraphs. |
| There are no escape sequences or other uses of the backslash beyond use as |
| the line-continuation character.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Lines are relevant for compiler diagnostic messages and the preprocessor. |
| They are terminated by carriage-return or line-feed. |
| If both are used together, it will count as only a single line termination. |
| For the remainder of this document, any of these combinations is simply |
| referred to as a new-line. |
| Lines may be of arbitrary length.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In general, the language’s use of this character set is case sensitive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are no character or string data types, so no quoting characters are |
| included.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is no end-of-file character.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="source-strings">3.2. Source Strings</h3> |
| <div class="paragraph"> |
| <p>The source for a single shader is an array of strings of characters from the |
| character set. |
| A single shader is made from the concatenation of these strings. |
| Each string can contain multiple lines, separated by new-lines. |
| No new-lines need be present in a string; a single line can be formed from |
| multiple strings. |
| No new-lines or other characters are inserted by the implementation when it |
| concatenates the strings to form a single shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Diagnostic messages returned from compiling a shader must identify both the |
| line number within a string and which source string the message applies to. |
| Source strings are counted sequentially with the first string being string |
| 0. |
| Line numbers are one more than the number of new-lines that have been |
| processed, including counting the new-lines that will be removed by the |
| line-continuation character (<strong>\</strong>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Lines separated by the line-continuation character preceding a new-line are |
| concatenated together before either comment processing or preprocessing. |
| This means that no white space is substituted for the line-continuation |
| character. |
| That is, a single token could be formed by the concatenation by taking the |
| characters at the end of one line concatenating them with the characters at |
| the beginning of the next line.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> f\ |
| oo; |
| <span class="comment">// forms a single line equivalent to "float foo;"</span> |
| <span class="comment">// (assuming '\' is the last character before the new-line and "oo" are</span> |
| <span class="comment">// the first two characters of the next line)</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="version-declaration">3.3. Version Declaration</h3> |
| <div class="paragraph"> |
| <p>Shaders must declare the version of the language they are written to. |
| The version is specified in the first line of a shader by a character |
| string:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#version</span> number es</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>number</em> must be a version of the language, following the same |
| convention as __VERSION__ above. |
| The directive “<strong>#version 320 es</strong>” is required in any shader that |
| uses version 3.20 of the language. |
| Any <em>number</em> representing a version of the language a compiler does not |
| support will cause an error to be generated. |
| Version 1.00 of the language does not require shaders to include this |
| directive, and shaders that do not include a <strong>#version</strong> directive will be |
| treated as targeting version 1.00.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Shaders declaring version 3.20 of the shading language cannot be |
| linked with shaders declaring a previous version.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>#version</strong> directive must be present in the first line of a shader and |
| must be followed by a newline. |
| It may contain optional white-space as specified below but no other |
| characters are allowed. |
| The directive is only permitted in the first line of a shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Processing of the #version directive occurs before all other preprocessing, |
| including line concatenation and comment processing.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>version-declaration</em> : </dt> |
| <dd> |
| <p><em>whitespace<sub>opt</sub></em> POUND <em>whitespace<sub>opt</sub></em> VERSION <em>whitespace</em> <em>number</em> |
| <em>whitespace</em> ES <em>whitespace<sub>opt</sub></em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Tokens:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>POUND <strong>#</strong><br> |
| VERSION <strong>version</strong><br> |
| ES <strong>es</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="preprocessor">3.4. Preprocessor</h3> |
| <div class="paragraph"> |
| <p>There is a preprocessor that processes the source strings as part of the |
| compilation process. |
| Except as noted below, it behaves as the C++ standard preprocessor (see |
| “<a href="#references">Normative References</a>”).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The complete list of preprocessor directives is as follows.</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>#<br> |
| #define<br> |
| #undef<br></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>#if<br> |
| #ifdef<br> |
| #ifndef<br> |
| #else<br> |
| #elif<br> |
| #endif<br></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>#error<br> |
| #pragma<br></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>#extension<br></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>#line</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The following |
| operator is |
| also available:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>defined<br></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the version directive is not considered to be a preprocessor |
| directive and so is not listed here.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Each number sign (<strong>#</strong>) can be preceded in its line only by spaces or |
| horizontal tabs. |
| It may also be followed by spaces and horizontal tabs, preceding the |
| directive. |
| Each directive is terminated by a new-line. |
| Preprocessing does not change the number or relative location of new-lines |
| in a source string.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The number sign (<strong>#</strong>) on a line by itself is ignored. |
| Any directive not listed above will cause an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>#define</strong> and <strong>#undef</strong> functionality are defined as is standard for C++ |
| preprocessors for macro definitions both with and without macro parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following predefined macros are available:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>__LINE__<br> |
| __FILE__<br> |
| __VERSION__<br> |
| GL_ES</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>__LINE__ will substitute a decimal integer constant that is one more than |
| the number of preceding new-lines in the current source string.</p> |
| </div> |
| <div class="paragraph"> |
| <p>__FILE__ will substitute a decimal integer constant that says which source |
| string number is currently being processed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>__VERSION__ will substitute a decimal integer reflecting the version |
| number of the OpenGL ES Shading Language. |
| The version of the shading language described in this document will have |
| __VERSION__ substitute the decimal integer 320.</p> |
| </div> |
| <div class="paragraph"> |
| <p>GL_ES will be defined and set to 1. |
| This is not true for the non-ES OpenGL Shading Language, so it can be used |
| to do a compile time test to determine if a shader is compiling as an |
| GLSL ES shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By convention, all macro names containing two consecutive underscores (__) |
| are reserved for use by underlying software layers. |
| Defining |
| such a name in a shader does not itself result in an error, but may |
| result in unintended behaviors that stem from having multiple definitions of |
| the same name. |
| All macro names prefixed with “GL_” (“GL” followed by a single |
| underscore) are also reserved, and defining |
| such a name results in a compile-time error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is an error to undefine or to redefine a built-in (pre-defined) macro |
| name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Implementations must support macro-name lengths of up to 1024 characters. |
| It is an error to declare a name with a length greater than this.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>#if</strong>, <strong>#ifdef</strong>, <strong>#ifndef</strong>, <strong>#else</strong>, <strong>#elif</strong>, and <strong>#endif</strong> are defined to |
| operate as is standard for C++ preprocessors except for the following:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Expressions following <strong>#if</strong> and <strong>#elif</strong> are |
| restricted to <em>pp-constant-expressions</em> as defined below.</p> |
| </li> |
| <li> |
| <p>Undefined identifiers not consumed by the <strong>defined</strong> operator do not |
| default to '0'. |
| Use of such identifiers causes an error.</p> |
| </li> |
| <li> |
| <p>Character constants are not supported.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>As in C++, a macro name defined with an empty replacement list does not |
| default to '0' when used in a preprocessor expression.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>pp-constant-expression</em> is an integral expression, evaluated at |
| compile-time during preprocessing and formed from literal integer constants |
| and the following operators:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Precedence</th> |
| <th class="tableblock halign-left valign-top">Operator class</th> |
| <th class="tableblock halign-left valign-top">Operators</th> |
| <th class="tableblock halign-left valign-top">Associativity</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">unary</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">defined<br> |
| + - ~ !</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><< >></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">< > <= >=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">&</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">&&</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">12 (lowest)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The <strong>defined</strong> operator can be used in either of the following ways:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">defined identifier |
| defined ( identifier )</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There are no number sign based operators (e.g. no <strong><mark></strong> or <strong></mark>@</strong>), no <strong>##</strong> |
| operator, nor is there a <strong>sizeof</strong> operator.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The semantics of applying operators in the preprocessor match those standard |
| in the C++ preprocessor with the following exceptions:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The 2<sup>nd</sup> operand in a logical and ('&&') operation is evaluated if and |
| only if the 1<sup>st</sup> operand evaluates to non-zero.</p> |
| </li> |
| <li> |
| <p>The 2<sup>nd</sup> operand in a logical or ('||') operation is evaluated if and |
| only if the 1<sup>st</sup> operand evaluates to zero.</p> |
| </li> |
| <li> |
| <p>There is no boolean type and no boolean literals. |
| A <em>true</em> or <em>false</em> result is returned as integer <em>one</em> or <em>zero</em> |
| respectively. |
| Wherever a boolean operand is expected, any non-zero integer is |
| interpreted as <em>true</em> and a zero integer as <em>false</em>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>If an operand is not evaluated, the presence of undefined identifiers in the |
| operand will not cause an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>#error</strong> will cause the implementation to put a compile-time diagnostic message |
| into the shader object’s information log (see section 7.12 “Shader, Program |
| and Program Pipeline Queries” of the <a href="#references">OpenGL ES Specification</a> for how to |
| access a shader object’s information log). |
| The message will be the tokens following the <strong>#error</strong> directive, up to the |
| first new-line. |
| The implementation must treat the presence of a <strong>#error</strong> directive as a |
| compile-time error.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>#pragma</strong> allows implementation-dependent compiler control. |
| Tokens following <strong>#pragma</strong> are not subject to preprocessor macro expansion. |
| If an implementation does not recognize the tokens following <strong>#pragma</strong>, then |
| it will ignore that pragma. |
| The following pragmas are defined as part of the language.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>STDGL</strong> pragma is used to reserve pragmas for use by future revisions of |
| this language. |
| No implementation may use a pragma whose first token is <strong>STDGL</strong>.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> optimize(on) |
| <span class="preprocessor">#pragma</span> optimize(off)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>can be used to turn off optimizations as an aid in developing and debugging |
| shaders. |
| It can only be used outside function definitions. |
| By default, optimization is turned on for all shaders. |
| The debug pragma</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> debug(on) |
| <span class="preprocessor">#pragma</span> debug(off)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>can be used to enable compiling and annotating a shader with debug |
| information, so that it can be used with a debugger. |
| It can only be used outside function definitions. |
| By default, debug is turned off.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scope as well as the effect of the optimize and debug pragmas is |
| implementation-dependent except that their use must not generate an error. |
| Incorrect use of predefined pragmas does not cause an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By default, compilers of this language must issue compile-time |
| syntactic, semantic, |
| and |
| grammatical errors for shaders that do not conform to this specification. |
| Any extended behavior must first be enabled. |
| Directives to control the behavior of the compiler with respect to |
| extensions are declared with the <strong>#extension</strong> directive</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> extension_name : behavior |
| <span class="preprocessor">#extension</span> all : behavior</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>extension_name</em> is the name of an extension. |
| Extension names are not documented in this specification. |
| The token <strong>all</strong> means the behavior applies to all extensions supported by |
| the compiler. |
| The <em>behavior</em> can be one of the following:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Behavior</th> |
| <th class="tableblock halign-left valign-top">Effect</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>require</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br> |
| Give a compile-time error on the <strong>#extension</strong> if the extension |
| <em>extension_name</em> is not supported, or if <strong>all</strong> is specified.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>enable</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br> |
| Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is |
| not supported.<br> |
| Give an error on the <strong>#extension</strong> if <strong>all</strong> is |
| specified.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>warn</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>, |
| except issue warnings on any detectable use of that extension, |
| unless such use is supported by other enabled or required |
| extensions.<br> |
| If <strong>all</strong> is specified, then warn on all detectable uses of any |
| extension used.<br> |
| Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is |
| not supported.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>disable</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Behave (including issuing errors and warnings) as if the |
| extension <em>extension_name</em> is not part of the language |
| definition.<br> |
| If <strong>all</strong> is specified, then behavior must revert back to that |
| of the non-extended core version of the language being |
| compiled to.<br> |
| Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is |
| not supported.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The <strong>extension</strong> directive is a simple, low-level mechanism to set the |
| behavior for each extension. |
| It does not define policies such as which combinations are appropriate, |
| those must be defined elsewhere. |
| Order of directives matters in setting the behavior for each extension: |
| Directives that occur later override those seen earlier. |
| The <strong>all</strong> variant sets the behavior for all extensions, overriding all |
| previously issued <strong>extension</strong> directives, but only for the <em>behaviors</em> |
| <strong>warn</strong> and <strong>disable</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The initial state of the compiler is as if the directive</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> all : disable</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>was issued, telling the compiler that all error and warning reporting must |
| be done according to this specification, ignoring any extensions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Each extension can define its allowed granularity of scope. |
| If nothing is said, the granularity is a shader (that is, a single |
| compilation unit), and the extension directives must occur before any |
| non-preprocessor tokens. |
| If necessary, the linker can enforce granularities larger than a single |
| compilation unit, in which case each involved shader will have to contain |
| the necessary extension directive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Macro expansion is not done on lines containing <strong>#extension</strong> and <strong>#version</strong> |
| directives.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For each extension there is an associated macro. |
| The macro is always defined in an implementation that supports the |
| extension. |
| This allows the following construct to be used:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#ifdef</span> OES_extension_name |
| <span class="preprocessor">#extension</span> OES_extension_name : enable |
| <span class="comment">// code that requires the extension</span> |
| <span class="preprocessor">#else</span> |
| <span class="comment">// alternative code</span> |
| <span class="preprocessor">#endif</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>#line</strong> must have, after macro substitution, one of the following forms:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#line</span> line |
| <span class="preprocessor">#line</span> line source-<span class="predefined-type">string</span>-number</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>line</em> and <em>source-string-number</em> are |
| <em>pp-constant-expressions</em>. |
| If these constant expressions are not integer literals then behavior is undefined. |
| After processing this directive (including its new-line), the implementation |
| will behave as if it is compiling at line number <em>line</em> and source string |
| number <em>source-string-number</em>. |
| Subsequent source strings will be numbered sequentially, until another |
| <strong>#line</strong> directive overrides that numbering.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="title">Note</div> |
| <div class="paragraph"> |
| <p>Some implementations have allowed constant expressions in #line directives and |
| some have not. Even where expressions are supported the grammar is ambiguous and so |
| results are implementation dependent. For example, |
| + #line +2 +2 // Line number set to 4, or file to 2 and line to 2</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, the following predefined macro is available:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> VULKAN <span class="integer">100</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If during macro expansion a preprocessor directive is encountered, the |
| results are undefined; the compiler may or may not report an error in such |
| cases.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="comments">3.5. Comments</h3> |
| <div class="paragraph"> |
| <p>Comments are delimited by <strong>/*</strong> and <strong>*/</strong>, or by <strong>//</strong> and a new-line. |
| // style comments include the initial // marker and continue up to, but |
| not including, the terminating newline. |
| /*...*/ comments include both the start and end marker. |
| The begin comment delimiters (/* or //) are not recognized as comment |
| delimiters inside of a comment, hence comments cannot be nested. |
| Comments are treated syntactically as a single space.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="tokens">3.6. Tokens</h3> |
| <div class="paragraph"> |
| <p>The language, after preprocessing, is a sequence of tokens. |
| A token can be</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>token</em> : </dt> |
| <dd> |
| <p><em>keyword</em><br> |
| <em>identifier</em><br> |
| <em>integer-constant</em><br> |
| <em>floating-constant</em><br> |
| <em>operator</em><br> |
| <strong>;</strong> <strong>{</strong> <strong>}</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="keywords">3.7. Keywords</h3> |
| <div class="paragraph"> |
| <p>The following are the keywords in the language and (after |
| preprocessing) can only be used as described in this specification, |
| or an error results:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>const</strong> <strong>uniform</strong> <strong>buffer</strong> <strong>shared</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>coherent</strong> <strong>volatile</strong> <strong>restrict</strong> <strong>readonly</strong> <strong>writeonly</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>atomic_uint</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>layout</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>centroid</strong> <strong>flat</strong> <strong>smooth</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>patch</strong> <strong>sample</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>invariant</strong> <strong>precise</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>break</strong> <strong>continue</strong> <strong>do</strong> <strong>for</strong> <strong>while</strong> <strong>switch</strong> <strong>case</strong> <strong>default</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>if</strong> <strong>else</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>in</strong> <strong>out</strong> <strong>inout</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>int</strong> <strong>void</strong> <strong>bool</strong> <strong>true</strong> <strong>false</strong> <strong>float</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>discard</strong> <strong>return</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>vec2</strong> <strong>vec3</strong> <strong>vec4</strong> <strong>ivec2</strong> <strong>ivec3</strong> <strong>ivec4</strong> <strong>bvec2</strong> <strong>bvec3</strong> <strong>bvec4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>uint</strong> <strong>uvec2</strong> <strong>uvec3</strong> <strong>uvec4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>mat2</strong> <strong>mat3</strong> <strong>mat4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>mat2x2</strong> <strong>mat2x3</strong> <strong>mat2x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>mat3x2</strong> <strong>mat3x3</strong> <strong>mat3x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>mat4x2</strong> <strong>mat4x3</strong> <strong>mat4x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>lowp</strong> <strong>mediump</strong> <strong>highp</strong> <strong>precision</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler2D</strong> <strong>sampler2DShadow</strong> <strong>sampler2DArray</strong> <strong>sampler2DArrayShadow</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>isampler2D</strong> <strong>isampler2DArray</strong> <strong>usampler2D</strong> <strong>usampler2DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler2DMS</strong> <strong>isampler2DMS</strong> <strong>usampler2DMS</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler2DMSArray</strong> <strong>isampler2DMSArray</strong> <strong>usampler2DMSArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler3D</strong> <strong>isampler3D</strong> <strong>usampler3D</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>samplerCube</strong> <strong>samplerCubeShadow</strong> <strong>isamplerCube</strong> <strong>usamplerCube</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>samplerCubeArray</strong> <strong>samplerCubeArrayShadow</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>isamplerCubeArray</strong> <strong>usamplerCubeArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>samplerBuffer</strong> <strong>isamplerBuffer</strong> <strong>usamplerBuffer</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image2D</strong> <strong>iimage2D</strong> <strong>uimage2D</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image2DArray</strong> <strong>iimage2DArray</strong> <strong>uimage2DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image3D</strong> <strong>iimage3D</strong> <strong>uimage3D</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>imageCube</strong> <strong>iimageCube</strong> <strong>uimageCube</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>imageCubeArray</strong> <strong>iimageCubeArray</strong> <strong>uimageCubeArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>imageBuffer</strong> <strong>iimageBuffer</strong> <strong>uimageBuffer</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>struct</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>In addition, when targeting Vulkan, the following keywords also exist:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>texture2D</strong> <strong>texture2DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>itexture2D</strong> <strong>itexture2DArray</strong> <strong>utexture2D</strong> <strong>utexture2DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>texture2DMS</strong> <strong>itexture2DMS</strong> <strong>utexture2DMS</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>texture2DMSArray</strong> <strong>itexture2DMSArray</strong> <strong>utexture2DMSArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>texture3D</strong> <strong>itexture3D</strong> <strong>utexture3D</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>textureCube</strong> <strong>itextureCube</strong> <strong>utextureCube</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>textureCubeArray</strong> <strong>itextureCubeArray</strong> <strong>utextureCubeArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>textureBuffer</strong> <strong>itextureBuffer</strong> <strong>utextureBuffer</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler</strong> <strong>samplerShadow</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>subpassInput</strong> <strong>isubpassInput</strong> <strong>usubpassInput</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>subpassInputMS</strong> <strong>isubpassInputMS</strong> <strong>usubpassInputMS</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The following are the keywords reserved for future use. |
| Using them will result in an error:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>attribute</strong> <strong>varying</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>noperspective</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>subroutine</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>common</strong> <strong>partition</strong> <strong>active</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>asm</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>class</strong> <strong>union</strong> <strong>enum</strong> <strong>typedef</strong> <strong>template</strong> <strong>this</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>resource</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>goto</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>inline</strong> <strong>noinline</strong> <strong>public</strong> <strong>static</strong> <strong>extern</strong> <strong>external</strong> <strong>interface</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>long</strong> <strong>short</strong> <strong>half</strong> <strong>fixed</strong> <strong>unsigned</strong> <strong>superp</strong> |
| <strong>double</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>input</strong> <strong>output</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>hvec2</strong> <strong>hvec3</strong> <strong>hvec4</strong> <strong>fvec2</strong> <strong>fvec3</strong> <strong>fvec4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>dvec2</strong> <strong>dvec3</strong> <strong>dvec4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>dmat2</strong> <strong>dmat3</strong> <strong>dmat4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>dmat2x2</strong> <strong>dmat2x3</strong> <strong>dmat2x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>dmat3x2</strong> <strong>dmat3x3</strong> <strong>dmat3x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>dmat4x2</strong> <strong>dmat4x3</strong> <strong>dmat4x4</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>filter</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sizeof</strong> <strong>cast</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>namespace</strong> <strong>using</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler1D</strong> <strong>sampler1DShadow</strong> <strong>sampler1DArray</strong> <strong>sampler1DArrayShadow</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>isampler1D</strong> <strong>isampler1DArray</strong> <strong>usampler1D</strong> <strong>usampler1DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler2DRect</strong> <strong>sampler2DRectShadow</strong> <strong>isampler2DRect</strong> <strong>usampler2DRect</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>sampler3DRect</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image1D</strong> <strong>iimage1D</strong> <strong>uimage1D</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image1DArray</strong> <strong>iimage1DArray</strong> <strong>uimage1DArray</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image2DRect</strong> <strong>iimage2DRect</strong> <strong>uimage2DRect</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image2DMS</strong> <strong>iimage2DMS</strong> <strong>uimage2DMS</strong></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><strong>image2DMSArray</strong> <strong>iimage2DMSArray</strong> <strong>uimage2DMSArray</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>In addition, all identifiers containing two consecutive underscores (__) |
| are reserved for use by underlying software layers. |
| Defining such a name in a shader does not itself result in an error, but may |
| result in unintended behaviors that stem from having multiple definitions of |
| the same name.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="identifiers">3.8. Identifiers</h3> |
| <div class="paragraph"> |
| <p>Identifiers are used for variable names, function names, structure names, |
| and field selectors (field selectors select components of |
| <code><a href="#vector-components">vectors</a></code> and <code><a href="#matrix-components">matrices</a></code>, |
| similarly to structure members). |
| Identifiers have the form:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>identifier</em> : </dt> |
| <dd> |
| <p><em>nondigit</em><br> |
| <em>identifier</em> <em>nondigit</em><br> |
| <em>identifier</em> <em>digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>nondigit</em> : one of </dt> |
| <dd> |
| <p><strong>_</strong> <strong>a b c d e f g h i j k l m n o p q r s t u v w x y z</strong><br> |
| <strong>A B C D E F G H I J K L M N O P Q R S T U V W X Y Z</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>digit</em> : one of </dt> |
| <dd> |
| <p><strong>0 1 2 3 4 5 6 7 8 9</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Identifiers starting with “gl_” are reserved, and |
| in general, may not be declared in a shader; |
| this results in an error. |
| However, as noted in the specification, there are some cases where |
| previously declared variables can be redeclared, and predeclared “gl_” |
| names are allowed to be redeclared in a shader only for these specific |
| purposes.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Implementations must support identifier lengths of up to 1024 characters. |
| It is an error if the length exceeds this value.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="definitions">3.9. Definitions</h3> |
| <div class="paragraph"> |
| <p>Some language rules described below depend on the following definitions.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="static-use">3.9.1. Static Use</h4> |
| <div class="paragraph"> |
| <p>A shader contains a <em>static use</em> of a variable <em>x</em> if, after preprocessing, |
| the shader contains a statement that would access any part of <em>x</em>, |
| whether or not flow of control will cause that statement to be executed. |
| Such a variable is referred to as being <em>statically used</em>. If the access is a |
| write then <em>x</em> is further said to be <em>statically assigned</em>.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="uniform-and-non-uniform-control-flow">3.9.2. Uniform and Non-Uniform Control Flow</h4> |
| <div class="paragraph"> |
| <p>When executing statements in a fragment shader, control flow starts as |
| <em>uniform control flow</em>; all fragments enter the same control path into |
| <em>main()</em>. |
| Control flow becomes <em>non-uniform</em> when different fragments take different |
| paths through control-flow statements (selection, iteration, and jumps). |
| Control flow subsequently returns to being uniform after such divergent |
| sub-statements or skipped code completes, until the next time different |
| control paths are taken.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">main() |
| { |
| <span class="predefined-type">float</span> a = ...; <span class="comment">// this is uniform control flow</span> |
| <span class="keyword">if</span> (a < b) { <span class="comment">// this expression is true for some fragments, not all</span> |
| ...; <span class="comment">// non-uniform control flow</span> |
| } <span class="keyword">else</span> { |
| ...; <span class="comment">// non-uniform control flow</span> |
| } |
| ...; <span class="comment">// uniform control flow again</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Other examples of non-uniform control flow can occur within switch |
| statements and after conditional breaks, continues, early returns, and after |
| fragment discards, when the condition is true for some fragments but not |
| others. |
| Loop iterations that only some fragments execute are also non-uniform |
| control flow.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is similarly defined for other shader stages, based on the per-instance |
| data items they process.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="dynamically-uniform-expressions">3.9.3. Dynamically Uniform Expressions</h4> |
| <div class="paragraph"> |
| <p>A fragment-shader expression is <em>dynamically uniform</em> if all fragments |
| evaluating it get the same resulting value. |
| When loops are involved, this refers to the expression’s value for the same |
| loop iteration. |
| When functions are involved, this refers to calls from the same call point.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is similarly defined for other shader stages, based on the per-instance |
| data they process.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that constant expressions are trivially dynamically uniform. |
| It follows that typical loop counters based on these are also dynamically |
| uniform.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="logical-phases-of-compilation">3.10. Logical Phases of Compilation</h3> |
| <div class="paragraph"> |
| <p>The compilation units for the shader processors are processed separately |
| before optionally being linked together in the final stage of compilation. |
| The logical phases of compilation are:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>Source strings are input as byte sequences. |
| The value 'zero' is interpreted as a terminator.</p> |
| </li> |
| <li> |
| <p>Source strings are concatenated to form a single input. |
| Zero bytes are discarded but all other values are retained.</p> |
| </li> |
| <li> |
| <p>Each string is interpreted according to the UTF-8 standard, with the |
| exception that all invalid byte sequences are retained in their original |
| form for subsequent processing.</p> |
| </li> |
| <li> |
| <p>Each {carriage-return, line-feed} and {line-feed, carriage return} |
| sequence is replaced by a single newline. |
| All remaining carriage-return and line-feed characters are then each |
| replaced by a newline.</p> |
| </li> |
| <li> |
| <p>Line numbering for each character, which is equal to the number of |
| preceding newlines plus one, is noted. |
| Note this can only be subsequently changed by the #line directive and is |
| not affected by the removal of newlines in phase 6 of compilation.</p> |
| </li> |
| <li> |
| <p>Wherever a backslash ('\') occurs immediately before a newline, both are |
| deleted. |
| Note that no whitespace is substituted, thereby allowing a single |
| preprocessing token to span a newline. |
| This operation is not recursive; any new {backslash newline} sequences |
| generated are not removed.</p> |
| </li> |
| <li> |
| <p>All comments are replaced with a single space. |
| All (non-zero) characters and invalid UTF-8 byte sequences are allowed |
| within comments. |
| '//' style comments include the initial '//' marker and continue up to, |
| but not including, the terminating newline. |
| '/<strong>…​</strong>/' comments include both the start and end marker.</p> |
| </li> |
| <li> |
| <p>The source string is converted into a sequence of preprocessing tokens. |
| These tokens include preprocessing numbers, identifiers and |
| preprocessing operations. |
| The line number associated with each token is copied from the line |
| number of the first character of the token.</p> |
| </li> |
| <li> |
| <p>The preprocessor is run. |
| Directives are executed and macro expansion is performed.</p> |
| </li> |
| <li> |
| <p>White space and newlines are discarded.</p> |
| </li> |
| <li> |
| <p>Preprocessing tokens are converted into tokens.</p> |
| </li> |
| <li> |
| <p>The syntax is analyzed according to the GLSL ES grammar.</p> |
| </li> |
| <li> |
| <p>The result is checked according to the semantic rules of the language.</p> |
| </li> |
| <li> |
| <p>Optionally, the shaders are linked together to form one or more programs |
| or separable programs. |
| When a pair of shaders from consecutive stages are linked into the same |
| program, any outputs and corresponding inputs not used in both shaders |
| may be discarded.</p> |
| </li> |
| <li> |
| <p>The binary is generated.</p> |
| </li> |
| </ol> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="variables-and-types">4. Variables and Types</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>All variables and functions must be declared before being used. |
| Variable and function names are identifiers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are no default types. |
| All variable and function declarations must have a declared type, and |
| optionally qualifiers. |
| A variable is declared by specifying its type followed by one or more names |
| separated by commas. |
| In many cases, a variable can be initialized as part of its declaration by |
| using the assignment operator (<strong>=</strong>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>User-defined types may be defined using <strong>struct</strong> to aggregate a list of |
| existing types into a single name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language is type safe. |
| There are no implicit conversions between types.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="basic-types">4.1. Basic Types</h3> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">Definition</dt> |
| <dd> |
| <p>A <em>basic type</em> is a type defined by a keyword in the language.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language supports the following basic data types, grouped as follows.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Transparent Types</strong></p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>void</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">for functions that do not return a value</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bool</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a conditional type, taking on values of true or false</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a signed integer</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uint</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">an unsigned integer</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>float</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point scalar</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a two-component single-precision floating-point vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a three-component single-precision floating-point vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a four-component single-precision floating-point vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a two-component Boolean vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a three-component Boolean vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a four-component Boolean vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a two-component signed integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a three-component signed integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a four-component signed integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a two-component unsigned integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a three-component unsigned integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a four-component unsigned integer vector</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a 2 × 2 single-precision floating-point matrix</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a 3 × 3 single-precision floating-point matrix</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a 4 × 4 single-precision floating-point matrix</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat2</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 3 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 4 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 2 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat3</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 4 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x2</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 2 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x3</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 3 rows</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x4</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat4</strong></p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Note that where the following tables say “accessing a texture”, the |
| <strong>sampler*</strong> opaque types access textures, and the <strong>image*</strong> opaque types |
| access images, of a specified type.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Floating-Point Opaque Types</strong></p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2D</strong><br> |
| <strong>texture2D</strong><br> |
| <strong>image2D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DShadow</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D depth texture with comparison</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArray</strong><br> |
| <strong>texture2DArray</strong><br> |
| <strong>image2DArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArrayShadow</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array depth texture with comparison</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMS</strong><br> |
| <strong>texture2DMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMSArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler3D</strong><br> |
| <strong>texture3D</strong><br> |
| <strong>image3D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 3D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCube</strong><br> |
| <strong>textureCube</strong><br> |
| <strong>imageCube</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube mapped texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeShadow</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map depth texture with comparison</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArray</strong><br> |
| <strong>textureCubeArray</strong><br> |
| <strong>imageCubeArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArrayShadow</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array depth texture with comparison</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerBuffer</strong><br> |
| <strong>textureBuffer</strong><br> |
| <strong>imageBuffer</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a buffer texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>subpassInput</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a floating-point subpass input</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>subpassInputMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a multi-sampled floating-point subpass input</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p><strong>Signed Integer Opaque Types</strong></p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2D</strong><br> |
| <strong>itexture2D</strong><br> |
| <strong>iimage2D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DArray</strong><br> |
| <strong>itexture2DArray</strong><br> |
| <strong>iimage2DArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMS</strong><br> |
| <strong>itexture2DMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMSArray</strong><br> |
| <strong>itexture2DMSArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler3D</strong><br> |
| <strong>itexture3D</strong><br> |
| <strong>iimage3D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 3D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCube</strong><br> |
| <strong>itextureCube</strong><br> |
| <strong>iimageCube</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube mapped texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCubeArray</strong><br> |
| <strong>itextureCubeArray</strong><br> |
| <strong>iimageCubeArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube map array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerBuffer</strong><br> |
| <strong>itextureBuffer</strong><br> |
| <strong>iimageBuffer</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer buffer texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isubpassInput</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer subpass input</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isubpassInputMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a multi-sampled integer subpass input</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p><strong>Unsigned Integer Opaque Types</strong></p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2D</strong><br> |
| <strong>utexture2D</strong><br> |
| <strong>uimage2D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DArray</strong><br> |
| <strong>utexture1DArray</strong><br> |
| <strong>uimage2DArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMS</strong><br> |
| <strong>utexture2DMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMSArray</strong><br> |
| <strong>utexture2DMSArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler3D</strong><br> |
| <strong>utexture3D</strong><br> |
| <strong>uimage3D</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 3D texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCube</strong><br> |
| <strong>utextureCube</strong><br> |
| <strong>uimageCube</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube mapped texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCubeArray</strong><br> |
| <strong>utextureCubeArray</strong><br> |
| <strong>uimageCubeArray</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube map array texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerBuffer</strong><br> |
| <strong>utextureBuffer</strong><br> |
| <strong>uimageBuffer</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer buffer texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>atomic_uint</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer atomic counter</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usubpassInput</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned-integer subpass input</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usubpassInputMS</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a multi-sampled unsigned-integer subpass input</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p><strong>Sampler Opaque Types</strong></p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing state describing how to sample a texture</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerShadow</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing state describing how to sample a depth |
| texture with comparison</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>In addition, a shader can aggregate these basic types using arrays and |
| structures to build more complex types.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are no pointer types.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="void">4.1.1. Void</h4> |
| <div class="paragraph"> |
| <p>Functions that do not return a value must be declared as <strong>void</strong>. |
| There is no default function return type. |
| The keyword <strong>void</strong> cannot be used in any other declarations (except for |
| empty formal or actual parameter lists), or an error results.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="booleans">4.1.2. Booleans</h4> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">Definition</dt> |
| <dd> |
| <p>A <em>boolean type</em> is any boolean scalar or vector type (<strong>bool</strong>, <strong>bvec2</strong>, |
| <strong>bvec3</strong>, <strong>bvec4</strong>)</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>To make conditional execution of code easier to express, the type <strong>bool</strong> is |
| supported. |
| There is no expectation that hardware directly supports variables of this |
| type. |
| It is a genuine Boolean type, holding only one of two values meaning either |
| true or false. |
| Two keywords <strong>true</strong> and <strong>false</strong> can be used as literal Boolean constants. |
| Booleans are declared and optionally initialized as in the follow example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">bool</span> success; <span class="comment">// declare "success" to be a Boolean</span> |
| <span class="predefined-type">bool</span> done = <span class="predefined-constant">false</span>; <span class="comment">// declare and initialize "done"</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Expressions used for conditional jumps (<strong>if</strong>, <strong>for</strong>, <strong>?:</strong>, <strong>while</strong>, |
| <strong>do</strong>-<strong>while</strong>) must evaluate to the type <strong>bool</strong>.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="integers">4.1.3. Integers</h4> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">Definitions</dt> |
| <dd> |
| <p>An <em>integral type</em> is any signed or unsigned, scalar or vector integer type. |
| It excludes arrays and structures.</p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>A <em>scalar integral type</em> is a scalar signed or unsigned integer type:</p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>A <em>vector integral type</em> is a vector of signed or unsigned integers:</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>Signed and unsigned integer variables are fully supported. |
| In this document, the term <em>integer</em> is meant to generally include both |
| signed and unsigned integers.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>highp</strong> |
| unsigned integers have exactly 32 bits of precision.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>highp</strong> |
| signed integers use 32 bits, including a sign bit, in two’s complement form.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, <strong>mediump</strong> and <strong>lowp</strong> integers are as defined by the |
| SPIR-V <strong>RelaxedPrecision</strong> decoration. |
| Otherwise, <strong>mediump</strong> and <strong>lowp</strong> integers have implementation-defined numbers of bits. |
| See “<a href="#range-and-precision">Range and Precision</a>” for details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For all precisions, addition, |
| subtraction and multiplication resulting in overflow or |
| underflow will result in the low-order |
| n |
| bits of the correct result R, where |
| n is the size in bits of the integer and |
| R is computed with enough precision to avoid overflow or underflow. |
| Division resulting in overflow will result in an undefined value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Integers are declared and optionally initialized with integer expressions, |
| as in the following example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> i, j = <span class="integer">42</span>; <span class="comment">// default integer literal type is int</span> |
| uint k = <span class="integer">3</span>u; <span class="comment">// "u" establishes the type as uint</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Literal integer constants can be expressed in decimal (base 10), octal (base |
| 8), or hexadecimal (base 16) as follows.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>integer-constant</em> : </dt> |
| <dd> |
| <p><em>decimal-constant</em> <em>integer-suffix<sub>opt</sub></em><br> |
| <em>octal-constant</em> <em>integer-suffix<sub>opt</sub></em><br> |
| <em>hexadecimal-constant</em> <em>integer-suffix<sub>opt</sub></em></p> |
| </dd> |
| <dt class="hdlist1"><em>integer-suffix</em> : one of </dt> |
| <dd> |
| <p><strong>u</strong> <strong>U</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>decimal-constant</em> : </dt> |
| <dd> |
| <p><em>nonzero-digit</em><br> |
| <em>decimal-constant</em> <em>digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>octal-constant</em> : </dt> |
| <dd> |
| <p><strong>0</strong><br> |
| <em>octal-constant</em> <em>octal-digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>hexadecimal-constant</em> : </dt> |
| <dd> |
| <p><strong>0x</strong> <em>hexadecimal-digit</em><br> |
| <strong>0X</strong> <em>hexadecimal-digit</em><br> |
| <em>hexadecimal-constant</em> <em>hexadecimal-digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>digit</em> : </dt> |
| <dd> |
| <p><strong>0</strong><br> |
| <em>nonzero-digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>nonzero-digit</em> : one of </dt> |
| <dd> |
| <p><strong>1 2 3 4 5 6 7 8 9</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>octal-digit</em> : one of </dt> |
| <dd> |
| <p><strong>0 1 2 3 4 5 6 7</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>hexadecimal-digit</em> : one of </dt> |
| <dd> |
| <p><strong>0 1 2 3 4 5 6 7 8 9<br> |
| a b c d e f<br> |
| A B C D E F</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>No white space is allowed between the digits of an integer constant, |
| including after the leading <strong>0</strong> or after the leading <strong>0x</strong> or <strong>0X</strong> of a |
| constant, or before the suffix <strong>u</strong> or <strong>U</strong>. |
| When the suffix <strong>u</strong> or <strong>U</strong> is present, the literal has type <strong>uint</strong>, |
| otherwise the type is <strong>int</strong>. |
| A leading unary minus sign (-) is interpreted as an arithmetic unary |
| negation, not as part of the constant. |
| Hence, literals themselves are always expressed with non-negative syntax, |
| though they could result in a negative value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is an error to provide a literal integer whose bit pattern |
| cannot fit in 32 bits. |
| The bit pattern of the literal is always used unmodified. |
| So a signed literal whose bit pattern includes a set sign bit creates a |
| negative value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="integer">1</span> <span class="comment">// OK. Signed integer, value 1</span> |
| <span class="integer">1</span>u <span class="comment">// OK. Unsigned integer, value 1</span> |
| -<span class="integer">1</span> <span class="comment">// OK. Unary minus applied to signed integer.</span> |
| <span class="comment">// result is a signed integer, value -1</span> |
| -<span class="integer">1</span>u <span class="comment">// OK. Unary minus applies to unsigned integer.</span> |
| <span class="comment">// Result is an unsigned integer, value 0xffffffff</span> |
| <span class="hex">0xA0000000</span> <span class="comment">// OK. 32-bit signed hexadecimal</span> |
| <span class="hex">0xABcdEF00</span>u <span class="comment">// OK. 32-bit unsigned hexadecimal</span> |
| <span class="hex">0xffffffff</span> <span class="comment">// OK. Signed integer, value -1</span> |
| <span class="hex">0x80000000</span> <span class="comment">// OK. Evaluates to -2147483648</span> |
| <span class="hex">0xffffffff</span>u <span class="comment">// OK. Unsigned integer, value 0xffffffff</span> |
| <span class="hex">0xfffffffff</span> <span class="comment">// Error: needs more than 32 bits</span> |
| <span class="integer">3000000000</span> <span class="comment">// OK. A signed decimal literal taking 32 bits.</span> |
| <span class="comment">// It evaluates to -1294967296</span> |
| <span class="integer">2147483648</span> <span class="comment">// OK. Evaluates to -2147483648 (the literal set the sign bit)</span> |
| <span class="integer">5000000000</span> <span class="comment">// Error: needs more than 32 bits</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="floats">4.1.4. Floats</h4> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">Definition</dt> |
| <dd> |
| <p>A <em>floating-point type</em> is any floating-point scalar, vector or matrix type. |
| It excludes arrays and structures.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>Floats are available for use in a variety of scalar calculations. |
| Floating-point variables are defined as in the following example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a, b = <span class="float">1</span><span class="float">.5</span>;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>As an input value to one of the processing units, a floating-point variable |
| is expected to match the IEEE 754 single precision floating-point definition |
| for precision and dynamic range. |
| <strong>highp</strong> floating-point variables within a shader are encoded according to |
| the IEEE 754 specification for single-precision floating-point values |
| (logically, not necessarily physically). |
| While encodings are logically IEEE 754, operations (addition, |
| multiplication, etc.) are not necessarily performed as required by IEEE 754. |
| See “<a href="#range-and-precision">Range and Precision</a>” for more details on |
| precision and usage of NaNs (Not a Number) and Infs (positive or negative |
| infinities).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Floating-point constants are defined as follows.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>floating-constant</em> : </dt> |
| <dd> |
| <p><em>fractional-constant</em> <em>exponent-part<sub>opt</sub></em> <em>floating-suffix<sub>opt</sub></em><br> |
| <em>digit-sequence</em> <em>exponent-part</em> <em>floating-suffix<sub>opt</sub></em></p> |
| </dd> |
| <dt class="hdlist1"><em>fractional-constant</em> : </dt> |
| <dd> |
| <p><em>digit-sequence</em> <strong>.</strong> <em>digit-sequence</em><br> |
| <em>digit-sequence</em> <strong>.</strong><br> |
| <strong>.</strong> <em>digit-sequence</em></p> |
| </dd> |
| <dt class="hdlist1"><em>exponent-part</em> : </dt> |
| <dd> |
| <p><strong>e</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em><br> |
| <strong>E</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em></p> |
| </dd> |
| <dt class="hdlist1"><em>sign</em> : one of </dt> |
| <dd> |
| <p><strong>+</strong> <strong>-</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>digit-sequence</em> : </dt> |
| <dd> |
| <p><em>digit</em><br> |
| <em>digit-sequence</em> <em>digit</em></p> |
| </dd> |
| <dt class="hdlist1"><em>floating-suffix</em> : one of </dt> |
| <dd> |
| <p><strong>f</strong> <strong>F</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A decimal point (<strong>.</strong>) is not needed if the exponent part is present. |
| No white space may appear anywhere within a floating-point constant, |
| including before a suffix. |
| A leading unary minus sign (<strong>-</strong>) is interpreted as a unary operator and is |
| not part of the floating-point constant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is no limit on the number of digits in any <em>digit-sequence</em>. |
| If the value of the floating-point number is too large (small) to be stored |
| as a single precision value, it is converted to positive (negative) |
| infinity. |
| A value with a magnitude too small to be represented as a mantissa and |
| exponent is converted to zero. |
| Implementations may also convert subnormal (denormalized) numbers to zero.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="vectors">4.1.5. Vectors</h4> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language includes data types for generic 2-, 3-, and 4-component vectors |
| of floating-point values, integers, and Booleans. |
| Floating-point vector variables can be used to store colors, normals, |
| positions, texture coordinates, texture lookup results and the like. |
| Boolean vectors can be used for component-wise comparisons of numeric |
| vectors. |
| Some examples of vector declarations are:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec2 texcoord1, texcoord2; |
| vec3 position; |
| vec4 myRGBA; |
| ivec2 textureLookup; |
| bvec3 less;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Initialization of vectors can be done with constructors. |
| See “<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>”.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="matrices">4.1.6. Matrices</h4> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language has built-in types for 2 × 2, 2 × 3, 2 × 4, 3 |
| × 2, 3 × 3, 3 × 4, 4 × 2, 4 × 3, and 4 × |
| 4 matrices of floating-point numbers. |
| The first number in the type is the number of columns, the second is the |
| number of rows. |
| If there is only one number, the matrix is square. |
| Example matrix declarations:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat2 mat2D; |
| mat3 optMatrix; |
| mat4 view, projection; |
| mat4x4 view; <span class="comment">// an alternate way of declaring a mat4</span> |
| mat3x2 m; <span class="comment">// a matrix with 3 columns and 2 rows</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Initialization of matrix values is done with constructors (described in |
| “<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>”) in |
| column-major order.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>mat2</strong> is an alias for <strong>mat2x2</strong>, not a distinct type. |
| Similarly for <strong>mat3</strong> and <strong>mat4.</strong> The following is legal:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat2 a; |
| mat2x2 b = a;</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="opaque-types">4.1.7. Opaque Types</h4> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">Definition</dt> |
| <dd> |
| <p>An <em>opaque type</em> is a type where the internal structure of the type is |
| hidden from the language.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The opaque types, as listed in the following sections, declare variables |
| that are effectively opaque handles to other objects. |
| These objects are accessed through built-in functions, not through direct |
| reading or writing of the declared variable. |
| They can only be declared as function parameters or in <strong>uniform</strong>-qualified |
| variables (see “<a href="#uniform-variables">Uniform Variables</a>”). |
| The only opaque types that take memory qualifiers are the image types. |
| Except for array indexing, structure member selection, and parentheses, |
| opaque variables are not allowed to be operands in expressions; such use |
| results in a compile-time error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When aggregated into arrays within a shader, opaque types can only be |
| indexed with a dynamically uniform integral expression (see “Dynamically |
| Uniform Expressions”) unless otherwise noted; otherwise, results are |
| undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Opaque variables cannot be treated as l-values; hence cannot be used as |
| <strong>out</strong> or <strong>inout</strong> function parameters, nor can they be assigned into. |
| Any such use results in a compile-time error. |
| However, they can be passed as <strong>in</strong> parameters with matching types and |
| memory qualifiers. |
| They cannot be declared with an initializer.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Because a single opaque type declaration effectively declares two objects, |
| the opaque handle itself and the object it is a handle to, there is room for |
| both a storage qualifier and a memory qualifier. |
| The storage qualifier will qualify the opaque handle, while the memory |
| qualifier will qualify the object it is a handle to.</p> |
| </div> |
| <div class="sect4"> |
| <h5 id="samplers">Texture-Combined Samplers</h5> |
| <div class="paragraph"> |
| <p>Texture-combined sampler types (e.g. <strong>sampler2D</strong>) are the sampler types |
| described in the Basic Types tables as handles for accessing textures. |
| (They do not include <strong>sampler</strong> and <strong>samplerShadow</strong>.) |
| There are distinct texture-combined sampler types for each texture target, |
| and for each of float, integer, and unsigned integer data types. |
| Texture accesses are done through built-in texture functions (described in |
| “<a href="#texture-functions">Texture Functions</a>”) and texture-combined samplers |
| are used to specify which texture to access and how it is to be filtered.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Texture-combined sampler types are opaque types, |
| declared and behaving as described above for opaque types.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="images">Images</h5> |
| <div class="paragraph"> |
| <p>Image types are opaque types, declared and behaving as described above for |
| opaque types. |
| They can be further qualified with memory qualifiers. |
| When aggregated into arrays within a shader, images can only be indexed with |
| a constant integral expression.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Image variables are handles to |
| two-, or three-dimensional images |
| corresponding to all or a portion of a single level of a texture image bound |
| to an image unit. |
| There are distinct image variable types for each texture target, and for |
| each of float, integer, and unsigned integer data types. |
| Image accesses should use an image type that matches the target of the |
| texture whose level is bound to the image unit, or for non-layered bindings |
| of 3D or array images should use the image type that matches the |
| dimensionality of the layer of the image (i.e., a layer of 3D, 2DArray, |
| Cube, or CubeArray should use |
| <strong>image2D</strong>). |
| If the image target type does not match the bound image in this manner, if |
| the data type does not match the bound image, or if the format layout |
| qualifier does not match the image unit format as described in section |
| 8.22 |
| “Texture Image Loads and Stores” of the <a href="#references">OpenGL ES Specification</a>, the |
| results of image accesses are undefined but cannot include program |
| termination.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Image variables are used in the image load, store, and atomic functions |
| described in “<a href="#image-functions">Image Functions</a>” to specify an image to |
| access.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="atomic-counters">Atomic Counters</h5> |
| <div class="paragraph"> |
| <p>Atomic counter types (e.g. <strong>atomic_uint</strong>) are opaque handles to counters, |
| declared and behaving as described above for opaque types. |
| The variables they declare specify which counter to access when using the |
| built-in atomic counter functions as described in |
| “<a href="#atomic-counter-functions">Atomic Counter Functions</a>”. |
| They are bound to buffers as described in |
| “<a href="#atomic-counter-layout-qualifiers">Atomic Counter Layout Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic counters aggregated into arrays within a shader can only be indexed |
| with dynamically uniform integral expressions, otherwise results are |
| undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Members of structures cannot be declared as atomic counter types.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The default precision of all atomic types is <strong>highp</strong>. |
| It is an error to declare an atomic type with a different precision or to |
| specify the default precision for an atomic type to be <strong>lowp</strong> or <strong>mediump</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic counter types are not available when targeting Vulkan.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_texture_sampler_and_samplershadow_types">Texture, <strong>sampler</strong>, and <strong>samplerShadow</strong> Types</h5> |
| <div class="paragraph"> |
| <p>Texture (e.g., <strong>texture2D</strong>), <strong>sampler</strong>, and <strong>samplerShadow</strong> types are opaque |
| types, declared and behaving as described above for opaque types. |
| These types are only available when targeting Vulkan. |
| When aggregated into arrays within a shader, these types can only be indexed |
| with a dynamically uniform expression, or texture lookup will result in |
| undefined values. |
| Texture variables are handles to one-, two-, and three-dimensional textures, |
| cube maps, etc., as enumerated in the basic types tables. |
| There are distinct texture types for each texture target, and for each of |
| float, integer, and unsigned integer data types. |
| Textures can be combined with a variable of type <strong>sampler</strong> or <strong>samplerShadow</strong> |
| to create a texture-combined sampler type (e.g., sampler2D, or sampler2DShadow). |
| This is done with a constructor, e.g., <code>sampler2D(texture2D, sampler)</code>, |
| <code>sampler2DShadow(texture2D, sampler)</code>, <code>sampler2DShadow(texture2D, samplerShadow)</code>, |
| or <code>sampler2D(texture2D, samplerShadow)</code> and is described in more detail |
| in section 5.4 "Constructors".</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_subpass_inputs">Subpass Inputs</h5> |
| <div class="paragraph"> |
| <p>Subpass-input types are only available when targeting Vulkan.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass-input types (e.g., <strong>subpassInput</strong>) are opaque types, declared |
| and behaving as described above for opaque types. |
| When aggregated into arrays within a shader, they can only be indexed with a |
| dynamically uniform integral expression, otherwise results are undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass-input types are handles to two-dimensional single sampled or |
| multi-sampled images, with distinct types for each of float, integer, |
| and unsigned integer data types.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass-input types are only available in fragment shaders. It is |
| an error to use them in any other stage.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="structures">4.1.8. Structures</h4> |
| <div class="paragraph"> |
| <p>User-defined types can be created by aggregating other already defined types |
| into a structure using the <strong>struct</strong> keyword. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light { |
| <span class="predefined-type">float</span> intensity; |
| vec3 position; |
| } lightVar;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In this example, <em>light</em> becomes the name of the new type, and <em>lightVar</em> |
| becomes a variable of type <em>light</em>. |
| To declare variables of the new type, use its name (without the keyword |
| <strong>struct</strong>).</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">light lightVar2;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>More formally, structures are declared as follows. |
| However, the definitive grammar is as given in |
| “<a href="#shading-language-grammar">Shading Language Grammar</a>”.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>struct-definition</em> : </dt> |
| <dd> |
| <p><em>qualifier<sub>opt</sub></em> <strong>struct</strong> name<sub>opt</sub>_ <strong>{</strong> <em>member-list</em> <strong>}</strong> |
| <em>declarators<sub>opt</sub></em> <strong>;</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>member-list</em> : </dt> |
| <dd> |
| <p><em>member-declaration</em> <strong>;</strong><br> |
| <em>member-declaration</em> <em>member-list</em> <strong>;</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>member-declaration</em> : </dt> |
| <dd> |
| <p><em>basic-type</em> <em>declarators</em> <strong>;</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>name</em> becomes the user-defined type, and can be used to declare |
| variables to be of this new type. |
| The <em>name</em> shares the same name space as other variables, types, and |
| functions. |
| All previously visible variables, types, constructors, or functions with |
| that name are hidden. |
| The optional <em>qualifier</em> only applies to any <em>declarators</em>, and is not part |
| of the type being defined for <em>name</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Structures must have at least one member declaration. |
| Member declarators may contain precision qualifiers, but use of any other |
| qualifier results in an error. |
| Bit fields are not supported. |
| Member types must be already defined (there are no forward references). |
| Member declarations cannot contain initializers. |
| Member declarators can contain arrays. |
| Such arrays must have a size specified, and the size must be a constant |
| integral expression that’s greater than zero (see |
| “<a href="#constant-expressions">Constant Expressions</a>”). |
| Each level of structure has its own name space for names given in member |
| declarators; such names need only be unique within that name space.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Anonymous structures are not supported. |
| Embedded structure definitions are not supported.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S { <span class="predefined-type">float</span> f; }; <span class="comment">// Allowed: S is defined as a structure.</span> |
| |
| <span class="keyword">struct</span> T { |
| S; <span class="comment">// Error: anonymous structures disallowed</span> |
| <span class="keyword">struct</span> { ... }; <span class="comment">// Error: embedded structures disallowed</span> |
| S s; <span class="comment">// Allowed: nested structure with a name.</span> |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Structures can be initialized at declaration time using constructors, as |
| discussed in “<a href="#structure-constructors">Structure Constructors</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any restrictions on the usage of a type or qualifier also apply to any |
| structure that contains a member of that type or qualifier. |
| This also applies to structure members that are structures, recursively.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Structures can contain variables of any type except:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>atomic_uint</strong> (since there is no mechanism to specify the binding)</p> |
| </li> |
| <li> |
| <p>image types (since there is no mechanism to specify the format |
| qualifier)</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="arrays">4.1.9. Arrays</h4> |
| <div class="paragraph"> |
| <p>Variables of the same type can be aggregated into arrays by declaring a name |
| followed by brackets (<strong>[ ]</strong>) enclosing an optional size.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When present, the array size must be a constant integral expression (see |
| “<a href="#constant-expressions">Constant Expressions</a>”) greater than zero. |
| The type of the size parameter can be a signed or unsigned integer and the |
| choice of type does not affect the type of the resulting array. |
| Arrays only have a single dimension (a single number within “[ ]”), |
| however, arrays of arrays can be declared. |
| Any type can be formed into an array.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays are sized either at compile-time or at run-time. |
| To size an array at compile-time, either the size must be specified within |
| the brackets as above or must be inferred from the type of the initializer.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an array is declared as the last member of a shader storage block and the |
| size is not specified at compile-time, it is sized at run-time. |
| In all other cases, arrays are sized only at compile-time. |
| An array declaration sized at compile-time which leaves the size of the |
| array unspecified is an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For compile-time sized arrays, it is illegal to index an array with a |
| constant integral expression greater than or equal to the declared size or |
| with a negative constant expression. |
| Arrays declared as formal parameters in a function declaration must also |
| specify a size. |
| Undefined behavior results from indexing an array with a non-constant |
| expression that’s greater than or equal to the array’s size or less than 0. |
| If robust buffer access is enabled (see section 10.3.5 “Robust Buffer |
| Access” of the <a href="#references">OpenGL ES Specification</a>), such indexing must not result in |
| abnormal program termination. |
| The results are still undefined, but implementations are encouraged to |
| produce zero values for such accesses.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Some examples are:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> frequencies[<span class="integer">3</span>]; |
| uniform vec4 lightPosition[<span class="integer">4</span>u]; |
| <span class="directive">const</span> <span class="predefined-type">int</span> numLights = <span class="integer">2</span>; |
| light lights[numLights]; |
| vec4 a[<span class="integer">3</span>][<span class="integer">2</span>]; |
| a.length() <span class="comment">// this is 3</span> |
| a[x].length() <span class="comment">// this is 2</span> |
| <span class="comment">// a shader storage block, introduced in section 4.3.7 "Buffer Variables"</span> |
| buffer b { |
| <span class="predefined-type">float</span> u[]; <span class="comment">// an error</span> |
| vec4 v[]; <span class="comment">// okay, v will be sized at run-time</span> |
| } name[<span class="integer">3</span>]; <span class="comment">// when the block is arrayed, all u will be the same size,</span> |
| <span class="comment">// but not necessarily all v, if sized dynamically</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When the <strong>length</strong>() method will return a compile-time constant, the |
| expression in brackets (x above) will be evaluated and subject to the rules |
| required for array indices, but the array will not be dereferenced. |
| Thus, behavior is well defined even if the run-time value of the expression |
| is out of bounds.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An array type can be formed by specifying a non-array type |
| (<a href="#type_specifier_nonarray">[type_specifier_nonarray]</a>) followed by an <a href="#array_specifier">[array_specifier]</a>.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>]</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the construct <em>type [size]</em> does not always result in an array of |
| length <em>size</em> of type <em>type</em>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">2</span>][<span class="integer">3</span>] <span class="comment">// an array of size [2] of array of size [3] of float,</span> |
| <span class="comment">// not size [3] of float[2]</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This type can be used anywhere any other type can be used, including as the |
| return value from a function</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] foo() { }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>as a constructor of an array:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>as an unnamed parameter:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> foo(<span class="predefined-type">float</span>[<span class="integer">5</span>])</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and as an alternate way of declaring a variable or function parameter:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] a;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>An array type can also be formed without specifying a size if the definition |
| includes an initializer:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> x[] = <span class="predefined-type">float</span>[<span class="integer">2</span>] (<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>); <span class="comment">// declares an array of size 2</span> |
| <span class="predefined-type">float</span> y[] = <span class="predefined-type">float</span>[] (<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>); <span class="comment">// declares an array of size 3</span> |
| <span class="predefined-type">float</span> a[<span class="integer">5</span>]; |
| <span class="predefined-type">float</span> b[] = a;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the initializer itself does not need to be a constant expression |
| but the length of the initializer will be a constant expression.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays can have initializers formed from array constructors:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>); |
| <span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>); <span class="comment">// same thing</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>An array of arrays can be declared as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 a[<span class="integer">3</span>][<span class="integer">2</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>which declares a one-dimensional array of size 3 of one-dimensional arrays |
| of size 2 of <strong>vec4</strong>. |
| The following declarations do the same thing:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4[<span class="integer">2</span>] a[<span class="integer">3</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span> |
| vec4[<span class="integer">3</span>][<span class="integer">2</span>] a; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When in transparent memory (like in a uniform block), the layout is that the |
| inner-most (right-most in declaration) dimensions iterate faster than the |
| outer dimensions. |
| That is, for the above, the order in memory would be:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>Low address : a[0][0] : a[0][1] : a[1][0] : a[1][1] : a[2][0] : a[2][1] |
| : High address</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The last member of a shader storage block (see “<a href="#buffer-variables">Buffer |
| Variables</a>”), may be declared without specifying a size. |
| For such arrays, the effective array size is inferred at run-time from the |
| size of the data store backing the shader storage block. |
| Such runtime-sized arrays may be indexed with general integer expressions, |
| but may not be passed as an argument to a function or indexed with a |
| negative constant expression.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S { <span class="predefined-type">float</span> f; }; |
| buffer ShaderStorageBlock1 |
| { |
| vec4 a[]; <span class="comment">// illegal</span> |
| vec4 b[]; <span class="comment">// legal, runtime-sized arrays are last member</span> |
| }; |
| buffer ShaderStorageBlock2 |
| { |
| vec4 a[<span class="integer">4</span>]; <span class="comment">// legal, size declared</span> |
| S b[]; <span class="comment">// legal, runtime-sized arrays are allowed,</span> |
| <span class="comment">// including arrays of structures</span> |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>However, it is a compile-time error to assign to a runtime-sized array. |
| Assignments to individual elements of the array is allowed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays have a fixed number of elements. |
| This can be obtained by using the <strong>length</strong>() method:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>]; |
| a.length(); <span class="comment">// returns 5</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The return value is a signed integral expression. |
| For compile-time sized arrays, the value returned by the length method is a |
| constant expression. |
| For run-time sized arrays , the value returned will not be constant |
| expression and will be determined at run time based on the size of the |
| buffer object providing storage for the block.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The precision is determined using the same rules as for other cases where |
| there is no intrinsic precision. |
| See “<a href="#precision-qualifiers">Precision Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any restrictions on the usage of a type also apply to arrays of that type. |
| This applies recursively.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="scoping">4.2. Scoping</h3> |
| <div class="paragraph"> |
| <p>The scope of a declaration determines where the declaration is visible. |
| GLSL ES uses a system of statically nested scopes. |
| This allows names to be redefined within a shader.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="definition-of-terms">4.2.1. Definition of Terms</h4> |
| <div class="paragraph"> |
| <p>The term <em>scope</em> refers to a specified region of the program where names are |
| guaranteed to be visible. |
| For example, a <em>compound_statement_with_scope</em> ('{' <em>statement</em> <em>statement</em> |
| …​ |
| '}') defines a scope.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>nested scope</em> is a scope defined within an outer scope.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The terms '<em>same scope'</em> and '<em>current scope</em>' are equivalent to the term |
| '<em>scope</em>' but used to emphasize that nested scopes are excluded.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>scope of a declaration</em> is the region or regions of the program where |
| that declaration is visible.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>name space</em> defines where names may be defined. |
| Within a single name space, a name has at most one entry, specifying it to |
| be one of: structure, variable, or function.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In general, each scope has an associated name space. |
| However, in certain cases e.g. for uniforms, multiple scopes share the same |
| name space. |
| In these cases, conflicting declarations are an error, even though the name |
| is only visible in the scopes where it is declared.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="types-of-scope">4.2.2. Types of Scope</h4> |
| <div class="paragraph"> |
| <p>The scope of a variable is determined by where it is declared. |
| If it is declared outside all function definitions, it has global scope, |
| which starts from where it is declared and persists to the end of the shader |
| it is declared in. |
| If it is declared in a <strong>while</strong> test or a <strong>for</strong> statement, then it is scoped |
| to the end of the following sub-statement (specified as |
| <em>statement-no-new-scope</em> in the grammar). |
| Otherwise, if it is declared as a statement within a compound statement, it |
| is scoped to the end of that compound statement. |
| If it is declared as a parameter in a function definition, it is scoped |
| until the end of that function definition. |
| A function’s parameter declarations and body together form a single scope.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> f( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> k) |
| { |
| <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// redeclaration error of the name k</span> |
| ... |
| } |
| <span class="predefined-type">int</span> f(<span class="predefined-type">int</span> k) |
| { |
| { |
| <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// 2nd k is parameter, initializing nested first k</span> |
| <span class="predefined-type">int</span> m = k <span class="comment">// use of new k, which is hiding the parameter</span> |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For both for and while loops, the sub-statement itself does not introduce a |
| new scope for variable names, so the following has a redeclaration |
| compile-time error:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> ( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> i = <span class="integer">0</span>; i < <span class="integer">10</span>; i++) |
| { |
| <span class="predefined-type">int</span> i; <span class="comment">// redeclaration error</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The body of a <strong>do</strong>-<strong>while</strong> loop introduces a new scope lasting only between |
| the do and while (not including the while test expression), whether or not |
| the body is simple or compound:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> _i_ = <span class="integer">17</span>; |
| <span class="keyword">do</span> |
| <span class="predefined-type">int</span> i = <span class="integer">4</span>; <span class="comment">// okay, in nested scope</span> |
| <span class="keyword">while</span> (i == <span class="integer">0</span>); <span class="comment">// i is 17, scoped outside the do-while body</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The statement following a <strong>switch</strong> (…​) forms a nested scope.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Representing the if construct as:</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>if</strong> if-expression <strong>then</strong> if-statement <strong>else</strong> else-statement,</p> |
| </div> |
| <div class="paragraph"> |
| <p>a variable declared in the if-statement is scoped to the end of the |
| if-statement. |
| A variable declared in the else-statement is scoped to the end of the |
| else-statement. |
| This applies both when these statements are simple statements and when they |
| are compound statements. |
| The if-expression does not allow new variables to be declared, hence does |
| not form a new scope.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Within a declaration, the scope of a name starts immediately after the |
| initializer if present or immediately after the name being declared if not. |
| Several examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x = <span class="integer">1</span>; |
| { |
| <span class="predefined-type">int</span> x = <span class="integer">2</span>,<span class="comment">/* 2nd x visible here */</span> y = x; <span class="comment">// y is initialized to 2</span> |
| <span class="predefined-type">int</span> z = z; <span class="comment">// error if z not previously defined.</span> |
| } |
| { |
| <span class="predefined-type">int</span> x = x; <span class="comment">// x is initialized to '1'</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A structure name declaration is visible at the end of the <em>struct_specifier</em> |
| in which it was declared:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S |
| { |
| <span class="predefined-type">int</span> x; |
| }; |
| { |
| S S = S(<span class="integer">0</span>); <span class="comment">// 'S' is only visible as a struct and constructor</span> |
| S; <span class="comment">// 'S' is now visible as a variable</span> |
| } |
| <span class="predefined-type">int</span> x = x; <span class="comment">// Error if x has not been previously defined.</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="redeclaring-names">4.2.3. Redeclaring Names</h4> |
| <div class="paragraph"> |
| <p>All variable names, structure type names, and function names in a given |
| scope share the same name space. |
| Function names can be redeclared in the same scope, with the same or |
| different parameters, without error. |
| Otherwise, within a shader, a declared name cannot be redeclared in the same |
| scope; doing so results in a redeclaration error. |
| If a nested scope redeclares a name used in an outer scope, it hides all |
| existing uses of that name. |
| There is no way to access the hidden name or make it unhidden, without |
| exiting the scope that hid it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Names of built-in functions cannot be redeclared as functions. |
| Therefore overloading or redefining built-in functions is an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>declaration</em> is considered to be a statement that adds a name or |
| signature to the symbol table. |
| A <em>definition</em> is a statement that fully defines that name or signature. |
| E.g.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> f();<span class="comment">// declaration;</span> |
| <span class="predefined-type">int</span> f() {<span class="keyword">return</span> <span class="integer">0</span>;}<span class="comment">// declaration and definition</span> |
| <span class="predefined-type">int</span> x; <span class="comment">// declaration and definition</span> |
| <span class="predefined-type">int</span> a[<span class="integer">4</span>];<span class="comment">// array declaration and definition</span> |
| <span class="keyword">struct</span> S {<span class="predefined-type">int</span> x;};<span class="comment">// structure declaration and definition</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The determination of equivalence of two declarations depends on the type of |
| declaration. |
| For functions, the whole function signature must be considered (see |
| “Function Definitions”). |
| For variables (including arrays) and structures only the names must match.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Within each scope, a name may be declared either as a variable declaration |
| <em>or</em> as function declarations <em>or</em> as a structure.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Examples of combinations that are allowed:</p> |
| </div> |
| <div class="paragraph"> |
| <p>1.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>) {...} |
| <span class="directive">void</span> f(<span class="predefined-type">float</span>) {...}<span class="comment">// function overloading allowed</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>2.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>);<span class="comment">// 1^st^ declaration (allowed)</span> |
| <span class="directive">void</span> f(<span class="predefined-type">int</span>);<span class="comment">// repeated declaration (allowed)</span> |
| <span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}<span class="comment">// single definition (allowed)</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Examples of combinations that are disallowed:</p> |
| </div> |
| <div class="paragraph"> |
| <p>1.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>) {...} |
| <span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}<span class="comment">// Error: repeated definition</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>2.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>); |
| <span class="keyword">struct</span> f {<span class="predefined-type">int</span> x;};<span class="comment">// Error: type 'f' conflicts with function 'f'</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>3.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> f {<span class="predefined-type">int</span> x;}; |
| <span class="predefined-type">int</span> f;<span class="comment">// Error: conflicts with the type 'f'</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>4.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> a[<span class="integer">3</span>]; |
| <span class="predefined-type">int</span> a[<span class="integer">3</span>];<span class="comment">// Error: repeated array definition</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>5.</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x; |
| <span class="predefined-type">int</span> x;<span class="comment">// Error: repeated variable definition</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="global-scope">4.2.4. Global Scope</h4> |
| <div class="paragraph"> |
| <p>The built-in functions are scoped in the global scope users declare global |
| variables in. |
| That is, a shader’s global scope, available for user-defined functions and |
| global variables, is the same as the scope containing the built-in |
| functions. |
| Function declarations (prototypes) cannot occur inside of functions; they |
| must be at global scope. |
| Hence it is not possible to hide a name with a function.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="shared-globals">4.2.5. Shared Globals</h4> |
| <div class="paragraph"> |
| <p>Shared globals are variables that can be accessed by multiple compilation |
| units. |
| In GLSL ES the only shared globals are uniforms. |
| Vertex shader outputs are not considered to be shared globals since they |
| must pass through the rasterization stage before they are used as input by |
| the fragment shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Shared globals share the same name space, and must be declared with the same |
| type and precision. |
| They will share the same storage. |
| Shared global arrays must have the same base type and the same explicit |
| size. |
| Scalars must have exactly the same precision, type name and type definition. |
| Structures must have the same name, sequence of type names, and type |
| definitions, and member names to be considered the same type. |
| This rule applies recursively for nested or embedded types.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="storage-qualifiers">4.3. Storage Qualifiers</h3> |
| <div class="paragraph"> |
| <p>Variable declarations may have at most one storage qualifier specified in |
| front of the type. |
| These are summarized as</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Storage Qualifier</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><none: default></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">local read/write memory, or an input parameter to a |
| function</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>const</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">a compile-time constant</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">linkage into a shader from a previous stage, variable |
| is copied in</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">linkage out of a shader to a subsequent stage, |
| variable is copied out</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">value does not change across the primitive being |
| processed, uniforms form the linkage between a shader, |
| API, and the application</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>buffer</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">value is stored in a buffer object, and can be read or |
| written both by shader invocations and the API</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>shared</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">compute shader only; variable storage is shared across |
| all work items in a workgroup</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Some input and output qualified variables can be qualified with at most one |
| additional auxiliary storage qualifier:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Auxiliary Storage Qualifier</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">centroid-based interpolation</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sample</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">per-sample interpolation</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">per-tessellation-patch attributes</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Local variables can only use the <strong>const</strong> storage qualifier (or use no |
| storage qualifier).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that function parameters can use <strong>const</strong>, <strong>in</strong>, and <strong>out</strong> qualifiers, |
| but as <em>parameter qualifiers</em>. |
| Parameter qualifiers are discussed in |
| “<a href="#function-calling-conventions">Function Calling Conventions</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Function return types and structure members do not use storage qualifiers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Data types for communication from one run of a shader executable to its next |
| run (to communicate between fragments or between vertices) do not exist. |
| This would prevent parallel execution of the same shader executable on |
| multiple vertices or fragments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In declarations of global variables with no storage qualifier or with a |
| const qualifier, any initializer must be a constant expression. |
| Declarations of global variables with other storage qualifiers may not |
| contain initializers. |
| Global variables without storage qualifiers that are not initialized in |
| their declaration or by the application will not be initialized, |
| but rather will enter <em>main()</em> with undefined values.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="default-storage-qualifier">4.3.1. Default Storage Qualifier</h4> |
| <div class="paragraph"> |
| <p>If no qualifier is present on a global variable, then the variable has no |
| linkage to the application or shaders running on other pipeline stages. |
| For either global or local unqualified variables, the declaration will |
| appear to allocate memory associated with the processor it targets. |
| This variable will provide read/write access to this allocated memory.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="constant-qualifier">4.3.2. Constant Qualifier</h4> |
| <div class="paragraph"> |
| <p>Named compile-time constants |
| can be declared using |
| the <strong>const</strong> qualifier. |
| Any variables qualified as constant are read-only variables for that shader. |
| Declaring variables as constant allows more descriptive shaders than using |
| hard-wired numerical constants. |
| The <strong>const</strong> qualifier can be used with any of the non-void transparent basic |
| data types, as well as with structures and arrays of these. |
| It is an error to write to a <strong>const</strong> variable outside of its |
| declaration, so they must be initialized when declared. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> vec3 zAxis = vec3 (<span class="float">0</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Structure members may not be qualified with <strong>const</strong>. |
| Structure variables can be declared as <strong>const</strong>, and initialized with a |
| structure |
| constructor.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Initializers for <strong>const</strong> declarations |
| must be constant expressions, as defined in |
| “<a href="#constant-expressions">Constant Expressions</a>”.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="constant-expressions">4.3.3. Constant Expressions</h4> |
| <div class="paragraph"> |
| <p>SPIR-V specialization constants are expressed in GLSL ES as <strong>const</strong> with the |
| layout qualifier <strong>constant_id</strong>, as described in |
| “<a href="#specialization-constant-qualifier">Specialization-Constant |
| Qualifier.</a>”</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>constant expression</em> is one of</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A literal value (e.g. <strong>5</strong> or <strong>true</strong>).</p> |
| </li> |
| <li> |
| <p>A variable declared with the <strong>const</strong> qualifier and an initializer, where |
| the initializer is a constant expression. |
| This includes both <strong>const</strong> declared with a specialization-constant |
| layout qualifier, e.g. <strong>layout</strong>(<strong>constant_id</strong> = …​), and those declared |
| without a specialization-constant layout qualifier.</p> |
| </li> |
| <li> |
| <p>Built-in variables qualified as <strong>const</strong>.</p> |
| </li> |
| <li> |
| <p>An expression formed by an operator on operands that are all constant |
| expressions, including getting an element of a constant array, or a |
| member of a constant structure, or components of a constant vector. |
| However, the lowest precedence operators of the sequence operator (<strong>,</strong>) |
| and the assignment operators (<strong>=</strong>, <strong>+=</strong>, <strong>…​</strong>) are not included in the |
| operators that can create a constant expression. |
| Also, an array access with a specialization constant as an index does |
| not result in a constant expression.</p> |
| </li> |
| <li> |
| <p>The <strong>length</strong>() method on a compile-time sized array, whether or not the |
| object itself is constant.</p> |
| </li> |
| <li> |
| <p>A constructor whose arguments are all constant expressions.</p> |
| </li> |
| <li> |
| <p>For non-specialization constants only: |
| A built-in function call whose arguments are all constant expressions, |
| with the exception of the texture lookup functions. |
| This rule excludes functions with a <strong>void</strong> return or functions that have |
| an <strong>out</strong> parameter. |
| The built-in functions <strong>dFdx</strong>, <strong>dFdy</strong>, and <strong>fwidth</strong> must return 0 when |
| evaluated inside an initializer with an argument that is a constant |
| expression.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Function calls to user-defined functions (non-built-in functions) cannot be |
| used to form constant expressions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Scalar, vector, matrix, array and structure variables are constant |
| expressions if qualified as <strong>const</strong>. |
| Opaque types cannot be constant expressions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>constant integral expression</em> is a constant expression that evaluates to |
| a scalar signed or unsigned integer.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Constant expressions will be evaluated in an invariant way so as to create |
| the same value in multiple shaders when the same constant expressions appear |
| in those shaders. |
| See “<a href="#the-invariant-qualifier">The Invariant Qualifier</a>” for more details |
| on how to create invariant expressions and |
| “<a href="#precision-qualifiers">Precision Qualifiers</a>” for detail on how |
| expressions are evaluated.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Constant expressions respect the <strong>precise</strong> and <strong>invariant</strong> qualifiers but |
| will be always be evaluated in an invariant way, independent of the use of |
| such qualification, so as to create the same value in multiple shaders when |
| the same constant expressions appear in those shaders. |
| See “<a href="#the-invariant-qualifier">The Invariant Qualifier</a>” and |
| “<a href="#the-precise-qualifier">The Precise Qualifier</a>” for more details on how |
| to create invariant expressions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Constant-expressions may be evaluated by a |
| host platform, and are therefore not required to compute the same value that |
| the same expression would evaluate to on the shader execution target. |
| However, the host must use the same or greater precision than the target |
| would use. |
| When the precision qualification cannot be determined, the expression is |
| evaluated at <strong>highp</strong>. |
| See “<a href="#default-precision-qualifiers">Default Precision Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Specialization-constant expressions are never evaluated by the compiler |
| front end, but instead retain the expression’s operations needed to evaluate |
| them later on the host.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="input-variables">4.3.4. Input Variables</h4> |
| <div class="paragraph"> |
| <p>Shader input variables are declared with the <strong>in</strong> storage qualifier. |
| They form the input interface between previous stages of the API |
| pipeline and the declaring shader. |
| Input variables must be declared at global scope. |
| Values from the previous pipeline stage are copied into input variables at |
| the beginning of shader execution. |
| It is an error to write to a variable declared as an input.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Only the input variables that are |
| actually |
| read need to be written by the |
| previous stage; it is allowed to have superfluous declarations of input |
| variables.</p> |
| </div> |
| <div class="paragraph"> |
| <p>See “<a href="#built-in-variables">Built-In Variables</a>” for a list of the built-in |
| input names.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Vertex shader input variables (or attributes) receive per-vertex data. |
| It is an error to use auxiliary storage or interpolation qualifiers |
| on a vertex shader input. |
| The values copied in are established by the API or through the use |
| of the layout identifier <strong>location</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error to declare a vertex shader input with, or that |
| contains, any of the following types:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A <a href="#booleans">boolean type</a></p> |
| </li> |
| <li> |
| <p>An <a href="#opaque-types">opaque type</a></p> |
| </li> |
| <li> |
| <p>An array</p> |
| </li> |
| <li> |
| <p>A structure</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Example declarations in a vertex shader:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in vec4 position; |
| in vec3 normal; |
| in vec2 texCoord[<span class="integer">4</span>];</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>It is expected that graphics hardware will have a small number of fixed |
| vector locations for passing vertex inputs. |
| Therefore, the OpenGL ES Shading Language defines each non-matrix input variable as taking up |
| one such vector location. |
| There is an implementation-dependent limit on the number of locations that |
| can be used, and if this is exceeded it will cause a link-time error. |
| (Declared input variables that are not statically used do not count against |
| this limit.) A scalar input counts the same amount against this limit as a |
| <strong>vec4</strong>, so applications may want to consider packing groups of four |
| unrelated float inputs together into a vector to better utilize the |
| capabilities of the underlying hardware. |
| A matrix input will use up multiple locations. |
| The number of locations used will equal the number of columns in the matrix.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Tessellation control, evaluation, and geometry shader input variables get |
| the per-vertex values written out by output variables of the same names in |
| the previous active shader stage. |
| For these inputs, <strong>centroid</strong> and interpolation qualifiers are allowed, but |
| have no effect. |
| Since tessellation control, tessellation evaluation, and geometry shaders |
| operate on a set of vertices, each input variable (or input block, see |
| interface blocks below) needs to be declared as an array. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in <span class="predefined-type">float</span> foo[]; <span class="comment">// geometry shader input for vertex "out float foo"</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Each element of such an array corresponds to one vertex of the primitive |
| being processed. |
| Each array can optionally have a size declared. |
| For geometry shaders, the array size will be set by, (or if provided must be |
| consistent with) the input <strong>layout</strong> declaration(s) establishing the type of |
| input primitive, as described later in “<a href="#input-layout-qualifiers">Input |
| Layout Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Some inputs and outputs are <em>arrayed</em>, meaning that for an interface between |
| two shader stages either the input or output declaration requires an extra |
| level of array indexing for the declarations to match. |
| For example, with the interface between a vertex shader and a geometry |
| shader, vertex shader output variables and geometry shader input variables |
| of the same name must have matching types, except that the geometry shader |
| will have one more array dimension than the vertex shader, to allow for |
| vertex indexing. |
| If such an arrayed interface variable is not declared with the necessary |
| additional input or output array dimension, a link-time error will result. |
| Geometry shader inputs, tessellation control shader inputs and outputs, and |
| tessellation evaluation inputs all have an additional level of arrayness |
| relative to other shader inputs and outputs. |
| These inputs and outputs are known as <em>per-vertex-arrayed</em> inputs and |
| outputs. |
| Component limits for arrayed interfaces (e.g. |
| <em>gl_MaxTessControlInputComponents</em>) are limits per vertex, not limits for |
| the entire interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For non-arrayed interfaces (meaning array dimensionally stays the same |
| between stages), it is a link-time error if the input variable is not |
| declared with the same type, including array dimensionality, as the matching |
| output variable.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The link-time type-matching rules apply to all declared input and output |
| variables, whether or not they are used.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additionally, tessellation evaluation shaders support per-patch input |
| variables declared with the <strong>patch</strong> and <strong>in</strong> qualifiers. |
| Per-patch input variables are filled with the values of per-patch output |
| variables written by the tessellation control shader. |
| Per-patch inputs may be declared as one-dimensional arrays, but are not |
| indexed by vertex number. |
| Applying the <strong>patch</strong> qualifier to inputs can only be done in tessellation |
| evaluation shaders. |
| As with other input variables, per-patch inputs must be declared using the |
| same type and qualification as per-patch outputs from the previous |
| (tessellation control) shader stage. |
| It is a compile-time error to use <strong>patch</strong> with inputs in any other stage.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error to declare a tessellation control, tessellation |
| evaluation or geometry shader input with, or that contains, any of the |
| following types:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A <a href="#booleans">boolean type</a></p> |
| </li> |
| <li> |
| <p>An <a href="#opaque-types">opaque type</a></p> |
| </li> |
| <li> |
| <p>A structure containing an array</p> |
| </li> |
| <li> |
| <p>A structure containing a structure</p> |
| </li> |
| <li> |
| <p>For per-vertex-arrayed variables:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Per-vertex-arrayed arrays of arrays</p> |
| </li> |
| <li> |
| <p>Per-vertex-arrayed arrays of structures</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>For non-per-vertex-arrayed variables:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>An array of arrays</p> |
| </li> |
| <li> |
| <p>An array of structures</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shader inputs get per-fragment values, typically interpolated from |
| a previous stage’s outputs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error to declare a fragment shader input with, or that |
| contains, any of the following types:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A <a href="#booleans">boolean type</a></p> |
| </li> |
| <li> |
| <p>An <a href="#opaque-types">opaque type</a></p> |
| </li> |
| <li> |
| <p>An array of arrays</p> |
| </li> |
| <li> |
| <p>An array of structures</p> |
| </li> |
| <li> |
| <p>A structure containing an array</p> |
| </li> |
| <li> |
| <p>A structure containing a structure</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shader inputs that are, or contain, integral |
| types must be |
| qualified with the interpolation qualifier <strong>flat</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment inputs are declared as in the following examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in vec3 normal; |
| centroid in vec2 TexCoord; |
| flat in vec3 myColor;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The fragment shader inputs form an interface with the last active shader in |
| the vertex processing pipeline. |
| For this interface, the last active shader stage output variables and |
| fragment shader input variables of the same name must match in type and |
| qualification, with a few exceptions: The storage qualifiers must, of |
| course, differ (one is <strong>in</strong> and one is <strong>out</strong>). |
| Also, |
| auxiliary qualification (e.g. <strong>centroid</strong>) may differ. |
| When |
| auxiliary qualifiers do not match, those provided in |
| the fragment shader supersede those provided in previous stages. |
| If any such qualifiers are completely missing in the fragment shaders, then |
| the default is used, rather than any qualifiers that may have been declared |
| in previous stages. |
| That is, what matters is what is declared in the fragment shaders, not what |
| is declared in shaders in previous stages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When an interface between shader stages is formed using shaders from two |
| separate program objects, it is not possible to detect mismatches between |
| inputs and outputs when the programs are linked. |
| When there are mismatches between inputs and outputs on such interfaces, |
| attempting to use the two programs in the same program pipeline will result |
| in program pipeline validation failures, as described in section 7.4.1 |
| “Shader Interface Matching” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Shaders can ensure matches across such interfaces either by using input and |
| output layout qualifiers (sections “<a href="#input-layout-qualifiers">Input Layout |
| Qualifiers</a>” and “<a href="#output-layout-qualifiers">Output Layout |
| Qualifiers</a>”) or by using identical input and output declarations of |
| blocks or variables. |
| Complete rules for interface matching are found in section 7.4.1 “Shader |
| Interface Matching” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Compute shaders do not permit user-defined input variables and do not form a |
| formal interface with any other shader stage. |
| See “<a href="#compute-shader-special-variables">Compute Shader Special |
| Variables</a>” for a description of built-in compute shader input variables. |
| All other input to a compute shader is retrieved explicitly through image |
| loads, texture fetches, loads from uniforms or uniform buffers, or other |
| user supplied code.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="uniform-variables">4.3.5. Uniform Variables</h4> |
| <div class="paragraph"> |
| <p>The <strong>uniform</strong> qualifier is used to declare global variables whose values are |
| the same across the entire primitive being processed. |
| All <strong>uniform</strong> variables are read-only. |
| Except for variables declared within a uniform block, all uniform variables |
| are initialized to 0 at link time and may be updated through the API. |
| When targeting Vulkan, it is an error to declare <strong>uniform</strong> |
| variables outside a block.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example declarations are:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">uniform vec4 lightPosition;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>uniform</strong> qualifier can be used with any of the basic data types, or |
| when declaring a variable whose type is a structure, or an array of any of |
| these.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is an implementation-dependent limit on the amount of storage for |
| uniforms that can be used for each type of shader and if this is exceeded it |
| will cause a compile-time or link-time error. |
| Uniform variables that are declared but not |
| statically |
| used do not count against this limit. |
| The number of user-defined uniform variables and the number of built-in |
| uniform variables that are used within a shader are added together to |
| determine whether available uniform storage has been exceeded.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Uniforms in shaders all share a single global name space when linked into a |
| program or separable program. |
| Hence, the types, |
| precisions, |
| and any location specifiers of all statically used uniform variables with the |
| same name must match across all shaders that are linked into a single program. |
| However it is not required to repeat the |
| location specifier in all the linked shaders. |
| While this single uniform name space is cross stage, a uniform variable |
| name’s scope is per stage: If a uniform variable name is declared in one |
| stage (e.g. a vertex shader) but not in another (e.g. a fragment shader), |
| then that name is still available in the other stage for a different use.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A compile or link-time error is generated if any of the explicitly given or |
| compiler generated uniform locations is greater than the |
| implementation-defined maximum number of uniform locations minus one.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Unlike locations for inputs and outputs, uniform locations are logical |
| values, not register locations, and there is no concept of overlap. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">2</span>) uniform mat4 x; |
| layout(location = <span class="integer">3</span>) uniform mat4 y; <span class="comment">// No overlap with x</span> |
| layout(location = <span class="integer">2</span>) in mat4 x; |
| layout(location = <span class="integer">3</span>) in mat4 y; <span class="comment">// Error, locations conflict with x</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="output-variables">4.3.6. Output Variables</h4> |
| <div class="paragraph"> |
| <p>Shader output variables are declared with the <strong>out</strong> storage qualifier. |
| They form the output interface between the declaring shader and the |
| subsequent stages of the API pipeline. |
| Output variables must be declared at global scope. |
| During shader execution they will behave as normal unqualified global |
| variables. |
| Their values are copied out to the subsequent pipeline stage on shader exit. |
| Only output variables that are read by the subsequent pipeline stage need to |
| be written; it is allowed to have superfluous declarations of output |
| variables.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is <em>not</em> an <strong>inout</strong> storage qualifier for declaring a single variable |
| name as both input and output to a shader. |
| Also, a variable cannot be declared with both the <strong>in</strong> and the <strong>out</strong> |
| qualifiers, this will result in a compile-time or link-time error. |
| Output variables must be declared with different names than input variables. |
| However, nesting an input or output inside an interface block with an |
| instance name allows the same names with one referenced through a block |
| instance name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Vertex, tessellation evaluation, and geometry output variables output |
| per-vertex data and are declared using the <strong>out</strong> storage qualifier. |
| Applying <strong>patch</strong> to an output can only be done in a tessellation control |
| shader. |
| It is a compile-time error to use <strong>patch</strong> on outputs in any other stage.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error to declare a vertex, tessellation evaluation, |
| tessellation control, or geometry shader output with, or that contains, any |
| of the following types:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A <a href="#booleans">boolean type</a></p> |
| </li> |
| <li> |
| <p>An <a href="#opaque-types">opaque type</a></p> |
| </li> |
| <li> |
| <p>A structure containing an array</p> |
| </li> |
| <li> |
| <p>A structure containing a structure</p> |
| </li> |
| <li> |
| <p>For per-vertex-arrayed variables (applies to tessellation control, |
| tessellation evaluation and geometry shaders):</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Per-vertex-arrayed arrays of arrays</p> |
| </li> |
| <li> |
| <p>Per-vertex-arrayed arrays of structures</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>For non-per-vertex-arrayed variables:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>An array of arrays</p> |
| </li> |
| <li> |
| <p>An array of structures</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Vertex shader outputs may be qualified with the interpolation qualifier |
| <strong>flat</strong><sup>1</sup>.</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">1</dt> |
| <dd> |
| <p>Unlike previous versions of the OpenGL ES Shading Language, there is no requirement for |
| outputs containing integers to be qualified as <strong>flat</strong>, since the vertex |
| shader may interface with the tessellation control shader. |
| However, in all cases, the qualifier must match across interfaces.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>Individual outputs are declared as in the following examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out vec3 normal; |
| centroid out vec2 TexCoord; |
| invariant centroid out vec4 Color; |
| flat out vec3 myColor; |
| sample out vec4 perSampleColor;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>These can also appear in interface blocks, as described in |
| “<a href="#interface-blocks">Interface Blocks</a>”. |
| Interface blocks allow simpler addition of arrays to the interface from |
| vertex to geometry shader. |
| They also allow a fragment shader to have the same input interface as a |
| geometry shader for a given vertex shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Tessellation control shader output variables are used to output |
| per-vertex and per-patch data. |
| Per-vertex output variables are arrayed (see <em>arrayed</em> under |
| “<a href="#input-variables">Input Variables</a>”) and declared using the <strong>out</strong> |
| qualifier without the <strong>patch</strong> qualifier. |
| Per-patch output variables are declared using the <strong>patch</strong> and <strong>out</strong> |
| qualifiers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Since tessellation control shaders produce an arrayed primitive comprising |
| multiple vertices, each per-vertex output variable (or output block, see |
| interface blocks below) needs to be declared as an array. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out <span class="predefined-type">float</span> foo[]; <span class="comment">// feeds next stage input "in float foo[]"</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Each element of such an array corresponds to one vertex of the primitive |
| being produced. |
| Each array can optionally have a size declared. |
| The array size will be set by (or if provided must be consistent with) the |
| output layout declaration(s) establishing the number of vertices in the |
| output patch, as described later in |
| “<a href="#tessellation-control-outputs">Tessellation Control Outputs</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Each tessellation control shader invocation has a corresponding output patch |
| vertex, and may assign values to per-vertex outputs only if they belong to |
| that corresponding vertex. |
| If a per-vertex output variable is used as an l-value, it is a compile-time |
| or link-time error if the expression indicating the vertex index is not the |
| identifier <em>gl_InvocationID</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The order of execution of a tessellation control shader invocation relative |
| to the other invocations for the same input patch is undefined unless the |
| built-in function <strong>barrier</strong>() is used. |
| This provides some control over relative execution order. |
| When a shader invocation calls <strong>barrier</strong>(), its execution pauses until all |
| other invocations have reached the same point of execution. |
| Output variable assignments performed by any invocation executed prior to |
| calling <strong>barrier</strong>() will be visible to any other invocation after the call |
| to <strong>barrier</strong>() returns.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Because tessellation control shader invocations execute in undefined order |
| between barriers, the values of per-vertex or per-patch output variables |
| will sometimes be undefined. |
| Consider the beginning and end of shader execution and each call to |
| <strong>barrier</strong>() as synchronization points. |
| The value of an output variable will be undefined in any of the three |
| following cases:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>At the beginning of execution.</p> |
| </li> |
| <li> |
| <p>At each synchronization point, unless</p> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the value was well-defined after the previous synchronization point and |
| was not written by any invocation since, or</p> |
| </li> |
| <li> |
| <p>the value was written by exactly one shader invocation since the previous |
| synchronization point, or</p> |
| </li> |
| <li> |
| <p>the value was written by multiple shader invocations since the previous |
| synchronization point, and the last write performed by all such |
| invocations wrote the same value.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </li> |
| <li> |
| <p>When read by a shader invocation, if</p> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the value was undefined at the previous synchronization point and has not |
| been written by the same shader invocation since, or</p> |
| </li> |
| <li> |
| <p>the output variable is written to by any other shader invocation between |
| the previous and next synchronization points, even if that assignment |
| occurs in code following the read.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment outputs output per-fragment data and are declared using the <strong>out</strong> |
| storage qualifier. |
| It is an error to use auxiliary storage qualifiers or |
| interpolation qualifiers in a fragment shader output declaration. |
| It is a compile-time error to declare a fragment shader output with, or that |
| contains, any of the following types:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A <a href="#booleans">boolean type</a></p> |
| </li> |
| <li> |
| <p>An <a href="#opaque-types">opaque type</a></p> |
| </li> |
| <li> |
| <p>A matrix type</p> |
| </li> |
| <li> |
| <p>A structure</p> |
| </li> |
| <li> |
| <p>An array of arrays</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shader outputs declared as arrays may only be indexed by a constant |
| integral expression.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment outputs are declared as in the following examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out vec4 FragmentColor; |
| out uint Luminosity;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Compute shaders have no built-in output variables, do not support |
| user-defined output variables and do not form a formal interface with any |
| other shader stage. |
| All outputs from a compute shader take the form of the side effects such as |
| image stores and operations on atomic counters.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="buffer-variables">4.3.7. Buffer Variables</h4> |
| <div class="paragraph"> |
| <p>The <strong>buffer</strong> qualifier is used to declare global variables whose values are |
| stored in the data store of a buffer object bound through the API. |
| Buffer variables can be read and written, with the underlying storage shared |
| among all active shader invocations. |
| Buffer variable memory reads and writes within a single shader invocation |
| are processed in order. |
| However, the order of reads and writes performed in one invocation relative |
| to those performed by another invocation is largely undefined. |
| Buffer variables may be qualified with memory qualifiers affecting how the |
| underlying memory is accessed, as described in “<a href="#memory-qualifiers">Memory |
| Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>buffer</strong> qualifier can be used to declare interface blocks (see |
| “<a href="#interface-blocks">Interface Blocks</a>”), which are then referred to as |
| shader storage blocks. |
| It is a compile-time error to declare buffer variables outside a block. |
| Buffer variables cannot have initializers.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="title">Note</div> |
| <div class="paragraph"> |
| <p>The terms <em>shader storage buffer (object)</em>, and <em>shader storage block</em> are |
| often used interchangeably. |
| The former generally refers to the underlying storage whereas the latter |
| refers only to the interface definition in the shader. |
| Similarly for <em>uniform buffer objects</em> and _uniform blocks.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// use buffer to create a buffer block (shader storage block)</span> |
| buffer BufferName { <span class="comment">// externally visible name of buffer</span> |
| <span class="predefined-type">int</span> count; <span class="comment">// typed, shared memory...</span> |
| ... <span class="comment">// ...</span> |
| vec4 v[]; <span class="comment">// last member may be an array that is not sized</span> |
| <span class="comment">// until after link time (dynamically sized)</span> |
| } Name; <span class="comment">// name of block within the shader</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There are implementation-dependent limits on the number of shader storage |
| blocks used for each type of shader, the combined number of shader storage |
| blocks used for a program, and the amount of storage required by each |
| individual shader storage block. |
| If any of these limits are exceeded, it will cause a compile-time or |
| link-time error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If multiple shaders are linked together, then they will share a single |
| global buffer variable name space. |
| Hence, the types of all declared buffer variables with the same name must |
| match across all shaders that are linked into a single program.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Precision qualifiers for such variables need not match.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="shared-variables">4.3.8. Shared Variables</h4> |
| <div class="paragraph"> |
| <p>The <strong>shared</strong> qualifier is used to declare global variables that have storage |
| shared between all work items in a compute shader workgroup. |
| Variables declared as <strong>shared</strong> may only be used in compute shaders (see |
| “<a href="#compute-processor">Compute Processor</a>”). |
| Any other declaration of a <strong>shared</strong> variable is an error. |
| Shared variables are implicitly coherent (see |
| “<a href="#memory-qualifiers">Memory Qualifiers</a>”).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Variables declared as <strong>shared</strong> may not have initializers and their contents |
| are undefined at the beginning of shader execution. |
| Any data written to <strong>shared</strong> variables will be visible to other work items |
| (executing the same shader) within the same workgroup.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the absence of synchronization, the order of reads and writes to the same |
| <strong>shared</strong> variable by different invocations of a shader is not defined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to achieve ordering with respect to reads and writes to <strong>shared</strong> |
| variables, control flow barriers must be employed using the <strong>barrier</strong>() function |
| (see “<a href="#shader-invocation-control-functions">Shader Invocation Control |
| Functions</a>”).</p> |
| </div> |
| <div class="paragraph"> |
| <p>There is a limit to the total size of all variables declared as <strong>shared</strong> in a |
| single program. |
| This limit, expressed in units of basic machine units may be determined by |
| using the OpenGL ES API to query the value of |
| MAX_COMPUTE_SHARED_MEMORY_SIZE.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="interface-blocks">4.3.9. Interface Blocks</h4> |
| <div class="paragraph"> |
| <p>Input, output, uniform, and buffer variable declarations can be grouped into |
| named interface blocks to provide coarser granularity backing than is |
| achievable with individual declarations. |
| They can have an optional instance name, used in the shader to reference |
| their members. |
| An output block of one programmable stage is backed by a corresponding input |
| block in the subsequent programmable stage. |
| A <em>uniform block</em> is backed by the application with a buffer object. |
| A block of buffer variables, called a <em>shader storage block</em>, is also backed |
| by the application with a buffer object. |
| It is a compile-time error to have an input block in a vertex shader or an |
| output block in a fragment shader. |
| These uses are reserved for future use.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An interface block is started by an <strong>in</strong>, <strong>out</strong>, <strong>uniform</strong>, or <strong>buffer</strong> |
| keyword, followed by a block name, followed by an open curly brace (<strong>{</strong>) as |
| follows:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>interface-block</em> : </dt> |
| <dd> |
| <p><em>layout-qualifier<sub>opt</sub></em> <em>interface-qualifier</em> <em>block-name</em> <strong>{</strong> |
| <em>member-list</em> <strong>}</strong> <em>instance-name<sub>opt</sub></em> <strong>;</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>interface-qualifier</em> : </dt> |
| <dd> |
| <p><strong>in</strong><br> |
| <strong>out</strong><br> |
| <strong>patch</strong> <strong>in</strong> // Note: Qualifiers can be in any order.<br> |
| <strong>patch</strong> <strong>out</strong><br> |
| <strong>uniform</strong><br> |
| <strong>buffer</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>member-list</em> : </dt> |
| <dd> |
| <p><em>member-declaration</em><br> |
| <em>member-declaration</em> <em>member-list</em></p> |
| </dd> |
| <dt class="hdlist1"><em>member-declaration</em> : </dt> |
| <dd> |
| <p><em>layout-qualifier<sub>opt</sub></em> <em>qualifiers<sub>opt</sub></em> <em>type</em> <em>declarators</em> <strong>;</strong></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>instance-name</em> : </dt> |
| <dd> |
| <p><em>identifier</em><br> |
| <em>identifier</em> <strong>[</strong> <strong>]</strong><br> |
| <em>identifier</em> <strong>[</strong> <em>constant-integral-expression</em> <strong>]</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Each of the above elements is discussed below, with the exception of layout |
| qualifiers (<em>layout-qualifier</em>), which are defined in the next section.</p> |
| </div> |
| <div class="paragraph"> |
| <p>First, an example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">uniform Transform { |
| mat4 ModelViewMatrix; |
| mat4 ModelViewProjectionMatrix; |
| uniform mat3 NormalMatrix; <span class="comment">// allowed restatement of qualifier</span> |
| <span class="predefined-type">float</span> Deformation; |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above establishes a uniform block named “Transform” with four uniforms |
| grouped inside it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Types and declarators are the same as for other input, output, uniform, and |
| buffer variable declarations outside blocks, with these exceptions:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Opaque types are not allowed</p> |
| </li> |
| <li> |
| <p>Structure definitions cannot be nested inside a block</p> |
| </li> |
| <li> |
| <p>Arrays of arrays of blocks are not allowed, except for the case in the |
| tessellation pipe where the declaration is a per-vertex-array of arrays |
| of blocks.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>If no optional qualifier is used in a member-declaration, the qualification |
| of the member includes all <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> as |
| determined by <em>interface-qualifier</em>. |
| If optional qualifiers are used, they can include interpolation qualifiers, |
| auxiliary storage qualifiers, |
| precision qualifiers, |
| and storage qualifiers and they must declare |
| an input, output, or uniform member consistent with the interface qualifier |
| of the block: Input variables, output variables, uniform variables, and |
| <strong>buffer</strong> members can only be in <strong>in</strong> blocks, <strong>out</strong> blocks, <strong>uniform</strong> blocks, |
| and shader storage blocks, respectively.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Repeating the <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> interface |
| qualifier for a member’s storage qualifier is optional. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in Material { |
| smooth in vec4 Color1; <span class="comment">// legal, input inside in block</span> |
| smooth vec4 Color2; <span class="comment">// legal, 'in' inherited from 'in Material'</span> |
| vec2 TexCoord; <span class="comment">// legal, TexCoord is an input</span> |
| uniform <span class="predefined-type">float</span> Atten; <span class="comment">// illegal, mismatched storage qualifier</span> |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A <em>shader interface</em> is defined to be one of these:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>All the uniform variables and uniform blocks declared in a program. |
| This spans all compilation units linked together within one program.</p> |
| </li> |
| <li> |
| <p>All the <strong>buffer</strong> blocks declared in a program.</p> |
| </li> |
| <li> |
| <p>The boundary between adjacent programmable pipeline stages: This spans |
| all the outputs declared in all compilation units of the first stage and |
| all the inputs declared in all compilation units of the second stage. |
| Note that for the purposes of this definition, the fragment shader and |
| the preceding shader are considered to have a shared boundary even |
| though in practice, all values passed to the fragment shader first pass |
| through the rasterizer and interpolator.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The block name (<em>block-name</em>) is used to match within shader interfaces: an |
| output block of one pipeline stage will be matched to an input block with |
| the same name in the subsequent pipeline stage. |
| For uniform or shader storage blocks, the application uses the block name to |
| identify the block. |
| Block names have no other use within a shader beyond interface matching; it |
| is an error |
| to use a block name at global scope for anything other than as a |
| block name (e.g. use of a block name for a global variable name or function |
| name is currently reserved). |
| It is a compile-time error to use the same block name for more than one |
| block declaration in the same shader interface (as defined above) within one |
| shader, even if the block contents are identical.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Matched block names within a shader interface (as defined above) must match |
| in terms of having the same number of declarations with the same sequence of |
| types and the same sequence of member names, as well as having matching |
| member-wise layout qualification |
| as defined in “<a href="#matching-of-qualifiers">Matching of Qualifiers</a>”. |
| Matched uniform or shader storage block names (but not input or output block |
| names) must also either all be lacking an instance name or all having an |
| instance name, putting their members at the same scoping level. |
| When instance names are present on matched block names, it is allowed for |
| the instance names to differ; they need not match for the blocks to match. |
| Furthermore, if a matching block is declared as an array, then the array |
| sizes must also match (or follow array matching rules for the shader |
| interface between consecutive shader stages). |
| Any mismatch will generate a link-time error. |
| A block name is allowed to have different definitions in different shader |
| interfaces within the same shader, allowing, for example, an input block and |
| output block to have the same name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an instance name (<em>instance-name</em>) is not used, the names declared inside |
| the block are scoped at the global level and accessed as if they were |
| declared outside the block. |
| If an instance name (<em>instance-name</em>) is used, then it puts all the members |
| inside a scope within its own name space, accessed with the field selector |
| (<strong>.</strong>) operator (analogously to structures). |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in Light { |
| vec4 LightPos; |
| vec3 LightColor; |
| }; |
| in ColoredTexture { |
| vec4 Color; |
| vec2 TexCoord; |
| } Material; <span class="comment">// instance name</span> |
| vec3 Color; <span class="comment">// different Color than Material.Color</span> |
| vec4 LightPos; <span class="comment">// illegal, already defined</span> |
| ... |
| ... = LightPos; <span class="comment">// accessing LightPos</span> |
| ... = Material.Color; <span class="comment">// accessing Color in ColoredTexture block</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Outside the shading language (i.e., in the API), members are similarly |
| identified except the block name is always used in place of the instance |
| name (API accesses are to shader interfaces, not to shaders). |
| If there is no instance name, then the API does not use the block name to |
| access a member, just the member name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Within a shader interface, all declarations of the same global name must be |
| for the same object and must match in type and in whether they declare a |
| variable or member of a block with no instance name. |
| The API also needs this name to uniquely identify an object in the shader |
| interface. |
| It is a link-time error if any particular shader interface contains</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>two different blocks, each having no instance name, and each having a |
| member of the same name, or</p> |
| </li> |
| <li> |
| <p>a variable outside a block, and a block with no instance name, where the |
| variable has the same name as a member in the block.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out Vertex { |
| vec4 Position; <span class="comment">// API transform/feedback will use "Vertex.Position"</span> |
| vec2 Texture; |
| } Coords; <span class="comment">// shader will use "Coords.Position"</span> |
| out Vertex2 { |
| vec4 Color; <span class="comment">// API will use "Color"</span> |
| <span class="predefined-type">float</span> Color2; |
| }; |
| |
| <span class="comment">// in same program as Vertex2 above:</span> |
| out Vertex3 { |
| <span class="predefined-type">float</span> Intensity; |
| vec4 Color; <span class="comment">// ERROR, name collision with Color in Vertex2</span> |
| }; |
| <span class="predefined-type">float</span> Color2; <span class="comment">// ERROR, collides with Color2 in Vertex2</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For blocks declared as arrays, the array index must also be included when |
| accessing members, as in this example</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">uniform Transform { <span class="comment">// API uses "Transform[2]" to refer to instance 2</span> |
| mat4 ModelViewMatrix; |
| mat4 ModelViewProjectionMatrix; |
| <span class="predefined-type">float</span> Deformation; |
| } transforms[<span class="integer">4</span>]; |
| ... |
| ... = transforms[<span class="integer">2</span>].ModelViewMatrix; <span class="comment">// shader access of instance 2</span> |
| <span class="comment">// API uses "Transform.ModelViewMatrix" to query an offset or other query</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For uniform or shader storage blocks declared as an array, each individual |
| array element corresponds to a separate buffer object bind range, backing |
| one instance of the block. |
| As the array size indicates the number of buffer objects needed, uniform and |
| shader storage block array declarations must specify an array size. |
| All indices used to index a shader storage block array must be constant |
| integral expressions. |
| A uniform block array can only be indexed with a dynamically uniform |
| integral expression, otherwise results are undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When using OpenGL ES API entry points to identify the name of an individual |
| block in an array of blocks, the name string may include an array index |
| (e.g. <em>Transform[2]</em>). |
| When using OpenGL ES API entry points to refer to offsets or other |
| characteristics of a block member, an array index must not be specified |
| (e.g. <em>Transform.ModelViewMatrix</em>). |
| See section 7.3.1 “Program Interfaces” of the <a href="#references">OpenGL ES Specification</a> for |
| details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Tessellation control, tessellation evaluation and geometry shader input |
| blocks must be declared as arrays and follow the array declaration and |
| linking rules for all shader inputs for the respective stages. |
| All other input and output block arrays must specify an array size.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are implementation-dependent limits on the number of uniform blocks |
| and the number of shader storage blocks that can be used per stage. |
| If either limit is exceeded, it will cause a link-time error.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="layout-qualifiers">4.4. Layout Qualifiers</h3> |
| <div class="paragraph"> |
| <p>Layout qualifiers can appear in several forms of declaration. |
| They can appear as part of an interface block definition or block member, as |
| shown in the grammar in the previous section. |
| They can also appear with just an <em>interface-qualifier</em> to establish layouts |
| of other declarations made with that qualifier:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="paragraph"> |
| <p><em>layout-qualifier</em> <em>interface-qualifier</em> <strong>;</strong></p> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Or, they can appear with an individual variable declared with an interface |
| qualifier:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="paragraph"> |
| <p><em>layout-qualifier</em> <em>interface-qualifier</em> <em>declaration</em> <strong>;</strong></p> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Declarations of layouts can only be made at global scope or block members, |
| and only where indicated in the following subsections; their details are |
| specific to what the interface qualifier is, and are discussed individually.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>layout-qualifier</em> expands to:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier</em> : </dt> |
| <dd> |
| <p><strong>layout</strong> <strong>(</strong> <em>layout-qualifier-id-list</em> <strong>)</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>layout-qualifier-id-list</em> : </dt> |
| <dd> |
| <p><em>layout-qualifier-id</em><br> |
| <em>layout-qualifier-id</em> <strong>,</strong> <em>layout-qualifier-id-list</em></p> |
| </dd> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><em>layout-qualifier-name</em><br> |
| <em>layout-qualifier-name</em> <strong>=</strong> <em>layout-qualifier-value</em><br> |
| <strong>shared</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-value</em> : </dt> |
| <dd> |
| <p><em>integer-constant</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The tokens used for <em>layout-qualifier-name</em> are identifiers, not keywords, |
| however, the <strong>shared</strong> keyword is allowed as a <em>layout-qualifier-id</em>. |
| Generally, they can be listed in any order. |
| Order-dependent meanings exist only if explicitly called out below. |
| As for other identifiers, they are case sensitive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The set of allowed layout qualifiers depends on the shader, the interface |
| and the variable type as specified in the following sections. |
| For example, a sampler in the default uniform block in a fragment shader can |
| have <strong>location</strong> and <strong>binding</strong> layout qualifiers but no others. |
| Invalid use of layout qualifiers is an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following table summarizes the use of layout qualifiers. |
| It shows for each one what kinds of declarations it may be applied to. |
| These are all discussed in detail in the following sections.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.667%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-middle">Layout Qualifier</th> |
| <th class="tableblock halign-center valign-middle">Qualifier Only</th> |
| <th class="tableblock halign-center valign-middle">Individual Variable</th> |
| <th class="tableblock halign-center valign-middle">Block</th> |
| <th class="tableblock halign-center valign-middle">Block Member</th> |
| <th class="tableblock halign-left valign-middle">Allowed Interfaces</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>shared</strong><br> |
| <strong>packed</strong><br> |
| <strong>std140</strong><br> |
| <strong>std430</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle" rowspan="5"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>row_major</strong><br> |
| <strong>column_major</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>binding</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">opaque types only</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>offset</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">atomic counters only</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">Vulkan only</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>align</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">Vulkan only</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">Vulkan only</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>set</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">opaque types only</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong> (Vulkan only)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>push_constant</strong></p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniform</strong> (Vulkan only)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>input_attachment_index</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">subpass types only</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniform</strong> (Vulkan only)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>location</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>location</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X<sup>1</sup></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">all <strong>in</strong> / <strong>out</strong>, except for compute</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>triangles</strong><br> |
| <strong>quads</strong><br> |
| <strong>isolines</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>equal_spacing</strong><br> |
| <strong>fractional_even_spacing</strong><br> |
| <strong>fractional_odd_spacing</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>cw</strong><br> |
| <strong>ccw</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>point_mode</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>points</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">geometry <strong>in</strong>/<strong>out</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">[ <strong>points</strong> ]<br> |
| <strong>lines</strong><br> |
| <strong>lines_adjacency</strong><br> |
| <strong>triangles</strong><br> |
| <strong>triangles_adjacency</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">geometry <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>invocations</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">geometry <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>early_fragment_tests</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">fragment <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>local_size_x</strong> =<br> |
| <strong>local_size_y</strong> =<br> |
| <strong>local_size_z</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">compute <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>local_size_x_id</strong> =<br> |
| <strong>local_size_y_id</strong> =<br> |
| <strong>local_size_z_id</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">compute <strong>in</strong> (SPIR-V only)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>vertices</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">tessellation control <strong>out</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">[ <strong>points</strong> ]<br> |
| <strong>line_strip</strong><br></p> |
| <p class="tableblock"> <strong>triangle_strip</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle" rowspan="2"><p class="tableblock">geometry <strong>out</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>max_vertices</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>constant_id</strong> =</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">scalar only</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>const</strong> (SPIR-V only)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>rgba32f</strong><br> |
| <strong>rgba16f</strong><br> |
| <strong>r32f</strong><br> |
| <strong>rgba8</strong><br> |
| <strong>rgba8_snorm</strong><br> |
| <strong>rgba32i</strong><br> |
| <strong>rgba16i</strong><br> |
| <strong>rgba8i</strong><br> |
| <strong>r32i</strong><br> |
| <strong>rgba32ui</strong><br> |
| <strong>rgba16ui</strong><br> |
| <strong>rgba8ui</strong><br> |
| <strong>r32ui</strong></p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">image types only</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniform</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>blend_support_multiply</strong><br> |
| <strong>blend_support_screen</strong><br> |
| <strong>blend_support_overlay</strong><br> |
| <strong>blend_support_darken</strong><br> |
| <strong>blend_support_lighten</strong><br> |
| <strong>blend_support_colordodge blend_support_colorburn</strong><br> |
| <strong>blend_support_hardlight</strong><br> |
| <strong>blend_support_softlight</strong><br> |
| <strong>blend_support_difference</strong><br> |
| <strong>blend_support_exclusion</strong><br> |
| <strong>blend_support_hsl_hue</strong><br> |
| <strong>blend_support_hsl_saturation</strong><br> |
| <strong>blend_support_hsl_color blend_support_hsl_luminosity</strong><br> |
| <strong>blend_support_all_equations</strong></p></td> |
| <td class="tableblock halign-center valign-middle"><p class="tableblock">X</p></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-center valign-middle"></td> |
| <td class="tableblock halign-left valign-middle"><p class="tableblock">fragment <strong>out</strong></p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">1</dt> |
| <dd> |
| <p>Location qualifiers are not allowed for members of an arrayed block, |
| except for per-vertex-arrays (see “<a href="#interface-blocks">Interface |
| Blocks</a>”).</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="sect3"> |
| <h4 id="input-layout-qualifiers">4.4.1. Input Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Layout qualifiers specific to a particular shader language are discussed in |
| separate sections below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All shaders except compute shaders allow <strong>location</strong> layout qualifiers on |
| input variable declarations, input block declarations, and input block |
| member declarations.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in vec4 normal;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that the shader input <em>normal</em> is assigned to vector location |
| number |
| 3. |
| For vertex shader inputs, the location specifies the number of the |
| vertex attribute from which input values are taken. |
| For inputs of all other shader types, the location specifies a vector number |
| that can be used to match against outputs from a previous shader stage, even |
| if that shader is in a different program object.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following language describes how many locations are consumed by a given |
| type. |
| However, geometry shader inputs, tessellation control shader inputs and |
| outputs, and tessellation evaluation inputs all have an additional level of |
| arrayness relative to other shader inputs and outputs. |
| This outer array level is removed from the type before considering how many |
| locations the type consumes.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a shader input is any scalar or vector type, it will consume a single |
| location.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared input (after potentially removing an outer array level as |
| just described above) is an array of size <em>n</em> and each of the elements takes |
| <em>m</em> locations, it will be assigned <em>m</em> * <em>n</em> consecutive locations starting |
| with the location specified. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">6</span>) in vec4 colors[<span class="integer">3</span>];</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that the shader input <em>colors</em> is assigned to vector location |
| numbers 6, 7, and 8.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared input is an <em>n</em> × <em>m</em> |
| matrix, it will be assigned multiple locations starting with the location |
| specified. |
| The number of locations assigned for each matrix will be the same as for an |
| <em>n</em>-element array of <em>m</em>-component vectors. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">9</span>) in mat4 transforms[<span class="integer">2</span>];</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that shader input <em>transforms</em> is assigned to vector |
| locations 9-16, with <em>transforms[0]</em> being assigned to locations 9-12, and |
| <em>transforms[1]</em> being assigned to locations 13-16.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared input is a structure or block, its members will be assigned |
| consecutive locations in their order of declaration, with the first member |
| assigned the location provided in the layout qualifier. |
| For a structure, this process applies to the entire structure. |
| It is a compile-time error to use a <strong>location</strong> qualifier on a member of a |
| structure. |
| For a block, this process applies to the entire block, or until the first |
| member is reached that has a <strong>location</strong> layout qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a block member is declared with a <strong>location</strong> qualifier, its location |
| comes from that qualifier; the member’s <strong>location</strong> qualifier overrides the |
| block-level declaration. |
| Subsequent members are again assigned consecutive locations, based on the |
| newest location, until the next member declared with a <strong>location</strong> qualifier. |
| The values used for locations do not have to be declared in increasing |
| order.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a block has no block-level <strong>location</strong> layout qualifier, it is required |
| that either all or none of its members have a <strong>location</strong> layout qualifier, |
| or a compile-time error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an input is declared as an array of blocks, excluding per-vertex-arrays |
| as required for tessellation, it is an error to declare a member of the |
| block with a <strong>location</strong> qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When generating SPIR-V, all <strong>in</strong> and <strong>out</strong> qualified user-declared (non |
| built-in) variables and blocks (or all their members) must have a |
| shader-specified <strong>location</strong>. |
| Otherwise, a compile-time error is generated.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The locations consumed by block and structure members are determined by |
| applying the rules above recursively as though the structure member were |
| declared as an input variable of the same type. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in <span class="keyword">struct</span> S |
| { |
| vec3 a; <span class="comment">// gets location 3</span> |
| mat2 b; <span class="comment">// gets locations 4 and 5</span> |
| vec4 c[<span class="integer">2</span>]; <span class="comment">// gets locations 6 and 7</span> |
| layout(location = <span class="integer">8</span>) vec2 A; <span class="comment">// ERROR, can't use on struct member</span> |
| } s; |
| layout(location = <span class="integer">4</span>) in block |
| { |
| vec4 d; <span class="comment">// gets location 4</span> |
| vec4 e; <span class="comment">// gets location 5</span> |
| layout(location = <span class="integer">7</span>) vec4 f; <span class="comment">// gets location 7</span> |
| vec4 g; <span class="comment">// gets location 8</span> |
| layout(location = <span class="integer">1</span>) vec4 h; <span class="comment">// gets location 1</span> |
| vec4 i; <span class="comment">// gets location 2</span> |
| vec4 j; <span class="comment">// gets location 3</span> |
| vec4 k; <span class="comment">// ERROR, location 4 already used</span> |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The number of input locations available to a shader is limited. |
| For vertex shaders, the limit is the advertised number of vertex attributes. |
| For all other shaders, the limit is implementation-dependent and must be no |
| less than one fourth of the advertised maximum input component count.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A program will fail to link if any attached shader uses a location greater |
| than or equal to the number of supported locations, unless device-dependent |
| optimizations are able to make the program fit within available hardware |
| resources.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A program will fail to link if explicit location assignments leave the |
| linker unable to find space for other variables without explicit |
| assignments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the purposes of determining if a non-vertex input matches an output from |
| a previous shader stage, the <strong>location</strong> layout qualifier (if any) must |
| match.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a vertex shader input variable with no location assigned in the shader |
| text has a location specified through the OpenGL ES API, the API-assigned |
| location will be used. |
| Otherwise, such variables will be assigned a location by the linker. |
| See section 11.1.1 “Vertex Attributes” of the <a href="#references">OpenGL ES Specification</a> for |
| more details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is an error if more than one input or element of a matrix input is bound |
| to the same location.</p> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-evaluation-inputs">Tessellation Evaluation Inputs</h5> |
| <div class="paragraph"> |
| <p>Additional input layout qualifier identifiers allowed for tessellation |
| evaluation shaders are described below.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><em>primitive_mode</em><br> |
| <em>vertex_spacing</em><br> |
| <em>ordering</em><br> |
| <em>point_mode</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>primitive-mode</strong> is used to specify a tessellation primitive mode to be |
| used by the tessellation primitive generator.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>primitive-mode</em>: </dt> |
| <dd> |
| <p><strong>triangles</strong><br> |
| <strong>quads</strong><br> |
| <strong>isolines</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If present, the <em>primitive-mode</em> specifies that the tessellation primitive |
| generator should subdivide a triangle into smaller triangles, a quad into |
| triangles, or a quad into a collection of lines, respectively.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A second group of layout identifiers, <em>vertex spacing</em>, is used to specify |
| the spacing used by the tessellation primitive generator when subdividing an |
| edge.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>vertex-spacing</em>: </dt> |
| <dd> |
| <p><strong>equal_spacing</strong><br> |
| <strong>fractional_even_spacing</strong><br> |
| <strong>fractional_odd_spacing</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>equal_spacing</strong> specifies that edges should be divided into a collection of |
| equal-sized segments;</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>fractional_even_spacing</strong> specifies that edges should be divided into an |
| even number of equal-length segments plus two additional shorter |
| “fractional” segments; or</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>fractional_odd_spacing</strong> specifies that edges should be divided into an odd |
| number of equal-length segments plus two additional shorter “fractional” |
| segments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A third group of layout identifiers, <em>ordering</em>, specifies whether the |
| tessellation primitive generator produces triangles in clockwise or |
| counter-clockwise order, according to the coordinate system depicted in the |
| <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>ordering</em>: </dt> |
| <dd> |
| <p><strong>cw</strong><br> |
| <strong>ccw</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The identifiers <strong>cw</strong> and <strong>ccw</strong> indicate clockwise and counter-clockwise |
| triangles, respectively. |
| If the tessellation primitive generator does not produce triangles, the |
| order is ignored.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Finally, <em>point mode</em> indicates that the tessellation primitive generator |
| should produce one point for each distinct vertex in the subdivided |
| primitive, rather than generating lines or triangles.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>point-mode</em>: </dt> |
| <dd> |
| <p><strong>point_mode</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Any or all of these identifiers may be specified one or more times in a |
| single input layout declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The tessellation evaluation shader object in a program must declare a |
| primitive mode in its input layout. |
| Declaring vertex spacing, ordering, or point mode identifiers is optional. |
| If spacing or vertex ordering declarations are omitted, the tessellation |
| primitive generator will use equal spacing or counter-clockwise vertex |
| ordering, respectively. |
| If a point mode declaration is omitted, the tessellation primitive generator |
| will produce lines or triangles according to the primitive mode.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="geometry-shader-inputs">Geometry Shader Inputs</h5> |
| <div class="paragraph"> |
| <p>Additional layout qualifier identifiers for geometry shader inputs include |
| <em>primitive</em> identifiers and an <em>invocation count</em> identifier:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>points</strong><br> |
| <strong>lines</strong><br> |
| <strong>lines_adjacency</strong><br> |
| <strong>triangles</strong><br> |
| <strong>triangles_adjacency</strong><br> |
| <strong>invocations</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The identifiers <strong>points</strong>, <strong>lines</strong>, <strong>lines_adjacency</strong>, <strong>triangles</strong>, and |
| <strong>triangles_adjacency</strong> are used to specify the type of input primitive |
| accepted by the geometry shader, and only one of these is accepted. |
| The geometry shader must declare this input primitive layout.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The identifier <strong>invocations</strong> is used to specify the number of times the |
| geometry shader executable is invoked for each input primitive received. |
| Invocation count declarations are optional. |
| If no invocation count is declared in the geometry shader, it will be run |
| once for each input primitive. |
| If an invocation count is declared, all such declarations must specify the |
| same count. |
| If a shader specifies an invocation count greater than the |
| implementation-dependent maximum, or less than or equal to zero, |
| a compile-time error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(triangles, invocations = <span class="integer">6</span>) in;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that all inputs to the geometry shader are triangles and that |
| the geometry shader executable is run six times for each triangle processed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All geometry shader input unsized array declarations will be sized by an |
| earlier input primitive layout qualifier, when present, as per the following |
| table.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Layout</th> |
| <th class="tableblock halign-left valign-top">Size of Input Arrays</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>points</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines_adjacency</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles_adjacency</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The intrinsically declared input array <em>gl_in[]</em> will also be sized by any |
| input primitive-layout declaration. |
| Hence, the expression</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">gl_in.length()</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will return the value from the table above.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An input can be declared without an array size if there is a previous layout |
| which specifies the size. |
| For built-in inputs (e.g. <em>gl_in[]</em>), a layout must be declared before any |
| use.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error if a layout declaration’s array size (from the |
| table above) does not match all the explicit array sizes specified in |
| declarations of an input variables in the same shader. |
| The following includes examples of compile-time errors:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// code sequence within one shader...</span> |
| in vec4 Color2[<span class="integer">2</span>]; <span class="comment">// legal, size is 2</span> |
| in vec4 Color3[<span class="integer">3</span>]; <span class="comment">// illegal, input sizes are inconsistent</span> |
| layout(lines) in; <span class="comment">// legal for Color2, input size is 2, matching Color2</span> |
| in vec4 Color4[<span class="integer">3</span>]; <span class="comment">// illegal, contradicts layout of lines</span> |
| layout(lines) in; <span class="comment">// legal, matches other layout() declaration</span> |
| layout(triangles) in; <span class="comment">// illegal, does not match earlier layout() declaration</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>It is a link-time error if not all provided sizes (sized input arrays and |
| layout size) match in the geometry shader of a program.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="fragment-shader-inputs">Fragment Shader Inputs</h5> |
| <div class="paragraph"> |
| <p>Fragment shaders allow the following layout qualifier on <strong>in</strong> only (not with |
| variable declarations):</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>early_fragment_tests</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>to request that fragment tests be performed before fragment shader |
| execution, as described in section 13.8.4 “Early Fragment Tests” of the |
| <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(early_fragment_tests) in;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Specifying this will make per-fragment tests be performed before fragment |
| shader execution. |
| In addition it is an error to statically write to <em>gl_FragDepth</em> in the |
| fragment shader. |
| If this is not declared, per-fragment tests will be performed after fragment |
| shader execution.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="compute-shader-inputs">Compute Shader Inputs</h5> |
| <div class="paragraph"> |
| <p>There are no layout location qualifiers for compute shader inputs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Layout qualifier identifiers for compute shader inputs are the workgroup |
| size qualifiers:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>local_size_x</strong> <strong>=</strong> <em>layout-qualifier-value</em><br> |
| <strong>local_size_y</strong> <strong>=</strong> <em>layout-qualifier-value</em><br> |
| <strong>local_size_z</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> qualifiers are used |
| to declare a fixed workgroup size by the compute shader in the first, |
| second, and third dimension, respectively. |
| If a shader does not specify a size for one of the dimensions, that |
| dimension will have a size of 1.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, the following declaration in a compute shader</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">32</span>, local_size_y = <span class="integer">32</span>) in;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>is used to declare a two-dimensional compute shader with a workgroup size of 32 |
| X 32 elements, which is equivalent to a three-dimensional compute shader |
| where the third dimension has size one.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As another example, the declaration</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">8</span>) in;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>effectively specifies that a one-dimensional compute shader is being |
| compiled, and its size is 8 elements.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the fixed workgroup size of the shader in any dimension is less than |
| or equal to zero or greater than the maximum size supported by the |
| implementation for that dimension, a compile-time error results. |
| Also, if such a layout qualifier is declared more than once in the same |
| shader, all those declarations must set the same set of workgroup |
| sizes and set them to the same values; otherwise a compile-time error |
| results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Furthermore, if a program object contains a compute shader, that shader must |
| contain an input layout qualifier specifying a fixed workgroup size for |
| the program, or a link-time error will occur.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="output-layout-qualifiers">4.4.2. Output Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Some output layout qualifiers apply to all shader stages and some apply only |
| to specific stages. |
| The latter are discussed in separate sections below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As with input layout qualifiers, all shaders except compute shaders allow |
| <strong>location</strong> layout qualifiers on output variable declarations, output block |
| declarations, and output block member declarations.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The usage and rules for applying the <strong>location</strong> qualifier |
| to blocks and structures are exactly as described in |
| “<a href="#input-layout-qualifiers">Input Layout Qualifiers</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The qualifier may appear at most once within a declaration. |
| For example, in a fragment shader,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) out vec4 color;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that the fragment shader output <em>color</em> is assigned to</p> |
| </div> |
| <div class="paragraph"> |
| <p>fragment color 3.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For fragment shader outputs, the location |
| specifies |
| the color output number |
| receiving the values of the output. |
| For outputs of all other shader stages, the location specifies a vector |
| number that can be used to match against inputs in a subsequent shader |
| stage, even if that shader is in a different program object.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Declared outputs of scalar or vector type consume a single location.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared output is an array, it will be assigned consecutive |
| locations starting with the location specified. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">2</span>) out vec4 colors[<span class="integer">3</span>];</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that <em>colors</em> is assigned to vector location numbers 2, 3, |
| and 4.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared output is an <em>n</em> × <em>m</em> |
| matrix, it will be assigned multiple locations starting with the location |
| specified. |
| The number of locations assigned will be the same as for an <em>n</em>-element |
| array of <em>m</em>-component vectors.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the declared output is a structure, its members will be assigned |
| consecutive locations in the order of declaration, with the first member |
| assigned the location specified for the structure. |
| The number of locations consumed by a structure member is determined by |
| applying the rules above recursively as though the structure member were |
| declared as an output variable of the same type.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>location</strong> layout qualifiers may be used on output variables declared as |
| structures. |
| However, it is a compile-time error to use a <strong>location</strong> qualifier on a |
| structure member. |
| Location layout qualifiers may be used on output blocks and output block |
| members.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an output is declared as an array of blocks, excluding per-vertex-arrays |
| as required for tessellation, it is an error to declare a member of the |
| block with a <strong>location</strong> qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The number of output locations available to a shader is limited. |
| For fragment shaders, the limit is the advertised number of draw buffers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For all other shaders, the limit is implementation-dependent and must be no |
| less than one fourth of the advertised maximum output component count |
| (compute shaders have no outputs). |
| A program will fail to link if any attached shader uses a location greater |
| than or equal to the number of supported locations, unless device-dependent |
| optimizations are able to make the program fit within available hardware |
| resources.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Compile-time errors may also be given if at compile time it is known the |
| link will fail. |
| A negative output location will result in an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time or link-time error if any of the following occur:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>any two fragment shader output variables are assigned to the same |
| location.</p> |
| </li> |
| <li> |
| <p>if any two output variables from the same vertex, tessellation or |
| geometry shader stage are assigned to the same location.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>For all shader types, a program will fail to link if explicit location |
| assignments leave the linker unable to find space for other variables |
| without explicit assignments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an output variable has no location assigned in the shader text, it will |
| be assigned a location by the linker. |
| See section 11.1.3 “Shader Execution” of the <a href="#references">OpenGL ES Specification</a> for |
| more details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If there is only a single output, the location does not need to be |
| specified, in which case it defaults to zero. |
| This applies for all output types, including arrays. |
| If there is more than one fragment output, the location must be specified |
| for all outputs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the purposes of determining if a non-fragment output matches an input |
| from a subsequent shader stage, the <strong>location</strong> layout qualifier (if any) |
| must match.</p> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-control-outputs">Tessellation Control Outputs</h5> |
| <div class="paragraph"> |
| <p>Tessellation control shaders allow output layout qualifiers only on the |
| interface |
| qualifier <strong>out</strong>, not on an output block, block member, or variable |
| declaration. |
| The output layout qualifier identifiers allowed for tessellation control |
| shaders are:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The identifier <strong>vertices</strong> specifies the number of vertices in the output |
| patch produced by the tessellation control shader, which also specifies the |
| number of times the tessellation control shader is invoked. |
| It is a compile- or link-time error for the output vertex count to be less |
| than or equal to zero, or greater than the implementation-dependent maximum |
| patch size.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The intrinsically declared tessellation control output array <em>gl_out[]</em> will |
| also be sized by any output layout declaration. |
| Hence, the expression</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">gl_out.length()</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will return the output patch vertex count specified in a previous output |
| layout qualifier. |
| For outputs declared without an array size, including intrinsically declared |
| outputs (i.e., <em>gl_out</em>), a layout must be declared before any use of the |
| method <strong>length</strong>() or other array use that requires its size to be known.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error if the output patch vertex count specified in an |
| output layout qualifier does not match the array size specified in any |
| output variable declaration in the same shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All tessellation control shader layout declarations in a program must |
| specify the same output patch vertex count. |
| There must be at least one layout qualifier specifying an output patch |
| vertex count in any program containing a tessellation control shader.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="geometry-outputs">Geometry Outputs</h5> |
| <div class="paragraph"> |
| <p>Geometry shaders can have two additional types of output layout identifiers: |
| an output primitive type and a maximum output vertex count. |
| The primitive type and vertex count identifiers are allowed only on the |
| interface qualifier <strong>out</strong>, not on an output block, block member, or variable |
| declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The layout qualifier identifiers for geometry shader outputs are</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>points</strong><br> |
| <strong>line_strip</strong><br> |
| <strong>triangle_strip</strong><br> |
| <strong>max_vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The primitive type identifiers <strong>points</strong>, <strong>line_strip</strong>, and <strong>triangle_strip</strong> |
| are used to specify the type of output primitive produced by the geometry |
| shader, and only one of these is accepted. |
| The geometry shader object in a program must declare an output primitive |
| type, and all geometry shader output primitive type declarations in a |
| program must declare the same primitive type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The vertex count identifier <strong>max_vertices</strong> is used to specify the maximum |
| number of vertices the shader will ever emit in a single invocation. |
| The geometry shader object in a program must declare a maximum output vertex |
| count, and all geometry shader output vertex count declarations in a program |
| must declare the same count.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In this example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(triangle_strip, max_vertices = <span class="integer">60</span>) out; <span class="comment">// order does not matter</span> |
| layout(max_vertices = <span class="integer">60</span>) out; <span class="comment">// redeclaration okay</span> |
| layout(triangle_strip) out; <span class="comment">// redeclaration okay</span> |
| layout(points) out; <span class="comment">// error, contradicts triangle_strip</span> |
| layout(max_vertices = <span class="integer">30</span>) out; <span class="comment">// error, contradicts 60</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>all outputs from the geometry shader are triangles and at most 60 vertices |
| will be emitted by the shader. |
| It is an error for the maximum number of vertices to be greater than |
| <em>gl_MaxGeometryOutputVertices</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All geometry shader output layout declarations in a program must declare the |
| same layout and same value for <strong>max_vertices</strong>. |
| If geometry shaders are in a program, there must be at least one geometry |
| output layout declaration somewhere in that |
| program.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="fragment-outputs">Fragment Outputs</h5> |
| <div class="paragraph"> |
| <p>Fragment shaders can have an output layout for redeclaring the built-in |
| variable <em>gl_FragDepth</em>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// redeclaration that changes nothing is allowed +</span> |
| out <span class="predefined-type">float</span> gl_FragDepth;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in <em>gl_FragDepth</em> is only predeclared in fragment shaders, so |
| redeclaring it in any other shader language results in an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shaders additionally support layout qualifiers specifying a set of |
| advanced blend equations supported when the fragment shader is used. |
| These layout qualifiers are only permitted on the interface qualifier <strong>out</strong>, |
| and use the identifiers specified in the “Layout Qualifier” column of the |
| table below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a layout qualifier in the table below is specified in the fragment |
| shader, the fragment shader may be used with the corresponding advanced |
| blend equation in the “Blend Equation(s) Supported” column. |
| Additionally, the special qualifier <strong>blend_support_all_equations</strong> indicates |
| that the shader may be used with any advanced blending equation supported by |
| the <a href="#references">OpenGL ES Specification</a>. |
| It is not an error to specify more than one of these identifiers in any |
| fragment shader. |
| Specifying more than one qualifier or <strong>blend_support_all_equations</strong> means |
| that the fragment shader may be used with multiple advanced blend equations. |
| Additionally, it is not an error to specify any single one of these layout |
| qualifiers more than once.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Layout Qualifier</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Blend Equations(s) Supported</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_multiply</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">MULTIPLY</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_screen</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SCREEN</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_overlay</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">OVERLAY</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_darken</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">DARKEN</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_lighten</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">LIGHTEN</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_colordodge</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">COLORDODGE</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_colorburn</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">COLORBURN</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hardlight</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HARDLIGHT</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_softlight</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SOFTLIGHT</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_difference</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">DIFFERENCE</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_exclusion</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">EXCLUSION</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_hue</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HSL_HUE</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_saturation</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HSL_SATURATION</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_color</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HSL_COLOR</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_luminosity</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HSL_LUMINOSITY</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_all_equations</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">all blend equations</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="uniform-variable-layout-qualifiers">4.4.3. Uniform Variable Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>The following layout qualifier can be used for all default-block uniform |
| variables but not for variables in uniform or shader storage blocks. |
| The layout qualifier identifier for uniform variables is:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The location specifies the location by which the API can reference |
| the uniform and update its value. |
| Individual elements of a uniform array are assigned consecutive locations |
| with the first element taking location <strong>location</strong>. |
| Default-block uniform variable declarations sharing the same location |
| linked in the program have to match by name, type, qualifiers and arrayness. |
| For arrays their array dimensionality and array sizes must match. |
| For structs this rule applies recursively to all members. |
| Valid locations for default-block uniform variable locations are in the |
| range of 0 to the implementation-defined maximum number of uniform locations |
| minus one.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Locations can be assigned to default-block uniform arrays and structures. |
| The first inner-most scalar, vector or matrix member or element takes the |
| specified <strong>location</strong> and the compiler assigns the next inner-most member or |
| element the next incremental location value. |
| Each subsequent inner-most member or element gets incremental locations for |
| the entire structure or array. |
| This rule applies to nested structures and arrays and gives each inner-most |
| scalar, vector, or matrix member a unique location. |
| When the linker generates locations for uniforms without an explicit |
| location, it assumes for all uniforms with an explicit location all their |
| array elements and structure members are used and the linker will not |
| generate a conflicting location, even if that element or member is deemed |
| unused.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, the <strong>push_constant</strong> qualifier is used to |
| declare an entire block, and represents a set of <em>push constants</em>, as defined |
| by the Vulkan API. |
| It is an error to apply this to anything other than a uniform block |
| declaration, or when not targeting Vulkan. |
| The values in the block will be initialized as per the Vulkan API specification. |
| A block declared with <code>layout(push_constant)</code> may optionally include an |
| <em>instance-name</em>. |
| There can be only one <strong>push_constant</strong> block per stage, or a compile-time or |
| link-time error will result. |
| A push-constant array can only be indexed with dynamically uniform indices. |
| Uniform blocks declared with <strong>push_constant</strong> use different resources |
| than those without; and are accounted for separately.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="uniform-and-shader-storage-block-layout-qualifiers">4.4.4. Uniform and Shader Storage Block Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Layout qualifiers can be used for uniform and shader storage blocks, but not |
| for non-block uniform declarations. |
| The layout qualifier identifiers (and <strong>shared</strong> keyword) for uniform and |
| shader storage blocks are:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>shared</strong><br> |
| <strong>packed</strong><br> |
| <strong>std140</strong><br> |
| <strong>std430</strong><br> |
| <strong>row_major</strong><br> |
| <strong>column_major</strong><br> |
| <strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em><br> |
| <strong>offset</strong> <strong>=</strong> <em>layout-qualifier-value</em> // Vulkan only<br> |
| <strong>align</strong> <strong>=</strong> <em>layout-qualifier-value</em> // Vulkan only</p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>None of these have any semantic effect at all on the usage of the variables |
| being declared; they only describe how data is laid out in memory. |
| For example, matrix semantics are always column-based, as described in the |
| rest of this specification, no matter what layout qualifiers are being used.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Uniform and shader storage block layout qualifiers can be declared for |
| global scope, on a single uniform or shader storage block, or on a single |
| block member declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Default layouts are established at global scope for uniform blocks as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) uniform;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and for shader storage blocks as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) buffer;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When this is done, the previous default qualification is first inherited and |
| then overridden as per the override rules listed below for each qualifier |
| listed in the declaration. |
| The result becomes the new default qualification scoped to subsequent |
| uniform or shader storage block definitions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The initial state of compilation when generating SPIR-V is as if the |
| following were declared:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(std140, column_major) uniform; |
| layout(std430, column_major) buffer;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>However, when <strong>push_constant</strong> is declared, the default layout of the |
| buffer will be <strong>std430</strong>. There is no method to globally set this default.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The initial state of compilation when not generating SPIR-V is as if the |
| following were declared:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(shared, column_major) uniform; |
| layout(shared, column_major) buffer;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Uniform and shader storage blocks can be declared with optional layout |
| qualifiers, and so can their individual member declarations. |
| Such block layout qualification is scoped only to the content of the block. |
| As with global layout declarations, block layout qualification first |
| inherits from the current default qualification and then overrides it. |
| Similarly, individual member layout qualification is scoped just to the |
| member declaration, and inherits from and overrides the block’s |
| qualification.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>shared</strong> qualifier overrides only the <strong>std140</strong>, <strong>std430</strong>, and <strong>packed</strong> |
| qualifiers; other qualifiers are inherited. |
| The compiler/linker will ensure that multiple programs and programmable |
| stages containing this definition will share the same memory layout for this |
| block, as long as they also matched in their <strong>row_major</strong> and/or |
| <strong>column_major</strong> qualifications. |
| This allows use of the same buffer to back the same block definition across |
| different programs. |
| It is a compile-time error to use the <strong>shared</strong> qualifier when generating |
| SPIR-V.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>packed</strong> qualifier overrides only <strong>std140</strong>, <strong>std430</strong>, and <strong>shared</strong>; |
| other qualifiers are inherited. |
| When <strong>packed</strong> is used, no shareable layout is guaranteed. |
| The compiler and linker can optimize memory use based on what variables |
| actively get used and on other criteria. |
| Offsets must be queried, as there is no other way of guaranteeing where (and |
| which) variables reside within the block.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a link-time error to access the same packed uniform or shader storage |
| block in multiple stages within a program. |
| Attempts to access the same packed uniform or shader storage block across |
| programs can result in conflicting member offsets and in undefined values |
| being read. |
| However, implementations may aid application management of packed blocks by |
| using canonical layouts for packed blocks. |
| It is a compile-time error to use the <strong>packed</strong> qualifier when generating |
| SPIR-V.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>std140</strong> and <strong>std430</strong> qualifiers override only the <strong>packed</strong>, <strong>shared</strong>, |
| <strong>std140</strong>, and <strong>std430</strong> qualifiers; other qualifiers are inherited. |
| The <strong>std430</strong> qualifier is supported only for shader storage blocks; a shader |
| using the <strong>std430</strong> qualifier on a uniform block will result in |
| an error, unless it is also declared with <strong>push_constant</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The layout is explicitly determined by this, as described in section 7.6.2.2 |
| “Standard Uniform Block Layout” of the <a href="#references">OpenGL ES Specification</a>. |
| Hence, as in <strong>shared</strong> above, the resulting layout is shareable across |
| programs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Layout qualifiers on member declarations cannot use the <strong>shared</strong>, <strong>packed</strong>, |
| <strong>std140</strong>, or <strong>std430</strong> qualifiers. |
| These can only be used at global scope (without an object) or on a block |
| declaration, or an error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>row_major</strong> and <strong>column_major</strong> qualifiers only affect the layout of |
| matrices, including all matrices contained in structures and arrays they are |
| applied to, to all depths of nesting. |
| These qualifiers can be applied to other types, but will have no effect.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>row_major</strong> qualifier overrides only the <strong>column_major</strong> qualifier; other |
| qualifiers are inherited. |
| Elements within a matrix row will be contiguous in memory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>column_major</strong> qualifier overrides only the <strong>row_major</strong> qualifier; other |
| qualifiers are inherited. |
| Elements within a matrix column will be contiguous in memory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>binding</strong> qualifier specifies the uniform buffer binding point |
| corresponding to the uniform or shader storage block, which will be used to |
| obtain the values of the member variables of the block. |
| It is a compile-time error to specify the <strong>binding</strong> qualifier for the global |
| scope or for block member declarations. |
| Any uniform or shader storage block declared without a <strong>binding</strong> qualifier |
| is initially assigned to block binding point zero. |
| After a program is linked, the binding points used for uniform |
| (but not shader storage) blocks |
| declared with or without a <strong>binding</strong> qualifier can be updated |
| by the API.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When used with OpenGL ES, |
| if the <strong>binding</strong> qualifier is used with a uniform block or shader storage |
| block instanced as an array, the first element of the array takes the |
| specified block binding and each subsequent element takes the next |
| consecutive binding point. |
| For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a |
| binding point, and they are ordered per the array of array ordering |
| described in “<a href="#arrays">Arrays.</a>”</p> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, |
| if the <strong>binding</strong> qualifier is used with a uniform block or buffer block |
| instanced as an array, the entire array takes only the provided binding |
| number. |
| The next consecutive binding number is available for a different |
| object. |
| For an array of arrays, descriptor set array element numbers used |
| in descriptor set accesses are ordered per the array-of-array ordering |
| described in “<a href="#arrays">Arrays.</a>”</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the binding point for any uniform or shader storage block instance is |
| less than zero, or greater than or equal to the corresponding |
| implementation-dependent maximum number of buffer bindings, a compile-time |
| error will occur. |
| When the <strong>binding</strong> qualifier is used with a uniform or shader storage block |
| instanced as an array of size <em>N</em>, all elements of the array from <strong>binding</strong> |
| through <em>binding + N - 1</em> must be within this range.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>set</strong> qualifier is only available when targeting Vulkan. |
| It specifies the descriptor set this object belongs to. |
| It is an error to apply <strong>set</strong> to a standalone qualifier, to |
| a member of a block, or when not targeting an API that supports descriptor sets. |
| It is an error to apply <strong>set</strong> to a block qualified as <strong>push_constant</strong>. |
| By default, any non-push-constant uniform or shader storage block declared |
| without a <strong>set</strong> identifier is assigned to descriptor set 0. |
| Similarly, any sampler, texture, or subpass-input type declared as a uniform |
| without a <strong>set</strong> identifier is also assigned to descriptor set 0.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If applied to an object declared as an array, all elements of the array |
| belong to the specified <strong>set</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When generating SPIR-V, it is an error for either the <strong>set</strong> or |
| <strong>binding</strong> value to exceed a front-end-configuration supplied maximum value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When multiple arguments are listed in a <strong>layout</strong> declaration, the effect |
| will be the same as if they were declared one at a time, in order from left |
| to right, each in turn inheriting from and overriding the result from the |
| previous qualification.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(row_major, column_major)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>results in the qualification being <strong>column_major</strong>. |
| Other examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(shared, row_major) uniform; <span class="comment">// default is now shared and row_major</span> |
| |
| layout(std140) uniform Transform { <span class="comment">// layout of this block is std140</span> |
| mat4 M1; <span class="comment">// row major</span> |
| layout(column_major) mat4 M2; <span class="comment">// column major</span> |
| mat3 N1; <span class="comment">// row major</span> |
| }; |
| |
| uniform T2 { <span class="comment">// layout of this block is shared</span> |
| ... |
| }; |
| |
| layout(column_major) uniform T3 { <span class="comment">// shared and column major</span> |
| mat4 M3; <span class="comment">// column major</span> |
| layout(row_major) mat4 m4; <span class="comment">// row major</span> |
| mat3 N2; <span class="comment">// column major</span> |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, the <strong>offset</strong> and <strong>align</strong> qualifiers for blocks and |
| block members can only be used with <strong>uniform</strong> and <strong>buffer</strong> blocks. |
| When not targeting Vulkan, they cannot be used with blocks or block members.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>offset</strong> qualifier can only be used on block members. |
| The <strong>offset</strong> qualifier forces the qualified member to start at or after the |
| specified <em>layout-qualifier-value</em>, which will be its byte offset from |
| the beginning of the buffer. |
| It is a compile-time error to have any offset, explicit or assigned, that |
| lies within another member of the block. |
| Two blocks linked together in the same program with the same block name must |
| have the exact same set of members qualified with <strong>offset</strong> and their |
| <em>layout-qualifier-value</em> values must be the same, or a link-time error |
| results. |
| The specified offset must be a multiple of the base alignment of the type of |
| the block member it qualifies, or a compile-time error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>align</strong> qualifier makes the start of each block member have a minimum |
| byte alignment. |
| It does not affect the internal layout within each member, which will still |
| follow the <strong>std140</strong> or <strong>std430</strong> rules. |
| The specified alignment must be greater than 0 and a power of 2, or a |
| compile-time error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>actual alignment</em> of a member will be the greater of the specified |
| <strong>align</strong> alignment and the standard (e.g. <strong>std140</strong>) base alignment for the |
| member’s type. |
| The <em>actual offset</em> of a member is computed as follows: If <strong>offset</strong> was |
| declared, start with that offset, otherwise start with the offset immediately |
| following the preceding member (in declaration order). |
| If the resulting offset is not a multiple of the <em>actual alignment</em>, |
| increase it to the first offset that is a multiple of the <em>actual |
| alignment</em>. |
| This results in the <em>actual offset</em> the member will have.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When <strong>align</strong> is applied to an array, it affects only the start of the array, |
| not the array’s internal stride. |
| Both an <strong>offset</strong> and an <strong>align</strong> qualifier can be specified on a declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>align</strong> qualifier, when used on a block, has the same effect as |
| qualifying each member with the same <strong>align</strong> value as declared on the block, |
| and gets the same compile-time results and errors as if this had been done. |
| As described in general earlier, an individual member can specify its own |
| <strong>align</strong>, which overrides the block-level <strong>align</strong>, but just for that member.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Examples:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(std140) uniform block { |
| vec4 a; <span class="comment">// a takes offsets 0-15</span> |
| layout(offset = <span class="integer">32</span>) vec3 b; <span class="comment">// b takes offsets 32-43</span> |
| layout(offset = <span class="integer">40</span>) vec2 c; <span class="comment">// ERROR, lies within previous member</span> |
| layout(offset = <span class="integer">48</span>) vec2 d; <span class="comment">// d takes offsets 48-55</span> |
| layout(align = <span class="integer">16</span>) <span class="predefined-type">float</span> e; <span class="comment">// e takes offsets 64-67</span> |
| layout(align = <span class="integer">2</span>) <span class="predefined-type">double</span> f; <span class="comment">// f takes offsets 72-79</span> |
| layout(align = <span class="integer">6</span>) <span class="predefined-type">double</span> g; <span class="comment">// ERROR, 6 is not a power of 2</span> |
| layout(offset = <span class="integer">80</span>) <span class="predefined-type">float</span> h; <span class="comment">// h takes offsets 80-83</span> |
| layout(align = <span class="integer">64</span>) dvec3 i; <span class="comment">// i takes offsets 128-151</span> |
| layout(offset = <span class="integer">164</span>, align = <span class="integer">8</span>) |
| <span class="predefined-type">float</span> j; <span class="comment">// j takes offsets 168-171</span> |
| };</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="opaque-uniform-layout-qualifiers">4.4.5. Opaque Uniform Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Opaque uniform variables can take the uniform layout qualifier for binding:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>binding</strong> qualifier specifies the point where the variable will be bound. |
| Any opaque variable declared without a binding qualifier has a default binding |
| of zero.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When used with OpenGL ES, |
| if the <strong>binding</strong> qualifier is used with an array, the first element of the |
| array takes the specified binding point and each subsequent element takes the |
| next consecutive binding point. |
| For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a |
| binding point, and they are ordered per the array of array ordering |
| described in “<a href="#arrays">Arrays.</a>”</p> |
| </div> |
| <div class="paragraph"> |
| <p>When targeting Vulkan, |
| if the <strong>binding</strong> qualifier is used with an array, the entire array |
| takes only the provided binding number. The next consecutive binding |
| number is available for a different object.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the <strong>binding</strong> is less than zero, or greater than or equal to the |
| implementation-dependent maximum supported number of binding points, |
| a compile-time error will occur. |
| When the <strong>binding</strong> qualifier is used with an array of size <em>N</em>, all elements |
| of the array from <strong>binding</strong> through <em>binding + N - 1</em> must be within this |
| range.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A link-time error will result if two shaders in a program specify different |
| <em>layout-qualifier-value</em> bindings for the same opaque-uniform name. |
| However, it is not an error to specify a binding on some but not all |
| declarations for the same name, as shown in the examples below.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// in one shader...</span> |
| layout(binding=<span class="integer">3</span>) uniform sampler2D s; <span class="comment">// s bound to point 3</span> |
| |
| <span class="comment">// in another shader...</span> |
| uniform sampler2D s; <span class="comment">// okay, s still bound at 3</span> |
| |
| <span class="comment">// in another shader...</span> |
| layout(binding=<span class="integer">4</span>) uniform sampler2D s; <span class="comment">// ERROR: contradictory bindings</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="atomic-counter-layout-qualifiers">4.4.6. Atomic Counter Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Atomic counters are not available when targeting Vulkan.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic counter layout qualifiers can be used on atomic counter declarations. |
| The atomic counter qualifiers are:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em><br> |
| <strong>offset</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint a;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that the opaque handle to the atomic counter <em>a</em> will be |
| bound to atomic counter buffer binding point 2 at an offset of 4 basic |
| machine units into that buffer. |
| The default <em>offset</em> for binding point 2 will be post incremented by 4 (the |
| size of an atomic counter).</p> |
| </div> |
| <div class="paragraph"> |
| <p>A subsequent atomic counter declaration will inherit the previous (post |
| incremented) offset. |
| For example, a subsequent declaration of</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will establish that the atomic counter <em>bar</em> has a binding to buffer binding |
| point 2 at an offset of 8 basic machine units into that buffer. |
| The offset for binding point 2 will again be post-incremented by 4 (the size |
| of an atomic counter).</p> |
| </div> |
| <div class="paragraph"> |
| <p>When multiple variables are listed in a layout declaration, the effect will |
| be the same as if they were declared one at a time, in order from left to |
| right.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Binding points are not inherited, only offsets. |
| Each binding point tracks its own current default <em>offset</em> for inheritance |
| of subsequent variables using the same <strong>binding</strong>. |
| The initial state of compilation is that all <strong>binding</strong> points have an |
| <em>offset</em> of 0. |
| The <em>offset</em> can be set per binding point at global scope (without declaring |
| a variable). |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Establishes that the next <strong>atomic_uint</strong> declaration for binding point 2 will |
| inherit <em>offset</em> 4 (but does not establish a default <strong>binding</strong>):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar; <span class="comment">// offset is 4</span> |
| layout(offset = <span class="integer">8</span>) uniform atomic_uint bar; <span class="comment">// error, no default binding</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic counters may share the same binding point, but if a binding is |
| shared, their offsets must be either explicitly or implicitly (from |
| inheritance) unique and non overlapping.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example valid uniform declarations, assuming top of shader:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(binding=<span class="integer">3</span>, offset=<span class="integer">4</span>) uniform atomic_uint a; <span class="comment">// offset = 4</span> |
| layout(binding=<span class="integer">2</span>) uniform atomic_uint b; <span class="comment">// offset = 0</span> |
| layout(binding=<span class="integer">3</span>) uniform atomic_uint c; <span class="comment">// offset = 8</span> |
| layout(binding=<span class="integer">2</span>) uniform atomic_uint d; <span class="comment">// offset = 4</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Example of an invalid uniform declaration:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(offset=<span class="integer">4</span>) ... <span class="comment">// error, must include binding</span> |
| layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... a; <span class="comment">// okay</span> |
| layout(binding=<span class="integer">2</span>, offset=<span class="integer">0</span>) ... b; <span class="comment">// okay</span> |
| layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... c; <span class="comment">// error, offsets must not be shared</span> |
| <span class="comment">// between a and c</span> |
| layout(binding=<span class="integer">1</span>, offset=<span class="integer">2</span>) ... d; <span class="comment">// error, overlaps offset 0 of a</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time error to bind an atomic counter with a binding value |
| greater than or equal to <em>gl_MaxAtomicCounterBindings</em>.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="format-layout-qualifiers">4.4.7. Format Layout Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Format layout qualifiers can be used on image variable declarations (those |
| declared with a basic type having “<strong>image</strong>” in its keyword). |
| The format layout qualifier identifiers for image variable declarations are:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>layout-qualifier-id</em> : </dt> |
| <dd> |
| <p><em>float-image-format-qualifier</em><br> |
| <em>int-image-format-qualifier</em><br> |
| <em>uint-image-format-qualifier</em><br> |
| <strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>float-image-format-qualifier</em> : </dt> |
| <dd> |
| <p><strong>rgba32f</strong><br> |
| <strong>rgba16f</strong><br> |
| <strong>r32f</strong><br> |
| <strong>rgba8</strong><br> |
| <strong>rgba8_snorm</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>int-image-format-qualifier</em> : </dt> |
| <dd> |
| <p><strong>rgba32i</strong><br> |
| <strong>rgba16i</strong><br> |
| <strong>rgba8i</strong><br> |
| <strong>r32i</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>uint-image-format-qualifier</em> : </dt> |
| <dd> |
| <p><strong>rgba32ui</strong><br> |
| <strong>rgba16ui</strong><br> |
| <strong>rgba8ui</strong><br> |
| <strong>r32ui</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A format layout qualifier specifies the image format associated with a |
| declared image variable. |
| Only one format qualifier may be specified for any image variable |
| declaration. |
| For image variables with floating-point component types (keywords starting |
| with “<strong>image</strong>”), signed integer component types (keywords starting with |
| “<strong>iimage</strong>”), or unsigned integer component types (keywords starting with |
| “<strong>uimage</strong>”), the format qualifier used must match the |
| <em>float-image-format-qualifier</em>, <em>int-image-format-qualifier</em>, or |
| <em>uint-image-format-qualifier</em> grammar rules, respectively. |
| It is an error to declare an image variable where the format |
| qualifier does not match the image variable type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any image variable must specify a format layout qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>binding</strong> qualifier was described in |
| “<a href="#opaque-uniform-layout-qualifiers">Opaque Uniform Layout Qualifiers</a>”.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_subpass_input_qualifier">4.4.8. Subpass Input Qualifier</h4> |
| <div class="paragraph"> |
| <p>Subpass inputs are only available when targeting Vulkan.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass inputs are declared with the basic <strong>subpassInput</strong> types. |
| They must be declared with the layout qualifier |
| <strong>input_attachment_index</strong>, or an error results. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(input_attachment_index = <span class="integer">2</span>) uniform subpassInput t;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This selects which subpass input is being read from. The value assigned |
| to <strong>input_attachment_index</strong>, say <em>i</em> (<code>input_attachment_index = i</code>), selects |
| that entry (<em>i</em> th entry) in the input list for the pass. See the API |
| documentation for more detail about passes and the input list.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an array of size <em>N</em> is declared, it consumes <em>N</em> consecutive |
| <strong>input_attachment_index</strong> values, starting with the one provided.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time or link-time error to have different variables |
| declared with the same <strong>input_attachment_index</strong>. |
| This includes any overlap in the implicit <strong>input_attachment_index</strong> consumed by |
| array declarations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is an error if the value assigned to an <strong>input_attachment_index</strong> |
| is greater than or equal to <em>gl_MaxInputAttachments</em>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="interpolation-qualifiers">4.5. Interpolation Qualifiers</h3> |
| <div class="paragraph"> |
| <p>Inputs and outputs that could be interpolated can be further qualified by at |
| most one of the following interpolation qualifiers:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">perspective correct interpolation</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>flat</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">no interpolation</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The presence of and type of interpolation is controlled by the above |
| interpolation qualifiers as well as the auxiliary storage qualifiers |
| <strong>centroid</strong> and <strong>sample</strong>. |
| When no interpolation qualifier is present, smooth interpolation is used. |
| It is a compile-time error to use more than one interpolation qualifier. |
| The auxiliary storage qualifier <strong>patch</strong> is not used for interpolation; it is |
| a compile-time error to use interpolation qualifiers with <strong>patch</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A variable qualified as <strong>flat</strong> will not be interpolated. |
| Instead, it will have the same value for every fragment within a primitive. |
| This value will come from a single provoking vertex, as described by the |
| <a href="#references">API</a>. |
| A variable qualified as <strong>flat</strong> may also be qualified as <strong>centroid</strong> or |
| <strong>sample</strong>, which will mean the same thing as qualifying it only as <strong>flat</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A variable qualified as <strong>smooth</strong> will be interpolated in a |
| perspective-correct manner over the primitive being rendered.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Interpolation in a perspective correct manner is specified in equations 13.4 |
| of the <a href="#references">OpenGL ES Specification</a>, section 13.4.1 “Line Segments” and |
| equation 13.7, section 13.5.1 “Polygon Interpolation”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When multisample rasterization is disabled, or for fragment shader input |
| variables qualified with neither <strong>centroid</strong> nor <strong>sample</strong>, the value of the |
| assigned variable may be interpolated anywhere within the pixel and a single |
| value may be assigned to each sample within the pixel, to the extent |
| permitted by the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When multisample rasterization is enabled, <strong>centroid</strong> and <strong>sample</strong> may be |
| used to control the location and frequency of the sampling of the qualified |
| fragment shader input. |
| If a fragment shader input is qualified with <strong>centroid</strong>, a single value may |
| be assigned to that variable for all samples in the pixel, but that value |
| must be interpolated at a location that lies in both the pixel and in the |
| primitive being rendered, including any of the pixel’s samples covered by |
| the primitive. |
| Because the location at which the variable is interpolated may be different |
| in neighboring pixels, and derivatives may be computed by computing |
| differences between neighboring pixels, derivatives of centroid-sampled |
| inputs may be less accurate than those for non-centroid interpolated |
| variables. |
| If a fragment shader input is qualified with <strong>sample</strong>, a separate value must |
| be assigned to that variable for each covered sample in the pixel, and that |
| value must be sampled at the location of the individual sample.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="parameter-qualifiers">4.6. Parameter Qualifiers</h3> |
| <div class="paragraph"> |
| <p>In addition to precision qualifiers and memory qualifiers, parameters can |
| have these parameter qualifiers.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><none: default></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">same as <strong>in</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed into a function</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed back out of a function, |
| but not initialized for use when passed in</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inout</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed both into and out of a |
| function</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Parameter qualifiers are discussed in more detail in |
| “<a href="#function-calling-conventions">Function Calling Conventions</a>”.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</h3> |
| <div class="paragraph"> |
| <p>When targeting Vulkan: |
| For interface matching, uniform variables and uniform and buffer block |
| members must have the same precision qualification. |
| Global variables declared in different compilation units linked into the |
| same shader stage must be declared with the same precision qualification.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the purposes of determining if an output from one shader stage matches |
| an input of the next stage, the precision qualifier need not match.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="range-and-precision">4.7.1. Range and Precision</h4> |
| <div class="paragraph"> |
| <p>The precision of <strong>highp</strong> |
| floating-point variables is defined by the IEEE 754 standard for |
| 32-bit |
| floating-point numbers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This includes support for NaNs (Not a Number) and Infs (positive or negative |
| infinities) and positive and negative zeros.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following rules apply to <strong>highp</strong> |
| operations: |
| Signed infinities and zeros are generated as dictated by IEEE, but subject |
| to the precisions allowed in the following table. |
| Any subnormal (denormalized) value input into a shader or potentially |
| generated by any operation in a shader can be flushed to 0. |
| The rounding mode cannot be set and is undefined but must not affect the |
| result by more than 1 ULP. |
| NaNs are not required to be generated. |
| Support for signaling NaNs is not required and exceptions are never raised. |
| Operations including built-in functions that operate on a NaN are not |
| required to return a NaN as the result. |
| However if NaNs are generated, <strong>isnan</strong>() must return the correct value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Precisions are expressed in terms of maximum relative error in units of ULP |
| (units in the last place), unless otherwise noted.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For single precision operations, precisions are required as follows:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Operation</th> |
| <th class="tableblock halign-left valign-top">Precision</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> + <em>b</em>, <em>a</em> - <em>b</em>, <em>a</em> * <em>b</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><, <=, ==, >, >=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Correct result.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> / <em>b</em>, 1.0 / <em>b</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2.5 ULP for <span class="eq">|b|</span> in the range <span class="eq">[2<sup>-126</sup>, 2<sup>126</sup>]</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> * <em>b</em> + <em>c</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded single operation or |
| sequence of two correctly rounded operations.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>fma</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <em>a</em> * <em>b</em> + <em>c</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>pow</strong>(<em>x</em>, <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <strong>exp2</strong>(<em>y</em> * <strong>log2</strong>(<em>x</em>)).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>exp</strong>(<em>x</em>), <strong>exp2</strong>(<em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(3 + 2 · |x|)</span> ULP.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>log</strong>(), <strong>log2</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3 ULP outside the range <span class="eq">[0.5,2.0]</span>.<br> |
| Absolute error < 2<sup>-21</sup> inside the range |
| <span class="eq">[0.5,2.0]</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sqrt</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from 1.0 / <strong>inversesqrt</strong>().</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inversesqrt</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2 ULP.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">implicit and explicit |
| conversions between types</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Built-in functions defined in the specification with an equation built from |
| the above operations inherit the above errors. |
| These include, for example, the geometric functions, the common functions, |
| and many of the matrix functions. |
| Built-in functions not listed above and not defined as equations of the |
| above have undefined precision. |
| These include, for example, the trigonometric functions and determinant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Storage requirements are declared through use of <em>precision qualifiers</em>. |
| The precision of operations must preserve the storage precisions of the |
| variables involved.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>highp</strong> floating-point values are stored in IEEE 754 single precision |
| floating-point format. |
| <strong>mediump</strong> and <strong>lowp</strong> floating-point values have minimum range and precision |
| requirements as detailed below and have maximum range and precision as |
| defined by IEEE 754.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All integral types are assumed to be implemented as integers and so may not |
| be emulated by floating-point values. |
| <strong>highp</strong> signed integers are represented as twos-complement 32-bit signed |
| integers. |
| <strong>highp</strong> unsigned integers are represented as unsigned 32-bit integers. |
| <strong>mediump</strong> integers (signed and unsigned) must be represented as an integer |
| with between 16 and 32 bits inclusive. |
| <strong>lowp</strong> integers (signed and unsigned) must be represented as an integer with |
| between 9 and 32 bits inclusive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The required ranges and precisions for precision qualifiers are:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.667%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top">Floating-Point Range</th> |
| <th class="tableblock halign-left valign-top">Floating-Point Magnitude Range</th> |
| <th class="tableblock halign-left valign-top">Floating-Point Precision</th> |
| <th class="tableblock halign-left valign-top">Signed Integer Range</th> |
| <th class="tableblock halign-left valign-top">Unsigned Integer Range</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>highp</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754<br> |
| <span class="eq">(-2<sup>128</sup>,2<sup>128</sup>)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754<br> |
| 0.0, <span class="eq">[2<sup>-126</sup>,2<sup>128</sup>)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754 relative:<br> |
| <span class="eq">2<sup>-23</sup></span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>31</sup>,2<sup>31</sup>-1]</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>32</sup>-1]</span></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mediump</strong> (minimum requirements)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(-2<sup>14</sup>,2<sup>14</sup>)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">0.0, <span class="eq">[2<sup>-14</sup>,2<sup>14</sup>)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Relative:<br> |
| <span class="eq">2<sup>-10</sup></span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>15</sup>,2<sup>15</sup>-1]</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>16</sup>-1]</span></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong> (minimum requirements)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(-2,2)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(2<sup>-8</sup>,2)</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Absolute:<br> |
| <span class="eq">2<sup>-8</sup></span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>8</sup>,2<sup>8</sup>-1]</span></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>9</sup>-1]</span></p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The semi-open interval notation used for the magnitude ranges means that the |
| lower end of the interval is included, but the upper end is excluded. Thus the |
| largest required magnitude is half of the relative precision less than the |
| value given. The largest required value for highp, for example, is <span class="eq">2<sup>128</sup> |
| × (1 - 2<sup>-24</sup>)</span>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>Relative precision</em> is defined as the worst case (i.e. largest) ratio of |
| the smallest step in relation to the value for all non-zero values in the |
| required ranges, above:</p> |
| </div> |
| <div class="stemblock"> |
| <div class="content"> |
| \[\begin{aligned} |
| \mathit{Precision}_{relative} = { |
| \left| { |
| { \left| v_1 - v_2 \right| }_{min} } \over { v_1 } |
| \right| |
| }_{max}, & |
| v_1,v_2 \neq 0, v_1 \neq v_2 |
| \end{aligned}\] |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>It is therefore twice the maximum rounding error when converting from a real |
| number. |
| Subnormal numbers may be supported and may have lower relative precision.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In addition, the range and precision of a <strong>mediump</strong> floating-point value |
| must be the same as or greater than the range and precision of a <strong>lowp</strong> |
| floating-point value. |
| The range and precision of a <strong>highp</strong> floating-point value must be the same |
| as or greater than the range and precision of a <strong>mediump</strong> floating-point |
| value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The range of a <strong>mediump</strong> integer value must be the same as or greater than |
| the range of a <strong>lowp</strong> integer value. |
| The range of a <strong>highp</strong> integer value must be the same as or greater than the |
| range of a <strong>mediump</strong> integer value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Within the above specification, an implementation is allowed to vary the |
| representation of numeric values, both within a shader and between different |
| shaders. |
| If necessary, this variance can be controlled using the invariance |
| qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The actual ranges and precisions provided by an implementation can be |
| queried through the API. |
| See the <a href="#references">normative references</a> for details on how to do |
| this.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="conversion-between-precisions">4.7.2. Conversion between precisions</h4> |
| <div class="paragraph"> |
| <p>Within the same type, conversion from a lower to a higher precision must be |
| exact. |
| When converting from a higher precision to a lower precision, if the value |
| is representable by the implementation of the target precision, the |
| conversion must also be exact. |
| If the value is not representable, the behavior is dependent on the type:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>For signed and unsigned integers, the value is truncated; bits in |
| positions not present in the target precision are set to zero. |
| (Positions start at zero and the least significant bit is considered to |
| be position zero for this purpose.)</p> |
| </li> |
| <li> |
| <p>For floating-point values, the value should either clamp to +Inf or |
| -Inf, or to the maximum or minimum value that the implementation |
| supports. |
| While this behavior is implementation-dependent, it should be consistent |
| for a given implementation.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="precision-qualifiers">4.7.3. Precision Qualifiers</h4> |
| <div class="paragraph"> |
| <p>Any |
| floating-point, integer, or opaque-type declaration can have the type |
| preceded by one of these precision qualifiers:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Qualifier</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Meaning</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>highp</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The variable satisfies the minimum requirements for <strong>highp</strong> |
| described above. <strong>highp</strong> variables have the maximum range and |
| precision available but may cause operations to run more |
| slowly on some implementations.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mediump</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SPIR-V <strong>RelaxedPrecision</strong> when targeting Vulkan, otherwise |
| the variable satisfies the minimum requirements for <strong>mediump</strong> |
| described above. <strong>mediump</strong> variables may typically be used to |
| store high dynamic range colors and low precision geometry.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SPIR-V <strong>RelaxedPrecision</strong> when targeting Vulkan, otherwise |
| the variable satisfies the minimum requirements for <strong>lowp</strong> |
| described above. <strong>lowp</strong> variables may typically be used to |
| store 8-bit color values.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">lowp <span class="predefined-type">float</span> color; |
| out mediump vec2 P; |
| lowp ivec2 foo(lowp mat3); |
| highp mat4 m;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Literal constants do not have precision qualifiers. |
| Neither do Boolean variables. |
| Neither do constructors.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For this paragraph, “operation” includes operators, built-in functions, |
| and constructors, and “operand” includes function arguments and |
| constructor arguments. |
| The precision used to internally evaluate an operation, and the precision |
| qualification subsequently associated with any resulting intermediate |
| values, must be at least as high as the highest precision qualification of |
| the operands consumed by the operation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In cases where operands do not have a precision qualifier, the precision |
| qualification will come from the other operands. |
| If no operands have a precision qualifier, then the precision qualifications |
| of the operands of the next consuming operation in the expression will be |
| used. |
| This rule can be applied recursively until a precision qualified operand is |
| found. |
| If necessary, it will also include the precision qualification of l-values |
| for assignments, of the declared variable for initializers, of formal |
| parameters for function call arguments, or of function return types for |
| function return values. |
| If the precision cannot be determined by this method e.g. if an entire |
| expression is composed only of operands with no precision qualifier, and the |
| result is not assigned or passed as an argument, then it is evaluated at the |
| default precision of the type or greater. |
| When this occurs in the fragment shader, the default precision must be |
| defined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, consider the statements:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">uniform highp <span class="predefined-type">float</span> h1; |
| highp <span class="predefined-type">float</span> h2 = <span class="float">2</span><span class="float">.3</span> * <span class="float">4</span><span class="float">.7</span>; <span class="comment">// operation and result are highp</span> |
| precision |
| mediump <span class="predefined-type">float</span> m; |
| m = <span class="float">3</span><span class="float">.7</span> * h1 * h2; <span class="comment">// all operations are highp precision</span> |
| h2 = m * h1; <span class="comment">// operation is highp precision</span> |
| m = h2 - h1; <span class="comment">// operation is highp precision</span> |
| h2 = m + m; <span class="comment">// addition and result at mediump precision</span> |
| <span class="directive">void</span> f(highp <span class="predefined-type">float</span> p); |
| f(<span class="float">3</span><span class="float">.3</span>); <span class="comment">// 3.3 will be passed in at highp precision</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Precision qualifiers, as with other qualifiers, do not affect the basic type |
| of the variable. |
| In particular, there are no constructors for precision conversions; |
| constructors only convert types. |
| Similarly, precision qualifiers, as with other qualifiers, do not contribute |
| to function overloading based on parameter types. |
| As discussed in “<a href="#function-calling-conventions">Function Calling |
| Conventions</a>”, function input and output is done through copies, and |
| therefore qualifiers do not have to match.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Precision qualifiers for outputs in one shader matched to inputs in another |
| shader need not match when both shaders are linked into the same program. |
| When both shaders are in separate programs, mismatched precision qualifiers |
| will result in a program interface mismatch that will result in program |
| pipeline validation failures, as described in section 7.4.1 “Shader |
| Interface Matching” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The precision of a variable is determined when the variable is declared and |
| cannot be subsequently changed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Where the precision of a constant integral or constant floating-point |
| expression is not specified, evaluation is performed at <strong>highp</strong>. |
| This rule does not affect the precision qualification of the expression.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The evaluation of constant expressions must be invariant and will usually be |
| performed at compile time.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="default-precision-qualifiers">4.7.4. Default Precision Qualifiers</h4> |
| <div class="paragraph"> |
| <p>The precision statement</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">precision precision-qualifier type;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>can be used to establish a default precision qualifier. |
| The <em>type</em> field can be either <strong>int</strong>, <strong>float</strong>, or any of the opaque types, |
| and the <em>precision-qualifier</em> can be <strong>lowp</strong>, <strong>mediump</strong>, or <strong>highp</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any other types or qualifiers will result in an error. |
| If <em>type</em> is <strong>float</strong>, the directive applies to non-precision-qualified |
| floating-point type (scalar, vector, and matrix) declarations. |
| If <em>type</em> is <strong>int</strong>, the directive applies to all non-precision-qualified |
| integer type (scalar, vector, signed, and unsigned) declarations. |
| This includes global variable declarations, function return declarations, |
| function parameter declarations, and local variable declarations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Non-precision qualified declarations will use the precision qualifier |
| specified in the most recent <strong>precision</strong> statement that is still in scope. |
| The <strong>precision</strong> statement has the same scoping rules as variable |
| declarations. |
| If it is declared inside a compound statement, its effect stops at the end |
| of the inner-most statement it was declared in. |
| Precision statements in nested scopes override precision statements in outer |
| scopes. |
| Multiple precision statements for the same basic type can appear inside the |
| same scope, with later statements overriding earlier statements within that |
| scope.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All languages except for the fragment language have the following |
| predeclared globally scoped default precision statements:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">precision highp <span class="predefined-type">float</span>; |
| precision highp <span class="predefined-type">int</span>; |
| precision lowp sampler2D; |
| precision lowp samplerCube; |
| precision highp atomic_uint;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The fragment language has the following predeclared globally scoped default |
| precision statements:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">precision mediump <span class="predefined-type">int</span>; |
| precision lowp sampler2D; |
| precision lowp samplerCube; |
| precision highp atomic_uint;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The fragment language has no default precision qualifier for floating-point |
| types. |
| Hence for <strong>float</strong>, floating-point vector and matrix variable declarations, |
| either the declaration must include a precision qualifier or the default |
| float precision must have been previously declared. |
| Similarly, there is no default precision qualifier in any of the languages |
| for any type not listed above.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="available-precision-qualifiers">4.7.5. Available Precision Qualifiers</h4> |
| <div class="paragraph"> |
| <p>The built-in macro GL_FRAGMENT_PRECISION_HIGH is defined to one:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_FRAGMENT_PRECISION_HIGH <span class="integer">1</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This macro is available in all languages except compute.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</h3> |
| <div class="paragraph"> |
| <p>In this section, <em>variance</em> refers to the possibility of getting different |
| values from the same expression in different programs. |
| For example, consider the situation where two vertex shaders, in different |
| programs, each set <em>gl_Position</em> with the same expression, and the input |
| values into that expression are the same when both shaders run. |
| It is possible, due to independent compilation of the two shaders, that the |
| values assigned to <em>gl_Position</em> are not exactly the same when the two |
| shaders run. |
| In this example, this can cause problems with alignment of geometry in a |
| multi-pass algorithm.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In general, such variance between shaders is allowed. |
| When such variance does not exist for a particular output variable, that |
| variable is said to be <em>invariant</em>.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="the-invariant-qualifier">4.8.1. The Invariant Qualifier</h4> |
| <div class="paragraph"> |
| <p>To ensure that a particular output variable is invariant, it is necessary to |
| use the <strong>invariant</strong> qualifier. |
| It can either be used to qualify a previously declared variable as being |
| invariant:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">invariant gl_Position; <span class="comment">// make existing gl_Position be invariant</span> |
| out vec3 Color; |
| invariant Color; <span class="comment">// make existing Color be invariant</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>or as part of a declaration when a variable is declared:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">invariant centroid out vec3 Color;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Only variables output from a shader can be candidates for invariance. |
| This includes user-defined output variables and the built-in output |
| variables. |
| As only outputs can be declared as invariant, an output from one shader |
| stage will still match an input of a subsequent stage without the input |
| being declared as invariant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>invariant</strong> keyword can be followed by a comma separated list of |
| previously declared identifiers. |
| All uses of <strong>invariant</strong> must be at global scope or on block |
| members, and before any use of the variables being declared as invariant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To guarantee invariance of a particular output variable across two programs, |
| the following must also be true:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The output variable is declared as invariant in both programs.</p> |
| </li> |
| <li> |
| <p>The same values must be input to all shader input variables consumed by |
| expressions and control flow contributing to the value assigned to the |
| output variable.</p> |
| </li> |
| <li> |
| <p>The texture formats, texel values, and texture filtering are set the |
| same way for any texture function calls contributing to the value of the |
| output variable.</p> |
| </li> |
| <li> |
| <p>All input values are all operated on in the same way. |
| All operations in the consuming expressions and any intermediate |
| expressions must be the same, with the same order of operands and same |
| associativity, to give the same order of evaluation. |
| Intermediate variables and functions must be declared as the same type |
| with the same explicit or implicit precision |
| qualifiers and the same constant qualifiers. |
| Any control flow affecting the output value must be the same, and any |
| expressions consumed to determine this control flow must also follow |
| these invariance rules.</p> |
| </li> |
| <li> |
| <p>All the data flow and control flow leading to setting the invariant |
| output variable reside in a single compilation unit.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Essentially, all the data flow and control flow leading to an invariant |
| output must match.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Initially, by default, all output variables are allowed to be variant. |
| To force all output variables to be invariant, use the pragma</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL invariant(all)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>before all declarations in a shader. |
| If this pragma is used after the declaration of any variables or functions, |
| then the set of outputs that behave as invariant is undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Generally, invariance is ensured at the cost of flexibility in optimization, |
| so performance can be degraded by use of invariance. |
| Hence, use of this pragma is intended as a debug aid, to avoid individually |
| declaring all output variables as invariant.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="invariance-within-a-shader">4.8.2. Invariance Within a Shader</h4> |
| <div class="paragraph"> |
| <p>When a value is stored in a variable, it is usually assumed it will remain |
| constant unless explicitly changed. |
| However, during the process of optimization, it is possible that the |
| compiler may choose to recompute a value rather than store it in a register. |
| Since the precision of operations is not completely specified (e.g. a low |
| precision operation may be done at medium or high precision), it would be |
| possible for the recomputed value to be different from the original value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Values are allowed to be variant within a shader. |
| To prevent this, the invariant qualifier or invariant pragma must be used.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Within a shader, there is no invariance for values generated by different |
| non-constant expressions, even if those expressions are identical.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example 1:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">precision mediump; |
| vec4 col; |
| vec2 a = ... |
| ... |
| col = texture(tex, a);<span class="comment">// a has a value _a1 _</span> |
| ... |
| col = texture(tex, a); <span class="comment">// a has a value a2 where possibly a1 != a2</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To enforce invariance in this example use:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL invariant(all)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Example 2:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec2 m = ...; |
| vec2 n = ...; |
| vec2 a = m + n; |
| vec2 b = m + n; <span class="comment">// a and b are not guaranteed to be exactly equal</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There is no mechanism to enforce invariance between a and b.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="invariance-of-constant-expressions">4.8.3. Invariance of Constant Expressions</h4> |
| <div class="paragraph"> |
| <p>Invariance must be guaranteed for constant expressions. |
| A particular constant expression must evaluate to the same result if it |
| appears again in the same shader or a different shader. |
| This includes the same expression appearing in two shaders of the same |
| language or shaders of two different languages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Constant expressions must evaluate to the same result when operated on as |
| already described above for invariant variables. |
| Constant expressions are not invariant with respect to equivalent |
| non-constant expressions, even when the <strong>invariant</strong> qualifier or pragma is |
| used.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="invariance-of-undefined-values">4.8.4. Invariance of Undefined Values</h4> |
| <div class="paragraph"> |
| <p>Undefined values are not invariant nor can they be made invariant by use of |
| the invariant qualifier or pragma. |
| In some implementations, undefined values may cause unexpected behavior if |
| they are used in control-flow expressions e.g. in the following case, one, |
| both or neither functions may be executed and this may not be consistent |
| over multiple invocations of the shader:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x; <span class="comment">// undefined value</span> |
| <span class="keyword">if</span> (x == <span class="integer">1</span>) |
| { |
| f(); <span class="comment">// Undefined whether f() is executed</span> |
| } |
| <span class="keyword">if</span> (x == <span class="integer">2</span>) |
| { |
| g(); <span class="comment">// Undefined whether g() is executed.</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that an undefined value is a value that has not been specified. |
| A value that has been specified but has a potentially large error due to, |
| for example, lack of precision in an expression, is not undefined and so can |
| be made invariant.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="the-precise-qualifier">4.9. The Precise Qualifier</h3> |
| <div class="paragraph"> |
| <p>Some algorithms require floating-point computations to exactly follow the |
| order of operations specified in the source code and to treat all operations |
| consistently, even if the implementation supports optimizations that could |
| produce nearly equivalent results with higher performance. |
| For example, many GL implementations support a “multiply-add” instruction |
| that can compute a floating-point expression such as</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">result = (a * b) + (c * d);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>in two operations instead of three operations; one multiply and one |
| multiply-add instead of two multiplies and one add. |
| The result of a floating-point multiply-add might not always be identical to |
| first doing a multiply yielding a floating-point result and then doing a |
| floating-point add. |
| Hence, in this example, the two multiply operations would not be treated |
| consistently; the two multiplies could effectively appear to have differing |
| precisions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The key computation that needs to be made consistent appears when |
| tessellating, where intermediate points for subdivision are synthesized in |
| different directions, yet need to yield the same result, as shown in the |
| diagram below.</p> |
| </div> |
| <div id="img-precise" class="imageblock"> |
| <div class="content"> |
| <img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KCjxzdmcgdmVyc2lvbj0iMS4yIiBiYXNlUHJvZmlsZT0idGlueSIgd2lkdGg9IjIxMG1tIiBoZWlnaHQ9IjI5N21tIiB2aWV3Qm94PSIwIDAgMjEwMDAgMjk3MDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSIgc3Ryb2tlLXdpZHRoPSIyOC4yMjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6b29vPSJodHRwOi8veG1sLm9wZW5vZmZpY2Uub3JnL3N2Zy9leHBvcnQiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIj4KIDxkZWZzIGNsYXNzPSJDbGlwUGF0aEdyb3VwIj4KICA8Y2xpcFBhdGggaWQ9InByZXNlbnRhdGlvbl9jbGlwX3BhdGgiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIxMDAwIiBoZWlnaHQ9IjI5NzAwIi8+CiAgPC9jbGlwUGF0aD4KIDwvZGVmcz4KIDxkZWZzPgogIDxmb250IGlkPSJFbWJlZGRlZEZvbnRfMSIgaG9yaXotYWR2LXg9IjIwNDgiPgogICA8Zm9udC1mYWNlIGZvbnQtZmFtaWx5PSJMaWJlcmF0aW9uIFNhbnMgZW1iZWRkZWQiIHVuaXRzLXBlci1lbT0iMjA0OCIgZm9udC13ZWlnaHQ9Im5vcm1hbCIgZm9udC1zdHlsZT0ibm9ybWFsIiBhc2NlbnQ9IjE4NTIiIGRlc2NlbnQ9IjQyMyIvPgogICA8bWlzc2luZy1nbHlwaCBob3Jpei1hZHYteD0iMjA0OCIgZD0iTSAwLDAgTCAyMDQ3LDAgMjA0NywyMDQ3IDAsMjA0NyAwLDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idyIgaG9yaXotYWR2LXg9IjE1MDkiIGQ9Ik0gMTE3NCwwIEwgOTY1LDAgNzkyLDY5OCBDIDc4Nyw3MTYgNzgxLDczOCA3NzYsNzY1IDc3MCw3OTIgNzY0LDgxOCA3NTksODQzIDc1Miw4NzIgNzQ2LDkwMyA3NDAsOTM0IDczNCw5MDQgNzI4LDg3NCA3MjEsODQ1IDcxNiw4MjAgNzEwLDc5MyA3MDQsNzY2IDY5Nyw3MzkgNjkxLDcxNSA2ODYsNjk0IEwgNTA4LDAgMzAwLDAgLTMsMTA4MiAxNzUsMTA4MiAzNTgsMzQ3IEMgMzYzLDMzMiAzNjcsMzEzIDM3MiwyOTEgMzc3LDI2OCAzODEsMjQ2IDM4NiwyMjUgMzkxLDIwMCAzOTYsMTc1IDQwMSwxNDkgNDA2LDE3NCA0MTIsMTk5IDQxOCwyMjMgNDIzLDI0NCA0MjksMjY1IDQzNCwyODYgNDM5LDMwNyA0NDQsMzI1IDQ0OCwzMzkgTCA2NDQsMTA4MiA4MzcsMTA4MiAxMDI2LDMzOSBDIDEwMzEsMzIyIDEwMzYsMzAyIDEwNDEsMjgwIDEwNDYsMjU4IDEwNTEsMjM3IDEwNTYsMjE4IDEwNjEsMTk1IDEwNjcsMTcyIDEwNzIsMTQ5IDEwNzcsMTc0IDEwODMsMTk5IDEwODgsMjIzIDEwOTMsMjQ0IDEwOTgsMjY1IDExMDMsMjg4IDExMDgsMzEwIDExMTIsMzMwIDExMTcsMzQ3IEwgMTMwOCwxMDgyIDE0ODQsMTA4MiAxMTc0LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idiIgaG9yaXotYWR2LXg9IjEwMzMiIGQ9Ik0gNjEzLDAgTCA0MDAsMCA3LDEwODIgMTk5LDEwODIgNDM3LDM3OCBDIDQ0MiwzNjMgNDQ3LDM0NiA0NTQsMzI1IDQ2MCwzMDQgNDY2LDI4MiA0NzMsMjU5IDQ4MCwyMzYgNDg2LDIxNSA0OTIsMTk0IDQ5NywxNzMgNTAyLDE1NSA1MDYsMTQxIDUxMCwxNTUgNTE1LDE3MyA1MjIsMTk0IDUyOCwyMTUgNTM0LDIzNiA1NDEsMjU4IDU0OCwyODAgNTU1LDMwMiA1NjIsMzIzIDU2OSwzNDQgNTc1LDM2MSA1ODAsMzc2IEwgODI2LDEwODIgMTAxNywxMDgyIDYxMywwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InUiIGhvcml6LWFkdi14PSI4NzQiIGQ9Ik0gMzE0LDEwODIgTCAzMTQsMzk2IEMgMzE0LDM0MyAzMTgsMjk5IDMyNiwyNjQgMzMzLDIyOSAzNDYsMjAwIDM2MywxNzkgMzgwLDE1NyA0MDMsMTQyIDQzMiwxMzMgNDYwLDEyNCA0OTUsMTE5IDUzNywxMTkgNTgwLDExOSA2MTgsMTI3IDY1MywxNDIgNjg3LDE1NyA3MTYsMTc4IDc0MSwyMDcgNzY1LDIzNSA3ODQsMjcwIDc5NywzMTIgODEwLDM1MyA4MTcsNDAxIDgxNyw0NTUgTCA4MTcsMTA4MiA5OTcsMTA4MiA5OTcsMjMxIEMgOTk3LDIwOCA5OTcsMTg1IDk5OCwxNjAgOTk4LDEzNSA5OTgsMTExIDk5OSw4OSAxMDAwLDY2IDEwMDAsNDcgMTAwMSwzMSAxMDAyLDE1IDEwMDIsNSAxMDAzLDAgTCA4MzMsMCBDIDgzMiwzIDgzMiwxMiA4MzEsMjcgODMwLDQyIDgzMCw1OSA4MjksNzggODI4LDk3IDgyNywxMTYgODI2LDEzNiA4MjUsMTU1IDgyNSwxNzIgODI1LDE4NSBMIDgyMiwxODUgQyA4MDUsMTU0IDc4NiwxMjUgNzY1LDEwMCA3NDQsNzUgNzIwLDUzIDY5MywzNiA2NjYsMTggNjM0LDQgNTk5LC02IDU2NCwtMTUgNTIzLC0yMCA0NzYsLTIwIDQxNiwtMjAgMzY0LC0xMyAzMjEsMiAyNzgsMTcgMjQyLDM5IDIxNCw3MCAxODYsMTAxIDE2NiwxNDAgMTUzLDE4OCAxNDAsMjM2IDEzMywyOTQgMTMzLDM2MSBMIDEzMywxMDgyIDMxNCwxMDgyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InQiIGhvcml6LWFkdi14PSI1MzEiIGQ9Ik0gNTU0LDggQyA1MjcsMSA0OTksLTUgNDcxLC0xMCA0NDIsLTE0IDQwOSwtMTYgMzcyLC0xNiAyMjgsLTE2IDE1Niw2NiAxNTYsMjI5IEwgMTU2LDk1MSAzMSw5NTEgMzEsMTA4MiAxNjMsMTA4MiAyMTYsMTMyNCAzMzYsMTMyNCAzMzYsMTA4MiA1MzYsMTA4MiA1MzYsOTUxIDMzNiw5NTEgMzM2LDI2OCBDIDMzNiwyMTYgMzQ1LDE4MCAzNjIsMTU5IDM3OSwxMzggNDA4LDEyNyA0NTAsMTI3IDQ2NywxMjcgNDg0LDEyOCA1MDEsMTMxIDUxNywxMzQgNTM1LDEzNyA1NTQsMTQxIEwgNTU0LDggWiIvPgogICA8Z2x5cGggdW5pY29kZT0icyIgaG9yaXotYWR2LXg9IjkwMSIgZD0iTSA5NTAsMjk5IEMgOTUwLDI0OCA5NDAsMjAzIDkyMSwxNjQgOTAxLDEyNCA4NzIsOTEgODM1LDY0IDc5OCwzNyA3NTIsMTYgNjk4LDIgNjQzLC0xMyA1ODEsLTIwIDUxMSwtMjAgNDQ4LC0yMCAzOTIsLTE1IDM0MiwtNiAyOTEsNCAyNDcsMjAgMjA5LDQxIDE3MSw2MiAxMzksOTEgMTE0LDEyNiA4OCwxNjEgNjksMjAzIDU3LDI1NCBMIDIxNiwyODUgQyAyMzEsMjI3IDI2MywxODUgMzExLDE1OCAzNTksMTMxIDQyNiwxMTcgNTExLDExNyA1NTAsMTE3IDU4NSwxMjAgNjE4LDEyNSA2NTAsMTMwIDY3OCwxNDAgNzAxLDE1MyA3MjQsMTY2IDc0MywxODMgNzU2LDIwNSA3NjksMjI2IDc3NSwyNTMgNzc1LDI4NSA3NzUsMzE4IDc2NywzNDUgNzUyLDM2NiA3MzcsMzg3IDcxNSw0MDQgNjg4LDQxOCA2NjEsNDMyIDYyOCw0NDQgNTg5LDQ1NSA1NTAsNDY1IDUwNyw0NzYgNDYwLDQ4OSA0MTcsNTAwIDM3NCw1MTMgMzMxLDUyNyAyODgsNTQxIDI1MCw1NjAgMjE2LDU4MyAxODEsNjA2IDE1Myw2MzQgMTMyLDY2OCAxMTEsNzAyIDEwMCw3NDUgMTAwLDc5NiAxMDAsODk1IDEzNSw5NzAgMjA2LDEwMjIgMjc2LDEwNzMgMzc4LDEwOTkgNTEzLDEwOTkgNjMyLDEwOTkgNzI3LDEwNzggNzk4LDEwMzYgODY4LDk5NCA5MTIsOTI3IDkzMSw4MzQgTCA3NjksODE0IEMgNzYzLDg0MiA3NTIsODY2IDczNiw4ODUgNzIwLDkwNCA3MDEsOTE5IDY3OCw5MzEgNjU1LDk0MiA2MzAsOTUxIDYwMiw5NTYgNTczLDk2MSA1NDQsOTYzIDUxMyw5NjMgNDMyLDk2MyAzNzIsOTUxIDMzMyw5MjYgMjk0LDkwMSAyNzUsODY0IDI3NSw4MTQgMjc1LDc4NSAyODIsNzYxIDI5Nyw3NDIgMzExLDcyMyAzMzEsNzA3IDM1Nyw2OTQgMzgyLDY4MSA0MTMsNjY5IDQ0OSw2NjAgNDg1LDY1MCA1MjUsNjQwIDU2OCw2MjkgNTk3LDYyMiA2MjYsNjE0IDY1Niw2MDYgNjg2LDU5NyA3MTUsNTg3IDc0NCw1NzYgNzcyLDU2NCA3OTksNTUwIDgyNCw1MzUgODQ5LDUxOSA4NzAsNTAwIDg4OSw0NzggOTA4LDQ1NiA5MjMsNDMwIDkzNCw0MDEgOTQ1LDM3MiA5NTAsMzM4IDk1MCwyOTkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iciIgaG9yaXotYWR2LXg9IjUzMCIgZD0iTSAxNDIsMCBMIDE0Miw4MzAgQyAxNDIsODUzIDE0Miw4NzYgMTQyLDkwMCAxNDEsOTIzIDE0MSw5NDYgMTQwLDk2OCAxMzksOTkwIDEzOSwxMDExIDEzOCwxMDMwIDEzNywxMDQ5IDEzNywxMDY3IDEzNiwxMDgyIEwgMzA2LDEwODIgQyAzMDcsMTA2NyAzMDgsMTA0OSAzMDksMTAzMCAzMTAsMTAxMCAzMTEsOTkwIDMxMiw5NjkgMzEzLDk0OCAzMTMsOTI5IDMxNCw5MTAgMzE0LDg5MSAzMTQsODc0IDMxNCw4NjEgTCAzMTgsODYxIEMgMzMxLDkwMiAzNDQsOTM4IDM1OSw5NjkgMzczLDk5OSAzOTAsMTAyNCA0MDksMTA0NCA0MjgsMTA2MyA0NTEsMTA3OCA0NzgsMTA4OCA1MDUsMTA5NyA1MzcsMTEwMiA1NzUsMTEwMiA1OTAsMTEwMiA2MDQsMTEwMSA2MTcsMTA5OSA2MzAsMTA5NiA2NDEsMTA5NCA2NDgsMTA5MiBMIDY0OCw5MjcgQyA2MzYsOTMwIDYyMiw5MzMgNjA2LDkzNSA1OTAsOTM2IDU3Miw5MzcgNTUyLDkzNyA1MTEsOTM3IDQ3Niw5MjggNDQ3LDkwOSA0MTgsODkwIDM5NCw4NjUgMzc2LDgzMiAzNTcsNzk5IDM0NCw3NTkgMzM1LDcxNCAzMjYsNjY4IDMyMiw2MTggMzIyLDU2NCBMIDMyMiwwIDE0MiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InAiIGhvcml6LWFkdi14PSI5NTMiIGQ9Ik0gMTA1Myw1NDYgQyAxMDUzLDQ2NCAxMDQ2LDM4OCAxMDMzLDMxOSAxMDIwLDI1MCA5OTgsMTkwIDk2NywxNDAgOTM2LDkwIDg5NSw1MSA4NDQsMjMgNzkzLC02IDczMCwtMjAgNjU1LC0yMCA1NzgsLTIwIDUxMCwtNSA0NTIsMjQgMzk0LDUzIDM1MCwxMDEgMzE5LDE2OCBMIDMxNCwxNjggQyAzMTUsMTY3IDMxNSwxNjEgMzE2LDE1MCAzMTYsMTM5IDMxNiwxMjYgMzE3LDExMCAzMTcsOTQgMzE3LDc2IDMxOCw1NyAzMTgsMzcgMzE4LDE3IDMxOCwtMiBMIDMxOCwtNDI1IDEzOCwtNDI1IDEzOCw4NjEgQyAxMzgsODg3IDEzOCw5MTIgMTM4LDkzNiAxMzcsOTYwIDEzNyw5ODIgMTM2LDEwMDIgMTM1LDEwMjEgMTM1LDEwMzggMTM0LDEwNTIgMTMzLDEwNjYgMTMzLDEwNzYgMTMyLDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDgwIDMwOCwxMDczIDMwOSwxMDYxIDMxMCwxMDQ5IDMxMSwxMDM1IDMxMiwxMDE4IDMxMywxMDAxIDMxNCw5ODIgMzE1LDk2MyAzMTYsOTQ0IDMxNiw5MjUgMzE2LDkwOCBMIDMyMCw5MDggQyAzMzcsOTQzIDM1Niw5NzIgMzc3LDk5NyAzOTgsMTAyMSA0MjMsMTA0MSA0NTAsMTA1NyA0NzcsMTA3MiA1MDgsMTA4NCA1NDIsMTA5MSA1NzUsMTA5OCA2MTMsMTEwMSA2NTUsMTEwMSA3MzAsMTEwMSA3OTMsMTA4OCA4NDQsMTA2MSA4OTUsMTAzNCA5MzYsOTk3IDk2Nyw5NDkgOTk4LDkwMCAxMDIwLDg0MiAxMDMzLDc3NCAxMDQ2LDcwNSAxMDUzLDYyOSAxMDUzLDU0NiBaIE0gODY0LDU0MiBDIDg2NCw2MDkgODYwLDY2OCA4NTIsNzIwIDg0NCw3NzIgODMwLDgxNiA4MTEsODUyIDc5MSw4ODggNzY1LDkxNSA3MzIsOTM0IDY5OSw5NTMgNjU4LDk2MiA2MDksOTYyIDU2OSw5NjIgNTMxLDk1NiA0OTYsOTQ1IDQ2MSw5MzQgNDMwLDkxMiA0MDQsODgwIDM3Nyw4NDggMzU2LDgwNCAzNDEsNzQ4IDMyNiw2OTEgMzE4LDYxOCAzMTgsNTI4IDMxOCw0NTEgMzI0LDM4NyAzMzcsMzM0IDM1MCwyODEgMzY4LDIzOCAzOTMsMjA1IDQxNywxNzIgNDQ3LDE0OSA0ODMsMTM1IDUxOSwxMjAgNTYwLDExMyA2MDcsMTEzIDY1NywxMTMgNjk5LDEyMyA3MzIsMTQyIDc2NSwxNjEgNzkxLDE4OSA4MTEsMjI2IDgzMCwyNjMgODQ0LDMwOCA4NTIsMzYxIDg2MCw0MTQgODY0LDQ3NCA4NjQsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9Im8iIGhvcml6LWFkdi14PSI5ODAiIGQ9Ik0gMTA1Myw1NDIgQyAxMDUzLDM1MyAxMDExLDIxMiA5MjgsMTE5IDg0NSwyNiA3MjQsLTIwIDU2NSwtMjAgNDkwLC0yMCA0MjIsLTkgMzYzLDE0IDMwNCwzNyAyNTQsNzEgMjEzLDExOCAxNzIsMTY1IDE0MCwyMjMgMTE5LDI5NCA5NywzNjQgODYsNDQ3IDg2LDU0MiA4Niw5MTUgMjQ4LDExMDIgNTcxLDExMDIgNjU1LDExMDIgNzI4LDEwOTAgNzg5LDEwNjcgODUwLDEwNDQgOTAwLDEwMDkgOTM5LDk2MiA5NzgsOTE1IDEwMDYsODU3IDEwMjUsNzg3IDEwNDQsNzE3IDEwNTMsNjM1IDEwNTMsNTQyIFogTSA4NjQsNTQyIEMgODY0LDYyNiA4NTgsNjk1IDg0NSw3NTAgODMyLDgwNSA4MTMsODQ4IDc4OCw4ODEgNzYzLDkxNCA3MzIsOTM3IDY5Niw5NTAgNjYwLDk2MyA2MTksOTY5IDU3NCw5NjkgNTI4LDk2OSA0ODcsOTYyIDQ1MCw5NDkgNDEzLDkzNSAzODEsOTEyIDM1NSw4NzkgMzI5LDg0NiAzMDksODAyIDI5Niw3NDcgMjgyLDY5MiAyNzUsNjI0IDI3NSw1NDIgMjc1LDQ1OCAyODIsMzg5IDI5NywzMzQgMzEyLDI3OSAzMzIsMjM1IDM1OCwyMDIgMzgzLDE2OSA0MTQsMTQ2IDQ0OSwxMzMgNDg0LDEyMCA1MjIsMTEzIDU2MywxMTMgNjA5LDExMyA2NTEsMTIwIDY4OCwxMzMgNzI1LDE0NiA3NTcsMTY4IDc4MywyMDEgODA5LDIzNCA4MjksMjc4IDg0MywzMzMgODU3LDM4OCA4NjQsNDU4IDg2NCw1NDIgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibiIgaG9yaXotYWR2LXg9Ijg3NCIgZD0iTSA4MjUsMCBMIDgyNSw2ODYgQyA4MjUsNzM5IDgyMSw3ODMgODE0LDgxOCA4MDYsODUzIDc5Myw4ODIgNzc2LDkwNCA3NTksOTI1IDczNiw5NDEgNzA4LDk1MCA2NzksOTU5IDY0NCw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTYgNDg3LDk0MSA0NTIsOTI2IDQyMyw5MDQgMzk5LDg3NiAzNzQsODQ3IDM1NSw4MTIgMzQyLDc3MSAzMjksNzI5IDMyMiw2ODEgMzIyLDYyNyBMIDMyMiwwIDE0MiwwIDE0Miw4NTEgQyAxNDIsODc0IDE0Miw4OTggMTQyLDkyMyAxNDEsOTQ4IDE0MSw5NzEgMTQwLDk5NCAxMzksMTAxNiAxMzksMTAzNSAxMzgsMTA1MSAxMzcsMTA2NyAxMzcsMTA3NyAxMzYsMTA4MiBMIDMwNiwxMDgyIEMgMzA3LDEwNzkgMzA3LDEwNzAgMzA4LDEwNTUgMzA5LDEwNDAgMzEwLDEwMjQgMzExLDEwMDUgMzEyLDk4NiAzMTIsOTY2IDMxMyw5NDcgMzE0LDkyNyAzMTQsOTEwIDMxNCw4OTcgTCAzMTcsODk3IEMgMzM0LDkyOCAzNTMsOTU3IDM3NCw5ODIgMzk1LDEwMDcgNDE5LDEwMjkgNDQ2LDEwNDcgNDczLDEwNjQgNTA1LDEwNzggNTQwLDEwODggNTc1LDEwOTcgNjE2LDExMDIgNjYzLDExMDIgNzIzLDExMDIgNzc1LDEwOTUgODE4LDEwODAgODYxLDEwNjUgODk3LDEwNDMgOTI1LDEwMTIgOTUzLDk4MSA5NzQsOTQyIDk4Nyw4OTQgMTAwMCw4NDUgMTAwNiw3ODggMTAwNiw3MjEgTCAxMDA2LDAgODI1LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibSIgaG9yaXotYWR2LXg9IjE0NTciIGQ9Ik0gNzY4LDAgTCA3NjgsNjg2IEMgNzY4LDczOSA3NjUsNzgzIDc1OCw4MTggNzUxLDg1MyA3NDAsODgyIDcyNSw5MDQgNzA5LDkyNSA2ODgsOTQxIDY2Myw5NTAgNjM4LDk1OSA2MDcsOTYzIDU3MCw5NjMgNTMyLDk2MyA0OTgsOTU2IDQ2Nyw5NDEgNDM2LDkyNiA0MTAsOTA0IDM4OSw4NzYgMzY3LDg0NyAzNTAsODEyIDMzOSw3NzEgMzI3LDcyOSAzMjEsNjgxIDMyMSw2MjcgTCAzMjEsMCAxNDIsMCAxNDIsODUxIEMgMTQyLDg3NCAxNDIsODk4IDE0Miw5MjMgMTQxLDk0OCAxNDEsOTcxIDE0MCw5OTQgMTM5LDEwMTYgMTM5LDEwMzUgMTM4LDEwNTEgMTM3LDEwNjcgMTM3LDEwNzcgMTM2LDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDc5IDMwNywxMDcwIDMwOCwxMDU1IDMwOSwxMDQwIDMxMCwxMDI0IDMxMSwxMDA1IDMxMiw5ODYgMzEyLDk2NiAzMTMsOTQ3IDMxNCw5MjcgMzE0LDkxMCAzMTQsODk3IEwgMzE3LDg5NyBDIDMzMyw5MjggMzUwLDk1NyAzNjksOTgyIDM4OCwxMDA3IDQxMCwxMDI5IDQzNSwxMDQ3IDQ2MCwxMDY0IDQ4OCwxMDc4IDUyMSwxMDg4IDU1MywxMDk3IDU5MCwxMTAyIDYzMywxMTAyIDcxNSwxMTAyIDc4MCwxMDg2IDgyOCwxMDUzIDg3NSwxMDIwIDkwOCw5NjggOTI3LDg5NyBMIDkzMCw4OTcgQyA5NDYsOTI4IDk2NCw5NTcgOTg0LDk4MiAxMDA0LDEwMDcgMTAyNywxMDI5IDEwNTQsMTA0NyAxMDgxLDEwNjQgMTExMSwxMDc4IDExNDQsMTA4OCAxMTc3LDEwOTcgMTIxNSwxMTAyIDEyNTgsMTEwMiAxMzEzLDExMDIgMTM2MCwxMDk1IDE0MDAsMTA4MCAxNDM5LDEwNjUgMTQ3MiwxMDQzIDE0OTcsMTAxMiAxNTIyLDk4MSAxNTQxLDk0MiAxNTUzLDg5NCAxNTY1LDg0NSAxNTcxLDc4OCAxNTcxLDcyMSBMIDE1NzEsMCAxMzkzLDAgMTM5Myw2ODYgQyAxMzkzLDczOSAxMzkwLDc4MyAxMzgzLDgxOCAxMzc2LDg1MyAxMzY1LDg4MiAxMzUwLDkwNCAxMzM0LDkyNSAxMzEzLDk0MSAxMjg4LDk1MCAxMjYzLDk1OSAxMjMyLDk2MyAxMTk1LDk2MyAxMTU3LDk2MyAxMTIzLDk1NiAxMDkyLDk0MiAxMDYxLDkyNyAxMDM1LDkwNiAxMDE0LDg3OCA5OTIsODUwIDk3NSw4MTUgOTY0LDc3MyA5NTIsNzMxIDk0Niw2ODIgOTQ2LDYyNyBMIDk0NiwwIDc2OCwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImwiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM4LDAgTCAxMzgsMTQ4NCAzMTgsMTQ4NCAzMTgsMCAxMzgsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJrIiBob3Jpei1hZHYteD0iOTAxIiBkPSJNIDgxNiwwIEwgNDUwLDQ5NCAzMTgsMzg1IDMxOCwwIDEzOCwwIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCw1NTcgNzkzLDEwODIgMTAwNCwxMDgyIDU2NSw2MTcgMTAyNywwIDgxNiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImkiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM3LDEzMTIgTCAxMzcsMTQ4NCAzMTcsMTQ4NCAzMTcsMTMxMiAxMzcsMTMxMiBaIE0gMTM3LDAgTCAxMzcsMTA4MiAzMTcsMTA4MiAzMTcsMCAxMzcsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJoIiBob3Jpei1hZHYteD0iODc0IiBkPSJNIDMxNyw4OTcgQyAzMzcsOTM0IDM1OSw5NjUgMzgyLDk5MSA0MDUsMTAxNiA0MzEsMTAzNyA0NTksMTA1NCA0ODcsMTA3MSA1MTgsMTA4MyA1NTEsMTA5MSA1ODQsMTA5OCA2MjIsMTEwMiA2NjMsMTEwMiA3MzIsMTEwMiA3ODksMTA5MyA4MzQsMTA3NCA4NzgsMTA1NSA5MTMsMTAyOSA5MzksOTk2IDk2NCw5NjIgOTgyLDkyMiA5OTIsODc1IDEwMDEsODI4IDEwMDYsNzc3IDEwMDYsNzIxIEwgMTAwNiwwIDgyNSwwIDgyNSw2ODYgQyA4MjUsNzMyIDgyMiw3NzIgODE3LDgwNyA4MTEsODQyIDgwMCw4NzEgNzg0LDg5NCA3NjgsOTE3IDc0NSw5MzQgNzE2LDk0NiA2ODcsOTU3IDY0OSw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTUgNDg3LDk0MCA0NTIsOTI1IDQyMyw5MDMgMzk5LDg3NSAzNzQsODQ3IDM1NSw4MTMgMzQyLDc3MyAzMjksNzMzIDMyMiw2ODggMzIyLDYzOCBMIDMyMiwwIDE0MiwwIDE0MiwxNDg0IDMyMiwxNDg0IDMyMiwxMDk4IEMgMzIyLDEwNzYgMzIyLDEwNTQgMzIxLDEwMzIgMzIwLDEwMTAgMzIwLDk5MCAzMTksOTcxIDMxOCw5NTIgMzE3LDkzNyAzMTYsOTI0IDMxNSw5MTEgMzE1LDkwMiAzMTQsODk3IEwgMzE3LDg5NyBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJnIiBob3Jpei1hZHYteD0iOTI3IiBkPSJNIDU0OCwtNDI1IEMgNDg2LC00MjUgNDMxLC00MTkgMzgzLC00MDYgMzM1LC0zOTMgMjk0LC0zNzUgMjYwLC0zNTIgMjI2LC0zMjggMTk4LC0zMDAgMTc3LC0yNjcgMTU2LC0yMzQgMTQwLC0xOTggMTMxLC0xNTggTCAzMTIsLTEzMiBDIDMyNCwtMTgyIDM1MSwtMjIwIDM5MiwtMjQ4IDQzMywtMjc0IDQ4NiwtMjg4IDU1MywtMjg4IDU5NCwtMjg4IDYzMSwtMjgyIDY2NCwtMjcxIDY5NywtMjYwIDcyNiwtMjQxIDc0OSwtMjE3IDc3MiwtMTkxIDc5MCwtMTU5IDgwMywtMTE5IDgxNiwtNzkgODIyLC0zMCA4MjIsMjcgTCA4MjIsMjAxIDgyMCwyMDEgQyA4MDcsMTc0IDc5MCwxNDggNzcxLDEyMyA3NTEsOTggNzI3LDc1IDY5OSw1NiA2NzAsMzcgNjM3LDIxIDYwMCwxMCA1NjMsLTIgNTIwLC04IDQ3MiwtOCA0MDMsLTggMzQ1LDQgMjk2LDI3IDI0Nyw1MCAyMDcsODQgMTc2LDEzMCAxNDUsMTc2IDEyMiwyMzMgMTA4LDMwMiA5MywzNzAgODYsNDQ5IDg2LDUzOSA4Niw2MjYgOTMsNzA0IDEwOCw3NzMgMTIyLDg0MiAxNDUsOTAxIDE3OCw5NTAgMjEwLDk5OCAyNTIsMTAzNSAzMDQsMTA2MSAzNTUsMTA4NiA0MTgsMTA5OSA0OTIsMTA5OSA1NjksMTA5OSA2MzUsMTA4MiA2OTIsMTA0NyA3NDgsMTAxMiA3OTEsOTYyIDgyMiw4OTcgTCA4MjQsODk3IEMgODI0LDkxNCA4MjUsOTMyIDgyNiw5NTMgODI3LDk3NCA4MjgsOTkzIDgyOSwxMDEyIDgzMCwxMDMwIDgzMSwxMDQ2IDgzMiwxMDU5IDgzMywxMDcyIDgzNSwxMDgwIDgzNiwxMDgyIEwgMTAwNywxMDgyIEMgMTAwNiwxMDc2IDEwMDYsMTA2NiAxMDA1LDEwNTIgMTAwNCwxMDM3IDEwMDQsMTAyMCAxMDAzLDEwMDAgMTAwMiw5ODAgMTAwMiw5NTggMTAwMiw5MzQgMTAwMSw5MDkgMTAwMSw4ODQgMTAwMSw4NTggTCAxMDAxLDMxIEMgMTAwMSwtMTIwIDk2NCwtMjM0IDg5MCwtMzExIDgxNSwtMzg3IDcwMSwtNDI1IDU0OCwtNDI1IFogTSA4MjIsNTQxIEMgODIyLDYxNiA4MTQsNjgxIDc5OCw3MzUgNzgxLDc4OCA3NjAsODMyIDczMyw4NjYgNzA2LDkwMCA2NzYsOTI1IDY0Miw5NDEgNjA3LDk1NyA1NzIsOTY1IDUzNiw5NjUgNDkwLDk2NSA0NTEsOTU3IDQxOCw5NDEgMzg1LDkyNSAzNTcsOTAwIDMzNiw4NjYgMzE0LDgzMSAyOTgsNzg3IDI4OCw3MzQgMjc3LDY4MCAyNzIsNjE2IDI3Miw1NDEgMjcyLDQ2MyAyNzcsMzk4IDI4OCwzNDUgMjk4LDI5MiAzMTQsMjQ5IDMzNSwyMTYgMzU2LDE4MyAzODMsMTYwIDQxNiwxNDYgNDQ5LDEzMiA0ODgsMTI1IDUzMywxMjUgNTY5LDEyNSA2MDQsMTMzIDYzOSwxNDggNjczLDE2MyA3MDQsMTg4IDczMSwyMjEgNzU4LDI1NCA3ODAsMjk3IDc5NywzNTAgODE0LDQwMyA4MjIsNDY2IDgyMiw1NDEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iZiIgaG9yaXotYWR2LXg9IjU1NyIgZD0iTSAzNjEsOTUxIEwgMzYxLDAgMTgxLDAgMTgxLDk1MSAyOSw5NTEgMjksMTA4MiAxODEsMTA4MiAxODEsMTIwNCBDIDE4MSwxMjQzIDE4NSwxMjgwIDE5MiwxMzE0IDE5OSwxMzQ3IDIxMywxMzc3IDIzMywxNDAyIDI1MiwxNDI3IDI3OSwxNDQ2IDMxMywxNDYxIDM0NywxNDc1IDM5MSwxNDgyIDQ0NSwxNDgyIDQ2NiwxNDgyIDQ4OSwxNDgxIDUxMiwxNDc5IDUzNSwxNDc3IDU1NSwxNDc0IDU3MiwxNDcwIEwgNTcyLDEzMzMgQyA1NjEsMTMzNSA1NDgsMTMzNyA1MzMsMTMzOSA1MTgsMTM0MCA1MDQsMTM0MSA0OTIsMTM0MSA0NjUsMTM0MSA0NDQsMTMzNyA0MjcsMTMzMCA0MTAsMTMyMyAzOTYsMTMxMiAzODcsMTI5OSAzNzcsMTI4NSAzNzAsMTI2OCAzNjcsMTI0OCAzNjMsMTIyOCAzNjEsMTIwNSAzNjEsMTE3OSBMIDM2MSwxMDgyIDU3MiwxMDgyIDU3Miw5NTEgMzYxLDk1MSBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJlIiBob3Jpei1hZHYteD0iOTgwIiBkPSJNIDI3Niw1MDMgQyAyNzYsNDQ2IDI4MiwzOTQgMjk0LDM0NyAzMDUsMjk5IDMyMywyNTggMzQ4LDIyNCAzNzIsMTg5IDQwMywxNjMgNDQxLDE0NCA0NzksMTI1IDUyNSwxMTUgNTc4LDExNSA2NTYsMTE1IDcxOSwxMzEgNzY2LDE2MiA4MTMsMTkzIDg0NCwyMzMgODYxLDI4MSBMIDEwMTksMjM2IEMgMTAwOCwyMDYgOTkyLDE3NiA5NzIsMTQ2IDk1MSwxMTUgOTI0LDg4IDg5MCw2NCA4NTYsMzkgODE0LDE5IDc2Myw0IDcxMiwtMTIgNjUwLC0yMCA1NzgsLTIwIDQxOCwtMjAgMjk2LDI4IDIxMywxMjMgMTI5LDIxOCA4NywzNjAgODcsNTQ4IDg3LDY0OSAxMDAsNzM1IDEyNSw4MDYgMTUwLDg3NiAxODUsOTMzIDIyOSw5NzcgMjczLDEwMjEgMzI0LDEwNTMgMzgzLDEwNzMgNDQyLDEwOTIgNTA0LDExMDIgNTcxLDExMDIgNjYyLDExMDIgNzM4LDEwODcgNzk5LDEwNTggODYwLDEwMjkgOTA5LDk4OCA5NDYsOTM3IDk4Myw4ODUgMTAwOSw4MjQgMTAyNSw3NTQgMTA0MCw2ODQgMTA0OCw2MDggMTA0OCw1MjcgTCAxMDQ4LDUwMyAyNzYsNTAzIFogTSA4NjIsNjQxIEMgODUyLDc1NSA4MjMsODM4IDc3NSw4OTEgNzI3LDk0MyA2NTgsOTY5IDU2OCw5NjkgNTM4LDk2OSA1MDcsOTY0IDQ3NCw5NTUgNDQxLDk0NSA0MTAsOTI4IDM4Miw5MDMgMzU0LDg3OCAzMzAsODQ1IDMxMSw4MDMgMjkyLDc2MCAyODEsNzA2IDI3OCw2NDEgTCA4NjIsNjQxIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImQiIGhvcml6LWFkdi14PSI5MjciIGQ9Ik0gODIxLDE3NCBDIDc4OCwxMDUgNzQ0LDU1IDY4OSwyNSA2MzQsLTUgNTY1LC0yMCA0ODQsLTIwIDM0NywtMjAgMjQ3LDI2IDE4MywxMTggMTE4LDIxMCA4NiwzNDkgODYsNTM2IDg2LDkxMyAyMTksMTEwMiA0ODQsMTEwMiA1NjYsMTEwMiA2MzQsMTA4NyA2ODksMTA1NyA3NDQsMTAyNyA3ODgsOTc5IDgyMSw5MTQgTCA4MjMsOTE0IEMgODIzLDkyMSA4MjMsOTMxIDgyMyw5NDYgODIyLDk2MCA4MjIsOTc1IDgyMiw5OTEgODIxLDEwMDYgODIxLDEwMjEgODIxLDEwMzUgODIxLDEwNDkgODIxLDEwNTkgODIxLDEwNjUgTCA4MjEsMTQ4NCAxMDAxLDE0ODQgMTAwMSwyMjMgQyAxMDAxLDE5NyAxMDAxLDE3MiAxMDAyLDE0OCAxMDAyLDEyNCAxMDAyLDEwMiAxMDAzLDgyIDEwMDQsNjIgMTAwNCw0NSAxMDA1LDMxIDEwMDYsMTYgMTAwNiw2IDEwMDcsMCBMIDgzNSwwIEMgODM0LDcgODMzLDE2IDgzMiwyOSA4MzEsNDEgODMwLDU1IDgyOSw3MSA4MjgsODcgODI3LDEwNCA4MjYsMTIyIDgyNSwxMzkgODI1LDE1NyA4MjUsMTc0IEwgODIxLDE3NCBaIE0gMjc1LDU0MiBDIDI3NSw0NjcgMjgwLDQwMyAyODksMzUwIDI5OCwyOTcgMzEzLDI1MyAzMzQsMjE5IDM1NSwxODQgMzgxLDE1OSA0MTMsMTQzIDQ0NSwxMjcgNDg0LDExOSA1MzAsMTE5IDU3NywxMTkgNjE5LDEyNyA2NTYsMTQyIDY5MiwxNTcgNzIyLDE4MiA3NDcsMjE3IDc3MSwyNTEgNzg5LDI5NiA4MDIsMzUxIDgxNSw0MDYgODIxLDQ3NCA4MjEsNTU0IDgyMSw2MzEgODE1LDY5NiA4MDIsNzQ5IDc4OSw4MDIgNzcxLDg0NCA3NDYsODc3IDcyMSw5MTAgNjkxLDkzMyA2NTYsOTQ4IDYyMCw5NjIgNTc5LDk2OSA1MzIsOTY5IDQ4OCw5NjkgNDUwLDk2MSA0MTgsOTQ2IDM4Niw5MzEgMzU5LDkwNiAzMzgsODcyIDMxNyw4MzggMzAxLDc5NCAyOTEsNzQwIDI4MCw2ODUgMjc1LDYxOSAyNzUsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImMiIGhvcml6LWFkdi14PSI5MDEiIGQ9Ik0gMjc1LDU0NiBDIDI3NSw0ODQgMjgwLDQyNyAyODksMzc1IDI5OCwzMjMgMzEzLDI3OCAzMzQsMjQxIDM1NSwyMDMgMzg0LDE3NCA0MTksMTUzIDQ1NCwxMzIgNDk3LDEyMiA1NDgsMTIyIDYxMiwxMjIgNjY2LDEzOSA3MDksMTczIDc1MiwyMDYgNzc4LDI1OCA3ODgsMzI4IEwgOTcwLDMyOCBDIDk2NCwyODMgOTUxLDIzOSA5MzEsMTk3IDkxMSwxNTUgODg0LDExOCA4NTAsODYgODE1LDU0IDc3MywyOCA3MjQsOSA2NzUsLTEwIDYxOCwtMjAgNTUzLC0yMCA0NjgsLTIwIDM5NiwtNiAzMzcsMjMgMjc4LDUyIDIzMCw5MSAxOTMsMTQyIDE1NiwxOTIgMTI5LDI1MSAxMTIsMzIwIDk1LDM4OCA4Nyw0NjIgODcsNTQyIDg3LDYxNSA5Myw2NzkgMTA1LDczNSAxMTcsNzkwIDEzNCw4MzkgMTU2LDg4MSAxNzcsOTIyIDIwMyw5NTcgMjMyLDk4NiAyNjEsMTAxNCAyOTMsMTAzNyAzMjgsMTA1NCAzNjIsMTA3MSAzOTgsMTA4MyA0MzYsMTA5MSA0NzQsMTA5OCA1MTIsMTEwMiA1NTEsMTEwMiA2MTIsMTEwMiA2NjYsMTA5NCA3MTMsMTA3NyA3NjAsMTA2MCA4MDEsMTAzOCA4MzYsMTAwOSA4NzAsOTgwIDg5OCw5NDUgOTE5LDkwNiA5NDAsODY3IDk1NSw4MjQgOTY0LDc3OSBMIDc3OSw3NjUgQyA3NzAsODI1IDc0Niw4NzMgNzA4LDkwOCA2NzAsOTQzIDYxNiw5NjEgNTQ2LDk2MSA0OTUsOTYxIDQ1Miw5NTMgNDE4LDkzNiAzODMsOTE5IDM1NSw4OTMgMzM0LDg1OSAzMTMsODI0IDI5OCw3ODEgMjg5LDcyOSAyODAsNjc3IDI3NSw2MTYgMjc1LDU0NiBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJiIiBob3Jpei1hZHYteD0iOTUzIiBkPSJNIDEwNTMsNTQ2IEMgMTA1MywxNjkgOTIwLC0yMCA2NTUsLTIwIDU3MywtMjAgNTA1LC01IDQ1MSwyNSAzOTYsNTQgMzUyLDEwMiAzMTgsMTY4IEwgMzE2LDE2OCBDIDMxNiwxNTEgMzE2LDEzMyAzMTUsMTE0IDMxNCw5NSAzMTMsNzggMzEyLDYyIDMxMSw0NiAzMTAsMzIgMzA5LDIxIDMwOCwxMCAzMDcsMyAzMDYsMCBMIDEzMiwwIEMgMTMzLDYgMTMzLDE2IDEzNCwzMSAxMzUsNDUgMTM1LDYyIDEzNiw4MiAxMzcsMTAyIDEzNywxMjQgMTM4LDE0OCAxMzgsMTcyIDEzOCwxOTcgMTM4LDIyMyBMIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCwxMDYxIEMgMzE4LDEwNDEgMzE4LDEwMjIgMzE4LDEwMDQgMzE3LDk4NSAzMTcsOTY5IDMxNiw5NTUgMzE1LDkzOCAzMTUsOTIzIDMxNCw5MDggTCAzMTgsOTA4IEMgMzUxLDk3NyAzOTYsMTAyNyA0NTEsMTA1NyA1MDYsMTA4NyA1NzQsMTEwMiA2NTUsMTEwMiA3OTIsMTEwMiA4OTIsMTA1NiA5NTcsOTY0IDEwMjEsODcyIDEwNTMsNzMzIDEwNTMsNTQ2IFogTSA4NjQsNTQwIEMgODY0LDYxNSA4NTksNjc5IDg1MCw3MzIgODQxLDc4NSA4MjYsODI5IDgwNSw4NjQgNzg0LDg5OCA3NTgsOTIzIDcyNiw5MzkgNjk0LDk1NSA2NTUsOTYzIDYwOSw5NjMgNTYyLDk2MyA1MjAsOTU1IDQ4NCw5NDAgNDQ3LDkyNSA0MTcsOTAwIDM5Myw4NjYgMzY4LDgzMiAzNTAsNzg3IDMzNyw3MzIgMzI0LDY3NyAzMTgsNjA5IDMxOCw1MjkgMzE4LDQ1MiAzMjQsMzg3IDMzNywzMzQgMzUwLDI4MSAzNjgsMjM5IDM5MywyMDYgNDE3LDE3MyA0NDcsMTQ5IDQ4MywxMzUgNTE5LDEyMCA1NjAsMTEzIDYwNywxMTMgNjUxLDExMyA2ODksMTIxIDcyMSwxMzYgNzUzLDE1MSA3ODAsMTc2IDgwMSwyMTAgODIyLDI0NCA4MzgsMjg4IDg0OSwzNDMgODU5LDM5NyA4NjQsNDYzIDg2NCw1NDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iYSIgaG9yaXotYWR2LXg9IjEwNjAiIGQ9Ik0gNDE0LC0yMCBDIDMwNSwtMjAgMjI0LDkgMTY5LDY2IDExNCwxMjQgODcsMjAzIDg3LDMwMyA4NywzNzUgMTAxLDQzNCAxMjgsNDgwIDE1NSw1MjYgMTkwLDU2MiAyMzQsNTg4IDI3Nyw2MTQgMzI3LDYzMiAzODMsNjQyIDQzOSw2NTIgNDk2LDY1NyA1NTQsNjU3IEwgNzk3LDY1NyA3OTcsNzE3IEMgNzk3LDc2MiA3OTIsODAwIDc4Myw4MzIgNzc0LDg2MyA3NTksODg5IDc0MCw5MDggNzIxLDkyOCA2OTcsOTQyIDY2OCw5NTEgNjM5LDk2MCA2MDQsOTY1IDU2NSw5NjUgNTMwLDk2NSA0OTksOTYzIDQ3MSw5NTggNDQzLDk1MyA0MTksOTQ0IDM5OCw5MzEgMzc3LDkxOCAzNjEsOTAwIDM0OCw4NzggMzM1LDg1NSAzMjcsODI3IDMyMyw3OTMgTCAxMzUsODEwIEMgMTQyLDg1MyAxNTQsODkyIDE3Myw5MjggMTkyLDk2MyAyMTgsOTk0IDI1MywxMDIwIDI4NywxMDQ2IDMzMCwxMDY2IDM4MiwxMDgxIDQzMywxMDk1IDQ5NiwxMTAyIDU2OSwxMTAyIDcwNSwxMTAyIDgwNywxMDcxIDg3NiwxMDA5IDk0NSw5NDYgOTc5LDg1NiA5NzksNzM4IEwgOTc5LDI3MiBDIDk3OSwyMTkgOTg2LDE3OSAxMDAwLDE1MiAxMDE0LDEyNSAxMDQxLDExMSAxMDgwLDExMSAxMDkwLDExMSAxMTAwLDExMiAxMTEwLDExMyAxMTIwLDExNCAxMTMwLDExNiAxMTM5LDExOCBMIDExMzksNiBDIDExMTYsMSAxMDk0LC0zIDEwNzIsLTYgMTA0OSwtOSAxMDI1LC0xMCAxMDAwLC0xMCA5NjYsLTEwIDkzNywtNSA5MTMsNCA4ODgsMTMgODY4LDI2IDg1Myw0NSA4MzgsNjMgODI2LDg2IDgxOCwxMTMgODEwLDE0MCA4MDUsMTcxIDgwMywyMDcgTCA3OTcsMjA3IEMgNzc4LDE3MiA3NTcsMTQxIDczNCwxMTMgNzExLDg1IDY4NCw2MSA2NTMsNDIgNjIyLDIyIDU4OCw3IDU0OSwtNCA1MTAsLTE1IDQ2NSwtMjAgNDE0LC0yMCBaIE0gNDU1LDExNSBDIDUxMiwxMTUgNTYzLDEyNSA2MDYsMTQ2IDY0OSwxNjcgNjg0LDE5NCA3MTMsMjI2IDc0MSwyNTkgNzYyLDI5NCA3NzYsMzMyIDc5MCwzNzEgNzk3LDQwOCA3OTcsNDQzIEwgNzk3LDUzMSA2MDAsNTMxIEMgNTU2LDUzMSA1MTQsNTI4IDQ3NSw1MjIgNDM1LDUxNyA0MDAsNTA2IDM3MCw0ODkgMzQwLDQ3MiAzMTYsNDQ5IDI5OSw0MTggMjgxLDM4OCAyNzIsMzQ5IDI3MiwzMDAgMjcyLDI0MSAyODgsMTk1IDMyMCwxNjMgMzUxLDEzMSAzOTYsMTE1IDQ1NSwxMTUgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iUyIgaG9yaXotYWR2LXg9IjExOTIiIGQ9Ik0gMTI3MiwzODkgQyAxMjcyLDMzMCAxMjYxLDI3NSAxMjM4LDIyNSAxMjE1LDE3NSAxMTc5LDEzMiAxMTMxLDk2IDEwODMsNTkgMTAyMywzMSA5NTAsMTEgODc3LC0xMCA3OTAsLTIwIDY5MCwtMjAgNTE1LC0yMCAzNzgsMTEgMjgwLDcyIDE4MiwxMzMgMTIwLDIyMiA5MywzMzggTCAyNzgsMzc1IEMgMjg3LDMzOCAzMDIsMzA1IDMyMSwyNzUgMzQwLDI0NSAzNjcsMjE5IDQwMCwxOTggNDMzLDE3NiA0NzMsMTU5IDUyMiwxNDcgNTcxLDEzNSA2MjksMTI5IDY5NywxMjkgNzU0LDEyOSA4MDYsMTM0IDg1MywxNDQgOTAwLDE1MyA5NDEsMTY4IDk3NSwxODggMTAwOSwyMDggMTAzNiwyMzQgMTA1NSwyNjYgMTA3NCwyOTcgMTA4MywzMzUgMTA4MywzNzkgMTA4Myw0MjUgMTA3Myw0NjIgMTA1Miw0OTEgMTAzMSw1MjAgMTAwMSw1NDMgOTYzLDU2MiA5MjUsNTgxIDg4MCw1OTYgODI3LDYwOSA3NzQsNjIyIDcxNiw2MzUgNjUyLDY1MCA2MTMsNjU5IDU3Myw2NjggNTM0LDY3OSA0OTQsNjg5IDQ1Niw3MDEgNDIwLDcxNiAzODMsNzMwIDM0OSw3NDcgMzE3LDc2NiAyODUsNzg1IDI1Nyw4MDkgMjM0LDgzNiAyMTEsODYzIDE5Miw4OTQgMTc5LDkzMCAxNjYsOTY1IDE1OSwxMDA2IDE1OSwxMDUzIDE1OSwxMTIwIDE3MywxMTc3IDIwMCwxMjI1IDIyNywxMjcyIDI2NCwxMzExIDMxMiwxMzQyIDM2MCwxMzczIDQxNywxMzk1IDQ4MiwxNDA5IDU0NywxNDIzIDYxOCwxNDMwIDY5NCwxNDMwIDc4MSwxNDMwIDg1NiwxNDIzIDkxOCwxNDEwIDk4MCwxMzk2IDEwMzIsMTM3NSAxMDc1LDEzNDggMTExOCwxMzIxIDExNTIsMTI4NyAxMTc4LDEyNDcgMTIwMywxMjA2IDEyMjQsMTE1OSAxMjM5LDExMDYgTCAxMDUxLDEwNzMgQyAxMDQyLDExMDcgMTAyOCwxMTM3IDEwMTEsMTE2NCA5OTMsMTE5MSA5NzAsMTIxMyA5NDEsMTIzMSA5MTIsMTI0OSA4NzgsMTI2MyA4MzcsMTI3MiA3OTYsMTI4MSA3NDcsMTI4NiA2OTIsMTI4NiA2MjcsMTI4NiA1NzIsMTI4MCA1MjgsMTI2OSA0ODMsMTI1NyA0NDgsMTI0MSA0MjEsMTIyMSAzOTQsMTIwMSAzNzQsMTE3OCAzNjMsMTE1MSAzNTEsMTEyNCAzNDUsMTA5NCAzNDUsMTA2MyAzNDUsMTAyMSAzNTYsOTg3IDM3Nyw5NjAgMzk4LDkzMyA0MjYsOTEwIDQ2Miw4OTIgNDk4LDg3NCA1NDAsODU5IDU4Nyw4NDcgNjM0LDgzNSA2ODUsODIzIDczOCw4MTEgNzgxLDgwMSA4MjUsNzkxIDg2OCw3ODEgOTExLDc3MCA5NTIsNzU4IDk5MSw3NDQgMTAzMCw3MjkgMTA2Nyw3MTIgMTEwMiw2OTMgMTEzNiw2NzQgMTE2Niw2NTAgMTE5MSw2MjIgMTIxNiw1OTQgMTIzNiw1NjEgMTI1MSw1MjMgMTI2NSw0ODUgMTI3Miw0NDAgMTI3MiwzODkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iTyIgaG9yaXotYWR2LXg9IjE0MzAiIGQ9Ik0gMTQ5NSw3MTEgQyAxNDk1LDYwMSAxNDc5LDUwMSAxNDQ4LDQxMSAxNDE2LDMyMSAxMzcwLDI0NCAxMzEwLDE4MCAxMjUwLDExNiAxMTc3LDY3IDEwOTAsMzIgMTAwMywtMyA5MDUsLTIwIDc5NSwtMjAgNjc5LC0yMCA1NzcsLTIgNDkwLDM1IDQwMyw3MSAzMzAsMTIyIDI3MiwxODcgMjE0LDI1MiAxNzAsMzI5IDE0MSw0MTggMTEyLDUwNyA5Nyw2MDUgOTcsNzExIDk3LDgyMSAxMTIsOTIwIDE0MywxMDA5IDE3NCwxMDk4IDIxOSwxMTczIDI3OCwxMjM2IDMzNywxMjk4IDQxMSwxMzQ2IDQ5OCwxMzgwIDU4NSwxNDEzIDY4NCwxNDMwIDc5NywxNDMwIDkwOSwxNDMwIDEwMDksMTQxMyAxMDk2LDEzNzkgMTE4MywxMzQ1IDEyNTYsMTI5NyAxMzE1LDEyMzQgMTM3NCwxMTcxIDE0MTgsMTA5NiAxNDQ5LDEwMDcgMTQ4MCw5MTggMTQ5NSw4MjAgMTQ5NSw3MTEgWiBNIDEzMDAsNzExIEMgMTMwMCw3OTYgMTI4OSw4NzMgMTI2OCw5NDIgMTI0NiwxMDExIDEyMTQsMTA3MSAxMTcyLDExMjAgMTEyOSwxMTY5IDEwNzcsMTIwNyAxMDE0LDEyMzQgOTUxLDEyNjEgODc5LDEyNzQgNzk3LDEyNzQgNzEzLDEyNzQgNjM5LDEyNjEgNTc2LDEyMzQgNTEzLDEyMDcgNDYwLDExNjkgNDE4LDExMjAgMzc1LDEwNzEgMzQ0LDEwMTEgMzIzLDk0MiAzMDIsODczIDI5MSw3OTYgMjkxLDcxMSAyOTEsNjI2IDMwMiw1NDkgMzI0LDQ3OSAzNDUsNDA4IDM3NywzNDggNDIwLDI5NyA0NjIsMjQ2IDUxNSwyMDYgNTc4LDE3OCA2NDEsMTQ5IDcxMywxMzUgNzk1LDEzNSA4ODMsMTM1IDk1OSwxNDkgMTAyMywxNzggMTA4NiwyMDcgMTEzOSwyNDcgMTE4MCwyOTggMTIyMSwzNDkgMTI1MSw0MDkgMTI3MSw0ODAgMTI5MCw1NTEgMTMwMCw2MjggMTMwMCw3MTEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iQyIgaG9yaXotYWR2LXg9IjEzMjQiIGQ9Ik0gNzkyLDEyNzQgQyA3MTIsMTI3NCA2NDEsMTI2MSA1ODAsMTIzNCA1MTgsMTIwNyA0NjYsMTE2OSA0MjUsMTEyMCAzODMsMTA3MSAzNTEsMTAxMSAzMzAsOTQyIDMwOSw4NzMgMjk4LDc5NiAyOTgsNzExIDI5OCw2MjYgMzEwLDU0OSAzMzMsNDc5IDM1Niw0MDggMzg5LDM0OCA0MzIsMjk3IDQ3NSwyNDYgNTI3LDIwNyA1OTAsMTc5IDY1MiwxNTEgNzIyLDEzNyA4MDAsMTM3IDg1NSwxMzcgOTA1LDE0NCA5NTAsMTU5IDk5NSwxNzMgMTAzNSwxOTMgMTA3MiwyMTkgMTEwOCwyNDUgMTE0MCwyNzYgMTE2OSwzMTIgMTE5OCwzNDcgMTIyMywzODcgMTI0NSw0MzAgTCAxNDAxLDM1MiBDIDEzNzYsMjk5IDEzNDQsMjUwIDEzMDcsMjA1IDEyNzAsMTYwIDEyMjYsMTIwIDExNzYsODcgMTEyNSw1NCAxMDY4LDI4IDEwMDUsOSA5NDEsLTEwIDg3MCwtMjAgNzkxLC0yMCA2NzcsLTIwIDU3NywtMiA0OTIsMzUgNDA2LDcxIDMzNCwxMjIgMjc3LDE4NyAyMTksMjUyIDE3NiwzMjkgMTQ3LDQxOCAxMTgsNTA3IDEwNCw2MDUgMTA0LDcxMSAxMDQsODIxIDExOSw5MjAgMTUwLDEwMDkgMTgwLDEwOTggMjI0LDExNzMgMjgzLDEyMzYgMzQxLDEyOTggNDEzLDEzNDYgNDk4LDEzODAgNTgzLDE0MTMgNjgxLDE0MzAgNzkwLDE0MzAgOTQwLDE0MzAgMTA2NSwxNDAxIDExNjYsMTM0MiAxMjY3LDEyODMgMTM0MSwxMTk2IDEzODgsMTA4MSBMIDEyMDcsMTAyMSBDIDExOTQsMTA1NCAxMTc2LDEwODYgMTE1MywxMTE3IDExMzAsMTE0NyAxMTAyLDExNzQgMTA2OCwxMTk3IDEwMzQsMTIyMCA5OTQsMTIzOSA5NDksMTI1MyA5MDMsMTI2NyA4NTEsMTI3NCA3OTIsMTI3NCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSIgIiBob3Jpei1hZHYteD0iNTU2Ii8+CiAgPC9mb250PgogPC9kZWZzPgogPGRlZnMgY2xhc3M9IlRleHRTaGFwZUluZGV4Ij4KICA8ZyBvb286c2xpZGU9ImlkMSIgb29vOmlkLWxpc3Q9ImlkMyBpZDQgaWQ1IGlkNiBpZDcgaWQ4IGlkOSBpZDEwIGlkMTEgaWQxMiBpZDEzIGlkMTQgaWQxNSBpZDE2IGlkMTcgaWQxOCBpZDE5Ii8+CiA8L2RlZnM+CiA8ZGVmcyBjbGFzcz0iRW1iZWRkZWRCdWxsZXRDaGFycyI+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDU3MzU2KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gNTgwLDExNDEgTCAxMTYzLDU3MSA1ODAsMCAtNCw1NzEgNTgwLDExNDEgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoNTczNTQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSA4LDExMjggTCAxMTM3LDExMjggMTEzNywwIDgsMCA4LDExMjggWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAxNDYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAxNzQsMCBMIDYwMiw3MzkgMTc0LDE0ODEgMTQ1Niw3MzkgMTc0LDAgWiBNIDEzNTgsNzM5IEwgMzA5LDEzNDYgNjU5LDczOSAxMzU4LDczOSBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSgxMDEzMikiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIDIwMTUsNzM5IEwgMTI3NiwwIDcxNywwIDEyNjAsNTQzIDE3NCw1NDMgMTc0LDkzNiAxMjYwLDkzNiA3MTcsMTQ4MSAxMjc0LDE0ODEgMjAxNSw3MzkgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDcpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAwLC0yIEMgLTcsMTQgLTE2LDI3IC0yNSwzNyBMIDM1Niw1NjcgQyAyNjIsODIzIDIxNSw5NTIgMjE1LDk1NCAyMTUsOTc5IDIyOCw5OTIgMjU1LDk5MiAyNjQsOTkyIDI3Niw5OTAgMjg5LDk4NyAzMTAsOTkxIDMzMSw5OTkgMzU0LDEwMTIgTCAzODEsOTk5IDQ5Miw3NDggNzcyLDEwNDkgODM2LDEwMjQgODYwLDEwNDkgQyA4ODEsMTAzOSA5MDEsMTAyNSA5MjIsMTAwNiA4ODYsOTM3IDgzNSw4NjMgNzcwLDc4NCA3NjksNzgzIDcxMCw3MTYgNTk0LDU4NCBMIDc3NCwyMjMgQyA3NzQsMTk2IDc1MywxNjggNzExLDEzOSBMIDcyNywxMTkgQyA3MTcsOTAgNjk5LDc2IDY3Miw3NiA2NDEsNzYgNTcwLDE3OCA0NTcsMzgxIEwgMTY0LC03NiBDIDE0MiwtMTEwIDExMSwtMTI3IDcyLC0xMjcgMzAsLTEyNyA5LC0xMTAgOCwtNzYgMSwtNjcgLTIsLTUyIC0yLC0zMiAtMiwtMjMgLTEsLTEzIDAsLTIgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAyODUsLTMzIEMgMTgyLC0zMyAxMTEsMzAgNzQsMTU2IDUyLDIyOCA0MSwzMzMgNDEsNDcxIDQxLDU0OSA1NSw2MTYgODIsNjcyIDExNiw3NDMgMTY5LDc3OCAyNDAsNzc4IDI5Myw3NzggMzI4LDc0NyAzNDYsNjg0IEwgMzY5LDUwOCBDIDM3Nyw0NDQgMzk3LDQxMSA0MjgsNDEwIEwgMTE2MywxMTE2IEMgMTE3NCwxMTI3IDExOTYsMTEzMyAxMjI5LDExMzMgMTI3MSwxMTMzIDEyOTIsMTExOCAxMjkyLDEwODcgTCAxMjkyLDk2NSBDIDEyOTIsOTI5IDEyODIsOTAxIDEyNjIsODgxIEwgNDQyLDQ3IEMgMzkwLC02IDMzOCwtMzMgMjg1LC0zMyBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSg5Njc5KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gODEzLDAgQyA2MzIsMCA0ODksNTQgMzgzLDE2MSAyNzYsMjY4IDIyMyw0MTEgMjIzLDU5MiAyMjMsNzczIDI3Niw5MTYgMzgzLDEwMjMgNDg5LDExMzAgNjMyLDExODQgODEzLDExODQgOTkyLDExODQgMTEzNiwxMTMwIDEyNDUsMTAyMyAxMzUzLDkxNiAxNDA3LDc3MiAxNDA3LDU5MiAxNDA3LDQxMiAxMzUzLDI2OCAxMjQ1LDE2MSAxMTM2LDU0IDk5MiwwIDgxMywwIFoiLz4KICA8L2c+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDgyMjYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAzNDYsNDU3IEMgMjczLDQ1NyAyMDksNDgzIDE1NSw1MzUgMTAxLDU4NiA3NCw2NDkgNzQsNzIzIDc0LDc5NiAxMDEsODU5IDE1NSw5MTEgMjA5LDk2MyAyNzMsOTg5IDM0Niw5ODkgNDE5LDk4OSA0ODAsOTYzIDUzMSw5MTAgNTgyLDg1OSA2MDgsNzk2IDYwOCw3MjMgNjA4LDY0OCA1ODMsNTg2IDUzMiw1MzUgNDgyLDQ4MyA0MjAsNDU3IDM0Niw0NTcgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoODIxMSkiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIC00LDQ1OSBMIDExMzUsNDU5IDExMzUsNjA2IC00LDYwNiAtNCw0NTkgWiIvPgogIDwvZz4KIDwvZGVmcz4KIDxkZWZzIGNsYXNzPSJUZXh0RW1iZWRkZWRCaXRtYXBzIi8+CiA8Zz4KICA8ZyBpZD0iaWQyIiBjbGFzcz0iTWFzdGVyX1NsaWRlIj4KICAgPGcgaWQ9ImJnLWlkMiIgY2xhc3M9IkJhY2tncm91bmQiLz4KICAgPGcgaWQ9ImJvLWlkMiIgY2xhc3M9IkJhY2tncm91bmRPYmplY3RzIi8+CiAgPC9nPgogPC9nPgogPGcgY2xhc3M9IlNsaWRlR3JvdXAiPgogIDxnPgogICA8ZyBpZD0iaWQxIiBjbGFzcz0iU2xpZGUiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSI+CiAgICA8ZyBjbGFzcz0iUGFnZSI+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMyI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MCw3MDAwIEwgNzAwMCw3MDAwIDcwMDAsMzAwMCA5OTAwLDMwMDAgOTkwMCw3MDAwIDg0NTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTIwNTAsNzAwMCBMIDEwMTAwLDcwMDAgMTAxMDAsMzAwMCAxNDAwMCwzMDAwIDE0MDAwLDcwMDAgMTIwNTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkVsbGlwc2VTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDUiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDg5OTksMzMwMCBDIDkxMDUsMzMxMiA5MTk1LDMzODMgOTI4OCwzNTMxIDkzODcsMzY5MCA5NDU5LDM4ODkgOTUxNiw0MTY1IDk1NzQsNDQ0MSA5NjAwLDQ3MTIgOTYwMCw1MDMxIDk2MDAsNTM1MCA5NTc0LDU2MjEgOTUxNiw1ODk3IDk0NTksNjE3MyA5NDAyLDYzMjggOTMxOSw2NDc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiIGQ9Ik0gOTE0MSw2NzAxIEwgOTQwNSw2NTI2IDkyNDgsNjQwMyA5MTQxLDY3MDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5FbGxpcHNlU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ2Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDc5NCw2NzEwIEMgMTA3NDgsNjY2OSAxMDcxMCw2NjE4IDEwNjY4LDY1NDAgMTA1ODMsNjM4MCAxMDUyMSw2MTgxIDEwNDcyLDU5MDUgMTA0MjIsNTYyOCAxMDQwMCw1MzU2IDEwNDAwLDUwMzYgMTA0MDAsNDcxNiAxMDQyMiw0NDQ0IDEwNDcyLDQxNjggMTA1MjEsMzg5MSAxMDU4MywzNjkyIDEwNjY4LDM1MzIgMTA3NDgsMzM4MyAxMDY5MCwzNDkyIDEwNzAxLDM0NzQiLz4KICAgICAgIDxwYXRoIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSIgZD0iTSAxMDkxNiwzMzAwIEwgMTA2MjIsMzQxNiAxMDc1MCwzNTY5IDEwOTE2LDMzMDAgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDciPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4OTksNjkwMCBDIDk5NTUsNjkwMCA5OTk5LDY5NDMgOTk5OSw2OTk5IDk5OTksNzA1NSA5OTU1LDcwOTkgOTg5OSw3MDk5IDk4NDMsNzA5OSA5ODAwLDcwNTUgOTgwMCw2OTk5IDk4MDAsNjk0MyA5ODQzLDY5MDAgOTg5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODAwLDY5MDAgTCA5ODAwLDY5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAxLDcxMDEgTCAxMDAwMSw3MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ4Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDA5OSwyOTAwIEMgMTAxNTUsMjkwMCAxMDE5OSwyOTQzIDEwMTk5LDI5OTkgMTAxOTksMzA1NSAxMDE1NSwzMDk5IDEwMDk5LDMwOTkgMTAwNDMsMzA5OSAxMDAwMCwzMDU1IDEwMDAwLDI5OTkgMTAwMDAsMjk0MyAxMDA0MywyOTAwIDEwMDk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAwLDI5MDAgTCAxMDAwMCwyOTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMSwzMTAxIEwgMTAyMDEsMzEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkOSI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTg5OSwyOTAwIEMgOTk1NSwyOTAwIDk5OTksMjk0MyA5OTk5LDI5OTkgOTk5OSwzMDU1IDk5NTUsMzA5OSA5ODk5LDMwOTkgOTg0MywzMDk5IDk4MDAsMzA1NSA5ODAwLDI5OTkgOTgwMCwyOTQzIDk4NDMsMjkwMCA5ODk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4MDAsMjkwMCBMIDk4MDAsMjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDEsMzEwMSBMIDEwMDAxLDMxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEwIj4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODk5LDQ5MDAgQyA5OTU1LDQ5MDAgOTk5OSw0OTQzIDk5OTksNDk5OSA5OTk5LDUwNTUgOTk1NSw1MDk5IDk4OTksNTA5OSA5ODQzLDUwOTkgOTgwMCw1MDU1IDk4MDAsNDk5OSA5ODAwLDQ5NDMgOTg0Myw0OTAwIDk4OTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTgwMCw0OTAwIEwgOTgwMCw0OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMSw1MTAxIEwgMTAwMDEsNTEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTEiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDk5LDQ5MDAgQyAxMDE1NSw0OTAwIDEwMTk5LDQ5NDMgMTAxOTksNDk5OSAxMDE5OSw1MDU1IDEwMTU1LDUwOTkgMTAwOTksNTA5OSAxMDA0Myw1MDk5IDEwMDAwLDUwNTUgMTAwMDAsNDk5OSAxMDAwMCw0OTQzIDEwMDQzLDQ5MDAgMTAwOTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDAsNDkwMCBMIDEwMDAwLDQ5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjAxLDUxMDEgTCAxMDIwMSw1MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxMiI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwOTksNjkwMCBDIDEwMTU1LDY5MDAgMTAxOTksNjk0MyAxMDE5OSw2OTk5IDEwMTk5LDcwNTUgMTAxNTUsNzA5OSAxMDA5OSw3MDk5IDEwMDQzLDcwOTkgMTAwMDAsNzA1NSAxMDAwMCw2OTk5IDEwMDAwLDY5NDMgMTAwNDMsNjkwMCAxMDA5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMCw2OTAwIEwgMTAwMDAsNjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAyMDEsNzEwMSBMIDEwMjAxLDcxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEzIj4KICAgICAgIDxwYXRoIGZpbGw9InJnYigyNTUsMjU1LDI1NSkiIHN0cm9rZT0ibm9uZSIgZD0iTSA1MTAwLDUyMDAgTCAzNTAwLDUyMDAgMzUwMCwzMDAwIDY3MDAsMzAwMCA2NzAwLDUyMDAgNTEwMCw1MjAwIFoiLz4KICAgICAgIDx0ZXh0IGNsYXNzPSJUZXh0U2hhcGUiPjx0c3BhbiBjbGFzcz0iVGV4dFBhcmFncmFwaCIgZm9udC1mYW1pbHk9IkxpYmVyYXRpb24gU2Fucywgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNTNweCIgZm9udC13ZWlnaHQ9IjQwMCI+PHRzcGFuIGNsYXNzPSJUZXh0UG9zaXRpb24iIHg9IjM3NTAiIHk9IjM0MzMiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPlN1YmRpdmlzaW9uIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iMzgyNyI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+cG9pbnRzIG5lZWQgdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI0MjIxIj48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5sYW5kIG9uIHRoZSBzYW1lIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iNDYxNSI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+bG9jYXRpb24gdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI1MDA5Ij48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5wcmV2ZW50IGNyYWNraW5nPC90c3Bhbj48L3RzcGFuPjwvdHNwYW4+PC90ZXh0PgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5MaW5lU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjYwMCw0MjAwIEwgNjY1MSw0MjEzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjcwMyw0MjI3IEwgNjc1NCw0MjQwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjgwNiw0MjUzIEwgNjg1Nyw0MjY2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjkwOCw0MjgwIEwgNjk2MCw0MjkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzAxMSw0MzA2IEwgNzA2Myw0MzE5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzExNCw0MzMzIEwgNzE2NSw0MzQ2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzIxNyw0MzU5IEwgNzI2OCw0MzcyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzMyMCw0Mzg2IEwgNzM3MSw0Mzk5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzQyMyw0NDEyIEwgNzQ3NCw0NDI2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzUyNSw0NDM5IEwgNzU3Nyw0NDUyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzYyOCw0NDY1IEwgNzY4MCw0NDc5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzczMSw0NDkyIEwgNzc4Miw0NTA1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzgzNCw0NTE4IEwgNzg4NSw0NTMyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzkzNyw0NTQ1IEwgNzk4OCw0NTU4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODAzOSw0NTcxIEwgODA5MSw0NTg1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODE0Miw0NTk4IEwgODE5NCw0NjExIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODI0NSw0NjI1IEwgODI5Niw0NjM4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODM0OCw0NjUxIEwgODM5OSw0NjY0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MSw0Njc4IEwgODUwMiw0NjkxIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODU1Myw0NzA0IEwgODYwNSw0NzE3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODY1Niw0NzMxIEwgODcwOCw0NzQ0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODc1OSw0NzU3IEwgODgxMSw0NzcwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODg2Miw0Nzg0IEwgODkxMyw0Nzk3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODk2NSw0ODEwIEwgOTAxNiw0ODI0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTA2OCw0ODM3IEwgOTExOSw0ODUwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTE3MCw0ODYzIEwgOTIyMiw0ODc3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTI3Myw0ODkwIEwgOTMyNSw0OTAzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTM3Niw0OTE2IEwgOTQyNyw0OTMwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTQ3OSw0OTQzIEwgOTUzMCw0OTU2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTU4Miw0OTY5IEwgOTYzMyw0OTgzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTY4NCw0OTk2IEwgOTcwMCw1MDAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTUiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNjUwLDI3MDAgTCAxMDcwMCwyNzAwIDEwNzAwLDE1MDAgMTQ2MDAsMTUwMCAxNDYwMCwyNzAwIDEyNjUwLDI3MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTA5NTAiIHk9IjIwMjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMDk1MCIgeT0iMjQxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTYiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyODUwLDg1MDAgTCAxMDkwMCw4NTAwIDEwOTAwLDczMDAgMTQ4MDAsNzMwMCAxNDgwMCw4NTAwIDEyODUwLDg1MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9Ijc4MjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iODIxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTciPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNDAwLDUyMDAgTCAxMDkwMCw1MjAwIDEwOTAwLDMzMDAgMTM5MDAsMzMwMCAxMzkwMCw1MjAwIDEyNDAwLDUyMDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjM3ODAiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPk9wcG9zaW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQxNzQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmRpcmVjdGlvbnMgb2YgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iNDU2OCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+ZWRnZSB3YWxraW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQ5NjIiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmZvciBzdWJkaXZpc2lvbjwvdHNwYW4+PC90c3Bhbj48L3RzcGFuPjwvdGV4dD4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuTGluZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTgiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMzAwLDI5MDAgTCAxMDM0MSwyODY3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzODMsMjgzNCBMIDEwNDI0LDI4MDEiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ2NiwyNzY3IEwgMTA1MDcsMjczNCIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ5LDI3MDEgTCAxMDU5MCwyNjY4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsMjYzNSBMIDEwNjczLDI2MDIiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxNSwyNTY4IEwgMTA3NTYsMjUzNSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNzk3LDI1MDIgTCAxMDgwMCwyNTAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkxpbmVTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDE5Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMCw3MTAwIEwgMTAyNDMsNzEzMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjg2LDcxNjIgTCAxMDMzMCw3MTkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzNzMsNzIyMyBMIDEwNDE2LDcyNTQiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ1OSw3Mjg1IEwgMTA1MDIsNzMxNiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ2LDczNDcgTCAxMDU4OSw3Mzc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsNzQwOSBMIDEwNjc1LDc0MzkiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxOCw3NDcwIEwgMTA3NjIsNzUwMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwODA1LDc1MzIgTCAxMDg0OCw3NTYzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA4OTEsNzU5NCBMIDEwOTAwLDc2MDAiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgPC9nPgogIDwvZz4KIDwvZz4KPC9zdmc+" alt="precise"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>As stated in “<a href="#evaluation-of-expressions">Evaluation of Expressions</a>”, |
| the compiler may transform expressions even if this changes the resulting |
| value. |
| Without any qualifiers, implementations are permitted to perform |
| optimizations that effectively modify the order or number of operations used |
| to evaluate an expression, even if those optimizations may produce slightly |
| different results relative to unoptimized code.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>precise</strong> qualifier ensures that operations contributing to a |
| variable’s value are done in their stated order and with operator consistency. |
| The order is determined by operator precedence and parenthesis, as described in |
| “<a href="#operators">Operators</a>”. |
| Operator consistency means for each particular operator, for example the |
| multiply operator (<strong>*</strong>), its operation is always computed with the same |
| precision. |
| Specifically, values computed by compiler-generated code must adhere to the |
| following identities:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>a + b = b + a</p> |
| </li> |
| <li> |
| <p>a * b = b * a</p> |
| </li> |
| <li> |
| <p>a * b + c * d = b * a + c* d = d * c + b * a = <any other mathematically |
| valid combination></p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>While the following are prevented:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>a + (b + c) is not allowed to become (a + b) + c</p> |
| </li> |
| <li> |
| <p>a * (b * c) is not allowed to become (a * b) * c</p> |
| </li> |
| <li> |
| <p>a * b + c is not allowed to become a single operation <strong>fma</strong>(a, b, c)</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Where <em>a</em>, <em>b</em>, <em>c</em>, and <em>d</em>, are scalars or vectors, not matrices. |
| (Matrix multiplication generally does not commute.) It is the shader |
| writer’s responsibility to express the computation in terms of these rules |
| and the compiler’s responsibility to follow these rules. |
| See the description of <em>gl_TessCoord</em> for the rules the tessellation stages |
| are responsible for following, which in conjunction with the above allow |
| avoiding cracking when subdividing.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">precise out vec4 position;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>declares that operations used to produce the value of <em>position</em> must be |
| performed in exactly the order specified in the source code and with all |
| operators being treated consistently. |
| As with the <strong>invariant</strong> qualifier (see “<a href="#the-invariant-qualifier">The |
| Invariant Qualifier</a>”), the <strong>precise</strong> qualifier may be used to qualify a |
| built-in or previously declared user-defined variable as being precise:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out vec3 Color; |
| precise Color; <span class="comment">// make existing Color be precise</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When applied to a block, a structure type, or a variable of structure type, |
| <strong>precise</strong> applies to each contained member, recursively.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This qualifier will affect the evaluation of an r-value in a particular |
| function if and only if the result is eventually consumed in the same |
| function by an l-value qualified as <strong>precise</strong>. |
| Any other expressions within a function are not affected, including return |
| values and output parameters not declared as <strong>precise</strong> but that are |
| eventually consumed outside the function by a variable qualified as |
| <strong>precise</strong>. Unaffected expressions also include the controlling expressions |
| in selection and iteration statements and the condition in ternary |
| operators (<strong>?:</strong>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Some examples of the use of <strong>precise</strong>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in vec4 a, b, c, d; |
| precise out vec4 v; |
| |
| <span class="predefined-type">float</span> func(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h) |
| { |
| <span class="keyword">return</span> (e*f) + (g*h); <span class="comment">// no constraint on order or operator consistency</span> |
| } |
| |
| <span class="predefined-type">float</span> func2(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h) |
| { |
| precise <span class="predefined-type">float</span> result = (e*f) + (g*h); <span class="comment">// ensures same precision for the two multiplies</span> |
| <span class="keyword">return</span> result; |
| } |
| |
| <span class="predefined-type">float</span> func3(<span class="predefined-type">float</span> i, <span class="predefined-type">float</span> j, precise out <span class="predefined-type">float</span> k) |
| { |
| k = i * i + j; <span class="comment">// precise, due to <k> declaration</span> |
| } |
| |
| <span class="directive">void</span> main() |
| { |
| vec3 r = vec3(a * b); <span class="comment">// precise, used to compute v.xyz</span> |
| vec3 s = vec3(c * d); <span class="comment">// precise, used to compute v.xyz</span> |
| v.xyz = r + s; <span class="comment">// precise</span> |
| v.w = (a.w * b.w) + (c.w * d.w); <span class="comment">// precise</span> |
| v.x = func(a.x, b.x, c.x, d.x); <span class="comment">// values computed in func() are NOT precise</span> |
| v.x = func2(a.x, b.x, c.x, d.x); <span class="comment">// precise!</span> |
| func3(a.x * b.x, c.x * d.x, v.x); <span class="comment">// precise!</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For the purposes of determining if an output from one shader stage matches |
| an input of the next stage, the <strong>precise</strong> qualifier need not match between |
| the input and the output.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All constant expressions are evaluated as if <strong>precise</strong> was present, whether |
| or not it is present. |
| However, as described in “<a href="#constant-expressions">Constant Expressions</a>”, |
| there is no requirement that a compile-time constant expression evaluates to |
| the same value as a corresponding non-constant expression.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="memory-qualifiers">4.10. Memory Qualifiers</h3> |
| <div class="paragraph"> |
| <p>Shader storage blocks, variables declared within shader storage blocks and |
| variables declared as image types (the basic opaque types with “<strong>image</strong>” |
| in their keyword), can be further qualified with one or more of the |
| following memory qualifiers:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top">Meaning</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>coherent</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where reads and writes are coherent with |
| reads and writes from other shader invocations</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>volatile</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">memory variable whose underlying value may be changed at any |
| point during shader execution by some source other than the |
| current shader invocation</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>restrict</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where use of that variable is the only way |
| to read and write the underlying memory in the relevant |
| shader stage</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>readonly</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to read the underlying |
| memory, but cannot be used to write the underlying memory</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>writeonly</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to write the underlying |
| memory, but cannot be used to read the underlying memory</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Memory accesses to image variables declared using the <strong>coherent</strong> qualifier |
| are performed coherently with accesses to the same location from other |
| shader invocations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As described in section |
| 7.11 |
| “Shader Memory Access” of the |
| <a href="#references">OpenGL ES Specification</a>, shader memory reads and writes complete in a |
| largely undefined order. |
| The built-in function <strong>memoryBarrier</strong>() can be used if needed to guarantee |
| the completion and relative ordering of memory accesses performed by a |
| single shader invocation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When accessing memory using variables not declared as <strong>coherent</strong>, the memory |
| accessed by a shader may be cached by the implementation to service future |
| accesses to the same address. |
| Memory stores may be cached in such a way that the values written may not be |
| visible to other shader invocations accessing the same memory. |
| The implementation may cache the values fetched by memory reads and return |
| the same values to any shader invocation accessing the same memory, even if |
| the underlying memory has been modified since the first memory read. |
| While variables not declared as <strong>coherent</strong> may not be useful for |
| communicating between shader invocations, using non-coherent accesses may |
| result in higher performance.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Memory accesses to image variables declared using the <strong>volatile</strong> qualifier |
| must treat the underlying memory as though it could be read or written at |
| any point during shader execution by some source other than the executing |
| shader invocation. |
| When a volatile variable is read, its value must be re-fetched from the |
| underlying memory, even if the shader invocation performing the read had |
| previously fetched its value from the same memory. |
| When a volatile variable is written, its value must be written to the |
| underlying memory, even if the compiler can conclusively determine that its |
| value will be overwritten by a subsequent write. |
| Since the external source reading or writing a <strong>volatile</strong> variable may be |
| another shader invocation, variables declared as <strong>volatile</strong> are |
| automatically treated as coherent.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Memory accesses to image variables declared using the <strong>restrict</strong> qualifier |
| may be compiled assuming that the variable used to perform the memory access |
| is the only way to access the underlying memory using the shader stage in |
| question. |
| This allows the compiler to coalesce or reorder loads and stores using |
| <strong>restrict</strong>-qualified image variables in ways that wouldn’t be permitted |
| for image variables not so qualified, because the compiler can assume that |
| the underlying image won’t be read or written by other code. |
| Applications are responsible for ensuring that image memory referenced by |
| variables qualified with <strong>restrict</strong> will not be referenced using other |
| variables in the same scope; otherwise, accesses to <strong>restrict</strong>-qualified |
| variables will have undefined results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Memory accesses to image variables declared using the <strong>readonly</strong> qualifier |
| may only read the underlying memory, which is treated as read-only memory |
| and cannot be written to. |
| It is an error to pass an image variable qualified with |
| <strong>readonly</strong> to <strong>imageStore</strong>() or other built-in functions that modify image |
| memory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Memory accesses to image variables declared using the <strong>writeonly</strong> qualifier |
| may only write the underlying memory; the underlying memory cannot be read. |
| It is an error to pass an image variable qualified with |
| <strong>writeonly</strong> to <strong>imageLoad</strong>() or other built-in functions that read image |
| memory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A variable could be qualified as both <strong>readonly</strong> and <strong>writeonly</strong>, disallowing |
| both read and write. Such variables can still be used with some queries, for |
| example <strong>imageSize</strong>() and <strong>.length</strong>().</p> |
| </div> |
| <div class="paragraph"> |
| <p>Except for image variables qualified with the format qualifiers <strong>r32f</strong>, |
| <strong>r32i</strong>, and <strong>r32ui</strong>, image variables must specify a memory qualifier |
| (<strong>readonly</strong>, <strong>writeonly</strong>, or both).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The memory qualifiers <strong>coherent</strong>, <strong>volatile</strong>, <strong>restrict</strong>, <strong>readonly</strong>, and |
| <strong>writeonly</strong> may be used in the declaration of buffer variables (i.e., |
| members of shader storage blocks). |
| When a buffer variable is declared with a memory qualifier, the behavior |
| specified for memory accesses involving image variables described above |
| applies identically to memory accesses involving that buffer variable. |
| It is a compile-time error to assign to a buffer variable qualified with |
| <strong>readonly</strong> or to read from a buffer variable qualified with <strong>writeonly</strong>. |
| The combination <strong>readonly</strong> <strong>writeonly</strong> is allowed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additionally, memory qualifiers may be used at the block-level declaration |
| of a shader storage block, including the combination <strong>readonly</strong> <strong>writeonly</strong>. |
| When a block declaration is qualified with a memory qualifier, it is as if |
| all of its members were declared with the same memory qualifier. |
| For example, the block declaration</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">coherent buffer Block { |
| readonly vec4 member1; |
| vec4 member2; |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>is equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">buffer Block { |
| coherent readonly vec4 member1; |
| coherent vec4 member2; |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Memory qualifiers are only supported in the declarations of image variables, |
| buffer variables, and shader storage blocks; it is an error to use such |
| qualifiers in any other declarations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When calling user-defined functions, variables qualified with <strong>coherent</strong>, |
| <strong>volatile</strong>, <strong>readonly</strong>, or <strong>writeonly</strong> may not be passed to functions whose |
| formal parameters lack such qualifiers. |
| (See “<a href="#function-definitions">Function Definitions</a>” for more detail on |
| function calling.) It is legal to have any additional memory qualifiers on a |
| formal parameter, but only <strong>restrict</strong> can be taken away from a calling |
| argument, by a formal parameter that lacks the <strong>restrict</strong> qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a built-in function is called, the code generated is to be based on the |
| actual qualification of the calling argument, not on the list of memory |
| qualifiers specified on the formal parameter in the prototype.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 funcA(restrict image2D a) { ... } |
| vec4 funcB(image2D a) { ... } |
| layout(rgba32f) uniform image2D img1; |
| layout(rgba32f) coherent uniform image2D img2; |
| |
| funcA(img1); <span class="comment">// OK, adding "restrict" is allowed</span> |
| funcB(img2); <span class="comment">// illegal, stripping "coherent" is not</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Layout qualifiers cannot be used on formal function parameters, and layout |
| qualification is not included in parameter matching.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the use of <strong>const</strong> in an image variable declaration is qualifying |
| the const-ness of the variable being declared, not the image it refers to. |
| The qualifier <strong>readonly</strong> qualifies the image memory (as accessed through |
| that variable) while <strong>const</strong> qualifies the variable itself.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="specialization-constant-qualifier">4.11. Specialization-Constant Qualifier</h3> |
| <div class="paragraph"> |
| <p>Specialization constants are used only for SPIR-V and declared using the |
| <strong>constant_id</strong> layout qualifier. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">17</span>) <span class="directive">const</span> <span class="predefined-type">int</span> arraySize = <span class="integer">12</span>;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above makes a specialization constant with a default value of 12. |
| The number 17 is an example author-chosen id by which the API or other tools |
| can later refer to this specific specialization constant. |
| If it is never changed before final lowering, it will retain the value of |
| 12. |
| It is a compile-time error to use the <strong>constant_id</strong> qualifier on anything |
| but SPIR-V generation of a scalar <strong>bool</strong>, <strong>int</strong>, <strong>uint</strong>, <strong>float</strong>, or |
| <strong>double</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Built-in constants can be declared to be specialization constants. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">31</span>) gl_MaxClipDistances; <span class="comment">// add specialization_id</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The declaration uses just the name of the previously declared built-in |
| variable, with a <strong>constant_id</strong> layout-qualifier declaration. |
| It is a compile-time error to do this after the constant has been used: |
| Constants are strictly either non-specialization constants or specialization |
| constants, not both.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in constant vector <em>gl_WorkGroupSize</em> can be specialized using the |
| <strong>local_size_{xyz}_id</strong> qualifiers, to individually give the components an id. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x_id = <span class="integer">18</span>, local_size_z_id = <span class="integer">19</span>) in;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This leaves <em>gl_WorkGroupSize.y</em> as a non-specialization constant, with |
| <em>gl_WorkGroupSize</em> being a partially specialized vector. |
| Its <em>x</em> and <em>z</em> components can be later specialized, after generating |
| SPIR-V, using the ids 18 and 19. |
| These ids are declared independently from declaring the workgroup size:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">32</span>, local_size_y = <span class="integer">32</span>) in; <span class="comment">// size is (32,32,1)</span> |
| layout(local_size_x_id = <span class="integer">18</span>) in; <span class="comment">// constant_id for x</span> |
| layout(local_size_z_id = <span class="integer">19</span>) in; <span class="comment">// constant_id for z</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Existing rules for declaring <strong>local_size_x</strong>, <strong>local_size_y</strong>, and |
| <strong>local_size_z</strong> are not changed. |
| For the local-size ids, it is a compile-time error to provide different id |
| values for the same local-size id, or to provide them after any use. |
| Otherwise, order, placement, number of statements, and replication do not |
| cause errors.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Two arrays sized with specialization constants are the same type only if |
| sized with the same symbol, and involving no operations. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">51</span>) <span class="directive">const</span> <span class="predefined-type">int</span> aSize = <span class="integer">20</span>; |
| <span class="directive">const</span> <span class="predefined-type">int</span> pad = <span class="integer">2</span>; |
| <span class="directive">const</span> <span class="predefined-type">int</span> total = aSize + pad; <span class="comment">// specialization constant</span> |
| <span class="predefined-type">int</span> a[total], b[total]; <span class="comment">// a and b have the same type</span> |
| <span class="predefined-type">int</span> c[<span class="integer">22</span>]; <span class="comment">// different type than a or b</span> |
| <span class="predefined-type">int</span> d[aSize + pad]; <span class="comment">// different type than a, b, or c</span> |
| <span class="predefined-type">int</span> e[aSize + <span class="integer">2</span>]; <span class="comment">// different type than a, b, c, or d</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Types containing arrays sized with a specialization constant cannot be |
| compared, assigned as aggregates, declared with an initializer, or used as |
| an initializer. |
| They can, however, be passed as arguments to functions having formal |
| parameters of the same type. |
| Only the outer-most dimension of a variable declared as an array of arrays |
| can be a specialization constant, otherwise a compile-time error results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays inside a block may be sized with a specialization constant, but the |
| block will have a static layout. |
| Changing the specialized size will not re-layout the block. |
| In the absence of explicit offsets, the layout will be based on the default |
| size of the array.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="order-of-qualification">4.12. Order and Repetition of Qualification</h3> |
| <div class="paragraph"> |
| <p>When multiple qualifiers are present in a declaration, they may appear in |
| any order, but they must all appear before the type. |
| The <strong>layout</strong> qualifier is the only qualifier that can appear more than once. |
| Further, a declaration can have at most one storage qualifier, at most one |
| auxiliary storage qualifier, and at most one interpolation qualifier. |
| Multiple memory qualifiers can be used. |
| Any violation of these rules will cause a compile-time error.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="empty-declarations">4.13. Empty Declarations</h3> |
| <div class="paragraph"> |
| <p><em>Empty declarations</em> are declarations without a variable name, meaning no |
| object is instantiated by the declaration. |
| Generally, empty declarations are allowed. |
| Some are useful when declaring structures, while many others have no effect. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>; <span class="comment">// No effect</span> |
| <span class="keyword">struct</span> S {<span class="predefined-type">int</span> x;}; <span class="comment">// Defines a struct S</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The combinations of qualifiers that cause compile-time or link-time errors |
| are the same whether or not the declaration is empty, for example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">invariant in <span class="predefined-type">float</span> x; <span class="comment">// Error. An input cannot be invariant.</span> |
| invariant in <span class="predefined-type">float</span>; <span class="comment">// Error even though no variable is declared.</span></code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="operators-and-expressions">5. Operators and Expressions</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="operators">5.1. Operators</h3> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language has the following operators.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Precedence</th> |
| <th class="tableblock halign-left valign-top">Operator Class</th> |
| <th class="tableblock halign-left valign-top">Operators</th> |
| <th class="tableblock halign-left valign-top">Associativity</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">array subscript<br> |
| function call and constructor structure<br> |
| field or method selector, swizzle<br> |
| post fix increment and decrement</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">[ ]<br> |
| ( )<br> |
| .<br> |
| ++ --</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">prefix increment and decrement<br> |
| unary</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">++ --<br> |
| + - ~ !</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><< >></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">< > <= >=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">&</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">12</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">&&</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">13</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">logical exclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">^^</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">14</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">selection</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">? :</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">16</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Assignment<br> |
| arithmetic assignments</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">=<br> |
| += -=<br> |
| *= /=<br> |
| %= <<= >>=<br> |
| &= ^= |=</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">17 (lowest)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">sequence</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">,</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>There is no address-of operator nor a dereference operator. |
| There is no typecast operator; constructors are used instead.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="array-operations">5.2. Array Operations</h3> |
| <div class="paragraph"> |
| <p>These are now described in “<a href="#structure-and-array-operations">Structure and |
| Array Operations</a>”.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="function-calls">5.3. Function Calls</h3> |
| <div class="paragraph"> |
| <p>If a function returns a value, then a call to that function may be used as |
| an expression, whose type will be the type that was used to declare or |
| define the function.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Function definitions and calling conventions are discussed in |
| “<a href="#function-definitions">Function Definitions</a>”.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="constructors">5.4. Constructors</h3> |
| <div class="paragraph"> |
| <p>Constructors use the function call syntax, where the function name is a |
| type, and the call makes an object of that type. |
| Constructors are used the same way in both initializers and expressions. |
| (See “<a href="#shading-language-grammar">Shading Language Grammar</a>” for details.) |
| The parameters are used to initialize the constructed value. |
| Constructors can be used to request a data type conversion to change from |
| one scalar type to another scalar type, or to build larger types out of |
| smaller types, or to reduce a larger type to a smaller type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In general, constructors are not built-in functions with predetermined |
| prototypes. |
| For arrays and structures, there must be exactly one argument in the |
| constructor for each element or member. |
| For the other types, the arguments must provide a sufficient number of |
| components to perform the initialization, and it is an error to |
| include so many arguments that they cannot all be used. |
| Detailed rules follow. |
| The prototypes actually listed below are merely a subset of examples.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="conversion-and-scalar-constructors">5.4.1. Conversion and Scalar Constructors</h4> |
| <div class="paragraph"> |
| <p>Converting between scalar types is done as the following prototypes |
| indicate:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>(uint) <span class="comment">// converts an unsigned integer to a signed integer</span> |
| <span class="predefined-type">int</span>(<span class="predefined-type">bool</span>) <span class="comment">// converts a Boolean value to an int</span> |
| <span class="predefined-type">int</span>(<span class="predefined-type">float</span>) <span class="comment">// converts a float value to an int</span> |
| uint(<span class="predefined-type">int</span>) <span class="comment">// converts a signed integer value to an unsigned integer</span> |
| uint(<span class="predefined-type">bool</span>) <span class="comment">// converts a Boolean value to an unsigned integer</span> |
| uint(<span class="predefined-type">float</span>) <span class="comment">// converts a float value to an unsigned integer</span> |
| <span class="predefined-type">bool</span>(<span class="predefined-type">int</span>) <span class="comment">// converts a signed integer value to a Boolean</span> |
| <span class="predefined-type">bool</span>(uint) <span class="comment">// converts an unsigned integer value to a Boolean value</span> |
| <span class="predefined-type">bool</span>(<span class="predefined-type">float</span>) <span class="comment">// converts a float value to a Boolean</span> |
| <span class="predefined-type">float</span>(<span class="predefined-type">int</span>) <span class="comment">// converts a signed integer value to a float</span> |
| <span class="predefined-type">float</span>(uint) <span class="comment">// converts an unsigned integer value to a float value</span> |
| <span class="predefined-type">float</span>(<span class="predefined-type">bool</span>) <span class="comment">// converts a Boolean value to a float</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When constructors are used to convert a floating-point type to an integer |
| type, the fractional part of the floating-point value is dropped. |
| It is undefined to convert a negative floating-point value to an <strong>uint</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Integer values having more bits of precision than a single-precision |
| floating-point mantissa will lose precision when converted to <strong>float</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a constructor is used to convert any integer or floating-point type to |
| a <strong>bool</strong>, 0 and 0.0 are converted to <strong>false</strong>, and non-zero values are |
| converted to <strong>true</strong>. |
| When a constructor is used to convert a <strong>bool</strong> to any integer or |
| floating-point type, <strong>false</strong> is converted to 0 or 0.0, and <strong>true</strong> is |
| converted to 1 or 1.0.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The constructor <strong>int</strong>(<strong>uint</strong>) preserves the bit pattern in the argument, |
| which will change the argument’s value if its sign bit is set. |
| The constructor <strong>uint</strong>(<strong>int</strong>) preserves the bit pattern in the argument, |
| which will change its value if it is negative.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Identity constructors, like <strong>float</strong>(<strong>float</strong>) are also legal, but of little |
| use.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Scalar constructors with non-scalar parameters can be used to take the first |
| element from a non-scalar. |
| For example, the constructor <strong>float</strong>(<strong>vec3</strong>) will select the first component |
| of the <strong>vec3</strong> parameter.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="vector-and-matrix-constructors">5.4.2. Vector and Matrix Constructors</h4> |
| <div class="paragraph"> |
| <p>Constructors can be used to create vectors or matrices from a set of |
| scalars, vectors, or matrices. |
| This includes the ability to shorten vectors.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If there is a single scalar parameter to a vector constructor, it is used to |
| initialize all components of the constructed vector to that scalar’s value. |
| If there is a single scalar parameter to a matrix constructor, it is used to |
| initialize all the components on the matrix’s diagonal, with the remaining |
| components initialized to 0.0.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a vector is constructed from multiple scalars, one or more vectors, or |
| one or more matrices, or a mixture of these, the vector’s components will be |
| constructed in order from the components of the arguments. |
| The arguments will be consumed left to right, and each argument will have |
| all its components consumed, in order, before any components from the next |
| argument are consumed. |
| Similarly for constructing a matrix from multiple scalars or vectors, or a |
| mixture of these. |
| Matrix components will be constructed and consumed in column major order. |
| In these cases, there must be enough components provided in the arguments to |
| provide an initializer for every component in the constructed value. |
| It is an error to provide extra arguments beyond this last used |
| argument.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a matrix is constructed from a matrix, then each component (column <em>i</em>, |
| row <em>j</em>) in the result that has a corresponding component (column <em>i</em>, row |
| <em>j</em>) in the argument will be initialized from there. |
| All other components will be initialized to the identity matrix. |
| If a matrix argument is given to a matrix constructor, it is |
| an error to have any other arguments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the basic type (<strong>bool</strong>, <strong>int</strong>, |
| or <strong>float</strong>) |
| of a parameter to a |
| constructor does not match the basic type of the object being constructed, |
| the scalar construction rules (above) are used to convert the parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Some useful vector constructors are as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec3(<span class="predefined-type">float</span>) <span class="comment">// initializes each component of the vec3 with the float</span> |
| vec4(ivec4) <span class="comment">// makes a vec4 with component-wise conversion</span> |
| vec4(mat2) <span class="comment">// the vec4 is column 0 followed by column 1</span> |
| vec2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>) <span class="comment">// initializes a vec2 with 2 floats</span> |
| ivec3(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">int</span>) <span class="comment">// initializes an ivec3 with 3 ints</span> |
| bvec4(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>) <span class="comment">// uses 4 Boolean conversions</span> |
| vec2(vec3) <span class="comment">// drops the third component of a vec3</span> |
| vec3(vec4) <span class="comment">// drops the fourth component of a vec4</span> |
| vec3(vec2, <span class="predefined-type">float</span>) <span class="comment">// vec3.x = vec2.x, vec3.y = vec2.y, vec3.z = float</span> |
| vec3(<span class="predefined-type">float</span>, vec2) <span class="comment">// vec3.x = float, vec3.y = vec2.x, vec3.z = vec2.y</span> |
| vec4(vec3, <span class="predefined-type">float</span>) |
| vec4(<span class="predefined-type">float</span>, vec3) |
| vec4(vec2, vec2)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Some examples of these are:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 color = vec4(<span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>); |
| vec4 rgba = vec4(<span class="float">1</span><span class="float">.0</span>); <span class="comment">// sets each component to 1.0</span> |
| vec3 rgb = vec3(color); <span class="comment">// drop the 4th component</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To initialize the diagonal of a matrix with all other elements set to zero:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat2(<span class="predefined-type">float</span>) |
| mat3(<span class="predefined-type">float</span>) |
| mat4(<span class="predefined-type">float</span>)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>That is, <em>result[i][j]</em> is set to the <em>float</em> argument for all \(i |
| = j\) and set to 0 for all \(i \neq j\).</p> |
| </div> |
| <div class="paragraph"> |
| <p>To initialize a matrix by specifying vectors or scalars, the components are |
| assigned to the matrix elements in column-major order.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat2(vec2, vec2); <span class="comment">// one column per argument</span> |
| mat3(vec3, vec3, vec3); <span class="comment">// one column per argument</span> |
| mat4(vec4, vec4, vec4, vec4); <span class="comment">// one column per argument</span> |
| mat3x2(vec2, vec2, vec2); <span class="comment">// one column per argument</span> |
| mat2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// first column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>); <span class="comment">// second column</span> |
| mat3(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// first column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// second column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>); <span class="comment">// third column</span> |
| mat4(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// first column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// second column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="comment">// third column</span> |
| <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>); <span class="comment">// fourth column</span> |
| mat2x3(vec2, <span class="predefined-type">float</span>, <span class="comment">// first column</span> |
| vec2, <span class="predefined-type">float</span>); <span class="comment">// second column</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A wide range of other possibilities exist, to construct a matrix from |
| vectors and scalars, as long as enough components are present to initialize |
| the matrix. |
| To construct a matrix from a matrix:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat3x3(mat4x4); <span class="comment">// takes the upper-left 3x3 of the mat4x4</span> |
| mat2x3(mat4x2); <span class="comment">// takes the upper-left 2x2 of the mat4x4, last row is 0,0</span> |
| mat4x4(mat3x3); <span class="comment">// puts the mat3x3 in the upper-left, sets the lower right</span> |
| <span class="comment">// component to 1, and the rest to 0</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="structure-constructors">5.4.3. Structure Constructors</h4> |
| <div class="paragraph"> |
| <p>Once a structure is defined, and its type is given a name, a constructor is |
| available with the same name to construct instances of that structure. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light { |
| <span class="predefined-type">float</span> intensity; |
| vec3 position; |
| }; |
| |
| light lightVar = light(<span class="float">3</span><span class="float">.0</span>, vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>));</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The arguments to the constructor will be used to set the structure’s |
| members, in order, using one argument per member. |
| Each argument must be the same type as the member it |
| sets.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Structure constructors can be used as initializers or in expressions.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="array-constructors">5.4.4. Array Constructors</h4> |
| <div class="paragraph"> |
| <p>Array types can also be used as constructor names, which can then be used in |
| expressions or initializers. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> <span class="predefined-type">float</span> c[<span class="integer">3</span>] = <span class="predefined-type">float</span>[<span class="integer">3</span>](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>); |
| <span class="directive">const</span> <span class="predefined-type">float</span> d[<span class="integer">3</span>] = <span class="predefined-type">float</span>[](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>); |
| |
| <span class="predefined-type">float</span> g; |
| ... |
| <span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](g, <span class="integer">1</span>, g, <span class="float">2</span><span class="float">.3</span>, g); |
| <span class="predefined-type">float</span> b[<span class="integer">3</span>]; |
| |
| b = <span class="predefined-type">float</span>[<span class="integer">3</span>](g, g + <span class="float">1</span><span class="float">.0</span>, g + <span class="float">2</span><span class="float">.0</span>);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There must be exactly the same number of arguments as the size of the array |
| being constructed. |
| If no size is present in the constructor, then the array is explicitly sized |
| to the number of arguments provided. |
| The arguments are assigned in order, starting at element 0, to the elements |
| of the constructed array. |
| Each argument must be the same type as the element type of the |
| array.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays of arrays are similarly constructed, and the size for any dimension |
| is <strong class="purple">optional</strong></p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 b[<span class="integer">2</span>] = ...; |
| vec4[<span class="integer">3</span>][<span class="integer">2</span>](b, b, b); <span class="comment">// constructor</span> |
| vec4[][<span class="integer">2</span>](b, b, b); <span class="comment">// constructor, valid, size deduced</span> |
| vec4[<span class="integer">3</span>][](b, b, b); <span class="comment">// constructor, valid, size deduced</span> |
| vec4[][](b, b, b); <span class="comment">// constructor, valid, both sizes deduced</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_texture_combined_sampler_constructors">5.4.5. Texture-Combined Sampler Constructors</h4> |
| <div class="paragraph"> |
| <p>Texture-combined sampler constructors are only available when targeting Vulkan.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Texture-combined sampler types, like <strong>sampler2D</strong>, can be declared with an |
| initializer |
| that is a constructor of the same type, and consuming a texture and a |
| <strong>sampler</strong> or <strong>samplerShadow</strong>. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"> layout(...) uniform sampler s; <span class="comment">// handle to filtering information</span> |
| layout(...) uniform texture2D t; <span class="comment">// handle to a texture</span> |
| layout(...) in vec2 tCoord; |
| ... |
| texture(sampler2D(t, s), tCoord);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The result of a texture-combined sampler constructor cannot be assigned to a |
| variable:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"> ... sampler2D sConstruct = sampler2D(t, s); <span class="comment">// ERROR</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Texture-combined sampler constructors can only be consumed by a function parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Texture-combined sampler constructors of arrays are illegal:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"> layout(...) uniform texture2D tArray[<span class="integer">6</span>]; |
| ... |
| ... sampler2D[](tArray, s) ... <span class="comment">// ERROR</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Formally:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>every texture-combined sampler type can be used as a constructor</p> |
| </li> |
| <li> |
| <p>the type of the constructor must match the type of the variable being declared</p> |
| </li> |
| <li> |
| <p>the constructor’s first argument must be a texture type</p> |
| </li> |
| <li> |
| <p>the constructor’s second argument must be a scalar of type <strong>sampler</strong> |
| or <strong>samplerShadow</strong></p> |
| </li> |
| <li> |
| <p>the dimensionality (1D, 2D, 3D, Cube, Rect, Buffer, MS, and Array) |
| of the texture type must match that of the constructed type |
| (that is, the suffixes of the type of the first argument and the |
| type of the constructor will be spelled the same way)</p> |
| </li> |
| <li> |
| <p>there is no control flow construct (e.g., <code>?:</code>) that consumes any sampler type</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note: Shadow mismatches are allowed between constructors and the second argument. |
| Texture-combined non-shadow samplers can be constructed from <strong>samplerShadow</strong> and |
| texture-combined shadow samplers can be constructed from <strong>sampler</strong>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="vector-components">5.5. Vector Components</h3> |
| <div class="paragraph"> |
| <p>The names of the components of a vector |
| are denoted by a single letter. |
| As a notational convenience, several letters are associated with each |
| component based on common usage of position, color or texture coordinate |
| vectors. |
| The individual components can be selected by following the variable name |
| with period (<strong>.</strong>) and then the component name.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The component names supported are:</p> |
| </div> |
| <table class="tableblock frame-all grid-all fit-content"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ x, y, z, w }</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent points or normals</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ r, g, b, a }</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent colors</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ s, t, p, q }</em></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent texture coordinates</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The component names <em>x</em>, <em>r</em>, and <em>s</em> are, for example, synonyms for the |
| same (first) component in a vector.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the third component of the texture coordinate set |
| has been renamed <em>p</em> so as to avoid the confusion with <em>r</em> (for |
| red) in a color.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Accessing components beyond those declared for the type is |
| an error so, for example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec2 pos; |
| pos.x <span class="comment">// is legal</span> |
| pos.z <span class="comment">// is illegal</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The component selection syntax allows multiple components to be selected by |
| appending their names (from the same name set) after the period (<strong>.</strong>).</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 v4; |
| v4.rgba; <span class="comment">// is a vec4 and the same as just using v4,</span> |
| v4.rgb; <span class="comment">// is a vec3,</span> |
| v4.b; <span class="comment">// is a float,</span> |
| v4.xy; <span class="comment">// is a vec2,</span> |
| v4.xgba; <span class="comment">// is illegal - the component names do not come from the same set</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>No more than 4 components can be selected.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 v4; |
| v4.xyzwxy; <span class="comment">// is illegal since it has 6 components</span> |
| (v4.xyzwxy).xy; <span class="comment">// is illegal since the intermediate value has 6</span> |
| components</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The order of the components can be different to swizzle them, or replicated:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>); |
| vec4 swiz = pos.wzyx; <span class="comment">// swiz = (4.0, 3.0, 2.0, 1.0)</span> |
| vec4 dup = pos.xxyy; <span class="comment">// dup = (1.0, 1.0, 2.0, 2.0)</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This notation is more concise than the constructor syntax. |
| To form an r-value, it can be applied to any expression that results in a |
| vector r-value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The component group notation can occur on the left hand side of an |
| expression.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>); |
| pos.xw = vec2(<span class="float">5</span><span class="float">.0</span>, <span class="float">6</span><span class="float">.0</span>); <span class="comment">// pos = (5.0, 2.0, 3.0, 6.0)</span> |
| pos.wx = vec2(<span class="float">7</span><span class="float">.0</span>, <span class="float">8</span><span class="float">.0</span>); <span class="comment">// pos = (8.0, 2.0, 3.0, 7.0)</span> |
| pos.xx = vec2(<span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>); <span class="comment">// illegal - 'x' used twice</span> |
| pos.xy = vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>); <span class="comment">// illegal - mismatch between vec2 and vec3</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To form an l-value, swizzling must further be applied to an l-value and |
| contain no duplicate components. It results in an l-value of scalar or |
| vector type, depending on number of components specified.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Array subscripting syntax can also be applied to vectors (but not to |
| scalars) to provide numeric indexing. |
| So in</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 pos;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><em>pos[2]</em> refers to the third element of <em>pos</em> and is equivalent to <em>pos.z</em>. |
| This allows variable indexing into a vector, as well as a generic way of |
| accessing components. |
| Any integer expression can be used as the subscript. |
| The first component is at index zero. |
| Reading from or writing to a vector using a constant integral expression |
| with a value that is negative or greater than or equal to the size of the |
| vector results in an error. |
| When indexing with non-constant expressions, behavior is undefined if the |
| index is negative, or greater than or equal to the size of the vector.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that scalars are not considered to be single-component vectors and |
| therefore the use of component selection operators on scalars is illegal.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="matrix-components">5.6. Matrix Components</h3> |
| <div class="paragraph"> |
| <p>The components of a matrix can be accessed using array subscripting syntax. |
| Applying a single subscript to a matrix treats the matrix as an array of |
| column vectors, and selects a single column, whose type is a vector of the |
| same size as the (column size of the) matrix. |
| The leftmost column is column 0. |
| A second subscript would then operate on the resulting vector, as defined |
| earlier for vectors. |
| Hence, two subscripts select a column and then a row.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat4 m; |
| m[<span class="integer">1</span>] = vec4(<span class="float">2</span><span class="float">.0</span>); <span class="comment">// sets the second column to all 2.0</span> |
| m[<span class="integer">0</span>][<span class="integer">0</span>] = <span class="float">1</span><span class="float">.0</span>; <span class="comment">// sets the upper left element to 1.0</span> |
| m[<span class="integer">2</span>][<span class="integer">3</span>] = <span class="float">2</span><span class="float">.0</span>; <span class="comment">// sets the 4th element of the third column to 2.0</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Behavior is undefined when accessing a component outside the bounds of a |
| matrix with a non-constant expression. |
| It is an error to access a matrix with a constant expression |
| that is outside the bounds of the matrix.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="structure-and-array-operations">5.7. Structure and Array Operations</h3> |
| <div class="paragraph"> |
| <p>The members of a structure and the <strong>length</strong>() method of an array are |
| selected using the period (<strong>.</strong>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>In total, only the following operators are allowed to operate on arrays and |
| structures as whole entities:</p> |
| </div> |
| <table class="tableblock frame-all grid-all fit-content"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">field selector</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>.</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>==</strong> <strong>!=</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">assignment</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>=</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Ternary operator</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>?:</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Sequence operator</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>,</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">indexing (arrays only)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>[</strong> <strong>]</strong></p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The equality operators and assignment operator are only allowed if the two |
| operands are same size and type. |
| The operands cannot contain any opaque types. |
| Structure types must be of the same declared structure. |
| Both array operands must be |
| compile-time |
| sized. |
| When using the equality operators, two structures are equal if and only if |
| all the members are component-wise equal, and two arrays are equal if and |
| only if all the elements are element-wise equal.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Array elements are accessed using the array subscript operator (<strong>[ ]</strong>). |
| An example of accessing an array element is</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">diffuseColor += lightIntensity[<span class="integer">3</span>] * NdotL;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Array indices start at zero. |
| Array elements are accessed using an expression whose type is <strong>int</strong> or |
| <strong>uint</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Behavior is undefined if a shader subscripts an array with an index less |
| than 0 or greater than or equal to the size the array was declared with.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays can also be accessed with the method operator (<strong>.</strong>) and the <strong>length</strong> |
| method to query the size of the array:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">lightIntensity.length() <span class="comment">// return the size of the array</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="assignments">5.8. Assignments</h3> |
| <div class="paragraph"> |
| <p>Assignments of values to variable names are done with the assignment |
| operator (<strong>=</strong>):</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><em>lvalue-expression</em> = <em>rvalue-expression</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>lvalue-expression</em> evaluates to an l-value. |
| The assignment operator stores the value of <em>rvalue-expression</em> into the |
| l-value and returns an r-value with the type and precision of |
| <em>lvalue-expression</em>. |
| The <em>lvalue-expression</em> and <em>rvalue-expression</em> must have the same |
| type. |
| Any type-conversions must be specified explicitly via constructors. |
| It is an error if the l-value is not writable. |
| Variables that are built-in types, entire structures or arrays, structure |
| members, l-values with the field selector (<strong>.</strong>) applied to select components |
| or swizzles without repeated fields, l-values within parentheses, and |
| l-values dereferenced with the array subscript operator (<strong>[ ]</strong>) are all |
| l-values. |
| Other binary or unary expressions, function names, swizzles with repeated |
| fields, and constants cannot be l-values. |
| The ternary operator (<strong>?:</strong>) is also not allowed as an l-value. |
| Using an incorrect expression as an l-value results in an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Expressions on the left of an assignment are evaluated before expressions on |
| the right of the assignment.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The other assignment operators are</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>add into (<strong>+=</strong>)</p> |
| </li> |
| <li> |
| <p>subtract from (<strong>-=</strong>)</p> |
| </li> |
| <li> |
| <p>multiply into (<strong>*=</strong>)</p> |
| </li> |
| <li> |
| <p>divide into (<strong>/=</strong>)</p> |
| </li> |
| <li> |
| <p>modulus into (<strong>%=</strong>)</p> |
| </li> |
| <li> |
| <p>left shift by (<strong><<=</strong>)</p> |
| </li> |
| <li> |
| <p>right shift by (<strong>>>=</strong>)</p> |
| </li> |
| <li> |
| <p>and into (<strong>&=</strong>)</p> |
| </li> |
| <li> |
| <p>inclusive-or into (<strong>|=</strong>)</p> |
| </li> |
| <li> |
| <p>exclusive-or into (<strong>^=</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>where the general expression</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><em>lvalue</em> <em>op</em>= <em>expression</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>is equivalent to</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><em>lvalue</em> = <em>lvalue</em> <em>op</em> <em>expression</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>lvalue</em> is the value returned by <em>lvalue-expression</em>, <em>op</em> is as |
| described below, and the <em>lvalue-expression</em> and <em>expression</em> must satisfy |
| the semantic requirements of both <em>op</em> and equals (<strong>=</strong>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Reading a variable before writing (or initializing) it is legal, however the |
| value is undefined.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="expressions">5.9. Expressions</h3> |
| <div class="paragraph"> |
| <p>Expressions in the shading language are built from the following:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Constants of type <strong>bool</strong>, all integral types, all floating-point types, |
| all vector types, and all matrix types.</p> |
| </li> |
| <li> |
| <p>Constructors of all types.</p> |
| </li> |
| <li> |
| <p>Variable names of all types.</p> |
| </li> |
| <li> |
| <p>Arrays with the length method applied.</p> |
| </li> |
| <li> |
| <p>Subscripted arrays.</p> |
| </li> |
| <li> |
| <p>Function calls that return values. |
| In some cases, function calls returning <strong>void</strong> are also allowed in |
| expressions as specified below.</p> |
| </li> |
| <li> |
| <p>Component field selectors and array subscript results.</p> |
| </li> |
| <li> |
| <p>Parenthesized expressions. |
| Any expression, including expressions with void type can be |
| parenthesized. |
| Parentheses can be used to group operations. |
| Operations within parentheses are done before operations across |
| parentheses.</p> |
| </li> |
| <li> |
| <p>The arithmetic binary operators add (<strong>+</strong>), subtract (<strong>-</strong>), multiply |
| (<strong>*</strong>), and divide (<strong>/</strong>) operate on integer and floating-point scalars, |
| vectors, and matrices. |
| If the operands are integral types, they must both be signed or both be |
| unsigned. |
| All arithmetic binary operators result in the same fundamental type |
| (signed integer, unsigned integer, or floating-point) as the operands |
| they operate on. |
| The following cases are valid</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The two operands are scalars. |
| In this case the operation is applied, resulting in a scalar.</p> |
| </li> |
| <li> |
| <p>One operand is a scalar, and the other is a vector or matrix. |
| In this case, the scalar operation is applied independently to each |
| component of the vector or matrix, resulting in the same size vector or |
| matrix.</p> |
| </li> |
| <li> |
| <p>The two operands are vectors of the same size. |
| In this case, the operation is done component-wise resulting in the |
| same size vector.</p> |
| </li> |
| <li> |
| <p>The operator is add (<strong>+</strong>), subtract (<strong>-</strong>), or divide (<strong>/</strong>), and the |
| operands are matrices with the same number of rows and the same number |
| of columns. |
| In this case, the operation is done component-wise resulting in the |
| same size matrix.</p> |
| </li> |
| <li> |
| <p>The operator is multiply (<strong>*</strong>), where both operands are matrices or one |
| operand is a vector and the other a matrix. |
| A right vector operand is treated as a column vector and a left vector |
| operand as a row vector. |
| In all these cases, it is required that the number of columns of the |
| left operand is equal to the number of rows of the right operand. |
| Then, the multiply (<strong>*</strong>) operation does a linear algebraic multiply, |
| yielding an object that has the same number of rows as the left operand |
| and the same number of columns as the right operand. |
| “<a href="#vector-and-matrix-operations">Vector and Matrix Operations</a>” |
| explains in more detail how vectors and matrices are operated on.</p> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="paragraph"> |
| <p>All other cases result in an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Use the built-in functions <strong>dot</strong>, <strong>cross</strong>, <strong>matrixCompMult</strong>, and |
| <strong>outerProduct</strong>, to get, respectively, vector dot product, vector cross |
| product, matrix component-wise multiplication, and the matrix product of a |
| column vector times a row vector.</p> |
| </div> |
| </div> |
| </div> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>The operator modulus (<strong>%</strong>) operates on signed or unsigned integers or |
| integer vectors. |
| The operand types must both be signed or both be unsigned. |
| The operands cannot be vectors of differing size; this is |
| an error. |
| If one operand is a scalar and the other vector, then the scalar is |
| applied component-wise to the vector, resulting in the same type as the |
| vector. |
| If both are vectors of the same size, the result is computed |
| component-wise. |
| The resulting value is undefined for any component computed with a |
| second operand that is zero, while results for other components with |
| non-zero second operands remain defined. |
| If both operands are non-negative, then the remainder is non-negative. |
| Results are undefined if one or both operands are negative. |
| The operator modulus (<strong>%</strong>) is not defined for any other data types |
| (non-integer types).</p> |
| </li> |
| <li> |
| <p>The arithmetic unary operators negate (<strong>-</strong>), post- and pre-increment and |
| decrement (<strong>--</strong> and <strong>++</strong>) operate on integer or floating-point values |
| (including vectors and matrices). |
| All unary operators work component-wise on their operands. |
| These result with the same type they operated on. |
| For post- and pre-increment and decrement, the expression must be a writable |
| l-value. |
| Pre-increment and pre-decrement add or subtract 1 or 1.0 to the contents |
| of the expression they operate on, and the value of the pre-increment or |
| pre-decrement expression is the resulting value of that modification. |
| Post-increment and post-decrement expressions add or subtract 1 or 1.0 |
| to the contents of the expression they operate on, but the resulting |
| expression has the expression’s value before the post-increment or |
| post-decrement was executed.</p> |
| </li> |
| <li> |
| <p>The relational operators greater than (<strong>></strong>), less than (<strong><</strong>), greater |
| than or equal (<strong>>=</strong>), and less than or equal (<strong><=</strong>) operate only on |
| scalar integer and scalar floating-point expressions. |
| The result is scalar Boolean. |
| The types of the operands must match. |
| To do component-wise relational comparisons on vectors, use the built-in |
| functions <strong>lessThan</strong>, <strong>lessThanEqual</strong>, <strong>greaterThan</strong>, and |
| <strong>greaterThanEqual.</strong></p> |
| </li> |
| <li> |
| <p>The equality operators <strong>equal</strong> (<strong>==</strong>), and not equal (<strong>!=</strong>) operate on |
| all types except opaque types. |
| They result in a scalar Boolean. |
| The types of the operands must match. |
| For vectors, matrices, structures, and arrays, all components, members, |
| or elements of one operand must equal the corresponding components, |
| members, or elements in the other operand for the operands to be |
| considered equal. |
| To get a vector of component-wise equality results for vectors, use the |
| built-in functions <strong>equal</strong> and <strong>notEqual</strong>.</p> |
| </li> |
| <li> |
| <p>The logical binary operators and (<strong>&&</strong>), or (<strong>||</strong>), and exclusive or |
| (<strong>^^</strong>) operate only on two Boolean expressions and result in a Boolean |
| expression. |
| And (<strong>&&</strong>) will only evaluate the right hand operand if the left hand |
| operand evaluated to <strong>true</strong>. |
| Or (<strong>||</strong>) will only evaluate the right hand operand if the left hand |
| operand evaluated to <strong>false</strong>. |
| Exclusive or (<strong>^^</strong>) will always evaluate both operands.</p> |
| </li> |
| <li> |
| <p>The logical unary operator not (<strong>!</strong>). |
| It operates only on a Boolean expression and results in a Boolean |
| expression. |
| To operate on a vector, use the built-in function <strong>not</strong>.</p> |
| </li> |
| <li> |
| <p>The sequence (<strong>,</strong>) operator that operates on expressions by returning |
| the type and value of the right-most expression in a comma separated |
| list of expressions. |
| All expressions are evaluated, in order, from left to right. |
| The operands to the sequence operator may have <strong>void</strong> type. |
| Opaque types cannot be used with the sequence (,) operator.</p> |
| </li> |
| <li> |
| <p>The ternary selection operator (<strong>?:</strong>). |
| It operates on three expressions (<em>exp1</em> <strong>?</strong> <em>exp2</em> <strong>:</strong> <em>exp3</em>). |
| This operator evaluates the first expression, which must result in a |
| scalar Boolean. |
| If the result is true, it selects to evaluate the second expression, |
| otherwise it selects to evaluate the third expression. |
| Only one of the second and third expressions is evaluated. |
| The second and third expressions cannot be opaque types, |
| or there will be an error. |
| Otherwise, |
| the second and third expressions can be any type, including <strong>void</strong>, as |
| long their types match. |
| This resulting matching type is the type of the entire expression.</p> |
| </li> |
| <li> |
| <p>The one’s complement operator (<strong>~</strong>). |
| The operand must be of type signed or unsigned integer or integer |
| vector, and the result is the one’s complement of its operand; each bit |
| of each component is complemented, including any sign bits.</p> |
| </li> |
| <li> |
| <p>The shift operators (<strong><<</strong>) and (<strong>>></strong>). |
| For both operators, the operands must be signed or unsigned integers or |
| integer vectors. |
| One operand can be signed while the other is unsigned. |
| In all cases, the resulting type will be the same type as the left |
| operand. |
| If the first operand is a scalar, the second operand has to be a scalar |
| as well. |
| If the first operand is a vector, the second operand must be a scalar or |
| a vector with the same size as the first operand, and the result is |
| computed component-wise. |
| The result is undefined if the right operand is negative, or greater |
| than or equal to the number of bits in the left expression’s base type. |
| The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted |
| by E2 bits. |
| The value of E1 >> E2 is E1 right-shifted by E2 bit positions. |
| If E1 is a signed integer, the right-shift will extend the sign bit. |
| If E1 is an unsigned integer, the right-shift will zero-extend.</p> |
| </li> |
| <li> |
| <p>The bitwise operators and (<strong>&</strong>), exclusive-or (<strong>^</strong>), and inclusive-or |
| (<strong>|</strong>). |
| The operands must be of type signed or unsigned integers or integer |
| vectors. |
| The operands cannot be vectors of differing size; this is an error. |
| If one operand is a scalar and the other a vector, the scalar is applied |
| component-wise to the vector, resulting in the same type as the vector. |
| The fundamental types of the operands (signed or unsigned) must match, |
| and will be the resulting fundamental type. |
| For and (<strong>&</strong>), the result is the bitwise-and function of the operands. |
| For exclusive-or (<strong>^</strong>), the result is the bitwise exclusive-or function |
| of the operands. |
| For inclusive-or (<strong>|</strong>), the result is the bitwise inclusive-or function |
| of the operands.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>For a complete specification of the syntax of expressions, see |
| “<a href="#shading-language-grammar">Shading Language Grammar</a>”.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="vector-and-matrix-operations">5.10. Vector and Matrix Operations</h3> |
| <div class="paragraph"> |
| <p>With a few exceptions, operations are component-wise. |
| Usually, when an operator operates on a vector or matrix, it is operating |
| independently on each component of the vector or matrix, in a component-wise |
| fashion. |
| For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u; |
| <span class="predefined-type">float</span> f; |
| v = u + f;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will be equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">v.x = u.x + f; |
| v.y = u.y + f; |
| v.z = u.z + f;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>And</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u, w; |
| w = v + u;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>will be equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">w.x = v.x + u.x; |
| w.y = v.y + u.y; |
| w.z = v.z + u.z;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and likewise for most operators and all integer and floating-point vector |
| and matrix types. |
| The exceptions are matrix multiplied by vector, vector multiplied by matrix, |
| and matrix multiplied by matrix. |
| These do not operate component-wise, but rather perform the correct linear |
| algebraic multiply.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u; |
| mat3 m; |
| u = v * m;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>is equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">u.x = dot(v, m[<span class="integer">0</span>]); <span class="comment">// m[0] is the left column of m</span> |
| u.y = dot(v, m[<span class="integer">1</span>]); <span class="comment">// dot(a,b) is the inner (dot) product of a and b</span> |
| u.z = dot(v, m[<span class="integer">2</span>]);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>And</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">u = m * v;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>is equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">u.x = m[<span class="integer">0</span>].x * v.x + m[<span class="integer">1</span>].x * v.y + m[<span class="integer">2</span>].x * v.z; |
| u.y = m[<span class="integer">0</span>].y * v.x + m[<span class="integer">1</span>].y * v.y + m[<span class="integer">2</span>].y * v.z; |
| u.z = m[<span class="integer">0</span>].z * v.x + m[<span class="integer">1</span>].z * v.y + m[<span class="integer">2</span>].z * v.z;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>And</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">mat3 m, n, r; |
| r = m * n;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>is equivalent to</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">r[<span class="integer">0</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">0</span>].z; |
| r[<span class="integer">1</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">1</span>].z; |
| r[<span class="integer">2</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">2</span>].z; |
| r[<span class="integer">0</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">0</span>].z; |
| r[<span class="integer">1</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">1</span>].z; |
| r[<span class="integer">2</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">2</span>].z; |
| r[<span class="integer">0</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">0</span>].z; |
| r[<span class="integer">1</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">1</span>].z; |
| r[<span class="integer">2</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">2</span>].z;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and similarly for other sizes of vectors and matrices.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="specialization-constant-operations">5.11. Specialization-Constant Operations</h3> |
| <div class="paragraph"> |
| <p>Specialization-constant operations are only available when targeting SPIR-V.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Only some operations discussed in this section may be applied to a |
| specialization constant and still yield a result that is a specialization |
| constant. |
| The operations that do so are listed below. |
| When a specialization constant is operated on with one of these operators |
| and with another constant or specialization constant, the result is |
| implicitly a specialization constant.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>int</strong>(), <strong>uint</strong>(), and <strong>bool</strong>() constructors for type conversions from |
| any of the following types to any of the following types:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>int</strong></p> |
| </li> |
| <li> |
| <p><strong>uint</strong></p> |
| </li> |
| <li> |
| <p><strong>bool</strong></p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>vector versions of the above conversion constructors</p> |
| </li> |
| <li> |
| <p>allowed implicit conversions of the above</p> |
| </li> |
| <li> |
| <p>swizzles (e.g. <code>foo.yx</code>)</p> |
| </li> |
| <li> |
| <p>the following when applied to integer or unsigned integer types:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>unary negative (<strong>-</strong>)</p> |
| </li> |
| <li> |
| <p>binary operations (<strong>+</strong>, <strong>-</strong>, <strong>*</strong>, <strong>/</strong>, <strong>%</strong>)</p> |
| </li> |
| <li> |
| <p>shift (<strong><<</strong>, <strong>>></strong>)</p> |
| </li> |
| <li> |
| <p>bitwise operations (<strong>&</strong>, <strong>|</strong>, <strong>^</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>the following when applied to integer or unsigned integer scalar types:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>comparison (<strong>==</strong>, <strong>!=</strong>, <strong>></strong>, <strong>>=</strong>, <strong><</strong>, <strong>⇐</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>The following when applied to the Boolean scalar type:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>not (<strong>!</strong>)</p> |
| </li> |
| <li> |
| <p>logical operations (<strong>&&</strong>, <strong>||</strong>, <strong>^^</strong>)</p> |
| </li> |
| <li> |
| <p>comparison (<strong>==</strong>, <strong>!=</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>the ternary operator (<strong>?:</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="evaluation-of-expressions">5.12. Evaluation of Expressions</h3> |
| <div class="paragraph"> |
| <p>In general expressions must be evaluated in the order specified by the |
| precedence of operations and may only be regrouped if the result is the same or |
| where the result is undefined. |
| No other transforms may be applied that affect the result of an operation. |
| GLSL ES relaxes these requirements for scalar operations in the following |
| ways:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Addition and multiplication are assumed to be associative.</p> |
| </li> |
| <li> |
| <p>Multiplication is assumed to be distributive over addition. |
| Therefore expressions may be expanded and re-factored.</p> |
| </li> |
| <li> |
| <p>Floating-point division may be replaced by reciprocal and |
| multiplication.</p> |
| </li> |
| <li> |
| <p>Multiplication may be replaced by repeated addition.</p> |
| </li> |
| <li> |
| <p>Within the constraints of invariance (where applicable), the precision |
| used may vary.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>These rules also apply to the built-in functions.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="statements-and-structure">6. Statements and Structure</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The fundamental building blocks of the OpenGL ES Shading Language are:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>statements and declarations</p> |
| </li> |
| <li> |
| <p>function definitions</p> |
| </li> |
| <li> |
| <p>selection (<strong>if</strong>-<strong>else</strong> and <strong>switch</strong>-<strong>case</strong>-<strong>default</strong>)</p> |
| </li> |
| <li> |
| <p>iteration (<strong>for</strong>, <strong>while</strong>, and <strong>do</strong>-<strong>while</strong>)</p> |
| </li> |
| <li> |
| <p>jumps (<strong>discard</strong>, <strong>return</strong>, <strong>break</strong>, and <strong>continue</strong>)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The overall structure of a shader is as follows</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>translation-unit</em> : </dt> |
| <dd> |
| <p><em>global-declaration</em><br> |
| <em>translation-unit</em> <em>global-declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>global-declaration</em> : </dt> |
| <dd> |
| <p><em>function-definition</em><br> |
| <em>declaration</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>That is, a shader is a sequence of declarations and function bodies. |
| Function bodies are defined as</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>function-definition</em> : </dt> |
| <dd> |
| <p><em>function-prototype</em> <strong>{</strong> <em>statement-list</em> <strong>}</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>statement-list</em> : </dt> |
| <dd> |
| <p><em>statement</em><br> |
| <em>statement-list</em> <em>statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>statement</em> : </dt> |
| <dd> |
| <p><em>compound-statement</em><br> |
| <em>simple-statement</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Curly braces are used to group sequences of statements into compound |
| statements.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>compound-statement</em> : </dt> |
| <dd> |
| <p><strong>{</strong> <em>statement-list</em> <strong>}</strong></p> |
| </dd> |
| <dt class="hdlist1"><em>simple-statement</em> : </dt> |
| <dd> |
| <p><em>declaration-statement</em><br> |
| <em>expression-statement</em><br> |
| <em>selection-statement</em><br> |
| <em>iteration-statement</em><br> |
| <em>jump-statement</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Simple declaration, expression, and jump statements end in a semi-colon.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This above is slightly simplified, and the complete grammar specified in |
| “<a href="#shading-language-grammar">Shading Language Grammar</a>” should be used as |
| the definitive specification.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Declarations and expressions have already been discussed.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="function-definitions">6.1. Function Definitions</h3> |
| <div class="paragraph"> |
| <p>As indicated by the grammar above, a valid shader is a sequence of global |
| declarations and function definitions. |
| A function is declared as the following example shows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// prototype</span> |
| returnType functionName (type0 arg0, type1 arg1, ..., typen argn);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and a function is defined like</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// definition</span> |
| returnType functionName (type0 arg0, type1 arg1, ..., typen argn) |
| { |
| <span class="comment">// do some computation</span> |
| <span class="keyword">return</span> returnValue; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>returnType</em> must be present and cannot be void, or:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> functionName (type0 arg0, type1 arg1, ..., typen argn) |
| { |
| <span class="comment">// do some computation</span> |
| <span class="keyword">return</span>; <span class="comment">// optional</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Each of the <em>typeN</em> must include a type and can optionally include a |
| parameter qualifier and/or <strong>const</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A function is called by using its name followed by a list of arguments in |
| parentheses.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays are allowed as arguments and as the return type. |
| In both cases, the array must be |
| compile-time |
| sized. |
| An array is passed or returned by using just its name, without brackets, and |
| the size of the array must match the size specified in the function’s |
| declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Structures are also allowed as argument types. |
| The return type can also be a structure.</p> |
| </div> |
| <div class="paragraph"> |
| <p>See “<a href="#shading-language-grammar">Shading Language Grammar</a>” for the |
| definitive reference on the syntax to declare and define functions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All functions must be either declared with a prototype or defined with a |
| body before they are called. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> myfunc (<span class="predefined-type">float</span> f, <span class="comment">// f is an input parameter</span> |
| out <span class="predefined-type">float</span> g); <span class="comment">// g is an output parameter</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Functions that return no value must be declared as <strong>void</strong>. |
| A <strong>void</strong> function can only use <strong>return</strong> without a return argument, even if |
| the return argument has <strong>void</strong> type. |
| Return statements only accept values:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> func1() { } |
| <span class="directive">void</span> func2() { <span class="keyword">return</span> func1(); } <span class="comment">// illegal return statement</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Only a precision qualifier is allowed on the return type of a function. |
| Formal parameters can have parameter, precision, and memory qualifiers, but |
| no other qualifiers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Functions that accept no input arguments need not use <strong>void</strong> in the argument |
| list because prototypes (or definitions) are required and therefore there is |
| no ambiguity when an empty argument list “( )” is declared. |
| The idiom “(<strong>void</strong>)” as a parameter list is provided for convenience.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Function names can be overloaded. |
| The same function name can be used for multiple functions, as long as the |
| parameter types differ. |
| If a function name is declared twice with the same parameter types, then the |
| return types and all qualifiers must also match, and it is the same function |
| being declared. |
| When function calls are resolved, an exact type match for all the arguments |
| is required.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example,</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4 f(in vec4 x, out vec4 y); |
| vec4 f(in vec4 x, out uvec4 y); <span class="comment">// allowed, different argument type</span> |
| <span class="predefined-type">int</span> f(in vec4 x, out vec4 y); <span class="comment">// error, only return type differs</span> |
| vec4 f(in vec4 x, in vec4 y); <span class="comment">// error, only qualifier differs</span> |
| vec4 f(<span class="directive">const</span> in vec4 x, out vec4 y); <span class="comment">// error, only qualifier differs</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Calling the first two functions above with the following argument types |
| yields</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">f(vec4, vec4) <span class="comment">// exact match of vec4 f(in vec4 x, out vec4 y)</span> |
| f(vec4, uvec4) <span class="comment">// exact match of vec4 f(in vec4 x, out uvec4 y)</span> |
| f(ivec4, vec4) <span class="comment">// error, no exact match.</span> |
| f(ivec4, uvec4) <span class="comment">// error, no exact match.</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>User-defined functions can have multiple declarations, but only one |
| definition.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A shader cannot redefine or overload built-in functions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The function <em>main</em> is used as the entry point to a shader executable. |
| All shaders must define a function named <em>main</em>. |
| This function takes no arguments, returns no value, and must be declared as |
| type <strong>void</strong>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> main() |
| { |
| ... |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The function <em>main</em> can contain uses of <strong>return</strong>. |
| See “<a href="#jumps">Jumps</a>” for more details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is a compile-time or link-time error to declare or define a function |
| <strong>main</strong> with any other parameters or return type.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="function-calling-conventions">6.1.1. Function Calling Conventions</h4> |
| <div class="paragraph"> |
| <p>Functions are called by value-return. |
| This means input arguments are copied into the function at call time, and |
| output arguments are copied back to the caller before function exit. |
| Because the function works with local copies of parameters, there are no |
| issues regarding aliasing of variables within a function. |
| To control what parameters are copied in and/or out through a function |
| definition or declaration:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The keyword <strong>in</strong> is used as a qualifier to denote a parameter is to be |
| copied in, but not copied out.</p> |
| </li> |
| <li> |
| <p>The keyword <strong>out</strong> is used as a qualifier to denote a parameter is to be |
| copied out, but not copied in. |
| This should be used whenever possible to avoid unnecessarily copying |
| parameters in.</p> |
| </li> |
| <li> |
| <p>The keyword <strong>inout</strong> is used as a qualifier to denote the parameter is to |
| be both copied in and copied out. |
| It means the same thing as specifying both <strong>in</strong> and <strong>out</strong>.</p> |
| </li> |
| <li> |
| <p>A function parameter declared with no such qualifier means the same |
| thing as specifying <strong>in</strong>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>All arguments are evaluated at call time, exactly once, in order, from left |
| to right. |
| Evaluation of an <strong>in</strong> parameter results in a value that is copied to the |
| formal parameter. |
| Evaluation of an <strong>out</strong> parameter results in an l-value that is used to copy |
| out a value when the function returns. |
| Evaluation of an <strong>inout</strong> parameter results in both a value and an l-value; |
| the value is copied to the formal parameter at call time and the l-value is |
| used to copy out a value when the function returns.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The order in which output parameters are copied back to the caller is |
| undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In a function, writing to an input-only parameter is allowed. |
| Only the function’s copy is modified. |
| This can be prevented by declaring a parameter with the <strong>const</strong> qualifier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When calling a function, expressions that do not evaluate to l-values cannot |
| be passed to parameters declared as <strong>out</strong> or <strong>inout</strong>, or an error |
| results.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Only precision qualifiers are allowed on the return type of a function.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The syntax for function prototypes can be informally expressed as:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>function_prototype</em> : </dt> |
| <dd> |
| <p>[ <em>type_qualifier</em> ] <em>type_specifier</em> <em>IDENTIFIER</em> <em>LEFT_PAREN</em> |
| <em>parameter_declaration</em> , <em>parameter_declaration</em> , …​ |
| , <em>RIGHT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>parameter_declaration</em> : </dt> |
| <dd> |
| <p>[ <em>type_qualifier</em> ] <em>type_specifier</em> [ <em>IDENTIFIER</em> [ <em>array_specifier</em> |
| ] ]</p> |
| </dd> |
| <dt class="hdlist1"><em>type_qualifier</em> : </dt> |
| <dd> |
| <p><em>single_type_qualifier</em> , <em>single_type_qualifier</em> , …​</p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The qualifiers allowed on formal parameters are:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p><em>empty</em><br> |
| <strong>const</strong><br> |
| <strong>in</strong><br> |
| <strong>out</strong><br> |
| <strong>inout</strong><br> |
| <strong>precise</strong><br> |
| <em>memory-qualifier</em><br> |
| <em>precision-qualifier</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>const</strong> qualifier cannot be used with <strong>out</strong> or <strong>inout</strong>, or |
| an error results. |
| The above is used both for function declarations (i.e., prototypes) and for |
| function definitions. |
| Hence, function definitions can have unnamed arguments.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Static, and hence dynamic recursion, are not allowed. |
| Static recursion is present if the static function-call graph of a program |
| contains cycles. |
| Dynamic recursion occurs if at any time control flow has entered but not |
| exited a single function more than once.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="selection">6.2. Selection</h3> |
| <div class="paragraph"> |
| <p>Conditional control flow in the shading language is done by either <strong>if</strong>, |
| <strong>if</strong>-<strong>else</strong>, or <strong>switch</strong> statements:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>selection-statement</em> : </dt> |
| <dd> |
| <p><strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em><br> |
| <strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em> <strong>else</strong> <em>statement</em><br> |
| <strong>switch</strong> <strong>(</strong> <em>init-expression</em> <strong>)</strong> <strong>{</strong> <em>switch-statement-list<sub>opt</sub></em> <strong>}</strong></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where <em>switch-statement-list</em> is a nested scope containing a list of zero or |
| more <em>switch-statement</em> and other statements defined by the language, where |
| <em>switch-statement</em> adds some forms of labels. |
| That is</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>switch-statement-list</em> : </dt> |
| <dd> |
| <p><em>switch-statement</em><br> |
| <em>switch-statement-list</em> <em>switch-statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>switch-statement</em> : </dt> |
| <dd> |
| <p><strong>case</strong> <em>constant-expression</em> <strong>:</strong><br> |
| <strong>default</strong> <strong>:</strong> <em>statement</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note the above grammar’s purpose is to aid discussion in this section; the |
| normative grammar is in “<a href="#shading-language-grammar">Shading Language |
| Grammar</a>”.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If an <strong>if</strong>-expression evaluates to <strong>true</strong>, then the first <em>statement</em> is |
| executed. |
| If it evaluates to <strong>false</strong> and there is an <strong>else</strong> part then the second |
| <em>statement</em> is executed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any expression whose type evaluates to a Boolean can be used as the |
| conditional expression <em>bool-expression</em>. |
| Vector types are not accepted as the expression to <strong>if</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Conditionals can be nested.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The type of <em>init-expression</em> in a <strong>switch</strong> statement must be a scalar |
| integer. |
| The type of <em>init-expression</em> must match the type of the <strong>case</strong> labels |
| within each <strong>switch</strong> statement. |
| Either signed integers or unsigned integers are allowed but there is no |
| implicit type conversion between the two. |
| If a <strong>case</strong> label has a <em>constant-expression</em> of equal value to |
| <em>init-expression</em>, execution will continue after that label. |
| Otherwise, if there is a <strong>default</strong> label, execution will continue after that |
| label. |
| Otherwise, execution skips the rest of the switch statement. |
| It is an error to have more than one <strong>default</strong> or a replicated |
| <em>constant-expression</em>. |
| A <strong>break</strong> statement not nested in a loop or other switch statement (either |
| not nested or nested only in <strong>if</strong> or <strong>if</strong>-<strong>else</strong> statements) will also skip |
| the rest of the switch statement. |
| Fall through labels are allowed, but it is an error to have no |
| statement between a label and the end of the switch statement. |
| No statements are allowed in a switch statement before the first <strong>case</strong> |
| statement.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>case</strong> and <strong>default</strong> labels can only appear within a <strong>switch</strong> statement. |
| No <strong>case</strong> or <strong>default</strong> labels can be nested inside other statements or |
| compound statements within their corresponding <strong>switch</strong>.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="iteration">6.3. Iteration</h3> |
| <div class="paragraph"> |
| <p>For, while, and do loops are allowed as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> (init-expression; condition-expression; loop-expression) |
| sub-statement |
| <span class="keyword">while</span> (condition-expression) |
| sub-statement |
| <span class="keyword">do</span> |
| statement |
| <span class="keyword">while</span> (condition-expression)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>See “<a href="#shading-language-grammar">Shading Language Grammar</a>” for the |
| definitive specification of loops.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>for</strong> loop first evaluates the <em>init-expression</em>, then the |
| <em>condition-expression</em>. |
| If the <em>condition-expression</em> evaluates to <strong>true</strong>, then the body of the loop |
| is executed. |
| After the body is executed, a <strong>for</strong> loop will then evaluate the |
| <em>loop-expression</em>, and then loop back to evaluate the |
| <em>condition-expression</em>, repeating until the <em>condition-expression</em> evaluates |
| to <strong>false</strong>. |
| The loop is then exited, skipping its body and skipping its |
| <em>loop-expression</em>. |
| Variables modified by the <em>loop-expression</em> maintain their value after the |
| loop is exited, provided they are still in scope. |
| Variables declared in <em>init-expression</em> or <em>condition-expression</em> are only |
| in scope until the end of the sub-statement of the <strong>for</strong> loop.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>while</strong> loop first evaluates the <em>condition-expression</em>. |
| If <strong>true</strong>, then the body is executed. |
| This is then repeated, until the <em>condition-expression</em> evaluates to |
| <strong>false</strong>, exiting the loop and skipping its body. |
| Variables declared in the <em>condition-expression</em> are only in scope until the |
| end of the sub-statement of the <strong>while</strong> loop.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For both <strong>for</strong> and <strong>while</strong> loops, the sub-statement does not introduce a new |
| scope for variable names, so the following has a redeclaration error:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> (<span class="predefined-type">int</span> i = <span class="integer">0</span>; i < <span class="integer">10</span>; i++) + |
| { |
| <span class="predefined-type">int</span> i; <span class="comment">// redeclaration error +</span> |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>do</strong>-<strong>while</strong> loop first executes the body, then executes the |
| <em>condition-expression</em>. |
| This is repeated until <em>condition-expression</em> evaluates to <strong>false</strong>, and then |
| the loop is exited.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Expressions for <em>condition-expression</em> must evaluate to a Boolean.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Both the <em>condition-expression</em> and the <em>init-expression</em> can declare and |
| initialize a variable, except in the <strong>do</strong>-<strong>while</strong> loop, which cannot declare |
| a variable in its <em>condition-expression</em>. |
| The variable’s scope lasts only until the end of the sub-statement that |
| forms the body of the loop.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Loops can be nested.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Non-terminating loops are allowed. |
| The consequences of very long or non-terminating loops are platform |
| dependent.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="jumps">6.4. Jumps</h3> |
| <div class="paragraph"> |
| <p>These are the jumps:</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>jump_statement</em> : </dt> |
| <dd> |
| <p><strong>continue</strong> <strong>;</strong><br> |
| <strong>break</strong> <strong>;</strong><br> |
| <strong>return</strong> <strong>;</strong><br> |
| <strong>return</strong> <em>expression</em> <strong>;</strong><br> |
| <strong>discard</strong> <strong>;</strong> // in the fragment shader language only</p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There is no “goto” or other non-structured flow of control.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>continue</strong> jump is used only in loops. |
| It skips the remainder of the body of the inner-most loop of which it is |
| inside. |
| For <strong>while</strong> and <strong>do</strong>-<strong>while</strong> loops, this jump is to the next evaluation of |
| the loop <em>condition-expression</em> from which the loop continues as previously |
| defined. |
| For <strong>for</strong> loops, the jump is to the <em>loop-expression</em>, followed by the |
| <em>condition-expression</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>break</strong> jump can also be used only in loops and <strong>switch</strong> statements. |
| It is simply an immediate exit of the inner-most loop or <strong>switch</strong> statements |
| containing the <strong>break</strong>. |
| No further execution of <em>condition-expression</em>, <em>loop-expression</em>, or |
| <em>switch-statement</em> is done.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>discard</strong> keyword is only allowed within fragment shaders. |
| It can be used within a fragment shader to abandon the operation on the |
| current fragment. |
| This keyword causes the fragment to be discarded and no updates to any |
| buffers will occur. |
| Any prior writes to other buffers such as shader storage buffers are |
| unaffected. |
| Control flow exits the shader, and subsequent implicit or explicit |
| derivatives are undefined when this control flow is non-uniform (meaning |
| different fragments within the primitive take different control paths). |
| It would typically be used within a conditional statement, for example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">if</span> (intensity < <span class="float">0</span><span class="float">.0</span>) |
| discard;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A fragment shader may test a fragment’s alpha value and discard the fragment |
| based on that test. |
| However, it should be noted that coverage testing occurs after the fragment |
| shader runs, and the coverage test can change the alpha value.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>return</strong> jump causes immediate exit of the current function. |
| If it has <em>expression</em> then that is the return value for the function.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The function <em>main</em> can use <strong>return</strong>. |
| This simply causes <em>main</em> to exit in the same way as when the end of the |
| function had been reached. |
| It does not imply a use of <strong>discard</strong> in a fragment shader. |
| Using <strong>return</strong> in <em>main</em> before defining outputs will have the same behavior |
| as reaching the end of <em>main</em> before defining outputs.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="built-in-variables">7. Built-In Variables</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="built-in-language-variables">7.1. Built-In Language Variables</h3> |
| <div class="paragraph"> |
| <p>Some operations occur outside shader functionality and need to provide |
| values to or receive values from shader executables. |
| Shaders communicate with fixed-function pipeline stages, and |
| optionally with other shader executables, through the use of built-in input |
| and output variables.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="vertex-shader-special-variables">7.1.1. Vertex Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>The built-in vertex shader variables are intrinsically declared as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in highp <span class="predefined-type">int</span> gl_VertexID; <span class="comment">// only present when not targeting Vulkan</span> |
| in highp <span class="predefined-type">int</span> gl_InstanceID; <span class="comment">// only present when not targeting Vulkan</span> |
| in highp <span class="predefined-type">int</span> gl_VertexIndex; <span class="comment">// only present when targeting Vulkan</span> |
| in highp <span class="predefined-type">int</span> gl_InstanceIndex; <span class="comment">// only present when targeting Vulkan</span> |
| |
| out gl_PerVertex { |
| out highp vec4 gl_Position; |
| out highp <span class="predefined-type">float</span> gl_PointSize; |
| };</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_Position</em> is intended for writing the homogeneous vertex |
| position. |
| It can be written at any time during shader execution. |
| This value will be used by primitive assembly, clipping, culling, and other |
| fixed functionality operations, if present, that operate on primitives after |
| vertex processing has occurred. |
| Its value is undefined after the vertex processing stage if the vertex |
| shader executable does not write <em>gl_Position</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_PointSize</em> is intended for a shader to write the size of |
| the point to be rasterized. |
| It is measured in pixels. |
| If <em>gl_PointSize</em> is not written to, its value is undefined in subsequent |
| pipe stages.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_VertexID</em> is a vertex shader input variable that holds an |
| integer index for the vertex, as defined under “Shader Inputs” in section |
| 11.1.3.9 “Shader Inputs” of the <a href="#references">OpenGL ES Specification</a>. |
| It is only present when not targeting Vulkan. |
| Even when present, the value of <em>gl_VertexID</em> is not always defined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_InstanceID</em> is a vertex shader input variable that holds |
| the instance number of the current primitive in an instanced draw call (see |
| “Shader Inputs” in section 11.1.3.9 “Shader Inputs” of the |
| <a href="#references">OpenGL ES Specification</a>). |
| It is only present when not targeting Vulkan. |
| If the current primitive does not come from an instanced draw call, the |
| value of <em>gl_InstanceID</em> is zero.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_VertexIndex</em> is a vertex language input variable that |
| holds an integer index for the vertex, relative to a base. |
| It is only present when targeting Vulkan. |
| Even when present, the value of <em>gl_VertexIndex</em> is not always defined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_InstanceIndex</em> is a vertex language input variable that |
| holds the instance number of the current primitive in an instanced draw |
| call, relative to a base. |
| It is only present when targeting Vulkan. |
| If the current primitive does not come from an instanced draw call, |
| the value of gl_InstanceIndex is zero.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="tessellation-control-shader-special-variables">7.1.2. Tessellation Control Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>In the tessellation control shader, built-in variables are intrinsically |
| declared as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex { |
| highp vec4 gl_Position; |
| } gl_in[gl_MaxPatchVertices]; |
| |
| in highp <span class="predefined-type">int</span> gl_PatchVerticesIn; |
| in highp <span class="predefined-type">int</span> gl_PrimitiveID; |
| in highp <span class="predefined-type">int</span> gl_InvocationID; |
| |
| out gl_PerVertex { |
| highp vec4 gl_Position; |
| } gl_out[]; |
| |
| patch out highp <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>]; |
| patch out highp <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>]; |
| patch out highp vec4 gl_BoundingBox[<span class="integer">2</span>];</code></pre> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-control-input-variables">Tessellation Control Input Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> contains the output written in the previous shader stage to |
| <em>gl_Position</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_PatchVerticesIn</em> contains the number of vertices in the input patch |
| being processed by the shader. |
| A single shader can read patches of differing sizes, so the value of |
| <em>gl_PatchVerticesIn</em> may differ between patches.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_PrimitiveID</em> contains the number of primitives processed by the shader |
| since the current set of rendering primitives was started.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_InvocationID</em> contains the number of the output patch vertex assigned to |
| the tessellation control shader invocation. |
| It is assigned integer values in the range [0, N-1], where N is the number |
| of output patch vertices per primitive.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-control-output-variables">Tessellation Control Output Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> is used in the same fashion as the corresponding output |
| variable in the vertex shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The values written to <em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are |
| assigned to the corresponding outer and inner tessellation levels of the |
| output patch. |
| They are used by the tessellation primitive generator to control primitive |
| tessellation and may be read by tessellation evaluation shaders.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The values written to <em>gl_BoundingBox</em> specify the minimum and maximum |
| clip-space extents of a bounding box containing all primitives generated |
| from the patch by the primitive generator, geometry shader, and clipping. |
| Fragments may or may not be generated for portions of these primitives |
| that extend outside the window-coordinate projection of this bounding |
| box.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="tessellation-evaluation-shader-special-variables">7.1.3. Tessellation Evaluation Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>In the tessellation evaluation shader, built-in variables are intrinsically |
| declared as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex { |
| highp vec4 gl_Position; |
| } gl_in[gl_MaxPatchVertices]; |
| |
| in highp <span class="predefined-type">int</span> gl_PatchVerticesIn; |
| in highp <span class="predefined-type">int</span> gl_PrimitiveID; |
| in highp vec3 gl_TessCoord; |
| patch in highp <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>]; |
| patch in highp <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>]; |
| |
| out gl_PerVertex { |
| highp vec4 gl_Position; |
| };</code></pre> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-evaluation-input-variables">Tessellation Evaluation Input Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> contains the output written in the previous shader stage to |
| <em>gl_Position</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_PatchVerticesIn</em> and <em>gl_PrimitiveID</em> are defined in the same fashion as |
| the corresponding input variables in the tessellation control shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_TessCoord</em> specifies a three-component <em>(u,v,w)</em> vector identifying the |
| position of the vertex being processed by the shader relative to the |
| primitive being tessellated. |
| Its values will obey the properties</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">gl_TessCoord.x == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.x) <span class="comment">// two operations performed</span> |
| gl_TessCoord.y == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.y) <span class="comment">// two operations performed</span> |
| gl_TessCoord.z == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.z) <span class="comment">// two operations performed</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>to aid in replicating subdivision computations.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are filled with the |
| corresponding outputs written by the active tessellation control shader.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="tessellation-evaluation-output-variables">Tessellation Evaluation Output Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> is used in the same fashion as the corresponding output |
| variable in the vertex shader.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="geometry-shader-special-variables">7.1.4. Geometry Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>In the geometry shader, built-in variables are intrinsically declared as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex { |
| highp vec4 gl_Position; |
| } gl_in[]; |
| |
| in highp <span class="predefined-type">int</span> gl_PrimitiveIDIn; |
| in highp <span class="predefined-type">int</span> gl_InvocationID; |
| |
| out gl_PerVertex { |
| highp vec4 gl_Position; |
| }; |
| |
| out highp <span class="predefined-type">int</span> gl_PrimitiveID; |
| out highp <span class="predefined-type">int</span> gl_Layer;</code></pre> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="geometry-shader-input-variables">Geometry Shader Input Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> contains the output written in the previous shader stage to |
| <em>gl_Position</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_PrimitiveIDIn</em> contains the number of primitives processed by the shader |
| since the current set of rendering primitives was started.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_InvocationID</em> contains the invocation number assigned to the geometry |
| shader invocation. |
| It is assigned integer values in the range [0, N-1], where N is the number |
| of geometry shader invocations per primitive.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="geometry-shader-output-variables">Geometry Shader Output Variables</h5> |
| <div class="paragraph"> |
| <p><em>gl_Position</em> is used in the same fashion as the corresponding output |
| variable in the vertex shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_PrimitiveID</em> is filled with a single integer that serves as a primitive |
| identifier to the fragment shader. |
| This is then available to fragment shaders, which will select the written |
| primitive ID from the provoking vertex of the primitive being shaded. |
| If a fragment shader using <em>gl_PrimitiveID</em> is active and a geometry shader |
| is also active, the geometry shader must write to <em>gl_PrimitiveID</em> or the |
| fragment shader input <em>gl_PrimitiveID</em> is undefined. |
| See section 11.3.4.4 “Geometry Shader Outputs” of the |
| <a href="#references">OpenGL ES Specification</a> for more information.</p> |
| </div> |
| <div class="paragraph"> |
| <p><em>gl_Layer</em> is used to select a specific layer (or face and layer of a cube |
| map) of a multi-layer framebuffer attachment. |
| The actual layer used will come from one of the vertices in the primitive |
| being shaded. |
| Which vertex the layer comes from is determined as discussed in section |
| 11.3.4.4 of the <a href="#references">OpenGL ES Specification</a> |
| but may be undefined, so it is best to write the same layer value for all |
| vertices of a primitive. |
| If a shader statically assigns a value to <em>gl_Layer</em>, layered rendering mode |
| is enabled. |
| See section 11.3.4.4 “Geometry Shader Outputs” and section 9.8 “Layered |
| Framebuffers” of the <a href="#references">OpenGL ES Specification</a> for more information. |
| If a shader statically assigns a value to <em>gl_Layer</em>, and there is an |
| execution path through the shader that does not set <em>gl_Layer</em>, then the |
| value of <em>gl_Layer</em> is undefined for executions of the shader that take that |
| path.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The output variable <em>gl_Layer</em> takes on a special value when used with an |
| array of cube map textures. |
| Instead of only referring to the layer, it is used to select a cube map face |
| and a layer. |
| Setting <em>gl_Layer</em> to the value <em>layer*6+face</em> will render to face <em>face</em> of |
| the cube defined in layer <em>layer</em>. |
| The face values are defined in table 8.25 of the <a href="#references">OpenGL ES Specification</a>, |
| but repeated below for clarity.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Face Value</th> |
| <th class="tableblock halign-left valign-top">Resulting Target</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_X</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_X</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Y</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Y</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Z</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Z</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>For example, to render to the positive <em>y</em> cube map face located in the 5th |
| layer of the cube map array, <em>gl_Layer</em> should be set to <em>5 * 6 + 2</em>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="fragment-shader-special-variables">7.1.5. Fragment Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>The built-in special variables that are accessible from a fragment shader |
| are intrinsically declared as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">in highp vec4 gl_FragCoord; |
| in <span class="predefined-type">bool</span> gl_FrontFacing; |
| out highp <span class="predefined-type">float</span> gl_FragDepth; |
| in mediump vec2 gl_PointCoord; |
| in <span class="predefined-type">bool</span> gl_HelperInvocation; |
| in highp <span class="predefined-type">int</span> gl_PrimitiveID; |
| in highp <span class="predefined-type">int</span> gl_Layer; |
| in lowp <span class="predefined-type">int</span> gl_SampleID; |
| in mediump vec2 gl_SamplePosition; |
| in highp <span class="predefined-type">int</span> gl_SampleMaskIn[(gl_MaxSamples+<span class="integer">31</span>)/<span class="integer">32</span>]; |
| out highp <span class="predefined-type">int</span> gl_SampleMask[(gl_MaxSamples+<span class="integer">31</span>)/<span class="integer">32</span>];</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The output of the fragment shader executable is processed by the fixed |
| function operations at the back end of the API pipeline.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The fixed functionality computed depth for a fragment may be obtained by |
| reading <em>gl_FragCoord.z</em>, described below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Writing to <em>gl_FragDepth</em> will establish the depth value for the fragment |
| being processed. |
| If depth buffering is enabled, and no shader writes <em>gl_FragDepth</em>, then the |
| fixed function value for depth will be used as the fragment’s depth value. |
| If a shader statically assigns a value to <em>gl_FragDepth</em>, and there is an |
| execution path through the shader that does not set <em>gl_FragDepth</em>, then the |
| value of the fragment’s depth may be undefined for executions of the shader |
| that take that path. |
| That is, if the set of linked fragment shaders statically contain a write to |
| <em>gl_FragDepth</em>, then it is responsible for always writing it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a shader executes the <strong>discard</strong> keyword, the fragment is discarded, and |
| the values of any user-defined fragment outputs, <em>gl_FragDepth</em>, and |
| <em>gl_SampleMask</em> become irrelevant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The variable <em>gl_FragCoord</em> is available as an input variable from within |
| fragment shaders and it holds the window relative coordinates (<em>x</em>, <em>y</em>, |
| <em>z</em>, <em>1/w</em>) values for the fragment. |
| If multi-sampling, this value can be for any location within the pixel, or |
| one of the fragment samples. |
| The use of <strong>centroid</strong> does not further restrict this value to be inside the |
| current primitive. |
| This value is the result of the fixed functionality that interpolates |
| primitives after vertex processing to generate fragments. |
| The <em>z</em> component is the depth value that would be used for the fragment’s |
| depth if no shader contained any writes to <em>gl_FragDepth</em>. |
| This is useful for invariance if a shader conditionally computes |
| <em>gl_FragDepth</em> but otherwise wants the fixed functionality fragment depth.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shaders have access to the input built-in variable |
| <em>gl_FrontFacing</em>, whose value is <strong>true</strong> if the fragment belongs to a |
| front-facing primitive. |
| One use of this is to emulate two-sided lighting by selecting one of two |
| colors calculated by a vertex or geometry shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The values in <em>gl_PointCoord</em> are two-dimensional coordinates indicating |
| where within a point primitive the current fragment is located, when point |
| sprites are enabled. |
| They range from 0.0 to 1.0 across the point. |
| If the current primitive is not a point, or if point sprites are not |
| enabled, then the values read from <em>gl_PointCoord</em> are undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For both the input array <em>gl_SampleMaskIn[]</em> and the output array |
| <em>gl_SampleMask[]</em>, bit <em>B</em> of mask <em>M</em> (<em>gl_SampleMaskIn[M]</em> or |
| <em>gl_SampleMask[M]</em>) corresponds to sample <em>32*M+B</em>. |
| These arrays have <strong>ceil</strong>(<em>s</em>/32) elements, where <em>s</em> is the maximum number |
| of color samples supported by the implementation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The input variable <em>gl_SampleMaskIn</em> indicates the set of samples covered by |
| the primitive generating the fragment during multisample rasterization. |
| It has a sample bit set if and only if the sample is considered covered for |
| this fragment shader invocation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The output array <em>gl_SampleMask[]</em> sets the sample mask for the fragment |
| being processed. |
| Coverage for the current fragment will become the logical AND of the |
| coverage mask and the output <em>gl_SampleMask</em>. |
| This array must be sized in the fragment shader either implicitly or |
| explicitly, to be no larger than the implementation-dependent maximum |
| sample-mask (as an array of 32bit elements), determined by the maximum |
| number of samples.. |
| If the fragment shader statically assigns a value to <em>gl_SampleMask</em>, the |
| sample mask will be undefined for any array elements of any fragment shader |
| invocations that fail to assign a value. |
| If a shader does not statically assign a value to <em>gl_SampleMask</em>, the |
| sample mask has no effect on the processing of a fragment.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The input variable <em>gl_SampleID</em> is filled with the sample number of the |
| sample currently being processed. |
| This variable is in the range <em>0</em> to <em>gl_NumSamples-1</em>, where |
| <em>gl_NumSamples</em> is the total number of samples in the framebuffer, or 1 if |
| rendering to a non-multisample framebuffer. |
| Any static use of this variable in a fragment shader causes the entire |
| shader to be evaluated per-sample.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The input variable <em>gl_SamplePosition</em> contains the position of the current |
| sample within the multisample draw buffer. |
| The <em>x</em> and <em>y</em> components of <em>gl_SamplePosition</em> contain the sub-pixel |
| coordinate of the current sample and will have values in the range 0.0 to |
| 1.0. |
| Any static use of this variable in a fragment shader causes the entire |
| shader to be evaluated per sample.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The value <em>gl_HelperInvocation</em> is <strong>true</strong> if the fragment shader invocation |
| is considered a <em>helper invocation</em> and is <strong>false</strong> otherwise. |
| A helper invocation is a fragment shader invocation that is created solely |
| for the purposes of evaluating derivatives for use in non-helper fragment |
| shader invocations. |
| Such derivatives are computed implicitly in the built-in function |
| <strong>texture</strong>() (see “<a href="#texture-functions">Texture Functions</a>”), and |
| explicitly in the derivative functions in |
| “<a href="#derivative-functions">Derivative Functions</a>”, for example <strong>dFdx</strong>() and |
| <strong>dFdy</strong>().</p> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment shader helper invocations execute the same shader code as |
| non-helper invocations, but will not have side effects that modify the |
| framebuffer or other shader-accessible memory. |
| In particular:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Fragments corresponding to helper invocations are discarded when shader |
| execution is complete, without updating the framebuffer.</p> |
| </li> |
| <li> |
| <p>Stores to image and buffer variables performed by helper invocations |
| have no effect on the underlying image or buffer memory.</p> |
| </li> |
| <li> |
| <p>Atomic operations to image, buffer, or atomic counter variables |
| performed by helper invocations have no effect on the underlying image |
| or buffer memory. |
| The values returned by such atomic operations are undefined.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Helper invocations may be generated for pixels not covered by a primitive |
| being rendered. |
| While fragment shader inputs qualified with <strong>centroid</strong> are normally required |
| to be sampled in the intersection of the pixel and the primitive, the |
| requirement is ignored for such pixels since there is no intersection |
| between the pixel and primitive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Helper invocations may also be generated for fragments that are covered by a |
| primitive being rendered when the fragment is killed by early fragment tests |
| (using the <strong>early_fragment_tests</strong> qualifier) or where the implementation is |
| able to determine that executing the fragment shader would have no effect |
| other than assisting in computing derivatives for other fragment shader |
| invocations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The set of helper invocations generated when processing any set of |
| primitives is implementation-dependent.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The input variable <em>gl_PrimitiveID</em> is filled with the value written to the |
| <em>gl_PrimitiveID</em> geometry shader output, if a geometry shader is present. |
| Otherwise, it is filled with the number of primitives processed by the |
| shader since the current set of rendering primitives was started.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The input variable <em>gl_Layer</em> is filled with the value written to the |
| <em>gl_Layer</em> geometry shader output, if a geometry shader is present. |
| If the geometry stage does not dynamically assign a value to <em>gl_Layer</em>, the |
| value of <em>gl_Layer</em> in the fragment stage will be undefined. |
| If the geometry stage makes no static assignment to <em>gl_Layer</em>, the input |
| value in the fragment stage will be zero. |
| Otherwise, the fragment stage will read the same value written by the |
| geometry stage, even if that value is out of range. |
| If a fragment shader contains a static access to <em>gl_Layer</em>, it will count |
| against the implementation defined limit for the maximum number of inputs to |
| the fragment stage.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="compute-shader-special-variables">7.1.6. Compute Shader Special Variables</h4> |
| <div class="paragraph"> |
| <p>In the compute shader, built-in variables are declared as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// workgroup dimensions</span> |
| in uvec3 gl_NumWorkGroups; |
| <span class="directive">const</span> uvec3 gl_WorkGroupSize; |
| |
| <span class="comment">// workgroup and invocation IDs</span> |
| in uvec3 gl_WorkGroupID; |
| in uvec3 gl_LocalInvocationID; |
| |
| <span class="comment">// derived variables</span> |
| in uvec3 gl_GlobalInvocationID; |
| in uint gl_LocalInvocationIndex;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in variable <em>gl_NumWorkGroups</em> is a compute-shader input variable |
| containing the number of workgroups in each dimension of the dispatch that |
| will execute the compute shader. |
| Its content is equal to the values specified in the <em>num_groups_x</em>, |
| <em>num_groups_y</em>, and <em>num_groups_z</em> parameters passed to the |
| <em>DispatchCompute</em> API entry point.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in constant <em>gl_WorkGroupSize</em> is a compute-shader constant |
| containing the workgroup size of the shader. |
| The size of the workgroup in the <em>X</em>, <em>Y</em>, and <em>Z</em> dimensions is stored in |
| the <em>x</em>, <em>y</em>, and <em>z</em> components. |
| The constants values in <em>gl_WorkGroupSize</em> will match those specified in the |
| required <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> layout |
| qualifiers for the current shader. |
| This is a constant so that it can be used to size arrays of memory that can |
| be shared within the workgroup. |
| It is a compile-time error to use <em>gl_WorkGroupSize</em> in a shader that does |
| not declare a fixed workgroup size, or before that shader has declared a |
| fixed workgroup size, using <strong>local_size_x</strong>, <strong>local_size_y</strong>, and |
| <strong>local_size_z</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in variable <em>gl_WorkGroupID</em> is a compute-shader input variable |
| containing the three-dimensional index of the workgroup that the |
| current invocation is executing in. |
| The possible values range across the parameters passed into |
| <em>DispatchCompute</em>, i.e., from (0, 0, 0) to (<em>gl_NumWorkGroups.x</em> - 1, |
| <em>gl_NumWorkGroups.y</em> - 1, <em>gl_NumWorkGroups.z</em> -1).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in variable <em>gl_LocalInvocationID</em> is a compute-shader input |
| variable containing the three-dimensional index of the current work item |
| within the workgroup. |
| The possible values for this variable range across the workgroup |
| size, i.e., (0,0,0) to (<em>gl_WorkGroupSize.x</em> - 1, <em>gl_WorkGroupSize.y</em> - 1, |
| <em>gl_WorkGroupSize.z</em> - 1). Use of <em>gl_LocalInvocationID</em> is allowed |
| before declarations of <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in variable <em>gl_GlobalInvocationID</em> is a compute shader input |
| variable containing the global index of the current work item. |
| This value uniquely identifies this invocation from all other invocations |
| across all workgroups initiated by the current <em>DispatchCompute</em> call. |
| This is computed as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">gl_GlobalInvocationID = |
| gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in variable <em>gl_LocalInvocationIndex</em> is a compute shader input |
| variable that contains the one-dimensional representation of the |
| <em>gl_LocalInvocationID</em>. |
| This is computed as:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">gl_LocalInvocationIndex = |
| gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + |
| gl_LocalInvocationID.y * gl_WorkGroupSize.x + |
| gl_LocalInvocationID.x;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Use of <em>gl_LocalInvocationIndex</em> is allowed before declarations of |
| <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="built-in-constants">7.2. Built-In Constants</h3> |
| <div class="paragraph"> |
| <p>The following built-in constants are declared in all shaders. |
| The actual values used are implementation-dependent, but must be at least |
| the value shown.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span> |
| <span class="comment">// Implementation-dependent constants. The example values below</span> |
| <span class="comment">// are the minimum values allowed for these maximums.</span> |
| <span class="comment">//</span></code></pre> |
| </div> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAttribs = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexUniformVectors = <span class="integer">256</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexOutputVectors = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexImageUniforms = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAtomicCounters = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAtomicCounterBuffers = <span class="integer">0</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlInputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlOutputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlUniformComponents = <span class="integer">1024</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlTotalOutputComponents = <span class="integer">2048</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlImageUniforms = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounters = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounterBuffers = <span class="integer">0</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessPatchComponents = <span class="integer">120</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxPatchVertices = <span class="integer">32</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessGenLevel = <span class="integer">64</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationInputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationOutputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationUniformComponents = <span class="integer">1024</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationImageUniforms = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounters = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounterBuffers = <span class="integer">0</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryInputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryOutputComponents = <span class="integer">64</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryImageUniforms = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryOutputVertices = <span class="integer">256</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryTotalOutputComponents = <span class="integer">1024</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryUniformComponents = <span class="integer">1024</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounters = <span class="integer">0</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounterBuffers = <span class="integer">0</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentInputVectors = <span class="integer">15</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentImageUniforms = <span class="integer">4</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentUniformVectors = <span class="integer">256</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounters = <span class="integer">8</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounterBuffers = <span class="integer">1</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxDrawBuffers = <span class="integer">4</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MinProgramTexelOffset = -<span class="integer">8</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxProgramTexelOffset = <span class="integer">7</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxImageUnits = <span class="integer">4</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxSamples = <span class="integer">4</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeImageUniforms = <span class="integer">4</span>; |
| <span class="directive">const</span> highp ivec3 gl_MaxComputeWorkGroupCount = ivec3(<span class="integer">65535</span>, <span class="integer">65535</span>, <span class="integer">65535</span>); |
| <span class="directive">const</span> highp ivec3 gl_MaxComputeWorkGroupSize = ivec3(<span class="integer">128</span>, <span class="integer">128</span>, <span class="integer">64</span>); |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeUniformComponents = <span class="integer">1024</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeTextureImageUnits = <span class="integer">16</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeAtomicCounters = <span class="integer">8</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeAtomicCounterBuffers = <span class="integer">1</span>; |
| |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedTextureImageUnits = <span class="integer">96</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedImageUniforms = <span class="integer">4</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedShaderOutputResources = <span class="integer">4</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounters = <span class="integer">8</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounterBuffers = <span class="integer">1</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxAtomicCounterBindings = <span class="integer">1</span>; |
| <span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxAtomicCounterBufferSize = <span class="integer">32</span>; |
| |
| <span class="directive">const</span> highp <span class="predefined-type">int</span> gl_MaxInputAttachments = <span class="integer">1</span>; <span class="comment">// only present when targeting Vulkan</span></code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="built-in-uniform-state">7.3. Built-In Uniform State</h3> |
| <div class="paragraph"> |
| <p>Built-in uniform state is not available when generating SPIR-V. |
| Otherwise, as an aid to accessing OpenGL ES processing state, the following |
| uniform variables are built into the OpenGL ES Shading Language.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span> |
| <span class="comment">// Depth range in window coordinates,</span> |
| <span class="comment">// section 12.5.1 "Controlling the Viewport" in the</span> |
| <span class="comment">// OpenGL ES Specification.</span> |
| <span class="comment">//</span> |
| <span class="keyword">struct</span> gl_DepthRangeParameters { |
| highp <span class="predefined-type">float</span> near; <span class="comment">// n</span> |
| highp <span class="predefined-type">float</span> far; <span class="comment">// f</span> |
| highp <span class="predefined-type">float</span> diff; <span class="comment">// f - n</span> |
| }; |
| uniform gl_DepthRangeParameters gl_DepthRange; |
| uniform lowp <span class="predefined-type">int</span> gl_NumSamples;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>These variables are only guaranteed to be available in the fragment stage. |
| In other stages, their presence and function is implementation-defined.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="redeclaring-built-in-blocks">7.4. Redeclaring Built-In Blocks</h3> |
| <div class="paragraph"> |
| <p>The <em>gl_PerVertex</em> block can be redeclared in a shader to explicitly |
| indicate what subset of the fixed pipeline interface will be used. |
| This is necessary to establish the interface between multiple programs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the <em>gl_PerVertex</em> block is not redefined in a given program, the |
| intrinsically declared definition of that block is used for the program |
| interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out gl_PerVertex { |
| highp vec4 gl_Position; <span class="comment">// will use gl_Position</span> |
| highp vec4 t; <span class="comment">// error, only gl_PerVertex members allowed</span> |
| }; <span class="comment">// no other members of gl_PerVertex will be used</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This establishes the output interface the shader will use with the |
| subsequent pipeline stage. |
| It must be a subset of the built-in members of <em>gl_PerVertex</em>. |
| Such a redeclaration can also add the <strong>invariant</strong> qualifier and |
| interpolation qualifiers.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Other layout qualifiers, like <strong>location</strong>, cannot be added to such a |
| redeclaration, unless specifically stated.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a built-in interface block is redeclared, it must appear in the shader |
| before any use of any member included in the built-in declaration, or a |
| compile-time error will result. |
| It is also a compile-time error to redeclare the block more than once or to |
| redeclare a built-in block and then use a member from that built-in block |
| that was not included in the redeclaration. |
| Also, if a built-in interface block is redeclared, no member of the built-in |
| declaration can be redeclared outside the block redeclaration. |
| If multiple shaders using members of a built-in block belonging to the same |
| interface are linked together in the same program, they must all redeclare |
| the built-in block in the same way, as described in |
| “<a href="#interface-blocks">Interface Blocks</a>” for interface block matching, or a |
| link-time error will result. |
| It will also be a link-time error if some shaders in a program redeclare a |
| specific built-in interface block while another shader in that program does |
| not redeclare that interface block yet still uses a member of that interface |
| block. |
| If a built-in block interface is formed across shaders in different |
| programs, the shaders must all redeclare the built-in block in the same way |
| (as described for a single program), or the values passed along the |
| interface are undefined.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="built-in-functions">8. Built-In Functions</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The OpenGL ES Shading Language defines an assortment of built-in convenience functions for |
| scalar and vector operations. |
| Many of these built-in functions can be used in more than one type of |
| shader, but some are intended to provide a direct mapping to hardware and so |
| are available only for a specific type of shader.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in functions basically fall into three categories:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>They expose some necessary hardware functionality in a convenient way |
| such as accessing a texture map. |
| There is no way in the language for these functions to be emulated by a |
| shader.</p> |
| </li> |
| <li> |
| <p>They represent a trivial operation (clamp, mix, etc.) that is very |
| simple for the user to write, but they are very common and may have |
| direct hardware support. |
| It is a very hard problem for the compiler to map expressions to complex |
| assembler instructions.</p> |
| </li> |
| <li> |
| <p>They represent an operation graphics hardware is likely to accelerate at |
| some point. |
| The trigonometry functions fall into this category.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Many of the functions are similar to the same named ones in common C |
| libraries, but they support vector input as well as the more traditional |
| scalar input.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Applications should be encouraged to use the built-in functions rather than |
| do the equivalent computations in their own shader code since the built-in |
| functions are assumed to be optimal (e.g. perhaps supported directly in |
| hardware).</p> |
| </div> |
| <div class="paragraph"> |
| <p>When the built-in functions are specified below, where the input arguments |
| (and corresponding output) can be <strong>float</strong>, <strong>vec2</strong>, <strong>vec3</strong>, or <strong>vec4</strong>, |
| <em>genFType</em> is used as the argument. |
| Where the input arguments (and corresponding output) can be <strong>int</strong>, <strong>ivec2</strong>, |
| <strong>ivec3</strong>, or <strong>ivec4</strong>, <em>genIType</em> is used as the argument. |
| Where the input arguments (and corresponding output) can be <strong>uint</strong>, <strong>uvec2</strong>, |
| <strong>uvec3</strong>, or <strong>uvec4</strong>, <em>genUType</em> is used as the argument. |
| Where the input arguments (or corresponding output) can be <strong>bool</strong>, <strong>bvec2</strong>, |
| <strong>bvec3</strong>, or <strong>bvec4</strong>, <em>genBType</em> is used as the argument. |
| For any specific use of a function, the actual types substituted for |
| <em>genFType</em>, <em>genIType</em>, <em>genUType</em>, or <em>genBType</em> have to have the same |
| number of components for all arguments and for the return type. |
| Similarly, <em>mat</em> is used for any matrix basic |
| type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Built-in functions have an effective precision qualification. |
| This qualification cannot be set explicitly and may be different from the |
| precision qualification of the result.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The precision qualification of the operation of a built-in function is based |
| on the precision qualification of its formal parameters and actual |
| parameters (input arguments): When a formal parameter specifies a precision |
| qualifier, that is used, otherwise, the precision qualification of the |
| actual (calling) argument is used. |
| The highest precision of these will be the precision of the operation of the |
| built-in function. |
| Generally, this is applied across all arguments to a built-in function, with |
| the exceptions being:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>bitfieldExtract</strong> and <strong>bitfieldInsert</strong> ignore the <em>offset</em> and <em>bits</em> |
| arguments.</p> |
| </li> |
| <li> |
| <p><strong>interpolateAt</strong> functions only look at the <em>interpolant</em> argument.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The precision qualification of the result of a built-in function is |
| determined in one of the following ways:</p> |
| </div> |
| <div class="paragraph"> |
| <p>For the texture sampling, image load and image store functions, the |
| precision of the return type matches the precision of the |
| texture-combined sampler type:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">uniform lowp sampler2D texSampler; |
| highp vec2 coord; |
| ... |
| lowp vec4 col = texture (texSampler, coord); <span class="comment">// texture() returns lowp</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Otherwise:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>For prototypes that do not specify a resulting precision qualifier, the |
| precision will be the same as the precision of the operation (as defined |
| earlier).</p> |
| </li> |
| <li> |
| <p>For prototypes that do specify a resulting precision qualifier, the |
| specified precision qualifier is the precision qualification of the |
| result.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Where the built-in functions in the following sections specify an equation, |
| the entire equation will be evaluated at the operation’s precision. |
| This may lead to underflow or overflow in the result, even when the correct |
| result could be represented in the operation precision.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</h3> |
| <div class="paragraph"> |
| <p>Function parameters specified as <em>angle</em> are assumed to be in units of |
| radians. |
| In no case will any of these functions result in a divide by zero error. |
| If the divisor of a ratio is 0, then results will be undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These all operate component-wise. |
| The description is per component.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>radians</strong>(genFType <em>degrees</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>degrees</em> to radians, i.e., |
| <span class="eq">(π / 180) · degrees</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>degrees</strong>(genFType <em>radians</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>radians</em> to degrees, i.e., |
| <span class="eq">(180 / π) · radians</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sin</strong>(genFType <em>angle</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric sine function.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cos</strong>(genFType <em>angle</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric cosine function.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tan</strong>(genFType <em>angle</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric tangent.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asin</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc sine. |
| Returns an angle whose sine is <em>x</em>. |
| The range of values returned by this function is |
| <span class="eq">[-π / 2, π / 2]</span>. |
| Results are undefined if <span class="eq">|x| > 1</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acos</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc cosine. |
| Returns an angle whose cosine is <em>x</em>. |
| The range of values returned by this function is <span class="eq">[0,Ï€]</span>. |
| Results are undefined if <span class="eq">|x| > 1</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y</em>, genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent. |
| Returns an angle whose tangent is <span class="eq">y / x</span>. |
| The signs of <em>x</em> and <em>y</em> are used to determine what quadrant the angle |
| is in. |
| The range of values returned by this function is <span class="eq">[-π, π</span>. |
| Results are undefined if <em>x</em> and <em>y</em> are both 0.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y_over_x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent. |
| Returns an angle whose tangent is <em>y_over_x</em>. |
| The range of values returned by this function is |
| <span class="eq">[-π / 2, π / 2]</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sinh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic sine function <span class="eq">(e<sup>x</sup> - e<sup>-x</sup>) / 2</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cosh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic cosine function <span class="eq">(e<sup>x</sup> + e<sup>-x</sup>) / 2</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tanh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic tangent function <span class="eq">sinh(x) / cosh(x)</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asinh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic sine; returns the inverse of <strong>sinh</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acosh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic cosine; returns the non-negative inverse of <strong>cosh</strong>. |
| Results are undefined if <span class="eq">x < 1</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atanh</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic tangent; returns the inverse of <strong>tanh</strong>. |
| Results are undefined if <span class="eq">x ≥ 1</span>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="exponential-functions">8.2. Exponential Functions</h3> |
| <div class="paragraph"> |
| <p>These all operate component-wise. |
| The description is per component.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>pow</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> raised to the <em>y</em> power, i.e., <span class="eq">x<sup>y</sup></span>. |
| Results are undefined if <span class="eq">x < 0</span>. |
| Results are undefined if <span class="eq">x = 0</span> and <span class="eq">y ≤ 0</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural exponentiation of <em>x</em>, i.e., <span class="eq">e<sup>x</sup></span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural logarithm of <em>x</em>, i.e., returns the value <em>y</em> |
| which satisfies the equation <span class="eq">x = e<sup>y</sup></span>. |
| Results are undefined if <span class="eq">x ≤ 0</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp2</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns 2 raised to the <em>x</em> power, i.e., <span class="eq">2<sup>x</sup></span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log2</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the base 2 logarithm of <em>x</em>, i.e., returns the value <em>y</em> which |
| satisfies the equation <span class="eq">x = 2<sup>y</sup></span>. |
| Results are undefined if <span class="eq">x ≤ 0</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sqrt</strong>(genFType <em>x</em>)<br> |
| genDType <strong>sqrt</strong>(genDType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">sqrt(x)</span>. |
| Results are undefined if <span class="eq">x < 0</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>inversesqrt</strong>(genFType <em>x</em>)<br> |
| genDType <strong>inversesqrt</strong>(genDType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">1 / sqrt(x)</span>. |
| Results are undefined if <span class="eq">x ≤ 0</span>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="common-functions">8.3. Common Functions</h3> |
| <div class="paragraph"> |
| <p>These all operate component-wise. |
| The description is per component.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>abs</strong>(genFType <em>x</em>)<br> |
| genIType <strong>abs</strong>(genIType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> if <span class="eq">x ≥ 0</span>; otherwise it returns -<em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sign</strong>(genFType <em>x</em>)<br> |
| genIType <strong>sign</strong>(genIType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns 1.0 if <em>x</em> > 0, 0.0 if <em>x</em> = 0, or -1.0 if <em>x</em> < 0.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>floor</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is less than or |
| equal to <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>trunc</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em> whose absolute |
| value is not larger than the absolute value of <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>round</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>. |
| The fraction 0.5 will round in a direction chosen by the |
| implementation, presumably the direction that is fastest. |
| This includes the possibility that <strong>round</strong>(<em>x</em>) returns the same value |
| as <strong>roundEven</strong>(<em>x</em>) for all values of <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>roundEven</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>. |
| A fractional part of 0.5 will round toward the nearest even integer. |
| (Both 3.5 and 4.5 for x will return 4.0.)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ceil</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is greater than or |
| equal to <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fract</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> - <strong>floor</strong>(<em>x</em>).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mod</strong>(genFType <em>x</em>, float <em>y</em>)<br> |
| genFType <strong>mod</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Modulus. |
| Returns <span class="eq">x - y · <strong>floor</strong>(x / y)</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>modf</strong>(genFType <em>x</em>, out genFType <em>i</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the fractional part of <em>x</em> and sets <em>i</em> to the integer part (as |
| a whole number floating-point value). |
| Both the return value and the output parameter will have the same sign |
| as <em>x</em>. |
| If <em>x</em> has the value +/- Inf, the return value should be NaN and must |
| be either NaN or 0.0. |
| For <strong>highp</strong> non-constant expressions, the value returned must be |
| consistent.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>min</strong>(genFType <em>x</em>, genFType <em>y</em>)<br> |
| genFType <strong>min</strong>(genFType <em>x</em>, float <em>y</em>)<br> |
| genIType <strong>min</strong>(genIType <em>x</em>, genIType <em>y</em>)<br> |
| genIType <strong>min</strong>(genIType <em>x</em>, int <em>y</em>)<br> |
| genUType <strong>min</strong>(genUType <em>x</em>, genUType <em>y</em>)<br> |
| genUType <strong>min</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>y</em> < <em>x;</em> otherwise it returns <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>max</strong>(genFType <em>x</em>, genFType <em>y</em>)<br> |
| genFType <strong>max</strong>(genFType <em>x</em>, float <em>y</em>)<br> |
| genIType <strong>max</strong>(genIType <em>x</em>, genIType <em>y</em>)<br> |
| genIType <strong>max</strong>(genIType <em>x</em>, int <em>y</em>)<br> |
| genUType <strong>max</strong>(genUType <em>x</em>, genUType <em>y</em>)<br> |
| genUType <strong>max</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>x</em> < <em>y;</em> otherwise it returns <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>clamp</strong>(genFType <em>x</em>, genFType <em>minVal</em>, genFType <em>maxVal</em>)<br> |
| genFType <strong>clamp</strong>(genFType <em>x</em>, float <em>minVal</em>, float <em>maxVal</em>)<br> |
| genIType <strong>clamp</strong>(genIType <em>x</em>, genIType <em>minVal</em>, genIType <em>maxVal</em>)<br> |
| genIType <strong>clamp</strong>(genIType <em>x</em>, int <em>minVal</em>, int <em>maxVal</em>)<br> |
| genUType <strong>clamp</strong>(genUType <em>x</em>, genUType <em>minVal</em>, genUType <em>maxVal</em>)<br> |
| genUType <strong>clamp</strong>(genUType <em>x</em>, uint <em>minVal</em>, uint <em>maxVal</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>min</strong>(<strong>max</strong>(<em>x</em>, <em>minVal</em>), <em>maxVal</em>). |
| Results are undefined if <em>minVal</em> > <em>maxVal</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType <em>a</em>)<br> |
| genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, float <em>a</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the linear blend of <em>x</em> and <em>y</em>, i.e., |
| <span class="eq">x · (1 - a) + y · a</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genBType <em>a</em>)<br> |
| genIType <strong>mix</strong>(genIType <em>x</em>, genIType <em>y</em>, genBType <em>a</em>)<br> |
| genUType <strong>mix</strong>(genUType <em>x</em>, genUType <em>y</em>, genBType <em>a</em>)<br> |
| genBType <strong>mix</strong>(genBType <em>x</em>, genBType <em>y</em>, genBType <em>a</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Selects which vector each returned component comes from. |
| For a component of <em>a</em> that is <strong>false</strong>, the corresponding component of |
| <em>x</em> is returned. |
| For a component of <em>a</em> that is <strong>true</strong>, the corresponding component of |
| <em>y</em> is returned. |
| Components of <em>x</em> and <em>y</em> that are not selected are allowed to be |
| invalid floating-point values and will have no effect on the results. |
| Thus, this provides different functionality than, for example,<br> |
| genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType(<em>a</em>))<br> |
| where <em>a</em> is a Boolean vector.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>step</strong>(genFType <em>edge</em>, genFType <em>x</em>)<br> |
| genFType <strong>step</strong>(float <em>edge</em>, genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns 0.0 if <em>x</em> < <em>edge;</em> otherwise it returns 1.0.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>smoothstep</strong>(genFType <em>edge0</em>, genFType <em>edge1</em>, genFType <em>x</em>)<br> |
| genFType <strong>smoothstep</strong>(float <em>edge0</em>, float <em>edge1</em>, genFType <em>x</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Returns 0.0 if <span class="eq">x ≤ edge0</span> and 1.0 if <span class="eq">x ≥ edge1</span>, and |
| performs smooth Hermite interpolation between 0 and 1 when <span class="eq">edge0 |
| < x < edge1</span>. |
| This is useful in cases where you would want a threshold function with |
| a smooth transition. |
| This is equivalent to:</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">genFType t; |
| t = clamp ((x - edge0) / (edge1 - edge0), <span class="integer">0</span>, <span class="integer">1</span>); |
| <span class="keyword">return</span> t * t * (<span class="integer">3</span> - <span class="integer">2</span> * t);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>(And similarly for doubles.) Results are undefined if <span class="eq">edge0 ≥ |
| edge1</span>.</p> |
| </div> |
| </div> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isnan</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a NaN. |
| Returns <strong>false</strong> otherwise. |
| Always returns <strong>false</strong> if NaNs are not implemented.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isinf</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a positive infinity or negative infinity. |
| Returns <strong>false</strong> otherwise.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>floatBitsToInt</strong>(highp genFType <em>value</em>)<br> |
| genUType <strong>floatBitsToUint</strong>(highp genFType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a signed or unsigned integer value representing the encoding |
| of a floating-point value. |
| The <strong>float</strong> value’s bit-level representation is preserved.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>intBitsToFloat</strong>(highp genIType <em>value</em>)<br> |
| genFType <strong>uintBitsToFloat</strong>(highp genUType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a floating-point value corresponding to a signed or unsigned |
| integer encoding of a floating-point value. |
| If an Inf or NaN is passed in, it will not signal, and the resulting |
| floating-point value is unspecified. |
| Otherwise, the bit-level representation is preserved.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fma</strong>(genFType <em>a</em>, genFType <em>b</em>, genFType <em>c</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Computes and returns <code>a * b + c</code>. |
| In uses where the return value is eventually consumed by a variable |
| declared as <strong>precise</strong>:</p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>fma</strong>() is considered a single operation, whereas the expression <code>a * b |
| + c</code> consumed by a variable declared <strong>precise</strong> is considered two |
| operations.</p> |
| </li> |
| <li> |
| <p>The precision of <strong>fma</strong>() can differ from the precision of the expression |
| <code>a * b + c</code>.</p> |
| </li> |
| <li> |
| <p><strong>fma</strong>() will be computed with the same precision as any other <strong>fma</strong>() |
| consumed by a precise variable, giving invariant results for the same |
| input values of <em>a</em>, <em>b</em>, and <em>c</em>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Otherwise, in the absence of <strong>precise</strong> consumption, there are no special |
| constraints on the number of operations or difference in precision between |
| <strong>fma</strong>() and the expression <code>a * b + c</code>.</p> |
| </div> |
| </div> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>frexp</strong>(highp genFType <em>x</em>, out highp genIType <em>exp</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Splits <em>x</em> into a floating-point significand in the range |
| <span class="eq">[0.5,1.0]</span>, and an integral exponent of two, such that</p> |
| <p class="tableblock"> <span class="eq">x = significant · 2<sup>exponent</sup></span></p> |
| <p class="tableblock"> The significand is returned by the function and the exponent is |
| returned in the parameter <em>exp</em>. |
| For a floating-point value of zero, the significand and exponent are |
| both zero.</p> |
| <p class="tableblock"> If an implementation supports signed zero, an input value of minus |
| zero should return a significand of minus zero. |
| For a floating-point value that is an infinity or is not a number, the |
| results are undefined.</p> |
| <p class="tableblock"> If the input <em>x</em> is a vector, this operation is performed in a |
| component-wise manner; the value returned by the function and the |
| value written to <em>exp</em> are vectors with the same number of components |
| as <em>x</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ldexp</strong>(highp genFType <em>x</em>, highp genIType <em>exp</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Builds a floating-point number from <em>x</em> and the corresponding integral |
| exponent of two in <em>exp</em>, returning:</p> |
| <p class="tableblock"> <span class="eq">significand · 2<sup>exponent</sup></span></p> |
| <p class="tableblock"> If this product is too large to be represented in the floating-point |
| type, the result is undefined.</p> |
| <p class="tableblock"> If <em>exp</em> is greater than +128, the value returned is undefined. |
| If <em>exp</em> is less than -126, the value returned may be flushed to zero. |
| Additionally, splitting the value into a significand and exponent |
| using <strong>frexp</strong>() and then reconstructing a floating-point value using |
| <strong>ldexp</strong>() should yield the original input for zero and all finite |
| non-denormalized values.<br> |
| If the input <em>x</em> is a vector, this operation is performed in a |
| component-wise manner; the value passed in <em>exp</em> and returned by the |
| function are vectors with the same number of components as <em>x</em>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</h3> |
| <div class="paragraph"> |
| <p>These functions do not operate component-wise, rather, as described in each |
| case.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>packUnorm2x16</strong>(vec2 <em>v</em>)<br> |
| highp uint <strong>packSnorm2x16</strong>(vec2 <em>v</em>)<br> |
| highp uint <strong>packUnorm4x8</strong>(vec4 <em>v</em>)<br> |
| highp uint <strong>packSnorm4x8</strong>(vec4 <em>v</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">First, converts each component of the normalized floating-point value |
| <em>v</em> into 16-bit (<strong>2x16</strong>) or 8-bit (<strong>4x8</strong>) integer values. |
| Then, the results are packed into the returned 32-bit unsigned |
| integer.</p> |
| <p class="tableblock"> The conversion for component <em>c</em> of <em>v</em> to fixed point is done as |
| follows:</p> |
| <p class="tableblock"> <strong>packUnorm2x16</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 65535.0)<br> |
| <strong>packSnorm2x16:</strong> <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 32767.0)<br> |
| <strong>packUnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 255.0)<br> |
| <strong>packSnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 127.0)</p> |
| <p class="tableblock"> The first component of the vector will be written to the least |
| significant bits of the output; the last component will be written to |
| the most significant bits.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp vec2 <strong>unpackUnorm2x16</strong>(highp uint <em>p</em>)<br> |
| highp vec2 <strong>unpackSnorm2x16</strong>(highp uint <em>p</em>)<br> |
| mediump vec4 <strong>unpackUnorm4x8</strong>(highp uint <em>p</em>)<br> |
| mediump vec4 <strong>unpackSnorm4x8</strong>(highp uint <em>p</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">First, unpacks a single 32-bit unsigned integer <em>p</em> into a pair of |
| 16-bit unsigned integers, a pair of 16-bit signed integers, four 8-bit |
| unsigned integers, or four 8-bit signed integers, respectively. |
| Then, each component is converted to a normalized floating-point value |
| to generate the returned two- or four-component vector.</p> |
| <p class="tableblock"> The conversion for unpacked fixed-point value <em>f</em> to floating-point is |
| done as follows:</p> |
| <p class="tableblock"> <strong>unpackUnorm2x16</strong>: <em>f</em> / 65535.0<br> |
| <strong>unpackSnorm2x16</strong>: <strong>clamp</strong>(<em>f</em> / 32767.0, -1, +1)<br> |
| <strong>unpackUnorm4x8</strong>: <em>f</em> / 255.0<br> |
| <strong>unpackSnorm4x8</strong>: <strong>clamp</strong>(<em>f</em> / 127.0, -1, +1)</p> |
| <p class="tableblock"> The first component of the returned vector will be extracted from the |
| least significant bits of the input; the last component will be |
| extracted from the most significant bits.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>packHalf2x16</strong>(vec2 <em>v</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns an unsigned integer obtained by converting the components of a |
| two-component floating-point vector to the 16-bit floating-point |
| representation of the <a href="#references">API</a>, and |
| then packing these two 16-bit integers into a 32-bit unsigned integer.</p> |
| <p class="tableblock"> The first vector component specifies the 16 least-significant bits of |
| the result; the second component specifies the 16 most-significant |
| bits.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">mediump vec2 <strong>unpackHalf2x16</strong>(highp uint <em>v</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a two-component floating-point vector with components obtained |
| by unpacking a 32-bit unsigned integer into a pair of 16-bit values, |
| interpreting those values as 16-bit floating-point numbers according |
| to the <a href="#references">API</a>, and converting them to |
| 32-bit floating-point values.</p> |
| <p class="tableblock"> The first component of the vector is obtained from the 16 |
| least-significant bits of <em>v</em>; the second component is obtained from |
| the 16 most-significant bits of <em>v</em>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="geometric-functions">8.5. Geometric Functions</h3> |
| <div class="paragraph"> |
| <p>These operate on vectors as vectors, not component-wise.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>length</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Returns the length of vector <em>x</em>, i.e., |
| <span class="eq">sqrt( x<sub>0</sub><sup>2</sup> + x<sub>1</sub><sup>2</sup> + …​ )</span>.</p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>distance</strong>(genFType <em>p0</em>, genFType <em>p1</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the distance between <em>p0</em> and <em>p1</em>, i.e., |
| <strong>length</strong>(<em>p0</em> - <em>p1</em>)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>dot</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dot product of <em>x</em> and <em>y</em>, i.e., |
| <span class="eq">x<sub>0</sub> · y<sub>0</sub> + x<sub>1</sub> · y<sub>1</sub> + …​</span></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">vec3 <strong>cross</strong>(vec3 <em>x</em>, vec3 <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Returns the cross product of <em>x</em> and <em>y</em>, i.e., |
| <span class="eq">(x<sub>1</sub> · y<sub>2</sub> - y<sub>1</sub> · x<sub>2</sub>, |
| x<sub>2</sub> · y<sub>0</sub> - y<sub>2</sub> · x<sub>0</sub>, |
| x<sub>0</sub> · y<sub>1</sub> - y<sub>0</sub> · x<sub>1</sub>)</span>.</p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>normalize</strong>(genFType <em>x</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a vector in the same direction as <em>x</em> but with a length of 1, |
| i.e. <em>x</em> / <strong>length</strong>(x).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>faceforward</strong>(genFType <em>N</em>, genFType <em>I</em>, genFType <em>Nref</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">If <strong>dot</strong>(<em>Nref</em>, <em>I</em>) < 0 return <em>N</em>, otherwise return -<em>N</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>reflect</strong>(genFType <em>I</em>, genFType <em>N</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">For the incident vector <em>I</em> and surface orientation <em>N</em>, returns the |
| reflection direction: <span class="eq">I - 2 · <strong>dot</strong>(N, I) · N</span>. |
| <em>N</em> must already be normalized in order to achieve the desired result.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>refract</strong>(genFType <em>I</em>, genFType <em>N</em>, float <em>eta</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>For the incident vector <em>I</em> and surface normal <em>N</em>, and the ratio of |
| indices of refraction <em>eta</em>, return the refraction vector. |
| The result is computed by the <a href="#refraction-equation">refraction |
| equation</a> shown below.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>The input parameters for the incident vector _I_ and the surface |
| normal _N_ must already be normalized to get the desired results.</pre> |
| </div> |
| </div></div></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="sect3"> |
| <h4 id="refraction-equation">8.5.1. Refraction Equation</h4> |
| <div class="stemblock"> |
| <div class="content"> |
| \[k = 1.0 - eta * eta * (1.0 - \textbf{dot}(N,I) \cdot \textbf{dot}(N,I))\] |
| </div> |
| </div> |
| <div class="stemblock"> |
| <div class="content"> |
| \[\begin{aligned} |
| result &= |
| \begin{cases} |
| genFType(0.0), & k < 0.0 \\ |
| eta * I - (eta * \textbf{dot}(N,I) + \sqrt { k }) * N, & \textbf{otherwise} |
| \end{cases} |
| \end{aligned}\] |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="matrix-functions">8.6. Matrix Functions</h3> |
| <div class="paragraph"> |
| <p>For each of the following built-in matrix functions, there is both a |
| single-precision floating-point version, where all arguments and return |
| values are single precision, and a double-precision floating-point version, |
| where all arguments and return values are double precision. |
| Only the single-precision floating-point version is shown.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">mat <strong>matrixCompMult</strong>(mat <em>x</em>, mat <em>y</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Multiply matrix <em>x</em> by matrix <em>y</em> component-wise, i.e., result[i][j] |
| is the scalar product of <em>x</em>[i][j] and <em>y</em>[i][j].<br></p> |
| <p class="tableblock"> Note: to get linear algebraic matrix multiplication, use the multiply |
| operator (<strong>*</strong>).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec2 <em>r</em>)<br> |
| mat3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec3 <em>r</em>)<br> |
| mat4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec4 <em>r</em>)<br> |
| mat2x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec2 <em>r</em>)<br> |
| mat3x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec3 <em>r</em>)<br> |
| mat2x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec2 <em>r</em>)<br> |
| mat4x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec4 <em>r</em>)<br> |
| mat3x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec3 <em>r</em>)<br> |
| mat4x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec4 <em>r</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Treats the first parameter <em>c</em> as a column vector (matrix with one |
| column) and the second parameter <em>r</em> as a row vector (matrix with one |
| row) and does a linear algebraic matrix multiply <em>c</em> * <em>r</em>, yielding a |
| matrix whose number of rows is the number of components in <em>c</em> and |
| whose number of columns is the number of components in <em>r</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>transpose</strong>(mat2 <em>m</em>)<br> |
| mat3 <strong>transpose</strong>(mat3 <em>m</em>)<br> |
| mat4 <strong>transpose</strong>(mat4 <em>m</em>)<br> |
| mat2x3 <strong>transpose</strong>(mat3x2 <em>m</em>)<br> |
| mat3x2 <strong>transpose</strong>(mat2x3 <em>m</em>)<br> |
| mat2x4 <strong>transpose</strong>(mat4x2 <em>m</em>)<br> |
| mat4x2 <strong>transpose</strong>(mat2x4 <em>m</em>)<br> |
| mat3x4 <strong>transpose</strong>(mat4x3 <em>m</em>)<br> |
| mat4x3 <strong>transpose</strong>(mat3x4 <em>m</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the transpose of <em>m</em>. |
| The input matrix <em>m</em> is not modified.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>determinant</strong>(mat2 <em>m</em>)<br> |
| float <strong>determinant</strong>(mat3 <em>m</em>)<br> |
| float <strong>determinant</strong>(mat4 <em>m</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the determinant of <em>m</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>inverse</strong>(mat2 <em>m</em>)<br> |
| mat3 <strong>inverse</strong>(mat3 <em>m</em>)<br> |
| mat4 <strong>inverse</strong>(mat4 <em>m</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the inverse of <em>m</em>. |
| The input matrix <em>m</em> is not modified. |
| The values in the returned matrix are undefined if <em>m</em> is singular or |
| poorly-conditioned (nearly singular).</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="vector-relational-functions">8.7. Vector Relational Functions</h3> |
| <div class="paragraph"> |
| <p>Relational and equality operators (<strong><</strong>, <strong><=</strong>, <strong>></strong>, <strong>>=</strong>, <strong>==</strong>, <strong>!=</strong>) are |
| defined to operate on scalars and produce scalar Boolean results. |
| For vector results, use the following built-in functions. |
| Below, the following placeholders are used for the listed specific types:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Placeholder</th> |
| <th class="tableblock halign-left valign-top">Specific Types Allowed</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec2, bvec3, bvec4</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ivec</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ivec2, ivec3, ivec4</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uvec</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uvec2, uvec3, uvec4</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">vec</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">vec2, vec3, vec4</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>In all cases, the sizes of all the input and return vectors for any |
| particular call must match.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThan</strong>(vec x, vec y)<br> |
| bvec <strong>lessThan</strong>(ivec x, ivec y)<br> |
| bvec <strong>lessThan</strong>(uvec x, uvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x < y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThanEqual</strong>(vec x, vec y)<br> |
| bvec <strong>lessThanEqual</strong>(ivec x, ivec y)<br> |
| bvec <strong>lessThanEqual</strong>(uvec x, uvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≤ y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThan</strong>(vec x, vec y)<br> |
| bvec <strong>greaterThan</strong>(ivec x, ivec y)<br> |
| bvec <strong>greaterThan</strong>(uvec x, uvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x > y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThanEqual</strong>(vec x, vec y)<br> |
| bvec <strong>greaterThanEqual</strong>(ivec x, ivec y)<br> |
| bvec <strong>greaterThanEqual</strong>(uvec x, uvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≥ y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>equal</strong>(vec x, vec y)<br> |
| bvec <strong>equal</strong>(ivec x, ivec y)<br> |
| bvec <strong>equal</strong>(uvec x, uvec y)<br> |
| bvec <strong>equal</strong>(bvec x, bvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x == y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>notEqual</strong>(vec x, vec y)<br> |
| bvec <strong>notEqual</strong>(ivec x, ivec y)<br> |
| bvec <strong>notEqual</strong>(uvec x, uvec y)<br> |
| bvec <strong>notEqual</strong>(bvec x, bvec y)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≠y</span>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>any</strong>(bvec x)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if any component of <em>x</em> is <strong>true</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>all</strong>(bvec x)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> only if all components of <em>x</em> are <strong>true</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>not</strong>(bvec x)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise logical complement of <em>x</em>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="integer-functions">8.8. Integer Functions</h3> |
| <div class="paragraph"> |
| <p>These all operate component-wise. |
| The description is per component. |
| The notation [<em>a</em>, <em>b</em>] means the set of bits from bit-number <em>a</em> through |
| bit-number <em>b</em>, inclusive. |
| The lowest-order bit is bit 0. |
| “Bit number” will always refer to counting up from the lowest-order bit as |
| bit 0.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>uaddCarry</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out lowp genUType <em>carry</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Adds 32-bit unsigned integers <em>x</em> and <em>y</em>, returning the sum modulo |
| 2<sup>32</sup>. |
| The value <em>carry</em> is set to zero if the sum was less than 2<sup>32</sup>, or |
| one otherwise.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>usubBorrow</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out lowp genUType <em>borrow</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Subtracts the 32-bit unsigned integer <em>y</em> from <em>x</em>, returning the |
| difference if non-negative, or 2<sup>32</sup> plus the difference otherwise. |
| The value <em>borrow</em> is set to zero if <span class="eq">x ≥ y</span>, or one |
| otherwise.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>umulExtended</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out highp genUType <em>msb</em>, out highp genUType <em>lsb</em>)<br> |
| void <strong>imulExtended</strong>(highp genIType <em>x</em>, highp genIType <em>y</em>, out highp genIType <em>msb</em>, out highp genIType <em>lsb</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Multiplies 32-bit unsigned or signed integers <em>x</em> and <em>y</em>, producing a |
| 64-bit result. |
| The 32 least-significant bits are returned in <em>lsb</em>. |
| The 32 most-significant bits are returned in <em>msb</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldExtract</strong>(genIType <em>value</em>, int <em>offset</em>, int <em>bits</em>)<br> |
| genUType <strong>bitfieldExtract</strong>(genUType <em>value</em>, int <em>offset</em>, int <em>bits</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Extracts bits <span class="eq">[offset, offset + bits - 1]</span> from <em>value</em>, |
| returning them in the least significant bits of the result.<br></p> |
| <p class="tableblock"> For unsigned data types, the most significant bits of the result will |
| be set to zero. |
| For signed data types, the most significant bits will be set to the |
| value of bit <span class="eq">offset + bits - 1</span>.<br></p> |
| <p class="tableblock"> If <em>bits</em> is zero, the result will be zero. |
| The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if |
| the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used |
| to store the operand. |
| Note that for vector versions of <strong>bitfieldExtract</strong>(), a single pair of |
| <em>offset</em> and <em>bits</em> values is shared for all components.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldInsert</strong>(genIType <em>base</em>, genIType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)<br> |
| genUType <strong>bitfieldInsert</strong>(genUType <em>base</em>, genUType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Inserts the <em>bits</em> least significant bits of <em>insert</em> into <em>base</em>.</p> |
| <p class="tableblock"> The result will have bits <span class="eq">[offset, offset + bits - 1]</span> taken from |
| bits <span class="eq">[0, bits - 1]</span> of <em>insert</em>, and all other bits taken |
| directly from the corresponding bits of <em>base</em>. |
| If <em>bits</em> is zero, the result will simply be <em>base</em>. |
| The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if |
| the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used |
| to store the operand.<br> |
| Note that for vector versions of <strong>bitfieldInsert</strong>(), a single pair of |
| <em>offset</em> and <em>bits</em> values is shared for all components.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldReverse</strong>(highp genIType <em>value</em>)<br> |
| genUType <strong>bitfieldReverse</strong>(highp genUType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Reverses the bits of <em>value</em>. |
| The bit numbered <em>n</em> of the result will be taken from bit <span class="eq">(bits - |
| 1) - n</span> of <em>value</em>, where <em>bits</em> is the total number of bits used to |
| represent <em>value</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>bitCount</strong>(genIType <em>value</em>)<br> |
| lowp genIType <strong>bitCount</strong>(genUType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of one bits in the binary representation of |
| <em>value</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>findLSB</strong>(genIType <em>value</em>)<br> |
| lowp genIType <strong>findLSB</strong>(genUType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the least significant one bit in the binary |
| representation of <em>value</em>. |
| If <em>value</em> is zero, -1 will be returned.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>findMSB</strong>(highp genIType <em>value</em>)<br> |
| lowp genIType <strong>findMSB</strong>(highp genUType <em>value</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the most significant bit in the binary |
| representation of <em>value</em>.</p> |
| <p class="tableblock"> For positive integers, the result will be the bit number of the most |
| significant one bit. |
| For negative integers, the result will be the bit number of the most |
| significant zero bit. |
| For a <em>value</em> of zero or negative one, -1 will be returned.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="texture-functions">8.9. Texture Functions</h3> |
| <div class="paragraph"> |
| <p>Texture lookup functions are available in all shading stages. |
| However, level-of-detail is implicitly computed only for fragment shaders. |
| Other shaders operate as though the base level-of-detail were computed as |
| zero. |
| The functions in the table below provide access to textures through |
| texture-combined samplers, as set up through the API. |
| Texture properties such as size, pixel format, number of dimensions, |
| filtering method, number of mipmap levels, depth comparison, and so on are |
| also defined by API calls. |
| Such properties are taken into account as the texture is accessed via the |
| built-in functions defined below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Texture data can be stored by the GL as single-precision floating-point, |
| unsigned normalized integer, unsigned integer or signed integer data. |
| This is determined by the type of the internal format of the texture.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Texture lookup functions are provided that can return their result as |
| floating-point, unsigned integer or signed integer, depending on the sampler |
| type passed to the lookup function. |
| Care must be taken to use the right sampler type for texture access. |
| The following table lists the supported combinations of sampler types and |
| texture internal formats. |
| Blank entries are unsupported. |
| Doing a texture lookup will return undefined values for unsupported |
| combinations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For depth/stencil textures, the internal texture format is determined by the |
| component being accessed as set through the API. |
| When the depth/stencil texture mode is set to DEPTH_COMPONENT, the internal |
| format of the depth component should be used. |
| When the depth/stencil texture mode is set to STENCIL_INDEX, the internal format |
| of the stencil component should be used.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Internal Texture Format</th> |
| <th class="tableblock halign-left valign-top">Floating-Point Sampler Types</th> |
| <th class="tableblock halign-left valign-top">Signed Integer Sampler Types</th> |
| <th class="tableblock halign-left valign-top">Unsigned Integer Sampler Types</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Floating-point</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Normalized Integer</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Signed Integer</p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Unsigned Integer</p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>If an integer sampler type is used, the result of a texture lookup is an |
| <strong>ivec4</strong>. |
| If an unsigned integer sampler type is used, the result of a texture lookup |
| is a <strong>uvec4</strong>. |
| If a floating-point sampler type is used, the result of a texture lookup is |
| a <strong>vec4</strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the prototypes below, the <code>g</code> in the return type <code>gvec4</code> is used |
| as a placeholder for either nothing, <code>i</code>, or <code>u</code> making a return type of |
| <strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong>. |
| In these cases, the sampler argument type also starts with <code>g</code>, |
| indicating the same substitution done on the return type; it is either a |
| floating-point, signed integer, or unsigned integer sampler, matching the |
| basic type of the return type, as described above.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For shadow forms (the sampler parameter is a shadow-type), a depth |
| comparison lookup on the depth texture bound to <em>sampler</em> is done as |
| described in section |
| 8.20 |
| “Texture Comparison Modes” of the |
| <a href="#references">OpenGL ES Specification</a>. |
| See the table below for which component specifies <em>D<sub>ref</sub></em>. |
| The texture bound to <em>sampler</em> must be a depth texture, or results are |
| undefined. |
| If a non-shadow texture call is made to a sampler that represents a depth |
| texture with depth comparisons turned on, then results are undefined. |
| If a shadow texture call is made to a sampler that represents a depth |
| texture with depth comparisons turned off, then results are undefined. |
| If a shadow texture call is made to a sampler that does not represent a |
| depth texture, then results are undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In all functions below, the <em>bias</em> parameter is optional for fragment |
| shaders. |
| The <em>bias</em> parameter is not accepted in any other shader stage. |
| For a fragment shader, if <em>bias</em> is present, it is added to the implicit |
| level-of-detail prior to performing the texture access operation. |
| No <em>bias</em> or <em>lod</em> parameters for |
| multisample textures, or texture buffers |
| are supported because mipmaps are not allowed for these types of textures.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The implicit level-of-detail is selected as follows: For a texture that is |
| not mipmapped, the texture is used directly. |
| If it is mipmapped and running in a fragment shader, the level-of-detail |
| computed by the implementation is used to do the texture lookup. |
| If it is mipmapped and running in a non-fragment shader, then the base |
| texture is used.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Some texture functions (non-“<strong>Lod</strong>” and non-“<strong>Grad</strong>” versions) may |
| require implicit derivatives. |
| Implicit derivatives are undefined within non-uniform control flow and for |
| non-fragment shader texture fetches.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For <strong>Cube</strong> forms, the direction of <em>P</em> is used to select which face to do a |
| 2-dimensional texture lookup in, as described in section 8.13 “Cube Map |
| Texture Selection” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For <strong>Array</strong> forms, the array layer used will be</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(\max(0,\min(d-1,\left\lfloor layer + 0.5\right\rfloor))\)</p> |
| </div> |
| <div class="paragraph"> |
| <p>where <em>d</em> is the depth of the texture array and <em>layer</em> comes from the |
| component indicated in the tables below.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="texture-query-functions">8.9.1. Texture Query Functions</h4> |
| <div class="paragraph"> |
| <p>The <strong>textureSize</strong> functions query the dimensions of a specific texture level |
| for a texture-combined sampler.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp ivec2 <strong>textureSize</strong>(gsampler2D <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec3 <strong>textureSize</strong>(gsampler3D <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec2 <strong>textureSize</strong>(gsamplerCube <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec2 <strong>textureSize</strong>(sampler2DShadow <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec2 <strong>textureSize</strong>(samplerCubeShadow <em>sampler</em>, int <em>lod</em>) |
| highp ivec3 <strong>textureSize</strong>(gsamplerCubeArray <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec3 <strong>textureSize</strong>(samplerCubeArrayShadow <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec3 <strong>textureSize</strong>(gsampler2DArray <em>sampler</em>, int <em>lod</em>)<br> |
| highp ivec3 <strong>textureSize</strong>(sampler2DArrayShadow <em>sampler</em>, int <em>lod</em>)<br> |
| highp int <strong>textureSize</strong>(gsamplerBuffer <em>sampler</em>)<br> |
| highp ivec2 <strong>textureSize</strong>(gsampler2DMS <em>sampler</em>)<br> |
| highp ivec3 <strong>textureSize</strong>(gsampler2DMSArray <em>sampler</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of level <em>lod</em> (if present) for the texture |
| bound to <em>sampler</em>, as described in section |
| 8.11 “Texture Queries” of the <a href="#references">OpenGL ES Specification</a>.<br> |
| The components in the return value are filled in, in order, with the |
| width, height, and depth of the texture.</p> |
| <p class="tableblock"> For the array forms, the last component of the return value is the |
| number of layers in the texture array, or the number of cubes in the |
| texture cube map array.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="texel-lookup-functions">8.9.2. Texel Lookup Functions</h4> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texture</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>texture</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>texture</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>[, float <em>bias</em>] )<br> |
| float <strong>texture</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>])<br> |
| float <strong>texture</strong>(samplerCubeShadow <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>texture</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>texture</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br> |
| float <strong>texture</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>)<br> |
| float <strong>texture</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>compare</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Use the texture coordinate <em>P</em> to do a texture lookup in the texture |
| currently bound to <em>sampler</em>.</p> |
| <p class="tableblock"> For shadow forms: When <em>compare</em> is present, it is used as <em>D<sub>ref</sub></em> |
| and the array layer comes from the last component of <em>P</em>. |
| When <em>compare</em> is not present, the last component of <em>P</em> is used as |
| <em>D<sub>ref</sub></em> and the array layer comes from the second to last component |
| of <em>P</em>.</p> |
| <p class="tableblock"> For non-shadow forms: the array layer comes from the last component of |
| <em>P</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureProj</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br> |
| float <strong>textureProj</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with projection. |
| The texture coordinates consumed from <em>P</em>, not including the last |
| component of <em>P</em>, are divided by the last component of <em>P</em> to |
| form projected coordinates <em>P'</em>. |
| The resulting third component of <em>P</em> in the shadow forms is used as |
| <em>D<sub>ref</sub></em>. |
| The third component of <em>P</em> is ignored when <em>sampler</em> has type |
| <strong>gsampler2D</strong> and <em>P</em> has type <strong>vec4</strong>. |
| After these values are computed, texture lookup proceeds as in |
| <strong>texture</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLod</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureLod</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureLod</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br> |
| float <strong>textureLod</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureLod</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureLod</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Do a texture lookup as in <strong>texture</strong> but with explicit level-of-detail; |
| <em>lod</em> specifies <span class="eq">λ<sub>base</sub>]</span> and sets the partial derivatives |
| as follows:<br> |
| (See section 8.14 “Texture Minification” and equations 8.4-8.6 of |
| the <a href="#references">OpenGL ES Specification</a>.)<br> |
| <br> |
| <span class="eq">∂u / ∂x = |
| ∂v / ∂x = |
| ∂w / ∂x = 0</span> |
| <br> |
| <span class="eq">∂u / ∂y = |
| ∂v / ∂y = |
| ∂w / ∂y = 0</span></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br> |
| float <strong>textureOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup as in <strong>texture</strong> but with <em>offset</em> added to the |
| <span class="eq">(u,v,w)</span> texel coordinates before looking up each texel. |
| The offset value must be a constant expression. |
| A limited range of offset values are supported; the minimum and |
| maximum offset values are implementation-dependent and given by |
| <em>gl_MinProgramTexelOffset</em> and <em>gl_MaxProgramTexelOffset</em>, |
| respectively.</p> |
| <p class="tableblock"> Note that <em>offset</em> does not apply to the layer coordinate for texture |
| arrays. |
| This is explained in detail in section 8.14.2 “Coordinate Wrapping |
| and Texel Selection” of the <a href="#references">OpenGL ES Specification</a>, where <em>offset</em> |
| is <span class="eq">(δ<sub>u</sub>, δ<sub>v</sub>, δ<sub>w</sub>)</span>.<br> |
| Note that texel offsets are also not supported for cube maps.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetch</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>)<br> |
| gvec4 <strong>texelFetch</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>) |
| gvec4 <strong>texelFetch</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>)<br> |
| gvec4 <strong>texelFetch</strong>(gsamplerBuffer <em>sampler</em>, int <em>P</em>)<br> |
| gvec4 <strong>texelFetch</strong>(gsampler2DMS <em>sampler</em>, ivec2 <em>P</em>, int <em>sample</em>)<br> |
| gvec4 <strong>texelFetch</strong>(gsampler2DMSArray <em>sampler</em>, ivec3 <em>P</em>, int <em>sample</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Use integer texture coordinate <em>P</em> to lookup a single texel from |
| <em>sampler</em>. |
| The array layer comes from the last component of <em>P</em> for the array |
| forms. |
| The level-of-detail <em>lod</em> (if present) is as described in sections |
| 11.1.3.2 “Texel Fetches” and 8.14.1 “Scale Factor and Level of |
| Detail” of the <a href="#references">OpenGL ES Specification</a>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetchOffset</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>texelFetchOffset</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec3 <em>offset</em>)<br> |
| gvec4 <strong>texelFetchOffset</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Fetch a single texel as in <strong>texelFetch</strong>, offset by <em>offset</em> as |
| described in <strong>textureOffset</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br> |
| gvec4 <strong>textureProjOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br> |
| float <strong>textureProjOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup as described in <strong>textureProj</strong>, offset |
| by <em>offset</em> as described in <strong>textureOffset</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLodOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureLodOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br> |
| float <strong>textureLodOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureLodOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset texture lookup with explicit level-of-detail. |
| See <strong>textureLod</strong> and <strong>textureOffset</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br> |
| gvec4 <strong>textureProjLod</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br> |
| float <strong>textureProjLod</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup with explicit level-of-detail. |
| See <strong>textureProj</strong> and <strong>textureLod</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureProjLodOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br> |
| float <strong>textureProjLodOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset projective texture lookup with explicit level-of-detail. |
| See <strong>textureProj</strong>, <strong>textureLod</strong>, and <strong>textureOffset</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGrad</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br> |
| gvec4 <strong>textureGrad</strong>(gsampler3D <em>sampler</em>, <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br> |
| gvec4 <strong>textureGrad</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br> |
| float <strong>textureGrad</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br> |
| float <strong>textureGrad</strong>(samplerCubeShadow <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br> |
| float <strong>textureGrad</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br> |
| gvec4 <strong>textureGrad</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Do a texture lookup as in <strong>texture</strong> but with <a href="#explicit-gradients">explicit gradients</a> as shown below. |
| The partial derivatives of <em>P</em> are with respect to window <em>x</em> and |
| window <em>y</em>. |
| For the cube version, the partial derivatives of <em>P</em> are assumed to be |
| in the coordinate system used before texture coordinates are projected |
| onto the appropriate cube face.</p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGradOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureGradOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br> |
| float <strong>textureGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureGradOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br> |
| float <strong>textureGradOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with both explicit gradient and offset, as |
| described in <strong>textureGrad</strong> and <strong>textureOffset</strong>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br> |
| gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br> |
| gvec4 <strong>textureProjGrad</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br> |
| float <strong>textureProjGrad</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup both projectively, as described in <strong>textureProj</strong>, |
| and with explicit gradient as described in <strong>textureGrad</strong>. |
| The partial derivatives <em>dPdx</em> and <em>dPdy</em> are assumed to be already |
| projected.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br> |
| gvec4 <strong>textureProjGradOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br> |
| float <strong>textureProjGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup projectively and with explicit gradient as |
| described in <strong>textureProjGrad</strong>, as well as with offset, as described in |
| <strong>textureOffset</strong>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="explicit-gradients">8.9.3. Explicit Gradients</h4> |
| <div class="paragraph"> |
| <p>In the <strong>textureGrad</strong> functions described above, explicit gradients control |
| texture lookups as follows:</p> |
| </div> |
| <div class="stemblock"> |
| <div class="content"> |
| \[\begin{aligned} |
| \frac{\partial{s}}{\partial{x}} & = \frac{\partial{P.s}}{\partial{x}} \\[0.8em] |
| \frac{\partial{s}}{\partial{y}} & = \frac{\partial{P.s}}{\partial{y}} \\[0.8em] |
| \frac{\partial{t}}{\partial{x}} & = \frac{\partial{P.t}}{\partial{x}} \\[0.8em] |
| \frac{\partial{t}}{\partial{y}} & = \frac{\partial{P.t}}{\partial{y}} \\[0.8em] |
| \frac{\partial{r}}{\partial{x}} & = |
| \begin{cases} |
| 0.0, & \text{for 2D} \\[0.8em] |
| \frac{\partial{P.p}}{\partial{x}}, & \text{cube, other} |
| \end{cases} \\[2.5em] |
| \frac{\partial{r}}{\partial{y}} & = |
| \begin{cases} |
| 0.0, & \text{for 2D} \\[0.8em] |
| \frac{\partial{P.p}}{\partial{y}}, & \text{cube, other} |
| \end{cases} |
| \end{aligned}\] |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="texture-gather-functions">8.9.4. Texture Gather Functions</h4> |
| <div class="paragraph"> |
| <p>The texture gather functions take components of a single floating-point |
| vector operand as a texture coordinate, determine a set of four texels to |
| sample from the base level-of-detail of the specified texture image, and |
| return one component from each texel in a four-component result vector.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When performing a texture gather operation, the minification and |
| magnification filters are ignored, and the rules for LINEAR filtering in the |
| <a href="#references">OpenGL ES Specification</a> are applied to the base level of the texture image |
| to identify the four texels <em>i<sub>0</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, and <em>i<sub>0</sub> |
| j<sub>0</sub></em>. |
| The texels are then converted to texture base colors (<em>R<sub>s</sub></em>, <em>G<sub>s</sub></em>, |
| <em>B<sub>s</sub></em>, <em>A<sub>s</sub></em>) according to table 15.1, followed by application of the |
| texture swizzle as described in section 15.2.1 “Texture Access” of the |
| <a href="#references">OpenGL ES Specification</a>. |
| A four-component vector is assembled by taking the selected component from |
| each of the post-swizzled texture source colors in the order (<em>i<sub>0</sub> j<sub>1</sub></em>, |
| <em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, <em>i<sub>0</sub> j<sub>0</sub></em>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The selected component is identified by the optional <em>comp</em> argument, where |
| the values zero, one, two, and three identify the <em>R<sub>s</sub></em>, <em>G<sub>s</sub></em>, <em>B<sub>s</sub></em>, or |
| <em>A<sub>s</sub></em> component, respectively. |
| If <em>comp</em> is omitted, it is treated as identifying the <em>R<sub>s</sub></em> component.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Incomplete textures (see section 8.16 “Texture Completeness” of the |
| <a href="#references">OpenGL ES Specification</a>) return a texture source color of (0,0,0,1) for all |
| four source texels.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For texture gather functions using a texture-combined shadow sampler type, |
| each of the four |
| texel lookups perform a depth comparison against the depth reference value |
| passed in (<em>refZ</em>), and returns the result of that comparison in the |
| appropriate component of the result vector.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As with other texture lookup functions, the results of a texture gather are |
| undefined for shadow samplers if the texture referenced is not a depth |
| texture or has depth comparisons disabled; or for non-shadow samplers if the |
| texture referenced is a depth texture with depth comparisons enabled.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <strong>textureGatherOffset</strong> built-in functions from the OpenGL ES Shading Language return a vector |
| derived from sampling four texels in the image array of level <em>level<sub>base</sub></em>. |
| For each of the four texel offsets specified by the <em>offsets</em> argument, the |
| rules for the LINEAR minification filter are applied to identify a 2 × |
| 2 texel footprint, from which the single texel T<sub>i0j0</sub> is selected. |
| A four-component vector is then assembled by taking a single component from |
| each of the four T<sub>i0j0</sub> texels in the same manner as for the |
| <strong>textureGather</strong> function.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGather</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, int <em>comp</em>])<br> |
| gvec4 <strong>textureGather</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br> |
| gvec4 <strong>textureGather</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br> |
| gvec4 <strong>textureGather</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>[, int <em>comp</em>])<br> |
| vec4 <strong>textureGather</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>)<br> |
| vec4 <strong>textureGather</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br> |
| vec4 <strong>textureGather</strong>(samplerCubeShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br> |
| vec4 <strong>textureGather</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>refZ</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Returns the value<br></p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">vec4(Sample_i0_j1(P, base).comp, |
| Sample_i1_j1(P, base).comp, |
| Sample_i1_j0(P, base).comp, |
| Sample_i0_j0(P, base).comp)</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If specified, the value of <em>comp</em> must be a constant integer expression with |
| a value of 0, 1, 2, or 3, identifying the <em>x</em>, <em>y</em>, <em>z</em>, or <em>w</em> |
| post-swizzled component of the four-component vector lookup result for each |
| texel, respectively. |
| If <em>comp</em> is not specified, it is treated as 0, selecting the <em>x</em> component |
| of each texel to generate the result.</p> |
| </div> |
| </div> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em>, [ int <em>comp</em>])<br> |
| gvec4 <strong>textureGatherOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [ int <em>comp</em>])<br> |
| vec4 <strong>textureGatherOffset</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br> |
| vec4 <strong>textureGatherOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Perform a texture gather operation as in <strong>textureGather</strong> by <em>offset</em> |
| as described in <strong>textureOffset</strong> except that the <em>offset</em> can be |
| variable (non constant) and the implementation-dependent minimum and |
| maximum offset values are given by MIN_PROGRAM_TEXTURE_GATHER_OFFSET |
| and MAX_PROGRAM_TEXTURE_GATHER_OFFSET, respectively.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffsets</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offsets</em>[4] [, int <em>comp</em>])<br> |
| gvec4 <strong>textureGatherOffsets</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offsets</em>[4] [, int <em>comp</em>])<br> |
| vec4 <strong>textureGatherOffsets</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br> |
| vec4 <strong>textureGatherOffsets</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Operate identically to <strong>textureGatherOffset</strong> except that <em>offsets</em> is |
| used to determine the location of the four texels to sample. |
| Each of the four texels is obtained by applying the corresponding |
| offset in <em>offsets</em> as a (<em>u</em>, <em>v</em>) coordinate offset to <em>P</em>, |
| identifying the four-texel LINEAR footprint, and then selecting the |
| texel <em>i<sub>0</sub> j<sub>0</sub></em> of that footprint. |
| The specified values in <em>offsets</em> must be constant integral |
| expressions.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="atomic-counter-functions">8.10. Atomic Counter Functions</h3> |
| <div class="paragraph"> |
| <p>The atomic-counter operations in this section operate atomically with |
| respect to each other. |
| They are atomic for any single counter, meaning any of these operations on a |
| specific counter in one shader instantiation will be indivisible by any of |
| these operations on the same counter from another shader instantiation. |
| There is no guarantee that these operations are atomic with respect to other |
| forms of access to the counter or that they are serialized when applied to |
| separate counters. |
| Such cases would require additional use of fences, barriers, or other forms |
| of synchronization, if atomicity or serialization is desired.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The underlying counter is a 32-bit unsigned integer. |
| The result of operations will wrap to [0, 2<sup>32</sup>-1].</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterIncrement</strong>(atomic_uint <em>c</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Atomically<br></p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>increments the counter for <em>c</em>, and</p> |
| </li> |
| <li> |
| <p>returns its value prior to the increment operation.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>These two steps are done atomically with respect to the atomic counter |
| functions in this table.</p> |
| </div> |
| </div> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterDecrement</strong>(atomic_uint <em>c</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p>Atomically<br></p> |
| </div> |
| <div class="openblock"> |
| <div class="content"> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>decrements the counter for <em>c</em>, and</p> |
| </li> |
| <li> |
| <p>returns the value resulting from the decrement operation.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>These two steps are done atomically with respect to the atomic counter |
| functions in this table.</p> |
| </div> |
| </div> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounter</strong>(atomic_uint <em>c</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the counter value for <em>c</em>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="atomic-memory-functions">8.11. Atomic Memory Functions</h3> |
| <div class="paragraph"> |
| <p>Atomic memory functions perform atomic operations on an individual signed or |
| unsigned integer stored in buffer object or shared variable storage. |
| All of the atomic memory operations read a value from memory, compute a new |
| value using one of the operations described below, write the new value to |
| memory, and return the original value read. |
| The contents of the memory being updated by the atomic operation are |
| guaranteed not to be modified by any other assignment or atomic memory |
| function in any shader invocation between the time the original value is |
| read and the time the new value is written.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic memory functions are supported only for a limited set of variables. |
| A shader will fail to compile if the value passed to the <em>mem</em> argument of |
| an atomic memory function does not correspond to a buffer or shared |
| variable. |
| It is acceptable to pass an element of an array or a single component of a |
| vector to the <em>mem</em> argument of an atomic memory function, as long as the |
| underlying array or vector is a buffer or shared variable.</p> |
| </div> |
| <div class="paragraph"> |
| <p>All the built-in functions in this section accept arguments with |
| combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification, |
| despite not having them listed in the prototypes. |
| The atomic operation will operate as required by the calling argument’s |
| memory qualification, not by the built-in function’s formal parameter memory |
| qualification.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAdd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicAdd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents |
| <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMin</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicMin</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and |
| the contents of <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMax</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicMax</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value of <em>data</em> and |
| the contents of <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAnd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicAnd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of |
| <em>data</em> and the contents of <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicOr</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicOr</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of |
| <em>data</em> and the contents of <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicXor</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicXor</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the |
| value of <em>data</em> and the contents of <em>mem</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicExchange</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br> |
| int <strong>atomicExchange</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCompSwap</strong>(inout uint <em>mem</em>, uint <em>compare</em>, uint <em>data</em>)<br> |
| int <strong>atomicCompSwap</strong>(inout int <em>mem</em>, int <em>compare</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of <em>mem</em>. |
| If the values are equal, the new value is given by <em>data</em>; otherwise, |
| it is taken from the original contents of <em>mem</em>.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="image-functions">8.12. Image Functions</h3> |
| <div class="paragraph"> |
| <p>Variables using one of the image basic types may be used by the built-in |
| shader image memory functions defined in this section to read and write |
| individual texels of a texture. |
| Each image variable references an image unit, which has a texture image |
| attached.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When image memory functions below access memory, an individual texel in the |
| image is identified using an (<em>i</em>), (<em>i, j</em>), or (<em>i, j, k</em>) coordinate |
| corresponding to the values of <em>P</em>. |
| The coordinates |
| are used to select an individual texel in the manner described in section |
| 8.22 |
| “Texture Image Loads and Stores” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Loads and stores support float, integer, and unsigned integer types. |
| The data types below starting <code>gimage</code> serve as placeholders meaning |
| types starting either “<strong>image</strong>”, “<strong>iimage</strong>”, or “<strong>uimage</strong>” in the same |
| way as "<strong>gvec</strong>" or "<strong>gsampler</strong>" in earlier sections.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>IMAGE_PARAMS</em> in the prototypes below is a placeholder representing |
| 18 |
| separate functions, each for a different type of image variable. |
| The <em>IMAGE_PARAMS</em> placeholder is replaced by one of the following parameter |
| lists:</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimage2D <em>image</em>, ivec2 <em>P</em></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimage3D <em>image</em>, ivec3 <em>P</em></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimageCube <em>image</em>, ivec3 <em>P</em></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimageBuffer <em>image</em>, int <em>P</em></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimage2DArray <em>image</em>, ivec3 <em>P</em></p> |
| </dd> |
| <dt class="hdlist1"></dt> |
| <dd> |
| <p>gimageCubeArray <em>image</em>, ivec3 <em>P</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>where each of the lines represents one of three different image variable |
| types, and <em>image</em>, |
| <em>P</em> |
| specify the individual texel to operate on. |
| The method for identifying the individual texel operated on from <em>image</em>, |
| <em>P</em>, |
| and the method for reading and writing the texel are specified in section |
| 8.22 |
| “Texture Image Loads and Stores” of the <a href="#references">OpenGL ES Specification</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The atomic functions perform operations on individual texels or samples of |
| an image variable. |
| Atomic memory operations read a value from the selected texel, compute a new |
| value using one of the operations described below, write the new value to |
| the selected texel, and return the original value read. |
| The contents of the texel being updated by the atomic operation are |
| guaranteed not to be modified by any other image store or atomic function |
| between the time the original value is read and the time the new value is |
| written.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Atomic memory operations are supported on only a subset of all image |
| variable types; <em>image</em> must be either:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>a signed integer image variable (type starts “<strong>iimage</strong>”) and a format |
| qualifier of <strong>r32i</strong>, used with a <em>data</em> argument of type <strong>int</strong>, or</p> |
| </li> |
| <li> |
| <p>an unsigned integer image variable (type starts “<strong>uimage</strong>”) and a |
| format qualifier of <strong>r32ui</strong>, used with a <em>data</em> argument of type <strong>uint</strong>, |
| or</p> |
| </li> |
| <li> |
| <p>a float image variable (type starts “<strong>image</strong>”) and a format qualifier |
| of <strong>r32f</strong>, used with a <em>data</em> argument of type <strong>float</strong> |
| (<strong>imageAtomicExchange</strong> only).</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>All the built-in functions in this section accept arguments with |
| combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification, |
| despite not having them listed in the prototypes. |
| The image operation will operate as required by the calling argument’s |
| memory qualification, not by the built-in function’s formal parameter memory |
| qualification.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp ivec2 <strong>imageSize</strong>(readonly writeonly gimage2D <em>image</em>)<br> |
| highp ivec3 <strong>imageSize</strong>(readonly writeonly gimage3D <em>image</em>)<br> |
| highp ivec2 <strong>imageSize</strong>(readonly writeonly gimageCube <em>image</em>)<br> |
| highp ivec3 <strong>imageSize</strong>(readonly writeonly gimageCubeArray <em>image</em>)<br> |
| highp ivec3 <strong>imageSize</strong>(readonly writeonly gimage2DArray <em>image</em>)<br> |
| highp int <strong>imageSize</strong>(readonly writeonly gimageBuffer <em>image</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of the image or images bound to <em>image</em>. |
| For arrayed images, the last component of the return value will hold |
| the size of the array. |
| Cube images only return the dimensions of one face, and the number of |
| cubes in the cube map array, if arrayed.<br> |
| Note: The qualification <strong>readonly writeonly</strong> accepts a variable |
| qualified with <strong>readonly</strong>, <strong>writeonly</strong>, both, or neither. |
| It means the formal argument will be used for neither reading nor |
| writing to the underlying memory.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp gvec4 <strong>imageLoad</strong>(readonly <em>IMAGE_PARAMS</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Loads the texel at the coordinate <em>P</em> from the image unit <em>image</em> (in |
| <em>IMAGE_PARAMS</em>). |
| When <em>image</em> and <em>P</em> |
| identify a valid texel, the bits used to represent the selected texel in |
| memory are converted to a <strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong> in the manner |
| described in section |
| 8.23 |
| “Texture Image Loads and Stores” of the |
| <a href="#references">OpenGL ES Specification</a> and returned.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>imageStore</strong>(writeonly <em>IMAGE_PARAMS</em>, gvec4 <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Stores <em>data</em> into the texel at the coordinate <em>P</em> from the image |
| specified by <em>image</em>. |
| When <em>image</em> and <em>P</em> |
| identify a valid texel, the bits used to represent <em>data</em> are converted |
| to the format of the image unit in the manner described in section |
| 8.23 |
| “Texture Image Loads and Stores” of the <a href="#references">OpenGL ES Specification</a> |
| and stored to the specified texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents of |
| the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and |
| the contents of the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value <em>data</em> and the |
| contents of the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of |
| <em>data</em> and the contents of the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of |
| <em>data</em> and the contents of the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the |
| value of <em>data</em> and the contents of the selected texel.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)<br> |
| highp float <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, float <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, uint <em>compare</em>, uint <em>data</em>)<br> |
| highp int <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, int <em>compare</em>, int <em>data</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of the selected |
| texel. |
| If the values are equal, the new value is given by <em>data</em>; otherwise, |
| it is taken from the original value loaded from the texel.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="geometry-shader-functions">8.13. Geometry Shader Functions</h3> |
| <div class="paragraph"> |
| <p>These functions are only available in geometry shaders. |
| They are described in more depth following the table.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EmitVertex</strong>()<br></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Emits the current values of output variables to the current output |
| primitive. |
| On return from this call, the values of output variables are |
| undefined.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EndPrimitive</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Completes the current output primitive and starts a new one. |
| No vertex is emitted.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The function <strong>EmitVertex</strong>() specifies that a vertex is completed. |
| A vertex is added to the current output primitive using the current values |
| of all built-in and user-defined output variables. |
| The values of all output variables are undefined after a call to |
| <strong>EmitVertex</strong>(). |
| If a geometry shader invocation has emitted more vertices than permitted by |
| the output layout qualifier <strong>max_vertices</strong>, the results of calling |
| <strong>EmitVertex</strong>() are undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The function <strong>EndPrimitive</strong>() specifies that the current output primitive is |
| completed and a new output primitive (of the same type) will be started by |
| any subsequent <strong>EmitVertex</strong>(). |
| This function does not emit a vertex. |
| If the output layout is declared to be <strong>points</strong>, calling <strong>EndPrimitive</strong>() is |
| optional.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A geometry shader starts with an output primitive containing no vertices. |
| When a geometry shader terminates, the current output primitive is |
| automatically completed. |
| It is not necessary to call <strong>EndPrimitive</strong>() if the geometry shader writes |
| only a single primitive.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="fragment-processing-functions">8.14. Fragment Processing Functions</h3> |
| <div class="paragraph"> |
| <p>Fragment processing functions are only available in fragment shaders.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="derivative-functions">8.14.1. Derivative Functions</h4> |
| <div class="paragraph"> |
| <p>Derivatives may be computationally expensive and/or numerically unstable. |
| Therefore, an implementation may approximate the true derivatives |
| by using a fast but not entirely accurate derivative computation. |
| Derivatives are undefined within non-uniform control flow.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The expected behavior of a derivative is specified using forward/backward |
| differencing.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Forward differencing:</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(F(x+dx) - F(x) \sim dFdx(x) \cdot dx (1a)\)</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(dFdx(x) \sim \frac{F(x+dx) - F(x)}{dx} (1b)\)</p> |
| </div> |
| <div class="paragraph"> |
| <p>Backward differencing:</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(F(x-dx) - F(x) \sim -dFdx(x) \cdot dx (2a)\)</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(dFdx(x) \sim \frac{F(x) - F(x-dx)}{dx} (2b)\)</p> |
| </div> |
| <div class="paragraph"> |
| <p>With single-sample rasterization, \(dx \leq 1.0\) in equations 1b |
| and 2b. |
| For multisample rasterization, \(dx < 2.0\) in equations 1b and 2b.</p> |
| </div> |
| <div class="paragraph"> |
| <p>\(dFdy\) is approximated similarly, with <em>y</em> replacing <em>x</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An implementation may use the above or other methods to perform |
| the calculation, subject to the following conditions:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>The method may use piecewise linear approximations. |
| Such linear approximations imply that higher order derivatives, |
| <strong>dFdx</strong>(<strong>dFdx</strong>(<em>x</em>)) and above, are undefined.</p> |
| </li> |
| <li> |
| <p>The method may assume that the function evaluated is continuous. |
| Therefore derivatives within the body of a non-uniform conditional are |
| undefined.</p> |
| </li> |
| <li> |
| <p>The method may differ per fragment, subject to the constraint that the |
| method may vary by window coordinates, not screen coordinates. |
| The invariance requirement described in section 13.2 “Invariance” of |
| the <a href="#references">OpenGL ES Specification</a>, is relaxed for derivative calculations, |
| because the method may be a function of fragment location.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Other properties that are desirable, but not required, are:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>Functions should be evaluated within the interior of a primitive |
| (interpolated, not extrapolated).</p> |
| </li> |
| <li> |
| <p>Functions for <strong>dFdx</strong> should be evaluated while holding <em>y</em> constant. |
| Functions for <strong>dFdy</strong> should be evaluated while holding <em>x</em> constant. |
| However, mixed higher order derivatives, like <strong>dFdx</strong>(<strong>dFdy</strong>(<em>y</em>)) and |
| <strong>dFdy</strong>(<strong>dFdx</strong>(<em>x</em>)) are undefined.</p> |
| </li> |
| <li> |
| <p>Derivatives of constant arguments should be 0.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>In some implementations, varying degrees of derivative accuracy may be |
| obtained by providing GL hints (see section 19.1 “Hints” of the |
| <a href="#references">OpenGL ES Specification</a>), allowing a user to make an image quality versus |
| speed trade off.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdx</strong>(genFType <em>p</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the derivative in x using local differencing for the input |
| argument <em>p</em>.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdy</strong>(genFType <em>p</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the derivative in y using local differencing for the input |
| argument <em>p</em>.<br> |
| <br> |
| These two functions are commonly used to estimate the filter width used |
| to anti-alias procedural textures. We are assuming that the expression |
| is being evaluated in parallel on a SIMD array so that at any given |
| point in time the value of the function is known at the grid points |
| represented by the SIMD array. Local differencing between SIMD array |
| elements can therefore be used to derive <strong>dFdx</strong>, <strong>dFdy</strong>, etc.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fwidth</strong>(genFType <em>p</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the sum of the absolute derivative in x and y using local |
| differencing for the input argument <em>p</em>, i.e., <strong>abs</strong>(<strong>dFdx</strong>(<em>p</em>)) |
| + <strong>abs</strong>(<strong>dFdy</strong>(<em>p</em>));</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="interpolation-functions">8.14.2. Interpolation Functions</h4> |
| <div class="paragraph"> |
| <p>Built-in interpolation functions are available to compute an interpolated |
| value of a fragment shader input variable at a shader-specified (<em>x</em>, <em>y</em>) |
| location. |
| A separate (<em>x</em>, <em>y</em>) location may be used for each invocation of the |
| built-in function, and those locations may differ from the default (<em>x</em>, |
| <em>y</em>) location used to produce the default value of the input. |
| For the <strong>interpolateAt*</strong> functions, the call will return a precision |
| qualification matching the precision of the <em>interpolant</em> argument to the |
| function call.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For all of the interpolation functions, <em>interpolant</em> must be an l-value |
| from an <strong>in</strong> declaration; |
| this can be either a variable, or an array element. |
| Component selection operators (e.g. <strong>.xy</strong>) may not be used when specifying <em>interpolant</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If <em>interpolant</em> is declared with the <strong>flat</strong> qualifier, the interpolated |
| value will have the same value everywhere for a single primitive, so the |
| location used for interpolation has no effect and the functions just return |
| that same value. |
| If <em>interpolant</em> is declared with the <strong>centroid</strong> qualifier, the value |
| returned by <strong>interpolateAtSample</strong>() and <strong>interpolateAtOffset</strong>() will be |
| evaluated at the specified location, ignoring the location normally used |
| with the <strong>centroid</strong> qualifier.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtCentroid</strong>(float <em>interpolant</em>)<br> |
| vec2 <strong>interpolateAtCentroid</strong>(vec2 <em>interpolant</em>)<br> |
| vec3 <strong>interpolateAtCentroid</strong>(vec3 <em>interpolant</em>)<br> |
| vec4 <strong>interpolateAtCentroid</strong>(vec4 <em>interpolant</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> sampled at a location |
| inside both the pixel and the primitive being processed. |
| The value obtained would be the same value assigned to the input |
| variable if declared with the <strong>centroid</strong> qualifier.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtSample</strong>(float <em>interpolant</em>, int <em>sample</em>)<br> |
| vec2 <strong>interpolateAtSample</strong>(vec2 <em>interpolant</em>, int <em>sample</em>)<br> |
| vec3 <strong>interpolateAtSample</strong>(vec3 <em>interpolant</em>, int <em>sample</em>)<br> |
| vec4 <strong>interpolateAtSample</strong>(vec4 <em>interpolant</em>, int <em>sample</em>)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable at the location |
| of sample number <em>sample</em>. |
| If multisample buffers are not available, the input variable will be |
| evaluated at the center of the pixel. |
| If sample <em>sample</em> does not exist, the position used to interpolate |
| the input variable is undefined.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtOffset</strong>(float <em>interpolant</em>, vec2 offset)<br> |
| vec2 <strong>interpolateAtOffset</strong>(vec2 <em>interpolant</em>, vec2 offset)<br> |
| vec3 <strong>interpolateAtOffset</strong>(vec3 <em>interpolant</em>, vec2 offset)<br> |
| vec4 <strong>interpolateAtOffset</strong>(vec4 <em>interpolant</em>, vec2 offset)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable sampled at an |
| offset from the center of the pixel specified by <em>offset</em>. |
| The two floating-point components of <em>offset</em>, give the offset in |
| pixels in the <em>x</em> and <em>y</em> directions, respectively.<br> |
| An offset of (0, 0) identifies the center of the pixel. |
| The range and granularity of offsets supported by this function is |
| implementation-dependent.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="shader-invocation-control-functions">8.15. Shader Invocation Control Functions</h3> |
| <div class="paragraph"> |
| <p>The shader invocation control function is only available in tessellation |
| control and compute shaders. |
| It is used to control the relative execution order of multiple shader |
| invocations used to process a patch (in the case of tessellation control |
| shaders) or a workgroup (in the case of compute shaders), which are |
| otherwise executed with an undefined relative order.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>barrier</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">For any given static instance of <strong>barrier</strong>(), all tessellation control |
| shader invocations for a single input patch must enter it before any |
| will be allowed to continue beyond it, or all compute shader |
| invocations for a single workgroup must enter it before any will |
| continue beyond it.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The function <strong>barrier</strong>() provides a partially defined order of execution |
| between shader invocations. |
| The ensures that, for some types of memory accesses, values written by one |
| invocation prior to a given static instance of <strong>barrier</strong>() can be safely read |
| by other invocations after their call to the same static instance <strong>barrier</strong>(). |
| Because invocations may execute in an undefined order between these barrier |
| calls, the values of a per-vertex or per-patch output variable for tessellation |
| control shaders, or the values of <strong>shared</strong> variables for compute shaders will be |
| undefined in a number of cases enumerated in |
| “<a href="#output-variables">Output Variables</a>” (for tessellation control shaders) |
| and “<a href="#shared-variables">Shared Variables</a>” (for compute shaders).</p> |
| </div> |
| <div class="paragraph"> |
| <p>For tessellation control shaders, the <strong>barrier</strong>() function may only be |
| placed inside the function <strong>main</strong>() of the shader and may not be called |
| within any control flow. |
| Barriers are also disallowed after a return statement in the function |
| <strong>main</strong>(). |
| Any such misplaced barriers result in a compile-time error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A <strong>barrier</strong>() affects control flow but only synchronizes memory accesses |
| to <strong>shared</strong> variables and tessellation control output variables. |
| For other memory accesses, it does not ensure that values written by one invocation |
| prior to a given static instance of <strong>barrier</strong>() can be safely read by other |
| invocations after their call to the same static instance of <strong>barrier</strong>(). |
| To achieve this requires the use of both <strong>barrier</strong>() and a memory barrier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For compute shaders, the <strong>barrier</strong>() function may be placed within control |
| flow, but that control flow must be uniform control flow. |
| That is, all the controlling expressions that lead to execution of the |
| barrier must be dynamically uniform expressions. |
| This ensures that if any shader invocation enters a conditional statement, |
| then all invocations will enter it. |
| While compilers are encouraged to give warnings if they can detect this |
| might not happen, compilers cannot completely determine this. |
| Hence, it is the author’s responsibility to ensure <strong>barrier</strong>() only exists |
| inside uniform control flow. |
| Otherwise, some shader invocations will stall indefinitely, waiting for a |
| barrier that is never reached by other invocations.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="shader-memory-control-functions">8.16. Shader Memory Control Functions</h3> |
| <div class="paragraph"> |
| <p>Within a single shader invocation, the visibility and order of writes made |
| by that invocation are well-defined. |
| However, the relative order of reads and writes to a single shared memory |
| address from multiple separate shader invocations is largely undefined. |
| Additionally, the order of accesses to multiple memory addresses performed |
| by a single shader invocation, as observed by other shader invocations, is |
| also undefined.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following built-in functions can be used to control the ordering of |
| reads and writes:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrier</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions issued by a single shader |
| invocation.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierAtomicCounter</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of accesses to atomic-counter variables issued by |
| a single shader invocation.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierBuffer</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to buffer variables issued |
| within a single shader invocation.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierShared</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to shared variables issued |
| within a single shader invocation, as viewed by other invocations in |
| the same workgroup.<br> |
| Only available in compute shaders.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierImage</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to images issued within a |
| single shader invocation.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>groupMemoryBarrier</strong>()</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of all memory transactions issued within a single |
| shader invocation, as viewed by other invocations in the same workgroup.<br> |
| Only available in compute shaders.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The memory barrier built-in functions can be used to order reads and writes |
| to variables stored in memory accessible to other shader invocations. |
| When called, these functions will wait for the completion of all reads and |
| writes previously performed by the caller that access selected variable |
| types, and then return with no other effect. |
| The built-in functions <strong>memoryBarrierAtomicCounter</strong>(), |
| <strong>memoryBarrierBuffer</strong>(), <strong>memoryBarrierImage</strong>(), and <strong>memoryBarrierShared</strong>() |
| wait for the completion of accesses to atomic counter, buffer, image, and |
| shared variables, respectively. |
| The built-in functions <strong>memoryBarrier</strong>() and <strong>groupMemoryBarrier</strong>() wait for |
| the completion of accesses to all of the above variable types. |
| The functions <strong>memoryBarrierShared</strong>() and <strong>groupMemoryBarrier</strong>() are |
| available only in compute shaders; the other functions are available in all |
| shader types.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When these functions return, the effects of any memory stores performed |
| using coherent variables prior to the call will be visible to any |
| future<sup>1</sup> coherent access to the same memory performed by any other shader |
| invocation. |
| In particular, the values written this way in one shader stage are |
| guaranteed to be visible to coherent memory accesses performed by shader |
| invocations in subsequent stages when those invocations were triggered by |
| the execution of the original shader invocation (e.g. fragment shader |
| invocations for a primitive resulting from a particular geometry |
| shader invocation).</p> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">1</dt> |
| <dd> |
| <p>An access is only a <em>future</em> access if a <em>happens-before</em> relation can |
| be established between the store and the load.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="paragraph"> |
| <p>Additionally, memory barrier functions order stores performed by the calling |
| invocation, as observed by other shader invocations. |
| Without memory barriers, if one shader invocation performs two stores to |
| coherent variables, a second shader invocation might see the values written |
| by the second store prior to seeing those written by the first. |
| However, if the first shader invocation calls a memory barrier function |
| between the two stores, selected other shader invocations will never see the |
| results of the second store before seeing those of the first. |
| When using the functions <strong>groupMemoryBarrier</strong>() or <strong>memoryBarrierShared</strong>(), |
| this ordering guarantee applies only to other shader invocations in the same |
| compute shader workgroup; all other memory barrier functions provide the |
| guarantee to all other shader invocations. |
| No memory barrier is required to guarantee the order of memory stores as |
| observed by the invocation performing the stores; an invocation reading from |
| a variable that it previously wrote will always see the most recently |
| written value unless another shader invocation also wrote to the same |
| memory.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_subpass_input_functions">8.17. Subpass-Input Functions</h3> |
| <div class="paragraph"> |
| <p>Subpass-input functions are only available when targeting a Vulkan fragment stage.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass inputs are read through the built-in functions below. The <code>g</code> is again |
| a placeholder for either nothing, <code>i</code>, or <code>u</code>, indicating either a floating-point, |
| signed integer, or unsigned integer, and these must match between argument type |
| and return type.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Syntax</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>subpassLoad</strong>(gsubpassInput subpass)<br> |
| gvec4 <strong>subpassLoad</strong>(gsubpassInputMS subpass, int sample)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Read from a subpass input, from the implicit location <em>(x, y, layer)</em> |
| of the current fragment coordinate.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="shader-interface-matching">9. Shader Interface Matching</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>As described in chapter 7 of the <a href="#references">OpenGL ES Specification</a>, shaders may be |
| linked together to form a <em>program object</em> before being bound to the |
| pipeline or may be linked and bound individually as <em>separable program |
| objects</em>.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="title">Note</div> |
| <div class="paragraph"> |
| <p>These were previously known as separate shader objects (SSOs) but the |
| mechanism has been extended to support future versions of the specification |
| that have more than two shader stages. |
| It allows a subset of the shaders to be linked together.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>Within a <em>program object</em> or a <em>separable program object</em>, qualifiers for |
| matching variables must themselves match according to the rules specified in |
| this section. |
| There are also matching rules for qualifiers of matching variables between |
| separable program objects but only for variables across an input/output |
| boundary between shader stages. |
| For other shader interface variables such as uniforms, each program object |
| or separable program object has its own name space and so the same name can |
| refer to multiple independent variables. |
| Consequently, there are no matching rules for qualifiers in these cases.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="input-output-matching-by-name-in-linked-programs">9.1. Input Output Matching by Name in Linked Programs</h3> |
| <div class="paragraph"> |
| <p>When linking shaders, the type of declared vertex outputs and fragment |
| inputs with the same name must match, otherwise the link command will fail. |
| Only those fragment inputs statically used (i.e. read) in the fragment |
| shader must be declared as outputs in the vertex shader; declaring |
| superfluous vertex shader outputs is permissible.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following table summarizes the rules for matching shader outputs to |
| shader inputs in consecutive stages when shaders are linked together.</p> |
| </div> |
| <table class="tableblock frame-all grid-all fit-content"> |
| <colgroup> |
| <col> |
| <col> |
| <col> |
| <col> |
| <col> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top" colspan="2" rowspan="2"><p class="tableblock">Treatment of Mismatched Input Variables</p></td> |
| <td class="tableblock halign-left valign-top" colspan="3"><p class="tableblock">Consuming Shader (input variables)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Declared but no Static Use</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Declared and Static Use</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top" rowspan="3"><p class="tableblock">Generating Shader (output variables)</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Declares; no static Use</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are undefined)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Declares and static Use</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are potentially undefined)</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>See “<a href="#static-use">Static Use</a>” for the definition of <em>static use</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The precision of a vertex output does not need to match the precision of the |
| corresponding fragment input. |
| The minimum precision at which vertex outputs are interpolated is the |
| minimum of the vertex output precision and the fragment input precision, |
| with the exception that for <strong>highp</strong>, implementations do not have to support |
| full IEEE 754 precision.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The precision of values exported to a transform feedback buffer is the |
| precision of the outputs of the vertex shader. |
| However, they are converted to <strong>highp</strong> format before being written.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="matching-of-qualifiers">9.2. Matching of Qualifiers</h3> |
| <div class="paragraph"> |
| <p>The following tables summarize the requirements for matching of qualifiers. |
| It applies whenever there are two or more matching variables in a shader |
| interface.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Notes:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p><em>Yes</em> means the qualifiers must match.</p> |
| </li> |
| <li> |
| <p><em>No</em> means the qualifiers do not need to match.</p> |
| </li> |
| <li> |
| <p><em>Consistent</em> means qualifiers may be missing from a subset of |
| declarations but they cannot conflict</p> |
| </li> |
| <li> |
| <p>If there are conflicting qualifiers, only the last of these is |
| significant.</p> |
| </li> |
| <li> |
| <p>Matching is based only on the resulting qualification, not on the |
| presence or otherwise of qualifiers.</p> |
| </li> |
| <li> |
| <p>The rules apply to all declared variables, irrespective of whether they |
| are statically used, with the exception of inputs and outputs when |
| shaders are linked (see |
| “<a href="#input-output-matching-by-name-in-linked-programs">Input Output |
| Matching by Name in Linked Programs</a>”).</p> |
| </li> |
| <li> |
| <p>Errors are generated for any conflicts.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="sect3"> |
| <h4 id="linked-shaders">9.2.1. Linked Shaders</h4> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.6666%;"> |
| <col style="width: 16.667%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier Class</th> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top"><strong>in</strong>/<strong>out</strong></th> |
| <th class="tableblock halign-left valign-top">Default Uniforms</th> |
| <th class="tableblock halign-left valign-top"><strong>uniform</strong> Block</th> |
| <th class="tableblock halign-left valign-top"><strong>buffer</strong> Block</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Storage<sup>1</sup></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong><br> |
| <strong>out</strong><br> |
| <strong>uniform</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">Auxiliary</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong><br> |
| <strong>sample</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top" rowspan="5"><p class="tableblock">Layout</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes<sup>2</sup></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Consistent</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Block layout<sup>3,4</sup></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Consistent</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">format</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Interpolation</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong><br> |
| <strong>flat</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Precision</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong><br> |
| <strong>mediump</strong><br> |
| <strong>highp</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Variance</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invariant</strong><br> |
| <strong>precise</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Memory</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">all</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1">1</dt> |
| <dd> |
| <p>Storage qualifiers determine <em>when</em> variables match rather than being |
| <em>required</em> to match for matching variables. |
| Note also that each shader interface has a separate name space so for |
| example, it is possible to use the same name for a vertex output and |
| fragment uniform.</p> |
| </dd> |
| <dt class="hdlist1">2</dt> |
| <dd> |
| <p>If present, the <strong>location</strong> qualifier determines the matching of inputs |
| and outputs. |
| See section 7.4.1 “Shader interface Matching” of the |
| <a href="#references">OpenGL ES Specification</a> for details.]</p> |
| </dd> |
| <dt class="hdlist1">3</dt> |
| <dd> |
| <p>The <strong>row_major</strong> and <strong>column_major</strong> layout qualifiers do not need to |
| match when applied to non-matrix types.</p> |
| </dd> |
| <dt class="hdlist1">4</dt> |
| <dd> |
| <p>In cases where a layout qualifier overrides a previous layout qualifier |
| or a default, only the resulting qualification must match.</p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="separable-programs">9.2.2. Separable Programs</h4> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 33.3333%;"> |
| <col style="width: 33.3333%;"> |
| <col style="width: 33.3334%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Qualifier Class</th> |
| <th class="tableblock halign-left valign-top">Qualifier</th> |
| <th class="tableblock halign-left valign-top"><strong>in</strong>/<strong>out</strong></th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Storage</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong><br> |
| <strong>out</strong><br> |
| <strong>uniform</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">Auxiliary</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong><br> |
| <strong>sample</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top" rowspan="5"><p class="tableblock">Layout</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Block layout</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">format</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Interpolation</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong><br> |
| <strong>flat</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Precision</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong><br> |
| <strong>mediump</strong><br> |
| <strong>highp</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Variance</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invariant</strong><br> |
| <strong>precise</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Memory</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">all</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="shading-language-grammar">10. Shading Language Grammar</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The grammar is fed from the output of lexical analysis. |
| The tokens returned from lexical analysis are</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="paragraph"> |
| <p>CONST BOOL FLOAT INT UINT</p> |
| </div> |
| <div class="paragraph"> |
| <p>BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4</p> |
| </div> |
| <div class="paragraph"> |
| <p>MAT2 MAT3 MAT4 |
| MAT2X2 MAT2X3 MAT2X4 |
| MAT3X2 MAT3X3 MAT3X4 |
| MAT4X2 MAT4X3 MAT4X4</p> |
| </div> |
| <div class="paragraph"> |
| <p>CENTROID IN OUT INOUT UNIFORM PATCH SAMPLE BUFFER SHARED |
| COHERENT VOLATILE RESTRICT READONLY WRITEONLY |
| FLAT SMOOTH LAYOUT</p> |
| </div> |
| <div class="paragraph"> |
| <p>ATOMIC_UINT</p> |
| </div> |
| <div class="paragraph"> |
| <p>SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER2DSHADOW |
| SAMPLERCUBESHADOW SAMPLER2DARRAY SAMPLER2DARRAYSHADOW |
| ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY |
| USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY</p> |
| </div> |
| <div class="paragraph"> |
| <p>SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER |
| SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW |
| ISAMPLERCUBEARRAY USAMPLERCUBEARRAY |
| SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS |
| SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY |
| IMAGE2D IIMAGE2D UIMAGE2D |
| IMAGE3D IIMAGE3D UIMAGE3D |
| IMAGECUBE IIMAGECUBE UIMAGECUBE |
| IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER |
| IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY |
| IMAGECUBEARRAY IIMAGECUBEARRAY UIMAGECUBEARRAY</p> |
| </div> |
| <div class="paragraph"> |
| <p>STRUCT VOID</p> |
| </div> |
| <div class="paragraph"> |
| <p>WHILE BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT</p> |
| </div> |
| <div class="paragraph"> |
| <p>IDENTIFIER TYPE_NAME |
| FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT |
| FIELD_SELECTION</p> |
| </div> |
| <div class="paragraph"> |
| <p>LEFT_OP RIGHT_OP |
| INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP |
| AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN |
| MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN |
| SUB_ASSIGN |
| LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT |
| COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT |
| LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION</p> |
| </div> |
| <div class="paragraph"> |
| <p>INVARIANT PRECISE |
| HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION</p> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The following describes the grammar for the OpenGL ES Shading Language in terms of the above |
| tokens. |
| The starting rule is <em>translation_unit</em>.</p> |
| </div> |
| <div class="openblock bnf"> |
| <div class="content"> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>variable_identifier</em> : </dt> |
| <dd> |
| <p><em>IDENTIFIER</em></p> |
| </dd> |
| <dt class="hdlist1"><em>primary_expression</em> : </dt> |
| <dd> |
| <p><em>variable_identifier</em><br> |
| <em>INTCONSTANT</em><br> |
| <em>UINTCONSTANT</em><br> |
| <em>FLOATCONSTANT</em><br> |
| <em>BOOLCONSTANT</em><br> |
| <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>postfix_expression</em> : </dt> |
| <dd> |
| <p><em>primary_expression</em><br> |
| <em>postfix_expression</em> <em>LEFT_BRACKET</em> <em>integer_expression</em> <em>RIGHT_BRACKET</em><br> |
| <em>function_call</em><br> |
| <em>postfix_expression</em> <em>DOT</em> <em>FIELD_SELECTION</em><br> |
| <em>postfix_expression</em> <em>INC_OP</em><br> |
| <em>postfix_expression</em> <em>DEC_OP</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>FIELD_SELECTION includes members in structures, component selection for |
| vectors and the 'length' identifier for the length() method</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>integer_expression</em> : </dt> |
| <dd> |
| <p><em>expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call</em> : </dt> |
| <dd> |
| <p><em>function_call_or_method</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call_or_method</em> : </dt> |
| <dd> |
| <p><em>function_call_generic</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call_generic</em> : </dt> |
| <dd> |
| <p><em>function_call_header_with_parameters</em> <em>RIGHT_PAREN</em><br> |
| <em>function_call_header_no_parameters</em> <em>RIGHT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call_header_no_parameters</em> : </dt> |
| <dd> |
| <p><em>function_call_header</em> <em>VOID</em><br> |
| <em>function_call_header</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call_header_with_parameters</em> : </dt> |
| <dd> |
| <p><em>function_call_header</em> <em>assignment_expression</em><br> |
| <em>function_call_header_with_parameters</em> <em>COMMA</em> <em>assignment_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_call_header</em> : </dt> |
| <dd> |
| <p><em>function_identifier</em> <em>LEFT_PAREN</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: Constructors look like functions, but lexical analysis |
| recognized most of them as keywords. |
| They are now recognized through <em>type_specifier</em>.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Methods (<strong>.length</strong>) and identifiers are recognized through |
| <em>postfix_expression</em>.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>function_identifier</em> : </dt> |
| <dd> |
| <p><em>type_specifier</em><br> |
| <em>postfix_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>unary_expression</em> : </dt> |
| <dd> |
| <p><em>postfix_expression</em><br> |
| <em>INC_OP</em> <em>unary_expression</em><br> |
| <em>DEC_OP</em> <em>unary_expression</em><br> |
| <em>unary_operator</em> <em>unary_expression</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: No traditional style type casts.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>unary_operator</em> : </dt> |
| <dd> |
| <p><em>PLUS</em><br> |
| <em>DASH</em><br> |
| <em>BANG</em><br> |
| <em>TILDE</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: No '*' or '&' unary ops. |
| Pointers are not supported.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>multiplicative_expression</em> : </dt> |
| <dd> |
| <p><em>unary_expression</em><br> |
| <em>multiplicative_expression</em> <em>STAR</em> <em>unary_expression</em><br> |
| <em>multiplicative_expression</em> <em>SLASH</em> <em>unary_expression</em><br> |
| <em>multiplicative_expression</em> <em>PERCENT</em> <em>unary_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>additive_expression</em> : </dt> |
| <dd> |
| <p><em>multiplicative_expression</em><br> |
| <em>additive_expression</em> <em>PLUS</em> <em>multiplicative_expression</em><br> |
| <em>additive_expression</em> <em>DASH</em> <em>multiplicative_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>shift_expression</em> : </dt> |
| <dd> |
| <p><em>additive_expression</em><br> |
| <em>shift_expression</em> <em>LEFT_OP</em> <em>additive_expression</em><br> |
| <em>shift_expression</em> <em>RIGHT_OP</em> <em>additive_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>relational_expression</em> : </dt> |
| <dd> |
| <p><em>shift_expression</em><br> |
| <em>relational_expression</em> <em>LEFT_ANGLE</em> <em>shift_expression</em><br> |
| <em>relational_expression</em> <em>RIGHT_ANGLE</em> <em>shift_expression</em><br> |
| <em>relational_expression</em> <em>LE_OP</em> <em>shift_expression</em><br> |
| <em>relational_expression</em> <em>GE_OP</em> <em>shift_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>equality_expression</em> : </dt> |
| <dd> |
| <p><em>relational_expression</em><br> |
| <em>equality_expression</em> <em>EQ_OP</em> <em>relational_expression</em><br> |
| <em>equality_expression</em> <em>NE_OP</em> <em>relational_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>and_expression</em> : </dt> |
| <dd> |
| <p><em>equality_expression</em><br> |
| <em>and_expression</em> <em>AMPERSAND</em> <em>equality_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>exclusive_or_expression</em> : </dt> |
| <dd> |
| <p><em>and_expression</em><br> |
| <em>exclusive_or_expression</em> <em>CARET</em> <em>and_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>inclusive_or_expression</em> : </dt> |
| <dd> |
| <p><em>exclusive_or_expression</em><br> |
| <em>inclusive_or_expression</em> <em>VERTICAL_BAR</em> <em>exclusive_or_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>logical_and_expression</em> : </dt> |
| <dd> |
| <p><em>inclusive_or_expression</em><br> |
| <em>logical_and_expression</em> <em>AND_OP</em> <em>inclusive_or_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>logical_xor_expression</em> : </dt> |
| <dd> |
| <p><em>logical_and_expression</em><br> |
| <em>logical_xor_expression</em> <em>XOR_OP</em> <em>logical_and_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>logical_or_expression</em> : </dt> |
| <dd> |
| <p><em>logical_xor_expression</em><br> |
| <em>logical_or_expression</em> <em>OR_OP</em> <em>logical_xor_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>conditional_expression</em> : </dt> |
| <dd> |
| <p><em>logical_or_expression</em><br> |
| <em>logical_or_expression</em> <em>QUESTION</em> <em>expression</em> <em>COLON</em> |
| <em>assignment_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>assignment_expression</em> : </dt> |
| <dd> |
| <p><em>conditional_expression</em><br> |
| <em>unary_expression</em> <em>assignment_operator</em> <em>assignment_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>assignment_operator</em> : </dt> |
| <dd> |
| <p><em>EQUAL</em><br> |
| <em>MUL_ASSIGN</em><br> |
| <em>DIV_ASSIGN</em><br> |
| <em>MOD_ASSIGN</em><br> |
| <em>ADD_ASSIGN</em><br> |
| <em>SUB_ASSIGN</em><br> |
| <em>LEFT_ASSIGN</em><br> |
| <em>RIGHT_ASSIGN</em><br> |
| <em>AND_ASSIGN</em><br> |
| <em>XOR_ASSIGN</em><br> |
| <em>OR_ASSIGN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>expression</em> : </dt> |
| <dd> |
| <p><em>assignment_expression</em><br> |
| <em>expression</em> <em>COMMA</em> <em>assignment_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>constant_expression</em> : </dt> |
| <dd> |
| <p><em>conditional_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>declaration</em> : </dt> |
| <dd> |
| <p><em>function_prototype</em> <em>SEMICOLON</em><br> |
| <em>init_declarator_list</em> <em>SEMICOLON</em><br> |
| <em>PRECISION</em> <em>precision_qualifier</em> <em>type_specifier</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> |
| <em>RIGHT_BRACE</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> |
| <em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> |
| <em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>IDENTIFIER</em> <em>identifier_list</em> <em>SEMICOLON</em></p> |
| </dd> |
| <dt class="hdlist1"><em>identifier_list</em> : </dt> |
| <dd> |
| <p><em>COMMA</em> <em>IDENTIFIER</em><br> |
| <em>identifier_list</em> <em>COMMA</em> <em>IDENTIFIER</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_prototype</em> : </dt> |
| <dd> |
| <p><em>function_declarator</em> <em>RIGHT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_declarator</em> : </dt> |
| <dd> |
| <p><em>function_header</em><br> |
| <em>function_header_with_parameters</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_header_with_parameters</em> : </dt> |
| <dd> |
| <p><em>function_header</em> <em>parameter_declaration</em><br> |
| <em>function_header_with_parameters</em> <em>COMMA</em> <em>parameter_declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_header</em> : </dt> |
| <dd> |
| <p><em>fully_specified_type</em> <em>IDENTIFIER</em> <em>LEFT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>parameter_declarator</em> : </dt> |
| <dd> |
| <p><em>type_specifier</em> <em>IDENTIFIER</em><br> |
| <em>type_specifier</em> <em>IDENTIFIER</em> <em>array_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>parameter_declaration</em> : </dt> |
| <dd> |
| <p><em>type_qualifier</em> <em>parameter_declarator</em><br> |
| <em>parameter_declarator</em><br> |
| <em>type_qualifier</em> <em>parameter_type_specifier</em><br> |
| <em>parameter_type_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>parameter_type_specifier</em> : </dt> |
| <dd> |
| <p><em>type_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>init_declarator_list</em> : </dt> |
| <dd> |
| <p><em>single_declaration</em><br> |
| <em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em><br> |
| <em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em><br> |
| <em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em> |
| <em>initializer</em><br> |
| <em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p> |
| </dd> |
| <dt class="hdlist1"><em>single_declaration</em> : </dt> |
| <dd> |
| <p><em>fully_specified_type</em><br> |
| <em>fully_specified_type</em> <em>IDENTIFIER</em><br> |
| <em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em><br> |
| <em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em> |
| <em>initializer</em><br> |
| <em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: No 'enum', or 'typedef'.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>fully_specified_type</em> : </dt> |
| <dd> |
| <p><em>type_specifier</em><br> |
| <em>type_qualifier</em> <em>type_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>invariant_qualifier</em> : </dt> |
| <dd> |
| <p><em>INVARIANT</em></p> |
| </dd> |
| <dt class="hdlist1"><em>interpolation_qualifier</em> : </dt> |
| <dd> |
| <p><em>SMOOTH</em><br> |
| <em>FLAT</em></p> |
| </dd> |
| <dt class="hdlist1"><em>layout_qualifier</em> : </dt> |
| <dd> |
| <p><em>LAYOUT</em> <em>LEFT_PAREN</em> <em>layout_qualifier_id_list</em> <em>RIGHT_PAREN</em></p> |
| </dd> |
| <dt class="hdlist1"><em>layout_qualifier_id_list</em> : </dt> |
| <dd> |
| <p><em>layout_qualifier_id</em><br> |
| <em>layout_qualifier_id_list</em> <em>COMMA</em> <em>layout_qualifier_id</em></p> |
| </dd> |
| <dt class="hdlist1"><em>layout_qualifier_id</em> : </dt> |
| <dd> |
| <p><em>IDENTIFIER</em><br> |
| <em>IDENTIFIER</em> <em>EQUAL</em> <em>INTCONSTANT</em><br> |
| <em>IDENTIFIER</em> <em>EQUAL</em> <em>UINTCONSTANT</em><br> |
| <em>SHARED</em></p> |
| </dd> |
| <dt class="hdlist1"><em>precise_qualifier</em> : </dt> |
| <dd> |
| <p><em>PRECISE</em></p> |
| </dd> |
| <dt class="hdlist1"><em>type_qualifier</em> : </dt> |
| <dd> |
| <p><em>single_type_qualifier</em><br> |
| <em>type_qualifier</em> <em>single_type_qualifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>single_type_qualifier</em> : </dt> |
| <dd> |
| <p><em>storage_qualifier</em><br> |
| <em>layout_qualifier</em><br> |
| <em>precision_qualifier</em><br> |
| <em>interpolation_qualifier</em><br> |
| <em>invariant_qualifier</em><br> |
| <em>precise_qualifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>storage_qualifier</em> : </dt> |
| <dd> |
| <p><em>CONST</em><br> |
| <em>IN</em><br> |
| <em>OUT</em><br> |
| <em>INOUT</em><br> |
| <em>CENTROID</em><br> |
| <em>PATCH</em><br> |
| <em>SAMPLE</em><br> |
| <em>UNIFORM</em><br> |
| <em>BUFFER</em><br> |
| <em>SHARED</em><br> |
| <em>COHERENT</em><br> |
| <em>VOLATILE</em><br> |
| <em>RESTRICT</em><br> |
| <em>READONLY</em><br> |
| <em>WRITEONLY</em></p> |
| </dd> |
| <dt class="hdlist1"><em>type_specifier</em> : </dt> |
| <dd> |
| <p><em>type_specifier_nonarray</em><br> |
| <em>type_specifier_nonarray</em> <em>array_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>array_specifier</em> : </dt> |
| <dd> |
| <p><em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br> |
| <em>LEFT_BRACKET</em> <em>conditional_expression</em> <em>RIGHT_BRACKET</em><br> |
| <em>array_specifier</em> <em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br> |
| <em>array_specifier</em> <em>LEFT_BRACKET</em> <em>conditional_expression</em> <em>RIGHT_BRACKET</em></p> |
| </dd> |
| <dt class="hdlist1"><em>type_specifier_nonarray</em> : </dt> |
| <dd> |
| <p><em>VOID</em><br> |
| <em>FLOAT</em><br> |
| <em>INT</em><br> |
| <em>UINT</em><br> |
| <em>BOOL</em><br> |
| <em>VEC2</em><br> |
| <em>VEC3</em><br> |
| <em>VEC4</em><br> |
| <em>BVEC2</em><br> |
| <em>BVEC3</em><br> |
| <em>BVEC4</em><br> |
| <em>IVEC2</em><br> |
| <em>IVEC3</em><br> |
| <em>IVEC4</em><br> |
| <em>UVEC2</em><br> |
| <em>UVEC3</em><br> |
| <em>UVEC4</em><br> |
| <em>MAT2</em><br> |
| <em>MAT3</em><br> |
| <em>MAT4</em><br> |
| <em>MAT2X2</em><br> |
| <em>MAT2X3</em><br> |
| <em>MAT2X4</em><br> |
| <em>MAT3X2</em><br> |
| <em>MAT3X3</em><br> |
| <em>MAT3X4</em><br> |
| <em>MAT4X2</em><br> |
| <em>MAT4X3</em><br> |
| <em>MAT4X4</em><br> |
| <em>ATOMIC_UINT</em><br> |
| <em>SAMPLER2D</em><br> |
| <em>SAMPLER3D</em><br> |
| <em>SAMPLERCUBE</em><br> |
| <em>SAMPLER2DSHADOW</em><br> |
| <em>SAMPLERCUBESHADOW</em><br> |
| <em>SAMPLER2DARRAY</em><br> |
| <em>SAMPLER2DARRAYSHADOW</em><br> |
| <em>SAMPLERCUBEARRAY</em><br> |
| <em>SAMPLERCUBEARRAYSHADOW</em><br> |
| <em>ISAMPLER2D</em><br> |
| <em>ISAMPLER3D</em><br> |
| <em>ISAMPLERCUBE</em><br> |
| <em>ISAMPLER2DARRAY</em><br> |
| <em>ISAMPLERCUBEARRAY</em><br> |
| <em>USAMPLER2D</em><br> |
| <em>USAMPLER3D</em><br> |
| <em>USAMPLERCUBE</em><br> |
| <em>USAMPLER2DARRAY</em><br> |
| <em>USAMPLERCUBEARRAY</em><br> |
| <em>SAMPLERBUFFER</em><br> |
| <em>ISAMPLERBUFFER</em><br> |
| <em>USAMPLERBUFFER</em><br> |
| <em>SAMPLER2DMS</em><br> |
| <em>ISAMPLER2DMS</em><br> |
| <em>USAMPLER2DMS</em><br> |
| <em>SAMPLER2DMSARRAY</em><br> |
| <em>ISAMPLER2DMSARRAY</em><br> |
| <em>USAMPLER2DMSARRAY</em><br> |
| <em>IMAGE2D</em><br> |
| <em>IIMAGE2D</em><br> |
| <em>UIMAGE2D</em><br> |
| <em>IMAGE3D</em><br> |
| <em>IIMAGE3D</em><br> |
| <em>UIMAGE3D</em><br> |
| <em>IMAGECUBE</em><br> |
| <em>IIMAGECUBE</em><br> |
| <em>UIMAGECUBE</em><br> |
| <em>IMAGEBUFFER</em><br> |
| <em>IIMAGEBUFFER</em><br> |
| <em>UIMAGEBUFFER</em><br> |
| <em>IMAGE2DARRAY</em><br> |
| <em>IIMAGE2DARRAY</em><br> |
| <em>UIMAGE2DARRAY</em><br> |
| <em>IMAGECUBEARRAY</em><br> |
| <em>IIMAGECUBEARRAY</em><br> |
| <em>UIMAGECUBEARRAY</em><br> |
| <em>struct_specifier</em><br> |
| <em>TYPE_NAME</em></p> |
| </dd> |
| <dt class="hdlist1"><em>precision_qualifier</em> : </dt> |
| <dd> |
| <p><em>HIGH_PRECISION</em><br> |
| <em>MEDIUM_PRECISION</em><br> |
| <em>LOW_PRECISION</em></p> |
| </dd> |
| <dt class="hdlist1"><em>struct_specifier</em> : </dt> |
| <dd> |
| <p><em>STRUCT</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> |
| <em>RIGHT_BRACE</em><br> |
| <em>STRUCT</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> <em>RIGHT_BRACE</em></p> |
| </dd> |
| <dt class="hdlist1"><em>struct_declaration_list</em> : </dt> |
| <dd> |
| <p><em>struct_declaration</em><br> |
| <em>struct_declaration_list</em> <em>struct_declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>struct_declaration</em> : </dt> |
| <dd> |
| <p><em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em><br> |
| <em>type_qualifier</em> <em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em></p> |
| </dd> |
| <dt class="hdlist1"><em>struct_declarator_list</em> : </dt> |
| <dd> |
| <p><em>struct_declarator</em><br> |
| <em>struct_declarator_list</em> <em>COMMA</em> <em>struct_declarator</em></p> |
| </dd> |
| <dt class="hdlist1"><em>struct_declarator</em> : </dt> |
| <dd> |
| <p><em>IDENTIFIER</em><br> |
| <em>IDENTIFIER</em> <em>array_specifier</em></p> |
| </dd> |
| <dt class="hdlist1"><em>initializer</em> : </dt> |
| <dd> |
| <p><em>assignment_expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>declaration_statement</em> : </dt> |
| <dd> |
| <p><em>declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>statement</em> : </dt> |
| <dd> |
| <p><em>compound_statement</em><br> |
| <em>simple_statement</em></p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: labeled statements for SWITCH only; 'goto' is not supported.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>simple_statement</em> : </dt> |
| <dd> |
| <p><em>declaration_statement</em><br> |
| <em>expression_statement</em><br> |
| <em>selection_statement</em><br> |
| <em>switch_statement</em><br> |
| <em>case_label</em><br> |
| <em>iteration_statement</em><br> |
| <em>jump_statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>compound_statement</em> : </dt> |
| <dd> |
| <p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br> |
| <em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p> |
| </dd> |
| <dt class="hdlist1"><em>statement_no_new_scope</em> : </dt> |
| <dd> |
| <p><em>compound_statement_no_new_scope</em><br> |
| <em>simple_statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>compound_statement_no_new_scope</em> : </dt> |
| <dd> |
| <p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br> |
| <em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p> |
| </dd> |
| <dt class="hdlist1"><em>statement_list</em> : </dt> |
| <dd> |
| <p><em>statement</em><br> |
| <em>statement_list</em> <em>statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>expression_statement</em> : </dt> |
| <dd> |
| <p><em>SEMICOLON</em><br> |
| <em>expression</em> <em>SEMICOLON</em></p> |
| </dd> |
| <dt class="hdlist1"><em>selection_statement</em> : </dt> |
| <dd> |
| <p><em>IF</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>selection_rest_statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>selection_rest_statement</em> : </dt> |
| <dd> |
| <p><em>statement</em> <em>ELSE</em> <em>statement</em><br> |
| <em>statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>condition</em> : </dt> |
| <dd> |
| <p><em>expression</em><br> |
| <em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p> |
| </dd> |
| <dt class="hdlist1"><em>switch_statement</em> : </dt> |
| <dd> |
| <p><em>SWITCH</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>LEFT_BRACE</em> |
| <em>switch_statement_list</em><br> |
| <em>RIGHT_BRACE</em></p> |
| </dd> |
| <dt class="hdlist1"><em>switch_statement_list</em> : </dt> |
| <dd> |
| <p>/* <em>nothing</em> */<br> |
| <em>statement_list</em></p> |
| </dd> |
| <dt class="hdlist1"><em>case_label</em> : </dt> |
| <dd> |
| <p><em>CASE</em> <em>expression</em> <em>COLON</em><br> |
| <em>DEFAULT</em> <em>COLON</em></p> |
| </dd> |
| <dt class="hdlist1"><em>iteration_statement</em> : </dt> |
| <dd> |
| <p><em>WHILE</em> <em>LEFT_PAREN</em> <em>condition</em> <em>RIGHT_PAREN</em> <em>statement_no_new_scope</em><br> |
| <em>DO</em> <em>statement</em> <em>WHILE</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> |
| <em>SEMICOLON</em><br> |
| <em>FOR</em> <em>LEFT_PAREN</em> <em>for_init_statement</em> <em>for_rest_statement</em> |
| <em>RIGHT_PAREN</em> <em>statement_no_new_scope</em></p> |
| </dd> |
| <dt class="hdlist1"><em>for_init_statement</em> : </dt> |
| <dd> |
| <p><em>expression_statement</em><br> |
| <em>declaration_statement</em></p> |
| </dd> |
| <dt class="hdlist1"><em>conditionopt</em> : </dt> |
| <dd> |
| <p><em>condition</em><br> |
| /* <em>empty</em> */</p> |
| </dd> |
| <dt class="hdlist1"><em>for_rest_statement</em> : </dt> |
| <dd> |
| <p><em>conditionopt</em> <em>SEMICOLON</em><br> |
| <em>conditionopt</em> <em>SEMICOLON</em> <em>expression</em></p> |
| </dd> |
| <dt class="hdlist1"><em>jump_statement</em> : </dt> |
| <dd> |
| <p><em>CONTINUE</em> <em>SEMICOLON</em><br> |
| <em>BREAK</em> <em>SEMICOLON</em><br> |
| <em>RETURN</em> <em>SEMICOLON</em><br> |
| <em>RETURN</em> <em>expression</em> <em>SEMICOLON</em><br> |
| <em>DISCARD</em> <em>SEMICOLON</em> // Fragment shader only.</p> |
| </dd> |
| </dl> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>Grammar Note: No 'goto'. |
| Gotos are not supported.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="dlist"> |
| <dl> |
| <dt class="hdlist1"><em>translation_unit</em> : </dt> |
| <dd> |
| <p><em>external_declaration</em><br> |
| <em>translation_unit</em> <em>external_declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>external_declaration</em> : </dt> |
| <dd> |
| <p><em>function_definition</em><br> |
| <em>declaration</em></p> |
| </dd> |
| <dt class="hdlist1"><em>function_definition</em> : </dt> |
| <dd> |
| <p><em>function_prototype</em> <em>compound_statement_no_new_scope</em></p> |
| </dd> |
| </dl> |
| </div> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In general the above grammar describes a super set of the OpenGL ES Shading Language. |
| Certain constructs that are valid purely in terms of the grammar are |
| disallowed by statements elsewhere in this specification.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="counting-of-inputs-and-outputs">11. Counting of Inputs and Outputs</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This section applies to outputs from the last active vertex processing stage |
| and inputs to the fragment stage. |
| GLSL ES 3.20 specifies the storage available for such variables in terms of |
| an array of 4-vectors. |
| The assumption is that variables will be packed into these arrays without |
| wasting space. |
| This places significant burden on implementations since optimal packing is |
| computationally intensive. |
| Implementations may have more internal resources than exposed to the |
| application and so avoid the need to perform packing but this is also |
| considered an expensive solution.</p> |
| </div> |
| <div class="paragraph"> |
| <p>GLSL ES 3.20 therefore relaxes the requirements for packing by |
| specifying a simpler algorithm that may be used. |
| This algorithm specifies a minimum requirement for when a set of variables |
| must be supported by an implementation. |
| The implementation is allowed to support more than the minimum and so may |
| use a more efficient algorithm and/or may support more registers than the |
| virtual target machine.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Outputs from the last active vertex stage and inputs to the fragment stage are |
| counted separately. |
| If statically used in the fragment shader, the built-in special variables |
| (<em>gl_FragCoord</em>, <em>gl_FrontFacing</em> and <em>gl_PointCoord</em>) are included when |
| calculating the storage requirements of fragment inputs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the last active vertex-pipeline shader and fragment shader are linked |
| together, inputs and outputs are only counted if they are statically used |
| within the shader. |
| If the shaders are each compiled into a separable program, all declared inputs |
| and outputs are counted.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="title">Note</div> |
| <div class="paragraph"> |
| <p>GLSL ES 3.20 does not require the implementation to remove |
| outputs which are not statically used in the fragment shader.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>For the algorithm used, failing resource allocation for a variable must |
| result in an error.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The resource allocation of variables must succeed for all cases where the |
| following packing algorithm succeeds:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The target architecture consists of a grid of registers, 16 rows by 4 |
| columns. |
| Each register can contain a scalar value, i.e. a float, int or uint.</p> |
| </li> |
| <li> |
| <p>Variables with an explicit location are allocated first. |
| When attempting to allocate a location for other variables, if there is |
| a conflict, the search moves to the next available free location.</p> |
| </li> |
| <li> |
| <p>Structures are assumed to be flattened. |
| Each data member is treated as if it were at global scope.</p> |
| </li> |
| <li> |
| <p>Variables are packed into the registers one at a time so that they each |
| occupy a contiguous sub-rectangle. |
| No splitting of variables is permitted.</p> |
| </li> |
| <li> |
| <p>The orientation of variables is fixed. |
| Vectors always occupy registers in a single row. |
| Elements of an array must be in different rows. |
| E.g. <strong>vec4</strong> will always occupy one row; float[16] will occupy one |
| column. |
| Since it is not permitted to split a variable, large arrays e.g. |
| float[32] will always fail with this algorithm.</p> |
| </li> |
| <li> |
| <p>Non-square matrices of type <strong>matCxR</strong> consume the same space as a square |
| matrix of type <strong>matN</strong> where N is the greater of C and R. |
| Variables of type <strong>mat2</strong> occupies 2 complete rows. |
| These rules allow implementations more flexibility in how variables are |
| stored. |
| + Other variables consume only the minimum space required.</p> |
| </li> |
| <li> |
| <p>Arrays of size N are assumed to take N times the size of the base type.</p> |
| </li> |
| <li> |
| <p>Variables are packed in the following order:</p> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p><strong>mat4</strong> and arrays of <strong>mat4</strong>.</p> |
| </li> |
| <li> |
| <p><strong>mat2</strong> and arrays of <strong>mat2</strong> (since they occupy full rows)</p> |
| </li> |
| <li> |
| <p><strong>vec4</strong> and arrays of <strong>vec4</strong></p> |
| </li> |
| <li> |
| <p><strong>mat3</strong> and arrays of <strong>mat3</strong></p> |
| </li> |
| <li> |
| <p><strong>vec3</strong> and arrays of <strong>vec3</strong></p> |
| </li> |
| <li> |
| <p><strong>vec2</strong> and arrays of <strong>vec2</strong></p> |
| </li> |
| <li> |
| <p>Scalar types and arrays of scalar types</p> |
| </li> |
| </ol> |
| </div> |
| </li> |
| <li> |
| <p>For each of the above types, the arrays are processed in order of size, |
| largest first. |
| Arrays of size 1 and the base type are considered equivalent. |
| The first type to be packed will be mat4[4], mat4[3], mat[2] followed by |
| mat4, mat2[4]…​mat2[2], mat2, vec4[8], vec4[7],…​vec4[1], vec4, |
| mat3[2], mat3 and so on. |
| The last variables to be packed will be float (and float[1]).</p> |
| </li> |
| <li> |
| <p>For 2,3 and 4 component variables packing is started using the 1<sup>st</sup> |
| column of the 1<sup>st</sup> row. |
| Variables are then allocated to successive rows, aligning them to the |
| 1<sup>st</sup> column.</p> |
| </li> |
| <li> |
| <p>For 2 component variables, when there are no spare rows, the strategy is |
| switched to using the highest numbered row and the lowest numbered |
| column where the variable will fit. |
| (In practice, this means they will be aligned to the x or z component.) |
| Packing of any further 3 or 4 component variables will fail at this |
| point.</p> |
| </li> |
| <li> |
| <p>1 component variables (e.g. floats and arrays of floats) have their own |
| packing rule. |
| They are packed in order of size, largest first. |
| Each variable is placed in the column that leaves the least amount of |
| space in the column and aligned to the lowest available rows within that |
| column. |
| During this phase of packing, space will be available in up to 4 |
| columns. |
| The space within each column is always contiguous in the case where no |
| variables have explicit locations.</p> |
| </li> |
| <li> |
| <p>For each type, variables with the 'smooth' property are packed first, |
| followed by variables with the 'flat' property.</p> |
| </li> |
| <li> |
| <p>Each row can contain either values with the 'smooth' property or the |
| 'flat' property but not both. |
| If this situation is encountered during allocation, the algorithm skips |
| the component location and continues with the next available location. |
| These skipped locations may be used for other values later in the |
| allocation process.</p> |
| </li> |
| <li> |
| <p>There is no backtracking. |
| Once a value is assigned a location, it cannot be changed, even if such |
| a change is required for a successful allocation.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Example: pack the following types:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="CodeRay highlight"><code data-lang="c++">out vec4 a; <span class="comment">// top left</span> |
| out mat3 b; <span class="comment">// align to left, lowest numbered rows</span> |
| out mat2x3 c; <span class="comment">// same size as mat3, align to left</span> |
| out vec2 d[<span class="integer">6</span>]; <span class="comment">// align to left, lowest numbered rows</span> |
| out vec2 e[<span class="integer">4</span>]; <span class="comment">// Cannot align to left so align to z column, highest</span> |
| <span class="comment">// numbered rows</span> |
| out vec2 f; <span class="comment">// Align to left, lowest numbered rows.</span> |
| out <span class="predefined-type">float</span> g[<span class="integer">3</span>] <span class="comment">// Column with minimum space</span> |
| out <span class="predefined-type">float</span> h[<span class="integer">2</span>]; <span class="comment">// Column with minimum space (choice of 3, any</span> |
| <span class="comment">// can be used)</span> |
| out <span class="predefined-type">float</span> i; <span class="comment">// Column with minimum space</span></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In this example, the variables happen to be listed in the order in which |
| they are packed. |
| Packing is independent of the order of declaration.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 20%;"> |
| <col style="width: 20%;"> |
| <col style="width: 20%;"> |
| <col style="width: 20%;"> |
| <col style="width: 20%;"> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>x</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>y</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>z</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>w</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">12</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">13</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>f</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>f</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">14</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>h</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>i</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>h</strong></p></td> |
| <td class="tableblock halign-left valign-top"></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>Some types e.g. mat4[8] will be too large to fit. |
| These always fail with this algorithm.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="acknowledgments">12. Acknowledgments</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This specification is based on the work of those who contributed to past |
| versions of the Open GL and Open GL ES Language Specifications and the |
| following contributors to this version:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Acorn Pooley, NVIDIA<br> |
| Alberto Moreira, Qualcomm<br> |
| Aleksandra Krstic, Qualcomm<br> |
| Alon Or-bach, Nokia & Samsung<br> |
| Andrzej Kacprowski, Intel<br> |
| Arzhange Safdarzadeh, Intel<br> |
| Aske Simon Christensen, ARM<br> |
| Avi Shapira, Graphic Remedy<br> |
| Barthold Lichtenbelt, NVIDIA<br> |
| Ben Bowman, Imagination Technologies<br> |
| Ben Brierton, Broadcom<br> |
| Benj Lipchak, Apple<br> |
| Benson Tao, Vivante<br> |
| Bill Licea-Kane, Qualcomm<br> |
| Brent Insko, Intel<br> |
| Brian Murray, Freescale<br> |
| Bruce Merry, ARM<br> |
| Carlos Santa, TI<br> |
| Cass Everitt, Epic Games & NVIDIA<br> |
| Cemil Azizoglu, TI<br> |
| Chang-Hyo Yu, Samsung<br> |
| Chris Dodd, NVIDIA<br> |
| Chris Knox, NVIDIA<br> |
| Chris Tserng, TI<br> |
| Clay Montgomery, TI<br> |
| Daniel Kartch, NVIDIA<br> |
| Daniel Koch, Transgaming& NVIDIA<br> |
| Daoxiang Gong, Imagination Technologies<br> |
| Dave Shreiner, ARM<br> |
| David Garcia, AMD<br> |
| David Jarmon, Vivante<br> |
| Derek Cornish, Epic Games<br> |
| Dominick Witczak, Mobica<br> |
| Eben Upton, Broadcom<br> |
| Ed Plowman, ARM<br> |
| Eisaku Ohbuchi, DMP<br> |
| Elan Lennard, ARM<br> |
| Erik Faye-Lund, ARM<br> |
| Graham Connor, Imagination Technologies<br> |
| Graham Sellers, AMD<br> |
| Greg Roth, NVIDIA<br> |
| Guillaume Portier, Hi Corporation<br> |
| Guofang Jiao, Qualcomm<br> |
| Hans-Martin Will, Vincent<br> |
| Hwanyong Lee, Huone<br> |
| I-Gene Leong, NVIDIA<br> |
| Ian Romanick, Intel<br> |
| Ian South-Dickinson, NVIDIA<br> |
| Ilan Aelion-Exch, Samsung<br> |
| Inkyun Lee, Huone<br> |
| Jacob Strm, Ericsson<br> |
| James Adams, Broadcom<br> |
| James Jones, Imagination Technologies<br> |
| James McCombe, Imagination Technologies<br> |
| Jamie Gennis, Google<br> |
| Jan-Harald Fredriksen, ARM<br> |
| Jani Vaisanen, Nokia<br> |
| Jarkko Kemppainen, Symbio<br> |
| Jeff Bolz, NVIDIA<br> |
| Jeff Leger, Qualcomm<br> |
| Jeff Vigil, Qualcomm<br> |
| Jeremy Sandmel, Apple<br> |
| Jeremy Thorne, Broadcom<br> |
| Jim Hauxwell, Broadcom<br> |
| Jinsung Kim, Huone<br> |
| Jiyoung Yoon, Huone<br> |
| John Kessenich, Google<br> |
| Jon Kennedy, 3DLabs<br> |
| Jon Leech, Khronos<br> |
| Jonathan Putsman, Imagination Technologies<br> |
| Joohoon Lee, Samsung<br> |
| JoukoKylmäoja, Symbio<br> |
| Jrn Nystad, ARM<br> |
| Jussi Rasanen, NVIDIA<br> |
| Kalle Raita, drawElements<br> |
| Kari Pulli, Nokia<br> |
| Keith Whitwell, VMware<br> |
| Kent Miller, Netlogic Microsystems<br> |
| Kimmo Nikkanen, Nokia<br> |
| Konsta Karsisto, Nokia<br> |
| Krzysztof Kaminski, Intel<br> |
| Larry Seiler, Intel<br> |
| Lars Remes, Symbio<br> |
| Lee Thomason, Adobe<br> |
| Lefan Zhong, Vivante<br> |
| Marcus Lorentzon, Ericsson<br> |
| Mark Butler, Imagination Technologies<br> |
| Mark Callow, Hi Corporation<br> |
| Mark Cresswell, Broadcom<br> |
| Mark Snyder, Alt Software<br> |
| Mark Young, AMD<br> |
| Mathieu Robart, STM<br> |
| Matt Netsch, Qualcomm<br> |
| Matt Russo, Matrox<br> |
| Maurice Ribble, Qualcomm<br> |
| Max Kazakov, DMP<br> |
| Mika Pesonen, Nokia<br> |
| Mike Cai, Vivante<br> |
| Mike Weiblen, Zebra Imaging & Qualcomm<br> |
| Mila Smith, AMD<br> |
| Nakhoon Baek, Kyungpook Univeristy<br> |
| Nate Huang, NVIDIA<br> |
| Neil Trevett, NVIDIA<br> |
| Nelson Kidd, Intel<br> |
| Nick Haemel, NVIDIA<br> |
| Nick Penwarden, Epic Games<br> |
| Niklas Smedberg, Epic Games<br> |
| Nizar Romdan, ARM<br> |
| Oliver Wohlmuth , Fujitsu<br> |
| Pat Brown, NVIDIA<br> |
| Paul Ruggieri, Qualcomm<br> |
| Per Wennersten, Ericsson<br> |
| Petri Talala, Symbio<br> |
| Phil Huxley, ZiiLabs<br> |
| Philip Hatcher, Freescale & Intel<br> |
| Piers Daniell, NVIDIA<br> |
| Pyry Haulos, drawElements<br> |
| Piotr Tomaszewski, Ericsson<br> |
| Piotr Uminski, Intel<br> |
| Rami Mayer, Samsung<br> |
| Rauli Laatikainen, RightWare<br> |
| Rob Barris, NVIDIA<br> |
| Rob Simpson, Qualcomm<br> |
| Roj Langhi, Vivante<br> |
| Rune Holm, ARM<br> |
| Sami Kyostila, Nokia<br> |
| Sean Ellis, ARM<br> |
| Shereef Shehata, TI<br> |
| Sila Kayo, Nokia<br> |
| Slawomir Cygan, Intel<br> |
| Slawomir Grajewski, Intel<br> |
| Steve Hill, STM & Broadcom<br> |
| Steven Olney, DMP<br> |
| Suman Sharma, Intel<br> |
| Tapani Palli, Nokia<br> |
| Teemu Laakso, Symbio<br> |
| Tero Karras, NVIDIA<br> |
| Timo Suoranta, Imagination Technologies & Broadcom<br> |
| Tom Cooksey, ARM<br> |
| Tom McReynolds, NVIDIA<br> |
| Tom Olson, TI & ARM<br> |
| Tomi Aarnio, Nokia<br> |
| Tommy Asano, Takumi<br> |
| Wes Bang, Nokia<br> |
| Yanjun Zhang, Vivante</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="references">13. Normative References</h2> |
| <div class="sectionbody"> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>International Standard ISO/IEC 14882:1998(E). |
| Programming Languages - C++. Referenced for preprocessor only</p> |
| </li> |
| <li> |
| <p>“OpenGL<sup>R</sup> ES, Version 3.2”, |
| <a href="https://www.khronos.org/registry/OpenGL/index_es.php" class="bare">https://www.khronos.org/registry/OpenGL/index_es.php</a>, November 3, 2016.</p> |
| </li> |
| <li> |
| <p>“The OpenGL<sup>R</sup> Graphics System: A Specification, Version 4.6 (Core |
| Profile)”, <a href="https://www.khronos.org/registry/OpenGL/index_gl.php" class="bare">https://www.khronos.org/registry/OpenGL/index_gl.php</a>, June |
| 1, 2016.</p> |
| </li> |
| <li> |
| <p>International Standard ISO/IEC 646:1991. |
| Information technology - ISO 7-bit coded character set for information |
| interchange</p> |
| </li> |
| <li> |
| <p>The Unicode Standard Version 6.0 - Core Specification.</p> |
| </li> |
| <li> |
| <p>IEEE 754-2008. |
| <em>IEEE Standard for Floating-Point Arithmetic</em></p> |
| </li> |
| <li> |
| <p>“SPIR-V Specification, Version 1.3, Revision 7” , |
| <a href="https://www.khronos.org/registry/spir-v/" class="bare">https://www.khronos.org/registry/spir-v/</a>.</p> |
| </li> |
| <li> |
| <p>“Vulkan<sup>R</sup> 1.1.105 - A Specification”, |
| <a href="https://www.khronos.org/registry/vulkan/" class="bare">https://www.khronos.org/registry/vulkan/</a>, |
| March 19, 2019.</p> |
| </li> |
| </ol> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_non_normative_spir_v_mappings">14. Non-Normative SPIR-V Mappings</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This appendix includes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>a comparision of feature differences with SPIR-V versus without, for both Vulkan and OpenGL</p> |
| </li> |
| <li> |
| <p>a discussion of how GLSL features logically map to SPIR-V features.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_feature_comparisons">14.1. Feature Comparisons</h3> |
| <div class="paragraph"> |
| <p>The following features are removed for both OpenGL and Vulkan:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>subroutines</p> |
| </li> |
| <li> |
| <p>shared and packed block layouts</p> |
| </li> |
| <li> |
| <p>the already deprecated texturing functions (e.g., <code>texture2D()</code>)</p> |
| </li> |
| <li> |
| <p>the already deprecated noise functions (e.g., <code>noise1()</code>)</p> |
| </li> |
| <li> |
| <p>compatibility-profile features</p> |
| </li> |
| <li> |
| <p><em>gl_DepthRangeParameters</em> and <em>gl_NumSamples</em></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Vulkan removed the following features, which are still present for OpenGL:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Default uniforms, for non-opaque types: |
| The <strong>UniformConstant</strong> storage class can be used on individual |
| variables at global scope. (That is, uniforms don’t have to be in a |
| block, unless they are built-in members that are in block in GLSL |
| version 4.5 or above.)</p> |
| </li> |
| <li> |
| <p>GLSL atomic-counter bindings have the <em>offset</em> layout qualifier → |
| SPIR-V <strong>AtomicCounter</strong> storage class using the <strong>Offset</strong> decoration</p> |
| </li> |
| <li> |
| <p>GLSL <em>origin_lower_left</em> → SPIR-V <strong>OriginLowerLeft</strong></p> |
| </li> |
| <li> |
| <p>special rules for locations for input doubles in the vertex shader</p> |
| </li> |
| <li> |
| <p><em>gl_VertexID</em> and <em>gl_InstanceID</em> (more detail follows)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The following features are added for both OpenGL and Vulkan:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>specialization constants</p> |
| </li> |
| <li> |
| <p><em>offset</em> can organize members in a different order than declaration order</p> |
| </li> |
| <li> |
| <p><em>offset</em> and <em>align</em> layout qualifiers for uniform/buffer blocks for |
| versions that did not support them</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Vulkan Only: The following features are added:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>push-constant buffers</p> |
| </li> |
| <li> |
| <p>shader combining of separate textures and samplers (SPIR-V <strong>OpTypeSampler</strong>)</p> |
| </li> |
| <li> |
| <p>descriptor sets (<strong>DescriptorSet</strong> must be 0, if present)</p> |
| </li> |
| <li> |
| <p><em>gl_VertexIndex</em> and <em>gl_InstanceIndex</em></p> |
| </li> |
| <li> |
| <p>subpass-input targets and input attachments (<em>input_attachment_index</em>)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The following features are changed in both OpenGL and Vulkan:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><em>gl_FragColor</em> will no longer indicate an implicit broadcast</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Vulkan Only: The following features are changed:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>precision qualifiers (<strong>mediump</strong> and <strong>lowp</strong>) will be respected for all |
| versions, not dropped for desktop versions (default precision for |
| desktop versions is <strong>highp</strong> for all types)</p> |
| </li> |
| <li> |
| <p>arrays of uniforms and buffer blocks take only one binding number for |
| the entire object, not one per array element</p> |
| </li> |
| <li> |
| <p>the default origin is <em>origin_upper_left</em> instead of <em>origin_lower_left</em></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Vulkan does not allow multi-dimensional arrays of resources like |
| UBOs and SSBOs in its SPIR-V environment spec. SPIR-V supports |
| it and OpenGL already allows this for GLSL shaders. SPIR-V |
| for OpenGL also allows it.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_mapping_from_glsl_to_spir_v">14.2. Mapping from GLSL to SPIR-V</h3> |
| <div class="sect3"> |
| <h4 id="_specialization_constants">14.2.1. Specialization Constants</h4> |
| <div class="paragraph"> |
| <p>SPIR-V specialization constants, which can be set later by the client API, |
| can be declared using <code>layout(constant_id=…​)</code>. For example, to make a |
| specialization constant with a default value of 12:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(constant_id = 17) const int arraySize = 12;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Above, <code>17</code> is the ID by which the API or other tools can later refer to |
| this specific specialization constant. The API or an intermediate tool can |
| then change its value to another constant integer before it is fully |
| lowered to executable code. If it is never changed before final lowering, |
| it will retain the value of 12.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Specialization constants have const semantics, except they don’t fold. |
| Hence, an array can be declared with <code>arraySize</code> from above:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>vec4 data[arraySize]; // legal, even though arraySize might change</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Specialization constants can be in expressions:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>vec4 data2[arraySize + 2];</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This will make <code>data2</code> be sized by 2 more than whatever constant value |
| <code>arraySize</code> has when it is time to lower the shader to executable code.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An expression formed with specialization constants also behaves in the |
| shader like a specialization constant, not a like a constant.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>arraySize + 2 // a specialization constant (with no constant_id)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Such expressions can be used in the same places as a constant.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <em>constant_id</em> can only be applied to a scalar integer, a scalar floating-point |
| or a scalar Boolean.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Only basic operators and constructors can be applied to a specialization |
| constant and still result in a specialization constant:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(constant_id = 17) const int arraySize = 12; |
| sin(float(arraySize)); // result is not a specialization constant</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>While SPIR-V specialization constants are only for scalars, a vector |
| can be made by operations on scalars:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(constant_id = 18) const int scX = 1; |
| layout(constant_id = 19) const int scZ = 1; |
| const vec3 scVec = vec3(scX, 1, scZ); // partially specialized vector</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A built-in variable can have a <em>constant_id</em> attached to it:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(constant_id = 18) gl_MaxImageUnits;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This makes it behave as a specialization constant. It is not a full |
| redeclaration; all other characteristics are left intact from the |
| original built-in declaration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The built-in vector <em>gl_WorkGroupSize</em> can be specialized using special |
| layout <code>local_size_{xyz}_id</code> applied to the <strong>in</strong> qualifier. For example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(local_size_x_id = 18, local_size_z_id = 19) in;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This leaves <em>gl_WorkGroupSize.y</em> as a non-specialization constant, with |
| <em>gl_WorkGroupSize</em> being a partially specialized vector. Its <em>x</em> and <em>z</em> |
| components can be later specialized using the ID’s 18 and 19.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_vulkan_only_push_constants">14.2.2. Vulkan Only: Push Constants</h4> |
| <div class="paragraph"> |
| <p>Push constants reside in a uniform block declared using the new |
| layout-qualifier-id <em>push_constant</em> applied to a uniform-block declaration. |
| The API writes a set of constants to a push-constant buffer, and the shader |
| reads them from a <em>push_constant</em> block:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(push_constant) uniform BlockName { |
| int member1; |
| float member2; |
| ... |
| } InstanceName; // optional instance name |
| ... = InstanceName.member2; // read a push constant</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The memory accounting used for the <em>push_constant</em> uniform block is different |
| than for other uniform blocks: There is a separate small pool of memory |
| it must fit within. By default, a <em>push_constant</em> buffer follows the std430 |
| packing rules.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_vulkan_only_descriptor_sets">14.2.3. Vulkan Only: Descriptor Sets</h4> |
| <div class="paragraph"> |
| <p>Each shader resource in a descriptor set is assigned a tuple of (set |
| number, binding number, array element) that defines its location within |
| a descriptor set layout. |
| In GLSL, the set number and binding number are assigned via the <em>set</em> |
| and <em>binding</em> layout qualifiers respectively, and the array element is |
| implicitly assigned consecutively starting with index equal to zero for |
| the first element of an array (and array element is zero for non-array |
| variables):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>// Assign set number = M, binding number = N, array element = 0 |
| layout (set=M, binding=N) uniform sampler2D variableName;</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>// Assign set number = M, binding number = N for all array elements, |
| // and array element = i for the ith member of an array of size I. |
| layout (set=M, binding=N) uniform sampler2D variableNameArray[I];</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For example, two combined texture/sampler objects can be declared in two |
| different descriptor sets as follows</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout(set = 0, binding = 0) uniform sampler2D ts3; |
| layout(set = 1, binding = 0) uniform sampler2D ts4;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>See the API documentation for more detail on the operation model of |
| descriptor sets.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_vulkan_only_samplers_images_textures_and_buffers">14.2.4. Vulkan Only: Samplers, Images, Textures, and Buffers</h4> |
| <div class="sect4"> |
| <h5 id="_storage_images">Storage Images</h5> |
| <div class="paragraph"> |
| <p>Storage images are declared in GLSL shader source using uniform image |
| variables of the appropriate dimensionality as well as a format layout |
| qualifier (if necessary):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n, r32f) uniform image2D myStorageImage;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "myStorageImage" |
| OpDecorate %9 DescriptorSet m |
| OpDecorate %9 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 2D 0 0 0 2 R32f |
| %8 = OpTypePointer UniformConstant %7 |
| %9 = OpVariable %8 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_samplers">Samplers</h5> |
| <div class="paragraph"> |
| <p>SPIR-V samplers are declared in GLSL shader source using uniform <strong>sampler</strong> and |
| <strong>samplerShadow</strong> types:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) uniform sampler mySampler;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %8 "mySampler" |
| OpDecorate %8 DescriptorSet m |
| OpDecorate %8 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeSampler |
| %7 = OpTypePointer UniformConstant %6 |
| %8 = OpVariable %7 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_textures_sampled_images">Textures (Sampled Images)</h5> |
| <div class="paragraph"> |
| <p>Textures are declared in GLSL shader source using uniform texture |
| variables of the appropriate dimensionality:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) uniform texture2D mySampledImage;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "mySampledImage" |
| OpDecorate %9 DescriptorSet m |
| OpDecorate %9 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 2D 0 0 0 1 Unknown |
| %8 = OpTypePointer UniformConstant %7 |
| %9 = OpVariable %8 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_combined_texture_and_samplers">Combined Texture and Samplers</h5> |
| <div class="paragraph"> |
| <p>Combined textures and samplers are declared in GLSL shader source using |
| uniform texture-combined sampler variables of the appropriate dimensionality:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) uniform sampler2D myCombinedImageSampler;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %10 "myCombinedImageSampler" |
| OpDecorate %10 DescriptorSet m |
| OpDecorate %10 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 2D 0 0 0 1 Unknown |
| %8 = OpTypeSampledImage %7 |
| %9 = OpTypePointer UniformConstant %8 |
| %10 = OpVariable %9 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that a combined image sampler descriptor can be referred to as just |
| an image or sampler in the shader as per the above sections.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_combining_separate_samplers_and_textures">Combining Separate Samplers and Textures</h5> |
| <div class="paragraph"> |
| <p>A sampler, declared with the keyword <strong>sampler</strong>, contains just filtering |
| information, containing neither a texture nor an image:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>uniform sampler s; // a handle to filtering information</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A texture, declared with keywords like <strong>texture2D</strong>, contains just image |
| information, not filtering information:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>uniform texture2D t; // a handle to a texture (an image in SPIR-V)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Constructors can then be used to combine a sampler and a texture at the |
| point of making a texture lookup call:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>texture(sampler2D(t, s), ...);</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note, <code>layout()</code> information is omitted above for clarity of this feature.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_texture_buffers_uniform_texel_buffers">Texture Buffers (Uniform Texel Buffers)</h5> |
| <div class="paragraph"> |
| <p>Texture buffers are declared in GLSL shader source using uniform |
| textureBuffer variables:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) uniform textureBuffer myUniformTexelBuffer;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "myUniformTexelBuffer" |
| OpDecorate %9 DescriptorSet m |
| OpDecorate %9 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 Buffer 0 0 0 1 Unknown |
| %8 = OpTypePointer UniformConstant %7 |
| %9 = OpVariable %8 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_image_buffers_storage_texel_buffers">Image Buffers (Storage Texel Buffers)</h5> |
| <div class="paragraph"> |
| <p>Image buffers are declared in GLSL shader source using uniform |
| imageBuffer variables:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n, r32f) uniform imageBuffer myStorageTexelBuffer;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "myStorageTexelBuffer" |
| OpDecorate %9 DescriptorSet m |
| OpDecorate %9 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 Buffer 0 0 0 2 R32f |
| %8 = OpTypePointer UniformConstant %7 |
| %9 = OpVariable %8 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_storage_buffers">Storage Buffers</h5> |
| <div class="paragraph"> |
| <p>Storage buffers are declared in GLSL shader source using buffer storage |
| qualifier and block syntax:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) buffer myStorageBuffer |
| { |
| vec4 myElement[]; |
| };</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "myStorageBuffer" |
| OpMemberName %9 0 "myElement" |
| OpName %11 "" |
| OpDecorate %8 ArrayStride 16 |
| OpMemberDecorate %9 0 Offset 0 |
| OpDecorate %9 BufferBlock |
| OpDecorate %11 DescriptorSet m |
| OpDecorate %11 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 4 |
| %8 = OpTypeRuntimeArray %7 |
| %9 = OpTypeStruct %8 |
| %10 = OpTypePointer Uniform %9 |
| %11 = OpVariable %10 Uniform |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_uniform_buffers">Uniform Buffers</h5> |
| <div class="paragraph"> |
| <p>Uniform buffers are declared in GLSL shader source using the uniform storage |
| qualifier and block syntax:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (set=m, binding=n) uniform myUniformBuffer |
| { |
| vec4 myElement[32]; |
| };</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %11 "myUniformBuffer" |
| OpMemberName %11 0 "myElement" |
| OpName %13 "" |
| OpDecorate %10 ArrayStride 16 |
| OpMemberDecorate %11 0 Offset 0 |
| OpDecorate %11 Block |
| OpDecorate %13 DescriptorSet m |
| OpDecorate %13 Binding n |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 4 |
| %8 = OpTypeInt 32 0 |
| %9 = OpConstant %8 32 |
| %10 = OpTypeArray %7 %9 |
| %11 = OpTypeStruct %10 |
| %12 = OpTypePointer Uniform %11 |
| %13 = OpVariable %12 Uniform |
| ...</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_subpass_inputs_2">Subpass Inputs</h5> |
| <div class="paragraph"> |
| <p>Within a rendering pass, 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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Subpass inputs are read through a new set of types, available only |
| to fragment shaders:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>subpassInput |
| subpassInputMS |
| isubpassInput |
| isubpassInputMS |
| usubpassInput |
| usubpassInputMS</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Unlike sampler and image objects, subpass inputs are implicitly addressed |
| by the fragment’s (<em>x</em>, <em>y</em>, <em>layer</em>) coordinate.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Input attachments are decorated with their input attachment index in |
| addition to descriptor set and binding numbers.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>layout (input_attachment_index=i, set=m, binding=n) uniform subpassInput myInputAttachment;</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Which maps to the following SPIR-V:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> ... |
| %1 = OpExtInstImport "GLSL.std.450" |
| ... |
| OpName %9 "myInputAttachment" |
| OpDecorate %9 DescriptorSet m |
| OpDecorate %9 Binding n |
| OpDecorate %9 InputAttachmentIndex i |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeImage %6 SubpassData 0 0 0 2 Unknown |
| %8 = OpTypePointer UniformConstant %7 |
| %9 = OpVariable %8 UniformConstant |
| ...</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>An <em>input_attachment_index</em> of i selects the ith entry in the input pass |
| list. (See API specification for more information.)</p> |
| </div> |
| <div class="paragraph"> |
| <p>These objects support reading the subpass input through the following |
| functions:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>gvec4 subpassLoad(gsubpassInput subpass); |
| gvec4 subpassLoad(gsubpassInputMS subpass, int sample);</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_variables">14.2.5. Mapping Variables</h4> |
| <div class="sect4"> |
| <h5 id="_gl_fragcolor"><em>gl_FragColor</em></h5> |
| <div class="paragraph"> |
| <p>The fragment-stage built-in <em>gl_FragColor</em>, which implies a broadcast to all |
| outputs, is not present in SPIR-V. Shaders where writing to <em>gl_FragColor</em> |
| is allowed can still write to it, but it only means to write to an output:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>of the same type as <em>gl_FragColor</em></p> |
| </li> |
| <li> |
| <p>decorated with location 0</p> |
| </li> |
| <li> |
| <p>not decorated as a built-in variable.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>There is no implicit broadcast.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_vulkan_gl_vertexindex_and_gl_instanceindex">Vulkan <em>gl_VertexIndex</em> and <em>gl_InstanceIndex</em></h5> |
| <div class="paragraph"> |
| <p>Adds two new built-in variables, <em>gl_VertexIndex</em> and <em>gl_InstanceIndex</em> to |
| replace the existing built-in variables <em>gl_VertexID</em> and <em>gl_InstanceID</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the situations where the indexing is relative to some base offset, |
| these built-in variables are defined, for Vulkan, to take on values as |
| follows:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>gl_VertexIndex base, base+1, base+2, ... |
| gl_InstanceIndex base, base+1, base+2, ...</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where it depends on the situation what the base actually is.</p> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_storage_classes">Storage Classes:</h5> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>uniform sampler2D...; -> UniformConstant |
| uniform blockN { ... } ...; -> Uniform, with Block decoration |
| in / out variable -> Input/Output, possibly with block (below) |
| in / out block... -> Input/Output, with Block decoration |
| buffer blockN { ... } ...; -> Uniform, with BufferBlock decoration |
| shared -> Workgroup |
| <normal global> -> Private</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>Vulkan Only: buffer blockN { ... } ...; -> StorageBuffer, when requested |
| OpenGL Only: uniform variable (non-block) -> UniformConstant |
| OpenGL Only: ... uniform atomic_uint ... -> AtomicCounter</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_inputoutput">Input/Output</h5> |
| <div class="paragraph"> |
| <p>Mapping of input/output blocks or variables is the same for all versions |
| of GLSL or ESSL. To the extent variables or members are available in a |
| version, its location is as follows:</p> |
| </div> |
| <div class="paragraph"> |
| <p>These are mapped to SPIR-V individual variables, with similarly spelled |
| built-in decorations (except as noted):</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any stage:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>in gl_VertexIndex (Vulkan only) |
| in gl_VertexID (OpenGL only) |
| in gl_InstanceIndex (Vulkan only) |
| in gl_InstanceID (OpenGL only) |
| in gl_InvocationID |
| in gl_PatchVerticesIn (PatchVertices) |
| in gl_PrimitiveIDIn (PrimitiveID) |
| in/out gl_PrimitiveID (in/out based only on storage qualifier) |
| in gl_TessCoord</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>in/out gl_Layer |
| in/out gl_ViewportIndex</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>patch in/out gl_TessLevelOuter (uses Patch decoration) |
| patch in/out gl_TessLevelInner (uses Patch decoration)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Compute stage only:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>in gl_NumWorkGroups |
| in gl_WorkGroupSize |
| in gl_WorkGroupID |
| in gl_LocalInvocationID |
| in gl_GlobalInvocationID |
| in gl_LocalInvocationIndex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Fragment stage only:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>in gl_FragCoord |
| in gl_FrontFacing |
| in gl_ClipDistance |
| in gl_CullDistance |
| in gl_PointCoord |
| in gl_SampleID |
| in gl_SamplePosition |
| in gl_HelperInvocation |
| out gl_FragDepth |
| in gl_SampleMaskIn (SampleMask) |
| out gl_SampleMask (in/out based only on storage qualifier)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>These are mapped to SPIR-V blocks, as implied by the pseudo code, with |
| the members decorated with similarly spelled built-in decorations:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Non-fragment stage:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>in/out gl_PerVertex { // some subset of these members will be used |
| gl_Position |
| gl_PointSize |
| gl_ClipDistance |
| gl_CullDistance |
| } // name of block is for debug only</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There is at most one input and one output block per stage in SPIR-V. |
| The subset and order of members will match between stages sharing an |
| interface.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_vulkan_only_mapping_of_precision_qualifiers">14.2.6. Vulkan Only: Mapping of Precision Qualifiers</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>lowp -> RelaxedPrecision, on storage variable and operation |
| mediump -> RelaxedPrecision, on storage variable and operation |
| highp -> 32-bit, same as int or float</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>portability tool/mode -> OpQuantizeToF16</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_precise">14.2.7. Mapping of <strong>precise</strong>:</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>precise -> NoContraction</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_opengl_mapping_of_atomic_uint_offset_layout_qualifier">14.2.8. OpenGL Mapping of <strong>atomic_uint</strong> <em>offset</em> layout qualifier</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>offset -> Offset (decoration)</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_images">14.2.9. Mapping of Images</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>imageLoad() -> OpImageRead |
| imageStore() -> OpImageWrite |
| texelFetch() -> OpImageFetch |
| subpassInput -> OpTypeImage with Dim of SubpassData (Vulkan only) |
| subpassLoad() -> OpImageRead (Vulkan only)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>imageAtomicXXX(params, data) -> %ptr = OpImageTexelPointer params |
| OpAtomicXXX %ptr, data</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>XXXQueryXXX(combined) -> %image = OpImage combined |
| OpXXXQueryXXX %image</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_layouts">14.2.10. Mapping of Layouts</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>std140/std430 -> explicit Offset, ArrayStride, and MatrixStride |
| Decoration on struct members |
| shared/packed -> not allowed |
| <default> -> not shared, but std140 or std430 |
| xfb_offset -> Offset Decoration on the object or struct member |
| xfb_buffer -> XfbBuffer Decoration on the object |
| xfb_stride -> XfbStride Decoration on the object |
| any xfb_* -> the Xfb Execution Mode is set |
| captured XFB -> has both XfbBuffer and Offset |
| non-captured -> lacking XfbBuffer or Offset</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>max_vertices -> OutputVertices</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_barriers">14.2.11. Mapping of barriers</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>barrier() (compute) -> OpControlBarrier(/*Execution*/Workgroup, |
| /*Memory*/Workgroup, |
| /*Semantics*/AcquireRelease | |
| WorkgroupMemory)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>barrier() (tess control) -> OpControlBarrier(/*Execution*/Workgroup, |
| /*Memory*/Invocation, |
| /*Semantics*/None)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>memoryBarrier() -> OpMemoryBarrier(/*Memory*/Device, |
| /*Semantics*/AcquireRelease | |
| UniformMemory | |
| WorkgroupMemory | |
| ImageMemory)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>memoryBarrierBuffer() -> OpMemoryBarrier(/*Memory*/Device, |
| /*Semantics*/AcquireRelease | |
| UniformMemory)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>memoryBarrierShared() -> OpMemoryBarrier(/*Memory*/Device, |
| /*Semantics*/AcquireRelease | |
| WorkgroupMemory)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>memoryBarrierImage() -> OpMemoryBarrier(/*Memory*/Device, |
| /*Semantics*/AcquireRelease | |
| ImageMemory)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>groupMemoryBarrier() -> OpMemoryBarrier(/*Memory*/Workgroup, |
| /*Semantics*/AcquireRelease | |
| UniformMemory | |
| WorkgroupMemory | |
| ImageMemory)</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_atomics">14.2.12. Mapping of atomics</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>all atomic builtin functions -> Semantics = None(Relaxed)</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>atomicExchange() -> OpAtomicExchange |
| imageAtomicExchange() -> OpAtomicExchange |
| atomicCompSwap() -> OpAtomicCompareExchange |
| imageAtomicCompSwap() -> OpAtomicCompareExchange |
| N/A -> OpAtomicCompareExchangeWeak</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_opengl_only_mapping_of_atomics">14.2.13. OpenGL Only: Mapping of Atomics</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>atomicCounterIncrement -> OpAtomicIIncrement |
| atomicCounterDecrement -> OpAtomicIDecrement |
| atomicCounter -> OpAtomicLoad</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_mapping_of_other_instructions">14.2.14. Mapping of other instructions</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>% -> OpUMod/OpSMod |
| mod() -> OpFMod |
| N/A -> OpSRem/OpFRem</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>pack/unpack (conversion) -> pack/unpack in GLSL extended instructions |
| pack/unpack (no conversion) -> OpBitcast</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="footer"> |
| <div id="footer-text"> |
| Version 3.20.6<br> |
| Last updated 2019-07-10 14:42:53 MDT |
| </div> |
| </div> |
| |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script> |
| </body> |
| </html> |