1# Transform Feedback via extension 2 3## Outline 4 5ANGLE emulates transform feedback using the vertexPipelineStoresAndAtomics features in Vulkan. 6But some GPU vendors do not support these atomics. Also the emulation becomes more difficult in 7GLES 3.2. Therefore ANGLE must support using the VK_EXT_transform_feedback extension . 8 9But some GPU vendor does not support this feature, So we need another implementation using 10VK_EXT_transform_feedback. 11 12We also expect a performance gain when we use this extension. 13 14## Implementation of Pause/Resume using CounterBuffer 15 16The Vulkan extension does not provide separate APIs for `glPauseTransformFeedback` / 17`glEndTransformFeedback`. 18 19Instead, Vulkan introduced Counter buffers in `vkCmdBeginTransformFeedbackEXT` / 20`vkCmdEndTransformFeedbackEXT` as API parameters. 21 22To pause, we call `vkCmdEndTransformFeedbackEXT` and provide valid buffer handles in the 23`pCounterBuffers` array and valid offsets in the `pCounterBufferOffsets` array for the 24implementation to save the resume points. 25 26Then to resume, we call `vkCmdBeginTransformFeedbackEXT` with the previous `pCounterBuffers` 27and `pCounterBufferOffsets` values. 28 29Between the pause and resume there needs to be a memory barrier for the counter buffers with a 30source access of `VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT` at pipeline stage 31`VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT` to a destination access of 32`VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT` at pipeline stage 33`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`. 34 35## Implementation of glTransformFeedbackVaryings 36 37There is no equivalent function for glTransformFeedbackVaryings in Vulkan. The Vulkan specification 38states that the last vertex processing stage shader must be declared with the XFB execution mode. 39 40So we need to modify gl shader code to have transform feedback qualifiers. The glsl code will be 41converted proper SPIR-V code. 42 43we add the below layout qualifier for built-in XFB varyings. 44 45``` 46out gl_PerVertex 47 48{ 49 50layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride) varying_type varying_name; 51 52} 53``` 54 55 And for user xfb varyings. 56 57``` 58layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride, location = num ) 59out varying_type varying_name; 60 61``` 62 63There are some corner cases we should handle. 64 65If more than 2 built-in varyings are used in the shader, and only one varying is declared as a 66transformFeedback varying, we can generate a layout qualifier like this. 67 68``` 69out gl_PerVertex 70 71{ 72 73layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride) varying_type varying_name1; 74 75varying_type varying_name2; 76 77... 78 79} 80``` 81 82ANGLE modifies gl_position.z in vertex shader for the Vulkan coordinate system. So, if we capture 83the value of 'gl_position' in the XFB buffer, the captured values will be incorrect. 84 85To resolve this, we declare user declare an internal position varying and copy the value from 86'gl_position'. We capture the internal position varying during transform feedback operation. 87 88``` 89layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride, location = num ) 90out vec4 xfbANGLEPosition; 91 92.... 93 94void main(){ 95 96... 97 98xfbANGLEPosition = gl_Position; 99(gl_Position.z = ((gl_Position.z + gl_Position.w) * 0.5)); 100} 101``` 102 103