Vertex Shaders

   學習了頂點處理,你就知道固定功能流水線怎麼將頂點從模型空間座標系統轉化到屏幕空間座標系統。雖然固定功能流水線也可以通過設置渲染狀態和參數來改變最終輸出的結果,但是它的整體功能還是受限。當我們想實現一個外來的光照模型,外來的Fog或者點大小計算方式,等等,我們可能就放棄使用固定功能流水線,轉而使用CPU來實現這些計算。

   使用vertex shaders,它用一段小程序替換固定功能處理。這段小程序的輸入是模型空間的頂點,輸出齊次剪裁空間的頂點,並且還攜帶一些信息,如:per-vertex diffuse 和 specualr,霧,透明度,紋理座標和點大小。

  這一節我們將先講述vertex shaders的彙編語言編程模型。

 

Vertex Shader Arichitecture

 

    Direct3D對於不同的圖形處理器有不同的vertex shaders架構版本。每個版本都有不同數目和類型的寄存器和不同的指令集。一般情況,高版本一般是低版本的衍生品,提供了更多的指令和更少限制。我們將先看完整的1.1版本,然後討論各個版本在上面的增量。 

    DirectX 9.0c 支持的vertex shader版本包括1.1,2.0,2.x和3.0。 這些版本的彙編語言的語法標誌是:vs_1_1, vs_2_0, vs_2_x和vs_3_0。在老的SDK和文檔裏面,你也許會看到vs_2_a和vs_2_b,他們已經融合到了vs_2_x版本里面了。當你安裝SDK的時候,vertex shader的特殊版本也將會安裝,如vs_2_sw和vs_3_sw,這兩個版本只用於軟件處理,專門用於做模擬和調試之用。shader的軟件版本實現了2.0和3.0架構所有的功能,並且大部分的shader驗證將被放開。

shader 版本 vs_1_1 vs_2_0 vs_2_x vs_3_0
指令數目 128 256 >=256 >=512

     所有的架構都共享一個公共的執行模型。執行程序稱做shader,它在每個頂點上執行一次。shader包含一個或多個指令,每個指令由一個操作碼與0個或多個操作數組成的。shader可以訪問五組不同的寄存器:頂點數據的input寄存器,渲染參數的const寄存器,用於查詢const寄存器的地址寄存器,存儲臨時數據的臨時寄存器,採樣紋理的採樣寄存器,shader輸出結果的ouput寄存器。不同類型寄存器的數目如下表。

Version a0 aL bn cn in on p0 rn sn vn
vs_1_1 1 0 0 >=96 0 13 0 12 0 16
vs_2_0 1 1 16 >=256 16 13 0 12 0 16
vs_2_x 1 1 16 >=256 16 13 1 >=12 0 16
vs_3_0 1 1 16 >=256 16 12 1 32 4 16

    每個臨時寄存器都存儲一個四維的向量值,大多數指令都是在四維向量上進行操作。每個值都是一個浮點值,一般有6個小數數字。指令一般是通用算術運算,如加,乘和一般的向量計算(點積,向量矩陣乘法)。跟一般的CPU不一樣的是,低版本的shader一般不支持流控制,以便於shader更加簡單和容易硬件加速。

  • input 寄存器

    頂點組件通過合適的頂點聲明映射到對應的semantics上。semantics使用dcl_usage指令與shader的輸入寄存器關聯。輸入寄存器是隻讀的,只能用作頂點shader指令的數據源。雖然不同的操作數能應用到不同的修飾符,每個指令只能引用一個input regesiter。

  • const 寄存器和地址寄存器

     不隨着每個頂點變化的參數可以存放在const 寄存器。所有的shader版本都支持浮點const,整數const , bool const只能用在2.0以上的shader版本。每個指令一次只能訪問一個const 寄存器,但是不同的源操作數可以訪問帶有修飾符的同一個const寄存器。 const寄存器值在shader 裏面一般是通過def, defb和defi指令定義的,它也能來自於設備,通過方法:SetVertexShaderConstantF, SetVertexShaderConstantB 和 SetVertexShaderConstantI。你可以認爲通過shader指令定義的值爲local const,而通過設備方法定義的const爲global const。

    地址寄存器是一個帶符號的整數,記錄了距離base const寄存器的位置偏移量。const寄存器是隻讀的,地址寄存器是可寫的。當地址寄存器越界,它的值將是(0,0,0,0)。在使用地址寄存器之前,必須先初始化它。

    shader 1.1 只能使用地址寄存器的x組件來作爲索引。並且地址寄存器只能被設置成mov指令的目的地,當使用它的時候它將進行四捨五入成整數。 shader 2.0以上的版本提供了更加通用的一種使用方式。寄存器的四個組件都可以用來作爲索引,能夠同時索引const寄存器的不同的部分。mova指令用於設置地址寄存器的值。   

  • output寄存器

     output寄存器用於存儲shader計算的結果。output寄存器是可寫的。它用來存儲頂點的同次剪裁空間的座標以及每個頂點相關的數據,如顏色,紋理座標信息。3.0之前的shader版本,output寄存器將會分別命名。位置寄存器oPos, 顏色寄存器oD0和oD1,fog 寄存器oFog,點大小寄存器oPts和紋理座標寄存器oT0到oT7。 每個頂點shader都得寫oPos的四個組件。fog係數和點大小的縮放值將分別取oFog和oPts寄存器的x組件。oFog和oPts將被縮放到【0,1】區間。在shader 3.0版本,output寄存器將會使用dcl_usage指令定義。

  • 臨時寄存器

     頂點shader裏面通常會有大量的工作。shader 通常會將數據從輸入寄存器移動到臨時寄存器,然後在臨時寄存器上執行計算,最後把結果寫入到輸出寄存器。其他類型的寄存器在一個指令可能只使用一次,但是臨時寄存卻有可能使用多次。在一個指令裏面有可能有3個臨時寄存器被讀,一個被寫。任何讀取一個沒有寫入數據的臨時寄存器都會產生錯誤。

  • 循環計數器寄存器

     shader 2.0或者更高版本使用loop和endloop指令來控制流,循環計數寄存器al包含計數器的當前值。在循環體外部,這個值是未定義的。在循環體內部它的值將是固定數組的偏移量。在shader 3.0中,循環計數寄存器將用於索引輸出寄存器和const數組。

  • 條件寄存器

     shader 2.x 或者更高版本將提供了條件寄存器,它包含一個boo值的四維向量。bool值將用於執行條件控制流。setp_comp是唯一的賦值條件寄存器的指令。條件寄存器bool值用來控制if ,callnz,breakp指令。

  • 採樣寄存器

     shader3.0 採用採樣寄存器來訪問紋理。採樣寄存器本身使用texldl指令來採樣紋理。採樣寄存器在使用前必須使用dcl_usage聲明。使用採樣寄存器,頂點shader能夠執行紋理查詢。

  • 寄存器修飾符

     每個指令默認情況下操作在源操作數和目的操作數的四維向量值上。爲了提高頂點shader的靈活性,並且使指令數減少,每個操作數可以包含一個修飾符來提取某幾個維度的值。對於頂點shader指令,共有四種修飾符:目的操作數寫掩碼,源操作數multiplex,源操作數negation和絕對值操作數。修飾符的語法如下:

目的寄存器寫掩碼: r.xyzw

源寄存器multiplex: r.[xyzw][xyzw][xyzw][xyzw]

源寄存器negation:  -r

絕對值:   r_abs

邏輯negation:  !r

multiplex修改符允許一個四維向量從一個源寄存器的四個組件構造得到。一個組件可能被組合到一個向量的多個組件。

一個操作數也能使用多個修飾符,多個修飾符也能應用到一個指令裏面。

 

Vertex Shader 1.1 架構

 

    shader 1.1架構是最簡單的架構,沒流控制也沒有條件分支。最少有96個頂點shader const 寄存器。D3DCAPS9::MaxVertexShaderConst定義最大數目的const寄存器。constant寄存器在被地址寄存器的x組件索引。

    指令用於聲明,基本運算,矩陣計算,簡單比較以及基本光照計算。更高版本的shader能完全支持1.1的指令,只是在某些指令上有些微小的變動。

 

Vertex Shader 2.0 架構

 

   2.0架構保留了1.1所有的指令和寄存器,並且增加了很多額外的功能。版本2.0主要的改進增加了是靜態流控制。靜態條件指令包括subroutine,分支和循環指令。在靜態流控制裏面,計算分支點的條件表達式指向那些在shader執行過程中是const的值。使用靜態流控制,執行固定次數的循環,並且條件執行遵循同樣的路徑使用同一組constants來繪製primitives。 primitives的不同的batch處理可以通過改變constants來改變它們的行爲。所有的流控制指令都是成對出現,並且屬於一個指令block。

   提供了新的constant寄存器文件來定義了用於管理控制流的constants。在控制流裏面,你能寫一個頂點shader應用到不同類型的頂點。定義流的constants可以在兩次draw primitives調用之間重新更新。

   2.0版本或者更高版本也增強了地址寄存器的使用,提供了新的bool和整數寄存器文件。寄存器a0的四個組件都可以用來索引浮點數寄存器文件。bool和整數寄存器文件不可以被索引。地址寄存器的任何一個組件都可以用作一個索引,但是在一個指令裏面的所有的源操作數必須用同樣的組件和base寄存器。

   地址寄存器能夠使用mova指令來賦值,mov指令用於向臨時寄存器和output寄存器寫值。新的算術指令包括:abs,crs,lrp,nrm, pow, sgn和sincos指令。bool constant寄存器用於if,else,endif指令的條件分支。每個寄存器都有一個組件包含一個bool值。bool 寄存器文件的值能通過defb指令賦值。非條件suroutine使用call調用。subroutine的調用對象是lable和ret之間的block。 使用bool寄存器的條件subroutine使用callnz調用。整數constant寄存器文件裏面每個寄存器都有四個組件,但是第四個組件必須是0。 寄存器控制了rep, endrep,loop和endloop循環的執行次數。rep使用一個重複次數定義了一個簡單的循環,在循環過程中,不會訪問內部計數寄存器。    Loop指令定義了一個循環,這個循環通過al 循環計數寄存器控制內部計數器。在循環開始之前,就初始化這個寄存器。每當循環一次,它就加1。這個循環計數寄存器也可以像地址寄存器一樣來索引constant寄存器數組。整數寄存器文件的值能通過defi定義或者通過API SetVertexShaderConstantI方法定義。

 

頂點Shader 2.x 架構

 

   頂點2.x引入了版本2.0架構的擴展。在版本2.0的基礎上增加了條件,靜態流控制的深度嵌套和動態流控制指令。D3DCaps9的VS20Caps(它是一個D3DVSSHADERCAPS2_0結構)描述了可選的支持情況。2.x可選的支持包括predicate寄存器,動態流控制,大於12個臨時寄存器和靜態流控制的深度嵌套。

typedef struct _D3DVSHADERCAPS2_0

{

     DWORD  Caps;

     INT  DynamicFlowControlDepth;

     INT NumTemps;

     INT StaticFlowControlDepth;

} D3DVSHADERCAPS2_0;

 

   如果Caps的D3DVS20CAPS_PREDICATION爲被設置,設備將支持predicate寄存器p0和它相關的指令setp_comp,if, callnz和breakp。predicate寄存器是一個四維的bool向量,只能通過setp_cmp賦值。

   NumpTemps制定了能支持的臨時寄存器rn的數目,一般至少是12個,它的實際值將在【12,32】之間,D3DVS20_MIN_NUMTEMP和D3DVS20_MAX_NUMTEMPS指定了最大值和最小值。

   動態流控制的指令包括if_comp和break_comp。 如果dynamicFlowControlDepth不是0,它將能支持。

 

頂點Shader 3.0架構

 

   頂點shader 3.0放開了很多限制,產生了input和output寄存器文件,增加了saturate指令修飾符,並且使用新的採樣寄存器和相關指令來做紋理採樣。臨時寄存器的數目上升到32個。最小的指令slot可以達到512。input 和 output寄存器文件可以像浮點const 寄存器一樣被索引。它允許shader在一個循環裏面訪問input寄存器,然後產生ouput。output寄存器不用指定特定的名字,它就像input寄存器,統一命名爲on。它可以使用dcl_usage指定把output寄存器與一個semantics關聯。這樣就可以將shader的output映射到像素shader的input semantics。

    sn採樣寄存器與dcl_texture關聯。聲明之後,就可以使用texldl指令從對應的紋理採樣。

 

Shader指令語法

 

   在內部Direct3D使用一個DWORD數組來encode一個shader程序。這個encoding可以被認爲是一個shader程序的機器語言。因爲很難直接創建一個DWORD數組程序指令,SDK提供了工具把一個shader程序文本編譯成機器語言。

    shader指令的語法也跟大多數CPU彙編語言類似,首先是操作碼,然後是操作數。shader 程序文本首先被解析成一串可解析的符號。空格和註釋將會被忽略。跟其它彙編語言不同的是,它不必一行只能允許一條指令。一行可以寫多條指令。

   每個shader指令是由一個操作碼和多個操作數組成,並且他們都是大小寫敏感的。通常const寄存器操作數一般是c0....。但是,可以通過地址寄存器a0來索引const寄存器,c[16+a0.x] 或者c16[a0.x]。

 

執行模型

   頂點shader的執行模型是相當簡單,每個指令按照它在DWORD裏面的次序執行。每個頂點shader的開始都必須放置一個vs指令,用來定義頂點shader的架構版本。 3.0之前的版本,都必須把值存放在oPos寄存器;3.0版本,output postion semantic關聯的寄存器必須要賦值。

 

頂點軟件處理

   使用軟件或者混合處理創建的設備可以在CPU上運行頂點shader。頂點軟件處理能夠執行所有的頂點shader版本。

 

頂點shader 1.1 指令

   頂點shader指令分成兩組,一組是簡單指令,一組是複雜指令。簡單指令只在一個slot裏面執行,複雜指令需要在多個slot裏面執行。1.1支持的指令如下:

Instruction Slots Function
add d,s0,s1 1 add
dcl_usage d —— declare input register
def d,v0,v1,v2,v3 —— constant definition
dp3 d,s0,s1 1 3D dot product
dp4 d,s0,s1 1 4D dot product
dst d,s0,s1 1 distance
exp d,s <=10 full-precision exponentiate(指數)
expp d,s 1 patial-precision exponentiate
frc d,s <=3 fractional part(小數部分)
lit d,s 1 lighting
log d,s <=10 full-precision logarithm(全精度對數)
logp d,s 1 partial-precision(半精度對數)
m3*2 d,s0 ,s1 <=2 vector, 3*2 matrix product
m3*3 d,s0,s1 <=3 vector, 3*3 matrix product
m3*3 d,s0,s1 <=4 vector, 3*4 matrix product
m4*3 d,s0,s1 <=3 vector, 4*3 matrix product
m4*4 d,s0,s1 <=4 vector,4*4 matrix product
mad d,s0,s1,s2 1 multiply accumulate
max d,s0,s1 1 maximum
min d,s0,s1 1 minimum
mov d,s 1 copy
mul d,s0,s1 1 multiply
nop 1 no operation
rcp d,s >=1 reciprocal(倒數)
rsp  d,s >=1 reciparocal square root
sge d,s0,s1 1 >= compare
slt d,s0,s1 1 < compare
sub d,s0,s1 1 sutract
vs _major_minor_ —— shader version

    在詳細討論每個指令之前,我們先看看一個簡單的shader程序。這個shader 程序把輸入頂點數據直接寫入到對應的output寄存器。

vs_1_1

dcl_position v0

dcl_color0   v1

dcl_color1   v2

dcl_fog      v2.w

dcl_texcoord0 v3

dcl_texcoord1 v4

dcl_texcoord2 v5

dcl_texcoord3 v6

mov oPos, v0

mov oDo , v1

mov oD1,  v2.xyz

mov oFog, v2.w

mov oT0,v3

mov oT1,v4

mov oT2,v5

mov oT3,v6

 

  • 指令聲明

 每個頂點shader都必須使用vs指令聲明它的版本號碼,而且這個指令必須是這個shader程序的第一個指令。在shader通過SetVertexShader綁定到到設備的時候,頂點shader的constants也需要綁定。def 指令可以用來定義一個四浮點值的constant寄存器。def指令必須出現在版本指令之後,在任何計算指令之前。

def d,v0,v1,v2,v3 ------------->    d<---------(v0,v1,v2,v3)

   爲了將頂點的input寄存器映射到頂點對應的組件,dcl_usage指令被使用。

dcl_positionn s

dcl_blendweightn s

dcl_blendindicesn s

dcl_normaln s

dcl_psizen  s

dcl_texcoordn s

dcl_tangentn s

dcl_binormaln s

dcl_tessfactorn s

dcl_colorn s

dcl_fogn s

dcl_depthn s

dcl_sample s

 

  • 基本算術指令

  mov指令用來拷貝數據從源操作數到目的操作數。基本的運算執行只使用add,sub,mul 和mad指令。向量的加減使用add和sub指令。

mov d ,s     d<-------s

add d,s0,s1   d<---------(s0x+s1x,s0y+s1y,s0z+s1z,s0w+s1w)

sub d, s0,s1  d<---------(s0x-s1x,s0y-s1y,s0z-s1z,s0w-s1w)

mul d,s0,s1   d<---------(s0x s1x,s0y s1y,s0z s1z,s0w s1w)

mad d,s0,s1,s2   d<---------(s0x s1x + s2x, s0y s1y +  s2y, s0z s1z + s2z,   s0w s1w + s2w)

rcp  d, s   只計算w 組件。

      如果sw = 1,  d = (1,1,1,1); 如果sw = 0, d = (無窮大,無窮大,無窮大,無窮大);否則,d= (1/sw,1/sw,1/sw,1/sw)。

rsp d,s

      如果abs(sw) = 1, d = (1,1,1,1); 如果abs(sw) = 0,d = (無窮大,無窮大,無窮大,無窮大); 否則 d= (1/squart root(sw), 1/squart root(sw),1/squart root(sw),1/squart root(sw))

dp3 d, s0,s1

    d = (f,f,f,f)  f = s0x s1x + s0y s1y + s0z s1z

dp4 d, s0,s1

    d= (f,f,f,f)  f = s0x s1x + s0y s1y + s0z s1z + s0w s1w

min d , s0,s1

    d = (min(s0x,s1x),min(s0y,s1y),min(s0z,s1z),min(s0w,s1w))

max d, s0,s1

    d = (max(s0x,s1x),max(s0y,s1y),max(s0z,s1z),max(s0w,s1w))

exp d,s

     d = (f,f,f,f) f=2爲底指數爲sw的冪

log  d,s

     如果|sw| = 0 ,d = (負無窮大,負無窮大,負無窮大,負無窮大);否則,d= (f,f,f,f)  f= log2(|sw|) 

  • 矩陣指令

   m3*2, m3*3,m3*4,m4*4都是向量與矩陣相乘的指令。他們第一個操作數是向量,第二次操作數是矩陣。矩陣存放在連續的寄存器裏面,並且在同一個寄存器文件裏面。只有4*4,3*4修改了所有的四個組件,m3*2只修改xy,m3*3和m4*3只計算xyz。

  • 比較指令

   雖然1.1裏面不可以使用分支指令,但是執行一些有限的比較也是可能的。如果你想要在diffuse color上再增加一個color。既然分支計算不允許,你只能寫兩個shader。一個增加顏色,一個不增加顏色。然而,你也可以在一個shader裏面實現,當你不想增加的時候,另外一個顏色是0。sge和slt指令讓你可以這麼多。

sge d,s0,s1

    d = (s0x >= s1x, s0y>=s1y,s0z >= s1z, s0w >= s1w)。 True的時候組件是1.0, False的時候組件值是0.0。

slt  d,s0,s1

     d= (s0x < s1x, s0y < s1y, s0z <s1z,s0w<s1w)。

  • 光照指令

   dst 和 lit指令用於光照效果的計算。dst計算向量s0(*,k的平方,k的平方,*)和 s1=(*,1/k,*,1/k)的距離向量。 lit指令計算光照係數,給定兩個dot product和一個指數。源寄存器的x組件包含頂點法線和光線的點積,y組件包含頂點法線和halfway向量的點積,w組件包含一個指數。這個指數範圍將在[-128,128]。

   dst  d,s0, s1

         d = (1,k,k2,1/k)  s0=(*,k的平方,k平方,*)    s1= (*,1/k,*,1/k)

   lit   d, s

         如果sx >0 , sy >0 , d = (1,sx,sy爲底指數爲sw的冪,1);

         如果sx>0,   sy<=0 , d = (1,sx,0,1)

         否則,d= (1,0,0,1)

 

頂點Shader2.0 指令

   

     defb和def 定義bool和整數constant寄存器。

     defb d, v

          d = v

      defi  d, i0,i1,i2,i3

          d= (i0,i1,i2,i3)

      mova d, s

          d= (round(sx),round(sy),round(sz),round(sw))

      abs d,s

           d= (|sx|,|sy|,|sz|,|sw|)

       sgn d,s0,s1,s2

            d= (f(s0x),f(s0y),f(s0z),f(s0w))

            f(x) =-1(x<0); 0 (x=0); 1;(x>0)

       crs d,s0,s1  d爲s0和s1的叉積

       nrm d, s normalize向量s。

Instruction Slots Function
abs d,s 1 absolute value
call l 2 call a subroutine
callnz l,b 3 contionally call a subroutine
crs d, s0,s1 2 vector cross product
defb d, v0 —— bool constant definition
defi  d,v0,v1,v2,v3 —— integer constant definition
else 1 start a else block
endif 1 end an if or esle block
endloop 2 end a loop block
endrep 2 end a repeat block
if b 3 start an if block
label l —— start subroutine block
loop aL, i 3 start a loop block
lrp d,s0,s1,s2 2 linear interpolation
mova d,s 1 write a address register
nrm   d, s 3 vector normalization
pow d,s0,s1 3 full precision s0爲底s1爲指數的冪
rep i 3 start a repeat block
ret 1 end a subroutine block
sgn  d, s 3 sign function
sincos d, s0,s1,s2 8 sine and cosine,d = (cos(soc),sin(s0c),?,?);目的寄存器必須是一個臨時寄存器,並且必須使用寫掩碼.x,.y和.xy。s1,s2是浮點固定寄存器,他們的值分別是D3DSINCOSCONST1和D3DSINCOSCONST2。

   最簡單的循環是一個repeat block,如下:

rep i  //使用一個整數const寄存器作爲操作數,它的x組件將是循環的次數,範圍在[0,255]。

      count <---ix

      loop <----pc+1 //pc指向程序計數器,pc+1就是下個程序指令的地址

      if count = 0 then pc <-------endloop

endrep

     endloop <----- pc+1

     count <---------count -1

     if count >0  then pc <------- loop

 

loop循環重複執行loop和endloop之間的代碼block,一個loop block通過aL寄存器控制循環,al寄存器將作爲目的操作數。

loop aL,i

        aL <--- iy

        count <----ix

        loop <-------pc=1

        if count = 0 then pc<--------endloop

endloop

       endloop <----- pc+1

      count <---------count -1

       aL <----------aL + iz

      if count >0  then pc <------- loop

 

一個subroutine block將包含在lable和ret指令塊。 爲了使用一個subroutine,你必須在shader之前使用ret結束 main routine。

label l

         l <------------pc+1

ret

          pc <----------pop(pc)

call l

         push(pc,pc+1)

        pc <------------l

callnz  l,b

        if(b = true) then

           push(pc,pc+1)

            pc<-----l

         endif

 

  • 版本2.0 flow control 嵌套限制

GPU有限的的資源使shader裏面的流控制增加了一些限制。每種流控制指令(循環,分支,subroutine)都有對應的的嵌套限制。在一個指令block裏面嵌入另一個指令block,這就是嵌套block。嵌套限制如下表:

Feature 2.0 2.x 3.0
Call Nesting 1 1-4 4
static condition 16 16 24
Dynamic Conditions —— 0-24 0-24
Loop Nesting 1 1-4 4
static Flow count 16 16 無窮大

除了對嵌套的限制外,對控制流指令的數目也有限制。控制流指令的總數目稱作靜態流計數(static flow count)。if ,else,rep,loop,call和callnz都會增加static flow count。 在2.0裏面,靜態流條件指令只能出現在一個routine的top層。 call 和callnz也只能有一層調用,你不能在call裏面在調用另外一個call。Loop和rep也只能有一層嵌套,rep 可以放在if block裏面,但是它不能放在loop block。

 

頂點Shader 2.x指令

 

它在2.0的基礎上增加了predicate寄存器以及動態流控制。prediation指令一般是使用一個指令的修飾符來實現的。

新指令如下表:

Instruction Slots Function
break 1 break out of a loop
break_comp s0,1 3 conditionally break out of a loop
break p 3 conditionally break out of a loop
callnz l,p 3 conditionally call a subroutine
if_comp s0,s1 3 start a dynamic if block
if p 3 start a dynamic if block
setp_comp d,s0,s1 1 set predicate register

 

//p0= (true,false,false,true)

(p0.x) add r3,r1,r2   //r3 = r1+r2

(p0) add r4,r1,r2     //r4.x = r1.x + r2.x

                               // r4.w = r1.w + r2.w

(!p0.x) add r5, r1,r2 // r5 unchangned

setp_comp指令是唯一能寫入predicate寄存器的指令。

setp_eq d,s0,s1

           d = (s0x= s1x,s0y= s1y,s0z = s1z,s0w = s1w)

setp_ne , setp_ge,setp_gt,setp_le,setp_lt 這些指令都用於predicate寄存器賦值。

if 指令可以將predicate寄存器的某個組件結合起來使用,

break_eq s0.c,s1.c

         if s0c= s1c then pc<--- endloop

break_ne,break_ge,break_gt,break_le,break_lt 也break_eq類似。

if_eq s0.c,s1.c

         if(s0c = s1c) then ...

if_ne, if_ge,if_gt,if_le,if_lt 與if_eq類似。

 

頂點Shader 3.0指令

在3.0架構裏面,所有的ouput寄存器都必須聲明。聲明語法類似input的聲明語法,關聯一個semantic usage和索引。地址寄存器除了索引const 寄存器外,還可以索引input和output寄存器。3.0新增指令如下表:

Instruction Slots Function
dcl_position d 0 declare a positon output
dcl_blendweightn d 0 declare a blend weight output
dcl_blendindicesn d 0 declare a blend indices output
dcl_psizen d 0 declare a point size output
dcl_normaln d 0 declare a normal vector ouput
dcl_fogn  d 0 declare a fog factor output
dcl_texcoordn  d 0 declare a texture coordinate output
dcl_tangentn d 0 declare a tangent vector output
dcl_binormaln d 0 declare a binormal vector output
dcl_tessfactorn d 0 declare a tessellation factor output
dcl_depthn d 0 declare a depth output
dcl_2d s 0 declare a 2D texture sampler
dcl_cube s 0 declare a cube texture sampler
dcl_volume s 0 declare a volume texture sampler
texldl s 2 or 5 sample texture

 

3.0 架構在頂點處理階段引入了採樣功能。源紋理的拓撲結構使用dcl_2d,dcl_cube,dcl_volume指令聲明的。每個指令都攜帶單個操作數,它將採樣寄存器sn與一個紋理關聯起來。如: dcl_2d s, dcl_cube s , dcl_volume s。

一旦採樣寄存器被聲明,texldl指令用於將一個紋理採樣到一個臨時寄存器。下面的代碼描述了它的基本原理。

texldl d, s0,s1   //s0是紋理的紋理座標,s1是採樣寄存器,指示哪個紋理將會採樣。

     L = s0w + SSLODBias //s0w用於選擇mipmap level,如果這個值是負數,它將選擇紋理的the most detailed miplevel。它的小數部分將用於兩個miplevel之前插值。

     if(L<=0) then L = max(SSMaxMipLevel,0)

         L = max(SSMaxMipLevel,0)

         filter = SSMagFilter

         q = lookup(s0,s1,L,filter) //對紋理進行採樣

      else

          L = Max(SSMaxMipLevel,L)

         filter = SSMinFilter

         q = Lookup(s0,s1,floor(L),filter)

          if (SSMipFilter = Linear) then

              r = lookup(s0,s1,ceil(L),filter)

              f = s0w - floor(s0w)

              q = (1-f)q + fr

          endif

       endif

       d = q

 

Manipulating Shaders

 

    我們可以使用CreateVertexShader, SetVertexShader和GetVertexShader方法來管理頂點shader。應用程序可以使用D3DX把頂點shader源代碼編譯DWORD指令數組,提供給CreateVertexShader使用。如果你想要構建運行時動態shaders,最簡單的方法就是從字符串構建shader函數,然後把字符串編譯成DWORD指令數組。彙編shader比high level shader 語言要快,因爲它不必重新彙編shader。雖然high leve shader語言更消耗CPU,但是動態創建的high-level shader也可以按照這樣的方式執行。

    設備的頂點shader constant 文件屬性可以直接通過GetVertexShaderConstant和SetVertexShaderConstant管理。每個寄存器文件都它自己的設備方法,如:

HRESULT GetVertexShaderConstantB(DWORD start, BOOL* value, DWORD count);

HRESULT GetVertexShaderConstantF(DWORD start, float* value, DWORD count);

HRESULT GetVertexShaderConstantI(DWORD  start, int* value, DWORD count);

HRESULT  SetVertexShaderConstantB(DWORD start, const BOOL *value, DWORD count);

HRESULT  SetVertexShaderConstantF(DWORD start, const float* value, DWORD count)

HRESULT  SetVertexShaderConstantI(DWORD  start, const int * value, DWORD count);

    start 參數指示第一個寄存器的序號,count指示四維向量值的數目,value指向一個值的數組。下面的例子將在寄存器c15裏面存放一個值:

const float data[4] = {1.f,0.f,0.f,0.f};

device->SetVertexShaderConstantF(15,&data[0],1);

    頂點shader constant隨着頂點shader 聲明隱式的變化。constant寄存器的內容一直維持到設備rest。如果幾個頂點shader使用同樣的constant寄存器layout,constant寄存器可以只load一次,應用程序能夠在幾個頂點shader裏面前後前換,而不必重新load constant寄存器。 設備能支持的最大的constant寄存器的數目定義在D3DCAPS9::MaxVertexShaderConst。版本1.1至少是96個。

    如果D3DCAPS9::VertexShaderVersion非0,設備將支持頂點shader。

 

Drawing Multiple Instances

   頂點shader 3.0架構支持以不同的速率採樣不同的頂點流。這使我們能夠能夠繪製一個模型的多個實例,模型的數據將隨着每個頂點和每個實例變化。場景數據被至少將被分成兩組流,一組爲每頂點的數據,一組爲每實例的數據。source流的採樣頻率可以通過方法SetStreamSourceFreq方法設置。

HRESULT  SetStreamSourceFreq(UINT stream, UINT frequency);

   frequency將告訴runtime庫在跳到下一組組件之前每組頂點組件將需要重用多少次。Flags 將告訴runtime庫是否將將流解析成每頂點或者每實例。頂點shader 3.0版本支持instancing的索引流。頂點流的序號一般是從0開始,實例流的序號一般從大序號開始。

   最簡單的例子如,使用相同的幾何體,不同的每實例數據繪製n個幾何體實例。 幾何體數據將重複n次,實例數據將只重複一次。

   對於indexed primitives,將幾何流的頻率設置爲D3DSTREAMSOURCE_INDEXDATA與流重複次數的“或”連接,將實例流的平率設置爲D3DSTREAMSOURCE_INSTANCEDATA 與重用次數的"或"連接。

   如下例子:

struct GeometryVertex

{

        D3DVECTOR m_position;

       D3DVECTOR  m_normal;

}

struct InstanceVertex

{

        D3DVECTOR m_offset; //每個實例位置的偏移量

        D3DCOLOR  m_diffuse; //每個實例的diffuse color

}

IDirect3DVertexBuffer9 *geometry = fill_geometry();

IDirect3DVertexBuffer9* instance = fill_instance();

THR(device->SetStreamSource(0,geometry,0,sizeof(GeometryVertex)));

THR(device->SetStreamSourceFreq(0,D3DSTREAMSOURCE_INDEXEDDATA|20));

THR(device->SetStreamSource(1,instances,0,sizeof(InstanceVertex)));

THR(device->SetStreamSourceFreq(1,D3DSTREAMSOURCE_INSTANCEDATA | 1));

 

Common Computation

  • Constant generation

既然每個指令只能引用一個constant寄存器,使用多個constant寄存器作爲源操作數是非法的。你可以使用mov指令將一個constant賦值給一個臨時寄存器。然而,如果這個constant的只是1或者0,你可以使用調用指令來產生值,而不用浪費一個constant。

slt  r0,r0,r0         //r0= (0,0,0,0)

sge r0,r0,r0        //r0= (1,1,1,1)

  • Fractional Part

expp的結果的y組件存放的是源操作數w組件的小數部分。

expp r1.y r0.x    ;  r1.y = r0.x  - floor(r0.x)

mov r1.x ,r1.y

  • Absolute value

max r0 r0,-r0

  • Division

rcp r2.x, r1.x  ;1/r1.x

mul r2.x, r2.x, r0.x

  • Square root

rsq r1.x,r0.x

mul  r1.x ,r1.x,r0.x

  • conditional selection

; r0 = (c1 < c2) ? r3:r4

slt r0, r1,r2; c = (r1<r2)

mul r3,r3,r0   ;r3 = r3*r0

sge r0,r1,r2     ;c = (r1 >= r2)

mad r0 , r0 , r4, r3; r0 = c*r4 + r3

  • clamping to an interval

;interval [A, B]

def c0 , A, B, 0,0

;r0 = clamp(r0,A,B)

max  r0, r0,c0.x

min  r0,r0,c0.y

  • floor and ceiling
  • vector cross product

c = a和b的叉積 = (aybz - az by, az bx - ax bz, ax by - aybx)

  • vector normalization
  • Transposed matrix multipliation
  • signum function
  • minimum and maximum vector component
  • trigonometric functions
  • exponential and logarithmic functions

 

固定功能處理

 

  • 寄存器layout

使用在固定流水線的臨時寄存器的layout如下表:

r0 scratch
r1 scratch
r2 scratch
r3(Rd) scratch, light vector
r4(Rr,Rf,Rl) scratch , reflectance, eye or light vectors
r5(Rs, Rv) scratch, sphere vector, eye vector
r6(Rx) scratch, specular color
r7(Rc) scratch, diffuse color
r8(RH) scratch, half-angle vector
r9(Rh) homogeneous eye space position
r10(R3) cartesian eye space position
r11(Rn) eye space normal
  • constant 寄存器 layout

下面表給出了固定流水線constant 寄存器的layout。

Register Meaning or Value
C[NORMAL0_MATRIX_X]
C[NORMAL0_MATRIX_Y]
C[NORMAL0_MATRIX_Z]
inverse transpose world * view matrix 0
C[NORMAL1_MATRIX_X]
C[NORMAL1_MATRIX_Y]
C[NORMAL1_MATRIX_Z]
inverse transpose world * view matrix 1
C[NORMAL2_MATRIX_X]
C[NORMAL2_MATRIX_Y]
C[NORMAL2_MATRIX_Z]
inverse transpose world * view matrix 2
C[NORMAL3_MATRIX_X]
C[NORMAL3_MATRIX_Y]
C[NORMAL3_MATRIX_Z]
inverse transpose world * view matrix 3
c[WORLDVIEW0_MATRIX_X]
c[WORLDVIEW0_MATRIX_Y]
c[WORLDVIEW0_MATRIX_Z]
world * view matrix 0
c[WORLDVIEW1_MATRIX_X]
c[WORLDVIEW1_MATRIX_Y]
c[WORLDVIEW1_MATRIX_Z]
world* view matrix 1
c[WORLDVIEW2_MATRIX_X]
c[WORLDVIEW2_MATRIX_Y]
c[WORLDVIEW2_MATRIX_Z]
world * view matrix 2
c[WORLDVIEW3_MATRIX_X]
c[WORLDVIEW3_MATRIX_Y]
c[WORLDVIEW3_MATRIX_Z]
world*view matrix 3
c[PROJECTION_MATRIX_X]
c[PROJECTION_MATRIX_Y]
c[PROJECTION_MATRIX_Z]
c[PROJECTION_MATRIX_W]
projection matrix
c[COMPOSITE_MATRIX_X]
c[COMPOSITE_MATRIX_Y]
c[COMPOSITE_MATRIX_Z]
c[COMPOSITE_MATRIX_W]
world * view * projection matrix
c[TEXTURE_MATRIX_X]
c[TEXTURE_MATRIX_Y]
c[TEXTURE_MATRIX_Z]
c[TEXTURE_MATRIX_W]
texture matrix
c[GLOBAL_ILLUMINATION] RGBA,emission + global ambient
c[LIGHT_POSITION] x,y,z
c[LIGHT_HALF_ANGLE] x,y,z for infinite light w/local viewer
c[LIGHT_AMBIENT] RGB,light * material
c[LIGHT_DIFFUSE] RGB, light * material
c[LIGHT_SPECULAR] RGB, light * material, specular power
c[LIGHT_ATTENUATION] a0,a1,a2,spot power
c[LIGHT_SPOT_DIRECTION] x,y,z,cos(CUTOFF)
c[POINT_PARAMETER] size, max,min
c[POINT_ATTENUATION] a0,a1,a2
c[TEXTURE_OBJECT_PLANE_X]
c[TEXTURE_OBJECT_PLANE_Y]
c[TEXTURE_OBJECT_PLANE_Z]
c[TEXTURE_OBJECT_PLANE_W]
x,y,z,w
x,y,z,w
x,y,z,w
x,y,z,w
c[TEXTURE_EYE_PLANE_X]
c[TEXTURE_EYE_PLANE_Y]
c[TEXTURE_EYE_PLANE_Z]
c[TEXTURE_EYE_PLANE_W]
x,y,z,w
x,y,z,w
x,y,z,w
x,y,z,w
c[EYE_POSITION] x,y,z,w
c[CONSTANT0] -1,0,1,0.5
  • 座標轉換

頂點位置和法線被一個連接的世界和視圖矩陣所轉換。如果使用skinning,位置和法線還要被每個skinning矩陣轉換。

;position

m4*4 Rh, vPosition , c[MODELVIEW0_MATRIX_X]

;normal

m3*3 Rn, vNormal, c[NORMAL0_MATRIX_X]

  • 頂點blending

; weight preparation

mov r0, c[WEIGHT]

mov r0.w, c[CONSTANT0].z

dp4 r0.y , r0, c[CONSTANT0].xyyz

dp4 r0.z , r0, c[CONSTANT0].xxyz

dp4 r0.w, r0,c[CONSTNAT0].xxxz

;position /normal blend

mul Rh, r0.x, Rh          //1st weight

mul Rn, r0.x ,Rn

mad Rh,r0.y,r3,Rh   // 2th weight

mad Rn,r0.y,r2,Rn

mad Rh,r0.z,r5,Rh   // 3th weight

mad Rn,r0.z, r5,Rn

mad Rh,r0.w,r7,Rh // 4th weight

mad Rn, r0.w,r6,Rn

  • 位置輸出

m4*4 oPos, Rh,c[PROJECTION_MATRIX_X]

  • normalize eye normal

dp3 Rn.w,Rn,Rn

rsq Rn.w Rn.w

mul Rn,Rn, Rn.w

  • non-Homogeneous eye position

rcp r0.w, Rh.w

mul Re,Rh,r0.w

  • Eye space vectors

頂點和眼睛之間的距離:

add r0, -Re,c[EYE_POSITION]

dp3 r0.w,r0,r0

rsq r1.w,r0.w

mul Rv, r0,r1.w

dst Rf, r0.w, r1.w

  • Fog output

;radial fog

mov oFog.x Rf.y

;linear Z fog

mov oFog.x  -Re.z

  • Point Parameters

對於point sprites,頂點shader需要計算一個點的大小,輸出到oPts寄存器。

dp3 r0.w Rf, c[POINT_PARAMETER_ATTENUATION]

rsq r0.w r0.w

mul r0.w r0.w, c[POINT_PARAMETER].x

mul r0.w, r0.w, c[POINT_PARAMETER].y

mul oPts.w r0.w, c[POINT_PARAMETER].z

  • Lighting

初始化

   ;diffsue only

  mov Rc c[GLOBAL_ILLUMINATION]

; diffuse and specular

mov Rc c[GLOBAL_ILLUMINATION]

mov  Rx, c[CONSTANT0].y

infinite Light 或者 infinite Viewer

dp3 r0.x , Rn , c[Light_position]

dp3 r0.y, Rn,  c[LIGHT_HALF_ANGEL_VECTOR]

mov r0.w , c[LIGHT_SPECULAR].w

lit  r0, r0

mad Rc.xyz, r0.x , c[LIGHT_AMBIENT], Rc

mad Rc.xyz, r0.y, c[LIGHT_DIFFUSE], Rc

mad Rc.xyz, r0.z, c[LIGHT_SPECULAR],Rx

 

SpotLight , Local viewer

;light direction/distance vectors

add r0, -Re, c[LIGHT_POSITION]

dp3 r0.w, r0,r0

rsq r1.w,r0.w

mul r1, r0,r1.w

dst Rd, r0.w, r1.w

; half-angle vector

add Rh, Rv, Rl

;normalize

dp3 Rh.w Rh, Rh

rsq  Rh.w, Rh.w

mul Rh, Rh, Rh.w

;distance attenuation

dp3  r0.y , Rl, -c[LIGHT_SPOT_DIRECTION]

add  r0.x , r0.y , -c[LIGHT_SPOT_DIRECTION].w

mov r0.w, c[LIGHT_ATTENUATION].w

lit r0,r0

mul Rd, Rd.w, r0.z

dp3 r0.x, Rn, Rl

dp3 r0.y, Rn, RH

mov  r0.w, c[LIGHT_SPECULAR].w

lit r0,r0

mul r0,r0,Rd.w

mad Rc.xyz, r0.x, c[LIGHT_AMBIENT], Rc

mad Rc.xyz, r0.y, c[LIGHT_DIFFUSE], Rc

mad Rc.xyz, r0.z, c[LIGHT_SPECULAR], Rc

Lighting output

;diffuse only

mov oDO, Rc

;diffuse and specular

mov oD0 , Rc

mov oD1, Rx

  • Texture 座標generation

紋理座標可以直接從頂點產生,或者由應用程序直接傳遞給shader。

;pass-thru

mov r0, v[TEX0]

Initialization

;reflection vector

mul r0, Rn, c[EYE_POSITION].w

dp3 Rr.w Rn, Rv

mad Rr, Rr.w, R0,-Rv

;sphere map vector

add r0,c[CONSTANT0].yyzy,Rr

dp3 r0.w , r0, r0

rsq r0.w r0.w

mul r0.xyz, r0, c[CONSTANT0].wwyy

mad Rs,r0.w,r0,c[CONSTANT0].wwyy

Texture Coordinate Generation

;object space plane

m4*4 r0, vPosition, c[TEXTURE_OBJECT_PLANE_X]

;eye space plane

m4*4 r0,Rh, c[TEXTURE_EYE_PLANE_X]

;sphere map

mov r0.xy, Rs

;normal vector

mov r0.xyz, Rn

 

;reflection vector

mov r0.xyz, Rr

Texture Coordinate Transform

m4*4 oT0,r0,c[TEXTURE_MATRIX_X]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章