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