Merge branch 'nouveau-import'
[mesa.git] / src / mesa / drivers / dri / i915tex / intel_buffers.c
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 "context.h"
38 #include "utils.h"
39 #include "drirenderbuffer.h"
40 #include "framebuffer.h"
41 #include "swrast/swrast.h"
42 #include "vblank.h"
43
44
45 /**
46 * XXX move this into a new dri/common/cliprects.c file.
47 */
48 GLboolean
49 intel_intersect_cliprects(drm_clip_rect_t * dst,
50 const drm_clip_rect_t * a,
51 const drm_clip_rect_t * b)
52 {
53 GLint bx = b->x1;
54 GLint by = b->y1;
55 GLint bw = b->x2 - bx;
56 GLint bh = b->y2 - by;
57
58 if (bx < a->x1)
59 bw -= a->x1 - bx, bx = a->x1;
60 if (by < a->y1)
61 bh -= a->y1 - by, by = a->y1;
62 if (bx + bw > a->x2)
63 bw = a->x2 - bx;
64 if (by + bh > a->y2)
65 bh = a->y2 - by;
66 if (bw <= 0)
67 return GL_FALSE;
68 if (bh <= 0)
69 return GL_FALSE;
70
71 dst->x1 = bx;
72 dst->y1 = by;
73 dst->x2 = bx + bw;
74 dst->y2 = by + bh;
75
76 return GL_TRUE;
77 }
78
79 /**
80 * Return pointer to current color drawing region, or NULL.
81 */
82 struct intel_region *
83 intel_drawbuf_region(struct intel_context *intel)
84 {
85 struct intel_renderbuffer *irbColor =
86 intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0][0]);
87 if (irbColor)
88 return irbColor->region;
89 else
90 return NULL;
91 }
92
93 /**
94 * Return pointer to current color reading region, or NULL.
95 */
96 struct intel_region *
97 intel_readbuf_region(struct intel_context *intel)
98 {
99 struct intel_renderbuffer *irb
100 = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer);
101 if (irb)
102 return irb->region;
103 else
104 return NULL;
105 }
106
107
108
109 /**
110 * Update the following fields for rendering to a user-created FBO:
111 * intel->numClipRects
112 * intel->pClipRects
113 * intel->drawX
114 * intel->drawY
115 */
116 static void
117 intelSetRenderbufferClipRects(struct intel_context *intel)
118 {
119 assert(intel->ctx.DrawBuffer->Width > 0);
120 assert(intel->ctx.DrawBuffer->Height > 0);
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 intel->numClipRects = 1;
126 intel->pClipRects = &intel->fboRect;
127 intel->drawX = 0;
128 intel->drawY = 0;
129 }
130
131
132 /**
133 * As above, but for rendering to front buffer of a window.
134 * \sa intelSetRenderbufferClipRects
135 */
136 static void
137 intelSetFrontClipRects(struct intel_context *intel)
138 {
139 __DRIdrawablePrivate *dPriv = intel->driDrawable;
140
141 if (!dPriv)
142 return;
143
144 intel->numClipRects = dPriv->numClipRects;
145 intel->pClipRects = dPriv->pClipRects;
146 intel->drawX = dPriv->x;
147 intel->drawY = dPriv->y;
148 }
149
150
151 /**
152 * As above, but for rendering to back buffer of a window.
153 */
154 static void
155 intelSetBackClipRects(struct intel_context *intel)
156 {
157 __DRIdrawablePrivate *dPriv = intel->driDrawable;
158
159 if (!dPriv)
160 return;
161
162 if (intel->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0) {
163 /* use the front clip rects */
164 intel->numClipRects = dPriv->numClipRects;
165 intel->pClipRects = dPriv->pClipRects;
166 intel->drawX = dPriv->x;
167 intel->drawY = dPriv->y;
168 }
169 else {
170 /* use the back clip rects */
171 intel->numClipRects = dPriv->numBackClipRects;
172 intel->pClipRects = dPriv->pBackClipRects;
173 intel->drawX = dPriv->backX;
174 intel->drawY = dPriv->backY;
175 }
176 }
177
178
179 /**
180 * This will be called whenever the currently bound window is moved/resized.
181 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
182 */
183 void
184 intelWindowMoved(struct intel_context *intel)
185 {
186 GLcontext *ctx = &intel->ctx;
187 __DRIdrawablePrivate *dPriv = intel->driDrawable;
188 GLframebuffer *drawFb = (GLframebuffer *) dPriv->driverPrivate;
189
190 if (!intel->ctx.DrawBuffer) {
191 /* when would this happen? -BP */
192 intelSetFrontClipRects(intel);
193 }
194 else if (intel->ctx.DrawBuffer->Name != 0) {
195 /* drawing to user-created FBO - do nothing */
196 /* Cliprects would be set from intelDrawBuffer() */
197 }
198 else {
199 /* drawing to a window */
200 switch (drawFb->_ColorDrawBufferMask[0]) {
201 case BUFFER_BIT_FRONT_LEFT:
202 intelSetFrontClipRects(intel);
203 break;
204 case BUFFER_BIT_BACK_LEFT:
205 intelSetBackClipRects(intel);
206 break;
207 default:
208 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
209 intelSetFrontClipRects(intel);
210 }
211 }
212
213 /* Update Mesa's notion of window size */
214 driUpdateFramebufferSize(ctx, dPriv);
215 drawFb->Initialized = GL_TRUE; /* XXX remove someday */
216
217 if (intel->intelScreen->driScrnPriv->ddxMinor >= 7) {
218 drmI830Sarea *sarea = intel->sarea;
219 drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
220 .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
221 drm_clip_rect_t pipeA_rect = { .x1 = sarea->pipeA_x, .y1 = sarea->pipeA_y,
222 .x2 = sarea->pipeA_x + sarea->pipeA_w,
223 .y2 = sarea->pipeA_y + sarea->pipeA_h };
224 drm_clip_rect_t pipeB_rect = { .x1 = sarea->pipeB_x, .y1 = sarea->pipeB_y,
225 .x2 = sarea->pipeB_x + sarea->pipeB_w,
226 .y2 = sarea->pipeB_y + sarea->pipeB_h };
227 GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
228 GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
229 GLuint flags = intel->vblank_flags;
230
231 if (areaB > areaA || (areaA == areaB && areaB > 0)) {
232 flags = intel->vblank_flags | VBLANK_FLAG_SECONDARY;
233 } else {
234 flags = intel->vblank_flags & ~VBLANK_FLAG_SECONDARY;
235 }
236
237 if (flags != intel->vblank_flags) {
238 intel->vblank_flags = flags;
239 driGetCurrentVBlank(dPriv, intel->vblank_flags, &intel->vbl_seq);
240 }
241 } else {
242 intel->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
243 }
244
245 /* Update hardware scissor */
246 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
247 ctx->Scissor.Width, ctx->Scissor.Height);
248
249 /* Re-calculate viewport related state */
250 ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
251 }
252
253
254
255 /* A true meta version of this would be very simple and additionally
256 * machine independent. Maybe we'll get there one day.
257 */
258 static void
259 intelClearWithTris(struct intel_context *intel, GLbitfield mask)
260 {
261 GLcontext *ctx = &intel->ctx;
262 drm_clip_rect_t clear;
263
264 if (INTEL_DEBUG & DEBUG_BLIT)
265 _mesa_printf("%s 0x%x\n", __FUNCTION__, mask);
266
267 LOCK_HARDWARE(intel);
268
269 /* XXX FBO: was: intel->driDrawable->numClipRects */
270 if (intel->numClipRects) {
271 GLint cx, cy, cw, ch;
272 GLuint buf;
273
274 intel->vtbl.install_meta_state(intel);
275
276 /* Get clear bounds after locking */
277 cx = ctx->DrawBuffer->_Xmin;
278 cy = ctx->DrawBuffer->_Ymin;
279 ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
280 cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
281
282 /* note: regardless of 'all', cx, cy, cw, ch are now correct */
283 clear.x1 = cx;
284 clear.y1 = cy;
285 clear.x2 = cx + cw;
286 clear.y2 = cy + ch;
287
288 /* Back and stencil cliprects are the same. Try and do both
289 * buffers at once:
290 */
291 if (mask &
292 (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) {
293 struct intel_region *backRegion =
294 intel_get_rb_region(ctx->DrawBuffer, BUFFER_BACK_LEFT);
295 struct intel_region *depthRegion =
296 intel_get_rb_region(ctx->DrawBuffer, BUFFER_DEPTH);
297 const GLuint clearColor = (backRegion && backRegion->cpp == 4)
298 ? intel->ClearColor8888 : intel->ClearColor565;
299
300 intel->vtbl.meta_draw_region(intel, backRegion, depthRegion);
301
302 if (mask & BUFFER_BIT_BACK_LEFT)
303 intel->vtbl.meta_color_mask(intel, GL_TRUE);
304 else
305 intel->vtbl.meta_color_mask(intel, GL_FALSE);
306
307 if (mask & BUFFER_BIT_STENCIL)
308 intel->vtbl.meta_stencil_replace(intel,
309 intel->ctx.Stencil.WriteMask[0],
310 intel->ctx.Stencil.Clear);
311 else
312 intel->vtbl.meta_no_stencil_write(intel);
313
314 if (mask & BUFFER_BIT_DEPTH)
315 intel->vtbl.meta_depth_replace(intel);
316 else
317 intel->vtbl.meta_no_depth_write(intel);
318
319 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
320 * drawing origin may not be correctly emitted.
321 */
322 intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, intel->ctx.Depth.Clear, clearColor, 0, 0, 0, 0); /* texcoords */
323
324 mask &=
325 ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH);
326 }
327
328 /* clear the remaining (color) renderbuffers */
329 for (buf = 0; buf < BUFFER_COUNT && mask; buf++) {
330 const GLuint bufBit = 1 << buf;
331 if (mask & bufBit) {
332 struct intel_renderbuffer *irbColor =
333 intel_renderbuffer(ctx->DrawBuffer->
334 Attachment[buf].Renderbuffer);
335 GLuint color = (irbColor->region->cpp == 4)
336 ? intel->ClearColor8888 : intel->ClearColor565;
337
338 ASSERT(irbColor);
339
340 intel->vtbl.meta_no_depth_write(intel);
341 intel->vtbl.meta_no_stencil_write(intel);
342 intel->vtbl.meta_color_mask(intel, GL_TRUE);
343 intel->vtbl.meta_draw_region(intel, irbColor->region, NULL);
344
345 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the
346 * drawing origin may not be correctly emitted.
347 */
348 intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, 0, /* depth clear val */
349 color, 0, 0, 0, 0); /* texcoords */
350
351 mask &= ~bufBit;
352 }
353 }
354
355 intel->vtbl.leave_meta_state(intel);
356 intel_batchbuffer_flush(intel->batch);
357 }
358 UNLOCK_HARDWARE(intel);
359 }
360
361
362
363
364 /**
365 * Copy the window contents named by dPriv to the rotated (or reflected)
366 * color buffer.
367 * srcBuf is BUFFER_BIT_FRONT_LEFT or BUFFER_BIT_BACK_LEFT to indicate the source.
368 */
369 void
370 intelRotateWindow(struct intel_context *intel,
371 __DRIdrawablePrivate * dPriv, GLuint srcBuf)
372 {
373 intelScreenPrivate *screen = intel->intelScreen;
374 drm_clip_rect_t fullRect;
375 struct intel_region *src;
376 const drm_clip_rect_t *clipRects;
377 int numClipRects;
378 int i;
379 GLenum format, type;
380
381 int xOrig, yOrig;
382 int origNumClipRects;
383 drm_clip_rect_t *origRects;
384
385 /*
386 * set up hardware state
387 */
388 intelFlush(&intel->ctx);
389
390 LOCK_HARDWARE(intel);
391
392 if (!intel->numClipRects) {
393 UNLOCK_HARDWARE(intel);
394 return;
395 }
396
397 intel->vtbl.install_meta_state(intel);
398
399 intel->vtbl.meta_no_depth_write(intel);
400 intel->vtbl.meta_no_stencil_write(intel);
401 intel->vtbl.meta_color_mask(intel, GL_FALSE);
402
403
404 /* save current drawing origin and cliprects (restored at end) */
405 xOrig = intel->drawX;
406 yOrig = intel->drawY;
407 origNumClipRects = intel->numClipRects;
408 origRects = intel->pClipRects;
409
410 /*
411 * set drawing origin, cliprects for full-screen access to rotated screen
412 */
413 fullRect.x1 = 0;
414 fullRect.y1 = 0;
415 fullRect.x2 = screen->rotatedWidth;
416 fullRect.y2 = screen->rotatedHeight;
417 intel->drawX = 0;
418 intel->drawY = 0;
419 intel->numClipRects = 1;
420 intel->pClipRects = &fullRect;
421
422 intel->vtbl.meta_draw_region(intel, screen->rotated_region, NULL); /* ? */
423
424 if (srcBuf == BUFFER_BIT_FRONT_LEFT) {
425 src = intel->intelScreen->front_region;
426 clipRects = dPriv->pClipRects;
427 numClipRects = dPriv->numClipRects;
428 }
429 else {
430 src = intel->intelScreen->back_region;
431 clipRects = dPriv->pBackClipRects;
432 numClipRects = dPriv->numBackClipRects;
433 }
434
435 if (src->cpp == 4) {
436 format = GL_BGRA;
437 type = GL_UNSIGNED_BYTE;
438 }
439 else {
440 format = GL_BGR;
441 type = GL_UNSIGNED_SHORT_5_6_5_REV;
442 }
443
444 /* set the whole screen up as a texture to avoid alignment issues */
445 intel->vtbl.meta_tex_rect_source(intel,
446 src->buffer,
447 screen->width,
448 screen->height, src->pitch, format, type);
449
450 intel->vtbl.meta_texture_blend_replace(intel);
451
452 /*
453 * loop over the source window's cliprects
454 */
455 for (i = 0; i < numClipRects; i++) {
456 int srcX0 = clipRects[i].x1;
457 int srcY0 = clipRects[i].y1;
458 int srcX1 = clipRects[i].x2;
459 int srcY1 = clipRects[i].y2;
460 GLfloat verts[4][2], tex[4][2];
461 int j;
462
463 /* build vertices for four corners of clip rect */
464 verts[0][0] = srcX0;
465 verts[0][1] = srcY0;
466 verts[1][0] = srcX1;
467 verts[1][1] = srcY0;
468 verts[2][0] = srcX1;
469 verts[2][1] = srcY1;
470 verts[3][0] = srcX0;
471 verts[3][1] = srcY1;
472
473 /* .. and texcoords */
474 tex[0][0] = srcX0;
475 tex[0][1] = srcY0;
476 tex[1][0] = srcX1;
477 tex[1][1] = srcY0;
478 tex[2][0] = srcX1;
479 tex[2][1] = srcY1;
480 tex[3][0] = srcX0;
481 tex[3][1] = srcY1;
482
483 /* transform coords to rotated screen coords */
484
485 for (j = 0; j < 4; j++) {
486 matrix23TransformCoordf(&screen->rotMatrix,
487 &verts[j][0], &verts[j][1]);
488 }
489
490 /* draw polygon to map source image to dest region */
491 intel_meta_draw_poly(intel, 4, verts, 0, 0, tex);
492
493 } /* cliprect loop */
494
495 intel->vtbl.leave_meta_state(intel);
496 intel_batchbuffer_flush(intel->batch);
497
498 /* restore original drawing origin and cliprects */
499 intel->drawX = xOrig;
500 intel->drawY = yOrig;
501 intel->numClipRects = origNumClipRects;
502 intel->pClipRects = origRects;
503
504 UNLOCK_HARDWARE(intel);
505 }
506
507
508 /**
509 * Called by ctx->Driver.Clear.
510 */
511 static void
512 intelClear(GLcontext *ctx, GLbitfield mask)
513 {
514 struct intel_context *intel = intel_context(ctx);
515 const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
516 GLbitfield tri_mask = 0;
517 GLbitfield blit_mask = 0;
518 GLbitfield swrast_mask = 0;
519 GLuint i;
520
521 if (0)
522 fprintf(stderr, "%s\n", __FUNCTION__);
523
524 /* HW color buffers (front, back, aux, generic FBO, etc) */
525 if (colorMask == ~0) {
526 /* clear all R,G,B,A */
527 /* XXX FBO: need to check if colorbuffers are software RBOs! */
528 blit_mask |= (mask & BUFFER_BITS_COLOR);
529 }
530 else {
531 /* glColorMask in effect */
532 tri_mask |= (mask & BUFFER_BITS_COLOR);
533 }
534
535 /* HW stencil */
536 if (mask & BUFFER_BIT_STENCIL) {
537 const struct intel_region *stencilRegion
538 = intel_get_rb_region(ctx->DrawBuffer, BUFFER_STENCIL);
539 if (stencilRegion) {
540 /* have hw stencil */
541 if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
542 /* not clearing all stencil bits, so use triangle clearing */
543 tri_mask |= BUFFER_BIT_STENCIL;
544 }
545 else {
546 /* clearing all stencil bits, use blitting */
547 blit_mask |= BUFFER_BIT_STENCIL;
548 }
549 }
550 }
551
552 /* HW depth */
553 if (mask & BUFFER_BIT_DEPTH) {
554 /* clear depth with whatever method is used for stencil (see above) */
555 if (tri_mask & BUFFER_BIT_STENCIL)
556 tri_mask |= BUFFER_BIT_DEPTH;
557 else
558 blit_mask |= BUFFER_BIT_DEPTH;
559 }
560
561 /* SW fallback clearing */
562 swrast_mask = mask & ~tri_mask & ~blit_mask;
563
564 for (i = 0; i < BUFFER_COUNT; i++) {
565 GLuint bufBit = 1 << i;
566 if ((blit_mask | tri_mask) & bufBit) {
567 if (!ctx->DrawBuffer->Attachment[i].Renderbuffer->ClassID) {
568 blit_mask &= ~bufBit;
569 tri_mask &= ~bufBit;
570 swrast_mask |= bufBit;
571 }
572 }
573 }
574
575
576 intelFlush(ctx); /* XXX intelClearWithBlit also does this */
577
578 if (blit_mask)
579 intelClearWithBlit(ctx, blit_mask);
580
581 if (tri_mask)
582 intelClearWithTris(intel, tri_mask);
583
584 if (swrast_mask)
585 _swrast_Clear(ctx, swrast_mask);
586 }
587
588
589
590 /* Flip the front & back buffers
591 */
592 static void
593 intelPageFlip(const __DRIdrawablePrivate * dPriv)
594 {
595 #if 0
596 struct intel_context *intel;
597 int tmp, ret;
598
599 if (INTEL_DEBUG & DEBUG_IOCTL)
600 fprintf(stderr, "%s\n", __FUNCTION__);
601
602 assert(dPriv);
603 assert(dPriv->driContextPriv);
604 assert(dPriv->driContextPriv->driverPrivate);
605
606 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
607
608 intelFlush(&intel->ctx);
609 LOCK_HARDWARE(intel);
610
611 if (dPriv->pClipRects) {
612 *(drm_clip_rect_t *) intel->sarea->boxes = dPriv->pClipRects[0];
613 intel->sarea->nbox = 1;
614 }
615
616 ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
617 if (ret) {
618 fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
619 UNLOCK_HARDWARE(intel);
620 exit(1);
621 }
622
623 tmp = intel->sarea->last_enqueue;
624 intelRefillBatchLocked(intel);
625 UNLOCK_HARDWARE(intel);
626
627
628 intelSetDrawBuffer(&intel->ctx, intel->ctx.Color.DriverDrawBuffer);
629 #endif
630 }
631
632 #if 0
633 void
634 intelSwapBuffers(__DRIdrawablePrivate * dPriv)
635 {
636 if (dPriv->driverPrivate) {
637 const struct gl_framebuffer *fb
638 = (struct gl_framebuffer *) dPriv->driverPrivate;
639 if (fb->Visual.doubleBufferMode) {
640 GET_CURRENT_CONTEXT(ctx);
641 if (ctx && ctx->DrawBuffer == fb) {
642 _mesa_notifySwapBuffers(ctx); /* flush pending rendering */
643 }
644 if (0 /*intel->doPageFlip */ ) { /* doPageFlip is never set !!! */
645 intelPageFlip(dPriv);
646 }
647 else {
648 intelCopyBuffer(dPriv);
649 }
650 }
651 }
652 else {
653 _mesa_problem(NULL,
654 "dPriv has no gl_framebuffer pointer in intelSwapBuffers");
655 }
656 }
657 #else
658 /* Trunk version:
659 */
660 void
661 intelSwapBuffers(__DRIdrawablePrivate * dPriv)
662 {
663 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
664 GET_CURRENT_CONTEXT(ctx);
665 struct intel_context *intel;
666
667 if (ctx == NULL)
668 return;
669
670 intel = intel_context(ctx);
671
672 if (ctx->Visual.doubleBufferMode) {
673 intelScreenPrivate *screen = intel->intelScreen;
674 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
675 if (0 /*intel->doPageFlip */ ) { /* doPageFlip is never set !!! */
676 intelPageFlip(dPriv);
677 }
678 else {
679 intelCopyBuffer(dPriv, NULL);
680 }
681 if (screen->current_rotation != 0) {
682 intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
683 }
684 }
685 }
686 else {
687 /* XXX this shouldn't be an error but we can't handle it for now */
688 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
689 }
690 }
691 #endif
692
693 void
694 intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
695 {
696 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
697 struct intel_context *intel =
698 (struct intel_context *) dPriv->driContextPriv->driverPrivate;
699 GLcontext *ctx = &intel->ctx;
700
701 if (ctx->Visual.doubleBufferMode) {
702 drm_clip_rect_t rect;
703 rect.x1 = x + dPriv->x;
704 rect.y1 = (dPriv->h - y - h) + dPriv->y;
705 rect.x2 = rect.x1 + w;
706 rect.y2 = rect.y1 + h;
707 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
708 intelCopyBuffer(dPriv, &rect);
709 }
710 }
711 else {
712 /* XXX this shouldn't be an error but we can't handle it for now */
713 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
714 }
715 }
716
717
718 /**
719 * Update the hardware state for drawing into a window or framebuffer object.
720 *
721 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
722 * places within the driver.
723 *
724 * Basically, this needs to be called any time the current framebuffer
725 * changes, the renderbuffers change, or we need to draw into different
726 * color buffers.
727 */
728 void
729 intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb)
730 {
731 struct intel_context *intel = intel_context(ctx);
732 struct intel_region *colorRegion, *depthRegion = NULL;
733 struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL;
734 int front = 0; /* drawing to front color buffer? */
735
736 if (!fb) {
737 /* this can happen during the initial context initialization */
738 return;
739 }
740
741 /* Do this here, note core Mesa, since this function is called from
742 * many places within the driver.
743 */
744 if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
745 /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
746 _mesa_update_framebuffer(ctx);
747 /* this updates the DrawBuffer's Width/Height if it's a FBO */
748 _mesa_update_draw_buffer_bounds(ctx);
749 }
750
751 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
752 /* this may occur when we're called by glBindFrameBuffer() during
753 * the process of someone setting up renderbuffers, etc.
754 */
755 /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
756 return;
757 }
758
759 if (fb->Name)
760 intel_validate_paired_depth_stencil(ctx, fb);
761
762 /*
763 * How many color buffers are we drawing into?
764 */
765 if (fb->_NumColorDrawBuffers[0] != 1
766 #if 0
767 /* XXX FBO temporary - always use software rendering */
768 || 1
769 #endif
770 ) {
771 /* writing to 0 or 2 or 4 color buffers */
772 /*_mesa_debug(ctx, "Software rendering\n");*/
773 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
774 front = 1; /* might not have back color buffer */
775 }
776 else {
777 /* draw to exactly one color buffer */
778 /*_mesa_debug(ctx, "Hardware rendering\n");*/
779 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
780 if (fb->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT) {
781 front = 1;
782 }
783 }
784
785 /*
786 * Get the intel_renderbuffer for the colorbuffer we're drawing into.
787 * And set up cliprects.
788 */
789 if (fb->Name == 0) {
790 /* drawing to window system buffer */
791 if (intel->sarea->pf_current_page == 1) {
792 /* page flipped back/front */
793 front ^= 1;
794 }
795 if (front) {
796 intelSetFrontClipRects(intel);
797 colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
798 }
799 else {
800 intelSetBackClipRects(intel);
801 colorRegion = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
802 }
803 }
804 else {
805 /* drawing to user-created FBO */
806 struct intel_renderbuffer *irb;
807 intelSetRenderbufferClipRects(intel);
808 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0][0]);
809 colorRegion = (irb && irb->region) ? irb->region : NULL;
810 }
811
812 /* Update culling direction which changes depending on the
813 * orientation of the buffer:
814 */
815 if (ctx->Driver.FrontFace)
816 ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
817 else
818 ctx->NewState |= _NEW_POLYGON;
819
820 if (!colorRegion) {
821 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
822 }
823 else {
824 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
825 }
826
827 /***
828 *** Get depth buffer region and check if we need a software fallback.
829 *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
830 ***/
831 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
832 irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped);
833 if (irbDepth && irbDepth->region) {
834 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
835 depthRegion = irbDepth->region;
836 }
837 else {
838 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE);
839 depthRegion = NULL;
840 }
841 }
842 else {
843 /* not using depth buffer */
844 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
845 depthRegion = NULL;
846 }
847
848 /***
849 *** Stencil buffer
850 *** This can only be hardware accelerated if we're using a
851 *** combined DEPTH_STENCIL buffer (for now anyway).
852 ***/
853 if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
854 irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped);
855 if (irbStencil && irbStencil->region) {
856 ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
857 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
858 /* need to re-compute stencil hw state */
859 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
860 if (!depthRegion)
861 depthRegion = irbStencil->region;
862 }
863 else {
864 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE);
865 }
866 }
867 else {
868 /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */
869 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
870 /* need to re-compute stencil hw state */
871 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
872 }
873
874
875 /**
876 ** Release old regions, reference new regions
877 **/
878 #if 0 /* XXX FBO: this seems to be redundant with i915_state_draw_region() */
879 if (intel->draw_region != colorRegion) {
880 intel_region_release(&intel->draw_region);
881 intel_region_reference(&intel->draw_region, colorRegion);
882 }
883 if (intel->intelScreen->depth_region != depthRegion) {
884 intel_region_release(&intel->intelScreen->depth_region);
885 intel_region_reference(&intel->intelScreen->depth_region, depthRegion);
886 }
887 #endif
888
889 intel->vtbl.set_draw_region(intel, colorRegion, depthRegion);
890
891 /* update viewport since it depends on window size */
892 ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
893 ctx->Viewport.Width, ctx->Viewport.Height);
894
895 /* Update hardware scissor */
896 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
897 ctx->Scissor.Width, ctx->Scissor.Height);
898 }
899
900
901 static void
902 intelDrawBuffer(GLcontext * ctx, GLenum mode)
903 {
904 intel_draw_buffer(ctx, ctx->DrawBuffer);
905 }
906
907
908 static void
909 intelReadBuffer(GLcontext * ctx, GLenum mode)
910 {
911 if (ctx->ReadBuffer == ctx->DrawBuffer) {
912 /* This will update FBO completeness status.
913 * A framebuffer will be incomplete if the GL_READ_BUFFER setting
914 * refers to a missing renderbuffer. Calling glReadBuffer can set
915 * that straight and can make the drawing buffer complete.
916 */
917 intel_draw_buffer(ctx, ctx->DrawBuffer);
918 }
919 /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc)
920 * reference ctx->ReadBuffer and do appropriate state checks.
921 */
922 }
923
924
925 void
926 intelInitBufferFuncs(struct dd_function_table *functions)
927 {
928 functions->Clear = intelClear;
929 functions->DrawBuffer = intelDrawBuffer;
930 functions->ReadBuffer = intelReadBuffer;
931 }