intel: Fix crash in intel_flush().
[mesa.git] / src / mesa / drivers / dri / intel / intel_context.c
index 07d53aad23f59ad20ca356e8a61b92da7f760195..e593b236a795763309eea3da0db55da756bf9eef 100644 (file)
@@ -67,10 +67,12 @@ int INTEL_DEBUG = (0);
 #endif
 
 
-#define DRIVER_DATE                     "20090114"
+#define DRIVER_DATE                     "20090712 2009Q2 RC3"
 #define DRIVER_DATE_GEM                 "GEM " DRIVER_DATE
 
 
+static void intel_flush(GLcontext *ctx, GLboolean needs_mi_flush);
+
 static const GLubyte *
 intelGetString(GLcontext * ctx, GLenum name)
 {
@@ -159,6 +161,9 @@ intelGetString(GLcontext * ctx, GLenum name)
       case PCI_CHIP_G41_G:
          chipset = "Intel(R) G41";
          break;
+      case PCI_CHIP_B43_G:
+         chipset = "Intel(R) B43";
+         break;
       default:
          chipset = "Unknown Intel Chipset";
          break;
@@ -218,7 +223,9 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
       struct intel_renderbuffer *stencil_rb;
 
       i = 0;
-      if ((intel->is_front_buffer_rendering || !intel_fb->color_rb[1])
+      if ((intel->is_front_buffer_rendering ||
+          intel->is_front_buffer_reading ||
+          !intel_fb->color_rb[1])
           && intel_fb->color_rb[0]) {
         attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
         attachments[i++] = intel_bits_per_pixel(intel_fb->color_rb[0]);
@@ -394,7 +401,16 @@ intel_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
     if (!driContext->driScreenPriv->dri2.enabled)
        return;
 
-    if (!intel->internal_viewport_call) {
+    if (!intel->internal_viewport_call && ctx->DrawBuffer->Name == 0) {
+       /* If we're rendering to the fake front buffer, make sure all the pending
+       * drawing has landed on the real front buffer.  Otherwise when we
+       * eventually get to DRI2GetBuffersWithFormat the stale real front
+       * buffer contents will get copied to the new fake front buffer.
+       */
+       if (intel->is_front_buffer_rendering) {
+         intel_flush(ctx, GL_FALSE);
+       }
+
        intel_update_renderbuffers(driContext, driContext->driDrawablePriv);
        if (driContext->driDrawablePriv != driContext->driReadablePriv)
          intel_update_renderbuffers(driContext, driContext->driReadablePriv);
@@ -484,7 +500,8 @@ intel_flush(GLcontext *ctx, GLboolean needs_mi_flush)
 
       if (screen->dri2.loader &&
           (screen->dri2.loader->base.version >= 2)
-         && (screen->dri2.loader->flushFrontBuffer != NULL)) {
+         && (screen->dri2.loader->flushFrontBuffer != NULL) &&
+          intel->driDrawable && intel->driDrawable->loaderPrivate) {
         (*screen->dri2.loader->flushFrontBuffer)(intel->driDrawable,
                                                  intel->driDrawable->loaderPrivate);
 
@@ -494,7 +511,7 @@ intel_flush(GLcontext *ctx, GLboolean needs_mi_flush)
          * each of N places that do rendering.  This has worse performances,
          * but it is much easier to get correct.
          */
-        if (intel->is_front_buffer_rendering) {
+        if (!intel->is_front_buffer_rendering) {
            intel->front_buffer_dirty = GL_FALSE;
         }
       }
@@ -510,7 +527,27 @@ intelFlush(GLcontext * ctx)
 static void
 intel_glFlush(GLcontext *ctx)
 {
+   struct intel_context *intel = intel_context(ctx);
+
    intel_flush(ctx, GL_TRUE);
+
+   /* We're using glFlush as an indicator that a frame is done, which is
+    * what DRI2 does before calling SwapBuffers (and means we should catch
+    * people doing front-buffer rendering, as well)..
+    *
+    * Wait for the swapbuffers before the one we just emitted, so we don't
+    * get too many swaps outstanding for apps that are GPU-heavy but not
+    * CPU-heavy.
+    *
+    * Unfortunately, we don't have a handle to the batch containing the swap,
+    * and getting our hands on that doesn't seem worth it, so we just us the
+    * first batch we emitted after the last swap.
+    */
+   if (intel->first_post_swapbuffers_batch != NULL) {
+      drm_intel_bo_wait_rendering(intel->first_post_swapbuffers_batch);
+      drm_intel_bo_unreference(intel->first_post_swapbuffers_batch);
+      intel->first_post_swapbuffers_batch = NULL;
+   }
 }
 
 void
@@ -526,7 +563,7 @@ intelFinish(GLcontext * ctx)
 
        irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]);
 
-       if (irb->region)
+       if (irb && irb->region)
          dri_bo_wait_rendering(irb->region->buffer);
    }
    if (fb->_DepthBuffer) {
@@ -756,7 +793,8 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv)
 
       INTEL_FIREVERTICES(intel);
 
-      _mesa_delete_array_object(&intel->ctx, intel->clear.arrayObj);
+      if (intel->clear.arrayObj)
+         _mesa_delete_array_object(&intel->ctx, intel->clear.arrayObj);
 
       intel->vtbl.destroy(intel);
 
@@ -775,6 +813,8 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv)
       intel->prim.vb = NULL;
       dri_bo_unreference(intel->prim.vb_bo);
       intel->prim.vb_bo = NULL;
+      dri_bo_unreference(intel->first_post_swapbuffers_batch);
+      intel->first_post_swapbuffers_batch = NULL;
 
       if (release_texture_heaps) {
          /* This share group is about to go away, free our private
@@ -792,12 +832,23 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv)
 
       /* free the Mesa context */
       _mesa_free_context_data(&intel->ctx);
+
+      FREE(intel);
+      driContextPriv->driverPrivate = NULL;
    }
 }
 
 GLboolean
 intelUnbindContext(__DRIcontextPrivate * driContextPriv)
 {
+   struct intel_context *intel =
+      (struct intel_context *) driContextPriv->driverPrivate;
+
+   /* Deassociate the context with the drawables.
+    */
+   intel->driDrawable = NULL;
+   intel->driReadDrawable = NULL;
+
    return GL_TRUE;
 }