Equalizer logo
Collage logo
GPU-SD logo

Compounds

Author: eilemann@gmail.com
State: Partly implemented

Table of Contents

Background

OpenGL Multipipe SDK (MPK) used the concept of compounds to describe the decomposition and recomposition of the rendering. The compound had a mode describing the decomposition algorithm, and various flags to modify it. Each compound has a channel, on which the rendering is executed. Compounds form a tree. The root compound's channel defines the view to be rendered by all children. Equalizer has to provide at least the same functionality.

Equalizer eliminates the concept of a compound mode, which does configure both the decomposition and the recomposition. Instead Equalizer uses tasks, input frames and output frames to describe the rendering decomposition and recomposition. This allows for a more flexible configuration, especially when it comes to the various sort-last recomposition algorithms, e.g., direct send and binary swap.

Glossary

Requirements

The following decomposition modes have to be supported:

The following recomposition modes have to be supported:

The following optimisation have to be possible:

Specification

Equalizer uses a compound tree, similar to MPK. In contrast to MPK, the decomposition and recomposition is not described using flags. Instead, the rendering tasks are directly described for each compound. By combining the right tasks, the same functionality as in MPK can be achieved. The following config file illustrates the equivalent of a MPK 2-channel 2D compound:

 compound
 {
     channel "destination"
     wall {} // Frustum descriptions in Equalizer are on the compound

     compound // part rendered by second channel
     {
         channel "buffer"
         viewport [ .5 0 .5 1 ]

         outputframe {}
     }
     compound // part rendered by dest channel
     {
         task [ CULL DRAW ]
         viewport [ 0 0 .5 1 ] // restrict vp to half
     }

     inputframe { name "frame.buffer" }
 }

Each compound executes the tasks in the order they appear below. The default tasks for non-leaf compounds are assemble and readback. The default tasks for leaf compounds are all tasks. Assemble and readback tasks are only executed if output or input frames have been specified, respectively. The following tasks are possible:

Attributes

Attributes are inherited, that is, if they are not defined they are defined by the parent. If they are defined, they are often expressed relative to the parent. The following attributes are defined:

Input and Output

Certain tasks generate input and output. Right now, this can be queues for culling and frames for gathering. During compound initialisation, input and output objects with the same name are connected. IO entities can therefore not be shared between disjunct compound trees. Compound trees can be joined by a common parent compound, if entities are to be shared. Cached FrameDatas and Images are disposed during compound exit.

The default names are set during the adding of the object to the compound, if the object's name is empty. The default name for frames is 'frame.[compound-name]' if the compound has a name, otherwise 'frame.[channel-name]'. If neither has a name, the parent are tried until a name is found. If no name is found, the default name is 'frame'. For swap barriers, the default name is 'barrier.[root-compound-name]', 'barrier.[root-channel-name]' or 'barrier'.

Output frames use viewport, eye, period and phase attributes, which are relative to the compound attributes. Using the same output frame multiple times is currently undefined.

Input frames use the viewport, eye, period and phase attributes, which are relative to the corresponding output frame attributes. The same input frame can be used multiple times. Deadlocks are not checked and can occur when output and input frames are used inappropriately.

TODO: Queues and culling semantics

Swap barriers synchronize the compound's window before the execution of eq::Window::swap. If a swap barrier is set, eq::Window::finish is called before the barrier is entered. By default, this function calls glFinish to ensure the immediate execution of the swapbuffer command after the barrier is left. Deadlocks are not checked and can occur if multiple swap barriers are used inappropriately.

Images

Outsourced to a separate frames specification document.

Stereo

Problem Description

Equalizer traverses the compound tree once for each eye pass. If a compound renders multiple eye passes, and specifies a frame, the frame becomes used multiple times, which leads at least for output frames to undefined behaviour. This section design the implementation to correct this behaviour. Option 1 will be implemented.

Option 1: Eye-specific frames

This approach is mostly transparent to the application and user. The frame sets are separated by eye pass, which means that enabling stereo rendering just works. On the other hand, it prohibits the usage of frames between eyes, e.g., to swap eye views. This use case could be supported by an eye attribute on the frame, selecting the eye-specific frame independently of the current eye traversal.

Option 2: No changes

Keeping the implementation as it is does not prohibit stereo rendering and decompositions. However, it does require to write different configs for stereo rendering, as the individual eye passes have to be configured into separate compounds for each leaf compound, which increases complexity and is not user friendly.

Restrictions

The cull task, queues, DPlex and subpixel decomposition are not fully described. They will be designed further and implemented later. Stencil images will be implemented later. The behaviour of using the same output frame multiple times is currently undefined.

File Format

   compound
   {
       channel "channel-name"
       task    [ CLEAR CULL DRAW ASSEMBLE READBACK ]
       [ frustum-spec ]
       buffer  [ COLOR DEPTH STENCIL ]

       attributes
       {
           color, depth, stencil
           {
               format [ GL_enum ]
               type   [ GL_enum ]
           }
           hints
           {
               adaptive  [ bool ]
               decompose "split-string" // set during init, used by adaptive
           }
       }
       viewport [ x y w h ]
       range    [ start end ]
       eye      [ CYCLOP LEFT RIGHT ]
       period   [ int ]
       phase    [ int ]
       jitter   [ x y | AUTO ]

       (outputframe|inputframe)
       {
           name "frame-name"   // default see 'Input and Output'
           buffer   [ COLOR DEPTH STENCIL ]
           viewport [ x y w h ]
       }

       swapbarrier 
       { 
           name "barrier-name" // default see 'Input and Output'
           // later: period, phase
       }
   }
 

Example Config Files

   2-channel DB compound:

    compound {
        channel "destination"
        buffer [ COLOR DEPTH ]
        
        compound {
            channel "buffer"
            range [ 0 .5 ]
            outputframe {}
        }
        compound
        {
            task [ CULL DRAW ]
            range [ .5 1 ] 
        }
        inputframe { name "frame.buffer" }
    }
------------------------------------------------------------------------

   2-channel 2D ASYNC compound, latency should be >=1 :

    compound {
        channel "destination"
        
        compound {
            channel "buffer"
            viewport [ 0 0 .5 1 ]
            outputframe {}
        }

        compound { task [ ASSEMBLE ]  inputframe { name "frame.buffer" }}
        compound { task [ CULL DRAW ] viewport [ .5 0 .5 1 ] }
    }
------------------------------------------------------------------------
   
   2-channel SYNC compound:

    compound {
        compound {
            channel "channel1"
            wall {}
            swapbarrier {}
        }
        compound {
            channel "channel2"
            wall {}
            swapbarrier {}
        }
    }

------------------------------------------------------------------------
   
   2:3-channel DPlex compound:

    compound {
        channel "destination"
        
        compound {
            channel "buffer1"
            period 2
            phase  0

            outputframe {}
        }
        compound {
            channel "buffer2"
            period 2
            phase  1

            outputframe {}
        }

        inputframe { name "frame.buffer1" }
        inputframe { name "frame.buffer2" }
    }
------------------------------------------------------------------------

   1:2-channel CULL compound

    compound {
        channel "destination"
        wall{}
        
        compound {
            task    [ CULL ]
            channel "cull-channel"

            inputqueue[CULL] { name "queue.config" }
            outputqueue[CULL] {}
        }
        compound {
            task [ CLEAR DRAW ]
            inputqueue[DRAW] { name "queue.cull-channel" }
        }
    }
------------------------------------------------------------------------

   3-channel DB compound, direct send assembly

    compound {
        channel "dest"
        buffer [ COLOR DEPTH ]
        
        compound {
            channel "buffer1"

            compound {
                range [ 0 .3333 ]
                outputframe { name "frame1.buffer1" viewport [ 0 0   1 .33 ] }
                outputframe { name "frame2.buffer1" viewport [ 0 .33 1 .33 ] }
            }
            inputframe { name "frame2.buffer2" }
            inputframe { name "frame2.dest" }
            outputframe { buffer [ COLOR ] viewport [ 0 .66 1 .34 ] }
        }
        compound {
            channel "buffer2"

            compound {
                range [ .3333 .6666 ]
                outputframe { name "frame1.buffer2" viewport [0  0   1 .33 ] }
                outputframe { name "frame2.buffer2" viewport [0  .66 1 .34 ] }
            }
            inputframe { name "frame2.buffer1" }
            inputframe { name "frame1.dest" }
            outputframe { buffer [ COLOR ] viewport [ 0 .33 1 .33 ] }
        }
        compound {
            channel "dest"
            range   [ .6666 1 ]

            outputframe { name "frame1.dest" viewport [ 0 .33 1 .33 ] }
            outputframe { name "frame2.dest" viewport [ 0 .66 1 .34 ] }
        }

        inputframe { name "frame1.buffer1" }
        inputframe { name "frame1.buffer2" }
        inputframe { name "frame.buffer1" }
        inputframe { name "frame.buffer2" }
    }
------------------------------------------------------------------------

   4-channel DB compound, binary swap assembly

    compound {
        channel "dest"
        buffer [ COLOR DEPTH ]
        
        compound {
            channel "buffer1"

            compound {
                range [ 0 .25 ]
                outputframe { name "frame1.buffer1" viewport [ 0 0 1 .5 ] } 
            }
            compound {
                task [ ASSEMBLE READBACK ]
                inputframe { name "frame1.buffer2" }
                outputframe { name "frame2.buffer1" viewport [ 0 .5 1 .25 ] }
            }
            inputframe { name "frame2.buffer3" }
            outputframe { buffer [ COLOR ] viewport [ 0 .75 1 .25 ] } 
        }
        compound {
            channel "buffer2"

            compound {
                range [ .25 .5 ]
                outputframe { name "frame1.buffer2" viewport [ .5 0 1 .5 ] }
            }
            compound {
                task [ ASSEMBLE READBACK ]
                inputframe { name "frame1.buffer1" }
                outputframe { name "frame2.buffer2" viewport [ 0 0 1 .25 ] }
            }
            inputframe { name "frame2.dest" }
            outputframe { buffer [ COLOR ] viewport [ 0 .25 1 .25 ] }
        }
        compound {
            channel "buffer3"

            compound {
                range [ .5 .75 ]
                outputframe { name "frame1.buffer3" viewport [ 0 0 1 .5 ] } 
            }
            compound {
                task [ ASSEMBLE READBACK ]
                inputframe { name "frame1.dest" }
                outputframe { name "frame2.buffer3" viewport [ 0 .75 1 .25 ] }
            }
            inputframe { name "frame2.buffer1" {}
            outputframe { buffer [ COLOR ] viewport [ 0 .5 1 .25 ] }
            
        }
        compound {
            channel "dest"

            compound {
                range [ .75 1 ]
                outputframe { name "frame1.dest" viewport [ .5 0 .5 1 ] } 
            }
            compound {
                task [ ASSEMBLE READBACK ]
                inputframe { name "frame1.buffer3" }
                outputframe { name "frame2.dest" viewport [ 0 .25 1 .25 ] } 
            }
        }

        inputframe { name "frame2.buffer2" }
        inputframe { name "frame.buffer1" }
        inputframe { name "frame.buffer2" }
        inputframe { name "frame.buffer3" }
    }
------------------------------------------------------------------------

   2-channel 2D cross-balanced compound:

    compound {
        compound {
            channel "channel1"
            wall {}

            compound {
                channel "buffer-channel2"
                viewport [ ?? ]
                outputframe {}
            }
            compound
            {
                task [ CULL DRAW ]
                viewport [ 1-?? ] 
            }
            inputframe { name "frame.buffer-channel2" }

            swapbarrier {}
        }
        compound {
            channel "channel2"
            wall {}

            compound {
                channel "buffer-channel1"
                viewport [ ?? ]
                outputframe {}
            }
            compound
            {
                task [ CULL DRAW ]
                viewport [ 1-?? ] 
            }
            inputframe { name "frame.buffer-channel1" }

            swapbarrier {}
        }
    }