Name

    NV_clip_space_w_scaling

Name Strings

    GL_NV_clip_space_w_scaling

Contact

    Kedarnath Thangudu, NVIDIA Corporation (kthangudu 'at' nvidia.com)

Contributors

    Eric Werness, NVIDIA Corporation
    Ingo Esser, NVIDIA Corporation
    Pat Brown, NVIDIA Corporation
    Mark Kilgard, NVIDIA Corporation

Status

    Shipping in NVIDIA release 367.XX drivers and up.

Version

    Last Modified Date:         June 1, 2016
    NVIDIA Revision:            2

Number

    OpenGL Extension #486

Dependencies

    This extension is written against OpenGL 4.5 Specification
    (Compatibility Profile).

Overview

    Virtual Reality (VR) applications often involve a post-processing step to
    apply a "barrel" distortion to the rendered image to correct the
    "pincushion" distortion introduced by the optics in a VR device. The
    barrel distorted image has lower resolution along the edges compared to
    the center.  Since the original image is rendered at high resolution,
    which is uniform across the complete image, a lot of pixels towards the
    edges do not make it to the final post-processed image.

    This extension also provides a mechanism to render VR scenes at a
    non-uniform resolution, in particular a resolution that falls linearly
    from the center towards the edges.  This is achieved by scaling the "w"
    coordinate of the vertices in the clip space before perspective divide.
    The clip space "w" coordinate of the vertices may be offset as of a
    function of "x" and "y" coordinates as follows:

            w' = w + Ax + By

    In the intended use case for viewport position scaling, an application
    should use a set of 4 viewports, one for each of the 4 quadrants of a
    Cartesian coordinate system.  Each viewport is set to the dimension of the
    image, but is scissored to the quadrant it represents.  The application
    should specify A and B coefficients of the w-scaling equation above,
    that have the same value, but different signs, for each of the viewports.
    The signs of A and B should match the signs of X and Y for the quadrant
    that they represent such that the value of "w'" will always be greater
    than or equal to the original "w" value for the entire image. Since the
    offset to "w", (Ax + By), is always positive and increases with the
    absolute values of "x" and "y", the effective resolution will fall off
    linearly from the center of the image to its edges.

New Procedures and Functions

    void ViewportPositionWScaleNV(uint index, float xcoeff, float ycoeff)

New Tokens

    Accepted by the <cap> parameter of Enable, Disable, IsEnabled:

        VIEWPORT_POSITION_W_SCALE_NV            0x937C

    Accepted by the <pname> parameter of GetBooleani_v, GetDoublei_v,
    GetIntegeri_v, GetFloati_v, and GetInteger64i_v:

        VIEWPORT_POSITION_W_SCALE_X_COEFF_NV    0x937D
        VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV    0x937E

Additions to Chapter 13 of the OpenGL 4.5 (Compatibility Profile)
Specification (Fixed-Function Vertex Post-Processing)

    Modify Section 13.2 (Transform Feedback), p. 453

    Modify the first paragraph:

    ...The vertices are fed back after vertex color clamping, but before
    stereo view expansion,  viewport mask expansion, viewport swizzle,
    w coordinate warping, flat-shading, and clipping. ...

    Add a new Section 13.X (Viewport W Coordinate Scaling)

    If VIEWPORT_POSITION_W_SCALE_NV is enabled, the w coordinates for each
    primitive sent to a given viewport will be scaled as a function of
    its x and y coordinates using the following equation:

        w' = xcoeff * x + ycoeff * y + w;

    The coefficients for "x" and "y" used in the above equation depend on the
    viewport index, and are controlled by the command

        void ViewportPositionWScaleNV(uint index, float xcoeff, float ycoeff);

    The viewport specified by <index> has its coefficients for "x" and "y"
    set to the <xcoeff> and <ycoeff> values.  Specifying these coefficients
    enables rendering images at a non-uniform resolution, in particular a
    resolution that falls off linearly from the center towards the edges,
    which is useful for VR applications. VR applications often involve a
    post-processing step to apply a "barrel" distortion to the rendered image
    to correct the "pincushion" distortion introduced by the optics in a VR
    device. The barrel distorted image, has lower resolution along the edges
    compared to the center.  Since the original image is rendered at high
    resolution, which is uniform across the complete image, a lot of pixels
    towards the edges do not make it to the final post-processed image.
    VR applications may use the w-scaling to minimize the processing of unused
    fragments. To achieve the intended effect, applications should use a set of
    4 viewports one for each of the 4 quadrants of a Cartesian coordinate
    system.  Each viewport is set to the dimension of the image, but is
    scissored to the quadrant it represents.  The application should specify
    the x and y coefficients of the w-scaling equation above, that have the
    same value, but different signs, for each of the viewports.  The signs of
    <xcoeff> and <ycoeff> should match the signs of X and Y for the quadrant
    that they represent such that the value of "w'" will always be greater
    than or equal to the original "w" value for the entire image. Since the
    offset to "w", (Ax + By), is always positive and increases with the
    absolute values of "x" and "y", the effective resolution will fall off
    linearly from the center of the image to its edges.

    Errors:

    - The error INVALID_VALUE is generated if <index> is greater than or equal
      to the value of MAX_VIEWPORTS.

New Implementation Dependent State

    None.

New State

                                                                 Initial
    Get Value                             Get Command    Type    Value     Description                  Sec.    Attribute
    ------------------------------------  -----------    ----    -------   -----------                  ----    ---------
    VIEWPORT_POSITION_W_SCALE_NV          IsEnabled      B       FALSE     Enable W coordinate Scaling  13.X    enable
    VIEWPORT_POSITION_W_SCALE_X_COEFF_NV  GetFloati_v    R       0         x coefficient for the w      13.X    viewport
                                                                           coordinate scaling equation
    VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV  GetFloati_v    R       0         y coefficient for the w      13.X    viewport
                                                                           coordinate scaling equation

Additions to the AGL/GLX/WGL/EGL Specifications

    None.

GLX Protocol

    None.

Errors

    None.

Issues

    (1) Does this extension provide any functionality to convert the w-scaled
        image to the barrel distorted image used in VR?

      RESOLVED: No. VR applications would still require a post-processing step to
      generate a barrel distorted image to compensate for the lens distortion.
      The following vertex and fragment shader pair un-warps a w-scaled image.
      It can be incorporated into an existing post-processing shader to directly
      convert a w-scaled image to the barrel distorted image.

        // Vertex Shader
        // Draw a triangle that covers the whole screen
        const vec4 positions[3] = vec4[3](vec4(-1, -1, 0, 1),
                                          vec4( 3, -1, 0, 1),
                                          vec4(-1,  3, 0, 1));
        out vec2 uv;
        void main()
        {
          vec4 pos = positions[ gl_VertexID ];
          gl_Position = pos;
          uv = pos.xy;
        }

        // Fragment Shader
        uniform sampler2D tex;
        uniform float xcoeff;
        uniform float ycoeff;
        out vec4 Color;
        in vec2 uv;

        void main()
        {
          // Handle uv as if upper right quadrant
          vec2 uvabs = abs(uv);

          // unscale: transform w-scaled image into an unscaled image
          //   scale: transform unscaled image int a w-scaled image
          float unscale = 1.0 / (1 + xcoeff * uvabs.x + xcoeff * uvabs.y);
          //float scale = 1.0 / (1 - xcoeff * uvabs.x - xcoeff * uvabs.y);

          vec2 P = vec2(unscale * uvabs.x, unscale * uvabs.y);

          // Go back to the right quadrant
          P *= sign(uv);

          Color = texture(tex, P * 0.5 + 0.5);
        }

    (2) In the standard use case a application sets up 4 viewports, one for
        each quadrant. Does each primitive have to be broadcast to all the 4
        viewports?

      RESOLVED: No. Applications may see a better performance if the viewport
      mask for each primitive is limited to the viewports corresponding
      to the quadrants it falls in.


Revision History

    Revision 1
      - Internal revisions.
    Revision 2
      - Add _NV suffixes to _COEFF tokens
