// Copyright 2021-2024 The Khronos Group Inc. // // SPDX-License-Identifier: CC-BY-4.0 = VK_KHR_fragment_shader_barycentric :toc: left :refpage: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/ :sectnums: This document details the VK_KHR_fragment_shader_barcentric extension, which adds a cross-vendor way to access barycentric coordinates in a fragment shader. == Problem Statement Barycentric coordinates are widely used in computer graphics, and are an important building block for various algorithms. By being able to access the location of a pixel within a primitive and the non-interpolated attributes at the vertices, pixel shaders are able to perform things such as custom attribute interpolation or effects based on the pixel's location within a primitive. == Solution Space Two options have been considered: - Take VK_NV_fragment_shader_barycentric and add any new required properties and behaviours. - Start afresh This proposal focuses on the first option. == Proposal === New SPIR-V decorations A new SPIR-V extension https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/KHR/SPV_KHR_fragment_shader_barycentric.html[SPV_KHR_fragment_shader_barycentric] adds three fragment shader variable decorations: * `PerVertexKHR`, which indicates that a fragment shader input will not have interpolated values, but instead must be accessed with an extra array index that identifies one of the vertices of the primitive producing the fragment * `BaryCoordKHR`, which indicates that the variable is a three-component floating-point vector holding barycentric weights for the fragment produced using perspective interpolation * `BaryCoordNoPerspKHR`, which indicates that the variable is a three-component floating-point vector holding barycentric weights for the fragment produced using linear interpolation === Barycentric weights - For point primitives, `BaryCoordKHR` and `BaryCoordNoPerspKHR` are assigned the value (1,0,0). - For line primitives, `BaryCoordKHR` and `BaryCoordNoPerspKHR` are assigned the values (1,0,0) and (0,1,0) at the ends of the primitive. - For polygon primitives, `BaryCoordKHR` and `BaryCoordNoPerspKHR` are assigned the values (1,0,0), (0,1,0), and (0,0,1) at the three vertices. === Per-vertex attributes Per-vertex attributes for "missing" vertices, such as the third vertex of a line primitive, will return values from the valid vertex with the highest index. Vertices are numbered as follows: [cols="10,10,10,10",options="header",width = "80%"] |==== | Primitive Topology | Vertex 0 | Vertex 1 | Vertex 2 | `VK_PRIMITIVE_TOPOLOGY_POINT_LIST` | i | i | i | `VK_PRIMITIVE_TOPOLOGY_LINE_LIST` | 2i | 2i+1 | 2i+1 | `VK_PRIMITIVE_TOPOLOGY_LINE_STRIP` | i | i+1 | i+1 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST` | 3i | 3i+1 | 3i+2 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP` (even) | i | i+1 | i+2 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP` (odd) | i | i+2 | i+1 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN` | i+1 | i+2 | 0 | `VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY` | 4i+1 | 4i+2 | 4i+2 | `VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY` | i+1 | i+2 | i+2 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY` | 6i | 6i+2 | 6i+4 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY` (even) | 2i | 2i+2 | 2i+4 | `VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY` (odd) | 2i | 2i+4 | 2i+2 |==== When the provoking vertex mode is `VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT`, the original vertex numbers used are the same as above except as indicated in the table below. [cols="10,10,10,10",options="header",width = "80%"] |==== | Primitive Topology | Vertex 0 | Vertex 1 | Vertex 2 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP (odd, and `triStripVertexOrderIndependentOfProvokingVertex` is `VK_FALSE`) | i+1 | i | i+2 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN | 0 | i+1 | i+2 | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY (odd) | 2i+2 | 2i | 2i+4 |==== === Properties A new property structure is added: [source,c] ---- typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { VkStructureType sType; void* pNext; VkBool32 triStripVertexOrderIndependentOfProvokingVertex; } VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; ---- The `triStripVertexOrderIndependentOfProvokingVertex` property indicates that the implementation does not change its vertex numbering for triangle strip primitives when the link:{refpage}VkProvokingVertexModeEXT.html[provoking vertex mode] is `VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT`. === GLSL mapping The following variables from https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_fragment_shader_barycentric.txt[`GL_EXT_fragment_shader_barycentric`] map to these SPIR-V built-in decorations: - in vec3 gl_BaryCoordEXT; → BaryCoordKHR - in vec3 gl_BaryCoordNoPerspEXT; → BaryCoordNoPerspKHR GLSL variables declared using the `__pervertexEXT` GLSL qualifier are expected to be decorated with `PerVertexKHR` in SPIR-V. === HLSL mapping - in float3 barycentrics : SV_Barycentrics; → BaryCoordKHR - in noperspective float3 barycentrics : SV_Barycentrics; → BaryCoordNoPerspKHR Values of per-vertex attributes provided by `GetAttributeAtVertex` are expected to be decorated with `PerVertexKHR` in SPIR-V. == Issues None