Vulkan着色器的GLSL創建、編譯、加載、創建流程

Vulkan沒有指定官方的着色器編程語言,而是採用SPIR-V二進制中間格式進行表示。開發人員一般需要基於某種着色器編程語言開發着色器,之後再編譯爲SPIR-V格式。可以選用GLSL着色器編程語言進行開發。

       大型遊戲場景中,一般預先將着色器編譯爲SPIR-V格式保存在文件中,程序運行時直接加載SPIR-V數據,提高效率。

       着色器的預編譯和調用過程如面流程所示:

 

一、着色器源代碼預編譯

       首先編輯好GLSL的着色器文件,後綴依次爲:頂點着色器-.vert、片元着色器-.frag、細分控制着色器-.tesc、細分執行着色器-.tese、幾何着色器-.geom、計算着色器-.comp。之後使用Vulkan SDK中的glslang validator命令對着色器源代碼進行編譯。

glslangvalidator -V commonTexLight.vert -o commonTexLight.vert.spv

       其中,V參數代表得到SPIR-V格式的數據,o代表輸出文件的路徑。

       以下兩個文件給出了vert着色器和frag着色器的GLSL源代碼文件內容:

//給定了所用GLSL的版本
#version 400

//Vulkan中想使用着色器進行開發,需要開啓這兩個擴展
#extension GL_ARB_separate_shader_objects : enable//啓動GL_ARB_separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//啓動GL_ARB_shading_language_420pack

//聲明一致塊myBufferVals,包含接收總變換矩陣的成員mvp
layout (std140,set = 0, binding = 0) uniform bufferVals {//一致塊
    mat4 mvp;//總變換矩陣
} myBufferVals;

layout (location = 0) in vec3 pos;//傳入的物體座標系頂點位置
layout (location = 1) in vec3 color;//傳入的頂點顏色
layout (location = 0) out vec3 vcolor;//傳到片元着色器的頂點顏色

//定義了輸出接口塊
out gl_PerVertex {
	vec4 gl_Position;//頂點最終位置
};

//頂點着色器的主方法
void main() {
	//計算最終頂點位置:最終變換矩陣*物體座標系下的頂點座標
    gl_Position = myBufferVals.mvp * vec4(pos,1.0);
	//傳遞頂點顏色給片元着色器
    vcolor=color;
}
//給定了所用GLSL的版本
#version 400

//Vulkan中想使用着色器進行開發,需要開啓這兩個擴展
#extension GL_ARB_separate_shader_objects : enable//啓動GL_ARB_separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//啓動GL_ARB_shading_language_420pack

//定義兩個顏色數據值
layout (location = 0) in vec3 vcolor;//頂點着色器傳入的頂點顏色數據
layout (location = 0) out vec4 outColor;//輸出到渲染管線的片元顏色值

//片元着色器的主方法
void main() {
	//將頂點着色器傳遞過來的顏色值輸出,最後的1.0代表A通道
   outColor=vec4(vcolor.rgb,1.0);
}

二、用於加載着色器SPIR-V數據的結構體&

       結構體SpvDataStruct:存有兩個成員,size用於存儲SPIR-V數據的總字節數;data指向SPIR-V數據內存塊首地址的指針。

       類FileUtil:具有loadSPV函數,加載SPIR-V文件。

typedef struct SpvDataStruct{//存儲SPIR-V數據的結構體 
    int size;             //SPIR-V數據總字節數 
    uint32_t* data;      //指向SPIR-V數據內存塊首地址的指針 
} SpvData; 

class FileUtil{ 
   public:  //此處省略了原有FileUtil類頭文件中的成員方法聲明 
   static SpvData& loadSPV(string fname);   //加載Assets文件夾下的SPIR-V數據 
}; 

 

三、FuleUtil中的loadSPV函數

       首先通過AAsetManager_open方法獲得AAsset對象,之後通過AAset_getLength獲取總字節數,然後構建了用於存儲SPIR-V數據的結構體實例,最後加載數據。

//加載Assets文件夾下的SPIR-V數據文件 
SpvData& FileUtil::loadSPV(string fname){  
    AAsset* asset =AAssetManager_open(aam,fname.c_str(),AASSET_MODE_STREAMING);  
    assert(asset); 
    size_t size = AAsset_getLength(asset);  //獲取SPIR-V數據文件的總字節數 
    assert(size > 0);                       //檢查總字節數是否大於0 
    SpvData spvData;                        //構建SpvData結構體實例 
    spvData.size=size;                      //設置SPIR-V數據總字節數 
    spvData.data=(uint32_t*)(malloc(size)); //分配相應字節數的內存 
    AAsset_read(asset, spvData.data, size); //從文件中加載數據進入內存 
    AAsset_close(asset);                    //關閉AAsset對象 
    return spvData;                         //返回SpvData結構體實例 
}

 

四、根據SPIR-V文件創建着色器

       首先利用FileUtil類中的loadSPV方法獲取頂點、片元着色器的SPIR-V數據,之後分別構建頂點着色器、片元着色器模塊創建信息結構體實例。

void ShaderQueueSuit_Common::create_shader(VkDevice& device){ 
    //加載頂點着色器數據
    SpvData spvVertData=FileUtil::loadSPV("shader/commonTexLight.vert.spv"); 
    //加載片元着色器數據                                                                
    SpvData spvFragData=FileUtil::loadSPV("shader/commonTexLight.frag.spv"); 
	 
    //此處省略了部分源代碼
	
    VkShaderModuleCreateInfo moduleCreateInfo;       //準備頂點着色器模塊創建信息 
    moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 
    moduleCreateInfo.pNext = NULL;                   //自定義數據的指針 
    moduleCreateInfo.flags = 0;                      //供將來使用的標誌 
    moduleCreateInfo.codeSize = spvVertData.size;    //頂點着色器SPV數據總字節數 
    moduleCreateInfo.pCode = spvVertData.data;       //頂點着色器SPV數據 
	
    //此處省略了部分源代碼 
	
    VkShaderModuleCreateInfo moduleCreateInfo;       //準備片元着色器模塊創建信息 
    moduleCreateInfo.sType =VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;  
    moduleCreateInfo.pNext = NULL;                   //自定義數據的指針 
    moduleCreateInfo.flags = 0;                      //供將來使用的標誌 
    moduleCreateInfo.codeSize = spvFragData.size;    //片元着色器SPV數據總字節數 
    moduleCreateInfo.pCode = spvFragData.data;       //片元着色器SPV數據 
    //此處省略了部分源代碼
}

 

發佈了48 篇原創文章 · 獲贊 46 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章