/ appendices / VK_NV_clip_space_w_scaling.txt
VK_NV_clip_space_w_scaling.txt
  1  include::meta/VK_NV_clip_space_w_scaling.txt[]
  2  
  3  *Last Modified Date*::
  4      2017-02-15
  5  *Contributors*::
  6    - Eric Werness, NVIDIA
  7    - Kedarnath Thangudu, NVIDIA
  8  
  9  Virtual Reality (VR) applications often involve a post-processing step to
 10  apply a "`barrel`" distortion to the rendered image to correct the
 11  "`pincushion`" distortion introduced by the optics in a VR device.
 12  The barrel distorted image has lower resolution along the edges compared to
 13  the center.
 14  Since the original image is rendered at high resolution, which is uniform
 15  across the complete image, a lot of pixels towards the edges do not make it
 16  to the final post-processed image.
 17  
 18  This extension provides a mechanism to render VR scenes at a non-uniform
 19  resolution, in particular a resolution that falls linearly from the center
 20  towards the edges.
 21  This is achieved by scaling the [eq]#w# coordinate of the vertices in the
 22  clip space before perspective divide.
 23  The clip space [eq]#w# coordinate of the vertices can: be offset as of a
 24  function of [eq]#x# and [eq]#y# coordinates as follows:
 25  
 26  [eq]#w' = w + Ax + By#
 27  
 28  In the intended use case for viewport position scaling, an application
 29  should use a set of four viewports, one for each of the four quadrants of a
 30  Cartesian coordinate system.
 31  Each viewport is set to the dimension of the image, but is scissored to the
 32  quadrant it represents.
 33  The application should specify [eq]#A# and [eq]#B# coefficients of the
 34  [eq]#w#-scaling equation above, that have the same value, but different
 35  signs, for each of the viewports.
 36  The signs of [eq]#A# and [eq]#B# should match the signs of [eq]#x# and
 37  [eq]#y# for the quadrant that they represent such that the value of [eq]#w'#
 38  will always be greater than or equal to the original [eq]#w# value for the
 39  entire image.
 40  Since the offset to [eq]#w#, ([eq]#Ax + By#), is always positive, and
 41  increases with the absolute values of [eq]#x# and [eq]#y#, the effective
 42  resolution will fall off linearly from the center of the image to its edges.
 43  
 44  === New Object Types
 45  
 46  None.
 47  
 48  === New Enum Constants
 49  
 50    * Extending elink:VkStructureType:
 51    ** ename:VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV
 52    * Extending elink:VkDynamicState:
 53    ** ename:VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV
 54  
 55  === New Enums
 56  
 57  None.
 58  
 59  === New Structures
 60  
 61    * slink:VkViewportWScalingNV
 62    * slink:VkPipelineViewportWScalingStateCreateInfoNV
 63  
 64  === New Functions
 65  
 66    * flink:vkCmdSetViewportWScalingNV
 67  
 68  === Issues
 69  
 70  1) Is the pipeline struct name too long?
 71  
 72  *RESOLVED*: It fits with the naming convention.
 73  
 74  2) Separate W scaling section or fold into coordinate transformations?
 75  
 76  *RESOLVED*: Leaving it as its own section for now.
 77  
 78  === Examples
 79  
 80  [source,c++]
 81  --------------------------------------
 82  
 83  VkViewport viewports[4];
 84  VkRect2D scissors[4];
 85  VkViewportWScalingNV scalings[4];
 86  
 87  for (int i = 0; i < 4; i++) {
 88      int x = (i & 2) ? 0 : currentWindowWidth / 2;
 89      int y = (i & 1) ? 0 : currentWindowHeight / 2;
 90  
 91      viewports[i].x = 0;
 92      viewports[i].y = 0;
 93      viewports[i].width = currentWindowWidth;
 94      viewports[i].height = currentWindowHeight;
 95      viewports[i].minDepth = 0.0f;
 96      viewports[i].maxDepth = 1.0f;
 97  
 98      scissors[i].offset.x = x;
 99      scissors[i].offset.y = y;
100      scissors[i].extent.width = currentWindowWidth/2;
101      scissors[i].extent.height = currentWindowHeight/2;
102  
103      const float factor = 0.15;
104      scalings[i].xcoeff = ((i & 2) ? -1.0 : 1.0) * factor;
105      scalings[i].ycoeff = ((i & 1) ? -1.0 : 1.0) * factor;
106  }
107  
108  VkPipelineViewportWScalingStateCreateInfoNV vpWScalingStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV };
109  
110  vpWScalingStateInfo.viewportWScalingEnable = VK_TRUE;
111  vpWScalingStateInfo.viewportCount = 4;
112  vpWScalingStateInfo.pViewportWScalings = &scalings[0];
113  
114  VkPipelineViewportStateCreateInfo vpStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
115  vpStateInfo.viewportCount = 4;
116  vpStateInfo.pViewports = &viewports[0];
117  vpStateInfo.scissorCount = 4;
118  vpStateInfo.pScissors = &scissors[0];
119  vpStateInfo.pNext = &vpWScalingStateInfo;
120  
121  --------------------------------------
122  
123  Example shader to read from a w-scaled texture:
124  
125  [source,c++]
126  --------------------------------------
127  
128  // Vertex Shader
129  // Draw a triangle that covers the whole screen
130  const vec4 positions[3] = vec4[3](vec4(-1, -1, 0, 1),
131                                    vec4( 3, -1, 0, 1),
132                                    vec4(-1,  3, 0, 1));
133  out vec2 uv;
134  void main()
135  {
136      vec4 pos = positions[ gl_VertexID ];
137      gl_Position = pos;
138      uv = pos.xy;
139  }
140  
141  // Fragment Shader
142  uniform sampler2D tex;
143  uniform float xcoeff;
144  uniform float ycoeff;
145  out vec4 Color;
146  in vec2 uv;
147  
148  void main()
149  {
150      // Handle uv as if upper right quadrant
151      vec2 uvabs = abs(uv);
152  
153      // unscale: transform w-scaled image into an unscaled image
154      //   scale: transform unscaled image int a w-scaled image
155      float unscale = 1.0 / (1 + xcoeff * uvabs.x + xcoeff * uvabs.y);
156      //float scale = 1.0 / (1 - xcoeff * uvabs.x - xcoeff * uvabs.y);
157  
158      vec2 P = vec2(unscale * uvabs.x, unscale * uvabs.y);
159  
160      // Go back to the right quadrant
161      P *= sign(uv);
162  
163      Color = texture(tex, P * 0.5 + 0.5);
164  }
165  --------------------------------------
166  
167  === Version History
168  
169   * Revision 1, 2017-02-15 (Eric Werness)
170     - Internal revisions