st/egl_g3d: Add support for EGL_MESA_screen_surface.
authorChia-I Wu <olvaffe@gmail.com>
Mon, 4 Jan 2010 04:01:38 +0000 (12:01 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Tue, 12 Jan 2010 03:09:00 +0000 (11:09 +0800)
This is implemented through the modeset interface.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
src/gallium/state_trackers/egl_g3d/common/egl_g3d.c
src/gallium/state_trackers/egl_g3d/common/egl_g3d.h

index f4a58f77ebe8daea419ae0ffec69d6c3d8bb66a5..8b2e3b5f85b0bdcc374950f1799c74c6f430bbf1 100644 (file)
@@ -327,6 +327,69 @@ get_mode_api_mask(const __GLcontextModes *mode, EGLint api_mask)
    return api_mask;
 }
 
+#ifdef EGL_MESA_screen_surface
+
+static void
+egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+   const struct native_connector **native_connectors;
+   EGLint num_connectors, i;
+
+   native_connectors =
+      gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL);
+   if (!num_connectors) {
+      if (native_connectors)
+         free(native_connectors);
+      return;
+   }
+
+   for (i = 0; i < num_connectors; i++) {
+      const struct native_connector *nconn = native_connectors[i];
+      struct egl_g3d_screen *gscr;
+      const struct native_mode **native_modes;
+      EGLint num_modes, j;
+
+      /* TODO support for hotplug */
+      native_modes =
+         gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes);
+      if (!num_modes) {
+         if (native_modes)
+            free(native_modes);
+         continue;
+      }
+
+      gscr = CALLOC_STRUCT(egl_g3d_screen);
+      if (!gscr) {
+         free(native_modes);
+         continue;
+      }
+
+      _eglInitScreen(&gscr->base);
+
+      for (j = 0; j < num_modes; j++) {
+         const struct native_mode *nmode = native_modes[j];
+         _EGLMode *mode;
+
+         mode = _eglAddNewMode(&gscr->base, nmode->width, nmode->height,
+               nmode->refresh_rate, nmode->desc);
+         if (!mode)
+            break;
+         /* gscr->native_modes and gscr->base.Modes should be consistent */
+         assert(mode == &gscr->base.Modes[j]);
+      }
+
+      gscr->native = nconn;
+      gscr->native_modes = native_modes;
+
+      _eglAddScreen(dpy, &gscr->base);
+   }
+
+   free(native_connectors);
+}
+
+#endif /* EGL_MESA_screen_surface */
+
 /**
  * Add configs to display and return the next config ID.
  */
@@ -365,8 +428,17 @@ egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id)
       _eglInitConfig(&gconf->base, id);
       valid = _eglConfigFromContextModesRec(&gconf->base,
             &native_configs[i]->mode, api_mask, api_mask);
-      if (valid)
+      if (valid) {
+#ifdef EGL_MESA_screen_surface
+         /* check if scanout surface bit is set */
+         if (native_configs[i]->scanout_bit) {
+            EGLint val = GET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE);
+            val |= EGL_SCREEN_BIT_MESA;
+            SET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE, val);
+         }
+#endif
          valid = _eglValidateConfig(&gconf->base, EGL_FALSE);
+      }
       if (!valid) {
          _eglLog(_EGL_DEBUG, "skip invalid config 0x%x",
                native_configs[i]->mode.visualID);
@@ -403,10 +475,20 @@ static EGLBoolean
 egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy)
 {
    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+   EGLint i;
 
    _eglReleaseDisplayResources(drv, dpy);
    _eglCleanupDisplay(dpy);
 
+   if (dpy->Screens) {
+      for (i = 0; i < dpy->NumScreens; i++) {
+         struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]);
+         free(gscr->native_modes);
+         free(gscr);
+      }
+      free(dpy->Screens);
+   }
+
    if (gdpy->native)
       gdpy->native->destroy(gdpy->native);
 
@@ -444,6 +526,14 @@ egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy,
       goto fail;
    }
 
+#ifdef EGL_MESA_screen_surface
+   /* enable MESA_screen_surface */
+   if (gdpy->native->modeset) {
+      dpy->Extensions.MESA_screen_surface = EGL_TRUE;
+      egl_g3d_add_screens(drv, dpy);
+   }
+#endif
+
    *major = 1;
    *minor = 4;
 
@@ -863,6 +953,99 @@ egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
    return EGL_TRUE;
 }
 
+#ifdef EGL_MESA_screen_surface
+
+static _EGLSurface *
+egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+                              _EGLConfig *conf, const EGLint *attribs)
+{
+   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+   struct egl_g3d_config *gconf = egl_g3d_config(conf);
+   struct egl_g3d_surface *gsurf;
+
+   gsurf = CALLOC_STRUCT(egl_g3d_surface);
+   if (!gsurf) {
+      _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
+      return NULL;
+   }
+
+   if (!_eglInitSurface(drv, &gsurf->base,
+            EGL_SCREEN_BIT_MESA, conf, attribs)) {
+      free(gsurf);
+      return NULL;
+   }
+
+   gsurf->native =
+      gdpy->native->modeset->create_scanout_surface(gdpy->native,
+            gconf->native, gsurf->base.Width, gsurf->base.Height);
+   if (!gsurf->native) {
+      free(gsurf);
+      return NULL;
+   }
+
+   gsurf->render_att = (!gconf->native->mode.doubleBufferMode) ?
+      NATIVE_ATTACHMENT_FRONT_LEFT : NATIVE_ATTACHMENT_BACK_LEFT;
+
+   return &gsurf->base;
+}
+
+static EGLBoolean
+egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+                            _EGLScreen *scr, _EGLSurface *surf,
+                            _EGLMode *mode)
+{
+   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+   struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
+   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+   struct native_surface *nsurf;
+   const struct native_mode *nmode;
+   EGLBoolean changed;
+
+   if (gsurf) {
+      EGLint idx;
+
+      if (!mode)
+         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
+      if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
+         return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
+      if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
+         return _eglError(EGL_BAD_MATCH,
+               "eglShowSurfaceMESA(surface smaller than mode size)");
+
+      /* find the index of the mode */
+      for (idx = 0; idx < gscr->base.NumModes; idx++)
+         if (mode == &gscr->base.Modes[idx])
+            break;
+      if (idx >= gscr->base.NumModes) {
+         return _eglError(EGL_BAD_MODE_MESA,
+               "eglShowSurfaceMESA(unknown mode)");
+      }
+
+      nsurf = gsurf->native;
+      nmode = gscr->native_modes[idx];
+   }
+   else {
+      if (mode)
+         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
+
+      /* disable the screen */
+      nsurf = NULL;
+      nmode = NULL;
+   }
+
+   /* TODO surface panning by CRTC choosing */
+   changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
+         gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
+   if (changed) {
+      gscr->base.CurrentSurface = &gsurf->base;
+      gscr->base.CurrentMode = mode;
+   }
+
+   return changed;
+}
+
+#endif /* EGL_MESA_screen_surface */
+
 static void
 egl_g3d_unload(_EGLDriver *drv)
 {
@@ -903,6 +1086,11 @@ _eglMain(const char *args)
    gdrv->base.API.BindTexImage = egl_g3d_bind_tex_image;
    gdrv->base.API.ReleaseTexImage = egl_g3d_release_tex_image;
 
+#ifdef EGL_MESA_screen_surface
+   gdrv->base.API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
+   gdrv->base.API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
+#endif
+
    gdrv->base.Name = driver_name;
    gdrv->base.Unload = egl_g3d_unload;
 
index 525bb488e2d61883b408fbe12d2cb25a3eb60645..33894b614f971c5a8bcce6f6e5fdbf2ad330b366 100644 (file)
@@ -34,6 +34,8 @@
 #include "eglcontext.h"
 #include "eglsurface.h"
 #include "eglconfig.h"
+#include "eglscreen.h"
+#include "eglmode.h"
 
 #include "native.h"
 #include "egl_st.h"
@@ -78,6 +80,11 @@ struct egl_g3d_config {
    const struct native_config *native;
 };
 
+struct egl_g3d_screen {
+   _EGLScreen base;
+   const struct native_connector *native;
+   const struct native_mode **native_modes;
+};
 
 static INLINE struct egl_g3d_driver *
 egl_g3d_driver(_EGLDriver *drv)
@@ -110,4 +117,10 @@ egl_g3d_config(_EGLConfig *conf)
    return (struct egl_g3d_config *) conf;
 }
 
+static INLINE struct egl_g3d_screen *
+egl_g3d_screen(_EGLScreen *scr)
+{
+   return (struct egl_g3d_screen *) scr;
+}
+
 #endif /* _EGL_G3D_H_ */