From 426c8b8f41626527bcf764bc275d46ffe8c2e84b Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 12 Oct 2011 22:31:12 +0100 Subject: [PATCH] features: Support more than 32 features! Currently features are represented as bits in a 32bit mask so we obviously can't have more than 32 features with that approach. The new approach is to use the COGL_FLAGS_ macros which lets us handle bitmasks without a size limit and we change the public api to accept individual feature enums instead of a mask. This way there is no limit on the number of features we can add to Cogl. Instead of using cogl_features_available() there is a new cogl_has_feature() function and for checking multiple features there is cogl_has_features() which takes a zero terminated vararg list of features. In addition to being able to check for individual features this also adds a way to query all the features currently available via cogl_foreach_feature() which will call a callback for each feature. Since the new functions take an explicit context pointer there is also no longer any ambiguity over when users can first start to query features. Reviewed-by: Neil Roberts --- cogl/cogl-atlas-texture.c | 2 +- cogl/cogl-buffer.c | 4 +- cogl/cogl-context-private.h | 3 +- cogl/cogl-context.c | 30 +++- cogl/cogl-depth-state.h | 4 +- cogl/cogl-framebuffer.c | 6 +- cogl/cogl-pipeline-fragend-arbfp.c | 2 +- cogl/cogl-pipeline-fragend-glsl.c | 2 +- cogl/cogl-pipeline-layer-state.c | 4 +- cogl/cogl-pipeline-opengl.c | 6 +- cogl/cogl-pipeline-vertend-glsl.c | 2 +- cogl/cogl-shader.c | 2 +- cogl/cogl-texture-2d-sliced.c | 2 +- cogl/cogl-texture-2d.c | 8 +- cogl/cogl-texture-2d.h | 12 +- cogl/cogl-texture-3d.c | 8 +- cogl/cogl-texture-rectangle.c | 2 +- cogl/cogl-texture.c | 2 +- cogl/cogl.c | 32 ++++ cogl/cogl.h | 150 ++++++++++++++++++ cogl/driver/gl/cogl-gl.c | 49 +++++- cogl/driver/gl/cogl-texture-driver-gl.c | 4 +- cogl/driver/gles/cogl-gles.c | 62 ++++++-- cogl/winsys/cogl-winsys-egl.c | 2 + cogl/winsys/cogl-winsys-glx.c | 8 +- cogl/winsys/cogl-winsys-wgl.c | 2 + .../cogl-2.0-experimental-sections.txt | 7 + 27 files changed, 353 insertions(+), 64 deletions(-) diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c index 042cd7b3b..3fc459b7e 100644 --- a/cogl/cogl-atlas-texture.c +++ b/cogl/cogl-atlas-texture.c @@ -657,7 +657,7 @@ _cogl_atlas_texture_new_with_size (unsigned int width, /* If we can't use FBOs then it will be too slow to migrate textures and we shouldn't use the atlas */ - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) return COGL_INVALID_HANDLE; COGL_NOTE (ATLAS, "Adding texture of size %ix%i", width, height); diff --git a/cogl/cogl-buffer.c b/cogl/cogl-buffer.c index 7a6c77aaf..9fff90a55 100644 --- a/cogl/cogl-buffer.c +++ b/cogl/cogl-buffer.c @@ -134,10 +134,10 @@ bo_map (CoglBuffer *buffer, _COGL_GET_CONTEXT (ctx, NULL); if ((access & COGL_BUFFER_ACCESS_READ) && - !cogl_features_available (COGL_FEATURE_MAP_BUFFER_FOR_READ)) + !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) return NULL; if ((access & COGL_BUFFER_ACCESS_WRITE) && - !cogl_features_available (COGL_FEATURE_MAP_BUFFER_FOR_WRITE)) + !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE)) return NULL; target = buffer->last_target; diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 3981f7ba9..3b40b36e1 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -63,7 +63,8 @@ struct _CoglContext const CoglTextureDriver *texture_driver; /* Features cache */ - CoglFeatureFlags feature_flags; + unsigned int features[COGL_FLAGS_N_INTS_FOR_SIZE (_COGL_N_FEATURE_IDS)]; + CoglFeatureFlags feature_flags; /* legacy/deprecated feature flags */ CoglPrivateFeatureFlags private_feature_flags; CoglHandle default_pipeline; diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 452c67534..ebedd4431 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -80,16 +80,31 @@ _cogl_init_feature_overrides (CoglContext *ctx) ctx->private_feature_flags &= ~COGL_PRIVATE_FEATURE_PBOS; if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ARBFP))) - ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP; + { + ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_ARBFP, FALSE); + } if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_GLSL))) - ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL; + { + ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, FALSE); + } if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_NPOT_TEXTURES))) - ctx->feature_flags &= ~(COGL_FEATURE_TEXTURE_NPOT | - COGL_FEATURE_TEXTURE_NPOT_BASIC | - COGL_FEATURE_TEXTURE_NPOT_MIPMAP | - COGL_FEATURE_TEXTURE_NPOT_REPEAT); + { + ctx->feature_flags &= ~(COGL_FEATURE_TEXTURE_NPOT | + COGL_FEATURE_TEXTURE_NPOT_BASIC | + COGL_FEATURE_TEXTURE_NPOT_MIPMAP | + COGL_FEATURE_TEXTURE_NPOT_REPEAT); + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, FALSE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, FALSE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, FALSE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, FALSE); + } } const CoglWinsysVtable * @@ -148,6 +163,7 @@ cogl_context_new (CoglDisplay *display, _context = context; /* Init default values */ + memset (context->features, 0, sizeof (context->features)); context->feature_flags = 0; context->private_feature_flags = 0; @@ -378,7 +394,7 @@ cogl_context_new (CoglDisplay *display, coords enabled. We don't need to do this for GLES2 because point sprites are handled using a builtin varying in the shader. */ if (_context->driver != COGL_DRIVER_GLES2 && - cogl_features_available (COGL_FEATURE_POINT_SPRITE)) + cogl_has_feature (context, COGL_FEATURE_ID_POINT_SPRITE)) GE (context, glEnable (GL_POINT_SPRITE)); return _cogl_context_object_new (context); diff --git a/cogl/cogl-depth-state.h b/cogl/cogl-depth-state.h index 89dcbe666..0fff9a057 100644 --- a/cogl/cogl-depth-state.h +++ b/cogl/cogl-depth-state.h @@ -219,8 +219,8 @@ cogl_depth_state_get_test_function (CoglDepthState *state); * using GLES 1 drivers) then if you don't use the default range * values you will get an error reported when calling * cogl_pipeline_set_depth_state (). You can check ahead of time for - * the %COGL_FEATURE_DEPTH_RANGE feature with - * cogl_features_available() to know if this function will succeed. + * the %COGL_FEATURE_ID_DEPTH_RANGE feature with + * cogl_has_feature() 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]. diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 7f0654864..8c47b593e 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -629,7 +629,7 @@ _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer) #ifdef HAVE_COGL_GL if (ctx->driver == COGL_DRIVER_GL && - cogl_features_available (COGL_FEATURE_OFFSCREEN) && + cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) { GLenum attachment, pname; @@ -701,7 +701,7 @@ _cogl_offscreen_new_to_texture_full (CoglTexture *texture, _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) return COGL_INVALID_HANDLE; /* Make texture is a valid texture object */ @@ -1469,7 +1469,7 @@ bind_gl_framebuffer (CoglContext *ctx, _cogl_framebuffer_get_winsys (framebuffer); winsys->onscreen_bind (COGL_ONSCREEN (framebuffer)); /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) GE (ctx, glBindFramebuffer (target, 0)); } } diff --git a/cogl/cogl-pipeline-fragend-arbfp.c b/cogl/cogl-pipeline-fragend-arbfp.c index 42d18fed2..10bd1bda1 100644 --- a/cogl/cogl-pipeline-fragend-arbfp.c +++ b/cogl/cogl-pipeline-fragend-arbfp.c @@ -171,7 +171,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, /* First validate that we can handle the current state using ARBfp */ - if (!cogl_features_available (COGL_FEATURE_SHADERS_ARBFP)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) return FALSE; /* TODO: support fog */ diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c index bc770955e..472823686 100644 --- a/cogl/cogl-pipeline-fragend-glsl.c +++ b/cogl/cogl-pipeline-fragend-glsl.c @@ -190,7 +190,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, _COGL_GET_CONTEXT (ctx, FALSE); - if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c index c369c6d9a..d87772fef 100644 --- a/cogl/cogl-pipeline-layer-state.c +++ b/cogl/cogl-pipeline-layer-state.c @@ -664,11 +664,13 @@ cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, CoglPipelineLayer *new; CoglPipelineLayer *authority; + _COGL_GET_CONTEXT (ctx, FALSE); + g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); /* Don't allow point sprite coordinates to be enabled if the driver doesn't support it */ - if (enable && !cogl_features_available (COGL_FEATURE_POINT_SPRITE)) + if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_POINT_SPRITE)) { if (error) { diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c index 552fa4961..361364e9b 100644 --- a/cogl/cogl-pipeline-opengl.c +++ b/cogl/cogl-pipeline-opengl.c @@ -687,8 +687,8 @@ get_max_activateable_texture_units (void) defines the number of texture coordinates that can be uploaded (but doesn't necessarily relate to how many texture images can be sampled) */ - if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL) || - cogl_features_available (COGL_FEATURE_SHADERS_ARBFP)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL) || + cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) /* Previously this code subtracted the value by one but there was no explanation for why it did this and it doesn't seem to make sense so it has been removed */ @@ -697,7 +697,7 @@ get_max_activateable_texture_units (void) /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is defined for GLSL but not ARBfp */ - if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL)) GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, values + n_values++)); } diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c index ee1ec1488..a3a460d3a 100644 --- a/cogl/cogl-pipeline-vertend-glsl.c +++ b/cogl/cogl-pipeline-vertend-glsl.c @@ -134,7 +134,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, _COGL_GET_CONTEXT (ctx, FALSE); - if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); diff --git a/cogl/cogl-shader.c b/cogl/cogl-shader.c index 4d662ab37..b94f23d4c 100644 --- a/cogl/cogl-shader.c +++ b/cogl/cogl-shader.c @@ -203,7 +203,7 @@ _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle, } if (ctx->driver == COGL_DRIVER_GLES2 && - cogl_features_available (COGL_FEATURE_TEXTURE_3D)) + cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) { static const char texture_3d_extension[] = "#extension GL_OES_texture_3D : enable\n"; diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c index 8d922ec6a..03a25386b 100644 --- a/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl-texture-2d-sliced.c @@ -702,7 +702,7 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx, int (*slices_for_size) (int, int, int, GArray*); /* Initialize size of largest slice according to supported features */ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT)) { max_width = width; max_height = height; diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index f800fcb49..4697917d5 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -181,7 +181,7 @@ _cogl_texture_2d_can_create (unsigned int width, /* If NPOT textures aren't supported then the size must be a power of two */ - if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT) && (!_cogl_util_is_pot (width) || !_cogl_util_is_pot (height))) return FALSE; @@ -329,7 +329,7 @@ _cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp, /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN) && + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && (data = _cogl_bitmap_map (dst_bmp, COGL_BUFFER_ACCESS_READ, 0))) { @@ -771,7 +771,7 @@ _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) ctx->texture_driver->gl_generate_mipmaps (GL_TEXTURE_2D); #if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL) else @@ -825,7 +825,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex, /* If this touches the first pixel then we'll update our copy */ if (dst_x == 0 && dst_y == 0 && - !cogl_features_available (COGL_FEATURE_OFFSCREEN) && + !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0))) { CoglPixelFormat bpp = diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h index 2a5166458..8e2e7109f 100644 --- a/cogl/cogl-texture-2d.h +++ b/cogl/cogl-texture-2d.h @@ -49,8 +49,8 @@ G_BEGIN_DECLS * * You should be aware that many GPUs only support power of two sizes * for #CoglTexture2D textures. You can check support for non power of - * two textures by checking for the %COGL_FEATURE_TEXTURE_NPOT feature - * via cogl_features_available (). + * two textures by checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature + * via cogl_has_feature(). */ typedef struct _CoglTexture2D CoglTexture2D; @@ -87,8 +87,8 @@ cogl_is_texture_2d (void *object); * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by - * checking for the %COGL_FEATURE_TEXTURE_NPOT feature via - * cogl_features_available (). + * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via + * cogl_has_feature(). * * Returns: A newly allocated #CoglTexture2D, or if the size is not * supported (because it is too large or a non-power-of-two @@ -132,8 +132,8 @@ cogl_texture_2d_new_with_size (CoglContext *ctx, * * Many GPUs only support power of two sizes for #CoglTexture2D * textures. You can check support for non power of two textures by - * checking for the %COGL_FEATURE_TEXTURE_NPOT feature via - * cogl_features_available (). + * checking for the %COGL_FEATURE_ID_TEXTURE_NPOT feature via + * cogl_has_feature(). * * Returns: A newly allocated #CoglTexture2D, or if the size is not * supported (because it is too large or a non-power-of-two diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c index a64c3d2ad..58adee602 100644 --- a/cogl/cogl-texture-3d.c +++ b/cogl/cogl-texture-3d.c @@ -219,7 +219,7 @@ _cogl_texture_3d_can_create (unsigned int width, _COGL_GET_CONTEXT (ctx, FALSE); /* This should only happen on GLES */ - if (!cogl_features_available (COGL_FEATURE_TEXTURE_3D)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) { g_set_error (error, COGL_ERROR, @@ -230,7 +230,7 @@ _cogl_texture_3d_can_create (unsigned int width, /* If NPOT textures aren't supported then the size must be a power of two */ - if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT) && (!_cogl_util_is_pot (width) || !_cogl_util_is_pot (height) || !_cogl_util_is_pot (depth))) @@ -357,7 +357,7 @@ _cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp, /* Keep a copy of the first pixel so that if glGenerateMipmap isn't supported we can fallback to using GL_GENERATE_MIPMAP */ - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN) && + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) && (data = _cogl_bitmap_map (dst_bmp, COGL_BUFFER_ACCESS_READ, 0))) { @@ -578,7 +578,7 @@ _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) /* glGenerateMipmap is defined in the FBO extension. If it's not available we'll fallback to temporarily enabling GL_GENERATE_MIPMAP and reuploading the first pixel */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) ctx->texture_driver->gl_generate_mipmaps (GL_TEXTURE_3D); #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) else if (ctx->driver != COGL_DRIVER_GLES2) diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c index ca12fcb0c..558def692 100644 --- a/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl-texture-rectangle.c @@ -198,7 +198,7 @@ _cogl_texture_rectangle_can_create (unsigned int width, _COGL_GET_CONTEXT (ctx, FALSE); - if (!cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) return FALSE; ctx->texture_driver->pixel_format_to_gl (internal_format, diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 7bf0d6441..b2e0a409f 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -1121,7 +1121,7 @@ get_texture_bits_via_offscreen (CoglTexture *texture, _COGL_GET_CONTEXT (ctx, FALSE); - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN)) return FALSE; framebuffer = _cogl_offscreen_new_to_texture_full diff --git a/cogl/cogl.c b/cogl/cogl.c index e81caa7e5..bee8170d5 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -319,6 +319,38 @@ cogl_features_available (CoglFeatureFlags features) return (ctx->feature_flags & features) == features; } +gboolean +cogl_has_feature (CoglContext *ctx, CoglFeatureID feature) +{ + return COGL_FLAGS_GET (ctx->features, feature); +} + +gboolean +cogl_has_features (CoglContext *ctx, ...) +{ + va_list args; + CoglFeatureID feature; + + va_start (args, ctx); + while ((feature = va_arg (args, CoglFeatureID))) + if (!cogl_has_feature (ctx, feature)) + return FALSE; + va_end (args); + + return TRUE; +} + +void +cogl_foreach_feature (CoglContext *ctx, + CoglFeatureCallback callback, + void *user_data) +{ + int i; + for (i = 0; i < _COGL_N_FEATURE_IDS; i++) + if (COGL_FLAGS_GET (ctx->features, i)) + callback (i, user_data); +} + /* XXX: This function should either be replaced with one returning * integers, or removed/deprecated and make the * _cogl_framebuffer_get_viewport* functions public. diff --git a/cogl/cogl.h b/cogl/cogl.h index 08f440261..1f738a7c2 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -157,6 +157,156 @@ cogl_get_features (void); gboolean cogl_features_available (CoglFeatureFlags features); +/* XXX: not guarded by the EXPERIMENTAL_2_0_API defines to avoid + * upsetting glib-mkenums, but this can still be considered implicitly + * experimental since it's only useable with experimental API... */ +/** + * CoglFeatureID: + * @COGL_FEATURE_ID_TEXTURE_NPOT_BASIC: The hardware supports non power + * of two textures, but you also need to check the + * %COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP and %COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT + * features to know if the hardware supports npot texture mipmaps + * or repeat modes other than + * %COGL_RENDERER_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE respectively. + * @COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP: Mipmapping is supported in + * conjuntion with non power of two textures. + * @COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT: Repeat modes other than + * %COGL_RENDERER_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE are supported by the + * hardware. + * @COGL_FEATURE_ID_TEXTURE_NPOT: Non power of two textures are supported + * by the hardware. This is a equivalent to the + * %COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, %COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP + * and %COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT features combined. + * @COGL_FEATURE_ID_TEXTURE_RECTANGLE: Support for rectangular + * textures with non-normalized texture coordinates. + * @COGL_FEATURE_ID_TEXTURE_3D: 3D texture support + * @COGL_FEATURE_ID_OFFSCREEN: Offscreen rendering support + * @COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE: Multisample support for + * offscreen framebuffers + * @COGL_FEATURE_ID_ONSCREEN_MULTIPLE: Multiple onscreen framebuffers + * supported. + * @COGL_FEATURE_ID_GLSL: GLSL support + * @COGL_FEATURE_ID_ARBFP: ARBFP support + * @COGL_FEATURE_ID_UNSIGNED_INT_INDICES: Set if + * %COGL_RENDERER_INDICES_TYPE_UNSIGNED_INT is supported in + * cogl_indices_new(). + * @COGL_FEATURE_ID_DEPTH_RANGE: cogl_pipeline_set_depth_range() support + * @COGL_FEATURE_ID_POINT_SPRITE: Whether + * cogl_pipeline_set_layer_point_sprite_coords_enabled() is supported. + * @COGL_FEATURE_ID_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is + * supported with CoglBufferAccess including read support. + * @COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is + * supported with CoglBufferAccess including write support. + * + * + * All the capabilities that can vary between different GPUs supported + * by Cogl. Applications that depend on any of these features should explicitly + * check for them using cogl_has_feature() or cogl_has_features(). + * + * Since: 1.10 + */ +typedef enum _CoglFeatureID +{ + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC = 1, + COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, + COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, + COGL_FEATURE_ID_TEXTURE_NPOT, + COGL_FEATURE_ID_TEXTURE_RECTANGLE, + COGL_FEATURE_ID_TEXTURE_3D, + COGL_FEATURE_ID_GLSL, + COGL_FEATURE_ID_ARBFP, + COGL_FEATURE_ID_OFFSCREEN, + COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, + COGL_FEATURE_ID_ONSCREEN_MULTIPLE, + COGL_FEATURE_ID_UNSIGNED_INT_INDICES, + COGL_FEATURE_ID_DEPTH_RANGE, + COGL_FEATURE_ID_POINT_SPRITE, + COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, + COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, + + /*< private > */ + _COGL_N_FEATURE_IDS +} CoglFeatureID; + + +#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API + +#define cogl_has_feature cogl_has_feature_EXP +/** + * cogl_has_feature: + * @context: A #CoglContext pointer + * @feature: A #CoglFeatureID + * + * Checks if a given @feature is currently available + * + * Cogl does not aim to be a lowest common denominator API, it aims to + * expose all the interesting features of GPUs to application which + * means applications have some responsibility to explicitly check + * that certain features are available before depending on them. + * + * Returns: %TRUE if the @feature is currently supported or %FALSE if + * not. + * + * Since: 1.10 + * Stability: unstable + */ +gboolean +cogl_has_feature (CoglContext *context, CoglFeatureID feature); + +#define cogl_has_features cogl_has_features_EXP +/** + * cogl_has_features: + * @context: A #CoglContext pointer + * @...: A 0 terminated list of CoglFeatureIDs + * + * Checks if a list of features are all currently available. + * + * This checks all of the listed features using cogl_has_feature() and + * returns %TRUE if all the features are available or %FALSE + * otherwise. + * + * Return value: %TRUE if all the features are available, %FALSE + * otherwise. + * + * Since: 1.10 + * Stability: unstable + */ +gboolean +cogl_has_features (CoglContext *context, ...); + +/** + * CoglFeatureCallback: + * @feature: A single feature currently supported by Cogl + * @user_data: A private pointer passed to cogl_foreach_feature(). + * + * A callback used with cogl_foreach_feature() for enumerating all + * context level features supported by Cogl. + * + * Since: 1.10 + * Stability: unstable + */ +typedef void (*CoglFeatureCallback) (CoglFeatureID feature, void *user_data); + +#define cogl_foreach_feature cogl_foreach_feature_EXP +/** + * cogl_foreach_feature: + * @context: A #CoglContext pointer + * @callback: A #CoglFeatureCallback called for each supported feature + * @user_data: Private data to pass to the callback + * + * Iterates through all the context level features currently supported + * for a given @context and for each feature @callback is called. + * + * Since: 1.10 + * Stability: unstable + */ +void +cogl_foreach_feature (CoglContext *context, + CoglFeatureCallback callback, + void *user_data); + +#endif /* COGL_ENABLE_EXPERIMENTAL_2_0_API */ + /** * cogl_get_proc_address: * @name: the name of the function. diff --git a/cogl/driver/gl/cogl-gl.c b/cogl/driver/gl/cogl-gl.c index 609e21d0b..22d16b6e9 100644 --- a/cogl/driver/gl/cogl-gl.c +++ b/cogl/driver/gl/cogl-gl.c @@ -160,6 +160,9 @@ _cogl_gl_update_features (CoglContext *context, flags = (COGL_FEATURE_TEXTURE_READ_PIXELS | COGL_FEATURE_UNSIGNED_INT_INDICES | COGL_FEATURE_DEPTH_RANGE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE); gl_extensions = (const char *)ctx->glGetString (GL_EXTENSIONS); @@ -175,6 +178,13 @@ _cogl_gl_update_features (CoglContext *context, | COGL_FEATURE_TEXTURE_NPOT_BASIC | COGL_FEATURE_TEXTURE_NPOT_MIPMAP | COGL_FEATURE_TEXTURE_NPOT_REPEAT; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, TRUE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE); } if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions)) @@ -190,13 +200,20 @@ _cogl_gl_update_features (CoglContext *context, private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES; if (context->glGenRenderbuffers) - flags |= COGL_FEATURE_OFFSCREEN; + { + flags |= COGL_FEATURE_OFFSCREEN; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); + } if (context->glBlitFramebuffer) private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT; if (context->glRenderbufferStorageMultisampleIMG) + { flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE; + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, TRUE); + } if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 1) || _cogl_check_extension ("GL_EXT_pixel_buffer_object", gl_extensions)) @@ -204,26 +221,46 @@ _cogl_gl_update_features (CoglContext *context, if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) || _cogl_check_extension ("GL_ARB_point_sprite", gl_extensions)) - flags |= COGL_FEATURE_POINT_SPRITE; + { + flags |= COGL_FEATURE_POINT_SPRITE; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE); + } if (context->glGenPrograms) - flags |= COGL_FEATURE_SHADERS_ARBFP; + { + flags |= COGL_FEATURE_SHADERS_ARBFP; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_ARBFP, TRUE); + } if (context->glCreateProgram) - flags |= COGL_FEATURE_SHADERS_GLSL; + { + flags |= COGL_FEATURE_SHADERS_GLSL; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE); + } if (context->glGenBuffers) { private_flags |= COGL_PRIVATE_FEATURE_VBOS; flags |= (COGL_FEATURE_MAP_BUFFER_FOR_READ | COGL_FEATURE_MAP_BUFFER_FOR_WRITE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE); + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); } if (_cogl_check_extension ("GL_ARB_texture_rectangle", gl_extensions)) - flags |= COGL_FEATURE_TEXTURE_RECTANGLE; + { + flags |= COGL_FEATURE_TEXTURE_RECTANGLE; + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_RECTANGLE, TRUE); + } if (context->glTexImage3D) - flags |= COGL_FEATURE_TEXTURE_3D; + { + flags |= COGL_FEATURE_TEXTURE_3D; + COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE); + } if (context->glEGLImageTargetTexture2D) private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE; diff --git a/cogl/driver/gl/cogl-texture-driver-gl.c b/cogl/driver/gl/cogl-texture-driver-gl.c index f68a95d59..6ab1b3e3b 100644 --- a/cogl/driver/gl/cogl-texture-driver-gl.c +++ b/cogl/driver/gl/cogl-texture-driver-gl.c @@ -101,7 +101,7 @@ prep_gl_for_pixels_upload_full (int pixels_rowstride, GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); - if (cogl_features_available (COGL_FEATURE_TEXTURE_3D)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) GE( ctx, glPixelStorei (GL_UNPACK_IMAGE_HEIGHT, image_height) ); _cogl_texture_prep_gl_alignment_for_pixels_upload (pixels_rowstride); @@ -130,7 +130,7 @@ prep_gl_for_pixels_download_full (int pixels_rowstride, GE( ctx, glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); GE( ctx, glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); - if (cogl_features_available (COGL_FEATURE_TEXTURE_3D)) + if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D)) GE( ctx, glPixelStorei (GL_PACK_IMAGE_HEIGHT, image_height) ); _cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride); diff --git a/cogl/driver/gles/cogl-gles.c b/cogl/driver/gles/cogl-gles.c index 9b2f331da..988a34e10 100644 --- a/cogl/driver/gles/cogl-gles.c +++ b/cogl/driver/gles/cogl-gles.c @@ -89,36 +89,74 @@ _cogl_gles_update_features (CoglContext *context, * repeat modes other than CLAMP_TO_EDGE. */ flags |= COGL_FEATURE_TEXTURE_NPOT_BASIC; flags |= COGL_FEATURE_DEPTH_RANGE; + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLSL, TRUE); + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE); } private_flags |= COGL_PRIVATE_FEATURE_VBOS; /* Both GLES 1.1 and GLES 2.0 support point sprites in core */ flags |= COGL_FEATURE_POINT_SPRITE; + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE); if (context->glGenRenderbuffers) - flags |= COGL_FEATURE_OFFSCREEN; + { + flags |= COGL_FEATURE_OFFSCREEN; + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE); + } if (context->glBlitFramebuffer) private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT; if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions)) - flags |= COGL_FEATURE_UNSIGNED_INT_INDICES; + { + flags |= COGL_FEATURE_UNSIGNED_INT_INDICES; + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); + } - if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions) || - _cogl_check_extension ("GL_IMG_texture_npot", gl_extensions)) - flags |= (COGL_FEATURE_TEXTURE_NPOT | - COGL_FEATURE_TEXTURE_NPOT_BASIC | - COGL_FEATURE_TEXTURE_NPOT_MIPMAP | - COGL_FEATURE_TEXTURE_NPOT_REPEAT); + if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions)) + { + flags |= (COGL_FEATURE_TEXTURE_NPOT | + COGL_FEATURE_TEXTURE_NPOT_BASIC | + COGL_FEATURE_TEXTURE_NPOT_MIPMAP | + COGL_FEATURE_TEXTURE_NPOT_REPEAT); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT, TRUE); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE); + } + else if (_cogl_check_extension ("GL_IMG_texture_npot", gl_extensions)) + { + flags |= (COGL_FEATURE_TEXTURE_NPOT_BASIC | + COGL_FEATURE_TEXTURE_NPOT_MIPMAP); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE); + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE); + } if (context->glTexImage3D) - flags |= COGL_FEATURE_TEXTURE_3D; + { + flags |= COGL_FEATURE_TEXTURE_3D; + COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE); + } if (context->glMapBuffer) - /* The GL_OES_mapbuffer extension doesn't support mapping for - read */ - flags |= COGL_FEATURE_MAP_BUFFER_FOR_WRITE; + { + /* The GL_OES_mapbuffer extension doesn't support mapping for + read */ + flags |= COGL_FEATURE_MAP_BUFFER_FOR_WRITE; + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); + } if (context->glEGLImageTargetTexture2D) private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE; diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c index 5a9c93740..dfefbcd44 100644 --- a/cogl/winsys/cogl-winsys-egl.c +++ b/cogl/winsys/cogl-winsys-egl.c @@ -533,6 +533,8 @@ update_winsys_features (CoglContext *context, GError **error) #if defined (COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT) || \ defined (COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT) context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c index 8b645be59..86be11dda 100644 --- a/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/winsys/cogl-winsys-glx.c @@ -395,6 +395,8 @@ update_winsys_features (CoglContext *context, GError **error) COGL_NOTE (WINSYS, " GLX Extensions: %s", glx_extensions); context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); @@ -1604,7 +1606,7 @@ get_fbconfig_for_depth (CoglContext *context, stencil = value; /* glGenerateMipmap is defined in the offscreen extension */ - if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + if (cogl_has_feature (context, COGL_FEATURE_ID_OFFSCREEN)) { glx_renderer->glXGetFBConfigAttrib (dpy, fbconfigs[i], @@ -1639,7 +1641,7 @@ should_use_rectangle (CoglContext *context) if (context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_UNKNOWN) { - if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE)) + if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RECTANGLE)) { const char *rect_env; @@ -1654,7 +1656,7 @@ should_use_rectangle (CoglContext *context) are not available */ context->rectangle_state = - cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) ? + cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_NPOT) ? COGL_WINSYS_RECTANGLE_STATE_DISABLE : COGL_WINSYS_RECTANGLE_STATE_ENABLE; diff --git a/cogl/winsys/cogl-winsys-wgl.c b/cogl/winsys/cogl-winsys-wgl.c index 3124bcd9c..a90ab996d 100644 --- a/cogl/winsys/cogl-winsys-wgl.c +++ b/cogl/winsys/cogl-winsys-wgl.c @@ -592,6 +592,8 @@ update_winsys_features (CoglContext *context, GError **error) memset (context->winsys_features, 0, sizeof (context->winsys_features)); context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE; + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE); COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, TRUE); diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index c3a9679f6..d97ddcca5 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -76,6 +76,13 @@ cogl_wayland_display_set_compositor_display cogl_context_new cogl_context_get_display + +CoglFeatureID +cogl_has_feature +cogl_has_features +CoglFeatureCallback +cogl_foreach_feature + cogl_push_matrix cogl_pop_matrix