From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

Viewport FX Design

Viewport FX consists of two major parts:

  • A lower level OpenGL Compatibility Layer which provides a common interface to access primitive graphics operations.
  • A higher level Dynamic Compositing Viewport which divides Blender's drawing operations into distinct named pieces that can then be modified and combined.

There are also other important goals:

  • Create a strict OpenGL usage policy which covers how state should be managed efficiently and disparate modules can inter-operate without glitches.
  • Optimize OpenGL performance by removing redundant state changes, increasing vertex batch sizes, reducing overall API call count, and using memory and memory bandwidth effectively (all of these things are very closely related).

OpenGL Compatibility Layer

The compatibility layer serves three purposes:

  • Replace deprecated functionality with a "source compatible" version that has a small impact on existing code while removing dependencies on obsolete versions of OpenGL.
  • Encapsulate incompatibilities between Legacy OpenGL (versions 1 and 2), Contemporary OpenGL (versions 3 and 4), OpenGL ES 1, and OpenGL ES 2.
  • In general, provide hooks for other polymorphic behavior without breaking existing code.

It is not certain whether the compatibility layer should cover every aspect of OpenGL or just the deprecated and incompatible parts. Theoretically a compatibility layer could expand to the point that it completely encapsulate and a Direct3D version of Blender could be written.

Deprecation

There is nothing inherently wrong with a function like glLight or glMultMatrix, it was just decided that they no longer belonged in the library. That leaves it up to everybody writing for OpenGL to come up with their own ways of saying where lights are and how to manage matrices. If you have hundreds of thousands of lines of OpenGL code it only makes sense to make your replacement as "source compatible" as possible.

Source compatibility is the degree to which a simple search and replace operation could have you up and running with the new functions.

To aid with replacing deprecated functionality the compatibility layer should:

  • Reuse GLenum values where possible. These have not been deprecated, only the way in which they are used.
  • Create function names similar to existing API entries where we need close functionality.
  • Feel free to create non-source-compatible functions where we can do better (object oriented matrix stack, for example).
  • Feel free to not re-implement an API as a slavish copy of its OpenGL original if doing so will benefit Blender (leave out what Blender does not need!).

Deprecated functionality that needs to be replaced consists of:

  • The immediate mode interface exemplified by glBegin/glEnd.
  • The specification of lighting and material state.
  • The modelview, texture, and projection matrix settings. Note: as an example of how things could be improved over legacy OpenGL we can treat the "model" and "view" matrices separately everywhere in the API instead of combining them.
  • And finally there are common use cases, such as drawing a box, cube, circle, or sphere, which should be factored out into a common utility library to replace outdated libraries like GLU.

Other parts, such as vertex arrays and vertex buffer objects do not need to be replaced so much as abstracted into more easily programmed interfaces. The replacement for immediate mode is an example of such an interface, but other interfaces are needed to represent geometry that is either larger in size or does not change every frame.

There are some areas, such as textures, where careful programming (and following a usage policy!) will be just as important as creating a new set of functions. In this case it would be OK to use existing OpenGL APIs and they only need to be encapsulated to promote other goals, such as polymorphism.

Immediate Mode

There is lots of code that uses glBegin/glEnd and most of it does not draw more than a handful of vertexes. There is little benefit to breaking this code and regressing since the benefit to performance will be slight (or even negative!).

The immediate mode interface should do these things to be compatible with, but improve upon, OpenGL:

  • Only support the variations of glMultiTexCoord/glTexCoord/glColor/glNormal/glVertex that Blender actually uses.
  • Narrow these down even further by eliminating integer and double versions (except short for normals and ubytes for colors).
  • Although it breaks source compatibility, force the programmer to declare up front which components are going to be used and what dimension they are.
  • Use this interface to fill a vertex array or buffer object behind the scenes.
  • Extend the interface to allow for indexed primitives.
  • Let objects built using this interface be retained like a display list and allow for editing (rewrite a vertex, append a vertex, etc.)

User:Jwilkins/GSoC2012/Immediate_Mode_Replacement

Lighting

The interface for lighting should be lifted almost wholesale from OpenGL in a way that a search and replace would be all that is needed to port the code and the new functions just call the old functions when on a legacy system.

The existing API is easily extensible to support new kinds of lights and new light parameters. It should be possible to gradually extend the compatibility layer to support all of Blender's lighting parameters and have them be implemented in GLSL.

A basic plan for how this might go:

  • Create a thin wrapper for OpenGL lighting parameters that can directly replace glEnable(GL_LIGHTi)/glLight/glLightModel/glMaterial/glColorMaterial
  • Pay special special attention is the interaction between light position and any new transformation matrix interface.
  • In the future (not this summer) extend this interface to include Blender specific features.

Transformation

This section is due for a major revision after discussions on the mailing list.

A rough sketch of an OpenGL transformation library.

  • A matrix stack library that is source compatible with OpenGL in that the same sequence of operations will give the same matrix (accounting for floating point numbers of course).
  • Additional transformations based on Blender's small matrix library.
  • There would be no need to change "modes" and more matrix stackes could be created than the "standard" 3.
  • "Unlimited" stack depth.
  • The "standard" matrices would be automatically hooked up to their traditional meanings.
  • An option to separate modelview into "model" and "view" matrices which remain valid until you change the modelview directly.
  • Place lights either using the legacy method of using the current modelview or using a custom matrix.
  • Concatenate transformations to the top or bottom.
  • Use Blender's float[4][4] and float[3][3] matrix and float[4] quaternion types instead of float*.

In addition, some uses of the matrices in OpenGL are detrimental to performance because they force smaller batches. For example, using glTranslate to specify the position of individual letters forces text to be drawn one letter at a time (or worse, using multiple batches to draw a single letter!). One way to solve this may be to provide a set of functions to transform input locally on the CPU before putting it in a vertex buffer. Such an interface would not have to call the equivalent of glEnd/glDrawArrys/glDrawElements before making the next primitive.

I have a couple of things I'm not sure about:

  1. Should we copy glMatrixMode, but allow for any number of matrixes? This would be easy to port and would be less typing.
  2. If we do not want to call glLoadMatrix every time the matrix changes, how do we let the library know the matrix is "finished"?

One way might be to have an interface like this:

gpuMatrixMode(GPU_MODELVIEW); /* really fast, just an assignment, so always use this before a transform */

gpuPushMatrix() /* could have unlimited stack size, but would need to warn large stacks */

gpuMatrixTransformStart() /* creates a temporary work area to make a new matrix */

/* can't push while in a Transform region */

gpuLoadIdentity()
gpuScale(...);
gpuRotate(...);
gpuTranslate(...);
gpuLoadMatrix(...);
gpuGetMatrix(); /* intuitive name instead of GetFloat */

gpuMatrixTransformCommit();  /* load the result into OpenGL */
gpuMatrixTransformRollback(); /* or, throw away temporary and leave things alone (probably not needed) */

/* draw something here */

gpuPopMatrix();

With this interface we could search and replace, but would still have to go through and find where we need to put Commit and Rollback.

Without something like Commit I'm afraid that we'd have to call glLoadMatrix or glUniform every time before we draw. With some tricks we could do it automatically

Having to always use TransformStart/TransformEnd might be really verbose in some cases. Maybe something gpuScaleNow which takes both a matrix pointer and its parameters and immediately loads the result so its ready for use. That would eliminate the need for both TransformStart/TransformCommit and MatrixMode in situations where only one transform is needed.

Of course, all that is really needed is gpuLoadMatrixNow, but only having that would require more rewriting of almost all of the OpenGL matrix transform code.

GLU

Retained Mode

What do to about Non-deprecated APIs

Incompatibilities

Polymorphism

Dynamic Compositing Viewport

OpenGL Usage Policy

Performance Optimization