Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / glx / dri3_glx.c
index 4472a0bed2676b3d7b009dcb5d201624dc833f44..fc8e8157618ff258be45a600604b7d08368bd30a 100644 (file)
 static struct dri3_drawable *
 loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) {
    size_t offset = offsetof(struct dri3_drawable, loader_drawable);
+   if (!draw)
+      return NULL;
    return (struct dri3_drawable *)(((void*) draw) - offset);
 }
 
-static int
-glx_dri3_get_swap_interval(struct loader_dri3_drawable *draw)
-{
-   struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw);
-
-   return priv->swap_interval;
-}
-
-static int
-glx_dri3_clamp_swap_interval(struct loader_dri3_drawable *draw, int interval)
-{
-   return interval;
-}
-
-static void
-glx_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval)
-{
-   struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw);
-
-   priv->swap_interval = interval;
-}
-
 static void
 glx_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
                            int width, int height)
@@ -117,6 +97,10 @@ static bool
 glx_dri3_in_current_context(struct loader_dri3_drawable *draw)
 {
    struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw);
+
+   if (!priv)
+      return false;
+
    struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
 
@@ -133,7 +117,7 @@ glx_dri3_get_dri_context(struct loader_dri3_drawable *draw)
 }
 
 static __DRIscreen *
-glx_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
+glx_dri3_get_dri_screen(void)
 {
    struct glx_context *gc = __glXGetCurrentContext();
    struct dri3_context *pcp = (struct dri3_context *) gc;
@@ -163,7 +147,7 @@ glx_dri3_show_fps(struct loader_dri3_drawable *draw, uint64_t current_ust)
    /* DRI3+Present together uses microseconds for UST. */
    if (priv->previous_ust + interval * 1000000 <= current_ust) {
       if (priv->previous_ust) {
-         fprintf(stderr, "libGL: FPS = %.1f\n",
+         fprintf(stderr, "libGL: FPS = %.2f\n",
                  ((uint64_t) priv->frames * 1000000) /
                  (double)(current_ust - priv->previous_ust));
       }
@@ -173,9 +157,6 @@ glx_dri3_show_fps(struct loader_dri3_drawable *draw, uint64_t current_ust)
 }
 
 static const struct loader_dri3_vtable glx_dri3_vtable = {
-   .get_swap_interval = glx_dri3_get_swap_interval,
-   .clamp_swap_interval = glx_dri3_clamp_swap_interval,
-   .set_swap_interval = glx_dri3_set_swap_interval,
    .set_drawable_size = glx_dri3_set_drawable_size,
    .in_current_context = glx_dri3_in_current_context,
    .get_dri_context = glx_dri3_get_dri_context,
@@ -229,6 +210,11 @@ dri3_bind_context(struct glx_context *context, struct glx_context *old,
    if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read))
       return GLXBadContext;
 
+   if (dri_draw)
+      psc->f->invalidate(dri_draw);
+   if (dri_read && dri_read != dri_draw)
+      psc->f->invalidate(dri_read);
+
    return Success;
 }
 
@@ -260,7 +246,8 @@ dri3_create_context_attribs(struct glx_screen *base,
    uint32_t flags = 0;
    unsigned api;
    int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
-   uint32_t ctx_attribs[2 * 5];
+   int release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
+   uint32_t ctx_attribs[2 * 6];
    unsigned num_ctx_attribs = 0;
    uint32_t render_type;
 
@@ -269,9 +256,13 @@ dri3_create_context_attribs(struct glx_screen *base,
    if (!dri2_convert_glx_attribs(num_attribs, attribs,
                                  &major_ver, &minor_ver,
                                  &render_type, &flags, &api,
-                                 &reset, error))
+                                 &reset, &release, error))
       goto error_exit;
 
+   if (!dri2_check_no_error(flags, shareList, major_ver, error)) {
+      goto error_exit;
+   }
+
    /* Check the renderType value */
    if (!validate_renderType_against_config(config_base, render_type))
        goto error_exit;
@@ -287,7 +278,7 @@ dri3_create_context_attribs(struct glx_screen *base,
       goto error_exit;
    }
 
-   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
+   if (!glx_context_init(&pcp->base, &psc->base, config_base))
       goto error_exit;
 
    ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
@@ -304,6 +295,11 @@ dri3_create_context_attribs(struct glx_screen *base,
       ctx_attribs[num_ctx_attribs++] = reset;
    }
 
+   if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
+      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
+      ctx_attribs[num_ctx_attribs++] = release;
+   }
+
    if (flags != 0) {
       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
 
@@ -311,12 +307,16 @@ dri3_create_context_attribs(struct glx_screen *base,
        * GLX_CONTEXT_*_BIT values.
        */
       ctx_attribs[num_ctx_attribs++] = flags;
+
+      if (flags & __DRI_CTX_FLAG_NO_ERROR)
+         pcp->base.noError = GL_TRUE;
    }
 
    pcp->driContext =
       (*psc->image_driver->createContextAttribs) (psc->driScreen,
                                                   api,
-                                                  config->driConfig,
+                                                  config ? config->driConfig
+                                                         : NULL,
                                                   shared,
                                                   num_ctx_attribs / 2,
                                                   ctx_attribs,
@@ -342,9 +342,10 @@ dri3_create_context(struct glx_screen *base,
                     struct glx_context *shareList, int renderType)
 {
    unsigned int error;
+   uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType };
 
    return dri3_create_context_attribs(base, config_base, shareList,
-                                      0, NULL, &error);
+                                      1, attribs, &error);
 }
 
 static void
@@ -364,6 +365,11 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
    struct dri3_drawable *pdraw;
    struct dri3_screen *psc = (struct dri3_screen *) base;
    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+   bool has_multibuffer = false;
+#ifdef HAVE_DRI3_MODIFIERS
+   const struct dri3_display *const pdp = (struct dri3_display *)
+      base->display->dri3Display;
+#endif
 
    pdraw = calloc(1, sizeof(*pdraw));
    if (!pdraw)
@@ -374,11 +380,20 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
    pdraw->base.drawable = drawable;
    pdraw->base.psc = &psc->base;
 
+#ifdef HAVE_DRI3_MODIFIERS
+   if ((psc->image && psc->image->base.version >= 15) &&
+       (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 2)) &&
+       (pdp->presentMajor > 1 ||
+        (pdp->presentMajor == 1 && pdp->presentMinor >= 2)))
+      has_multibuffer = true;
+#endif
+
    (void) __glXInitialize(psc->base.dpy);
 
    if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy),
                                  xDrawable, psc->driScreen,
-                                 psc->is_different_gpu, config->driConfig,
+                                 psc->is_different_gpu, has_multibuffer,
+                                 config->driConfig,
                                  &psc->loader_dri3_ext, &glx_dri3_vtable,
                                  &pdraw->loader_drawable)) {
       free(pdraw);
@@ -487,26 +502,78 @@ dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
 
    loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
 
+   psc->f->invalidate(driDrawable);
    loader_dri3_wait_gl(draw);
 }
 
+/**
+ * Make sure all pending swapbuffers have been submitted to hardware
+ *
+ * \param driDrawable[in]  Pointer to the dri drawable whose swaps we are
+ * flushing.
+ * \param loaderPrivate[in]  Pointer to the corresponding struct
+ * loader_dri_drawable.
+ */
+static void
+dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate)
+{
+   struct loader_dri3_drawable *draw = loaderPrivate;
+   struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw);
+   struct dri3_screen *psc;
+
+   if (!pdraw)
+      return;
+
+   if (!pdraw->base.psc)
+      return;
+
+   psc = (struct dri3_screen *) pdraw->base.psc;
+
+   (void) __glXInitialize(psc->base.dpy);
+   loader_dri3_swapbuffer_barrier(draw);
+}
+
+static void
+dri_set_background_context(void *loaderPrivate)
+{
+   struct dri3_context *pcp = (struct dri3_context *)loaderPrivate;
+   __glXSetCurrentContext(&pcp->base);
+}
+
+static GLboolean
+dri_is_thread_safe(void *loaderPrivate)
+{
+   /* Unlike DRI2, DRI3 doesn't call GetBuffers/GetBuffersWithFormat
+    * during draw so we're safe here.
+    */
+   return true;
+}
+
 /* The image loader extension record for DRI3
  */
 static const __DRIimageLoaderExtension imageLoaderExtension = {
-   .base = { __DRI_IMAGE_LOADER, 1 },
+   .base = { __DRI_IMAGE_LOADER, 3 },
 
    .getBuffers          = loader_dri3_get_buffers,
    .flushFrontBuffer    = dri3_flush_front_buffer,
+   .flushSwapBuffers    = dri3_flush_swap_buffers,
 };
 
 const __DRIuseInvalidateExtension dri3UseInvalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
 };
 
+static const __DRIbackgroundCallableExtension driBackgroundCallable = {
+   .base = { __DRI_BACKGROUND_CALLABLE, 2 },
+
+   .setBackgroundContext = dri_set_background_context,
+   .isThreadSafe         = dri_is_thread_safe,
+};
+
 static const __DRIextension *loader_extensions[] = {
    &imageLoaderExtension.base,
-   &systemTimeExtension.base,
    &dri3UseInvalidate.base,
+   &driBackgroundCallable.base,
    NULL
 };
 
@@ -526,7 +593,7 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
 
    return loader_dri3_swap_buffers_msc(&priv->loader_drawable,
                                        target_msc, divisor, remainder,
-                                       flags, false);
+                                       flags, NULL, 0, false);
 }
 
 static int
@@ -545,6 +612,7 @@ dri3_destroy_screen(struct glx_screen *base)
    struct dri3_screen *psc = (struct dri3_screen *) base;
 
    /* Free the direct rendering per screen data */
+   loader_dri3_close_screen(psc->driScreen);
    (*psc->core->destroyScreen) (psc->driScreen);
    driDestroyConfigs(psc->driver_configs);
    close(psc->fd);
@@ -558,6 +626,8 @@ dri3_destroy_screen(struct glx_screen *base)
 static int
 dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
 {
+   assert(pdraw != NULL);
+
    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
    GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
@@ -591,9 +661,11 @@ dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
 static int
 dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
 {
+   assert(pdraw != NULL);
+
    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
 
-  return priv->swap_interval;
+  return priv->loader_drawable.swap_interval;
 }
 
 static void
@@ -610,7 +682,7 @@ dri3_bind_tex_image(Display * dpy,
    if (pdraw != NULL) {
       psc = (struct dri3_screen *) base->psc;
 
-      (*psc->f->invalidate)(pdraw->loader_drawable.dri_drawable);
+      psc->f->invalidate(pdraw->loader_drawable.dri_drawable);
 
       XSync(dpy, false);
 
@@ -669,7 +741,6 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
 
    extensions = psc->core->getExtensions(psc->driScreen);
 
-   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
@@ -715,6 +786,10 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
          __glXEnableDirectExtension(&psc->base,
                                     "GLX_ARB_create_context_robustness");
 
+      if (strcmp(extensions[i]->name, __DRI2_NO_ERROR) == 0)
+         __glXEnableDirectExtension(&psc->base,
+                                    "GLX_ARB_create_context_no_error");
+
       if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
          psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
          __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
@@ -722,6 +797,10 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
 
       if (strcmp(extensions[i]->name, __DRI2_INTEROP) == 0)
         psc->interop = (__DRI2interopExtension*)extensions[i];
+
+      if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0)
+         __glXEnableDirectExtension(&psc->base,
+                                    "GLX_ARB_context_flush_control");
    }
 }
 
@@ -755,8 +834,9 @@ dri3_create_screen(int screen, struct glx_display * priv)
    struct dri3_screen *psc;
    __GLXDRIscreen *psp;
    struct glx_config *configs = NULL, *visuals = NULL;
-   char *driverName, *deviceName, *tmp;
+   char *driverName, *tmp;
    int i;
+   unsigned char disable;
 
    psc = calloc(1, sizeof *psc);
    if (psc == NULL)
@@ -784,7 +864,6 @@ dri3_create_screen(int screen, struct glx_display * priv)
    }
 
    psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu);
-   deviceName = NULL;
 
    driverName = loader_get_driver_for_fd(psc->fd);
    if (!driverName) {
@@ -792,13 +871,7 @@ dri3_create_screen(int screen, struct glx_display * priv)
       goto handle_error;
    }
 
-   psc->driver = driOpenDriver(driverName);
-   if (psc->driver == NULL) {
-      ErrorMessageF("driver pointer missing\n");
-      goto handle_error;
-   }
-
-   extensions = driGetDriverExtensions(psc->driver, driverName);
+   extensions = driOpenDriver(driverName, &psc->driver);
    if (extensions == NULL)
       goto handle_error;
 
@@ -895,16 +968,26 @@ dri3_create_screen(int screen, struct glx_display * priv)
    psp->waitForSBC = dri3_wait_for_sbc;
    psp->setSwapInterval = dri3_set_swap_interval;
    psp->getSwapInterval = dri3_get_swap_interval;
-   __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
+   if (psc->config->configQueryb(psc->driScreen,
+                                 "glx_disable_oml_sync_control",
+                                 &disable) || !disable)
+      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
+
+   if (psc->config->configQueryb(psc->driScreen,
+                                 "glx_disable_sgi_video_sync",
+                                 &disable) || !disable)
+      __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
 
    psp->copySubBuffer = dri3_copy_sub_buffer;
    __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
 
    psp->getBufferAge = dri3_get_buffer_age;
-   __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
+   if (psc->config->configQueryb(psc->driScreen,
+                                 "glx_disable_ext_buffer_age",
+                                 &disable) || !disable)
+      __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
 
    free(driverName);
-   free(deviceName);
 
    tmp = getenv("LIBGL_SHOW_FPS");
    psc->show_fps_interval = tmp ? atoi(tmp) : 0;
@@ -916,7 +999,7 @@ dri3_create_screen(int screen, struct glx_display * priv)
    return &psc->base;
 
 handle_error:
-   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
+   CriticalErrorMessageF("failed to load driver: %s\n", driverName ? driverName : "(null)");
 
    if (configs)
        glx_config_destroy_list(configs);
@@ -931,7 +1014,6 @@ handle_error:
       dlclose(psc->driver);
 
    free(driverName);
-   free(deviceName);
    glx_screen_cleanup(&psc->base);
    free(psc);
 
@@ -948,6 +1030,18 @@ dri3_destroy_display(__GLXDRIdisplay * dpy)
    free(dpy);
 }
 
+/* Only request versions of these protocols which we actually support. */
+#define DRI3_SUPPORTED_MAJOR 1
+#define PRESENT_SUPPORTED_MAJOR 1
+
+#ifdef HAVE_DRI3_MODIFIERS
+#define DRI3_SUPPORTED_MINOR 2
+#define PRESENT_SUPPORTED_MINOR 2
+#else
+#define PRESENT_SUPPORTED_MINOR 0
+#define DRI3_SUPPORTED_MINOR 0
+#endif
+
 /** dri3_create_display
  *
  * Allocate, initialize and return a __DRIdisplayPrivate object.
@@ -979,13 +1073,11 @@ dri3_create_display(Display * dpy)
       return NULL;
 
    dri3_cookie = xcb_dri3_query_version(c,
-                                        XCB_DRI3_MAJOR_VERSION,
-                                        XCB_DRI3_MINOR_VERSION);
-
-
+                                        DRI3_SUPPORTED_MAJOR,
+                                        DRI3_SUPPORTED_MINOR);
    present_cookie = xcb_present_query_version(c,
-                                   XCB_PRESENT_MAJOR_VERSION,
-                                   XCB_PRESENT_MINOR_VERSION);
+                                              PRESENT_SUPPORTED_MAJOR,
+                                              PRESENT_SUPPORTED_MINOR);
 
    pdp = malloc(sizeof *pdp);
    if (pdp == NULL)
@@ -1013,8 +1105,6 @@ dri3_create_display(Display * dpy)
    pdp->base.destroyDisplay = dri3_destroy_display;
    pdp->base.createScreen = dri3_create_screen;
 
-   loader_set_logger(dri_message);
-
    pdp->loader_extensions = loader_extensions;
 
    return &pdp->base;