Shader定义了graphics、compute pipeline相应阶段,每个vertex、control point、tessellated vertex、primitive、fragment、workgroup的操作

Graphics pipeline包括vertex shader用于得到图元,tessellation control和evaluation shader作用于patch,gs作用于图元,ps作用于光栅化生成的像素。在本书中,vs、tessellation control、tessellation evaluation以及gs被规律额为vertex processing stages,发生在光栅化之前的logical pipeline。ps发生在光栅化之后的logically。

只有compute shader stage 发生在compute pipeline。cs操作与workgroup上的compute invocations。

shader可以从input variable读取数据,也可以从output variables读取和写入数据。input和output variable被用于在shader之间传输数据,也可以使得shader从执行环境获取数据。相应的,执行环境提供一些描述功能的常量。

Shader variables are associated with execution environment-provided inputs and outputs using built-in decorations in the shader. The available decorations for each stage are documented in the following subsections

VkResult vkCreateShaderModule( VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule);

Shader modules包含shader coude和若干个entry points。通过特定一个pipeline creation中的entry point,可以从shader module获取shader。pipeline stages可以使用不同module获取的shader。shader code必须是SPIR-V format,如Vulkan Environment for SPIR-V附录所述。

创建一个shader module

第一个输入参数,为用于创建 ShaderModule 的logical device

第二个输入参数,为一个 VkShaderModuleCreateInfo 的结构体,用于表明该 ShaderModule 的属性

第三个输入参数,用于内存分配

第四个输入参数,用于获取生成的 VkShaderModule

shader module创建好之后,其中的entry point可以被用于 compute pipeline和graphics pipeline中的pipeline shader stage

typedef struct VkShaderModuleCreateInfo { VkStructureType sType; //当前结构体的类型,必须是 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO const void* pNext; //NULL,或者扩展该结构体的另外一个结构体,必须为NULL VkShaderModuleCreateFlags flags; //reserved for future use,必须为0 size_t codeSize; //pCode的尺寸,以bytes为单位,必须大于0,且为4的倍数 const uint32_t* pCode; //一个指向用于创建shader module 的code的指针,type和format由pCode对应的memory中的内容而定,必须指向一个合法的SPIR-V code。尺寸为codeSize/4个uint32。 } VkShaderModuleCreateInfo;

在VS阶段中,如果一个顶点可能会被多次运算(一个顶点在ibo中出现多次),那么根据vendor公司的实现,可能会对结果进行重用,而非多次重复计算

TS的control shader中的执行是无序的,但是可以通过 OpControlBarrier 来略微干涉一下一个patch中的执行顺序。期间,如果一个指令读取另外一个指令写入的值,则返回undefine,或者如果两个指令在同一个output中写入不同的值,也会出现undefine

可以通过设置 EarlyFragmentTests OpExecutionMode ,强制走earlyz,然而这样的话,ps中对depth的修改就无效了。

光栅化的变量可以使用修饰符:Flat:不插值,NoPerspective:线性插值(用于line和polygons)。ps的输入参数中,如果不是上述两种的话,就会被当作perspective-correct的插值处理(用于line和polygons)

除此之外,还有Centroid或者Sample修饰符

Flat:不插值,也就是说,一个三角形中的每个片元都将使用相同的值(来自某个特定的vertex)。一个被Flat修饰的变量也可以使用Centroid或者Sample修饰符。意思和只有Flat的时候一样。

对于不是 Centroid 或 Sample 修饰的片元着色器输入变量,被赋值的变量也许会插值到像素内任意位置,一个值也许被赋值给像素内每一个采样点。

Centroid 和 Sample 可以被用于控制被修饰着色器输入变量采样的位置和频率。 如果一个片元着色器输入变量被 Centroid 修饰,像素内所有采样点都会被赋值为同一个值,但是这个值必须必须要被插值到一个位置,该位置在像素和被渲染的图元上, 包括这个图元覆盖的像素采样点中任一个点。 因为变量被插值的位置可能在临近的像素上,导数可能以两个临近像素来做计算, centroid-sampled 输入变量的导数可能比 non-centroid 插值的变量准确度偏低。 如果一个片元着色器输入被 Sample 修饰,对于该像素覆盖的每一个采样点都需要赋值一个单独的值,这个值必须从不同的采样点采样获取到。 当 rasterizationSamples 是 VK_SAMPLE_COUNT_1_BIT时,像素中心必须被用作 Centroid, Sample, 和无描述采样。

signed、unsigned integers、integer vectors或者其他double precision浮点类型都必须使用Flat修饰符。

如果shader stage编译错误,会出现 VK_ERROR_INVALID_SHADER_NV 的错误,如果打开 VK_EXT_debug_report ,则对应log会报给应用程序。

可能会出现的错误:VK_ERROR_OUT_OF_HOST_MEMORY、VK_ERROR_OUT_OF_DEVICE_MEMORY、VK_ERROR_INVALID_SHADER_NV

void vkDestroyShaderModule( VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator);

删除一个shader module

第一个输入参数,为用于创建 ShaderModule 的logical device

第二个输入参数,为即将被删除的 VkShaderModule,可以是 VK_NULL_HANDLE

第三个输入参数,用于内存分配,如果创建的时候定义了 VkAllocationCallbacks,这里需要定义一个对应的。反之,这里必须是NULL

shader module可以在对应pipeline还在使用中的时候被删除。

		Host access to shaderModule must be externally synchronized
	

本节教程就到此结束,希望大家继续阅读我之后的教程。

谢谢大家,再见!


原创技术文章,撰写不易,转载请注明出处:电子设备中的画家|王烁 于 2021 年 5 月 10 日发表,原文链接(http://geekfaner.com/shineengine/blog15_Vulkanv1.2_2.html)