intel_buffers.c revision 39b4061bb9be540dfb51891e22c505bc235ec8a2
1/**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "intel_screen.h"
29#include "intel_context.h"
30#include "intel_blit.h"
31#include "intel_buffers.h"
32#include "intel_chipset.h"
33#include "intel_depthstencil.h"
34#include "intel_fbo.h"
35#include "intel_regions.h"
36#include "intel_batchbuffer.h"
37#include "intel_reg.h"
38#include "main/context.h"
39#include "main/framebuffer.h"
40#include "swrast/swrast.h"
41#include "utils.h"
42#include "drirenderbuffer.h"
43#include "vblank.h"
44#include "i915_drm.h"
45
46#define FILE_DEBUG_FLAG DEBUG_BLIT
47
48/**
49 * XXX move this into a new dri/common/cliprects.c file.
50 */
51GLboolean
52intel_intersect_cliprects(drm_clip_rect_t * dst,
53                          const drm_clip_rect_t * a,
54                          const drm_clip_rect_t * b)
55{
56   GLint bx = b->x1;
57   GLint by = b->y1;
58   GLint bw = b->x2 - bx;
59   GLint bh = b->y2 - by;
60
61   if (bx < a->x1)
62      bw -= a->x1 - bx, bx = a->x1;
63   if (by < a->y1)
64      bh -= a->y1 - by, by = a->y1;
65   if (bx + bw > a->x2)
66      bw = a->x2 - bx;
67   if (by + bh > a->y2)
68      bh = a->y2 - by;
69   if (bw <= 0)
70      return GL_FALSE;
71   if (bh <= 0)
72      return GL_FALSE;
73
74   dst->x1 = bx;
75   dst->y1 = by;
76   dst->x2 = bx + bw;
77   dst->y2 = by + bh;
78
79   return GL_TRUE;
80}
81
82/**
83 * Return pointer to current color drawing region, or NULL.
84 */
85struct intel_region *
86intel_drawbuf_region(struct intel_context *intel)
87{
88   struct intel_renderbuffer *irbColor =
89      intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0]);
90   if (irbColor)
91      return irbColor->region;
92   else
93      return NULL;
94}
95
96/**
97 * Return pointer to current color reading region, or NULL.
98 */
99struct intel_region *
100intel_readbuf_region(struct intel_context *intel)
101{
102   struct intel_renderbuffer *irb
103      = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer);
104   if (irb)
105      return irb->region;
106   else
107      return NULL;
108}
109
110void
111intel_get_cliprects(struct intel_context *intel,
112		    struct drm_clip_rect **cliprects,
113		    unsigned int *num_cliprects,
114		    int *x_off, int *y_off)
115{
116   __DRIdrawablePrivate *dPriv = intel->driDrawable;
117   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
118
119   if (intel->constant_cliprect) {
120      /* FBO or DRI2 rendering, which can just use the fb's size. */
121      intel->fboRect.x1 = 0;
122      intel->fboRect.y1 = 0;
123      intel->fboRect.x2 = intel->ctx.DrawBuffer->Width;
124      intel->fboRect.y2 = intel->ctx.DrawBuffer->Height;
125
126      *cliprects = &intel->fboRect;
127      *num_cliprects = 1;
128      *x_off = 0;
129      *y_off = 0;
130   } else if (intel->front_cliprects || dPriv->numBackClipRects == 0) {
131      /* use the front clip rects */
132      *cliprects = dPriv->pClipRects;
133      *num_cliprects = dPriv->numClipRects;
134      *x_off = dPriv->x;
135      *y_off = dPriv->y;
136   }
137   else {
138      /* use the back clip rects */
139      *num_cliprects = dPriv->numBackClipRects;
140      *cliprects = dPriv->pBackClipRects;
141      *x_off = dPriv->backX;
142      *y_off = dPriv->backY;
143   }
144}
145
146/*
147 * Correct a drawablePrivate's set of vblank flags WRT the current context.
148 * When considering multiple crtcs.
149 */
150GLuint
151intelFixupVblank(struct intel_context *intel, __DRIdrawablePrivate *dPriv)
152{
153
154   if (!intel->intelScreen->driScrnPriv->dri2.enabled &&
155       intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
156      volatile drm_i915_sarea_t *sarea = intel->sarea;
157      drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
158				   .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
159      drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y,
160				     .x2 = sarea->planeA_x + sarea->planeA_w,
161				     .y2 = sarea->planeA_y + sarea->planeA_h };
162      drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y,
163				     .x2 = sarea->planeB_x + sarea->planeB_w,
164				     .y2 = sarea->planeB_y + sarea->planeB_h };
165      GLint areaA = driIntersectArea( drw_rect, planeA_rect );
166      GLint areaB = driIntersectArea( drw_rect, planeB_rect );
167      GLuint flags = dPriv->vblFlags;
168
169      /* Update vblank info
170       */
171      if (areaB > areaA || (areaA == areaB && areaB > 0)) {
172	 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
173      } else {
174	 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
175      }
176
177      return flags;
178   } else {
179	return dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
180   }
181}
182
183/**
184 * This will be called whenever the currently bound window is moved/resized.
185 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
186 */
187void
188intelWindowMoved(struct intel_context *intel)
189{
190   GLcontext *ctx = &intel->ctx;
191   __DRIdrawablePrivate *dPriv = intel->driDrawable;
192   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
193
194   if (!intel->intelScreen->driScrnPriv->dri2.enabled &&
195       intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
196      GLuint flags = intelFixupVblank(intel, dPriv);
197
198      /* Check to see if we changed pipes */
199      if (flags != dPriv->vblFlags && dPriv->vblFlags &&
200	  !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) {
201	 int64_t count;
202	 drmVBlank vbl;
203	 int i;
204
205	 /*
206	  * Deal with page flipping
207	  */
208	 vbl.request.type = DRM_VBLANK_ABSOLUTE;
209
210	 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) {
211	    vbl.request.type |= DRM_VBLANK_SECONDARY;
212	 }
213
214	 for (i = 0; i < 2; i++) {
215	    if (!intel_fb->color_rb[i] ||
216		(intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <=
217		(1<<23))
218	       continue;
219
220	    vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
221	    drmWaitVBlank(intel->driFd, &vbl);
222	 }
223
224	 /*
225	  * Update msc_base from old pipe
226	  */
227	 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count);
228	 dPriv->msc_base = count;
229	 /*
230	  * Then get new vblank_base and vblSeq values
231	  */
232	 dPriv->vblFlags = flags;
233	 driGetCurrentVBlank(dPriv);
234	 dPriv->vblank_base = dPriv->vblSeq;
235
236	 intel_fb->vbl_waited = dPriv->vblSeq;
237
238	 for (i = 0; i < 2; i++) {
239	    if (intel_fb->color_rb[i])
240	       intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited;
241	 }
242      }
243   } else {
244      dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY;
245   }
246
247   /* Update Mesa's notion of window size */
248   driUpdateFramebufferSize(ctx, dPriv);
249   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
250
251   /* Update hardware scissor */
252   if (ctx->Driver.Scissor != NULL) {
253      ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
254			  ctx->Scissor.Width, ctx->Scissor.Height);
255   }
256
257   /* Re-calculate viewport related state */
258   if (ctx->Driver.DepthRange != NULL)
259      ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
260}
261
262
263
264/* A true meta version of this would be very simple and additionally
265 * machine independent.  Maybe we'll get there one day.
266 */
267static void
268intelClearWithTris(struct intel_context *intel, GLbitfield mask)
269{
270   GLcontext *ctx = &intel->ctx;
271   struct gl_framebuffer *fb = ctx->DrawBuffer;
272   GLuint buf;
273
274   intel->vtbl.install_meta_state(intel);
275
276   /* Back and stencil cliprects are the same.  Try and do both
277    * buffers at once:
278    */
279   if (mask & (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) {
280      struct intel_region *backRegion =
281	 intel_get_rb_region(fb, BUFFER_BACK_LEFT);
282      struct intel_region *depthRegion =
283	 intel_get_rb_region(fb, BUFFER_DEPTH);
284
285      intel->vtbl.meta_draw_region(intel, backRegion, depthRegion);
286
287      if (mask & BUFFER_BIT_BACK_LEFT)
288	 intel->vtbl.meta_color_mask(intel, GL_TRUE);
289      else
290	 intel->vtbl.meta_color_mask(intel, GL_FALSE);
291
292      if (mask & BUFFER_BIT_STENCIL)
293	 intel->vtbl.meta_stencil_replace(intel,
294					  intel->ctx.Stencil.WriteMask[0],
295					  intel->ctx.Stencil.Clear);
296      else
297	 intel->vtbl.meta_no_stencil_write(intel);
298
299      if (mask & BUFFER_BIT_DEPTH)
300	 intel->vtbl.meta_depth_replace(intel);
301      else
302	 intel->vtbl.meta_no_depth_write(intel);
303
304      intel->vtbl.meta_draw_quad(intel,
305				 fb->_Xmin,
306				 fb->_Xmax,
307				 fb->_Ymin,
308				 fb->_Ymax,
309				 intel->ctx.Depth.Clear,
310				 intel->ClearColor8888,
311				 0, 0, 0, 0);   /* texcoords */
312
313      mask &= ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH);
314   }
315
316   /* clear the remaining (color) renderbuffers */
317   for (buf = 0; buf < BUFFER_COUNT && mask; buf++) {
318      const GLuint bufBit = 1 << buf;
319      if (mask & bufBit) {
320	 struct intel_renderbuffer *irbColor =
321	    intel_renderbuffer(fb->Attachment[buf].Renderbuffer);
322
323	 ASSERT(irbColor);
324
325	 intel->vtbl.meta_no_depth_write(intel);
326	 intel->vtbl.meta_no_stencil_write(intel);
327	 intel->vtbl.meta_color_mask(intel, GL_TRUE);
328	 intel->vtbl.meta_draw_region(intel, irbColor->region, NULL);
329
330	 intel->vtbl.meta_draw_quad(intel,
331				    fb->_Xmin,
332				    fb->_Xmax,
333				    fb->_Ymin,
334				    fb->_Ymax,
335				    0, intel->ClearColor8888,
336				    0, 0, 0, 0);   /* texcoords */
337
338	 mask &= ~bufBit;
339      }
340   }
341
342   intel->vtbl.leave_meta_state(intel);
343}
344
345static const char *buffer_names[] = {
346   [BUFFER_FRONT_LEFT] = "front",
347   [BUFFER_BACK_LEFT] = "back",
348   [BUFFER_FRONT_RIGHT] = "front right",
349   [BUFFER_BACK_RIGHT] = "back right",
350   [BUFFER_AUX0] = "aux0",
351   [BUFFER_AUX1] = "aux1",
352   [BUFFER_AUX2] = "aux2",
353   [BUFFER_AUX3] = "aux3",
354   [BUFFER_DEPTH] = "depth",
355   [BUFFER_STENCIL] = "stencil",
356   [BUFFER_ACCUM] = "accum",
357   [BUFFER_COLOR0] = "color0",
358   [BUFFER_COLOR1] = "color1",
359   [BUFFER_COLOR2] = "color2",
360   [BUFFER_COLOR3] = "color3",
361   [BUFFER_COLOR4] = "color4",
362   [BUFFER_COLOR5] = "color5",
363   [BUFFER_COLOR6] = "color6",
364   [BUFFER_COLOR7] = "color7",
365};
366
367/**
368 * Called by ctx->Driver.Clear.
369 */
370static void
371intelClear(GLcontext *ctx, GLbitfield mask)
372{
373   struct intel_context *intel = intel_context(ctx);
374   const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
375   GLbitfield tri_mask = 0;
376   GLbitfield blit_mask = 0;
377   GLbitfield swrast_mask = 0;
378   struct gl_framebuffer *fb = ctx->DrawBuffer;
379   GLuint i;
380
381   if (0)
382      fprintf(stderr, "%s\n", __FUNCTION__);
383
384   /* HW color buffers (front, back, aux, generic FBO, etc) */
385   if (colorMask == ~0) {
386      /* clear all R,G,B,A */
387      /* XXX FBO: need to check if colorbuffers are software RBOs! */
388      blit_mask |= (mask & BUFFER_BITS_COLOR);
389   }
390   else {
391      /* glColorMask in effect */
392      tri_mask |= (mask & BUFFER_BITS_COLOR);
393   }
394
395   /* HW stencil */
396   if (mask & BUFFER_BIT_STENCIL) {
397      const struct intel_region *stencilRegion
398         = intel_get_rb_region(fb, BUFFER_STENCIL);
399      if (stencilRegion) {
400         /* have hw stencil */
401         if (IS_965(intel->intelScreen->deviceID) ||
402	     (ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
403	    /* We have to use the 3D engine if we're clearing a partial mask
404	     * of the stencil buffer, or if we're on a 965 which has a tiled
405	     * depth/stencil buffer in a layout we can't blit to.
406	     */
407            tri_mask |= BUFFER_BIT_STENCIL;
408         }
409         else {
410            /* clearing all stencil bits, use blitting */
411            blit_mask |= BUFFER_BIT_STENCIL;
412         }
413      }
414   }
415
416   /* HW depth */
417   if (mask & BUFFER_BIT_DEPTH) {
418      /* clear depth with whatever method is used for stencil (see above) */
419      if (IS_965(intel->intelScreen->deviceID) ||
420	  tri_mask & BUFFER_BIT_STENCIL)
421         tri_mask |= BUFFER_BIT_DEPTH;
422      else
423         blit_mask |= BUFFER_BIT_DEPTH;
424   }
425
426   /* SW fallback clearing */
427   swrast_mask = mask & ~tri_mask & ~blit_mask;
428
429   for (i = 0; i < BUFFER_COUNT; i++) {
430      GLuint bufBit = 1 << i;
431      if ((blit_mask | tri_mask) & bufBit) {
432         if (!fb->Attachment[i].Renderbuffer->ClassID) {
433            blit_mask &= ~bufBit;
434            tri_mask &= ~bufBit;
435            swrast_mask |= bufBit;
436         }
437      }
438   }
439
440   if (blit_mask) {
441      if (INTEL_DEBUG & DEBUG_BLIT) {
442	 DBG("blit clear:");
443	 for (i = 0; i < BUFFER_COUNT; i++) {
444	    if (blit_mask & (1 << i))
445	       DBG(" %s", buffer_names[i]);
446	 }
447	 DBG("\n");
448      }
449      intelClearWithBlit(ctx, blit_mask);
450   }
451
452   if (tri_mask) {
453      if (INTEL_DEBUG & DEBUG_BLIT) {
454	 DBG("tri clear:");
455	 for (i = 0; i < BUFFER_COUNT; i++) {
456	    if (tri_mask & (1 << i))
457	       DBG(" %s", buffer_names[i]);
458	 }
459	 DBG("\n");
460      }
461      intelClearWithTris(intel, tri_mask);
462   }
463
464   if (swrast_mask) {
465      if (INTEL_DEBUG & DEBUG_BLIT) {
466	 DBG("swrast clear:");
467	 for (i = 0; i < BUFFER_COUNT; i++) {
468	    if (swrast_mask & (1 << i))
469	       DBG(" %s", buffer_names[i]);
470	 }
471	 DBG("\n");
472      }
473      _swrast_Clear(ctx, swrast_mask);
474   }
475}
476
477void
478intelSwapBuffers(__DRIdrawablePrivate * dPriv)
479{
480   __DRIscreenPrivate *psp = dPriv->driScreenPriv;
481
482   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
483      GET_CURRENT_CONTEXT(ctx);
484      struct intel_context *intel;
485
486      if (ctx == NULL)
487	 return;
488
489      intel = intel_context(ctx);
490
491      if (ctx->Visual.doubleBufferMode) {
492	 GLboolean missed_target;
493	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
494	 int64_t ust;
495
496	 _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
497
498	/*
499	 * The old swapping ioctl was incredibly racy, just wait for vblank
500	 * and do the swap ourselves.
501	 */
502	 driWaitForVBlank(dPriv, &missed_target);
503
504	 /*
505	  * Update each buffer's vbl_pending so we don't get too out of
506	  * sync
507	  */
508	 intel_get_renderbuffer(&intel_fb->Base,
509		   		BUFFER_BACK_LEFT)->vbl_pending = dPriv->vblSeq;
510         intel_get_renderbuffer(&intel_fb->Base,
511		   		BUFFER_FRONT_LEFT)->vbl_pending = dPriv->vblSeq;
512
513	 intelCopyBuffer(dPriv, NULL);
514
515	 intel_fb->swap_count++;
516	 (*psp->systemTime->getUST) (&ust);
517	 if (missed_target) {
518	    intel_fb->swap_missed_count++;
519	    intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
520	 }
521
522	 intel_fb->swap_ust = ust;
523      }
524      drmCommandNone(intel->driFd, DRM_I915_GEM_THROTTLE);
525
526   }
527   else {
528      /* XXX this shouldn't be an error but we can't handle it for now */
529      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
530   }
531}
532
533void
534intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
535{
536   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
537      struct intel_context *intel =
538         (struct intel_context *) dPriv->driContextPriv->driverPrivate;
539      GLcontext *ctx = &intel->ctx;
540
541      if (ctx->Visual.doubleBufferMode) {
542         drm_clip_rect_t rect;
543         rect.x1 = x + dPriv->x;
544         rect.y1 = (dPriv->h - y - h) + dPriv->y;
545         rect.x2 = rect.x1 + w;
546         rect.y2 = rect.y1 + h;
547         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
548         intelCopyBuffer(dPriv, &rect);
549      }
550   }
551   else {
552      /* XXX this shouldn't be an error but we can't handle it for now */
553      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
554   }
555}
556
557
558/**
559 * Update the hardware state for drawing into a window or framebuffer object.
560 *
561 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
562 * places within the driver.
563 *
564 * Basically, this needs to be called any time the current framebuffer
565 * changes, the renderbuffers change, or we need to draw into different
566 * color buffers.
567 */
568void
569intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb)
570{
571   struct intel_context *intel = intel_context(ctx);
572   struct intel_region *colorRegions[MAX_DRAW_BUFFERS], *depthRegion = NULL;
573   struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL;
574
575   if (!fb) {
576      /* this can happen during the initial context initialization */
577      return;
578   }
579
580   /* Do this here, not core Mesa, since this function is called from
581    * many places within the driver.
582    */
583   if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
584      /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
585      _mesa_update_framebuffer(ctx);
586      /* this updates the DrawBuffer's Width/Height if it's a FBO */
587      _mesa_update_draw_buffer_bounds(ctx);
588   }
589
590   if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
591      /* this may occur when we're called by glBindFrameBuffer() during
592       * the process of someone setting up renderbuffers, etc.
593       */
594      /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
595      return;
596   }
597
598   /*
599    * How many color buffers are we drawing into?
600    */
601   if (fb->_NumColorDrawBuffers == 0) {
602      /* writing to 0  */
603      colorRegions[0] = NULL;
604      intel->constant_cliprect = GL_TRUE;
605   }
606   else if (fb->_NumColorDrawBuffers > 1) {
607       int i;
608       struct intel_renderbuffer *irb;
609
610       for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
611           irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]);
612           colorRegions[i] = irb ? irb->region : NULL;
613       }
614       intel->constant_cliprect = GL_TRUE;
615   }
616   else {
617      /* Get the intel_renderbuffer for the single colorbuffer we're drawing
618       * into, and set up cliprects if it's .
619       */
620      if (fb->Name == 0) {
621	 intel->constant_cliprect = intel->driScreen->dri2.enabled;
622	 /* drawing to window system buffer */
623	 if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) {
624	    if (!intel->constant_cliprect && !intel->front_cliprects)
625	       intel_batchbuffer_flush(intel->batch);
626	    intel->front_cliprects = GL_TRUE;
627	    colorRegions[0] = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
628	 }
629	 else {
630	    if (!intel->constant_cliprect && intel->front_cliprects)
631	       intel_batchbuffer_flush(intel->batch);
632	    intel->front_cliprects = GL_FALSE;
633	    colorRegions[0]= intel_get_rb_region(fb, BUFFER_BACK_LEFT);
634	 }
635      }
636      else {
637	 /* drawing to user-created FBO */
638	 struct intel_renderbuffer *irb;
639	 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);
640	 colorRegions[0] = (irb && irb->region) ? irb->region : NULL;
641	 intel->constant_cliprect = GL_TRUE;
642      }
643   }
644
645   if (!colorRegions[0]) {
646      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
647   }
648   else {
649      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
650   }
651
652   /***
653    *** Get depth buffer region and check if we need a software fallback.
654    *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
655    ***/
656   if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
657      irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped);
658      if (irbDepth && irbDepth->region) {
659         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
660         depthRegion = irbDepth->region;
661      }
662      else {
663         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE);
664         depthRegion = NULL;
665      }
666   }
667   else {
668      /* not using depth buffer */
669      FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
670      depthRegion = NULL;
671   }
672
673   /***
674    *** Stencil buffer
675    *** This can only be hardware accelerated if we're using a
676    *** combined DEPTH_STENCIL buffer.
677    ***/
678   if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
679      irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped);
680      if (irbStencil && irbStencil->region) {
681         ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
682         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
683      }
684      else {
685         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE);
686      }
687   }
688   else {
689      /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */
690      FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
691   }
692
693   /*
694    * Update depth and stencil test state
695    */
696   if (ctx->Driver.Enable) {
697      ctx->Driver.Enable(ctx, GL_DEPTH_TEST,
698                         (ctx->Depth.Test && fb->Visual.depthBits > 0));
699      ctx->Driver.Enable(ctx, GL_STENCIL_TEST,
700                         (ctx->Stencil.Enabled && fb->Visual.stencilBits > 0));
701   }
702   else {
703      ctx->NewState |= (_NEW_DEPTH | _NEW_STENCIL);
704   }
705
706   intel->vtbl.set_draw_region(intel, colorRegions, depthRegion,
707                               fb->_NumColorDrawBuffers);
708
709   /* update viewport since it depends on window size */
710   if (ctx->Driver.Viewport) {
711      ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
712			   ctx->Viewport.Width, ctx->Viewport.Height);
713   }
714   else {
715      ctx->NewState |= _NEW_VIEWPORT;
716   }
717
718   /* Set state we know depends on drawable parameters:
719    */
720   if (ctx->Driver.Scissor)
721      ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
722			  ctx->Scissor.Width, ctx->Scissor.Height);
723   intel->NewGLState |= _NEW_SCISSOR;
724
725   if (ctx->Driver.DepthRange)
726      ctx->Driver.DepthRange(ctx,
727			     ctx->Viewport.Near,
728			     ctx->Viewport.Far);
729
730   /* Update culling direction which changes depending on the
731    * orientation of the buffer:
732    */
733   if (ctx->Driver.FrontFace)
734      ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
735   else
736      ctx->NewState |= _NEW_POLYGON;
737}
738
739
740static void
741intelDrawBuffer(GLcontext * ctx, GLenum mode)
742{
743   intel_draw_buffer(ctx, ctx->DrawBuffer);
744}
745
746
747static void
748intelReadBuffer(GLcontext * ctx, GLenum mode)
749{
750   if (ctx->ReadBuffer == ctx->DrawBuffer) {
751      /* This will update FBO completeness status.
752       * A framebuffer will be incomplete if the GL_READ_BUFFER setting
753       * refers to a missing renderbuffer.  Calling glReadBuffer can set
754       * that straight and can make the drawing buffer complete.
755       */
756      intel_draw_buffer(ctx, ctx->DrawBuffer);
757   }
758   /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc)
759    * reference ctx->ReadBuffer and do appropriate state checks.
760    */
761}
762
763
764void
765intelInitBufferFuncs(struct dd_function_table *functions)
766{
767   functions->Clear = intelClear;
768   functions->DrawBuffer = intelDrawBuffer;
769   functions->ReadBuffer = intelReadBuffer;
770}
771