Setting the LoadOp and StoreOp or Using invalidate/discard

Recommendations on what to instruct Vulkan or OpenGL ES to do with the frame buffer before and after rendering

In Vulkan and PVRVk, when creating a RenderPass object, set the LoadOp and the StoreOp to it.

The LoadOp means "when starting a render pass, what is necessary to do with whatever contents the frame buffer where we are rendering contains?"

There are three options here:

  • Clear actually means "forget what's in there, use this colour". This is usually the recommended operation.
  • Don't Care means "the entire scene will be rendered anyway, so it doesn't matter, don't load it"
  • Preserve means "the scene will be rendered incrementally, using whatever is already in the framebuffer, so the contents of it need to be preserved."

Clear and Don't Care may sound different, but it is important to realise that their effect is practically the same as far as the important parts of performance go. They both allow the driver to ignore what is in the frame buffer. In the case of Clear, the driver will just be using the clear colour instead of the contents of the frame buffer. Don't Care is similar, but also tells the driver that no specific colour is required.

Never use Preserve unless absolutely certain it is needed as it will introduce an entire round-trip to main memory. Its performance cost on bandwidth cannot be overstated. It is recommended to double-check the application design if Preserve is actually required.

In OpenGL ES, the situation is very similar. When glClear is called at the start of a frame, or glInvalidate depth/stencil before swapping, the driver may be allowed to discard the contents of the frame buffer / depth buffer before the next frame.

The specific flags depend on usage, but the baseline should be as follows:

Recommendations for LoadOp

  • Clear for depth/stencil, using the maximum depth value/whatever the stencil needs to be.
  • Clear for colour, if any part of the screen may not be rendered.
  • Ignore, if it is guaranteed that every single pixel on the screen will be rendered to. It would be almost the same to always set Clear in every case, but it does not hurt to be pedantic and set ignore if it is suitable. Never set Ignore and have pixels on screen that have not been specifically overwritten, as then there is undefined behaviour and there may be artifacts or flickering.

Conversely, for OpenGL ES:

  • glClear both colour and depth at the start of the frame.

Recommendations for StoreOp

The StoreOp is much the same, but it should be even more obvious. In nearly every case, it is necessary to:

  • Store the colour so that it can be displayed on screen
  • Discard the depth and stencil as their work is done

Conversely, for OpenGL ES, before calling eglSwapBuffers:

  • Do not do anything special for colour (EGL_PRESERVE in EGL swap behaviour)
  • glInvalidateFrameBuffers/glDiscardFrameBuffers any FBOs that are not being rendered, and all depth/stencil attachments.

In short:

  • Colour usually needs to be cleared on load, unless the contents of the frame buffer need to be explicitly read. A need to load the colour is very commonly a hint that subpasses/pixel local storage should be used instead if possible.
  • Colour usually needs to be stored at the end of the frame, in order to be presented.
  • Depth and stencil almost always need to be cleared to max value at the start of the pass.
  • Depth and stencil almost never need to be stored at the end of the pass, as they are not required for rendering.