intel_buffers.c revision 77a5bcaff43df8d54e0e0ef833726e4b41d7eb36
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_depthstencil.h"
33#include "intel_fbo.h"
34#include "intel_tris.h"
35#include "intel_regions.h"
36#include "intel_batchbuffer.h"
37#include "intel_reg.h"
38#include "context.h"
39#include "utils.h"
40#include "drirenderbuffer.h"
41#include "framebuffer.h"
42#include "swrast/swrast.h"
43#include "vblank.h"
44
45
46/* This block can be removed when libdrm >= 2.3.1 is required */
47
48#ifndef DRM_IOCTL_I915_FLIP
49
50#define DRM_VBLANK_FLIP 0x8000000
51
52typedef struct drm_i915_flip {
53   int pipes;
54} drm_i915_flip_t;
55
56#undef DRM_IOCTL_I915_FLIP
57#define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \
58				    drm_i915_flip_t)
59
60#endif
61
62
63/**
64 * XXX move this into a new dri/common/cliprects.c file.
65 */
66GLboolean
67intel_intersect_cliprects(drm_clip_rect_t * dst,
68                          const drm_clip_rect_t * a,
69                          const drm_clip_rect_t * b)
70{
71   GLint bx = b->x1;
72   GLint by = b->y1;
73   GLint bw = b->x2 - bx;
74   GLint bh = b->y2 - by;
75
76   if (bx < a->x1)
77      bw -= a->x1 - bx, bx = a->x1;
78   if (by < a->y1)
79      bh -= a->y1 - by, by = a->y1;
80   if (bx + bw > a->x2)
81      bw = a->x2 - bx;
82   if (by + bh > a->y2)
83      bh = a->y2 - by;
84   if (bw <= 0)
85      return GL_FALSE;
86   if (bh <= 0)
87      return GL_FALSE;
88
89   dst->x1 = bx;
90   dst->y1 = by;
91   dst->x2 = bx + bw;
92   dst->y2 = by + bh;
93
94   return GL_TRUE;
95}
96
97/**
98 * Return pointer to current color drawing region, or NULL.
99 */
100struct intel_region *
101intel_drawbuf_region(struct intel_context *intel)
102{
103   struct intel_renderbuffer *irbColor =
104      intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0][0]);
105   if (irbColor)
106      return irbColor->region;
107   else
108      return NULL;
109}
110
111/**
112 * Return pointer to current color reading region, or NULL.
113 */
114struct intel_region *
115intel_readbuf_region(struct intel_context *intel)
116{
117   struct intel_renderbuffer *irb
118      = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer);
119   if (irb)
120      return irb->region;
121   else
122      return NULL;
123}
124
125
126
127/**
128 * Update the following fields for rendering to a user-created FBO:
129 *   intel->numClipRects
130 *   intel->pClipRects
131 *   intel->drawX
132 *   intel->drawY
133 */
134static void
135intelSetRenderbufferClipRects(struct intel_context *intel)
136{
137   assert(intel->ctx.DrawBuffer->Width > 0);
138   assert(intel->ctx.DrawBuffer->Height > 0);
139   intel->fboRect.x1 = 0;
140   intel->fboRect.y1 = 0;
141   intel->fboRect.x2 = intel->ctx.DrawBuffer->Width;
142   intel->fboRect.y2 = intel->ctx.DrawBuffer->Height;
143   intel->numClipRects = 1;
144   intel->pClipRects = &intel->fboRect;
145   intel->drawX = 0;
146   intel->drawY = 0;
147}
148
149
150/**
151 * As above, but for rendering to front buffer of a window.
152 * \sa intelSetRenderbufferClipRects
153 */
154static void
155intelSetFrontClipRects(struct intel_context *intel)
156{
157   __DRIdrawablePrivate *dPriv = intel->driDrawable;
158
159   if (!dPriv)
160      return;
161
162   intel->numClipRects = dPriv->numClipRects;
163   intel->pClipRects = dPriv->pClipRects;
164   intel->drawX = dPriv->x;
165   intel->drawY = dPriv->y;
166}
167
168
169/**
170 * As above, but for rendering to back buffer of a window.
171 */
172static void
173intelSetBackClipRects(struct intel_context *intel)
174{
175   __DRIdrawablePrivate *dPriv = intel->driDrawable;
176   struct intel_framebuffer *intel_fb;
177
178   if (!dPriv)
179      return;
180
181   intel_fb = dPriv->driverPrivate;
182
183   if (intel_fb->pf_active || dPriv->numBackClipRects == 0) {
184      /* use the front clip rects */
185      intel->numClipRects = dPriv->numClipRects;
186      intel->pClipRects = dPriv->pClipRects;
187      intel->drawX = dPriv->x;
188      intel->drawY = dPriv->y;
189   }
190   else {
191      /* use the back clip rects */
192      intel->numClipRects = dPriv->numBackClipRects;
193      intel->pClipRects = dPriv->pBackClipRects;
194      intel->drawX = dPriv->backX;
195      intel->drawY = dPriv->backY;
196   }
197}
198
199
200/**
201 * This will be called whenever the currently bound window is moved/resized.
202 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
203 */
204void
205intelWindowMoved(struct intel_context *intel)
206{
207   GLcontext *ctx = &intel->ctx;
208   __DRIdrawablePrivate *dPriv = intel->driDrawable;
209   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
210
211   if (!intel->ctx.DrawBuffer) {
212      /* when would this happen? -BP */
213      intelSetFrontClipRects(intel);
214   }
215   else if (intel->ctx.DrawBuffer->Name != 0) {
216      /* drawing to user-created FBO - do nothing */
217      /* Cliprects would be set from intelDrawBuffer() */
218   }
219   else {
220      /* drawing to a window */
221      switch (intel_fb->Base._ColorDrawBufferMask[0]) {
222      case BUFFER_BIT_FRONT_LEFT:
223         intelSetFrontClipRects(intel);
224         break;
225      case BUFFER_BIT_BACK_LEFT:
226         intelSetBackClipRects(intel);
227         break;
228      default:
229         /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
230         intelSetFrontClipRects(intel);
231      }
232   }
233
234   if (intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
235      drmI830Sarea *sarea = intel->sarea;
236      drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
237				   .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
238      drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y,
239				     .x2 = sarea->planeA_x + sarea->planeA_w,
240				     .y2 = sarea->planeA_y + sarea->planeA_h };
241      drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y,
242				     .x2 = sarea->planeB_x + sarea->planeB_w,
243				     .y2 = sarea->planeB_y + sarea->planeB_h };
244      GLint areaA = driIntersectArea( drw_rect, planeA_rect );
245      GLint areaB = driIntersectArea( drw_rect, planeB_rect );
246      GLuint flags = dPriv->vblFlags;
247      GLboolean pf_active;
248      GLint pf_planes;
249
250      /* Update page flipping info
251       */
252      pf_planes = 0;
253
254      if (areaA > 0)
255	 pf_planes |= 1;
256
257      if (areaB > 0)
258	 pf_planes |= 2;
259
260      intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
261				   (intel_fb->pf_planes & 0x2)) & 0x3;
262
263      intel_fb->pf_num_pages = intel->intelScreen->third.handle ? 3 : 2;
264
265      pf_active = pf_planes && (pf_planes & intel->sarea->pf_active) == pf_planes;
266
267      if (INTEL_DEBUG & DEBUG_LOCK)
268	 if (pf_active != intel_fb->pf_active)
269	    _mesa_printf("%s - Page flipping %sactive\n", __progname,
270			 pf_active ? "" : "in");
271
272      if (pf_active) {
273	 /* Sync pages between planes if flipping on both at the same time */
274	 if (pf_planes == 0x3 && pf_planes != intel_fb->pf_planes &&
275	     (intel->sarea->pf_current_page & 0x3) !=
276	     (((intel->sarea->pf_current_page) >> 2) & 0x3)) {
277	    drm_i915_flip_t flip;
278
279	    if (intel_fb->pf_current_page ==
280		(intel->sarea->pf_current_page & 0x3)) {
281	       /* XXX: This is ugly, but emitting two flips 'in a row' can cause
282		* lockups for unknown reasons.
283		*/
284               intel->sarea->pf_current_page =
285		  intel->sarea->pf_current_page & 0x3;
286	       intel->sarea->pf_current_page |=
287		  ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
288		   intel_fb->pf_num_pages) << 2;
289
290	       flip.pipes = 0x2;
291	    } else {
292               intel->sarea->pf_current_page =
293		  intel->sarea->pf_current_page & (0x3 << 2);
294	       intel->sarea->pf_current_page |=
295		  (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
296		  intel_fb->pf_num_pages;
297
298	       flip.pipes = 0x1;
299	    }
300
301	    drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
302	 }
303
304	 intel_fb->pf_planes = pf_planes;
305      }
306
307      intel_fb->pf_active = pf_active;
308      intel_flip_renderbuffers(intel_fb);
309      intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
310
311      /* Update vblank info
312       */
313      if (areaB > areaA || (areaA == areaB && areaB > 0)) {
314	 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
315      } else {
316	 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
317      }
318
319      /* Check to see if we changed pipes */
320      if (flags != dPriv->vblFlags && dPriv->vblFlags &&
321	  !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) {
322	 int64_t count;
323	 drmVBlank vbl;
324	 int i;
325
326	 /*
327	  * Deal with page flipping
328	  */
329	 vbl.request.type = DRM_VBLANK_ABSOLUTE;
330
331	 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) {
332	    vbl.request.type |= DRM_VBLANK_SECONDARY;
333	 }
334
335	 for (i = 0; i < intel_fb->pf_num_pages; i++) {
336	    if (!intel_fb->color_rb[i] ||
337		(intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <=
338		(1<<23))
339	       continue;
340
341	    vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
342	    drmWaitVBlank(intel->driFd, &vbl);
343	 }
344
345	 /*
346	  * Update msc_base from old pipe
347	  */
348	 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count);
349	 dPriv->msc_base = count;
350	 /*
351	  * Then get new vblank_base and vblSeq values
352	  */
353	 dPriv->vblFlags = flags;
354	 driGetCurrentVBlank(dPriv);
355	 dPriv->vblank_base = dPriv->vblSeq;
356
357	 intel_fb->vbl_waited = dPriv->vblSeq;
358
359	 for (i = 0; i < intel_fb->pf_num_pages; i++) {
360	    if (intel_fb->color_rb[i])
361	       intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited;
362	 }
363      }
364   } else {
365      dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY;
366   }
367
368   /* Update Mesa's notion of window size */
369   driUpdateFramebufferSize(ctx, dPriv);
370   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
371
372   /* Update hardware scissor */
373   ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
374                       ctx->Scissor.Width, ctx->Scissor.Height);
375
376   /* Re-calculate viewport related state */
377   ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
378}
379
380
381
382/* A true meta version of this would be very simple and additionally
383 * machine independent.  Maybe we'll get there one day.
384 */
385static void
386intelClearWithTris(struct intel_context *intel, GLbitfield mask)
387{
388   GLcontext *ctx = &intel->ctx;
389   struct gl_framebuffer *fb = ctx->DrawBuffer;
390   drm_clip_rect_t clear;
391
392   if (INTEL_DEBUG & DEBUG_BLIT)
393      _mesa_printf("%s 0x%x\n", __FUNCTION__, mask);
394
395   LOCK_HARDWARE(intel);
396
397   /* XXX FBO: was: intel->driDrawable->numClipRects */
398   if (intel->numClipRects) {
399      GLint cx, cy, cw, ch;
400      GLuint buf;
401
402      intel->vtbl.install_meta_state(intel);
403
404      /* Get clear bounds after locking */
405      cx = fb->_Xmin;
406      cy = fb->_Ymin;
407      ch = fb->_Ymax - cx;
408      cw = fb->_Xmax - cy;
409
410      /* note: regardless of 'all', cx, cy, cw, ch are now correct */
411      clear.x1 = cx;
412      clear.y1 = cy;
413      clear.x2 = cx + cw;
414      clear.y2 = cy + ch;
415
416      /* Back and stencil cliprects are the same.  Try and do both
417       * buffers at once:
418       */
419      if (mask &
420          (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) {
421         struct intel_region *backRegion =
422            intel_get_rb_region(fb, BUFFER_BACK_LEFT);
423         struct intel_region *depthRegion =
424            intel_get_rb_region(fb, BUFFER_DEPTH);
425         const GLuint clearColor = (backRegion && backRegion->cpp == 4)
426            ? intel->ClearColor8888 : intel->ClearColor565;
427
428         intel->vtbl.meta_draw_region(intel, backRegion, depthRegion);
429
430         if (mask & BUFFER_BIT_BACK_LEFT)
431            intel->vtbl.meta_color_mask(intel, GL_TRUE);
432         else
433            intel->vtbl.meta_color_mask(intel, GL_FALSE);
434
435         if (mask & BUFFER_BIT_STENCIL)
436            intel->vtbl.meta_stencil_replace(intel,
437                                             intel->ctx.Stencil.WriteMask[0],
438                                             intel->ctx.Stencil.Clear);
439         else
440            intel->vtbl.meta_no_stencil_write(intel);
441
442         if (mask & BUFFER_BIT_DEPTH)
443            intel->vtbl.meta_depth_replace(intel);
444         else
445            intel->vtbl.meta_no_depth_write(intel);
446
447         /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
448          * drawing origin may not be correctly emitted.
449          */
450         intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, intel->ctx.Depth.Clear, clearColor, 0, 0, 0, 0);   /* texcoords */
451
452         mask &=
453            ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH);
454      }
455
456      /* clear the remaining (color) renderbuffers */
457      for (buf = 0; buf < BUFFER_COUNT && mask; buf++) {
458         const GLuint bufBit = 1 << buf;
459         if (mask & bufBit) {
460            struct intel_renderbuffer *irbColor =
461               intel_renderbuffer(fb->Attachment[buf].Renderbuffer);
462            GLuint color = (irbColor->region->cpp == 4)
463               ? intel->ClearColor8888 : intel->ClearColor565;
464
465            ASSERT(irbColor);
466
467            intel->vtbl.meta_no_depth_write(intel);
468            intel->vtbl.meta_no_stencil_write(intel);
469            intel->vtbl.meta_color_mask(intel, GL_TRUE);
470            intel->vtbl.meta_draw_region(intel, irbColor->region, NULL);
471
472            /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
473             * drawing origin may not be correctly emitted.
474             */
475            intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, 0,      /* depth clear val */
476                                 color, 0, 0, 0, 0);    /* texcoords */
477
478            mask &= ~bufBit;
479         }
480      }
481
482      intel->vtbl.leave_meta_state(intel);
483      intel_batchbuffer_flush(intel->batch);
484   }
485   UNLOCK_HARDWARE(intel);
486}
487
488
489
490
491/**
492 * Copy the window contents named by dPriv to the rotated (or reflected)
493 * color buffer.
494 * srcBuf is BUFFER_BIT_FRONT_LEFT or BUFFER_BIT_BACK_LEFT to indicate the source.
495 */
496void
497intelRotateWindow(struct intel_context *intel,
498                  __DRIdrawablePrivate * dPriv, GLuint srcBuf)
499{
500   intelScreenPrivate *screen = intel->intelScreen;
501   drm_clip_rect_t fullRect;
502   struct intel_framebuffer *intel_fb;
503   struct intel_region *src;
504   const drm_clip_rect_t *clipRects;
505   int numClipRects;
506   int i;
507   GLenum format, type;
508
509   int xOrig, yOrig;
510   int origNumClipRects;
511   drm_clip_rect_t *origRects;
512
513   /*
514    * set up hardware state
515    */
516   intelFlush(&intel->ctx);
517
518   LOCK_HARDWARE(intel);
519
520   if (!intel->numClipRects) {
521      UNLOCK_HARDWARE(intel);
522      return;
523   }
524
525   intel->vtbl.install_meta_state(intel);
526
527   intel->vtbl.meta_no_depth_write(intel);
528   intel->vtbl.meta_no_stencil_write(intel);
529   intel->vtbl.meta_color_mask(intel, GL_FALSE);
530
531
532   /* save current drawing origin and cliprects (restored at end) */
533   xOrig = intel->drawX;
534   yOrig = intel->drawY;
535   origNumClipRects = intel->numClipRects;
536   origRects = intel->pClipRects;
537
538   /*
539    * set drawing origin, cliprects for full-screen access to rotated screen
540    */
541   fullRect.x1 = 0;
542   fullRect.y1 = 0;
543   fullRect.x2 = screen->rotatedWidth;
544   fullRect.y2 = screen->rotatedHeight;
545   intel->drawX = 0;
546   intel->drawY = 0;
547   intel->numClipRects = 1;
548   intel->pClipRects = &fullRect;
549
550   intel->vtbl.meta_draw_region(intel, screen->rotated_region, NULL);    /* ? */
551
552   intel_fb = dPriv->driverPrivate;
553
554   if ((srcBuf == BUFFER_BIT_BACK_LEFT && !intel_fb->pf_active)) {
555      src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
556      clipRects = dPriv->pBackClipRects;
557      numClipRects = dPriv->numBackClipRects;
558   }
559   else {
560      src = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
561      clipRects = dPriv->pClipRects;
562      numClipRects = dPriv->numClipRects;
563   }
564
565   if (src->cpp == 4) {
566      format = GL_BGRA;
567      type = GL_UNSIGNED_BYTE;
568   }
569   else {
570      format = GL_BGR;
571      type = GL_UNSIGNED_SHORT_5_6_5_REV;
572   }
573
574   /* set the whole screen up as a texture to avoid alignment issues */
575   intel->vtbl.meta_tex_rect_source(intel,
576                                    src->buffer,
577                                    screen->width,
578                                    screen->height, src->pitch, format, type);
579
580   intel->vtbl.meta_texture_blend_replace(intel);
581
582   /*
583    * loop over the source window's cliprects
584    */
585   for (i = 0; i < numClipRects; i++) {
586      int srcX0 = clipRects[i].x1;
587      int srcY0 = clipRects[i].y1;
588      int srcX1 = clipRects[i].x2;
589      int srcY1 = clipRects[i].y2;
590      GLfloat verts[4][2], tex[4][2];
591      int j;
592
593      /* build vertices for four corners of clip rect */
594      verts[0][0] = srcX0;
595      verts[0][1] = srcY0;
596      verts[1][0] = srcX1;
597      verts[1][1] = srcY0;
598      verts[2][0] = srcX1;
599      verts[2][1] = srcY1;
600      verts[3][0] = srcX0;
601      verts[3][1] = srcY1;
602
603      /* .. and texcoords */
604      tex[0][0] = srcX0;
605      tex[0][1] = srcY0;
606      tex[1][0] = srcX1;
607      tex[1][1] = srcY0;
608      tex[2][0] = srcX1;
609      tex[2][1] = srcY1;
610      tex[3][0] = srcX0;
611      tex[3][1] = srcY1;
612
613      /* transform coords to rotated screen coords */
614
615      for (j = 0; j < 4; j++) {
616         matrix23TransformCoordf(&screen->rotMatrix,
617                                 &verts[j][0], &verts[j][1]);
618      }
619
620      /* draw polygon to map source image to dest region */
621      intel_meta_draw_poly(intel, 4, verts, 0, 0, tex);
622
623   }                            /* cliprect loop */
624
625   intel->vtbl.leave_meta_state(intel);
626   intel_batchbuffer_flush(intel->batch);
627
628   /* restore original drawing origin and cliprects */
629   intel->drawX = xOrig;
630   intel->drawY = yOrig;
631   intel->numClipRects = origNumClipRects;
632   intel->pClipRects = origRects;
633
634   UNLOCK_HARDWARE(intel);
635}
636
637
638/**
639 * Called by ctx->Driver.Clear.
640 */
641static void
642intelClear(GLcontext *ctx, GLbitfield mask)
643{
644   struct intel_context *intel = intel_context(ctx);
645   const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
646   GLbitfield tri_mask = 0;
647   GLbitfield blit_mask = 0;
648   GLbitfield swrast_mask = 0;
649   struct gl_framebuffer *fb = ctx->DrawBuffer;
650   GLuint i;
651
652   if (0)
653      fprintf(stderr, "%s\n", __FUNCTION__);
654
655   /* HW color buffers (front, back, aux, generic FBO, etc) */
656   if (colorMask == ~0) {
657      /* clear all R,G,B,A */
658      /* XXX FBO: need to check if colorbuffers are software RBOs! */
659      blit_mask |= (mask & BUFFER_BITS_COLOR);
660   }
661   else {
662      /* glColorMask in effect */
663      tri_mask |= (mask & BUFFER_BITS_COLOR);
664   }
665
666   /* HW stencil */
667   if (mask & BUFFER_BIT_STENCIL) {
668      const struct intel_region *stencilRegion
669         = intel_get_rb_region(fb, BUFFER_STENCIL);
670      if (stencilRegion) {
671         /* have hw stencil */
672         if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
673            /* not clearing all stencil bits, so use triangle clearing */
674            tri_mask |= BUFFER_BIT_STENCIL;
675         }
676         else {
677            /* clearing all stencil bits, use blitting */
678            blit_mask |= BUFFER_BIT_STENCIL;
679         }
680      }
681   }
682
683   /* HW depth */
684   if (mask & BUFFER_BIT_DEPTH) {
685      /* clear depth with whatever method is used for stencil (see above) */
686      if (tri_mask & BUFFER_BIT_STENCIL)
687         tri_mask |= BUFFER_BIT_DEPTH;
688      else
689         blit_mask |= BUFFER_BIT_DEPTH;
690   }
691
692   /* SW fallback clearing */
693   swrast_mask = mask & ~tri_mask & ~blit_mask;
694
695   for (i = 0; i < BUFFER_COUNT; i++) {
696      GLuint bufBit = 1 << i;
697      if ((blit_mask | tri_mask) & bufBit) {
698         if (!fb->Attachment[i].Renderbuffer->ClassID) {
699            blit_mask &= ~bufBit;
700            tri_mask &= ~bufBit;
701            swrast_mask |= bufBit;
702         }
703      }
704   }
705
706
707   intelFlush(ctx);             /* XXX intelClearWithBlit also does this */
708
709   if (blit_mask)
710      intelClearWithBlit(ctx, blit_mask);
711
712   if (tri_mask)
713      intelClearWithTris(intel, tri_mask);
714
715   if (swrast_mask)
716      _swrast_Clear(ctx, swrast_mask);
717}
718
719
720/* Emit wait for pending flips */
721void
722intel_wait_flips(struct intel_context *intel, GLuint batch_flags)
723{
724   struct intel_framebuffer *intel_fb =
725      (struct intel_framebuffer *) intel->ctx.DrawBuffer;
726   struct intel_renderbuffer *intel_rb =
727      intel_get_renderbuffer(&intel_fb->Base,
728			     intel_fb->Base._ColorDrawBufferMask[0] ==
729			     BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
730			     BUFFER_BACK_LEFT);
731
732   if (intel_fb->Base.Name == 0 && intel_rb->pf_pending == intel_fb->pf_seq) {
733      GLint pf_planes = intel_fb->pf_planes;
734      BATCH_LOCALS;
735
736      /* Wait for pending flips to take effect */
737      BEGIN_BATCH(2, batch_flags);
738      OUT_BATCH(pf_planes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP)
739		: 0);
740      OUT_BATCH(pf_planes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP)
741		: 0);
742      ADVANCE_BATCH();
743
744      intel_rb->pf_pending--;
745   }
746}
747
748
749/* Flip the front & back buffers
750 */
751static GLboolean
752intelPageFlip(const __DRIdrawablePrivate * dPriv)
753{
754   struct intel_context *intel;
755   int ret;
756   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
757
758   if (INTEL_DEBUG & DEBUG_IOCTL)
759      fprintf(stderr, "%s\n", __FUNCTION__);
760
761   assert(dPriv);
762   assert(dPriv->driContextPriv);
763   assert(dPriv->driContextPriv->driverPrivate);
764
765   intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
766
767   if (intel->intelScreen->drmMinor < 9)
768      return GL_FALSE;
769
770   intelFlush(&intel->ctx);
771
772   ret = 0;
773
774   LOCK_HARDWARE(intel);
775
776   if (dPriv->numClipRects && intel_fb->pf_active) {
777      drm_i915_flip_t flip;
778
779      flip.pipes = intel_fb->pf_planes;
780
781      ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
782   }
783
784   UNLOCK_HARDWARE(intel);
785
786   if (ret || !intel_fb->pf_active)
787      return GL_FALSE;
788
789   if (!dPriv->numClipRects) {
790      usleep(10000);	/* throttle invisible client 10ms */
791   }
792
793   intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
794				(intel_fb->pf_planes & 0x2)) & 0x3;
795
796   if (dPriv->numClipRects != 0) {
797      intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending =
798      intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending =
799	 ++intel_fb->pf_seq;
800   }
801
802   intel_flip_renderbuffers(intel_fb);
803   intel_draw_buffer(&intel->ctx, &intel_fb->Base);
804
805   return GL_TRUE;
806}
807
808#if 0
809void
810intelSwapBuffers(__DRIdrawablePrivate * dPriv)
811{
812   if (dPriv->driverPrivate) {
813      const struct gl_framebuffer *fb
814         = (struct gl_framebuffer *) dPriv->driverPrivate;
815      if (fb->Visual.doubleBufferMode) {
816         GET_CURRENT_CONTEXT(ctx);
817         if (ctx && ctx->DrawBuffer == fb) {
818            _mesa_notifySwapBuffers(ctx);       /* flush pending rendering */
819         }
820         if (intel->doPageFlip) {
821            intelPageFlip(dPriv);
822         }
823         else {
824            intelCopyBuffer(dPriv);
825         }
826      }
827   }
828   else {
829      _mesa_problem(NULL,
830                    "dPriv has no gl_framebuffer pointer in intelSwapBuffers");
831   }
832}
833#else
834/* Trunk version:
835 */
836
837static GLboolean
838intelScheduleSwap(__DRIdrawablePrivate * dPriv, GLboolean *missed_target)
839{
840   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
841   unsigned int interval;
842   struct intel_context *intel =
843      intelScreenContext(dPriv->driScreenPriv->private);
844   const intelScreenPrivate *intelScreen = intel->intelScreen;
845   unsigned int target;
846   drm_i915_vblank_swap_t swap;
847   GLboolean ret;
848
849   if (!dPriv->vblFlags ||
850       (dPriv->vblFlags & VBLANK_FLAG_NO_IRQ) ||
851       intelScreen->current_rotation != 0 ||
852       intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6))
853      return GL_FALSE;
854
855   interval = driGetVBlankInterval(dPriv);
856
857   swap.seqtype = DRM_VBLANK_ABSOLUTE;
858
859   if (dPriv->vblFlags & VBLANK_FLAG_SYNC) {
860      swap.seqtype |= DRM_VBLANK_NEXTONMISS;
861   } else if (interval == 0) {
862      return GL_FALSE;
863   }
864
865   swap.drawable = dPriv->hHWDrawable;
866   target = swap.sequence = dPriv->vblSeq + interval;
867
868   if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) {
869      swap.seqtype |= DRM_VBLANK_SECONDARY;
870   }
871
872   LOCK_HARDWARE(intel);
873
874   intel_batchbuffer_flush(intel->batch);
875
876   if ( intel_fb->pf_active ) {
877      swap.seqtype |= DRM_VBLANK_FLIP;
878
879      intel_fb->pf_current_page = (((intel->sarea->pf_current_page >>
880				     (intel_fb->pf_planes & 0x2)) & 0x3) + 1) %
881				  intel_fb->pf_num_pages;
882   }
883
884   if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
885			    sizeof(swap))) {
886      dPriv->vblSeq = swap.sequence;
887      swap.sequence -= target;
888      *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
889
890      intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending =
891	 intel_get_renderbuffer(&intel_fb->Base,
892				BUFFER_FRONT_LEFT)->vbl_pending =
893	 dPriv->vblSeq;
894
895      if (swap.seqtype & DRM_VBLANK_FLIP) {
896	 intel_flip_renderbuffers(intel_fb);
897	 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
898      }
899
900      ret = GL_TRUE;
901   } else {
902      if (swap.seqtype & DRM_VBLANK_FLIP) {
903	 intel_fb->pf_current_page = ((intel->sarea->pf_current_page >>
904					(intel_fb->pf_planes & 0x2)) & 0x3) %
905				     intel_fb->pf_num_pages;
906      }
907
908      ret = GL_FALSE;
909   }
910
911   UNLOCK_HARDWARE(intel);
912
913   return ret;
914}
915
916void
917intelSwapBuffers(__DRIdrawablePrivate * dPriv)
918{
919   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
920      GET_CURRENT_CONTEXT(ctx);
921      struct intel_context *intel;
922
923      if (ctx == NULL)
924	 return;
925
926      intel = intel_context(ctx);
927
928      if (ctx->Visual.doubleBufferMode) {
929         intelScreenPrivate *screen = intel->intelScreen;
930	 GLboolean missed_target;
931	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
932	 int64_t ust;
933
934	 _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
935
936         if (screen->current_rotation != 0 ||
937	     !intelScheduleSwap(dPriv, &missed_target)) {
938	    driWaitForVBlank(dPriv, &missed_target);
939
940	    if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
941	       intelCopyBuffer(dPriv, NULL);
942	    }
943
944	    if (screen->current_rotation != 0) {
945	       intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
946	    }
947	 }
948
949	 intel_fb->swap_count++;
950	 (*dri_interface->getUST) (&ust);
951	 if (missed_target) {
952	    intel_fb->swap_missed_count++;
953	    intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
954	 }
955
956	 intel_fb->swap_ust = ust;
957      }
958   }
959   else {
960      /* XXX this shouldn't be an error but we can't handle it for now */
961      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
962   }
963}
964#endif
965
966void
967intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
968{
969   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
970      struct intel_context *intel =
971         (struct intel_context *) dPriv->driContextPriv->driverPrivate;
972      GLcontext *ctx = &intel->ctx;
973
974      if (ctx->Visual.doubleBufferMode) {
975         drm_clip_rect_t rect;
976         rect.x1 = x + dPriv->x;
977         rect.y1 = (dPriv->h - y - h) + dPriv->y;
978         rect.x2 = rect.x1 + w;
979         rect.y2 = rect.y1 + h;
980         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
981         intelCopyBuffer(dPriv, &rect);
982      }
983   }
984   else {
985      /* XXX this shouldn't be an error but we can't handle it for now */
986      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
987   }
988}
989
990
991/**
992 * Update the hardware state for drawing into a window or framebuffer object.
993 *
994 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
995 * places within the driver.
996 *
997 * Basically, this needs to be called any time the current framebuffer
998 * changes, the renderbuffers change, or we need to draw into different
999 * color buffers.
1000 */
1001void
1002intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb)
1003{
1004   struct intel_context *intel = intel_context(ctx);
1005   struct intel_region *colorRegion, *depthRegion = NULL;
1006   struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL;
1007   int front = 0;               /* drawing to front color buffer? */
1008
1009   if (!fb) {
1010      /* this can happen during the initial context initialization */
1011      return;
1012   }
1013
1014   /* Do this here, note core Mesa, since this function is called from
1015    * many places within the driver.
1016    */
1017   if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
1018      /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
1019      _mesa_update_framebuffer(ctx);
1020      /* this updates the DrawBuffer's Width/Height if it's a FBO */
1021      _mesa_update_draw_buffer_bounds(ctx);
1022   }
1023
1024   if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1025      /* this may occur when we're called by glBindFrameBuffer() during
1026       * the process of someone setting up renderbuffers, etc.
1027       */
1028      /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
1029      return;
1030   }
1031
1032   if (fb->Name)
1033      intel_validate_paired_depth_stencil(ctx, fb);
1034
1035   /*
1036    * How many color buffers are we drawing into?
1037    */
1038   if (fb->_NumColorDrawBuffers[0] != 1
1039#if 0
1040       /* XXX FBO temporary - always use software rendering */
1041       || 1
1042#endif
1043      ) {
1044      /* writing to 0 or 2 or 4 color buffers */
1045      /*_mesa_debug(ctx, "Software rendering\n");*/
1046      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
1047      front = 1;                /* might not have back color buffer */
1048   }
1049   else {
1050      /* draw to exactly one color buffer */
1051      /*_mesa_debug(ctx, "Hardware rendering\n");*/
1052      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
1053      if (fb->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT) {
1054         front = 1;
1055      }
1056   }
1057
1058   /*
1059    * Get the intel_renderbuffer for the colorbuffer we're drawing into.
1060    * And set up cliprects.
1061    */
1062   if (fb->Name == 0) {
1063      /* drawing to window system buffer */
1064      if (front) {
1065         intelSetFrontClipRects(intel);
1066         colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
1067      }
1068      else {
1069         intelSetBackClipRects(intel);
1070         colorRegion = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
1071      }
1072   }
1073   else {
1074      /* drawing to user-created FBO */
1075      struct intel_renderbuffer *irb;
1076      intelSetRenderbufferClipRects(intel);
1077      irb = intel_renderbuffer(fb->_ColorDrawBuffers[0][0]);
1078      colorRegion = (irb && irb->region) ? irb->region : NULL;
1079   }
1080
1081   /* Update culling direction which changes depending on the
1082    * orientation of the buffer:
1083    */
1084   if (ctx->Driver.FrontFace)
1085      ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
1086   else
1087      ctx->NewState |= _NEW_POLYGON;
1088
1089   if (!colorRegion) {
1090      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
1091   }
1092   else {
1093      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
1094   }
1095
1096   /***
1097    *** Get depth buffer region and check if we need a software fallback.
1098    *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
1099    ***/
1100   if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
1101      irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped);
1102      if (irbDepth && irbDepth->region) {
1103         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
1104         depthRegion = irbDepth->region;
1105      }
1106      else {
1107         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE);
1108         depthRegion = NULL;
1109      }
1110   }
1111   else {
1112      /* not using depth buffer */
1113      FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
1114      depthRegion = NULL;
1115   }
1116
1117   /***
1118    *** Stencil buffer
1119    *** This can only be hardware accelerated if we're using a
1120    *** combined DEPTH_STENCIL buffer (for now anyway).
1121    ***/
1122   if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
1123      irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped);
1124      if (irbStencil && irbStencil->region) {
1125         ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
1126         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
1127         /* need to re-compute stencil hw state */
1128         ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
1129         if (!depthRegion)
1130            depthRegion = irbStencil->region;
1131      }
1132      else {
1133         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE);
1134      }
1135   }
1136   else {
1137      /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */
1138      FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
1139      /* need to re-compute stencil hw state */
1140      ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
1141   }
1142
1143   /*
1144    * Update depth test state
1145    */
1146   if (ctx->Depth.Test && fb->Visual.depthBits > 0) {
1147      ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_TRUE);
1148   }
1149   else {
1150      ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_FALSE);
1151   }
1152
1153   /**
1154    ** Release old regions, reference new regions
1155    **/
1156#if 0                           /* XXX FBO: this seems to be redundant with i915_state_draw_region() */
1157   if (intel->draw_region != colorRegion) {
1158      intel_region_release(&intel->draw_region);
1159      intel_region_reference(&intel->draw_region, colorRegion);
1160   }
1161   if (intel->intelScreen->depth_region != depthRegion) {
1162      intel_region_release(&intel->intelScreen->depth_region);
1163      intel_region_reference(&intel->intelScreen->depth_region, depthRegion);
1164   }
1165#endif
1166
1167   intel->vtbl.set_draw_region(intel, colorRegion, depthRegion);
1168
1169   /* update viewport since it depends on window size */
1170   ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
1171                        ctx->Viewport.Width, ctx->Viewport.Height);
1172
1173   /* Update hardware scissor */
1174   ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
1175                       ctx->Scissor.Width, ctx->Scissor.Height);
1176}
1177
1178
1179static void
1180intelDrawBuffer(GLcontext * ctx, GLenum mode)
1181{
1182   intel_draw_buffer(ctx, ctx->DrawBuffer);
1183}
1184
1185
1186static void
1187intelReadBuffer(GLcontext * ctx, GLenum mode)
1188{
1189   if (ctx->ReadBuffer == ctx->DrawBuffer) {
1190      /* This will update FBO completeness status.
1191       * A framebuffer will be incomplete if the GL_READ_BUFFER setting
1192       * refers to a missing renderbuffer.  Calling glReadBuffer can set
1193       * that straight and can make the drawing buffer complete.
1194       */
1195      intel_draw_buffer(ctx, ctx->DrawBuffer);
1196   }
1197   /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc)
1198    * reference ctx->ReadBuffer and do appropriate state checks.
1199    */
1200}
1201
1202
1203void
1204intelInitBufferFuncs(struct dd_function_table *functions)
1205{
1206   functions->Clear = intelClear;
1207   functions->DrawBuffer = intelDrawBuffer;
1208   functions->ReadBuffer = intelReadBuffer;
1209}
1210