Equalizer logo

Subpixel Compounds

Author: eilemann@gmail.com
State: Design

Overview

This features adds support for a new type of decomposition and recomposition, whereby each contributing channel renders one or multiple subsamples for full-scene anti-aliasing (FSAA) or depth-of-field (DOF).

Applications might already do multi-pass software FSAA/DOF, either during rendering or when the application is idle. Equalizer does not yet have a notion of idle/non-idle rendering.

Design

The application will do the adding of the frustum jitter, since it is the one which knows how many FSAA and/or DOF samples are desired. Therefore it needs to know in Channel::frameDraw which sample out of how many it should render.

The default implementation of Channel::applyFrustum will use the subpixel sample description to compute an FSAA jitter using a pre-defined lookup table. It will add this jitter to the frustum supplied by getFrustum.

Applications which have their own SWAA settings will use the subpixel sample description to calculate how many passes with which samples have to be rendered, e.g., if it desires to render 16 samples on a 4-time decomposition, the application will render 4 passes out of a 16-value jitter lookup table on each channel.

It is the application's responsibility to provide a blended result of the sub-passes on each channel. This should not be an overhead, since the application could already compute the accumulation and averaging before.

Compositing

API

  vmml::Vector2f Channel::getJitter() const;
  vmml::Vector2i Channel::getSubpixel() const;

File Format

    compound
    {
        subpixel [ index size ]
    }

Implementation

Modify eqPly to do idle SWAA:

  EqPly
    static const uint32_t sampleSize

  FrameData
    uint32_t _idleStep
    bool     _idleMode
  
  Channel
    FBO*     _accumBuffer
    uint32_t _primeNumberTable

  Config::startFrame
    if view is idle
      idleMode = true
      idleStep++
    else
      idleMode = false
    commit frame data

  Channel::frameViewFinish
    frameAssemble is done and back buffer is ready
    if view is idle
      if first idle step
        reset accum buffer
      accumulate back buffer to accum buffer
      compute average in back buffer

  Channel::applyFrustum
    frustum = getFrustum()
    jitter = getJitter();
    frustum += jitter;
    glFrustum( ... );
  Compositor?

  Channel::_lookupPrimeNumberTable( channel ID )

  Channel::_generateFloatRand( begin, end )

  Channel::_computeJitterStep
    subset_size = ( sample_size * sample_size ) / nb_channels
    idx =  ( idle_step * getPrimeNumber()) % subset_size
    global_jitter = ( id_channel * subset_size ) + idx

  Channel::_computeJitter
    Compute normalized jitter area (idle step, channel index)
    Compute pixel size on near plane (frustum)
    Compute random sample position in normalized coordinates
    jitter = jitter area * pixel size * random position
    Attn: Floating point rounding errors!

--------------------------------------------------
Current idle AA in Eq application:

  Channel::frameAssemble()
    assemble input frames into back buffer
    if view is idle
      if first idle step
        reset accum buffer
      accumulate back buffer to accum buffer
      compute average in back buffer
    
      
  Channel::frameDraw()
    if view is idle
      get idle step # and jitter frustum
    render

Idle AA with AA compounds:
  Channel::frameAssemble
    if first idle step
      reset accum buffer
    if has more than one jitter step or view is idle
      for each jitter step in input frames
        assemble input frames with jitter step in back buffer
        accumulate back buffer in accum buffer
        ++n
      compute average in back buffer
      increase application idle steps done by n
      
  Channel::frameDraw()
    jitter step = f(application idle step, Channel jitter param)
      jitter step = idle_step * jitter_grp_size + jitter_offset
    render


Issues

1. Do we need a one-dimensional or two-dimensional subpixel description for each source channel?

This depends on Q2. My feeling is a one-dimensional attribute is easier.

2. How do I compute my current jitter area?

The number of jitter areas, i.e, the number of FSAA or DOF samples, is an application parameter. The current jitter area within each Channel::frameDraw is a function of the current idle step and the channel's subpixel description.

Open Issue: the function itself. The jitter values for all channels in the first pass should be evenly distributed over the total subpixel grid.

Idea: Divide the sample grid into the number of channels to get a subset of pixels for each channel. For each pass, compute (pass_number * rnd_prime_number) % size to get kind of a randomized distribution. The size parameter is the size of the pixel subset for the current channel.