intel: Fix crash in intel_flush().
[mesa.git] / src / mesa / drivers / dri / intel / intel_context.c
index 0d9487b99ad3beff39b63c342be2226d8eff795f..e593b236a795763309eea3da0db55da756bf9eef 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "main/glheader.h"
 #include "main/context.h"
+#include "main/arrayobj.h"
 #include "main/extensions.h"
 #include "main/framebuffer.h"
 #include "main/imports.h"
@@ -66,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)
 {
@@ -123,6 +126,10 @@ intelGetString(GLcontext * ctx, GLenum name)
       case PCI_CHIP_Q33_G:
         chipset = "Intel(R) Q33";
         break;
+      case PCI_CHIP_IGD_GM:
+      case PCI_CHIP_IGD_G:
+        chipset = "Intel(R) IGD";
+        break;
       case PCI_CHIP_I965_Q:
         chipset = "Intel(R) 965Q";
         break;
@@ -154,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;
@@ -169,6 +179,24 @@ intelGetString(GLcontext * ctx, GLenum name)
    }
 }
 
+static unsigned
+intel_bits_per_pixel(const struct intel_renderbuffer *rb)
+{
+   switch (rb->Base._ActualFormat) {
+   case GL_RGB5:
+   case GL_DEPTH_COMPONENT16:
+      return 16;
+   case GL_RGB8:
+   case GL_RGBA8:
+   case GL_DEPTH_COMPONENT24:
+   case GL_DEPTH24_STENCIL8_EXT:
+   case GL_STENCIL_INDEX8_EXT:
+      return 32;
+   default:
+      return 0;
+   }
+}
+
 void
 intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
 {
@@ -176,7 +204,7 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
    struct intel_renderbuffer *rb;
    struct intel_region *region, *depth_region;
    struct intel_context *intel = context->driverPrivate;
-   __DRIbuffer *buffers;
+   __DRIbuffer *buffers = NULL;
    __DRIscreen *screen;
    int i, count;
    unsigned int attachments[10];
@@ -188,22 +216,65 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
 
    screen = intel->intelScreen->driScrnPriv;
 
-   i = 0;
-   if (intel_fb->color_rb[0])
-      attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
-   if (intel_fb->color_rb[1])
-      attachments[i++] = __DRI_BUFFER_BACK_LEFT;
-   if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH))
-      attachments[i++] = __DRI_BUFFER_DEPTH;
-   if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL))
-      attachments[i++] = __DRI_BUFFER_STENCIL;
-
-   buffers = (*screen->dri2.loader->getBuffers)(drawable,
-                                               &drawable->w,
-                                               &drawable->h,
-                                               attachments, i,
-                                               &count,
-                                               drawable->loaderPrivate);
+   if (screen->dri2.loader
+       && (screen->dri2.loader->base.version > 2)
+       && (screen->dri2.loader->getBuffersWithFormat != NULL)) {
+      struct intel_renderbuffer *depth_rb;
+      struct intel_renderbuffer *stencil_rb;
+
+      i = 0;
+      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]);
+      }
+
+      if (intel_fb->color_rb[1]) {
+        attachments[i++] = __DRI_BUFFER_BACK_LEFT;
+        attachments[i++] = intel_bits_per_pixel(intel_fb->color_rb[1]);
+      }
+
+      depth_rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH);
+      stencil_rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL);
+
+      if ((depth_rb != NULL) && (stencil_rb != NULL)) {
+        attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
+        attachments[i++] = intel_bits_per_pixel(depth_rb);
+      } else if (depth_rb != NULL) {
+        attachments[i++] = __DRI_BUFFER_DEPTH;
+        attachments[i++] = intel_bits_per_pixel(depth_rb);
+      } else if (stencil_rb != NULL) {
+        attachments[i++] = __DRI_BUFFER_STENCIL;
+        attachments[i++] = intel_bits_per_pixel(stencil_rb);
+      }
+
+      buffers =
+        (*screen->dri2.loader->getBuffersWithFormat)(drawable,
+                                                     &drawable->w,
+                                                     &drawable->h,
+                                                     attachments, i / 2,
+                                                     &count,
+                                                     drawable->loaderPrivate);
+   } else if (screen->dri2.loader) {
+      i = 0;
+      if (intel_fb->color_rb[0])
+        attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
+      if (intel_fb->color_rb[1])
+        attachments[i++] = __DRI_BUFFER_BACK_LEFT;
+      if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH))
+        attachments[i++] = __DRI_BUFFER_DEPTH;
+      if (intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL))
+        attachments[i++] = __DRI_BUFFER_STENCIL;
+
+      buffers = (*screen->dri2.loader->getBuffers)(drawable,
+                                                  &drawable->w,
+                                                  &drawable->h,
+                                                  attachments, i,
+                                                  &count,
+                                                  drawable->loaderPrivate);
+   }
 
    if (buffers == NULL)
       return;
@@ -231,6 +302,11 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
           region_name = "dri2 front buffer";
           break;
 
+       case __DRI_BUFFER_FAKE_FRONT_LEFT:
+          rb = intel_fb->color_rb[0];
+          region_name = "dri2 fake front buffer";
+          break;
+
        case __DRI_BUFFER_BACK_LEFT:
           rb = intel_fb->color_rb[1];
           region_name = "dri2 back buffer";
@@ -241,6 +317,11 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
           region_name = "dri2 depth buffer";
           break;
 
+       case __DRI_BUFFER_DEPTH_STENCIL:
+          rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH);
+          region_name = "dri2 depth / stencil buffer";
+          break;
+
        case __DRI_BUFFER_STENCIL:
           rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL);
           region_name = "dri2 stencil buffer";
@@ -254,6 +335,9 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
           return;
        }
 
+       if (rb == NULL)
+         continue;
+
        if (rb->region) {
          dri_bo_flink(rb->region->buffer, &name);
          if (name == buffers[i].name)
@@ -284,6 +368,23 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
 
        intel_renderbuffer_set_region(rb, region);
        intel_region_release(&region);
+
+       if (buffers[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) {
+         rb = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL);
+         if (rb != NULL) {
+            struct intel_region *stencil_region = NULL;
+
+            if (rb->region) {
+               dri_bo_flink(rb->region->buffer, &name);
+               if (name == buffers[i].name)
+                  continue;
+            }
+
+            intel_region_reference(&stencil_region, region);
+            intel_renderbuffer_set_region(rb, stencil_region);
+            intel_region_release(&stencil_region);
+         }
+       }
    }
 
    driUpdateFramebufferSize(&intel->ctx, drawable);
@@ -300,9 +401,20 @@ intel_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
     if (!driContext->driScreenPriv->dri2.enabled)
        return;
 
-    intel_update_renderbuffers(driContext, driContext->driDrawablePriv);
-    if (driContext->driDrawablePriv != driContext->driReadablePriv)
-       intel_update_renderbuffers(driContext, driContext->driReadablePriv);
+    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);
+    }
 
     old_viewport = ctx->Driver.Viewport;
     ctx->Driver.Viewport = NULL;
@@ -362,9 +474,8 @@ intelInvalidateState(GLcontext * ctx, GLuint new_state)
       intel->vtbl.invalidate_state( intel, new_state );
 }
 
-
-void
-intelFlush(GLcontext * ctx)
+static void
+intel_flush(GLcontext *ctx, GLboolean needs_mi_flush)
 {
    struct intel_context *intel = intel_context(ctx);
 
@@ -378,10 +489,65 @@ intelFlush(GLcontext * ctx)
     * lands onscreen in a timely manner, even if the X Server doesn't trigger
     * a flush for us.
     */
-   intel_batchbuffer_emit_mi_flush(intel->batch);
+   if (needs_mi_flush)
+      intel_batchbuffer_emit_mi_flush(intel->batch);
 
    if (intel->batch->map != intel->batch->ptr)
       intel_batchbuffer_flush(intel->batch);
+
+   if ((ctx->DrawBuffer->Name == 0) && intel->front_buffer_dirty) {
+      __DRIscreen *const screen = intel->intelScreen->driScrnPriv;
+
+      if (screen->dri2.loader &&
+          (screen->dri2.loader->base.version >= 2)
+         && (screen->dri2.loader->flushFrontBuffer != NULL) &&
+          intel->driDrawable && intel->driDrawable->loaderPrivate) {
+        (*screen->dri2.loader->flushFrontBuffer)(intel->driDrawable,
+                                                 intel->driDrawable->loaderPrivate);
+
+        /* Only clear the dirty bit if front-buffer rendering is no longer
+         * enabled.  This is done so that the dirty bit can only be set in
+         * glDrawBuffer.  Otherwise the dirty bit would have to be set at
+         * 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) {
+           intel->front_buffer_dirty = GL_FALSE;
+        }
+      }
+   }
+}
+
+void
+intelFlush(GLcontext * ctx)
+{
+   intel_flush(ctx, GL_FALSE);
+}
+
+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
@@ -397,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) {
@@ -410,7 +576,7 @@ intelInitDriverFunctions(struct dd_function_table *functions)
 {
    _mesa_init_driver_functions(functions);
 
-   functions->Flush = intelFlush;
+   functions->Flush = intel_glFlush;
    functions->Finish = intelFinish;
    functions->GetString = intelGetString;
    functions->UpdateState = intelInvalidateState;
@@ -481,16 +647,20 @@ intelInitContext(struct intel_context *intel,
       }
    }
 
-   ctx->Const.MaxTextureMaxAnisotropy = 2.0;
-
    /* This doesn't yet catch all non-conformant rendering, but it's a
     * start.
     */
    if (getenv("INTEL_STRICT_CONFORMANCE")) {
-      intel->strict_conformance = 1;
+      unsigned int value = atoi(getenv("INTEL_STRICT_CONFORMANCE"));
+      if (value > 0) {
+         intel->conformance_mode = value;
+      }
+      else {
+         intel->conformance_mode = 1;
+      }
    }
 
-   if (intel->strict_conformance) {
+   if (intel->conformance_mode > 0) {
       ctx->Const.MinLineWidth = 1.0;
       ctx->Const.MinLineWidthAA = 1.0;
       ctx->Const.MaxLineWidth = 1.0;
@@ -558,8 +728,6 @@ intelInitContext(struct intel_context *intel,
 
    intel->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS);
 
-   _math_matrix_ctr(&intel->ViewportMatrix);
-
    if (IS_965(intelScreen->deviceID) && !intel->intelScreen->irq_active) {
       _mesa_printf("IRQs not active.  Exiting\n");
       exit(1);
@@ -595,6 +763,16 @@ intelInitContext(struct intel_context *intel,
       intel->no_rast = 1;
    }
 
+   if (driQueryOptionb(&intel->optionCache, "always_flush_batch")) {
+      fprintf(stderr, "flushing batchbuffer before/after each draw call\n");
+      intel->always_flush_batch = 1;
+   }
+
+   if (driQueryOptionb(&intel->optionCache, "always_flush_cache")) {
+      fprintf(stderr, "flushing GPU caches before/after each draw call\n");
+      intel->always_flush_cache = 1;
+   }
+
    /* Disable all hardware rendering (skip emitting batches and fences/waits
     * to the kernel)
     */
@@ -615,6 +793,9 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv)
 
       INTEL_FIREVERTICES(intel);
 
+      if (intel->clear.arrayObj)
+         _mesa_delete_array_object(&intel->ctx, intel->clear.arrayObj);
+
       intel->vtbl.destroy(intel);
 
       release_texture_heaps = (intel->ctx.Shared->RefCount == 1);
@@ -632,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
@@ -649,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;
 }