2. Block Mode Settings

The 3DS render buffer can be set to block-8 mode or block-32 mode. The render buffer must be in block-32 mode when using early depth tests (described later). If you are not using early depth tests, leave the render buffer in the initial default setting of block-8 mode.

Use the glRenderBlockModeDMP function to set the block mode.

Code 2-1. glRenderBlockModeDMP Function
void glRenderBlockModeDMP(GLenum mode);

The mode parameter can take one of the following values.

Table 2-1. Block Mode Setting Values
Value Block Mode
GL_RENDER_BLOCK8_MODE_DMP Block-8 mode (default)
GL_RENDER_BLOCK32_MODE_DMP Block-32 mode

Unlike block-8 mode, block-32 mode has the following restrictions.

  • The block size is changed to 32, so the render buffer and display buffer width and height must both be in multiples of 32 pixels. Due to this restriction, it is not possible to allocate a render buffer or display buffer of the exact size of the LCD screen.
  • The glCopyTexImage2D and glCopyTexSubImage2D functions do not correctly copy images to textures.
  • Rendered results will not be correct when specifying a texture in the framebuffer (render to texture). Due to this restriction, it is not possible to carry out any processing that requires rendering to textures, such as rendering shadows or gases.

Rendered results are not guaranteed if you render while changing the block mode. All calls to the glDrawElements, glDrawArrays, and glReadPixels functions on the same render buffer must be run in the same block mode. Call the glGetIntegerv function and pass GL_RENDER_BLOCKMODE_DMP as an argument to get the current block mode.

2.1. Early Depth Test

The early depth test is a depth test that runs at the same time as rasterization. It can be used to discard unnecessary fragments at an earlier stage than the standard depth test. To use this feature, the render buffer must be in block-32 mode.

The early depth test is run using the early depth buffer. The early depth buffer treats a 32x32-pixel square as one block, with each block represented by one depth value. This representative value is stored with 12-bit precision, and the early depth value for the corresponding block is updated when depth values are written to the standard depth buffer. There is no need to allocate memory for the early depth buffer, and the early depth buffer supports depth buffers up to 1024×1024 pixels in size. The test compares the depth value of the polygon currently being rendered, as calculated at rasterization time, against the block's representative depth value (which is either the minimum or maximum depth value). If a block passes the early depth test, all of its fragments are passed along to the next process. If it fails the test, all fragments in the block are discarded.

The early depth test can be used to reduce the number of fragments sent through the fragment pipeline. However, the early depth test is less precise than the standard depth test, so it sometimes yields different results. Note that performance might improve less than expected, or fragments that are normally rendered might instead be discarded. Any fragments that are normally discarded (but are instead passed) are discarded by the standard depth test, so false passes do not have much effect on performance. However, false failures that discard fragments that are normally passed on for rendering may lead to display problems.

The early depth test is intended for use as a depth test that runs early in the pipeline, and it must be disabled (along with the standard depth test), whenever the standard depth test is disabled. If the early depth test alone is enabled, fragments that are normally rendered might be left out.

2.1.1. Test Control

Much as with the standard depth test, use the glEnable and glDisable functions to enable and disable the early depth test. Use the glIsEnabled function to check whether the early depth test is enabled. Pass GL_EARLY_DEPTH_TEST_DMP as the argument for the functions.

Code 2-2. Early Depth Test Control
glEnable(GL_EARLY_DEPTH_TEST_DMP);
glDisable(GL_EARLY_DEPTH_TEST_DMP);
glIsEnabled(GL_EARLY_DEPTH_TEST_DMP);

2.1.2. Clearing the Buffer

The early depth buffer is independent of the standard depth buffer. It can be cleared independently, but be sure to also clear the early depth buffer whenever you clear the standard depth buffer.

To clear the early depth buffer, call the glClear function and pass GL_EARLY_DEPTH_BUFFER_BIT_DMP for the mask parameter. Use the glClearEarlyDepthDMP function to set the value used to clear the buffer.

Code 2-3. Setting the Value Used to Clear the Early Depth Buffer
void glClearEarlyDepthDMP(GLuint depth);

The values used to clear the early depth buffer and the standard depth buffer are very similar, but whereas a GLfloat is used to clear the standard depth buffer, you must specify a positive integer for the early depth buffer. Use the following equation to calculate the value to specify.

Because the early depth test is less precise than the standard depth test, we recommend using a positive value of 0x1000 or greater for offset when using GL_LESS or GL_LEQUAL modes, and a value of –0x1000 or lower when using GL_GREATER or GL_GEQUAL modes. Valid clear values for the early depth buffer lie in the range from 0x000000 through 0xFFFFFF, so be sure to clamp to within this range if the results after adding offset ever fall outside these bounds.

To get the configured clear value, call the glGetIntegerv function and pass GL_EARLY_DEPTH_CLEAR_VALUE_DMP for the pname parameter.

2.1.3. Depth Buffer Update Flag

The early depth buffer contains early depth values in blocks of 32×32 pixels, in addition to update flags of the standard depth buffer (the depth buffer update flags) in 4×4 pixel units. This flag is set to 1 when even one pixel of the corresponding 4×4 pixel block in the depth buffer is changed as the result of the standard depth test. The early depth value held in the early depth buffer block that contains that pixel is then updated. When this flag is set to 1, the flag does not change, even if pixels in the corresponding block are updated in the depth buffer, and the early depth values are then also not updated. However, when the depth buffer is updated for pixels for which the corresponding flag is still 0, even when included in the same early depth buffer block, the flag is set to 1 and the early depth value is updated. The depth buffer update flag is only cleared to 0 when the early depth buffer is cleared.

The early depth test results are strongly dependent on the rendering order of the model, due to this controlling effect of the depth buffer update flag. To increase the effect of the early depth test, set the comparison function to GL_LESS or GL_LEQUAL to render a model from the foreground toward the back, and set to GL_GREATER or GL_GEQUAL to render from the back toward the foreground.

For example, when the comparison function is set to GL_LESS, rendering model objects farther toward the background first means that objects more in the foreground that are rendered later will not have their early depth buffers updated, causing an increase in the number of fragments that pass the early depth test and resulting in less of an effect from the early depth test. Conversely, rendering objects more in the foreground first results in an increase in the number of fragments discarded by the early depth test, and thus a greater effect from the test.

When setting as above and rendering the background first, the early depth test has no effect at all. In such cases, disable the early depth test just when rendering the background and then enable it when rendering other models to get at least some effect from the early depth test.

Note:

The early depth value is not updated for pixels that have already been rendered once because of the update flag. You must clear the early depth buffer each frame to set the update flag to 0, even though you change the comparison function between even and odd frames to avoid clearing the depth buffer.

2.1.4. Setting the Comparison Function

The comparison function to use for early depth tests must be configured separately from the standard depth test's comparison function. Use the glEarlyDepthFuncDMP function to set the comparison function.

Code 2-4. Setting the Early Depth Test Comparison Function
void glEarlyDepthFuncDMP(GLenum func);

The func parameter specifies the comparison function. The four comparison functions that can be set are GL_LESS, GL_LEQUAL, GL_GREATER, and GL_GEQUAL. No other comparison function can be set. Setting different comparison functions for the early depth test and standard depth test can cause inconsistencies in the pass/failure results of the tests.

Due to restrictions on the comparison function for the early depth test, it cannot be changed easily. If you change the depth test comparison function during rendering of a single scene, the early depth test can no longer be used until the early depth buffer is cleared.

However, this buffer is the only one that needs to be cleared to use the test again. To get the currently set comparison function, call the glGetIntegerv function and pass GL_EARLY_DEPTH_FUNC_DMP for the pname parameter. GL_LESS is the default setting.

If the early depth test is enabled, the corresponding early depth buffer value is updated to the maximum or minimum depth value of the fragments in that block whenever values are written to the standard depth buffer. The early depth buffer is updated to the maximum value when the early depth test comparison function is set to the GL_LESS or GL_LEQUAL mode, and to the minimum value when set to the GL_GREATER or GL_GEQUAL mode. The early depth buffer contents cannot be directly read or set from outside.

2.1.4.1. Changing the Comparison Function

Regardless of whether you change the early depth test comparison function during the rendering of a single frame, there are several restrictions you must observe whenever you change this comparison function.

  • The comparison function for the early depth test must be the same as for the standard depth test.
  • After an early depth test is set to a particular comparison function, this comparison function cannot be changed until the early depth buffer is cleared.
  • If the standard depth test comparison function is changed for a given render buffer and something more is rendered to that buffer, the early depth test cannot be enabled until the early depth buffer is cleared.
  • If the standard depth test comparison function is changed to one that cannot be used for the early depth test, the early depth test must be disabled.

Failing to comply with these restrictions may lead to the wrong fragments being discarded, resulting in incorrectly rendered results.

Some ways of avoiding these restrictions include: only enabling the early depth test in those locations where you want to improve performance, or always clearing the early depth buffer whenever you change the comparison function. However, clearing the early depth buffer too often can cause an increase in false passes, and prevent any improvements in performance.

When you clear the standard depth buffer and early depth buffer at different times (such as when you change the comparison function within a single frame), use either the minimum (0x000000) or maximum (0xFFFFFF) clear values to help avoid false test results.

2.1.5. Problems When Using Viewports With an Offset

There is a hardware bug with the early depth test that prevents the viewport offset from being applied to the coordinates that are read from the early depth buffer. As a result, the early depth test is not run properly when the viewport offset (the x and y parameters to the glViewport function) is not (0, 0).

Because the viewport offset is applied to the coordinates that are updated in the early depth buffer, the depth value of pixels with the viewport offset applied is compared with the depth values in the early depth buffer without the offset applied. This causes pixels that normally pass the early depth test to fail, and prevents pixels that are normally rendered from being rendered. When a pixel fails the early depth test, its entire 8×8 pixel block is mistakenly discarded.

The following are two ways to work around this issue.

  • Set a viewport offset other than (0, 0) and disable the early depth test. The early depth test is less effective if it switches between being enabled and disabled while a single scene is rendered, but the rendered results are the same because the normal depth test discards any pixels that are normally discarded.
  • Set the viewport offset to (0, 0) and then use a modelview transformation to shift the render region and cut off unnecessary areas with the scissor test.

 


CONFIDENTIAL