Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / mesa / drivers / dri / intel / intel_context.c
index 0a7dcb80c6bc695d858ef3672decfca0b3dea425..152cdcaf37d69b73fbc166a27413697c0e5cf0b5 100644 (file)
@@ -29,6 +29,7 @@
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/extensions.h"
+#include "main/fbobject.h"
 #include "main/framebuffer.h"
 #include "main/imports.h"
 #include "main/points.h"
@@ -39,8 +40,6 @@
 #include "drivers/common/driverfuncs.h"
 #include "drivers/common/meta.h"
 
-#include "i830_dri.h"
-
 #include "intel_chipset.h"
 #include "intel_buffers.h"
 #include "intel_tex.h"
@@ -63,12 +62,12 @@ int INTEL_DEBUG = (0);
 #endif
 
 
-#define DRIVER_DATE                     "20100328 2010Q1"
+#define DRIVER_DATE                     "20100330 DEVELOPMENT"
 #define DRIVER_DATE_GEM                 "GEM " DRIVER_DATE
 
 
 static const GLubyte *
-intelGetString(GLcontext * ctx, GLenum name)
+intelGetString(struct gl_context * ctx, GLenum name)
 {
    const struct intel_context *const intel = intel_context(ctx);
    const char *chipset;
@@ -156,14 +155,28 @@ intelGetString(GLcontext * ctx, GLenum name)
          chipset = "Intel(R) G41";
          break;
       case PCI_CHIP_B43_G:
+      case PCI_CHIP_B43_G1:
          chipset = "Intel(R) B43";
          break;
       case PCI_CHIP_ILD_G:
-         chipset = "Intel(R) IGDNG_D";
+         chipset = "Intel(R) Ironlake Desktop";
          break;
       case PCI_CHIP_ILM_G:
-         chipset = "Intel(R) IGDNG_M";
+         chipset = "Intel(R) Ironlake Mobile";
          break;
+      case PCI_CHIP_SANDYBRIDGE_GT1:
+      case PCI_CHIP_SANDYBRIDGE_GT2:
+      case PCI_CHIP_SANDYBRIDGE_GT2_PLUS:
+        chipset = "Intel(R) Sandybridge Desktop";
+        break;
+      case PCI_CHIP_SANDYBRIDGE_M_GT1:
+      case PCI_CHIP_SANDYBRIDGE_M_GT2:
+      case PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS:
+        chipset = "Intel(R) Sandybridge Mobile";
+        break;
+      case PCI_CHIP_SANDYBRIDGE_S:
+        chipset = "Intel(R) Sandybridge Server";
+        break;
       default:
          chipset = "Unknown Intel Chipset";
          break;
@@ -177,6 +190,30 @@ intelGetString(GLcontext * ctx, GLenum name)
    }
 }
 
+static void
+intel_flush_front(struct gl_context *ctx)
+{
+   struct intel_context *intel = intel_context(ctx);
+    __DRIcontext *driContext = intel->driContext;
+    __DRIscreen *const screen = intel->intelScreen->driScrnPriv;
+
+   if ((ctx->DrawBuffer->Name == 0) && intel->front_buffer_dirty) {
+      if (screen->dri2.loader &&
+          (screen->dri2.loader->base.version >= 2)
+         && (screen->dri2.loader->flushFrontBuffer != NULL) &&
+          driContext->driDrawablePriv &&
+         driContext->driDrawablePriv->loaderPrivate) {
+        (*screen->dri2.loader->flushFrontBuffer)(driContext->driDrawablePriv,
+                                                 driContext->driDrawablePriv->loaderPrivate);
+
+        /* We set the dirty bit in intel_prepare_render() if we're
+         * front buffer rendering once we get there.
+         */
+        intel->front_buffer_dirty = GL_FALSE;
+      }
+   }
+}
+
 static unsigned
 intel_bits_per_pixel(const struct intel_renderbuffer *rb)
 {
@@ -203,15 +240,17 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
     * real front buffer contents will get copied to the new fake front
     * buffer.
     */
-   if (intel->is_front_buffer_rendering)
-      intel_flush(&intel->ctx, GL_FALSE);
+   if (intel->is_front_buffer_rendering) {
+      intel_flush(&intel->ctx);
+      intel_flush_front(&intel->ctx);
+   }
 
    /* Set this up front, so that in case our buffers get invalidated
     * while we're getting new buffers, we don't clobber the stamp and
     * thus ignore the invalidate. */
    drawable->lastStamp = drawable->dri2.stamp;
 
-   if (INTEL_DEBUG & DEBUG_DRI)
+   if (unlikely(INTEL_DEBUG & DEBUG_DRI))
       fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
 
    screen = intel->intelScreen->driScrnPriv;
@@ -329,7 +368,7 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
        case __DRI_BUFFER_ACCUM:
        default:
           fprintf(stderr,
-                  "unhandled buffer attach event, attacment type %d\n",
+                  "unhandled buffer attach event, attachment type %d\n",
                   buffers[i].attachment);
           return;
        }
@@ -340,19 +379,20 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
        if (rb->region && rb->region->name == buffers[i].name)
             continue;
 
-       if (INTEL_DEBUG & DEBUG_DRI)
+       if (unlikely(INTEL_DEBUG & DEBUG_DRI))
          fprintf(stderr,
                  "attaching buffer %d, at %d, cpp %d, pitch %d\n",
                  buffers[i].name, buffers[i].attachment,
                  buffers[i].cpp, buffers[i].pitch);
        
        if (buffers[i].attachment == __DRI_BUFFER_STENCIL && depth_region) {
-         if (INTEL_DEBUG & DEBUG_DRI)
+         if (unlikely(INTEL_DEBUG & DEBUG_DRI))
             fprintf(stderr, "(reusing depth buffer as stencil)\n");
          intel_region_reference(&region, depth_region);
        }
        else
-          region = intel_region_alloc_for_handle(intel, buffers[i].cpp,
+          region = intel_region_alloc_for_handle(intel->intelScreen,
+                                                buffers[i].cpp,
                                                 drawable->w,
                                                 drawable->h,
                                                 buffers[i].pitch / buffers[i].cpp,
@@ -362,7 +402,7 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
        if (buffers[i].attachment == __DRI_BUFFER_DEPTH)
          depth_region = region;
 
-       intel_renderbuffer_set_region(rb, region);
+       intel_renderbuffer_set_region(intel, rb, region);
        intel_region_release(&region);
 
        if (buffers[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) {
@@ -374,7 +414,7 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
                   continue;
 
             intel_region_reference(&stencil_region, region);
-            intel_renderbuffer_set_region(rb, stencil_region);
+            intel_renderbuffer_set_region(intel, rb, stencil_region);
             intel_region_release(&stencil_region);
          }
        }
@@ -383,36 +423,71 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
    driUpdateFramebufferSize(&intel->ctx, drawable);
 }
 
+/**
+ * intel_prepare_render should be called anywhere that curent read/drawbuffer
+ * state is required.
+ */
 void
 intel_prepare_render(struct intel_context *intel)
 {
    __DRIcontext *driContext = intel->driContext;
    __DRIdrawable *drawable;
 
-   drawable = intel->driDrawable;
-   if (drawable->dri2.stamp != driContext->dri2.draw_stamp) {
+   drawable = driContext->driDrawablePriv;
+   if (drawable && drawable->dri2.stamp != driContext->dri2.draw_stamp) {
       if (drawable->lastStamp != drawable->dri2.stamp)
         intel_update_renderbuffers(driContext, drawable);
       intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
       driContext->dri2.draw_stamp = drawable->dri2.stamp;
    }
 
-   drawable = intel->driReadDrawable;
-   if (drawable->dri2.stamp != driContext->dri2.read_stamp) {
+   drawable = driContext->driReadablePriv;
+   if (drawable && drawable->dri2.stamp != driContext->dri2.read_stamp) {
       if (drawable->lastStamp != drawable->dri2.stamp)
         intel_update_renderbuffers(driContext, drawable);
       driContext->dri2.read_stamp = drawable->dri2.stamp;
    }
+
+   /* If we're currently rendering to the front buffer, the rendering
+    * that will happen next will probably dirty the front buffer.  So
+    * mark it as dirty here.
+    */
+   if (intel->is_front_buffer_rendering)
+      intel->front_buffer_dirty = GL_TRUE;
+
+   /* 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.
+    *
+    * We're using intelDRI2Flush (called from the loader before
+    * swapbuffer) and glFlush (for front buffer rendering) as the
+    * indicator that a frame is done and then throttle when we get
+    * here as we prepare to render the next frame.  At this point for
+    * round trips for swap/copy and getting new buffers are done and
+    * we'll spend less time waiting on the GPU.
+    *
+    * 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->need_throttle && intel->first_post_swapbuffers_batch) {
+      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;
+      intel->need_throttle = GL_FALSE;
+   }
 }
 
-void
-intel_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+static void
+intel_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
 {
     struct intel_context *intel = intel_context(ctx);
     __DRIcontext *driContext = intel->driContext;
 
-    if (!intel->using_dri2_swapbuffers &&
-       !intel->meta.internal_viewport_call && ctx->DrawBuffer->Name == 0) {
+    if (intel->saved_viewport)
+       intel->saved_viewport(ctx, x, y, w, h);
+
+    if (!intel->meta.internal_viewport_call && ctx->DrawBuffer->Name == 0) {
        dri2InvalidateDrawable(driContext->driDrawablePriv);
        dri2InvalidateDrawable(driContext->driReadablePriv);
     }
@@ -431,12 +506,12 @@ static const struct dri_debug_control debug_control[] = {
    { "buf",   DEBUG_BUFMGR},
    { "reg",   DEBUG_REGION},
    { "fbo",   DEBUG_FBO},
-   { "lock",  DEBUG_LOCK},
+   { "gs",    DEBUG_GS},
    { "sync",  DEBUG_SYNC},
    { "prim",  DEBUG_PRIMS },
    { "vert",  DEBUG_VERTS },
    { "dri",   DEBUG_DRI },
-   { "dma",   DEBUG_DMA },
+   { "sf",    DEBUG_SF },
    { "san",   DEBUG_SANITY },
    { "sleep", DEBUG_SLEEP },
    { "stats", DEBUG_STATS },
@@ -444,14 +519,16 @@ static const struct dri_debug_control debug_control[] = {
    { "sing",  DEBUG_SINGLE_THREAD },
    { "thre",  DEBUG_SINGLE_THREAD },
    { "wm",    DEBUG_WM },
+   { "glsl_force", DEBUG_GLSL_FORCE },
    { "urb",   DEBUG_URB },
    { "vs",    DEBUG_VS },
+   { "clip",  DEBUG_CLIP },
    { NULL,    0 }
 };
 
 
 static void
-intelInvalidateState(GLcontext * ctx, GLuint new_state)
+intelInvalidateState(struct gl_context * ctx, GLuint new_state)
 {
     struct intel_context *intel = intel_context(ctx);
 
@@ -468,7 +545,7 @@ intelInvalidateState(GLcontext * ctx, GLuint new_state)
 }
 
 void
-intel_flush(GLcontext *ctx, GLboolean needs_mi_flush)
+intel_flush(struct gl_context *ctx)
 {
    struct intel_context *intel = intel_context(ctx);
 
@@ -480,70 +557,26 @@ intel_flush(GLcontext *ctx, GLboolean needs_mi_flush)
 
    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)
+intel_glFlush(struct gl_context *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->using_dri2_swapbuffers &&
-       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;
-   }
+   intel_flush(ctx);
+   intel_flush_front(ctx);
+   intel->need_throttle = GL_TRUE;
 }
 
 void
-intelFinish(GLcontext * ctx)
+intelFinish(struct gl_context * ctx)
 {
    struct gl_framebuffer *fb = ctx->DrawBuffer;
    int i;
 
-   intelFlush(ctx);
+   intel_flush(ctx);
+   intel_flush_front(ctx);
 
    for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
        struct intel_renderbuffer *irb;
@@ -551,7 +584,7 @@ intelFinish(GLcontext * ctx)
        irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]);
 
        if (irb && irb->region)
-         dri_bo_wait_rendering(irb->region->buffer);
+         drm_intel_bo_wait_rendering(irb->region->buffer);
    }
    if (fb->_DepthBuffer) {
       /* XXX: Wait on buffer idle */
@@ -583,39 +616,60 @@ intelInitDriverFunctions(struct dd_function_table *functions)
 
 GLboolean
 intelInitContext(struct intel_context *intel,
-                 const __GLcontextModes * mesaVis,
+                int api,
+                 const struct gl_config * mesaVis,
                  __DRIcontext * driContextPriv,
                  void *sharedContextPrivate,
                  struct dd_function_table *functions)
 {
-   GLcontext *ctx = &intel->ctx;
-   GLcontext *shareCtx = (GLcontext *) sharedContextPrivate;
+   struct gl_context *ctx = &intel->ctx;
+   struct gl_context *shareCtx = (struct gl_context *) sharedContextPrivate;
    __DRIscreen *sPriv = driContextPriv->driScreenPriv;
    struct intel_screen *intelScreen = sPriv->private;
    int bo_reuse_mode;
+   struct gl_config visual;
 
    /* we can't do anything without a connection to the device */
    if (intelScreen->bufmgr == NULL)
       return GL_FALSE;
 
-   if (!_mesa_initialize_context(&intel->ctx, mesaVis, shareCtx,
-                                 functions, (void *) intel)) {
+   /* Can't rely on invalidate events, fall back to glViewport hack */
+   if (!driContextPriv->driScreenPriv->dri2.useInvalidate) {
+      intel->saved_viewport = functions->Viewport;
+      functions->Viewport = intel_viewport;
+   }
+
+   if (mesaVis == NULL) {
+      memset(&visual, 0, sizeof visual);
+      mesaVis = &visual;
+   }
+
+   if (!_mesa_initialize_context_for_api(&intel->ctx, api, mesaVis, shareCtx,
+                                        functions, (void *) intel)) {
       printf("%s: failed to init mesa context\n", __FUNCTION__);
       return GL_FALSE;
    }
 
    driContextPriv->driverPrivate = intel;
    intel->intelScreen = intelScreen;
-   intel->driScreen = sPriv;
    intel->driContext = driContextPriv;
    intel->driFd = sPriv->fd;
 
+   intel->has_xrgb_textures = GL_TRUE;
    if (IS_GEN6(intel->intelScreen->deviceID)) {
       intel->gen = 6;
       intel->needs_ff_sync = GL_TRUE;
       intel->has_luminance_srgb = GL_TRUE;
+   } else if (IS_GEN5(intel->intelScreen->deviceID)) {
+      intel->gen = 5;
+      intel->needs_ff_sync = GL_TRUE;
+      intel->has_luminance_srgb = GL_TRUE;
    } else if (IS_965(intel->intelScreen->deviceID)) {
       intel->gen = 4;
+      if (IS_G4X(intel->intelScreen->deviceID)) {
+         intel->has_luminance_srgb = GL_TRUE;
+         intel->is_g4x = GL_TRUE;
+      }
    } else if (IS_9XX(intel->intelScreen->deviceID)) {
       intel->gen = 3;
       if (IS_945(intel->intelScreen->deviceID)) {
@@ -623,20 +677,14 @@ intelInitContext(struct intel_context *intel,
       }
    } else {
       intel->gen = 2;
-   }
-
-   if (IS_IGDNG(intel->intelScreen->deviceID)) {
-      intel->is_ironlake = GL_TRUE;
-      intel->needs_ff_sync = GL_TRUE;
-      intel->has_luminance_srgb = GL_TRUE;
-   } else if (IS_G4X(intel->intelScreen->deviceID)) {
-      intel->has_luminance_srgb = GL_TRUE;
-      intel->is_g4x = GL_TRUE;
+      if (intel->intelScreen->deviceID == PCI_CHIP_I830_M ||
+         intel->intelScreen->deviceID == PCI_CHIP_845_G) {
+        intel->has_xrgb_textures = GL_FALSE;
+      }
    }
 
    driParseConfigFiles(&intel->optionCache, &intelScreen->optionCache,
-                       intel->driScreen->myNum,
-                      (intel->gen >= 4) ? "i965" : "i915");
+                       sPriv->myNum, (intel->gen >= 4) ? "i965" : "i915");
    if (intelScreen->deviceID == PCI_CHIP_I865_G)
       intel->maxBatchSize = 4096;
    else
@@ -687,13 +735,14 @@ intelInitContext(struct intel_context *intel,
    ctx->Const.MaxPointSizeAA = 3.0;
    ctx->Const.PointSizeGranularity = 1.0;
 
+   ctx->Const.MaxSamples = 1.0;
+
    /* reinitialize the context point state.
-    * It depend on constants in __GLcontextRec::Const
+    * It depend on constants in __struct gl_contextRec::Const
     */
    _mesa_init_point(ctx);
 
    meta_init_metaops(ctx, &intel->meta);
-   ctx->Const.MaxColorAttachments = 4;  /* XXX FBO: review this */
    if (intel->gen >= 4) {
       if (MAX_WIDTH > 8192)
         ctx->Const.MaxRenderbufferSize = 8192;
@@ -736,12 +785,26 @@ intelInitContext(struct intel_context *intel,
 
    intel->RenderIndex = ~0;
 
-   intelInitExtensions(ctx);
+   switch (ctx->API) {
+   case API_OPENGL:
+      intelInitExtensions(ctx);
+      break;
+   case API_OPENGLES:
+      break;
+   case API_OPENGLES2:
+      intelInitExtensionsES2(ctx);
+      break;
+   }
 
    INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
    if (INTEL_DEBUG & DEBUG_BUFMGR)
       dri_bufmgr_set_debug(intel->bufmgr, GL_TRUE);
 
+   /* XXX force SIMD8 kernel for Sandybridge before we fixed
+      SIMD16 interpolation. */
+   if (intel->gen == 6)
+       INTEL_DEBUG |= DEBUG_GLSL_FORCE;
+
    intel->batch = intel_batchbuffer_alloc(intel);
 
    intel_fbo_init(intel);
@@ -791,8 +854,6 @@ intelDestroyContext(__DRIcontext * driContextPriv)
 
    assert(intel);               /* should never be null */
    if (intel) {
-      GLboolean release_texture_heaps;
-
       INTEL_FIREVERTICES(intel);
 
       _mesa_meta_free(&intel->ctx);
@@ -801,7 +862,6 @@ intelDestroyContext(__DRIcontext * driContextPriv)
 
       intel->vtbl.destroy(intel);
 
-      release_texture_heaps = (intel->ctx.Shared->RefCount == 1);
       _swsetup_DestroyContext(&intel->ctx);
       _tnl_DestroyContext(&intel->ctx);
       _vbo_DestroyContext(&intel->ctx);
@@ -814,23 +874,11 @@ intelDestroyContext(__DRIcontext * driContextPriv)
 
       free(intel->prim.vb);
       intel->prim.vb = NULL;
-      dri_bo_unreference(intel->prim.vb_bo);
+      drm_intel_bo_unreference(intel->prim.vb_bo);
       intel->prim.vb_bo = NULL;
-      dri_bo_unreference(intel->first_post_swapbuffers_batch);
+      drm_intel_bo_unreference(intel->first_post_swapbuffers_batch);
       intel->first_post_swapbuffers_batch = NULL;
 
-      if (release_texture_heaps) {
-         /* Nothing is currently done here to free texture heaps;
-          * but we're not using the texture heap utilities, so I
-          * rather think we shouldn't.  I've taken a look, and can't
-          * find any private texture data hanging around anywhere, but
-          * I'm not yet certain there isn't any at all...
-          */
-         /* if (INTEL_DEBUG & DEBUG_TEXTURE)
-            fprintf(stderr, "do something to free texture heaps\n");
-          */
-      }
-
       driDestroyOptionCache(&intel->optionCache);
 
       /* free the Mesa context */
@@ -844,13 +892,8 @@ intelDestroyContext(__DRIcontext * driContextPriv)
 GLboolean
 intelUnbindContext(__DRIcontext * driContextPriv)
 {
-   struct intel_context *intel =
-      (struct intel_context *) driContextPriv->driverPrivate;
-
-   /* Deassociate the context with the drawables.
-    */
-   intel->driDrawable = NULL;
-   intel->driReadDrawable = NULL;
+   /* Unset current context and dispath table */
+   _mesa_make_current(NULL, NULL, NULL);
 
    return GL_TRUE;
 }
@@ -877,15 +920,26 @@ intelMakeCurrent(__DRIcontext * driContextPriv,
    }
 
    if (driContextPriv) {
-      struct gl_framebuffer *fb = driDrawPriv->driverPrivate;
-      struct gl_framebuffer *readFb = driReadPriv->driverPrivate;
+      struct gl_framebuffer *fb, *readFb;
+      
+      if (driDrawPriv == NULL && driReadPriv == NULL) {
+        fb = _mesa_get_incomplete_framebuffer();
+        readFb = _mesa_get_incomplete_framebuffer();
+      } else {
+        fb = driDrawPriv->driverPrivate;
+        readFb = driReadPriv->driverPrivate;
+        driContextPriv->dri2.draw_stamp = driDrawPriv->dri2.stamp - 1;
+        driContextPriv->dri2.read_stamp = driReadPriv->dri2.stamp - 1;
+      }
 
-      intel->driReadDrawable = driReadPriv;
-      intel->driDrawable = driDrawPriv;
-      driContextPriv->dri2.draw_stamp = driDrawPriv->dri2.stamp - 1;
-      driContextPriv->dri2.read_stamp = driReadPriv->dri2.stamp - 1;
       intel_prepare_render(intel);
       _mesa_make_current(&intel->ctx, fb, readFb);
+      
+      /* We do this in intel_prepare_render() too, but intel->ctx.DrawBuffer
+       * is NULL at that point.  We can't call _mesa_makecurrent()
+       * first, since we need the buffer size for the initial
+       * viewport.  So just call intel_draw_buffer() again here. */
+      intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
    }
    else {
       _mesa_make_current(NULL, NULL, NULL);