1. 程式人生 > >Vulkan程式設計指南翻譯 第六章 著色器和管線 第2節 SPIR-V 概述

Vulkan程式設計指南翻譯 第六章 著色器和管線 第2節 SPIR-V 概述

6.2  SPIR-V 概述

SPIR-V著色器嵌入在module裡。每一個module都可以包含一個或多個著色器。每一個著色器都有一個固定名字入口點和著色器型別,這用來定義著色器在哪個著色階段來使用。入口點之著色器開始執行時的起始位置。一個SPIR-Vmodule都隨著一些附帶資訊傳遞 給VulkanVulkan返回一個物件來表示這個module。此module可以用來構造一個管線,管線是附帶資訊的著色器經過編譯的版本,可以在裝置上執行。

6.2.1  如何表示SPIR-V

SPIR-VVulkan官方唯一支援的著色語言。在API層面被Vulkan接受,最終用來構建管線,管線物件可配置一個裝置來完成應用程式的工作。

SPIR-V被設計為可被工具和驅動很簡單就能使用。這減少了不同實現之間的不同意提高相容性。SPIR-V module在記憶體的32bi每字資料流形式儲存的。除非你是工具作者或者計劃自己生成SPIR-V,你不大可能會去直接處理二進位制編碼的SPIR-V。相反,你要麼會去看SPIR-V的文字形式,或者使用諸如glslangvalidatorChronos官方GLSL編譯器)的工具來生成SPIR-V

把著色器程式以.comp字尾名的方式儲存為文字檔案,告訴glslangvalidator把它當作計算著色器編譯。我們可以通過使用glslangvalidator命令列的方式來編譯著色器:

glslangvalidator simple.comp -o simple.spv

這會產生一個名為simple.spv SPIR-V二進位制檔案。我們可以使用SPIR-V反彙編工具,spirv-dis,來反編譯這個二進位制檔案,會輸出一份人可讀的反彙編程式碼。如Listing 6.2所示:

Listing 6.2: Simplest SPIR-V

; SPIR-V

; Version: 1.0

; Generator: Khronos Glslang Reference Front End; 1

; Bound: 6

; Schema: 0

OpCapability Shader

%1 = OpExtInstImport "GLSL.std.450"

OpMemoryModel Logical GLSL450

OpEntryPoint GLCompute %4 "main"

OpExecutionMode %4 LocalSize 1 1 1

OpSource GLSL 450

OpName %4 "main"

%2 = OpTypeVoid

%3 = OpTypeFunction %2

%4 = OpFunction %2 None %3

%5 = OpLabel

OpReturn

OpFunctionEnd

你可以看到SPIR-V的文字形式看起來像組合語言的變體。我們可深入這段反彙編,來看看他和原始的輸入檔案如何關聯。反彙編檔案的每一行待變一個SPIR-V指令,可能由多個token組成。

第一個指令OpCapability Shader,要求這個著色器開啟相容模式。SPIR-V功能粗略的分為“指令”和“特徵”。在你的著色器程式可以使用這些特徵之前,shader必須要宣告使用的特徵是哪一部分的。Listing 6.2的著色器程式是一個圖形著色器,因此使用Shader能力。這是最基礎的能力了。沒有這個,我們不能編譯圖形著色器。隨著我們引入更多SPIR-VVulkan功能,我們將介紹這些不同能力所依賴哦特徵。

下一行,我們看到 %1 = OpExtInstImport "GLSL.std.450"。 這就是引入了一些附加的指令,對應著GLSL 450包含的功能,這也是原始著色器程式所寫入的版本。注意這個指令以 %1 = 開頭。這把指令計算的結果使用ID命名。OpExtInstImport的結果是一個有效的庫。當我們需要呼叫這個庫的函式,我們可以使用OpExtInst指令,它接受一個庫(OpExtInstImport指令的結果)和一個指令索引。這允許SPIR-指令集被任意的拓展。

下一行,我們看到一些附加的宣告,OpMemoryModel指定了這個module的工作記憶體的模型,這是對應GLSL 450的邏輯上的記憶體模型。這意味著所有的記憶體訪問是通過資源而不是通過指標訪問記憶體的實體記憶體模型。

下一行是這個module入口點的宣告。OpEntryPoint GLCompute %4 "main" 指令表明對應的OpenGL計算著色器有一個可用的入口,以函式名字main匯出為ID 4。這個名字被用來當把結果著色器module返回Vulkan時的參考入口點。

我們在後續的指令中使用這個IDOpExecutionMode %4 LocalSize 1 1 1, 它定義了這個著色器的工作組大小為 1 × 1 × 1 work item。 如果沒有區域性大小的layout限定符,這在GLSL中是隱式的。

下面兩個指令是簡單的宣告型別的。OpSource GLSL 450表示這個moduleGLSL 450 版本編譯而來,OpName 4 "main"提供了ID4token的名字。

現在,我們看到這個函式的真身了。第一, %2 = OpTypeVoid聲明瞭我們想要以void型別使用ID 2. 所有東西在SPIR-V中都有一個ID,甚至是型別宣告。大型、複合的型別可以通過連續的小的,簡單的型別組成。然而,我們需要從某處開始,並且指定我們開始的地方型別為void

%3 = OpTypeFunction %2便是我們定義了ID 3 為一個函式型別,型別為void,不接受引數。我們在下一行使用它,%4 = OpFunction %2 None %3。這表示我們宣告ID 4(知其那被命名為“main”)為函式3的一個例項(在上一行宣告),返回void(如ID 2),且沒有特殊的宣告,這通過指令中的None表明,而且可以被用來表示諸如inline,不管變數是否為常量(常量性)等等。

最後,我們可以看到一個label(沒有被用到,編譯器操作的副作用)的宣告,隱式的返回語句,和函式的結束。這是我們SPIR-Vmodule的結尾。

這個著色器程式的二進位制dump192位元組長。SPIR-V是非常詳盡的,因為192位元組比原來的著色器要長。然而,SPIR-V把原來的著色語言中隱式的東西變得顯式了。比如,在GLSL中無需宣告記憶體模型,因為它只支援一種邏輯記憶體模型。更有,這裡編譯的SPIR-V module有一些冗餘資訊,我們不關心main函式的名字,ID 5 label從來沒有被使用,且著色器引入了GLSL.std.450庫,但是從來沒有使用過。我們可以把這個module中多餘的資訊抽離出去。即使在此之後,因為SPIR-V編碼方式相對稀疏,產生的二進位制檔案使用一個通用的壓縮器也相當容易被壓縮,而且使用一個專門的壓縮庫可以把它壓縮的更緊緻 。

所有的SPIR-V編碼都通過SSA來書寫(single static assignment),這表明每一個虛擬暫存器(在上面的List中寫作%ntoken)都被僅寫入一次。幾乎所有的工作的指令產生一個結果識別符號。當我們開始寫更復雜的著色器時,你將看到機器離線生成的SPIR-V有點笨拙,因為它的詳盡特性和SSA形式,非常難以手寫。非常建議你在應用程式中以lib形式使用編譯器來離線生成SPIR-V

如果你計劃自己生成或者解釋SPIR-V module,你可以使用預定義的二進位制編碼器來構建工具,來解析或生成它們。然而,它們都有格式良好的二進位制儲存格式,我們在本章稍後講解。

所有的SPIR-V module檔案都以一個magic number開始,這可以用來簡單的炎症二進位制塊,實際上就是SPIR-V module。這個魔法數字以無符號整型來看是0x07230203。這個數字也可以用來退單module的位元組順序。因為每一個SPIR-V toke 都是一個32-bit word,如果一個SPIR-V module通過磁碟或網路傳輸到有不同位元組順序的主機端,這些在一個word內的位元組都被交換位置了,它的值給改變了。例如,如貴哦一個SPIR-V module 儲存為小端格式,被載入到一個大端格式主機CPU,那麼魔法書記就會被讀為0x03022307,所以這個CPU就知道需要在這個module裡交換位元組順序。

在魔法數字的後面有幾個word,描述了module的屬性。第一個是SPIR-V使用的的版本數字。它被編碼在一個32-bit word裡,其中16-23 bit為包含主版本號,8-15 包含次版本號。 SPIR-V 1.0 因此使用編碼0x00010000。版本號剩下的bit位是保留的。下一個token包含生成SPIR-V module的工具的版本號。這個值由工具自定義。

下一個是本module中最大的ID號碼。所有的變數,函式,和SPIR-V module的其他成員都被賦值到一個比這個數字小的ID,所以,在最前面包含這個數字允許工具分配好陣列來存放它們,而不是隨時的分配記憶體。頭部最後一個word是保留的,應被置為0。接下來的是指令流。

6.2.2  SPIR-V傳遞給Vulkan

Vulkan並不關心SPIR-V 著色器和module從哪裡來。通常,它們會被離線編譯好作為應用程式的一部分,或者在應用程式中直接生成。一旦你有了一個SPIR-V module,你需要把它傳遞給Vulkan,以便可以使用它建立一個著色器module 物件。可以呼叫vkCreateShaderModule()來做到,其原型如下:

VkResult vkCreateShaderModule (

VkDevice device,

const VkShaderModuleCreateInfo* pCreateInfo,

const VkAllocationCallbacks* pAllocator,

VkShaderModule* pShaderModule);

和所有的Vulkan物件建立函式一樣,vkCreateShaderModule()接受一個裝置handle輸入,和一個指向包含建立物件資訊的資料的指標。此時,就是VkShaderModuleCreateInfo型別,其定義為:

typedef struct VkShaderModuleCreateInfo {

VkStructureType sType;

const void* pNext;

VkShaderModuleCreateFlags flags;

size_t codeSize;

const uint32_t* pCode;

} VkShaderModuleCreateInfo;

VkShaderModuleCreateInfosType域應置為VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFOpNext應置為nullptrflags域保留使用應置為0codeSize域包含了SPIR-V module位元組單位的大小,程式碼通過pCode傳入。

如果這個SPIR-V程式碼是有效的,且能夠被Vulkan理解,那麼vkCreateShaderModule()將返回VK_SUCCESS,並

相關推薦

Vulkan程式設計指南翻譯 著色管線 2 SPIR-V 概述

6.2  SPIR-V 概述 SPIR-V著色器嵌入在module裡。每一個module都可以包含一個或多個著色器。每一個著色器都有一個固定名字入口點和著色器型別,這用來定義著色器在哪個著色階段來使用。入口點之著色器開始執行時的起始位置。一個SPIR-Vmodule都隨著

Vulkan程式設計指南翻譯 著色管線 4 執行工作

6.4  執行工作 在前一節,你看到了如何使用vkCreateComputePipelines()構造一個計算管線並把大繫結到一個命令緩衝區。一旦管線被繫結,你可以用它來執行工作。 計算著色器作為計算管線的一部分,以分組的形式來執行,分組成為本地工作組。這些工作邏輯上速度一

Vulkan程式設計指南翻譯 著色管線 3 管線

6.3  管線 如你在前面小節所讀到的,Vulkan使用著色器module來表示一系列的著色器程式通過把module 程式碼交給vkCreateShaderModule()可以建立著色器module,但是,在它們可以在裝置上被用來工作之前,你需要建立管線。在Vulkan中有

Vulkan程式設計指南翻譯 圖形管線 4 建立簡單的圖形管線(下)

這一節實在太長了,拖了好久。還是分開發吧。 7.4.3  輸入組裝 圖形管線的輸入組裝階段接受頂點資料,並把它們分組,組成圖元,以供管線接下來的部分處理。它是通過一個VkPipelineInputAssemblyStateCreateInfo型別的資料描述的,通過V

編譯原理 屬性文法語法制導翻譯

一、知識總結        首先學習了屬性文法,屬性文法是在上下文無關文法的基礎上為每個文法符號(終結符或非終結符)配備若干個相關的“值”,稱為“屬性”。屬性分為綜合屬性和繼承屬性。綜合屬性用於“自下而上”傳遞資訊,在語法樹中,一個結點的綜合屬性的值,由其子結點的屬性值確定。

編譯原理-屬性文法語法制導翻譯

      第六章主要講了屬性文法、語義規則、基於屬性文法的處理、S屬性的自下而上計算、L-屬性文法的自頂向下翻譯等內容。一些基本的概念:屬性文法:是在上下文無關文法的基礎上為每個文法符號(終結符或非終結符)配備若干個相關的“值”(稱為屬性)。屬性:代表與文法符號相關的資訊,

初始繼承多態

機制 但是 就是 概念 base 類的設計 類重寫 結構 冗余 1.繼承的概念 其實生活中有很多繼承的例子。例如,在馬路上跑的卡車,我們每天都乘坐的公共汽車,它們都是汽車。卡車有自己的特征:有貨艙,有額定載重,行為都是可以拉貨、卸貨。而公共汽車的特征和行為:有客艙,有載客量

R語言編程藝術__因子

女性 案例 子列 認識 改變 posit 程序實現 style 各類 一、因子與水平 1、簡單直接的認識因子和水平   因子可以簡單的理解為包含了更多信息的向量。即因子=向量 + 水平。(當然實際上它們內部機理不同)。水平是對於向量中不同值的記錄,以下面代碼為例: >

函數調試

如果 怎麽辦 調試工具 將在 工具 argument real special one   在本章中,你將學習以下兩方面的基本知識: 函數 使用Python調試包pdb   函數是程序重要的組成部分,你將在第七章中使用它們,並學習如何使用隨機化

:隨機化(續2

重要 之間 ilog -o bbbb 動態 調試 即使 不同 6.10 隨機化句柄數組 如果想要產生多個隨機對象,那麽你可能需要建立隨機句柄數組,和整數數組不同,隨機求解器不會創建對象,所以你需要在隨機化前分配所有的元素。 動態數組可以按照需要分配最大數量的元素,然後按照約

類型成員基礎

frame 相同 vision 特殊 可見 要求 沒有 發送通知 操作符重載 目錄: 6.1 類型的各種成員 6.2 類型的可見性 6.3 成員的可見性 6.4 靜態類 6.5 分部類,結構和接口 6.6 組件,多態和版本控制 6.1 類型的各種成員 常量:數據值恒定不

【資料庫視訊】 資料查詢管理

一、簡單的SELECT語句 語法格式: SELECT [ALL|DISTINCT] select_list [INTO new_table] FROM table_source [WHERE search_conditions] [GROUP

玩轉資料結構——:集合對映

集合(Set) 什麼是集合? 集合是承載元素的容器; 特點:每個元素只能存在一次 優點:去重 二分搜尋樹的新增操作add:不能盛放重複元素 是非常好的實現“集合”的底層資料結構 /** * 集合的介面 */ public interface Set<

《C++ Primer Plus》學習筆記—— 分支語句邏輯運算子(一)

本章內容包括: if 語句 if else 語句 邏輯運算子 &&、||和! cctype字元函式庫 條件運算子: ? : switch 語句 continue和break語句 讀取數字的迴圈 基本檔案輸入和輸出 if 語句 if (tes

第二篇 建築裝修保溫系統檢查(二)

alt 系統 第二篇 等級 分享圖片 img 裝修 image 分享 裝修材料分4個等級, 保溫材料分3個等級 第二篇 第六章建築裝修和保溫系統檢查(二)

分支語句邏輯操作符

if 語句 if( test-condition ) statement 通常情況下,測試條件都是關係表示式。 if else 語句 if( test-condition ) stat

EffectiveJava:列舉註解

討論列舉和註解的最佳實踐。 30. 用enum代替int常量 列舉型別(enum type)是指由一組固定的常量組成合法值得型別,在程式語言還沒有引入列舉之前,表示列舉型別的常用模式是宣告一組具名的int常量,稱作int列舉模式。 int列舉模式的不

[] 深入理解計算機系統三版 家庭作業參考答案

6.22 磁軌數 d 與 r - x * r 成正比 設 d = k(r - x * r) = kr(1 - x) 總容量 c = 2πxk(r^2)(1 - x) = 2πk(r^2)(x - x^2) 上式實際上是關於 x 的二次式,其對稱軸為 1/2,即當

5:座標依賴/5.2 座標詳解

座標詳解 座標內容包括 groupid:必選 概念:通用用java包的形式表示(也就是.(點)表示法),內容一般是組織或者公司下的某個專案 例如:org.sonatype.nexus,org.sonatype 為非盈利組織

Atitit 現代資訊檢索 Atitit 重要章節 息檢索建模 檢索評價 8 文字分類 Line 210: 9 索引搜尋 11 Web檢索 13 結構化文字檢索 目錄 L

Atitit 現代資訊檢索   Atitit 重要章節 息檢索建模 檢索評價  第8章 文字分類 Line 210: 第9章 索引和搜尋 第11章 Web檢索 第13章 結構化文字檢索   目錄   Line 1