diff --git a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m index 595ddc6fc7..3adb0cd6be 100644 --- a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m +++ b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m @@ -39,6 +39,7 @@ static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstG static GstGLAPI gst_gl_context_cocoa_get_gl_api (GstGLContext * context); static GstGLPlatform gst_gl_context_cocoa_get_gl_platform (GstGLContext * context); static void gst_gl_context_cocoa_swap_buffers (GstGLContext * context); +static GstStructure * gst_gl_context_cocoa_get_config (GstGLContext * context); GST_DEBUG_CATEGORY_STATIC (gst_gl_context_cocoa_debug); #define GST_CAT_DEFAULT gst_gl_context_cocoa_debug @@ -66,6 +67,8 @@ static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstG GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_api); context_class->get_gl_platform = GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_platform); + context_class->get_config = + GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_config); } static void @@ -170,6 +173,57 @@ static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstG return context->priv->pixel_format; } +static GstStructure * +cgl_pixel_format_to_structure (CGLPixelFormatObj fmt) +{ + GstStructure *ret; + int val, alpha; + + ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME, + GST_GL_CONFIG_STRUCTURE_SET_ARGS(PLATFORM, GstGLPlatform, GST_GL_PLATFORM_CGL), + NULL); + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFAAlphaSize, &alpha) != kCGLNoError) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, alpha), NULL); + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFADepthSize, &val) != kCGLNoError) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(DEPTH_SIZE, int, val), NULL); + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFAStencilSize, &val) != kCGLNoError) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(STENCIL_SIZE, int, val), NULL); + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFAColorSize, &val) != kCGLNoError) + goto failure; + val -= alpha; + if (val % 3 == 0) { + /* XXX: assumes that bits are evenly distributed */ + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, val / 3), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, val / 3), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, val / 3), NULL); + } else { + GST_WARNING ("Don't know how to split a color size of %u into R,G,B values", + val); + goto failure; + } + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFASamples, &val) != kCGLNoError) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(SAMPLES, int, val), NULL); + + if (CGLDescribePixelFormat (fmt, 0, kCGLPFASampleBuffers, &val) != kCGLNoError) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(SAMPLE_BUFFERS, int, val), NULL); + + return ret; + +failure: + gst_structure_free (ret); + return NULL; +} + static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, GstGLContext *other_context, GError **error) @@ -338,3 +392,13 @@ static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstG { return (guintptr) CGLGetCurrentContext (); } + +static GstStructure * +gst_gl_context_cocoa_get_config (GstGLContext * context) +{ + GstGLContextCocoa *cocoa = GST_GL_CONTEXT_COCOA (context); + + g_return_val_if_fail (cocoa->priv->pixel_format, NULL); + + return cgl_pixel_format_to_structure (cocoa->priv->pixel_format); +} diff --git a/gst-libs/gst/gl/eagl/gstglcontext_eagl.m b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m index fe9bba97aa..b869030ac5 100644 --- a/gst-libs/gst/gl/eagl/gstglcontext_eagl.m +++ b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m @@ -50,6 +50,7 @@ static gboolean gst_gl_context_eagl_activate (GstGLContext * context, static GstGLAPI gst_gl_context_eagl_get_gl_api (GstGLContext * context); static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * context); +GstStructure *gst_gl_context_eagl_get_config (GstGLContext * context); struct _GstGLContextEaglPrivate { @@ -87,6 +88,7 @@ static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_api); context_class->get_gl_platform = GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_platform); + context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_config); } static void @@ -108,6 +110,71 @@ static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * return context; } +enum EAGLFormat +{ + FORMAT_RGBA8 = 1, + FORMAT_RGB565, +}; + +static GstStructure * +layer_config_to_structure (GstGLContextEagl *eagl, CAEAGLLayer * layer) +{ + GstStructure *ret; + NSDictionary *drawableProps = [layer drawableProperties]; + NSString *color_format; + enum EAGLFormat eagl_format = FORMAT_RGBA8; + + ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME, + GST_GL_CONFIG_STRUCTURE_SET_ARGS(PLATFORM, GstGLPlatform, GST_GL_PLATFORM_EAGL), + NULL); + + color_format = [drawableProps objectForKey:kEAGLDrawablePropertyColorFormat]; + if (!color_format) + color_format = [layer contentsFormat]; + + if (!color_format) { + GST_WARNING_OBJECT (eagl, "Could not retrieve color format from layer %p", layer); + goto failure; + } + + if (color_format == kEAGLColorFormatRGBA8 || color_format == kCAContentsFormatRGBA8Uint) { + eagl_format = FORMAT_RGBA8; + } else if (color_format == kEAGLColorFormatRGB565) { + eagl_format = FORMAT_RGB565; + } else { + GST_WARNING_OBJECT (eagl, "unknown drawable format: %s", [color_format UTF8String]); + goto failure; + } + + /* XXX: defaults chosen by _update_layer() */ + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(DEPTH_SIZE, int, 16), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(STENCIL_SIZE, int, 0), NULL); + + switch (eagl_format) { + case FORMAT_RGBA8: + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, 8), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, 8), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, 8), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, 8), NULL); + break; + case FORMAT_RGB565: + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, 5), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, 6), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, 5), NULL); + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, 0), NULL); + break; + default: + GST_WARNING_OBJECT (eagl, "Unhandled format!"); + goto failure; + } + + return ret; + +failure: + gst_structure_free (ret); + return NULL; +} + void gst_gl_context_eagl_resize (GstGLContextEagl * eagl_context) { @@ -167,6 +234,7 @@ static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * GstGLContextEagl *context_eagl = GST_GL_CONTEXT_EAGL (context); GstGLContextEaglPrivate *priv = context_eagl->priv; GstGLWindow *window = gst_gl_context_get_window (context); + GstStructure *fmt; if (!layer || !gst_gl_window_get_window_handle (window)) { GST_INFO_OBJECT (context, "window handle not set yet, not updating layer"); @@ -215,6 +283,12 @@ static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * priv->color_renderbuffer = color_renderbuffer; priv->depth_renderbuffer = depth_renderbuffer; + fmt = layer_config_to_structure (context_eagl, eagl_layer); + if (fmt) { + GST_DEBUG_OBJECT (context_eagl, "chosen config %" GST_PTR_FORMAT, fmt); + gst_structure_free (fmt); + } + out: if (window) gst_object_unref (window); @@ -384,3 +458,14 @@ static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext * { return (guintptr) [EAGLContext currentContext]; } + +GstStructure * +gst_gl_context_eagl_get_config (GstGLContext * context) +{ + GstGLContextEagl *eagl = GST_GL_CONTEXT_EAGL (context); + + if (!eagl->priv->eagl_layer) + return NULL; + + return layer_config_to_structure (eagl, (__bridge CAEAGLLayer *) eagl->priv->eagl_layer); +} diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index 147b7e9b0d..1254fdd09b 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -30,9 +30,8 @@ #include "gstglcontext_egl.h" +#include #include -#include -#include #include "gstegl.h" #include "../utils/opengl_versions.h" @@ -74,6 +73,9 @@ static gboolean gst_gl_context_egl_check_feature (GstGLContext * context, const gchar * feature); static void gst_gl_context_egl_get_gl_platform_version (GstGLContext * context, gint * major, gint * minor); +static GstStructure *gst_gl_context_egl_get_config (GstGLContext * context); +static gboolean gst_gl_context_egl_request_config (GstGLContext * context, + GstStructure * config); G_DEFINE_TYPE (GstGLContextEGL, gst_gl_context_egl, GST_TYPE_GL_CONTEXT); @@ -105,6 +107,9 @@ gst_gl_context_egl_class_init (GstGLContextEGLClass * klass) GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_current_context); context_class->get_gl_platform_version = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform_version); + context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_config); + context_class->request_config = + GST_DEBUG_FUNCPTR (gst_gl_context_egl_request_config); } static void @@ -152,6 +157,226 @@ gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error) return TRUE; } +static GstGLAPI +egl_conformant_to_gst (int conformant) +{ + GstGLAPI ret = GST_GL_API_NONE; + + if (conformant & EGL_OPENGL_BIT) + ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3; + if (conformant & EGL_OPENGL_ES_BIT) + ret |= GST_GL_API_GLES1; + if (conformant & EGL_OPENGL_ES2_BIT) + ret |= GST_GL_API_GLES2; +#if defined(EGL_KHR_create_context) + if (conformant & EGL_OPENGL_ES3_BIT_KHR) + /* FIXME: need another gles3 value? */ + ret |= GST_GL_API_GLES2; +#endif +#if 0 + if (conformant & EGL_OPENVG_BIT) + conformant_values[i++] = "OpenVG"; +#endif + + return ret; +} + +static GstGLConfigSurfaceType +egl_surface_type_to_gst (int surface) +{ + GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE; + + if (surface & EGL_WINDOW_BIT) + ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW; + if (surface & EGL_PBUFFER_BIT) + ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER; +#if 0 + if (surface & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) + surface_values[i++] = "multisample-resolve-box"; + if (surface & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) + surface_values[i++] = "swap-behaviour-preserved"; + if (surface & EGL_VG_ALPHA_FORMAT_PRE_BIT) + surface_values[i++] = "vg-alpha-format-pre"; + if (surface & EGL_VG_COLORSPACE_LINEAR_BIT) + surface_values[i++] = "vg-colorspace-linear"; +#endif + return ret; +} + +static GstGLConfigCaveat +egl_caveat_to_gst (int caveat) +{ + switch (caveat) { + case EGL_NONE: + return GST_GL_CONFIG_CAVEAT_NONE; + case EGL_SLOW_CONFIG: + return GST_GL_CONFIG_CAVEAT_SLOW; + case EGL_NON_CONFORMANT_CONFIG: + return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT; + default: + GST_WARNING ("unknown EGL caveat value %u (0x%x)", caveat, caveat); + return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT; + } +} + +static GstStructure * +egl_config_to_structure (EGLDisplay egl_display, EGLConfig config) +{ + GstStructure *ret; + int val; + int buffer_type; + + if (!egl_display) + return NULL; + + ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME, + GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform, + GST_GL_PLATFORM_EGL), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_ID, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int, + val), NULL); + +#if 0 + { + /* Don't know how to translate this value, it's platform and implementation + * dependant + */ + int native_visual_type; + if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_TYPE, + &native_visual_type)) + goto failure; + } +#endif + + if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_ID, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID, + guint, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_RENDERABLE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE, + gboolean, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_CONFORMANT, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFORMANT_API, + GstGLAPI, egl_conformant_to_gst (val)), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_RENDERABLE_TYPE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RENDERABLE_API, + GstGLAPI, egl_conformant_to_gst (val)), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_SURFACE_TYPE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE, + GstGLConfigSurfaceType, egl_surface_type_to_gst (val)), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_CAVEAT, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT, + GstGLConfigCaveat, egl_caveat_to_gst (val)), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_LEVEL, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val), + NULL); + + + if (!eglGetConfigAttrib (egl_display, config, EGL_COLOR_BUFFER_TYPE, + &buffer_type)) + goto failure; + + if (buffer_type == EGL_RGB_BUFFER) { + if (!eglGetConfigAttrib (egl_display, config, EGL_RED_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_GREEN_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_BLUE_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int, + val), NULL); + } else if (buffer_type == EGL_LUMINANCE_BUFFER) { + if (!eglGetConfigAttrib (egl_display, config, EGL_LUMINANCE_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LUMINANCE_SIZE, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int, + val), NULL); + } else { + GST_WARNING ("unknown EGL_COLOR_BUFFER_TYPE value %x", buffer_type); + goto failure; + } + + if (!eglGetConfigAttrib (egl_display, config, EGL_DEPTH_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_STENCIL_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_MIN_SWAP_INTERVAL, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MIN_SWAP_INTERVAL, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_SWAP_INTERVAL, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_SWAP_INTERVAL, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_WIDTH, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_HEIGHT, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_PIXELS, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS, + int, val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLE_BUFFERS, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLE_BUFFERS, int, + val), NULL); + + if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLES, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLES, int, val), + NULL); + + return ret; + +failure: + gst_structure_free (ret); + return NULL; +} + static void gst_gl_context_egl_dump_config (GstGLContextEGL * egl, EGLConfig config) { @@ -405,7 +630,7 @@ gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api, { gboolean create_context; EGLint numConfigs; - gint i; + gint i, n; EGLint config_attrib[20]; EGLint egl_api = 0; EGLBoolean ret = EGL_FALSE; @@ -446,25 +671,57 @@ gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api, try_again: i = 0; + n = G_N_ELEMENTS (config_attrib); config_attrib[i++] = EGL_SURFACE_TYPE; config_attrib[i++] = surface_type; config_attrib[i++] = EGL_RENDERABLE_TYPE; config_attrib[i++] = egl_api; + + if (egl->requested_config) { +#define TRANSFORM_VALUE(GL_CONF_NAME,EGL_ATTR_NAME) \ + G_STMT_START { \ + if (gst_structure_has_field_typed (egl->requested_config, \ + GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \ + GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \ + int val; \ + if (gst_structure_get (egl->requested_config, \ + GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \ + GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \ + config_attrib[i++] = EGL_ATTR_NAME; \ + config_attrib[i++] = (int) val; \ + g_assert (i <= n); \ + } \ + } \ + } G_STMT_END + + TRANSFORM_VALUE (CONFIG_ID, EGL_CONFIG_ID); + TRANSFORM_VALUE (RED_SIZE, EGL_RED_SIZE); + TRANSFORM_VALUE (GREEN_SIZE, EGL_GREEN_SIZE); + TRANSFORM_VALUE (BLUE_SIZE, EGL_BLUE_SIZE); + TRANSFORM_VALUE (ALPHA_SIZE, EGL_ALPHA_SIZE); + TRANSFORM_VALUE (DEPTH_SIZE, EGL_DEPTH_SIZE); + TRANSFORM_VALUE (STENCIL_SIZE, EGL_STENCIL_SIZE); + /* TODO: more values */ +#undef TRANSFORM_VALUE + } else { #if defined(USE_EGL_RPI) && GST_GL_HAVE_WINDOW_WAYLAND - /* The configurations with a=0 seems to be buggy whereas - * it works when using dispmanx directly */ - config_attrib[i++] = EGL_ALPHA_SIZE; - config_attrib[i++] = 1; + /* The configurations with a=0 seems to be buggy whereas + * it works when using dispmanx directly */ + config_attrib[i++] = EGL_ALPHA_SIZE; + config_attrib[i++] = 1; #endif - config_attrib[i++] = EGL_DEPTH_SIZE; - config_attrib[i++] = 16; - config_attrib[i++] = EGL_RED_SIZE; - config_attrib[i++] = 1; - config_attrib[i++] = EGL_GREEN_SIZE; - config_attrib[i++] = 1; - config_attrib[i++] = EGL_BLUE_SIZE; - config_attrib[i++] = 1; + config_attrib[i++] = EGL_DEPTH_SIZE; + config_attrib[i++] = 16; + config_attrib[i++] = EGL_RED_SIZE; + config_attrib[i++] = 1; + config_attrib[i++] = EGL_GREEN_SIZE; + config_attrib[i++] = 1; + config_attrib[i++] = EGL_BLUE_SIZE; + config_attrib[i++] = 1; + } + config_attrib[i++] = EGL_NONE; + g_assert (i <= n); ret = eglChooseConfig (egl->egl_display, config_attrib, &egl->egl_config, 1, &numConfigs); @@ -921,6 +1178,10 @@ gst_gl_context_egl_destroy_context (GstGLContext * context) gst_object_unref (egl->display_egl); egl->display_egl = NULL; } + + if (egl->requested_config) + gst_structure_free (egl->requested_config); + egl->requested_config = NULL; } static gboolean @@ -1117,3 +1378,87 @@ gst_gl_context_egl_get_gl_platform_version (GstGLContext * context, *major = context_egl->egl_major; *minor = context_egl->egl_minor; } + +static GstStructure * +gst_gl_context_egl_get_config (GstGLContext * context) +{ + GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context); + + g_return_val_if_fail (egl->egl_config, NULL); + + return egl_config_to_structure (egl->egl_display, egl->egl_config); +} + +static gboolean +gst_gl_context_egl_request_config (GstGLContext * context, + GstStructure * config) +{ + GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context); + + if (egl->requested_config) + gst_structure_free (egl->requested_config); + egl->requested_config = config; + + return TRUE; +} + +gboolean +gst_gl_context_egl_fill_info (GstGLContext * context) +{ + EGLContext egl_context = (EGLContext) gst_gl_context_get_gl_context (context); + GstGLDisplay *display_egl; + GstStructure *config; + EGLDisplay *egl_display; + EGLConfig egl_config; + int config_id, n_configs; + int attrs[3]; + + if (!egl_context) { + GST_ERROR_OBJECT (context, "no GLX context"); + return FALSE; + } + + display_egl = + GST_GL_DISPLAY (gst_gl_display_egl_from_gl_display (context->display)); + egl_display = (EGLDisplay) gst_gl_display_get_handle (display_egl); + + if (EGL_TRUE != eglQueryContext (egl_display, egl_context, EGL_CONFIG_ID, + &config_id)) { + GST_WARNING_OBJECT (context, + "could not retrieve egl config id from egl context: %s", + gst_egl_get_error_string (eglGetError ())); + goto failure; + } + + attrs[0] = EGL_CONFIG_ID; + attrs[1] = config_id; + attrs[2] = EGL_NONE; + + if (EGL_TRUE != eglChooseConfig (egl_display, attrs, &egl_config, 1, + &n_configs) || n_configs <= 0) { + GST_WARNING_OBJECT (context, + "could not retrieve egl config from its ID 0x%x. " + "Wrong EGLDisplay or context?", config_id); + goto failure; + } + + config = egl_config_to_structure (egl_display, egl_config); + if (!config) { + GST_WARNING_OBJECT (context, "could not transform config id 0x%x into " + "GstStructure", config_id); + goto failure; + } + + GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config); + + g_object_set_data_full (G_OBJECT (context), + GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config, + (GDestroyNotify) gst_structure_free); + + gst_object_unref (display_egl); + return TRUE; + +failure: + gst_object_unref (display_egl); + return FALSE; +} diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.h b/gst-libs/gst/gl/egl/gstglcontext_egl.h index 5dec8573a4..6d9a8a7aec 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.h +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.h @@ -67,6 +67,8 @@ struct _GstGLContextEGL /* Cached handle */ guintptr window_handle; + + GstStructure *requested_config; }; /** @@ -89,6 +91,9 @@ guintptr gst_gl_context_egl_get_current_context (void); G_GNUC_INTERNAL gpointer gst_gl_context_egl_get_proc_address (GstGLAPI gl_api, const gchar * name); +G_GNUC_INTERNAL +gboolean gst_gl_context_egl_fill_info (GstGLContext * context); + G_END_DECLS #endif /* __GST_GL_CONTEXT_EGL_H__ */ diff --git a/gst-libs/gst/gl/gl.h b/gst-libs/gst/gl/gl.h index 5246abbdea..6c7a37ff64 100644 --- a/gst-libs/gst/gl/gl.h +++ b/gst-libs/gst/gl/gl.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c index 4278d0b05a..115bbd08c6 100644 --- a/gst-libs/gst/gl/gstglcontext.c +++ b/gst-libs/gst/gl/gstglcontext.c @@ -27,6 +27,22 @@ * #GstGLContext wraps an OpenGL context object in a uniform API. As a result * of the limitation on OpenGL context, this object is not thread safe unless * specified and must only be activated in a single thread. + * + * Environment variables: + * - `GST_GL_API`: select which OpenGL API to create and OpenGL context for. + * Depending on the platform, the available values are + * 'opengl', 'opengl3' (core profile), and 'gles2'. See the + * the #GstGLAPI enumeration for more details. + * - `GST_GL_PLATFORM`: select which OpenGL platform to create an OpenGL + * context with. Depending on the platform and the + * dependencies available build-time, the available values + * are, 'glx', 'egl', 'cgl', 'wgl', and 'eagl' + * - `GST_GL_CONFIG`: select the configuration used for creating the OpenGL + * context and OpenGL surface. Written out as a GstStructure + * that has been serialized to string. e.g. + * `GST_GL_CONFIG="gst-gl-context-config,red-size=8,green-size=8,blue-size=8,alpha-size=8,depth-size=16"`. + * Not all platforms will support the same level of + * functionality. */ #ifdef HAVE_CONFIG_H @@ -215,6 +231,7 @@ struct _GstGLContextPrivate gint gl_minor; gchar *gl_exts; + GstStructure *requested_config; }; typedef struct @@ -235,17 +252,9 @@ typedef struct G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLContext, gst_gl_context, GST_TYPE_OBJECT); -#define GST_TYPE_GL_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type()) -static GType gst_gl_wrapped_context_get_type (void); G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context, GST_TYPE_GL_CONTEXT); -#define GST_GL_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContext)) -#define GST_GL_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_CONTEXT, GstGLContextClass)) -#define GST_IS_GL_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WRAPPED_CONTEXT)) -#define GST_IS_GL_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WRAPPED_CONTEXT)) -#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContextClass)) - /** * gst_gl_context_error_quark: * @@ -727,6 +736,10 @@ gst_gl_context_finalize (GObject * object) context->gl_vtable = NULL; } + if (context->priv->requested_config) + gst_structure_free (context->priv->requested_config); + context->priv->requested_config = NULL; + g_mutex_clear (&context->priv->render_lock); g_cond_clear (&context->priv->create_cond); @@ -1018,8 +1031,19 @@ gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context) * to share shareable OpenGL objects with. See the OpenGL specification for * what is shared between OpenGL contexts. * - * If an error occurs, and @error is not %NULL, then error will contain details - * of the error and %FALSE will be returned. + * Since 1.20, the configuration can be overriden with the environment variable + * `GST_GL_CONFIG` which is a stringified #GstStructure as would be returned + * from gst_gl_context_get_config(). If `GST_GL_CONFIG` is not set, then the + * config will be chosen from @other_context by calling + * gst_gl_context_get_config() on @other_context. Otherwise, a default + * configuration is used. + * + * Calling gst_gl_context_request_config()) before calling + * gst_gl_context_create() will override the config from @other_context but + * will not override the `GST_GL_CONFIG` environment variable. + * + * If an error occurs, and @error is not %NULL, then @error will contain + * details of the error and %FALSE will be returned. * * Should only be called once. * @@ -1190,6 +1214,7 @@ gst_gl_context_create_thread (GstGLContext * context) const gchar *user_choice; GError **error; GstGLContext *other_context; + GstStructure *config; g_mutex_lock (&context->priv->render_lock); @@ -1237,6 +1262,44 @@ gst_gl_context_create_thread (GstGLContext * context) goto failure; } + { + const gchar *config_str = g_getenv ("GST_GL_CONFIG"); + if (config_str) { + GstStructure *config = gst_structure_from_string (config_str, NULL); + if (!config) { + g_set_error (error, GST_GL_CONTEXT_ERROR, + GST_GL_CONTEXT_ERROR_WRONG_CONFIG, + "could not construct OpenGL config from the \'GST_GL_CONFIG\' " + "environment variable"); + g_free (compiled_api_s); + g_free (user_api_s); + g_free (display_api_s); + goto failure; + } + if (!gst_gl_context_request_config (context, gst_structure_copy (config))) { + GST_WARNING_OBJECT (context, + "failed to request config %" GST_PTR_FORMAT, config); + } else { + GST_INFO_OBJECT (context, "requesting config from environment %" + GST_PTR_FORMAT, config); + } + gst_structure_free (config); + } else if (other_context && !context->priv->requested_config) { + GstStructure *config = gst_gl_context_get_config (other_context); + if (config) { + if (!gst_gl_context_request_config (context, + gst_structure_copy (config))) { + GST_WARNING_OBJECT (context, + "failed to request config %" GST_PTR_FORMAT, config); + } else { + GST_INFO_OBJECT (context, "requesting config from other context %" + GST_PTR_FORMAT " %" GST_PTR_FORMAT, other_context, config); + } + gst_structure_free (config); + } + } + } + if (context_class->choose_format && !context_class->choose_format (context, error)) { GST_WARNING_OBJECT (context, "Failed to choose format"); @@ -1279,6 +1342,11 @@ gst_gl_context_create_thread (GstGLContext * context) api_string = gst_gl_api_to_string (gl_api); GST_INFO_OBJECT (context, "available GL APIs: %s", api_string); + if ((config = gst_gl_context_get_config (context))) { + GST_DEBUG_OBJECT (context, "Chosen config %" GST_PTR_FORMAT, config); + gst_structure_free (config); + } + if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "failed to create context, context " @@ -1472,6 +1540,20 @@ gst_gl_context_fill_info (GstGLContext * context, GError ** error) gl->IsVertexArray = NULL; } + if (GST_IS_GL_WRAPPED_CONTEXT (context)) { + /* XXX: vfunc? */ +#if GST_GL_HAVE_PLATFORM_GLX + if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_GLX + && !gst_gl_context_glx_fill_info (context)) + goto failure; +#endif +#if GST_GL_HAVE_PLATFORM_EGL + if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_EGL + && !gst_gl_context_egl_fill_info (context)) + goto failure; +#endif + } + return TRUE; failure: @@ -1807,6 +1889,85 @@ gst_gl_context_swap_buffers (GstGLContext * context) context_class->swap_buffers (context); } +/** + * gst_gl_context_get_config: + * @context: the #GstGLContext + * + * Retrieve the OpenGL configuration for this context. The context must + * have been successfully created for this function to return a valid value. + * + * Not all implementations currently support retrieving the config and will + * return %NULL when not supported. + * + * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context. + * + * Since: 1.20 + */ +GstStructure * +gst_gl_context_get_config (GstGLContext * context) +{ + GstGLContextClass *context_class; + + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL); + context_class = GST_GL_CONTEXT_GET_CLASS (context); + if (!context_class->get_config) { + GST_FIXME_OBJECT (context, "does not support retrieving a config"); + return NULL; + } + + return context_class->get_config (context); +} + +/** + * gst_gl_context_request_config: + * @context: the #GstGLContext + * @gl_config: (nullable) (transfer full): a configuration structure for + * configuring the OpenGL context + * + * Set the OpenGL configuration for this context. The context must not + * have been created for this function to succeed. Setting a %NULL + * @config has the affect of removing any specific configuration request. + * + * Not all implementations currently support retrieving the config and this + * function will return FALSE when not supported. + * + * Note that calling this function may cause a subsequent + * gst_gl_context_create() to fail if @config could not be matched with + * the platform-specific configuration. + * + * Note that the actual config used may be differ from the requested values. + * + * Returns: whether @gl_config could be successfully set on @context + * + * Since: 1.20 + */ +gboolean +gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config) +{ + GstGLContextClass *context_class; + gboolean ret; + + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE); + g_return_val_if_fail (context->priv->created == FALSE, FALSE); + context_class = GST_GL_CONTEXT_GET_CLASS (context); + if (!context_class->request_config) { + gst_structure_free (gl_config); + GST_FIXME_OBJECT (context, "does not support requesting a config"); + return FALSE; + } + + ret = context_class->request_config (context, gst_structure_copy (gl_config)); + if (ret) { + if (context->priv->requested_config) + gst_structure_free (context->priv->requested_config); + context->priv->requested_config = gl_config; + } else { + gst_structure_free (gl_config); + } + + return ret; +} + static GstGLAPI gst_gl_wrapped_context_get_gl_api (GstGLContext * context) { @@ -1850,6 +2011,37 @@ gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate) return TRUE; } +static gpointer +_structure_copy_if_set (gpointer data, gpointer user_data) +{ + GstStructure *ret = NULL; + + if (data) + ret = gst_structure_copy (data); + return ret; +} + +static GstStructure * +gst_gl_wrapped_context_get_config (GstGLContext * context) +{ + GstStructure *ret; + + ret = g_object_dup_data (G_OBJECT (context), + GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, + (GDuplicateFunc) _structure_copy_if_set, NULL); + if (ret) { + GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT, + ret); + return ret; + } else { + GST_FIXME_OBJECT (context, "wrapped context could not retrieve config. " + "The application may be missing a call to gst_gl_context_fill_info() " + "or the specific platform implemention is not implemented for " + "retrieving the config from a wrapped OpenGL context."); + return NULL; + } +} + static void gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass) { @@ -1862,6 +2054,8 @@ gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass) context_class->get_gl_platform = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform); context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate); + context_class->get_config = + GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_config); } static void diff --git a/gst-libs/gst/gl/gstglcontext.h b/gst-libs/gst/gl/gstglcontext.h index 007a6fb82a..9c1b5d8eff 100644 --- a/gst-libs/gst/gl/gstglcontext.h +++ b/gst-libs/gst/gl/gstglcontext.h @@ -117,6 +117,34 @@ struct _GstGLContext { * @destroy_context: destroy the OpenGL context * @swap_buffers: swap the default framebuffer's front/back buffers */ +/** + * GstGLContextClass::get_config: + * @context: the #GstGLContext + * + * Retrieve the configuration in use by this context. See also + * gst_gl_context_get_config(). + * + * Returns: (transfer full) (nullable): the configuration chosen for this + * #GstGLContext + * + * Since: 1.20 + */ +/** + * GstGLContextClass::request_config: + * @context: the #GstGLContext + * @gl_config: (nullable) (transfer full): a configuration structure for + * configuring on @context + * + * Request a configuration for this @context to use. + * + * Unknown fields within @gl_config should be ignored by subclasses. + * + * See also gst_gl_context_request_config(). + * + * Returns: Whether @gl_config could be successfull set on @context. + * + * Since: 1.20 + */ struct _GstGLContextClass { GstObjectClass parent_class; @@ -133,9 +161,11 @@ struct _GstGLContextClass { void (*swap_buffers) (GstGLContext *context); gboolean (*check_feature) (GstGLContext *context, const gchar *feature); void (*get_gl_platform_version) (GstGLContext *context, gint *major, gint *minor); + GstStructure *(*get_config) (GstGLContext * context); + gboolean (*request_config) (GstGLContext * context, GstStructure * gl_config); /*< private >*/ - gpointer _reserved[GST_PADDING]; + gpointer _reserved[GST_PADDING-2]; }; /* methods */ @@ -148,6 +178,11 @@ GstGLContext * gst_gl_context_new_wrapped (GstGLDisplay *display, GstGLPlatform context_type, GstGLAPI available_apis); +GST_GL_API +GstStructure * gst_gl_context_get_config (GstGLContext * context); +GST_GL_API +gboolean gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config); + GST_GL_API gboolean gst_gl_context_activate (GstGLContext *context, gboolean activate); GST_GL_API diff --git a/gst-libs/gst/gl/gstglcontext_private.h b/gst-libs/gst/gl/gstglcontext_private.h index 6926375e36..2fa8cfdf2d 100644 --- a/gst-libs/gst/gl/gstglcontext_private.h +++ b/gst-libs/gst/gl/gstglcontext_private.h @@ -29,6 +29,18 @@ G_GNUC_INTERNAL extern GstDebugCategory *gst_gl_context_debug; G_GNUC_INTERNAL gboolean _gst_gl_context_debug_is_enabled (GstGLContext * context); +#define GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME "gst.gl.context.wrapped.config" + +#define GST_TYPE_GL_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type()) +G_GNUC_INTERNAL +GType gst_gl_wrapped_context_get_type (void); + +#define GST_GL_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContext)) +#define GST_GL_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_CONTEXT, GstGLContextClass)) +#define GST_IS_GL_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WRAPPED_CONTEXT)) +#define GST_IS_GL_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WRAPPED_CONTEXT)) +#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContextClass)) + G_END_DECLS #endif /* __GST_GL_CONTEXT_PRIVATE_H__ */ diff --git a/gst-libs/gst/gl/gstglcontextconfig.c b/gst-libs/gst/gl/gstglcontextconfig.c new file mode 100644 index 0000000000..1a9948b256 --- /dev/null +++ b/gst-libs/gst/gl/gstglcontextconfig.c @@ -0,0 +1,438 @@ +/* + * GStreamer + * Copyright (C) 2020 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstglcontextconfig + * @short_description: OpenGL context configuration values + * @title: GstGLContext + * @see_also: #GstGLContext, #GstGLWindow + * + * A common list of well-known values for what a config retrievable from or set + * on a `GstGLContext` may contain. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstglcontextconfig.h" +#include + +/** + * GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME: + * + * The platform-specific config-id. This value is not stable across different + * machines or even different versions of the same underlying OpenGL + * implementation. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_CONFIG_ID_GTYPE: + * + * The #GType of the config-id field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME = "config-id"; +/** + * GST_GL_CONFIG_ATTRIB_PLATFORM_NAME: + * + * The #GstGLPlatform this config was made for. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_PLATFORM_GTYPE: + * + * The #GType of the 'platform' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_PLATFORM_NAME = "platform"; +/** + * GST_GL_CONFIG_ATTRIB_CAVEAT_NAME: + * + * Any #GstGLConfigCaveat's applied to this configuration. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_CAVEAT_GTYPE: + * + * The #GType of the 'caveat' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_CAVEAT_NAME = "caveat"; +/** + * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME: + * + * Flags of #GstGLConfigSurfaceType's that can apply to this configuration. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_GTYPE: + * + * The #GType of the 'surface-type' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME = "surface-type"; +/** + * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME: + * + * The #GstGLAPI's that this configuration meets the conformance requirements + * for. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_GTYPE: + * + * The #GType of the 'conformant-api' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME = "conformant-api"; +/** + * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME: + * + * The #GstGLAPI's that this configuration can be rendered with. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_GTYPE: + * + * The #GType of the 'renderable-api' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME = "renderable-api"; +/** + * GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME: + * + * The size of the red buffer with a colour backing buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_RED_SIZE_GTYPE: + * + * The #GType of the 'red-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME = "red-size"; +/** + * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME: + * + * The size of the green buffer with a colour backing buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_GTYPE: + * + * The #GType of the 'green-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME = "green-size"; +/** + * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME: + * + * The size of the blue buffer with a colour backing buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_GTYPE: + * + * The #GType of the 'blue-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME = "blue-size"; +/** + * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME: + * + * The size of the alpha buffer with a colour backing buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_GTYPE: + * + * The #GType of the 'alpha-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME = "alpha-size"; +/** + * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME: + * + * The size of the backing luminance buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_GTYPE: + * + * The #GType of the 'luminance-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME = "luminance-size"; +/** + * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME: + * + * The size of the backing depth buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_GTYPE: + * + * The #GType of the 'depth-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME = "depth-size"; +/** + * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME: + * + * The size of the backing stencil buffer. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_GTYPE: + * + * The #GType of the 'stencil-size' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME = "stencil-size"; +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME: + * + * The maximum width of a pbuffer created with this config. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_GTYPE: + * + * The #GType of the 'max-pbuffer-width' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME = "max-pbuffer-width"; +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME: + * + * The maximum height of a pbuffer created with this config. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_GTYPE: + * + * The #GType of the 'max-pbuffer-height' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME = + "max-pbuffer-height"; +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME: + * + * The maximum number of pixels that a pbuffer can be created with this config. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_GTYPE: + * + * The #GType of the 'max-pbuffer-pixels' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME = + "max-pbuffer-pixels"; +/** + * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME: + * + * The number of sample buffers for this config. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_GTYPE: + * + * The #GType of the 'sample-buffers' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME = "sample-buffers"; +/** + * GST_GL_CONFIG_ATTRIB_SAMPLES_NAME: + * + * The number of samples per pixel for this config. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_SAMPLES_GTYPE: + * + * The #GType of the 'samples' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_SAMPLES_NAME = "samples"; +/** + * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME: + * + * Whether this configuration is renderable to by the native drawing API. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_GTYPE: + * + * The #GType of the 'native-renderable' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME = "native-renderable"; +/** + * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME: + * + * The native visual ID of this config. This value may not be consistent + * across machines or even dependency versions. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_GTYPE: + * + * The #GType of the 'native-visual-id' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME = "native-visual-id"; +/** + * GST_GL_CONFIG_ATTRIB_LEVEL_NAME: + * + * Level of the under/overlay of this config. Positive values correspond to + * overlay, negative values are underlay. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_LEVEL_GTYPE: + * + * The #GType of the 'level' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_LEVEL_NAME = "level"; +/** + * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME: + * + * The minimum value available for vsync synchronisation. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_GTYPE: + * + * The #GType of the 'min-swap-interval' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME = "min-swap-interval"; +/** + * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME: + * + * The maximum value available for vsync synchronisation. + * + * Since: 1.20 + */ +/** + * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_GTYPE: + * + * The #GType of the 'max-swap-interval' field. + * + * Since: 1.20 + */ +const gchar *GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME = "max-swap-interval"; + +static const gchar * +gst_gl_enum_value_to_const_string (GType type, guint value) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + const gchar *str = NULL; + + enum_class = g_type_class_ref (type); + enum_value = g_enum_get_value (enum_class, value); + + if (enum_value) + str = enum_value->value_nick; + + g_type_class_unref (enum_class); + + return str; +} + +/** + * gst_gl_config_caveat_to_string: + * @caveat: the #GstGLConfigCaveat + * + * Returns: (nullable): a string version of @caveat or %NULL if @caveat does not + * exist. + * + * Since: 1.20 + */ +const gchar * +gst_gl_config_caveat_to_string (GstGLConfigCaveat caveat) +{ + return gst_gl_enum_value_to_const_string (GST_TYPE_GL_CONFIG_CAVEAT, caveat); +} + +/** + * gst_gl_config_surface_type_to_string: + * @surface_type: the #GstGLConfigSurfaceType + * + * Returns: (nullable): a string version of @caveat or %NULL if @surface_type does not + * exist. + * + * Since: 1.20 + */ +const gchar * +gst_gl_config_surface_type_to_string (GstGLConfigSurfaceType surface_type) +{ + return gst_gl_enum_value_to_const_string (GST_TYPE_GL_CONFIG_SURFACE_TYPE, + surface_type); +} diff --git a/gst-libs/gst/gl/gstglcontextconfig.h b/gst-libs/gst/gl/gstglcontextconfig.h new file mode 100644 index 0000000000..af33013742 --- /dev/null +++ b/gst-libs/gst/gl/gstglcontextconfig.h @@ -0,0 +1,160 @@ +/* + * GStreamer + * Copyright (C) 2020 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GL_CONTEXT_CONFIG_H__ +#define __GST_GL_CONTEXT_CONFIG_H__ + +#include + +#include + +G_BEGIN_DECLS + +/** + * GST_GL_CONFIG_STRUCTURE_NAME: + * + * The canonical name of a #GstStructure that contains a configuration for a + * #GstGLContext. + * + * Since: 1.20 + */ +#define GST_GL_CONFIG_STRUCTURE_NAME "gst-gl-context-config" + +/** + * GST_GL_CONFIG_ATTRIB_NAME: + * + * Get a reference to the variable name of a particular configuration field. + * + * e.g. for `CONFIG_ID`: `GST_GL_CONFIG_ATTRIB_NAME (CONFIG_ID)` + * + * Since: 1.20 + */ +#define GST_GL_CONFIG_ATTRIB_NAME(UPPER_NAME) \ + G_PASTE(G_PASTE(GST_GL_CONFIG_ATTRIB_,UPPER_NAME),_NAME) +/** + * GST_GL_CONFIG_ATTRIB_GTYPE: + * + * Get a reference to the #GType of a particular configuration field. + * + * e.g. for `CONFIG_ID`: `GST_GL_CONFIG_ATTRIB_GTYPE (CONFIG_ID)` + * + * Since: 1.20 + */ +#define GST_GL_CONFIG_ATTRIB_GTYPE(UPPER_NAME) \ + G_PASTE(G_PASTE(GST_GL_CONFIG_ATTRIB_,UPPER_NAME),_GTYPE) + +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME; +#define GST_GL_CONFIG_ATTRIB_CONFIG_ID_GTYPE G_TYPE_UINT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_PLATFORM_NAME; +#define GST_GL_CONFIG_ATTRIB_PLATFORM_GTYPE GST_TYPE_GL_PLATFORM +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CAVEAT_NAME; +#define GST_GL_CONFIG_ATTRIB_CAVEAT_GTYPE GST_TYPE_GL_CONFIG_CAVEAT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME; +#define GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_GTYPE GST_TYPE_GL_CONFIG_SURFACE_TYPE +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME; +#define GST_GL_CONFIG_ATTRIB_CONFORMANT_API_GTYPE GST_TYPE_GL_API +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME; +#define GST_GL_CONFIG_ATTRIB_RENDERABLE_API_GTYPE GST_TYPE_GL_API +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_RED_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_GREEN_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_BLUE_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME; +#define GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME; +#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME; +#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME; +#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME; +#define GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SAMPLES_NAME; +#define GST_GL_CONFIG_ATTRIB_SAMPLES_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME; +#define GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_GTYPE G_TYPE_BOOLEAN +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME; +#define GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_GTYPE G_TYPE_UINT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_LEVEL_NAME; +#define GST_GL_CONFIG_ATTRIB_LEVEL_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME; +#define GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_GTYPE G_TYPE_INT +GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME; +#define GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_GTYPE G_TYPE_INT + +/** + * GST_GL_CONFIG_STRUCTURE_SET_ARGS: + * + * Since: 1.20 + */ +#define GST_GL_CONFIG_STRUCTURE_SET_ARGS(def_name,ctype,val) \ + GST_GL_CONFIG_ATTRIB_NAME(def_name), \ + GST_GL_CONFIG_ATTRIB_GTYPE(def_name), \ + (ctype) (val) + +/** + * GstGLConfigCaveat: + * @GST_GL_CONFIG_CAVEAT_NONE: none + * @GST_GL_CONFIG_CAVEAT_SLOW: slow + * @GST_GL_CONFIG_CAVEAT_NON_CONFORMANT: non-conformant + * + * Since: 1.20 + */ +typedef enum +{ + GST_GL_CONFIG_CAVEAT_NONE, + GST_GL_CONFIG_CAVEAT_SLOW, + GST_GL_CONFIG_CAVEAT_NON_CONFORMANT, +} GstGLConfigCaveat; + +GST_GL_API +const gchar * gst_gl_config_caveat_to_string (GstGLConfigCaveat caveat); + +/** + * GstGLConfigSurfaceType: + * @GST_GL_CONFIG_SURFACE_TYPE_NONE: none + * @GST_GL_CONFIG_SURFACE_TYPE_WINDOW: window + * @GST_GL_CONFIG_SURFACE_TYPE_PBUFFER: pbuffer + * @GST_GL_CONFIG_SURFACE_TYPE_PIXMAP: pixmap + * + * Since: 1.20 + */ +typedef enum +{ + GST_GL_CONFIG_SURFACE_TYPE_NONE = 0, + GST_GL_CONFIG_SURFACE_TYPE_WINDOW = (1 << 0), + GST_GL_CONFIG_SURFACE_TYPE_PBUFFER = (1 << 1), + GST_GL_CONFIG_SURFACE_TYPE_PIXMAP = (1 << 2), +} GstGLConfigSurfaceType; + +GST_GL_API +const gchar * gst_gl_config_surface_type_to_string (GstGLConfigSurfaceType surface_type); + +G_END_DECLS + +#endif /* __GST_GL_CONTEXT_CONFIG_H__ */ diff --git a/gst-libs/gst/gl/meson.build b/gst-libs/gst/gl/meson.build index 80278d3a6e..67399f220f 100644 --- a/gst-libs/gst/gl/meson.build +++ b/gst-libs/gst/gl/meson.build @@ -14,6 +14,7 @@ gl_sources = [ 'gstglbuffer.c', 'gstglbufferpool.c', 'gstglcontext.c', + 'gstglcontextconfig.c', 'gstgldebug.c', 'gstgldisplay.c', 'gstglfeature.c', @@ -51,6 +52,7 @@ gir_gl_headers = [ 'gstglbufferpool.h', 'gstglcolorconvert.h', 'gstglcontext.h', + 'gstglcontextconfig.h', 'gstgldebug.h', 'gstgldisplay.h', 'gstglfeature.h', diff --git a/gst-libs/gst/gl/wgl/gstglcontext_wgl.c b/gst-libs/gst/gl/wgl/gstglcontext_wgl.c index b13dec4ef9..d75dc32fda 100644 --- a/gst-libs/gst/gl/wgl/gstglcontext_wgl.c +++ b/gst-libs/gst/gl/wgl/gstglcontext_wgl.c @@ -63,6 +63,7 @@ static GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext * context); static gboolean gst_gl_context_wgl_check_feature (GstGLContext * context, const gchar * feature); +GstStructure *gst_gl_context_wgl_get_config (GstGLContext * context); static void gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass) @@ -88,6 +89,7 @@ gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass) GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform); context_class->check_feature = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_check_feature); + context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_config); } static void @@ -302,6 +304,47 @@ gst_gl_context_wgl_destroy_context (GstGLContext * context) context_wgl->wgl_context = NULL; } +static GstGLConfigSurfaceType +pfd_flags_to_surface_type (int flags) +{ + GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE; + + if (flags & PFD_DRAW_TO_WINDOW) + ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW; + if (flags & PFD_DRAW_TO_BITMAP) + ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP; + + return ret; +} + +static GstStructure * +pixel_format_to_structure (HDC hdc, int pixfmt) +{ + GstStructure *ret; + PIXELFORMATDESCRIPTOR pfd; + + if (pixfmt == 0) + return NULL; + + if (DescribePixelFormat (hdc, pixfmt, sizeof (pfd), &pfd) == 0) + return NULL; + + ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME, + GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform, + GST_GL_PLATFORM_WGL), GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int, + pfd.cRedBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int, + pfd.cBlueBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int, + pfd.cGreenBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int, + pfd.cAlphaBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int, + pfd.cDepthBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int, + pfd.cStencilBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID, + guint, pixfmt), GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE, + GstGLConfigSurfaceType, pfd_flags_to_surface_type (pfd.dwFlags)), + NULL); + + return ret; +} + static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error) { @@ -310,6 +353,7 @@ gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error) gint pixelformat = 0; gboolean res = FALSE; HDC device; + GstStructure *config; window = gst_gl_context_get_window (context); gst_gl_window_win32_create_window (GST_GL_WINDOW_WIN32 (window), error); @@ -353,6 +397,10 @@ gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error) return FALSE; } + config = pixel_format_to_structure (device, pixelformat); + GST_INFO_OBJECT (context, "chosen config %" GST_PTR_FORMAT, config); + gst_structure_free (config); + res = SetPixelFormat (device, pixelformat, &pfd); return res; @@ -437,3 +485,18 @@ gst_gl_context_wgl_get_current_context (void) { return (guintptr) wglGetCurrentContext (); } + +GstStructure * +gst_gl_context_wgl_get_config (GstGLContext * context) +{ + GstGLWindow *window; + int pixfmt; + HDC hdc; + + window = gst_gl_context_get_window (context); + hdc = (HDC) gst_gl_window_get_display (window); + + pixfmt = GetPixelFormat (hdc); + + return pixel_format_to_structure (hdc, pixfmt); +} diff --git a/gst-libs/gst/gl/x11/gstglcontext_glx.c b/gst-libs/gst/gl/x11/gstglcontext_glx.c index cb74d47870..e581a7d4c3 100644 --- a/gst-libs/gst/gl/x11/gstglcontext_glx.c +++ b/gst-libs/gst/gl/x11/gstglcontext_glx.c @@ -55,6 +55,9 @@ static GstGLPlatform gst_gl_context_glx_get_gl_platform (GstGLContext * context); static void gst_gl_context_glx_get_gl_platform_version (GstGLContext * context, gint * major, gint * minor); +static GstStructure *gst_gl_context_glx_get_config (GstGLContext * context); +static gboolean gst_gl_context_glx_request_config (GstGLContext * context, + GstStructure * config); struct _GstGLContextGLXPrivate { @@ -66,6 +69,8 @@ struct _GstGLContextGLXPrivate GLXFBConfig *fbconfigs; GLXContext (*glXCreateContextAttribsARB) (Display *, GLXFBConfig, GLXContext, Bool, const int *); + + GstStructure *requested_config; }; #define gst_gl_context_glx_parent_class parent_class @@ -98,6 +103,9 @@ gst_gl_context_glx_class_init (GstGLContextGLXClass * klass) GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_current_context); context_class->get_gl_platform_version = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform_version); + context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_config); + context_class->request_config = + GST_DEBUG_FUNCPTR (gst_gl_context_glx_request_config); } static void @@ -121,6 +129,140 @@ gst_gl_context_glx_new (GstGLDisplay * display) return context; } +static GstGLConfigSurfaceType +glx_drawable_type_to_gst (int drawable_type) +{ + GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE; + + if (drawable_type & GLX_WINDOW_BIT) + ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW; + if (drawable_type & GLX_PIXMAP_BIT) + ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP; + if (drawable_type & GLX_PBUFFER_BIT) + ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER; + + return ret; +} + +static GstGLConfigCaveat +glx_caveat_to_gst (int caveat) +{ + switch (caveat) { + case GLX_NONE: + return GST_GL_CONFIG_CAVEAT_NONE; + case GLX_SLOW_CONFIG: + return GST_GL_CONFIG_CAVEAT_SLOW; + case GLX_NON_CONFORMANT_CONFIG: + return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT; + default: + GST_WARNING ("unknown GLX caveat value %u (0x%x)", caveat, caveat); + return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT; + } +} + +static GstStructure * +fb_config_to_structure (GstGLContext * context, + Display * dpy, GLXFBConfig fbconfig) +{ + GstStructure *ret; + int val, render_type; + + ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME, + GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform, + GST_GL_PLATFORM_GLX), "platform-sub-type", G_TYPE_STRING, "fbconfig", + NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_FBCONFIG_ID, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_VISUAL_ID, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID, + guint, val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_CONFIG_CAVEAT, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT, + GstGLConfigCaveat, glx_caveat_to_gst (val)), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DRAWABLE_TYPE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE, + GstGLConfigSurfaceType, glx_drawable_type_to_gst (val)), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_X_RENDERABLE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE, + gboolean, val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_LEVEL, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val), + NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RENDER_TYPE, + &render_type)) + goto failure; + + if (render_type & GLX_RGBA_BIT) { + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RED_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_GREEN_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_BLUE_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ALPHA_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int, + val), NULL); + } + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DEPTH_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_STENCIL_SIZE, &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int, + val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_WIDTH, + &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH, + int, val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_HEIGHT, + &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT, + int, val), NULL); + + if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_PIXELS, + &val)) + goto failure; + gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS, + int, val), NULL); + + return ret; + +failure: + gst_structure_free (ret); + return NULL; +} + static void gst_gl_context_glx_dump_fb_config (GstGLContextGLX * glx, Display * dpy, GLXFBConfig fbconfig) @@ -353,6 +495,60 @@ gst_gl_context_glx_dump_all_fb_configs (GstGLContextGLX * glx, XFree (configs); } +static int * +fb_config_attributes_from_structure (GstStructure * config) +{ + guint i = 0, n; + int *ret; + + if (!config) { + gint attribs[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 16, + GLX_DOUBLEBUFFER, True, + None + }; + + return g_memdup (attribs, sizeof (attribs)); + } + + n = gst_structure_n_fields (config) * 2 + 1; + ret = g_new0 (gint, n); + +#define TRANSFORM_VALUE(GL_CONF_NAME,GLX_ATTR_NAME) \ + G_STMT_START { \ + if (gst_structure_has_field_typed (config, \ + GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \ + GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \ + int val; \ + if (gst_structure_get (config, \ + GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \ + GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \ + ret[i++] = GLX_ATTR_NAME; \ + ret[i++] = (int) val; \ + } \ + } \ + } G_STMT_END + + TRANSFORM_VALUE (CONFIG_ID, GLX_FBCONFIG_ID); + TRANSFORM_VALUE (RED_SIZE, GLX_RED_SIZE); + TRANSFORM_VALUE (GREEN_SIZE, GLX_GREEN_SIZE); + TRANSFORM_VALUE (BLUE_SIZE, GLX_BLUE_SIZE); + TRANSFORM_VALUE (ALPHA_SIZE, GLX_ALPHA_SIZE); + TRANSFORM_VALUE (DEPTH_SIZE, GLX_DEPTH_SIZE); + TRANSFORM_VALUE (STENCIL_SIZE, GLX_STENCIL_SIZE); + /* TODO: more values */ + +#undef TRANSFORM_VALUE + + ret[i++] = None; + g_assert (i <= n); + return ret; +} + static GLXContext _create_context_with_flags (GstGLContextGLX * context_glx, Display * dpy, GLXFBConfig fbconfig, GLXContext share_context, gint major, gint minor, @@ -487,9 +683,6 @@ gst_gl_context_glx_create_context (GstGLContext * context, context_glx->priv->context_api = GST_GL_API_OPENGL; } - if (context_glx->priv->fbconfigs) - XFree (context_glx->priv->fbconfigs); - if (!context_glx->glx_context) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context"); @@ -523,10 +716,18 @@ gst_gl_context_glx_destroy_context (GstGLContext * context) window = gst_gl_context_get_window (context); device = (Display *) gst_gl_display_get_handle (window->display); + if (context_glx->priv->fbconfigs) + XFree (context_glx->priv->fbconfigs); + context_glx->priv->fbconfigs = NULL; + glXDestroyContext (device, context_glx->glx_context); context_glx->glx_context = 0; + if (context_glx->priv->requested_config) + gst_structure_free (context_glx->priv->requested_config); + context_glx->priv->requested_config = NULL; + gst_object_unref (window); } @@ -598,16 +799,12 @@ gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error) goto failure; } } else { - gint attribs[] = { - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DEPTH_SIZE, 16, - GLX_DOUBLEBUFFER, True, - None - }; int fbcount; + int *attribs; + + attribs = + fb_config_attributes_from_structure (context_glx-> + priv->requested_config); gst_gl_context_glx_dump_all_fb_configs (context_glx, device, DefaultScreen (device)); @@ -615,6 +812,8 @@ gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error) context_glx->priv->fbconfigs = glXChooseFBConfig (device, DefaultScreen (device), attribs, &fbcount); + g_free (attribs); + if (!context_glx->priv->fbconfigs) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, @@ -730,3 +929,109 @@ gst_gl_context_glx_get_gl_platform_version (GstGLContext * context, *major = context_glx->priv->glx_major; *minor = context_glx->priv->glx_minor; } + +static GstStructure * +gst_gl_context_glx_get_config (GstGLContext * context) +{ + GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context); + GstGLWindow *window; + GstGLWindowX11 *window_x11; + Display *device; + GstStructure *ret; + + window = gst_gl_context_get_window (context); + device = (Display *) gst_gl_display_get_handle (window->display); + window_x11 = GST_GL_WINDOW_X11 (window); + + g_return_val_if_fail (glx->priv->fbconfigs || window_x11->visual_info, NULL); + + if (glx->priv->fbconfigs) { + ret = fb_config_to_structure (context, device, glx->priv->fbconfigs[0]); + } else { + /*TODO: XVisualInfo for really old GLX/X11 versions, */ + ret = NULL; + } + gst_object_unref (window); + return ret; +} + +static gboolean +gst_gl_context_glx_request_config (GstGLContext * context, + GstStructure * config) +{ + GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context); + + if (glx->priv->requested_config) + gst_structure_free (glx->priv->requested_config); + glx->priv->requested_config = config; + + return TRUE; +} + +gboolean +gst_gl_context_glx_fill_info (GstGLContext * context) +{ + GLXContext glx_context = (GLXContext) gst_gl_context_get_gl_context (context); + GstStructure *config; + Display *device; + GLXFBConfig *fbconfigs; + int fbconfig_id, n_fbconfigs; + int glx_major, glx_minor; + int attrs[3]; + + if (!glx_context) { + GST_ERROR_OBJECT (context, "no GLX context"); + return FALSE; + } + + device = (Display *) gst_gl_display_get_handle (context->display); + + if (!glXQueryVersion (device, &glx_major, &glx_minor)) { + GST_WARNING_OBJECT (context, "could not retrieve GLX version"); + return FALSE; + } + + if (!GST_GL_CHECK_GL_VERSION (glx_major, glx_minor, 1, 4)) { + GST_FIXME_OBJECT (context, "No support for retrieving the " + "GstGLContextConfig from GLX < 1.4, have %u.%u", glx_major, glx_minor); + return TRUE; + } + + if (Success != glXQueryContext (device, glx_context, GLX_FBCONFIG_ID, + &fbconfig_id)) { + GST_WARNING_OBJECT (context, + "could not retrieve fbconfig id from glx context"); + goto failure; + } + + attrs[0] = GLX_FBCONFIG_ID; + attrs[1] = fbconfig_id; + attrs[2] = None; + + fbconfigs = glXChooseFBConfig (device, DefaultScreen (device), attrs, + &n_fbconfigs); + if (!fbconfigs || n_fbconfigs <= 0) { + GST_WARNING_OBJECT (context, + "could not retrieve fbconfig from its ID 0x%x. " + "Wrong Display or Screen?", fbconfig_id); + goto failure; + } + + config = fb_config_to_structure (context, device, fbconfigs[0]); + if (!config) { + GST_WARNING_OBJECT (context, "could not transform fbconfig id 0x%x into " + "GstStructure.", fbconfig_id); + goto failure; + } + + GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config); + + g_object_set_data_full (G_OBJECT (context), + GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config, + (GDestroyNotify) gst_structure_free); + + return TRUE; + +failure: + return FALSE; +} diff --git a/gst-libs/gst/gl/x11/gstglcontext_glx.h b/gst-libs/gst/gl/x11/gstglcontext_glx.h index 40886ed29c..e084cb545d 100644 --- a/gst-libs/gst/gl/x11/gstglcontext_glx.h +++ b/gst-libs/gst/gl/x11/gstglcontext_glx.h @@ -68,6 +68,9 @@ guintptr gst_gl_context_glx_get_current_context (void); G_GNUC_INTERNAL gpointer gst_gl_context_glx_get_proc_address (GstGLAPI gl_api, const gchar * name); +G_GNUC_INTERNAL +gboolean gst_gl_context_glx_fill_info (GstGLContext * context); + G_END_DECLS #endif /* __GST_GL_CONTEXT_H__ */