material: Make CoglMaterial responsible for depth state

This redirects the legacy depth testing APIs through CoglMaterial and
adds a new experimental cogl_material_ API for handling the depth
testing state.

This adds the following new functions:
cogl_material_set_depth_test_enabled
cogl_material_get_depth_test_enabled
cogl_material_set_depth_writing_enabled
cogl_material_get_depth_writing_enabled
cogl_material_set_depth_test_function
cogl_material_get_depth_test_function
cogl_material_set_depth_range
cogl_material_get_depth_range

As with other experimental Cogl API you need to define
COGL_ENABLE_EXPERIMENTAL_API to access them and their stability isn't
yet guaranteed.
This commit is contained in:
Robert Bragg 2010-05-26 11:33:32 +01:00
parent ff4d3e048b
commit c434f1fc48
11 changed files with 952 additions and 28 deletions

View File

@ -127,6 +127,14 @@ cogl_create_context (void)
_context->gl_blend_enable_cache = FALSE;
_context->depth_test_enabled_cache = FALSE;
_context->depth_test_function_cache = COGL_DEPTH_TEST_FUNCTION_LESS;
_context->depth_writing_enabled_cache = TRUE;
_context->depth_range_near_cache = 0;
_context->depth_range_far_cache = 1;
_context->legacy_depth_test_enabled = FALSE;
_context->framebuffer_stack = _cogl_create_framebuffer_stack ();
window_buffer = _cogl_onscreen_new ();

View File

@ -109,6 +109,14 @@ typedef struct
gboolean gl_blend_enable_cache;
gboolean depth_test_enabled_cache;
CoglDepthTestFunction depth_test_function_cache;
gboolean depth_writing_enabled_cache;
float depth_range_near_cache;
float depth_range_far_cache;
gboolean legacy_depth_test_enabled;
/* PBOs */
/* This can be used to check if a pbo is bound */
CoglBuffer *current_pbo;

View File

@ -311,8 +311,9 @@ typedef enum _CoglMaterialState
COGL_MATERIAL_STATE_ALPHA_FUNC = 1L<<4,
COGL_MATERIAL_STATE_BLEND = 1L<<5,
COGL_MATERIAL_STATE_USER_SHADER = 1L<<6,
COGL_MATERIAL_STATE_DEPTH = 1L<<7,
COGL_MATERIAL_STATE_REAL_BLEND_ENABLE = 1L<<7,
COGL_MATERIAL_STATE_REAL_BLEND_ENABLE = 1L<<8,
COGL_MATERIAL_STATE_ALL_SPARSE =
COGL_MATERIAL_STATE_COLOR |
@ -321,7 +322,8 @@ typedef enum _CoglMaterialState
COGL_MATERIAL_STATE_LIGHTING |
COGL_MATERIAL_STATE_ALPHA_FUNC |
COGL_MATERIAL_STATE_BLEND |
COGL_MATERIAL_STATE_USER_SHADER,
COGL_MATERIAL_STATE_USER_SHADER |
COGL_MATERIAL_STATE_DEPTH,
COGL_MATERIAL_STATE_AFFECTS_BLENDING =
COGL_MATERIAL_STATE_COLOR |
@ -335,7 +337,8 @@ typedef enum _CoglMaterialState
COGL_MATERIAL_STATE_LIGHTING |
COGL_MATERIAL_STATE_ALPHA_FUNC |
COGL_MATERIAL_STATE_BLEND |
COGL_MATERIAL_STATE_USER_SHADER
COGL_MATERIAL_STATE_USER_SHADER |
COGL_MATERIAL_STATE_DEPTH
} CoglMaterialState;
@ -388,12 +391,22 @@ typedef struct
GLint blend_dst_factor_rgb;
} CoglMaterialBlendState;
typedef struct
{
gboolean depth_test_enabled;
CoglDepthTestFunction depth_test_function;
gboolean depth_writing_enabled;
float depth_range_near;
float depth_range_far;
} CoglMaterialDepthState;
typedef struct
{
CoglMaterialLightingState lighting_state;
CoglMaterialAlphaFuncState alpha_state;
CoglMaterialBlendState blend_state;
CoglHandle user_program;
CoglMaterialDepthState depth_state;
} CoglMaterialBigState;
typedef enum

View File

@ -347,6 +347,7 @@ _cogl_material_init_default_material (void)
CoglMaterialLightingState *lighting_state = &big_state->lighting_state;
CoglMaterialAlphaFuncState *alpha_state = &big_state->alpha_state;
CoglMaterialBlendState *blend_state = &big_state->blend_state;
CoglMaterialDepthState *depth_state = &big_state->depth_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -409,6 +410,13 @@ _cogl_material_init_default_material (void)
big_state->user_program = COGL_INVALID_HANDLE;
/* The same as the GL defaults */
depth_state->depth_test_enabled = FALSE;
depth_state->depth_test_function = COGL_DEPTH_TEST_FUNCTION_LESS;
depth_state->depth_writing_enabled = TRUE;
depth_state->depth_range_near = 0;
depth_state->depth_range_far = 1;
ctx->default_material = _cogl_material_handle_new (material);
}
@ -989,6 +997,13 @@ _cogl_material_copy_differences (CoglMaterial *dest,
big_state->user_program = COGL_INVALID_HANDLE;
}
if (differences & COGL_MATERIAL_STATE_DEPTH)
{
memcpy (&big_state->depth_state,
&src->big_state->depth_state,
sizeof (CoglMaterialDepthState));
}
/* XXX: we shouldn't bother doing this in most cases since
* _copy_differences is typically used to initialize material state
* by copying it from the current authority, so it's not actually
@ -2890,6 +2905,15 @@ _cogl_material_blend_state_equal (CoglMaterial *authority0,
return TRUE;
}
static gboolean
_cogl_material_depth_state_equal (CoglMaterial *authority0,
CoglMaterial *authority1)
{
return memcmp (&authority0->big_state->depth_state,
&authority1->big_state->depth_state,
sizeof (CoglMaterialDepthState)) == 0;
}
static gboolean
_cogl_material_layers_equal (CoglMaterial *authority0,
CoglMaterial *authority1)
@ -3103,6 +3127,19 @@ _cogl_material_equal (CoglHandle handle0,
return FALSE;
}
if (materials_difference & COGL_MATERIAL_STATE_DEPTH)
{
CoglMaterial *authority0 =
_cogl_material_get_authority (material0,
COGL_MATERIAL_STATE_DEPTH);
CoglMaterial *authority1 =
_cogl_material_get_authority (material1,
COGL_MATERIAL_STATE_DEPTH);
if (!_cogl_material_depth_state_equal (authority0, authority1))
return FALSE;
}
if (materials_difference & COGL_MATERIAL_STATE_LAYERS)
{
CoglMaterial *authority0 =
@ -3888,6 +3925,200 @@ _cogl_material_set_user_program (CoglHandle handle,
handle_automatic_blend_enable (material, state);
}
void
cogl_material_set_depth_test_enabled (CoglHandle handle,
gboolean enable)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterialState state = COGL_MATERIAL_STATE_DEPTH;
CoglMaterial *authority;
CoglMaterialDepthState *depth_state;
g_return_if_fail (cogl_is_material (handle));
authority = _cogl_material_get_authority (material, state);
depth_state = &authority->big_state->depth_state;
if (depth_state->depth_test_enabled == enable)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the material has no dependants so it may be modified.
* - If the material isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_material_pre_change_notify (material, state, NULL);
material->big_state->depth_state.depth_test_enabled = enable;
_cogl_material_update_authority (material, authority, state,
_cogl_material_depth_state_equal);
}
gboolean
cogl_material_get_depth_test_enabled (CoglHandle handle)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterial *authority;
g_return_val_if_fail (cogl_is_material (handle), FALSE);
authority =
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_DEPTH);
return authority->big_state->depth_state.depth_test_enabled;
}
void
cogl_material_set_depth_writing_enabled (CoglHandle handle,
gboolean enable)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterialState state = COGL_MATERIAL_STATE_DEPTH;
CoglMaterial *authority;
CoglMaterialDepthState *depth_state;
g_return_if_fail (cogl_is_material (handle));
authority = _cogl_material_get_authority (material, state);
depth_state = &authority->big_state->depth_state;
if (depth_state->depth_writing_enabled == enable)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the material has no dependants so it may be modified.
* - If the material isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_material_pre_change_notify (material, state, NULL);
material->big_state->depth_state.depth_writing_enabled = enable;
_cogl_material_update_authority (material, authority, state,
_cogl_material_depth_state_equal);
}
gboolean
cogl_material_get_depth_writing_enabled (CoglHandle handle)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterial *authority;
g_return_val_if_fail (cogl_is_material (handle), TRUE);
authority =
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_DEPTH);
return authority->big_state->depth_state.depth_writing_enabled;
}
void
cogl_material_set_depth_test_function (CoglHandle handle,
CoglDepthTestFunction function)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterialState state = COGL_MATERIAL_STATE_DEPTH;
CoglMaterial *authority;
CoglMaterialDepthState *depth_state;
g_return_if_fail (cogl_is_material (handle));
authority = _cogl_material_get_authority (material, state);
depth_state = &authority->big_state->depth_state;
if (depth_state->depth_test_function == function)
return;
/* - Flush journal primitives referencing the current state.
* - Make sure the material has no dependants so it may be modified.
* - If the material isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_material_pre_change_notify (material, state, NULL);
material->big_state->depth_state.depth_test_function = function;
_cogl_material_update_authority (material, authority, state,
_cogl_material_depth_state_equal);
}
CoglDepthTestFunction
cogl_material_get_depth_test_function (CoglHandle handle)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterial *authority;
g_return_val_if_fail (cogl_is_material (handle),
COGL_DEPTH_TEST_FUNCTION_LESS);
authority =
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_DEPTH);
return authority->big_state->depth_state.depth_test_function;
}
gboolean
cogl_material_set_depth_range (CoglHandle handle,
float near,
float far,
GError **error)
{
#ifndef COGL_HAS_GLES
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterialState state = COGL_MATERIAL_STATE_DEPTH;
CoglMaterial *authority;
CoglMaterialDepthState *depth_state;
g_return_val_if_fail (cogl_is_material (handle), FALSE);
authority = _cogl_material_get_authority (material, state);
depth_state = &authority->big_state->depth_state;
if (depth_state->depth_range_near == near &&
depth_state->depth_range_far == far)
return TRUE;
/* - Flush journal primitives referencing the current state.
* - Make sure the material has no dependants so it may be modified.
* - If the material isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
_cogl_material_pre_change_notify (material, state, NULL);
material->big_state->depth_state.depth_range_near = near;
material->big_state->depth_state.depth_range_far = far;
_cogl_material_update_authority (material, authority, state,
_cogl_material_depth_state_equal);
return TRUE;
#else
g_set_error (error,
COGL_ERROR,
COGL_ERROR_MISSING_FEATURE,
"glDepthRange not available on GLES 1");
return FALSE;
#endif
}
void
cogl_material_get_depth_range (CoglHandle handle,
float *near,
float *far)
{
CoglMaterial *material = COGL_MATERIAL (handle);
CoglMaterial *authority;
g_return_if_fail (cogl_is_material (handle));
authority =
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_DEPTH);
*near = authority->big_state->depth_state.depth_range_near;
*far = authority->big_state->depth_state.depth_range_far;
}
static CoglMaterialLayer *
_cogl_material_layer_copy (CoglMaterialLayer *src)
{
@ -5838,7 +6069,43 @@ blend_factor_uses_constant (GLenum blend_factor)
#endif
static void
_cogl_material_flush_color_blend_alpha_state (CoglMaterial *material,
flush_depth_state (CoglMaterialDepthState *depth_state)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->depth_test_function_cache != depth_state->depth_test_function)
{
GE (glDepthFunc (depth_state->depth_test_function));
ctx->depth_test_function_cache = depth_state->depth_test_function;
}
if (ctx->depth_writing_enabled_cache != depth_state->depth_writing_enabled)
{
GE (glDepthMask (depth_state->depth_writing_enabled ?
GL_TRUE : GL_FALSE));
ctx->depth_writing_enabled_cache = depth_state->depth_writing_enabled;
}
#ifndef COGL_HAS_GLES
if (ctx->depth_range_near_cache != depth_state->depth_range_near ||
ctx->depth_range_far_cache != depth_state->depth_range_far)
{
#ifdef COGL_HAS_GLES2
GE (glDepthRangef (depth_state->depth_range_near,
depth_state->depth_range_far));
#else
GE (glDepthRange (depth_state->depth_range_near,
depth_state->depth_range_far));
#endif
ctx->depth_range_near_cache = depth_state->depth_range_near;
ctx->depth_range_far_cache = depth_state->depth_range_far;
}
#endif /* COGL_HAS_GLES */
}
static void
_cogl_material_flush_color_blend_alpha_depth_state (
CoglMaterial *material,
unsigned long materials_difference,
gboolean skip_gl_color)
{
@ -5948,12 +6215,36 @@ _cogl_material_flush_color_blend_alpha_state (CoglMaterial *material,
alpha_state->alpha_func_reference));
}
if (materials_difference & COGL_MATERIAL_STATE_DEPTH)
{
CoglMaterial *authority =
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_DEPTH);
CoglMaterialDepthState *depth_state = &authority->big_state->depth_state;
if (depth_state->depth_test_enabled)
{
if (ctx->depth_test_enabled_cache != TRUE)
{
GE (glEnable (GL_DEPTH_TEST));
ctx->depth_test_enabled_cache = depth_state->depth_test_enabled;
}
flush_depth_state (depth_state);
}
else if (ctx->depth_test_enabled_cache != FALSE)
{
GE (glDisable (GL_DEPTH_TEST));
ctx->depth_test_enabled_cache = depth_state->depth_test_enabled;
}
}
if (material->real_blend_enable != ctx->gl_blend_enable_cache)
{
if (material->real_blend_enable)
GE (glEnable (GL_BLEND));
else
GE (glDisable (GL_BLEND));
/* XXX: we shouldn't update any other blend state if blending
* is disabled! */
ctx->gl_blend_enable_cache = material->real_blend_enable;
}
}
@ -6129,7 +6420,7 @@ _cogl_material_flush_common_gl_state (CoglMaterial *material,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_material_flush_color_blend_alpha_state (material,
_cogl_material_flush_color_blend_alpha_depth_state (material,
materials_difference,
skip_gl_color);
@ -6568,16 +6859,18 @@ _cogl_material_apply_legacy_state (CoglHandle handle)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->current_program)
{
/* It was a mistake that we ever copied the OpenGL style API for
* making a program current (cogl_program_use) on the context.
* Until cogl_program_use is removed we will transparently set
* the program on the material because the cogl-material code is
* in the best position to juggle the corresponding GL state. */
_cogl_material_set_user_program (handle,
ctx->current_program);
}
* associating these things directly with the context when we
* originally wrote Cogl. Until the corresponding deprecated APIs
* can be removed though we now shoehorn the state changes through
* the cogl_material API instead.
*/
if (ctx->current_program)
_cogl_material_set_user_program (handle, ctx->current_program);
if (ctx->legacy_depth_test_enabled)
cogl_material_set_depth_test_enabled (handle, TRUE);
}
void

View File

@ -944,6 +944,213 @@ cogl_material_layer_get_wrap_mode_s (CoglHandle layer);
CoglMaterialWrapMode
cogl_material_layer_get_wrap_mode_t (CoglHandle layer);
/* XXX: should this be CoglMaterialDepthTestFunction?
* It makes it very verbose but would be consistent with
* CoglMaterialWrapMode */
/**
* CoglDepthTestFunction:
* @COGL_DEPTH_TEST_FUNCTION_NEVER: Never passes.
* @COGL_DEPTH_TEST_FUNCTION_LESS: Passes if the fragment's depth
* value is less than the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_EQUAL: Passes if the fragment's depth
* value is equal to the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_LEQUAL: Passes if the fragment's depth
* value is less or equal to the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_GREATER: Passes if the fragment's depth
* value is greater than the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_NOTEQUAL: Passes if the fragment's depth
* value is not equal to the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_GEQUAL: Passes if the fragment's depth
* value greater than or equal to the value currently in the depth buffer.
* @COGL_DEPTH_TEST_FUNCTION_ALWAYS: Always passes.
*
* When using depth testing one of these functions is used to compare
* the depth of an incoming fragment against the depth value currently
* stored in the depth buffer. The function is changed using
* cogl_material_set_depth_test_function().
*
* The test is only done when depth testing is explicitly enabled. (See
* cogl_material_set_depth_test_enabled())
*/
typedef enum
{
COGL_DEPTH_TEST_FUNCTION_NEVER = GL_NEVER,
COGL_DEPTH_TEST_FUNCTION_LESS = GL_LESS,
COGL_DEPTH_TEST_FUNCTION_EQUAL = GL_EQUAL,
COGL_DEPTH_TEST_FUNCTION_LEQUAL = GL_LEQUAL,
COGL_DEPTH_TEST_FUNCTION_GREATER = GL_GREATER,
COGL_DEPTH_TEST_FUNCTION_NOTEQUAL = GL_NOTEQUAL,
COGL_DEPTH_TEST_FUNCTION_GEQUAL = GL_GEQUAL,
COGL_DEPTH_TEST_FUNCTION_ALWAYS = GL_ALWAYS
} CoglDepthTestFunction;
/* XXX: to avoid having to split this into a separate include that can
* in #included internally without needing the
* COGL_ENABLE_EXPERIMENTAL_API define this isn't guarded. It's still
* considered experimental but it's guarded instead by the fact that
* there's no corresponding API. */
#ifdef COGL_ENABLE_EXPERIMENTAL_API
/**
* cogl_material_set_depth_test_enabled:
* @handle: A CoglMaterial handle
* @enable: The enable state you want
*
* Enables or disables depth testing according to the value of
* @enable.
*
* If depth testing is enable then the #CoglDepthTestFunction set
* using cogl_material_set_depth_test_function() us used to evaluate
* the depth value of incoming fragments against the corresponding
* value stored in the current depth buffer, and if the test passes
* then the fragments depth value is used to update the depth buffer.
* (unless you have disabled depth writing via
* cogl_material_set_depth_writing_enabled ())
*
* By default depth testing is disabled.
*
* Since: 1.4
*/
void
cogl_material_set_depth_test_enabled (CoglHandle handle,
gboolean enable);
/**
* cogl_material_get_depth_test_enabled:
* @handle: A CoglMaterial handle
*
* Gets the current depth test enabled state as previously set by
* cogl_material_set_depth_test_enabled().
*
* Returns: The material's current depth test enabled state.
* Since: 1.4
*/
gboolean
cogl_material_get_depth_test_enabled (CoglHandle handle);
/**
* cogl_material_set_depth_writing_enabled:
* @handle: A CoglMaterial handle
* @enable: The enable state you want
*
* Enables or disables depth buffer writing according to the value of
* @enable. Normally when depth testing is enabled and the comparison
* between a fragment's depth value and the corresponding depth buffer
* value passes then the fragment's depth is written to the depth
* buffer unless writing is disabled here.
*
* By default depth writing is enabled
*
* Since: 1.4
*/
void
cogl_material_set_depth_writing_enabled (CoglHandle handle,
gboolean enable);
/**
* cogl_material_get_depth_writing_enabled:
* @handle: A CoglMaterial handle
* Since: 1.4
*
* Gets the depth writing enable state as set by the corresponding
* cogl_material_set_depth_writing_enabled.
*
* Returns: The current depth writing enable state
* Since: 1.4
*/
gboolean
cogl_material_get_depth_writing_enabled (CoglHandle handle);
/**
* cogl_material_set_depth_test_function:
* @handle: A CoglMaterial handle
* @function: The #CoglDepthTestFunction to set
*
* Sets the #CoglDepthTestFunction used to compare the depth value of
* an incoming fragment against the corresponding value in the current
* depth buffer.
*
* Since: 1.4
*/
void
cogl_material_set_depth_test_function (CoglHandle handle,
CoglDepthTestFunction function);
/**
* cogl_material_get_depth_test_function:
* @handle: A CoglMaterial handle
*
* Gets the current depth test enable state as previously set via
* cogl_material_set_depth_test_enabled().
*
* Returns: The current depth test enable state.
* Since: 1.4
*/
CoglDepthTestFunction
cogl_material_get_depth_test_function (CoglHandle handle);
/**
* cogl_material_set_depth_range:
* @handle: A CoglMaterial handle
* @near: The near component of the desired depth range which will be
* clamped to the range [0, 1]
* @far: The far component of the desired depth range which will be
* clamped to the range [0, 1]
* @error: location to store an error of type #CoglError
*
* Sets the range to map depth values in normalized device coordinates
* to before writing out to a depth buffer.
*
* After your geometry has be transformed, clipped and had perspective
* division applied placing it in normalized device
* coordinates all depth values between the near and far z clipping
* planes are in the range -1 to 1. Before writing any depth value to
* the depth buffer though the value is mapped into the range [0, 1].
*
* With this function you can change the range which depth values are
* mapped too although the range must still lye within the range [0,
* 1].
*
* If your driver does not support this feature (for example you are
* using GLES 1 drivers) then this will return %FALSE and set an error
* if @error isn't NULL. You can check ahead of time for the
* %COGL_FEATURE_DEPTH_RANGE feature with cogl_features_available() to
* know if this function will succeed.
*
* By default normalized device coordinate depth values are mapped to
* the full range of depth buffer values, [0, 1].
*
* Returns: %TRUE if driver support is available else %FALSE.
*
* Since: 1.4
*/
gboolean
cogl_material_set_depth_range (CoglHandle handle,
float near,
float far,
GError **error);
/**
* cogl_material_get_depth_range_mapping:
* @handle: A CoglMaterial handle
* @near: A pointer to store the near component of the depth range
* @far: A pointer to store the far component of the depth range
*
* Gets the current range to which normalized depth values are mapped
* before writing to the depth buffer. This corresponds to the range
* set with cogl_material_set_depth_range().
*
* Since: 1.4
*/
void
cogl_material_get_depth_range (CoglHandle handle,
float *near,
float *far);
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
G_END_DECLS
#endif /* __COGL_MATERIAL_H__ */

View File

@ -233,6 +233,7 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
* @COGL_FEATURE_UNSIGNED_INT_INDICES: Set if
* %COGL_INDICES_TYPE_UNSIGNED_INT is supported in
* cogl_vertex_buffer_indices_new().
* @COGL_FEATURE_DEPTH_RANGE: cogl_material_set_depth_range() support
*
* Flags for the supported features.
*
@ -252,7 +253,8 @@ typedef enum
COGL_FEATURE_STENCIL_BUFFER = (1 << 10),
COGL_FEATURE_VBOS = (1 << 11),
COGL_FEATURE_PBOS = (1 << 12),
COGL_FEATURE_UNSIGNED_INT_INDICES = (1 << 13)
COGL_FEATURE_UNSIGNED_INT_INDICES = (1 << 13),
COGL_FEATURE_DEPTH_RANGE = (1 << 14)
} CoglFeatureFlags;
/**
@ -403,6 +405,27 @@ typedef enum { /*< prefix=COGL_BLEND_STRING_ERROR >*/
GQuark
cogl_blend_string_error_quark (void);
#define COGL_ERROR (_cogl_error_quark ())
/**
* CoglError:
* @COGL_ERROR_MISSING_FEATURE: You tried to use a feature not
* currently available; likely because of missing driver support.
*
* Error enumeration for Cogl
*
* Currently this is only used by Cogl API marked as experimental so
* this enum should also be considered experimental.
*
* Since: 1.4
*/
typedef enum { /*< prefix=COGL_ERROR >*/
COGL_ERROR_MISSING_FEATURE
} CoglError;
GQuark
_cogl_error_quark (void);
G_END_DECLS
#endif /* __COGL_TYPES_H__ */

View File

@ -287,25 +287,28 @@ _cogl_get_enable (void)
return ctx->enable_flags;
}
/* XXX: This API has been deprecated */
void
cogl_set_depth_test_enabled (gboolean setting)
{
/* Currently the journal can't track changes to depth state... */
_cogl_journal_flush ();
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (setting)
{
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
}
if (ctx->legacy_depth_test_enabled == setting)
return;
ctx->legacy_depth_test_enabled = setting;
if (ctx->legacy_depth_test_enabled)
ctx->legacy_state_set++;
else
glDisable (GL_DEPTH_TEST);
ctx->legacy_state_set--;
}
/* XXX: This API has been deprecated */
gboolean
cogl_get_depth_test_enabled (void)
{
return glIsEnabled (GL_DEPTH_TEST) == GL_TRUE ? TRUE : FALSE;
_COGL_GET_CONTEXT (ctx, FALSE);
return ctx->legacy_depth_test_enabled;
}
void
@ -1136,3 +1139,10 @@ _cogl_transform_point (const CoglMatrix *matrix_mv,
#undef VIEWPORT_TRANSFORM_X
#undef VIEWPORT_TRANSFORM_Y
GQuark
_cogl_error_quark (void)
{
return g_quark_from_static_string ("cogl-error-quark");
}

View File

@ -483,6 +483,9 @@ cogl_get_viewport (float v[4]);
* order specified using clutter_actor_raise() and
* clutter_actor_lower(), otherwise it will also take into account the
* actor's depth. Depth testing is disabled by default.
*
* Deprecated: 1.4: Use cogl_material_set_depth_test_enabled()
* instead.
*/
void
cogl_set_depth_test_enabled (gboolean setting);
@ -493,6 +496,9 @@ cogl_set_depth_test_enabled (gboolean setting);
* Queries if depth testing has been enabled via cogl_set_depth_test_enable()
*
* Return value: %TRUE if depth testing is enabled, and %FALSE otherwise
*
* Deprecated: 1.4: Use cogl_material_get_depth_test_enabled()
* instead.
*/
gboolean
cogl_get_depth_test_enabled (void);

View File

@ -31,6 +31,7 @@ test_conformance_SOURCES = \
test-cogl-pixel-buffer.c \
test-cogl-path.c \
test-cogl-object.c \
test-cogl-depth-test.c \
test-path.c \
test-pick.c \
test-clutter-rectangle.c \

View File

@ -0,0 +1,354 @@
#include <clutter/clutter.h>
#ifndef COGL_ENABLE_EXPERIMENTAL_API
#define COGL_ENABLE_EXPERIMENTAL_API
#endif
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
#define QUAD_WIDTH 20
#define RED 0
#define GREEN 1
#define BLUE 2
#define ALPHA 3
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24);
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16);
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8);
#define MASK_ALPHA(COLOR) (COLOR & 0xff);
typedef struct _TestState
{
guint frame;
ClutterGeometry stage_geom;
} TestState;
typedef struct
{
guint32 color;
float depth;
gboolean test_enable;
CoglDepthTestFunction test_function;
gboolean write_enable;
float range_near;
float range_far;
} TestDepthState;
static void
check_pixel (GLubyte *pixel, guint32 color)
{
guint8 r = MASK_RED (color);
guint8 g = MASK_GREEN (color);
guint8 b = MASK_BLUE (color);
guint8 a = MASK_ALPHA (color);
if (g_test_verbose ())
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert_cmpint (pixel[RED], ==, r);
g_assert_cmpint (pixel[GREEN], ==, g);
g_assert_cmpint (pixel[BLUE], ==, b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is
* RGB or RGBA */
/* g_assert (pixel[ALPHA] == a); */
}
static gboolean
draw_rectangle (TestState *state,
int x,
int y,
TestDepthState *rect_state)
{
guint8 Cr = MASK_RED (rect_state->color);
guint8 Cg = MASK_GREEN (rect_state->color);
guint8 Cb = MASK_BLUE (rect_state->color);
guint8 Ca = MASK_ALPHA (rect_state->color);
CoglHandle material;
material = cogl_material_new ();
cogl_material_set_depth_test_enabled (material, rect_state->test_enable);
cogl_material_set_depth_test_function (material, rect_state->test_function);
cogl_material_set_depth_writing_enabled (material, rect_state->write_enable);
if (!cogl_material_set_depth_range (material,
rect_state->range_near,
rect_state->range_far,
NULL))
{
cogl_handle_unref (material);
return FALSE;
}
cogl_material_set_color4ub (material, Cr, Cg, Cb, Ca);
cogl_set_source (material);
cogl_push_matrix ();
cogl_translate (0, 0, rect_state->depth);
cogl_rectangle (x * QUAD_WIDTH,
y * QUAD_WIDTH,
x * QUAD_WIDTH + QUAD_WIDTH,
y * QUAD_WIDTH + QUAD_WIDTH);
cogl_pop_matrix ();
cogl_handle_unref (material);
return TRUE;
}
static void
test_depth (TestState *state,
int x,
int y,
TestDepthState *rect0_state,
TestDepthState *rect1_state,
TestDepthState *rect2_state,
guint32 expected_result)
{
GLubyte pixel[4];
GLint y_off;
GLint x_off;
gboolean missing_feature = FALSE;
if (rect0_state)
missing_feature |= !draw_rectangle (state, x, y, rect0_state);
if (rect1_state)
missing_feature |= !draw_rectangle (state, x, y, rect1_state);
if (rect2_state)
missing_feature |= !draw_rectangle (state, x, y, rect2_state);
/* We don't consider it an error that we can't test something
* the driver doesn't support. */
if (missing_feature)
return;
/* See what we got... */
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
/* XXX:
* We haven't always had good luck with GL drivers implementing glReadPixels
* reliably and skipping the first two frames improves our chances... */
if (state->frame <= 2)
return;
cogl_read_pixels (x_off, y_off, 1, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixel);
check_pixel (pixel, expected_result);
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
int frame_num;
CoglMatrix projection_save;
CoglMatrix identity;
/* We don't want the effects of perspective division to interfere
* with the positions of our test rectangles on the x and y axis
* so we use an orthographic projection...
*/
cogl_get_projection_matrix (&projection_save);
cogl_ortho (0, state->stage_geom.width, /* left, right */
state->stage_geom.height, 0, /* bottom, top */
-1, 100 /* z near, far */);
cogl_push_matrix ();
cogl_matrix_init_identity (&identity);
cogl_set_modelview_matrix (&identity);
/* Sanity check a few of the different depth test functions
* and that depth writing can be disabled... */
{
/* Closest */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* Furthest */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* In the middle */
TestDepthState rect2_state = {
0x0000ffff, /* rgba color */
-20, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_NEVER,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
test_depth (state, 0, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x00ff00ff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_ALWAYS;
test_depth (state, 1, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_LESS;
test_depth (state, 2, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_GREATER;
test_depth (state, 3, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x00ff00ff); /* expected */
rect0_state.test_enable = TRUE;
rect1_state.write_enable = FALSE;
test_depth (state, 4, 0, /* position */
&rect0_state, &rect1_state, &rect2_state,
0x0000ffff); /* expected */
}
/* Check that the depth buffer values can be mapped into different
* ranges... */
{
/* Closest by depth, furthest by depth range */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_ALWAYS,
TRUE, /* depth write enable */
0.5, 1 /* depth range */
};
/* Furthest by depth, nearest by depth range */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
TRUE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_GREATER,
TRUE, /* depth write enable */
0, 0.5 /* depth range */
};
test_depth (state, 0, 1, /* position */
&rect0_state, &rect1_state, NULL,
0xff0000ff); /* expected */
}
/* Test that the legacy cogl_set_depth_test_enabled() API still
* works... */
{
/* Nearest */
TestDepthState rect0_state = {
0xff0000ff, /* rgba color */
-10, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_LESS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
/* Furthest */
TestDepthState rect1_state = {
0x00ff00ff, /* rgba color */
-70, /* depth */
FALSE, /* depth test enable */
COGL_DEPTH_TEST_FUNCTION_LESS,
TRUE, /* depth write enable */
0, 1 /* depth range */
};
cogl_set_depth_test_enabled (TRUE);
test_depth (state, 0, 2, /* position */
&rect0_state, &rect1_state, NULL,
0xff0000ff); /* expected */
cogl_set_depth_test_enabled (FALSE);
test_depth (state, 1, 2, /* position */
&rect0_state, &rect1_state, NULL,
0x00ff00ff); /* expected */
}
cogl_pop_matrix ();
cogl_set_projection_matrix (&projection_save);
/* XXX: Experiments have shown that for some buggy drivers, when using
* glReadPixels there is some kind of race, so we delay our test for a
* few frames and a few seconds: */
frame_num = state->frame++;
if (frame_num < 2)
g_usleep (G_USEC_PER_SEC);
/* Comment this out if you want visual feedback for what this test paints */
#if 1
if (frame_num == 3)
clutter_main_quit ();
#endif
}
static gboolean
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_cogl_depth_test (TestConformSimpleFixture *fixture,
gconstpointer data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
guint idle_source;
state.frame = 0;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_get_geometry (stage, &state.stage_geom);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
}

View File

@ -198,6 +198,7 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_premult);
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_readpixels);
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_path);
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_depth_test);
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_npot_texture);
TEST_CONFORM_SIMPLE ("/cogl/texture", test_cogl_multitexture);