intel_buffers.c revision 6cb3f5c4d8618a14bb7ad1d9df10ed7e648a7b2b
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "intel_screen.h" 29#include "intel_context.h" 30#include "intel_blit.h" 31#include "intel_buffers.h" 32#include "intel_chipset.h" 33#include "intel_depthstencil.h" 34#include "intel_fbo.h" 35#include "intel_regions.h" 36#include "intel_batchbuffer.h" 37#include "intel_reg.h" 38#include "context.h" 39#include "utils.h" 40#include "drirenderbuffer.h" 41#include "framebuffer.h" 42#include "swrast/swrast.h" 43#include "vblank.h" 44#include "i915_drm.h" 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#define FILE_DEBUG_FLAG DEBUG_BLIT 63 64/** 65 * XXX move this into a new dri/common/cliprects.c file. 66 */ 67GLboolean 68intel_intersect_cliprects(drm_clip_rect_t * dst, 69 const drm_clip_rect_t * a, 70 const drm_clip_rect_t * b) 71{ 72 GLint bx = b->x1; 73 GLint by = b->y1; 74 GLint bw = b->x2 - bx; 75 GLint bh = b->y2 - by; 76 77 if (bx < a->x1) 78 bw -= a->x1 - bx, bx = a->x1; 79 if (by < a->y1) 80 bh -= a->y1 - by, by = a->y1; 81 if (bx + bw > a->x2) 82 bw = a->x2 - bx; 83 if (by + bh > a->y2) 84 bh = a->y2 - by; 85 if (bw <= 0) 86 return GL_FALSE; 87 if (bh <= 0) 88 return GL_FALSE; 89 90 dst->x1 = bx; 91 dst->y1 = by; 92 dst->x2 = bx + bw; 93 dst->y2 = by + bh; 94 95 return GL_TRUE; 96} 97 98/** 99 * Return pointer to current color drawing region, or NULL. 100 */ 101struct intel_region * 102intel_drawbuf_region(struct intel_context *intel) 103{ 104 struct intel_renderbuffer *irbColor = 105 intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0]); 106 if (irbColor) 107 return irbColor->region; 108 else 109 return NULL; 110} 111 112/** 113 * Return pointer to current color reading region, or NULL. 114 */ 115struct intel_region * 116intel_readbuf_region(struct intel_context *intel) 117{ 118 struct intel_renderbuffer *irb 119 = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer); 120 if (irb) 121 return irb->region; 122 else 123 return NULL; 124} 125 126 127 128/** 129 * Update the following fields for rendering to a user-created FBO: 130 * intel->numClipRects 131 * intel->pClipRects 132 * intel->drawX 133 * intel->drawY 134 */ 135static void 136intelSetRenderbufferClipRects(struct intel_context *intel) 137{ 138 assert(intel->ctx.DrawBuffer->Width > 0); 139 assert(intel->ctx.DrawBuffer->Height > 0); 140 intel->fboRect.x1 = 0; 141 intel->fboRect.y1 = 0; 142 intel->fboRect.x2 = intel->ctx.DrawBuffer->Width; 143 intel->fboRect.y2 = intel->ctx.DrawBuffer->Height; 144 intel->numClipRects = 1; 145 intel->pClipRects = &intel->fboRect; 146 intel->drawX = 0; 147 intel->drawY = 0; 148} 149 150 151/** 152 * As above, but for rendering to front buffer of a window. 153 * \sa intelSetRenderbufferClipRects 154 */ 155static void 156intelSetFrontClipRects(struct intel_context *intel) 157{ 158 __DRIdrawablePrivate *dPriv = intel->driDrawable; 159 160 if (!dPriv) 161 return; 162 163 intel->numClipRects = dPriv->numClipRects; 164 intel->pClipRects = dPriv->pClipRects; 165 intel->drawX = dPriv->x; 166 intel->drawY = dPriv->y; 167} 168 169 170/** 171 * As above, but for rendering to back buffer of a window. 172 */ 173static void 174intelSetBackClipRects(struct intel_context *intel) 175{ 176 __DRIdrawablePrivate *dPriv = intel->driDrawable; 177 struct intel_framebuffer *intel_fb; 178 179 if (!dPriv) 180 return; 181 182 intel_fb = dPriv->driverPrivate; 183 184 if (intel_fb->pf_active || dPriv->numBackClipRects == 0) { 185 /* use the front clip rects */ 186 intel->numClipRects = dPriv->numClipRects; 187 intel->pClipRects = dPriv->pClipRects; 188 intel->drawX = dPriv->x; 189 intel->drawY = dPriv->y; 190 } 191 else { 192 /* use the back clip rects */ 193 intel->numClipRects = dPriv->numBackClipRects; 194 intel->pClipRects = dPriv->pBackClipRects; 195 intel->drawX = dPriv->backX; 196 intel->drawY = dPriv->backY; 197 } 198} 199 200#ifdef I915 201static void 202intelUpdatePageFlipping(struct intel_context *intel, 203 GLint areaA, GLint areaB) 204{ 205 __DRIdrawablePrivate *dPriv = intel->driDrawable; 206 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 207 GLboolean pf_active; 208 GLint pf_planes; 209 210 /* Update page flipping info */ 211 pf_planes = 0; 212 213 if (areaA > 0) 214 pf_planes |= 1; 215 216 if (areaB > 0) 217 pf_planes |= 2; 218 219 intel_fb->pf_current_page = (intel->sarea->pf_current_page >> 220 (intel_fb->pf_planes & 0x2)) & 0x3; 221 222 intel_fb->pf_num_pages = intel->intelScreen->third.handle ? 3 : 2; 223 224 pf_active = pf_planes && (pf_planes & intel->sarea->pf_active) == pf_planes; 225 226 if (INTEL_DEBUG & DEBUG_LOCK) 227 if (pf_active != intel_fb->pf_active) 228 _mesa_printf("%s - Page flipping %sactive\n", __progname, 229 pf_active ? "" : "in"); 230 231 if (pf_active) { 232 /* Sync pages between planes if flipping on both at the same time */ 233 if (pf_planes == 0x3 && pf_planes != intel_fb->pf_planes && 234 (intel->sarea->pf_current_page & 0x3) != 235 (((intel->sarea->pf_current_page) >> 2) & 0x3)) { 236 drm_i915_flip_t flip; 237 238 if (intel_fb->pf_current_page == 239 (intel->sarea->pf_current_page & 0x3)) { 240 /* XXX: This is ugly, but emitting two flips 'in a row' can cause 241 * lockups for unknown reasons. 242 */ 243 intel->sarea->pf_current_page = 244 intel->sarea->pf_current_page & 0x3; 245 intel->sarea->pf_current_page |= 246 ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) % 247 intel_fb->pf_num_pages) << 2; 248 249 flip.pipes = 0x2; 250 } else { 251 intel->sarea->pf_current_page = 252 intel->sarea->pf_current_page & (0x3 << 2); 253 intel->sarea->pf_current_page |= 254 (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) % 255 intel_fb->pf_num_pages; 256 257 flip.pipes = 0x1; 258 } 259 260 drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip)); 261 } 262 263 intel_fb->pf_planes = pf_planes; 264 } 265 266 intel_fb->pf_active = pf_active; 267 intel_flip_renderbuffers(intel_fb); 268 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer); 269} 270#endif /* I915 */ 271 272/** 273 * This will be called whenever the currently bound window is moved/resized. 274 * XXX: actually, it seems to NOT be called when the window is only moved (BP). 275 */ 276void 277intelWindowMoved(struct intel_context *intel) 278{ 279 GLcontext *ctx = &intel->ctx; 280 __DRIdrawablePrivate *dPriv = intel->driDrawable; 281 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 282 283 if (!intel->ctx.DrawBuffer) { 284 /* when would this happen? -BP */ 285 intelSetFrontClipRects(intel); 286 } 287 else if (intel->ctx.DrawBuffer->Name != 0) { 288 /* drawing to user-created FBO - do nothing */ 289 /* Cliprects would be set from intelDrawBuffer() */ 290 } 291 else { 292 /* drawing to a window */ 293 switch (intel_fb->Base._ColorDrawBufferIndexes[0]) { 294 case BUFFER_FRONT_LEFT: 295 intelSetFrontClipRects(intel); 296 break; 297 case BUFFER_BACK_LEFT: 298 intelSetBackClipRects(intel); 299 break; 300 default: 301 intelSetFrontClipRects(intel); 302 } 303 } 304 305 if (!intel->intelScreen->driScrnPriv->dri2.enabled && 306 intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) { 307 volatile struct drm_i915_sarea *sarea = intel->sarea; 308 drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w, 309 .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h }; 310 drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y, 311 .x2 = sarea->planeA_x + sarea->planeA_w, 312 .y2 = sarea->planeA_y + sarea->planeA_h }; 313 drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y, 314 .x2 = sarea->planeB_x + sarea->planeB_w, 315 .y2 = sarea->planeB_y + sarea->planeB_h }; 316 GLint areaA = driIntersectArea( drw_rect, planeA_rect ); 317 GLint areaB = driIntersectArea( drw_rect, planeB_rect ); 318 GLuint flags = dPriv->vblFlags; 319 320#ifdef I915 321 intelUpdatePageFlipping(intel, areaA, areaB); 322#endif 323 324 /* Update vblank info 325 */ 326 if (areaB > areaA || (areaA == areaB && areaB > 0)) { 327 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY; 328 } else { 329 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; 330 } 331 332 /* Check to see if we changed pipes */ 333 if (flags != dPriv->vblFlags && dPriv->vblFlags && 334 !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) { 335 int64_t count; 336 drmVBlank vbl; 337 int i; 338 339 /* 340 * Deal with page flipping 341 */ 342 vbl.request.type = DRM_VBLANK_ABSOLUTE; 343 344 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) { 345 vbl.request.type |= DRM_VBLANK_SECONDARY; 346 } 347 348 for (i = 0; i < intel_fb->pf_num_pages; i++) { 349 if (!intel_fb->color_rb[i] || 350 (intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <= 351 (1<<23)) 352 continue; 353 354 vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending; 355 drmWaitVBlank(intel->driFd, &vbl); 356 } 357 358 /* 359 * Update msc_base from old pipe 360 */ 361 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count); 362 dPriv->msc_base = count; 363 /* 364 * Then get new vblank_base and vblSeq values 365 */ 366 dPriv->vblFlags = flags; 367 driGetCurrentVBlank(dPriv); 368 dPriv->vblank_base = dPriv->vblSeq; 369 370 intel_fb->vbl_waited = dPriv->vblSeq; 371 372 for (i = 0; i < intel_fb->pf_num_pages; i++) { 373 if (intel_fb->color_rb[i]) 374 intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited; 375 } 376 } 377 } else { 378 dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY; 379 } 380 381 /* Update Mesa's notion of window size */ 382 driUpdateFramebufferSize(ctx, dPriv); 383 intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */ 384 385 /* Update hardware scissor */ 386 if (ctx->Driver.Scissor != NULL) { 387 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, 388 ctx->Scissor.Width, ctx->Scissor.Height); 389 } 390 391 /* Re-calculate viewport related state */ 392 if (ctx->Driver.DepthRange != NULL) 393 ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far ); 394} 395 396 397 398/* A true meta version of this would be very simple and additionally 399 * machine independent. Maybe we'll get there one day. 400 */ 401static void 402intelClearWithTris(struct intel_context *intel, GLbitfield mask) 403{ 404 GLcontext *ctx = &intel->ctx; 405 struct gl_framebuffer *fb = ctx->DrawBuffer; 406 GLuint buf; 407 408 intel->vtbl.install_meta_state(intel); 409 410 /* Back and stencil cliprects are the same. Try and do both 411 * buffers at once: 412 */ 413 if (mask & (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) { 414 struct intel_region *backRegion = 415 intel_get_rb_region(fb, BUFFER_BACK_LEFT); 416 struct intel_region *depthRegion = 417 intel_get_rb_region(fb, BUFFER_DEPTH); 418 419 intel->vtbl.meta_draw_region(intel, backRegion, depthRegion); 420 421 if (mask & BUFFER_BIT_BACK_LEFT) 422 intel->vtbl.meta_color_mask(intel, GL_TRUE); 423 else 424 intel->vtbl.meta_color_mask(intel, GL_FALSE); 425 426 if (mask & BUFFER_BIT_STENCIL) 427 intel->vtbl.meta_stencil_replace(intel, 428 intel->ctx.Stencil.WriteMask[0], 429 intel->ctx.Stencil.Clear); 430 else 431 intel->vtbl.meta_no_stencil_write(intel); 432 433 if (mask & BUFFER_BIT_DEPTH) 434 intel->vtbl.meta_depth_replace(intel); 435 else 436 intel->vtbl.meta_no_depth_write(intel); 437 438 intel->vtbl.meta_draw_quad(intel, 439 fb->_Xmin, 440 fb->_Xmax, 441 fb->_Ymin, 442 fb->_Ymax, 443 intel->ctx.Depth.Clear, 444 intel->ClearColor8888, 445 0, 0, 0, 0); /* texcoords */ 446 447 mask &= ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH); 448 } 449 450 /* clear the remaining (color) renderbuffers */ 451 for (buf = 0; buf < BUFFER_COUNT && mask; buf++) { 452 const GLuint bufBit = 1 << buf; 453 if (mask & bufBit) { 454 struct intel_renderbuffer *irbColor = 455 intel_renderbuffer(fb->Attachment[buf].Renderbuffer); 456 457 ASSERT(irbColor); 458 459 intel->vtbl.meta_no_depth_write(intel); 460 intel->vtbl.meta_no_stencil_write(intel); 461 intel->vtbl.meta_color_mask(intel, GL_TRUE); 462 intel->vtbl.meta_draw_region(intel, irbColor->region, NULL); 463 464 intel->vtbl.meta_draw_quad(intel, 465 fb->_Xmin, 466 fb->_Xmax, 467 fb->_Ymin, 468 fb->_Ymax, 469 0, intel->ClearColor8888, 470 0, 0, 0, 0); /* texcoords */ 471 472 mask &= ~bufBit; 473 } 474 } 475 476 intel->vtbl.leave_meta_state(intel); 477} 478 479static const char *buffer_names[] = { 480 [BUFFER_FRONT_LEFT] = "front", 481 [BUFFER_BACK_LEFT] = "back", 482 [BUFFER_FRONT_RIGHT] = "front right", 483 [BUFFER_BACK_RIGHT] = "back right", 484 [BUFFER_AUX0] = "aux0", 485 [BUFFER_AUX1] = "aux1", 486 [BUFFER_AUX2] = "aux2", 487 [BUFFER_AUX3] = "aux3", 488 [BUFFER_DEPTH] = "depth", 489 [BUFFER_STENCIL] = "stencil", 490 [BUFFER_ACCUM] = "accum", 491 [BUFFER_COLOR0] = "color0", 492 [BUFFER_COLOR1] = "color1", 493 [BUFFER_COLOR2] = "color2", 494 [BUFFER_COLOR3] = "color3", 495 [BUFFER_COLOR4] = "color4", 496 [BUFFER_COLOR5] = "color5", 497 [BUFFER_COLOR6] = "color6", 498 [BUFFER_COLOR7] = "color7", 499}; 500 501/** 502 * Called by ctx->Driver.Clear. 503 */ 504static void 505intelClear(GLcontext *ctx, GLbitfield mask) 506{ 507 struct intel_context *intel = intel_context(ctx); 508 const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask); 509 GLbitfield tri_mask = 0; 510 GLbitfield blit_mask = 0; 511 GLbitfield swrast_mask = 0; 512 struct gl_framebuffer *fb = ctx->DrawBuffer; 513 GLuint i; 514 515 if (0) 516 fprintf(stderr, "%s\n", __FUNCTION__); 517 518 /* HW color buffers (front, back, aux, generic FBO, etc) */ 519 if (colorMask == ~0) { 520 /* clear all R,G,B,A */ 521 /* XXX FBO: need to check if colorbuffers are software RBOs! */ 522 blit_mask |= (mask & BUFFER_BITS_COLOR); 523 } 524 else { 525 /* glColorMask in effect */ 526 tri_mask |= (mask & BUFFER_BITS_COLOR); 527 } 528 529 /* HW stencil */ 530 if (mask & BUFFER_BIT_STENCIL) { 531 const struct intel_region *stencilRegion 532 = intel_get_rb_region(fb, BUFFER_STENCIL); 533 if (stencilRegion) { 534 /* have hw stencil */ 535 if (IS_965(intel->intelScreen->deviceID) || 536 (ctx->Stencil.WriteMask[0] & 0xff) != 0xff) { 537 /* We have to use the 3D engine if we're clearing a partial mask 538 * of the stencil buffer, or if we're on a 965 which has a tiled 539 * depth/stencil buffer in a layout we can't blit to. 540 */ 541 tri_mask |= BUFFER_BIT_STENCIL; 542 } 543 else { 544 /* clearing all stencil bits, use blitting */ 545 blit_mask |= BUFFER_BIT_STENCIL; 546 } 547 } 548 } 549 550 /* HW depth */ 551 if (mask & BUFFER_BIT_DEPTH) { 552 /* clear depth with whatever method is used for stencil (see above) */ 553 if (IS_965(intel->intelScreen->deviceID) || 554 tri_mask & BUFFER_BIT_STENCIL) 555 tri_mask |= BUFFER_BIT_DEPTH; 556 else 557 blit_mask |= BUFFER_BIT_DEPTH; 558 } 559 560 /* SW fallback clearing */ 561 swrast_mask = mask & ~tri_mask & ~blit_mask; 562 563 for (i = 0; i < BUFFER_COUNT; i++) { 564 GLuint bufBit = 1 << i; 565 if ((blit_mask | tri_mask) & bufBit) { 566 if (!fb->Attachment[i].Renderbuffer->ClassID) { 567 blit_mask &= ~bufBit; 568 tri_mask &= ~bufBit; 569 swrast_mask |= bufBit; 570 } 571 } 572 } 573 574 if (blit_mask) { 575 if (INTEL_DEBUG & DEBUG_BLIT) { 576 DBG("blit clear:"); 577 for (i = 0; i < BUFFER_COUNT; i++) { 578 if (blit_mask & (1 << i)) 579 DBG(" %s", buffer_names[i]); 580 } 581 DBG("\n"); 582 } 583 intelClearWithBlit(ctx, blit_mask); 584 } 585 586 if (tri_mask) { 587 if (INTEL_DEBUG & DEBUG_BLIT) { 588 DBG("tri clear:"); 589 for (i = 0; i < BUFFER_COUNT; i++) { 590 if (tri_mask & (1 << i)) 591 DBG(" %s", buffer_names[i]); 592 } 593 DBG("\n"); 594 } 595 intelClearWithTris(intel, tri_mask); 596 } 597 598 if (swrast_mask) { 599 if (INTEL_DEBUG & DEBUG_BLIT) { 600 DBG("swrast clear:"); 601 for (i = 0; i < BUFFER_COUNT; i++) { 602 if (swrast_mask & (1 << i)) 603 DBG(" %s", buffer_names[i]); 604 } 605 DBG("\n"); 606 } 607 _swrast_Clear(ctx, swrast_mask); 608 } 609} 610 611 612/* Emit wait for pending flips */ 613void 614intel_wait_flips(struct intel_context *intel) 615{ 616 struct intel_framebuffer *intel_fb = 617 (struct intel_framebuffer *) intel->ctx.DrawBuffer; 618 struct intel_renderbuffer *intel_rb = 619 intel_get_renderbuffer(&intel_fb->Base, 620 intel_fb->Base._ColorDrawBufferIndexes[0] == 621 BUFFER_FRONT_LEFT ? BUFFER_FRONT_LEFT : 622 BUFFER_BACK_LEFT); 623 624 if (intel_fb->Base.Name == 0 && intel_rb && 625 intel_rb->pf_pending == intel_fb->pf_seq) { 626 GLint pf_planes = intel_fb->pf_planes; 627 BATCH_LOCALS; 628 629 /* Wait for pending flips to take effect */ 630 BEGIN_BATCH(2, NO_LOOP_CLIPRECTS); 631 OUT_BATCH(pf_planes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP) 632 : 0); 633 OUT_BATCH(pf_planes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP) 634 : 0); 635 ADVANCE_BATCH(); 636 637 intel_rb->pf_pending--; 638 } 639} 640 641 642/* Flip the front & back buffers 643 */ 644static GLboolean 645intelPageFlip(const __DRIdrawablePrivate * dPriv) 646{ 647#ifdef I915 648 struct intel_context *intel; 649 int ret; 650 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 651 652 if (INTEL_DEBUG & DEBUG_IOCTL) 653 fprintf(stderr, "%s\n", __FUNCTION__); 654 655 assert(dPriv); 656 assert(dPriv->driContextPriv); 657 assert(dPriv->driContextPriv->driverPrivate); 658 659 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate; 660 661 if (intel->intelScreen->drmMinor < 9) 662 return GL_FALSE; 663 664 intelFlush(&intel->ctx); 665 666 ret = 0; 667 668 LOCK_HARDWARE(intel); 669 670 if (dPriv->numClipRects && intel_fb->pf_active) { 671 drm_i915_flip_t flip; 672 673 flip.pipes = intel_fb->pf_planes; 674 675 ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip)); 676 } 677 678 UNLOCK_HARDWARE(intel); 679 680 if (ret || !intel_fb->pf_active) 681 return GL_FALSE; 682 683 if (!dPriv->numClipRects) { 684 usleep(10000); /* throttle invisible client 10ms */ 685 } 686 687 intel_fb->pf_current_page = (intel->sarea->pf_current_page >> 688 (intel_fb->pf_planes & 0x2)) & 0x3; 689 690 if (dPriv->numClipRects != 0) { 691 intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending = 692 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending = 693 ++intel_fb->pf_seq; 694 } 695 696 intel_flip_renderbuffers(intel_fb); 697 intel_draw_buffer(&intel->ctx, &intel_fb->Base); 698 699 return GL_TRUE; 700#else 701 return GL_FALSE; 702#endif 703} 704 705#if 0 706void 707intelSwapBuffers(__DRIdrawablePrivate * dPriv) 708{ 709 if (dPriv->driverPrivate) { 710 const struct gl_framebuffer *fb 711 = (struct gl_framebuffer *) dPriv->driverPrivate; 712 if (fb->Visual.doubleBufferMode) { 713 GET_CURRENT_CONTEXT(ctx); 714 if (ctx && ctx->DrawBuffer == fb) { 715 _mesa_notifySwapBuffers(ctx); /* flush pending rendering */ 716 } 717 if (intel->doPageFlip) { 718 intelPageFlip(dPriv); 719 } 720 else { 721 intelCopyBuffer(dPriv); 722 } 723 } 724 } 725 else { 726 _mesa_problem(NULL, 727 "dPriv has no gl_framebuffer pointer in intelSwapBuffers"); 728 } 729} 730#else 731/* Trunk version: 732 */ 733 734static GLboolean 735intelScheduleSwap(__DRIdrawablePrivate * dPriv, GLboolean *missed_target) 736{ 737 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 738 unsigned int interval; 739 struct intel_context *intel = 740 intelScreenContext(dPriv->driScreenPriv->private); 741 const intelScreenPrivate *intelScreen = intel->intelScreen; 742 unsigned int target; 743 drm_i915_vblank_swap_t swap; 744 GLboolean ret; 745 746 if (!dPriv->vblFlags || 747 (dPriv->vblFlags & VBLANK_FLAG_NO_IRQ) || 748 intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6)) 749 return GL_FALSE; 750 751 interval = driGetVBlankInterval(dPriv); 752 753 swap.seqtype = DRM_VBLANK_ABSOLUTE; 754 755 if (dPriv->vblFlags & VBLANK_FLAG_SYNC) { 756 swap.seqtype |= DRM_VBLANK_NEXTONMISS; 757 } else if (interval == 0) { 758 return GL_FALSE; 759 } 760 761 swap.drawable = dPriv->hHWDrawable; 762 target = swap.sequence = dPriv->vblSeq + interval; 763 764 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) { 765 swap.seqtype |= DRM_VBLANK_SECONDARY; 766 } 767 768 LOCK_HARDWARE(intel); 769 770 intel_batchbuffer_flush(intel->batch); 771 772 if ( intel_fb->pf_active ) { 773 swap.seqtype |= DRM_VBLANK_FLIP; 774 775 intel_fb->pf_current_page = (((intel->sarea->pf_current_page >> 776 (intel_fb->pf_planes & 0x2)) & 0x3) + 1) % 777 intel_fb->pf_num_pages; 778 } 779 780 if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap, 781 sizeof(swap))) { 782 dPriv->vblSeq = swap.sequence; 783 swap.sequence -= target; 784 *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23); 785 786 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending = 787 intel_get_renderbuffer(&intel_fb->Base, 788 BUFFER_FRONT_LEFT)->vbl_pending = 789 dPriv->vblSeq; 790 791 if (swap.seqtype & DRM_VBLANK_FLIP) { 792 intel_flip_renderbuffers(intel_fb); 793 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer); 794 } 795 796 ret = GL_TRUE; 797 } else { 798 if (swap.seqtype & DRM_VBLANK_FLIP) { 799 intel_fb->pf_current_page = ((intel->sarea->pf_current_page >> 800 (intel_fb->pf_planes & 0x2)) & 0x3) % 801 intel_fb->pf_num_pages; 802 } 803 804 ret = GL_FALSE; 805 } 806 807 UNLOCK_HARDWARE(intel); 808 809 return ret; 810} 811 812void 813intelSwapBuffers(__DRIdrawablePrivate * dPriv) 814{ 815 __DRIscreenPrivate *psp = dPriv->driScreenPriv; 816 817 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { 818 GET_CURRENT_CONTEXT(ctx); 819 struct intel_context *intel; 820 821 if (ctx == NULL) 822 return; 823 824 intel = intel_context(ctx); 825 826 if (ctx->Visual.doubleBufferMode) { 827 GLboolean missed_target; 828 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 829 int64_t ust; 830 831 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ 832 833 if (!intelScheduleSwap(dPriv, &missed_target)) { 834 driWaitForVBlank(dPriv, &missed_target); 835 836 if (!intelPageFlip(dPriv)) { 837 intelCopyBuffer(dPriv, NULL); 838 } 839 } 840 841 intel_fb->swap_count++; 842 (*psp->systemTime->getUST) (&ust); 843 if (missed_target) { 844 intel_fb->swap_missed_count++; 845 intel_fb->swap_missed_ust = ust - intel_fb->swap_ust; 846 } 847 848 intel_fb->swap_ust = ust; 849 } 850 } 851 else { 852 /* XXX this shouldn't be an error but we can't handle it for now */ 853 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); 854 } 855} 856#endif 857 858void 859intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h) 860{ 861 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { 862 struct intel_context *intel = 863 (struct intel_context *) dPriv->driContextPriv->driverPrivate; 864 GLcontext *ctx = &intel->ctx; 865 866 if (ctx->Visual.doubleBufferMode) { 867 drm_clip_rect_t rect; 868 rect.x1 = x + dPriv->x; 869 rect.y1 = (dPriv->h - y - h) + dPriv->y; 870 rect.x2 = rect.x1 + w; 871 rect.y2 = rect.y1 + h; 872 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ 873 intelCopyBuffer(dPriv, &rect); 874 } 875 } 876 else { 877 /* XXX this shouldn't be an error but we can't handle it for now */ 878 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); 879 } 880} 881 882 883/** 884 * Update the hardware state for drawing into a window or framebuffer object. 885 * 886 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other 887 * places within the driver. 888 * 889 * Basically, this needs to be called any time the current framebuffer 890 * changes, the renderbuffers change, or we need to draw into different 891 * color buffers. 892 */ 893void 894intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb) 895{ 896 struct intel_context *intel = intel_context(ctx); 897 struct intel_region *colorRegion, *depthRegion = NULL; 898 struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; 899 int front = 0; /* drawing to front color buffer? */ 900 901 if (!fb) { 902 /* this can happen during the initial context initialization */ 903 return; 904 } 905 906 /* Do this here, note core Mesa, since this function is called from 907 * many places within the driver. 908 */ 909 if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) { 910 /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ 911 _mesa_update_framebuffer(ctx); 912 /* this updates the DrawBuffer's Width/Height if it's a FBO */ 913 _mesa_update_draw_buffer_bounds(ctx); 914 } 915 916 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 917 /* this may occur when we're called by glBindFrameBuffer() during 918 * the process of someone setting up renderbuffers, etc. 919 */ 920 /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/ 921 return; 922 } 923 924 if (fb->Name) 925 intel_validate_paired_depth_stencil(ctx, fb); 926 927 /* If the batch contents require looping over cliprects, flush them before 928 * we go changing which cliprects get referenced when that happens. 929 */ 930 if (intel->batch->cliprect_mode == LOOP_CLIPRECTS) 931 intel_batchbuffer_flush(intel->batch); 932 933 /* 934 * How many color buffers are we drawing into? 935 */ 936 if (fb->_NumColorDrawBuffers != 1) { 937 /* writing to 0 or 2 or 4 color buffers */ 938 /*_mesa_debug(ctx, "Software rendering\n");*/ 939 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); 940 colorRegion = NULL; 941 942 if (fb->Name != 0) 943 intelSetRenderbufferClipRects(intel); 944 } 945 else { 946 /* draw to exactly one color buffer */ 947 /*_mesa_debug(ctx, "Hardware rendering\n");*/ 948 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); 949 if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { 950 front = 1; 951 } 952 953 /* 954 * Get the intel_renderbuffer for the colorbuffer we're drawing into. 955 * And set up cliprects. 956 */ 957 if (fb->Name == 0) { 958 /* drawing to window system buffer */ 959 if (front) { 960 intelSetFrontClipRects(intel); 961 colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); 962 } 963 else { 964 intelSetBackClipRects(intel); 965 colorRegion = intel_get_rb_region(fb, BUFFER_BACK_LEFT); 966 } 967 } 968 else { 969 /* drawing to user-created FBO */ 970 struct intel_renderbuffer *irb; 971 intelSetRenderbufferClipRects(intel); 972 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); 973 colorRegion = (irb && irb->region) ? irb->region : NULL; 974 } 975 } 976 977 /* Update culling direction which changes depending on the 978 * orientation of the buffer: 979 */ 980 if (ctx->Driver.FrontFace) 981 ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace); 982 else 983 ctx->NewState |= _NEW_POLYGON; 984 985 if (!colorRegion) { 986 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); 987 } 988 else { 989 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); 990 } 991 992 /*** 993 *** Get depth buffer region and check if we need a software fallback. 994 *** Note that the depth buffer is usually a DEPTH_STENCIL buffer. 995 ***/ 996 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { 997 irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); 998 if (irbDepth && irbDepth->region) { 999 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 1000 depthRegion = irbDepth->region; 1001 } 1002 else { 1003 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE); 1004 depthRegion = NULL; 1005 } 1006 } 1007 else { 1008 /* not using depth buffer */ 1009 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 1010 depthRegion = NULL; 1011 } 1012 1013 /*** 1014 *** Stencil buffer 1015 *** This can only be hardware accelerated if we're using a 1016 *** combined DEPTH_STENCIL buffer (for now anyway). 1017 ***/ 1018 if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { 1019 irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); 1020 if (irbStencil && irbStencil->region) { 1021 ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); 1022 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 1023 /* need to re-compute stencil hw state */ 1024 if (ctx->Driver.Enable != NULL) 1025 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); 1026 else 1027 ctx->NewState |= _NEW_STENCIL; 1028 if (!depthRegion) 1029 depthRegion = irbStencil->region; 1030 } 1031 else { 1032 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE); 1033 } 1034 } 1035 else { 1036 /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */ 1037 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 1038 /* need to re-compute stencil hw state */ 1039 if (ctx->Driver.Enable != NULL) 1040 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); 1041 else 1042 ctx->NewState |= _NEW_STENCIL; 1043 } 1044 1045 /* 1046 * Update depth test state 1047 */ 1048 if (ctx->Driver.Enable) { 1049 if (ctx->Depth.Test && fb->Visual.depthBits > 0) { 1050 ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_TRUE); 1051 } else { 1052 ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_FALSE); 1053 } 1054 } else { 1055 ctx->NewState |= _NEW_DEPTH; 1056 } 1057 1058 intel->vtbl.set_draw_region(intel, colorRegion, depthRegion); 1059 1060 /* update viewport since it depends on window size */ 1061 if (ctx->Driver.Viewport) { 1062 ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y, 1063 ctx->Viewport.Width, ctx->Viewport.Height); 1064 } else { 1065 ctx->NewState |= _NEW_VIEWPORT; 1066 } 1067 1068 /* Set state we know depends on drawable parameters: 1069 */ 1070 if (ctx->Driver.Scissor) 1071 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, 1072 ctx->Scissor.Width, ctx->Scissor.Height); 1073 intel->NewGLState |= _NEW_SCISSOR; 1074 1075 if (ctx->Driver.DepthRange) 1076 ctx->Driver.DepthRange(ctx, 1077 ctx->Viewport.Near, 1078 ctx->Viewport.Far); 1079} 1080 1081 1082static void 1083intelDrawBuffer(GLcontext * ctx, GLenum mode) 1084{ 1085 intel_draw_buffer(ctx, ctx->DrawBuffer); 1086} 1087 1088 1089static void 1090intelReadBuffer(GLcontext * ctx, GLenum mode) 1091{ 1092 if (ctx->ReadBuffer == ctx->DrawBuffer) { 1093 /* This will update FBO completeness status. 1094 * A framebuffer will be incomplete if the GL_READ_BUFFER setting 1095 * refers to a missing renderbuffer. Calling glReadBuffer can set 1096 * that straight and can make the drawing buffer complete. 1097 */ 1098 intel_draw_buffer(ctx, ctx->DrawBuffer); 1099 } 1100 /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc) 1101 * reference ctx->ReadBuffer and do appropriate state checks. 1102 */ 1103} 1104 1105 1106void 1107intelInitBufferFuncs(struct dd_function_table *functions) 1108{ 1109 functions->Clear = intelClear; 1110 functions->DrawBuffer = intelDrawBuffer; 1111 functions->ReadBuffer = intelReadBuffer; 1112} 1113