intel_buffers.c revision 6f1bfdc4bf5b72ac705b8cbb2dc431e133dcb5b8
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#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][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 201/** 202 * This will be called whenever the currently bound window is moved/resized. 203 * XXX: actually, it seems to NOT be called when the window is only moved (BP). 204 */ 205void 206intelWindowMoved(struct intel_context *intel) 207{ 208 GLcontext *ctx = &intel->ctx; 209 __DRIdrawablePrivate *dPriv = intel->driDrawable; 210 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 211 212 if (!intel->ctx.DrawBuffer) { 213 /* when would this happen? -BP */ 214 intelSetFrontClipRects(intel); 215 } 216 else if (intel->ctx.DrawBuffer->Name != 0) { 217 /* drawing to user-created FBO - do nothing */ 218 /* Cliprects would be set from intelDrawBuffer() */ 219 } 220 else { 221 /* drawing to a window */ 222 switch (intel_fb->Base._ColorDrawBufferMask[0]) { 223 case BUFFER_BIT_FRONT_LEFT: 224 intelSetFrontClipRects(intel); 225 break; 226 case BUFFER_BIT_BACK_LEFT: 227 intelSetBackClipRects(intel); 228 break; 229 default: 230 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */ 231 intelSetFrontClipRects(intel); 232 } 233 } 234 235 if (intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) { 236 drmI830Sarea *sarea = intel->sarea; 237 drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w, 238 .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h }; 239 drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y, 240 .x2 = sarea->planeA_x + sarea->planeA_w, 241 .y2 = sarea->planeA_y + sarea->planeA_h }; 242 drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y, 243 .x2 = sarea->planeB_x + sarea->planeB_w, 244 .y2 = sarea->planeB_y + sarea->planeB_h }; 245 GLint areaA = driIntersectArea( drw_rect, planeA_rect ); 246 GLint areaB = driIntersectArea( drw_rect, planeB_rect ); 247 GLuint flags = dPriv->vblFlags; 248 GLboolean pf_active; 249 GLint pf_planes; 250 251 /* Update page flipping info 252 */ 253 pf_planes = 0; 254 255 if (areaA > 0) 256 pf_planes |= 1; 257 258 if (areaB > 0) 259 pf_planes |= 2; 260 261 intel_fb->pf_current_page = (intel->sarea->pf_current_page >> 262 (intel_fb->pf_planes & 0x2)) & 0x3; 263 264 intel_fb->pf_num_pages = intel->intelScreen->third.handle ? 3 : 2; 265 266 pf_active = pf_planes && (pf_planes & intel->sarea->pf_active) == pf_planes; 267 268 if (INTEL_DEBUG & DEBUG_LOCK) 269 if (pf_active != intel_fb->pf_active) 270 _mesa_printf("%s - Page flipping %sactive\n", __progname, 271 pf_active ? "" : "in"); 272 273 if (pf_active) { 274 /* Sync pages between planes if flipping on both at the same time */ 275 if (pf_planes == 0x3 && pf_planes != intel_fb->pf_planes && 276 (intel->sarea->pf_current_page & 0x3) != 277 (((intel->sarea->pf_current_page) >> 2) & 0x3)) { 278 drm_i915_flip_t flip; 279 280 if (intel_fb->pf_current_page == 281 (intel->sarea->pf_current_page & 0x3)) { 282 /* XXX: This is ugly, but emitting two flips 'in a row' can cause 283 * lockups for unknown reasons. 284 */ 285 intel->sarea->pf_current_page = 286 intel->sarea->pf_current_page & 0x3; 287 intel->sarea->pf_current_page |= 288 ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) % 289 intel_fb->pf_num_pages) << 2; 290 291 flip.pipes = 0x2; 292 } else { 293 intel->sarea->pf_current_page = 294 intel->sarea->pf_current_page & (0x3 << 2); 295 intel->sarea->pf_current_page |= 296 (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) % 297 intel_fb->pf_num_pages; 298 299 flip.pipes = 0x1; 300 } 301 302 drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip)); 303 } 304 305 intel_fb->pf_planes = pf_planes; 306 } 307 308 intel_fb->pf_active = pf_active; 309 intel_flip_renderbuffers(intel_fb); 310 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer); 311 312 /* Update vblank info 313 */ 314 if (areaB > areaA || (areaA == areaB && areaB > 0)) { 315 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY; 316 } else { 317 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; 318 } 319 320 /* Check to see if we changed pipes */ 321 if (flags != dPriv->vblFlags && dPriv->vblFlags && 322 !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) { 323 int64_t count; 324 drmVBlank vbl; 325 int i; 326 327 /* 328 * Deal with page flipping 329 */ 330 vbl.request.type = DRM_VBLANK_ABSOLUTE; 331 332 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) { 333 vbl.request.type |= DRM_VBLANK_SECONDARY; 334 } 335 336 for (i = 0; i < intel_fb->pf_num_pages; i++) { 337 if (!intel_fb->color_rb[i] || 338 (intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <= 339 (1<<23)) 340 continue; 341 342 vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending; 343 drmWaitVBlank(intel->driFd, &vbl); 344 } 345 346 /* 347 * Update msc_base from old pipe 348 */ 349 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count); 350 dPriv->msc_base = count; 351 /* 352 * Then get new vblank_base and vblSeq values 353 */ 354 dPriv->vblFlags = flags; 355 driGetCurrentVBlank(dPriv); 356 dPriv->vblank_base = dPriv->vblSeq; 357 358 intel_fb->vbl_waited = dPriv->vblSeq; 359 360 for (i = 0; i < intel_fb->pf_num_pages; i++) { 361 if (intel_fb->color_rb[i]) 362 intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited; 363 } 364 } 365 } else { 366 dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY; 367 } 368 369 /* Update Mesa's notion of window size */ 370 driUpdateFramebufferSize(ctx, dPriv); 371 intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */ 372 373 /* Update hardware scissor */ 374 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, 375 ctx->Scissor.Width, ctx->Scissor.Height); 376 377 /* Re-calculate viewport related state */ 378 ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far ); 379} 380 381 382 383/* A true meta version of this would be very simple and additionally 384 * machine independent. Maybe we'll get there one day. 385 */ 386static void 387intelClearWithTris(struct intel_context *intel, GLbitfield mask) 388{ 389 GLcontext *ctx = &intel->ctx; 390 struct gl_framebuffer *fb = ctx->DrawBuffer; 391 GLuint buf; 392 393 intel->vtbl.install_meta_state(intel); 394 395 /* Back and stencil cliprects are the same. Try and do both 396 * buffers at once: 397 */ 398 if (mask & (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) { 399 struct intel_region *backRegion = 400 intel_get_rb_region(fb, BUFFER_BACK_LEFT); 401 struct intel_region *depthRegion = 402 intel_get_rb_region(fb, BUFFER_DEPTH); 403 const GLuint clearColor = (backRegion && backRegion->cpp == 4) 404 ? intel->ClearColor8888 : intel->ClearColor565; 405 406 intel->vtbl.meta_draw_region(intel, backRegion, depthRegion); 407 408 if (mask & BUFFER_BIT_BACK_LEFT) 409 intel->vtbl.meta_color_mask(intel, GL_TRUE); 410 else 411 intel->vtbl.meta_color_mask(intel, GL_FALSE); 412 413 if (mask & BUFFER_BIT_STENCIL) 414 intel->vtbl.meta_stencil_replace(intel, 415 intel->ctx.Stencil.WriteMask[0], 416 intel->ctx.Stencil.Clear); 417 else 418 intel->vtbl.meta_no_stencil_write(intel); 419 420 if (mask & BUFFER_BIT_DEPTH) 421 intel->vtbl.meta_depth_replace(intel); 422 else 423 intel->vtbl.meta_no_depth_write(intel); 424 425 intel_meta_draw_quad(intel, 426 fb->_Xmin, 427 fb->_Xmax, 428 fb->_Ymin, 429 fb->_Ymax, 430 intel->ctx.Depth.Clear, clearColor, 431 0, 0, 0, 0); /* texcoords */ 432 433 mask &= ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH); 434 } 435 436 /* clear the remaining (color) renderbuffers */ 437 for (buf = 0; buf < BUFFER_COUNT && mask; buf++) { 438 const GLuint bufBit = 1 << buf; 439 if (mask & bufBit) { 440 struct intel_renderbuffer *irbColor = 441 intel_renderbuffer(fb->Attachment[buf].Renderbuffer); 442 GLuint color = (irbColor->region->cpp == 4) 443 ? intel->ClearColor8888 : intel->ClearColor565; 444 445 ASSERT(irbColor); 446 447 intel->vtbl.meta_no_depth_write(intel); 448 intel->vtbl.meta_no_stencil_write(intel); 449 intel->vtbl.meta_color_mask(intel, GL_TRUE); 450 intel->vtbl.meta_draw_region(intel, irbColor->region, NULL); 451 452 /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the 453 * drawing origin may not be correctly emitted. 454 */ 455 intel_meta_draw_quad(intel, 456 fb->_Xmin, 457 fb->_Xmax, 458 fb->_Ymin, 459 fb->_Ymax, 460 0, color, 461 0, 0, 0, 0); /* texcoords */ 462 463 mask &= ~bufBit; 464 } 465 } 466 467 intel->vtbl.leave_meta_state(intel); 468 intel_batchbuffer_flush(intel->batch); 469} 470 471static const char *buffer_names[] = { 472 [BUFFER_FRONT_LEFT] = "front", 473 [BUFFER_BACK_LEFT] = "back", 474 [BUFFER_FRONT_RIGHT] = "front right", 475 [BUFFER_BACK_RIGHT] = "back right", 476 [BUFFER_AUX0] = "aux0", 477 [BUFFER_AUX1] = "aux1", 478 [BUFFER_AUX2] = "aux2", 479 [BUFFER_AUX3] = "aux3", 480 [BUFFER_DEPTH] = "depth", 481 [BUFFER_STENCIL] = "stencil", 482 [BUFFER_ACCUM] = "accum", 483 [BUFFER_COLOR0] = "color0", 484 [BUFFER_COLOR1] = "color1", 485 [BUFFER_COLOR2] = "color2", 486 [BUFFER_COLOR3] = "color3", 487 [BUFFER_COLOR4] = "color4", 488 [BUFFER_COLOR5] = "color5", 489 [BUFFER_COLOR6] = "color6", 490 [BUFFER_COLOR7] = "color7", 491}; 492 493/** 494 * Called by ctx->Driver.Clear. 495 */ 496static void 497intelClear(GLcontext *ctx, GLbitfield mask) 498{ 499 struct intel_context *intel = intel_context(ctx); 500 const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask); 501 GLbitfield tri_mask = 0; 502 GLbitfield blit_mask = 0; 503 GLbitfield swrast_mask = 0; 504 struct gl_framebuffer *fb = ctx->DrawBuffer; 505 GLuint i; 506 507 if (0) 508 fprintf(stderr, "%s\n", __FUNCTION__); 509 510 /* HW color buffers (front, back, aux, generic FBO, etc) */ 511 if (colorMask == ~0) { 512 /* clear all R,G,B,A */ 513 /* XXX FBO: need to check if colorbuffers are software RBOs! */ 514 blit_mask |= (mask & BUFFER_BITS_COLOR); 515 } 516 else { 517 /* glColorMask in effect */ 518 tri_mask |= (mask & BUFFER_BITS_COLOR); 519 } 520 521 /* HW stencil */ 522 if (mask & BUFFER_BIT_STENCIL) { 523 const struct intel_region *stencilRegion 524 = intel_get_rb_region(fb, BUFFER_STENCIL); 525 if (stencilRegion) { 526 /* have hw stencil */ 527 if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) { 528 /* not clearing all stencil bits, so use triangle clearing */ 529 tri_mask |= BUFFER_BIT_STENCIL; 530 } 531 else { 532 /* clearing all stencil bits, use blitting */ 533 blit_mask |= BUFFER_BIT_STENCIL; 534 } 535 } 536 } 537 538 /* HW depth */ 539 if (mask & BUFFER_BIT_DEPTH) { 540 /* clear depth with whatever method is used for stencil (see above) */ 541 if (tri_mask & BUFFER_BIT_STENCIL) 542 tri_mask |= BUFFER_BIT_DEPTH; 543 else 544 blit_mask |= BUFFER_BIT_DEPTH; 545 } 546 547 /* SW fallback clearing */ 548 swrast_mask = mask & ~tri_mask & ~blit_mask; 549 550 for (i = 0; i < BUFFER_COUNT; i++) { 551 GLuint bufBit = 1 << i; 552 if ((blit_mask | tri_mask) & bufBit) { 553 if (!fb->Attachment[i].Renderbuffer->ClassID) { 554 blit_mask &= ~bufBit; 555 tri_mask &= ~bufBit; 556 swrast_mask |= bufBit; 557 } 558 } 559 } 560 561 intelFlush(ctx); /* XXX intelClearWithBlit also does this */ 562 563 if (blit_mask) { 564 if (INTEL_DEBUG & DEBUG_BLIT) { 565 DBG("blit clear:"); 566 for (i = 0; i < BUFFER_COUNT; i++) { 567 if (blit_mask & (1 << i)) 568 DBG(" %s", buffer_names[i]); 569 } 570 DBG("\n"); 571 } 572 intelClearWithBlit(ctx, blit_mask); 573 } 574 575 if (tri_mask) { 576 if (INTEL_DEBUG & DEBUG_BLIT) { 577 DBG("tri clear:"); 578 for (i = 0; i < BUFFER_COUNT; i++) { 579 if (tri_mask & (1 << i)) 580 DBG(" %s", buffer_names[i]); 581 } 582 DBG("\n"); 583 } 584 intelClearWithTris(intel, tri_mask); 585 } 586 587 if (swrast_mask) { 588 if (INTEL_DEBUG & DEBUG_BLIT) { 589 DBG("swrast clear:"); 590 for (i = 0; i < BUFFER_COUNT; i++) { 591 if (swrast_mask & (1 << i)) 592 DBG(" %s", buffer_names[i]); 593 } 594 DBG("\n"); 595 } 596 _swrast_Clear(ctx, swrast_mask); 597 } 598} 599 600 601/* Emit wait for pending flips */ 602void 603intel_wait_flips(struct intel_context *intel, GLuint batch_flags) 604{ 605 struct intel_framebuffer *intel_fb = 606 (struct intel_framebuffer *) intel->ctx.DrawBuffer; 607 struct intel_renderbuffer *intel_rb = 608 intel_get_renderbuffer(&intel_fb->Base, 609 intel_fb->Base._ColorDrawBufferMask[0] == 610 BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT : 611 BUFFER_BACK_LEFT); 612 613 if (intel_fb->Base.Name == 0 && intel_rb && 614 intel_rb->pf_pending == intel_fb->pf_seq) { 615 GLint pf_planes = intel_fb->pf_planes; 616 BATCH_LOCALS; 617 618 /* Wait for pending flips to take effect */ 619 BEGIN_BATCH(2, batch_flags); 620 OUT_BATCH(pf_planes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP) 621 : 0); 622 OUT_BATCH(pf_planes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP) 623 : 0); 624 ADVANCE_BATCH(); 625 626 intel_rb->pf_pending--; 627 } 628} 629 630 631/* Flip the front & back buffers 632 */ 633static GLboolean 634intelPageFlip(const __DRIdrawablePrivate * dPriv) 635{ 636 struct intel_context *intel; 637 int ret; 638 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 639 640 if (INTEL_DEBUG & DEBUG_IOCTL) 641 fprintf(stderr, "%s\n", __FUNCTION__); 642 643 assert(dPriv); 644 assert(dPriv->driContextPriv); 645 assert(dPriv->driContextPriv->driverPrivate); 646 647 intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate; 648 649 if (intel->intelScreen->drmMinor < 9) 650 return GL_FALSE; 651 652 intelFlush(&intel->ctx); 653 654 ret = 0; 655 656 LOCK_HARDWARE(intel); 657 658 if (dPriv->numClipRects && intel_fb->pf_active) { 659 drm_i915_flip_t flip; 660 661 flip.pipes = intel_fb->pf_planes; 662 663 ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip)); 664 } 665 666 UNLOCK_HARDWARE(intel); 667 668 if (ret || !intel_fb->pf_active) 669 return GL_FALSE; 670 671 if (!dPriv->numClipRects) { 672 usleep(10000); /* throttle invisible client 10ms */ 673 } 674 675 intel_fb->pf_current_page = (intel->sarea->pf_current_page >> 676 (intel_fb->pf_planes & 0x2)) & 0x3; 677 678 if (dPriv->numClipRects != 0) { 679 intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending = 680 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending = 681 ++intel_fb->pf_seq; 682 } 683 684 intel_flip_renderbuffers(intel_fb); 685 intel_draw_buffer(&intel->ctx, &intel_fb->Base); 686 687 return GL_TRUE; 688} 689 690#if 0 691void 692intelSwapBuffers(__DRIdrawablePrivate * dPriv) 693{ 694 if (dPriv->driverPrivate) { 695 const struct gl_framebuffer *fb 696 = (struct gl_framebuffer *) dPriv->driverPrivate; 697 if (fb->Visual.doubleBufferMode) { 698 GET_CURRENT_CONTEXT(ctx); 699 if (ctx && ctx->DrawBuffer == fb) { 700 _mesa_notifySwapBuffers(ctx); /* flush pending rendering */ 701 } 702 if (intel->doPageFlip) { 703 intelPageFlip(dPriv); 704 } 705 else { 706 intelCopyBuffer(dPriv); 707 } 708 } 709 } 710 else { 711 _mesa_problem(NULL, 712 "dPriv has no gl_framebuffer pointer in intelSwapBuffers"); 713 } 714} 715#else 716/* Trunk version: 717 */ 718 719static GLboolean 720intelScheduleSwap(__DRIdrawablePrivate * dPriv, GLboolean *missed_target) 721{ 722 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 723 unsigned int interval; 724 struct intel_context *intel = 725 intelScreenContext(dPriv->driScreenPriv->private); 726 const intelScreenPrivate *intelScreen = intel->intelScreen; 727 unsigned int target; 728 drm_i915_vblank_swap_t swap; 729 GLboolean ret; 730 731 if (!dPriv->vblFlags || 732 (dPriv->vblFlags & VBLANK_FLAG_NO_IRQ) || 733 intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6)) 734 return GL_FALSE; 735 736 interval = driGetVBlankInterval(dPriv); 737 738 swap.seqtype = DRM_VBLANK_ABSOLUTE; 739 740 if (dPriv->vblFlags & VBLANK_FLAG_SYNC) { 741 swap.seqtype |= DRM_VBLANK_NEXTONMISS; 742 } else if (interval == 0) { 743 return GL_FALSE; 744 } 745 746 swap.drawable = dPriv->hHWDrawable; 747 target = swap.sequence = dPriv->vblSeq + interval; 748 749 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) { 750 swap.seqtype |= DRM_VBLANK_SECONDARY; 751 } 752 753 LOCK_HARDWARE(intel); 754 755 intel_batchbuffer_flush(intel->batch); 756 757 if ( intel_fb->pf_active ) { 758 swap.seqtype |= DRM_VBLANK_FLIP; 759 760 intel_fb->pf_current_page = (((intel->sarea->pf_current_page >> 761 (intel_fb->pf_planes & 0x2)) & 0x3) + 1) % 762 intel_fb->pf_num_pages; 763 } 764 765 if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap, 766 sizeof(swap))) { 767 dPriv->vblSeq = swap.sequence; 768 swap.sequence -= target; 769 *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23); 770 771 intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending = 772 intel_get_renderbuffer(&intel_fb->Base, 773 BUFFER_FRONT_LEFT)->vbl_pending = 774 dPriv->vblSeq; 775 776 if (swap.seqtype & DRM_VBLANK_FLIP) { 777 intel_flip_renderbuffers(intel_fb); 778 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer); 779 } 780 781 ret = GL_TRUE; 782 } else { 783 if (swap.seqtype & DRM_VBLANK_FLIP) { 784 intel_fb->pf_current_page = ((intel->sarea->pf_current_page >> 785 (intel_fb->pf_planes & 0x2)) & 0x3) % 786 intel_fb->pf_num_pages; 787 } 788 789 ret = GL_FALSE; 790 } 791 792 UNLOCK_HARDWARE(intel); 793 794 return ret; 795} 796 797void 798intelSwapBuffers(__DRIdrawablePrivate * dPriv) 799{ 800 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { 801 GET_CURRENT_CONTEXT(ctx); 802 struct intel_context *intel; 803 804 if (ctx == NULL) 805 return; 806 807 intel = intel_context(ctx); 808 809 if (ctx->Visual.doubleBufferMode) { 810 GLboolean missed_target; 811 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 812 int64_t ust; 813 814 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ 815 816 if (!intelScheduleSwap(dPriv, &missed_target)) { 817 driWaitForVBlank(dPriv, &missed_target); 818 819 if (!intelPageFlip(dPriv)) { 820 intelCopyBuffer(dPriv, NULL); 821 } 822 } 823 824 intel_fb->swap_count++; 825 (*dri_interface->getUST) (&ust); 826 if (missed_target) { 827 intel_fb->swap_missed_count++; 828 intel_fb->swap_missed_ust = ust - intel_fb->swap_ust; 829 } 830 831 intel_fb->swap_ust = ust; 832 } 833 } 834 else { 835 /* XXX this shouldn't be an error but we can't handle it for now */ 836 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); 837 } 838} 839#endif 840 841void 842intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h) 843{ 844 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { 845 struct intel_context *intel = 846 (struct intel_context *) dPriv->driContextPriv->driverPrivate; 847 GLcontext *ctx = &intel->ctx; 848 849 if (ctx->Visual.doubleBufferMode) { 850 drm_clip_rect_t rect; 851 rect.x1 = x + dPriv->x; 852 rect.y1 = (dPriv->h - y - h) + dPriv->y; 853 rect.x2 = rect.x1 + w; 854 rect.y2 = rect.y1 + h; 855 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ 856 intelCopyBuffer(dPriv, &rect); 857 } 858 } 859 else { 860 /* XXX this shouldn't be an error but we can't handle it for now */ 861 fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); 862 } 863} 864 865 866/** 867 * Update the hardware state for drawing into a window or framebuffer object. 868 * 869 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other 870 * places within the driver. 871 * 872 * Basically, this needs to be called any time the current framebuffer 873 * changes, the renderbuffers change, or we need to draw into different 874 * color buffers. 875 */ 876void 877intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb) 878{ 879 struct intel_context *intel = intel_context(ctx); 880 struct intel_region *colorRegion, *depthRegion = NULL; 881 struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; 882 int front = 0; /* drawing to front color buffer? */ 883 884 if (!fb) { 885 /* this can happen during the initial context initialization */ 886 return; 887 } 888 889 /* Do this here, note core Mesa, since this function is called from 890 * many places within the driver. 891 */ 892 if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) { 893 /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ 894 _mesa_update_framebuffer(ctx); 895 /* this updates the DrawBuffer's Width/Height if it's a FBO */ 896 _mesa_update_draw_buffer_bounds(ctx); 897 } 898 899 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 900 /* this may occur when we're called by glBindFrameBuffer() during 901 * the process of someone setting up renderbuffers, etc. 902 */ 903 /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/ 904 return; 905 } 906 907 if (fb->Name) 908 intel_validate_paired_depth_stencil(ctx, fb); 909 910 /* 911 * How many color buffers are we drawing into? 912 */ 913 if (fb->_NumColorDrawBuffers[0] != 1) { 914 /* writing to 0 or 2 or 4 color buffers */ 915 /*_mesa_debug(ctx, "Software rendering\n");*/ 916 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); 917 colorRegion = NULL; 918 } 919 else { 920 /* draw to exactly one color buffer */ 921 /*_mesa_debug(ctx, "Hardware rendering\n");*/ 922 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); 923 if (fb->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT) { 924 front = 1; 925 } 926 927 /* 928 * Get the intel_renderbuffer for the colorbuffer we're drawing into. 929 * And set up cliprects. 930 */ 931 if (fb->Name == 0) { 932 /* drawing to window system buffer */ 933 if (front) { 934 intelSetFrontClipRects(intel); 935 colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); 936 } 937 else { 938 intelSetBackClipRects(intel); 939 colorRegion = intel_get_rb_region(fb, BUFFER_BACK_LEFT); 940 } 941 } 942 else { 943 /* drawing to user-created FBO */ 944 struct intel_renderbuffer *irb; 945 intelSetRenderbufferClipRects(intel); 946 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0][0]); 947 colorRegion = (irb && irb->region) ? irb->region : NULL; 948 } 949 } 950 951 /* Update culling direction which changes depending on the 952 * orientation of the buffer: 953 */ 954 if (ctx->Driver.FrontFace) 955 ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace); 956 else 957 ctx->NewState |= _NEW_POLYGON; 958 959 if (!colorRegion) { 960 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); 961 } 962 else { 963 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); 964 } 965 966 /*** 967 *** Get depth buffer region and check if we need a software fallback. 968 *** Note that the depth buffer is usually a DEPTH_STENCIL buffer. 969 ***/ 970 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { 971 irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); 972 if (irbDepth && irbDepth->region) { 973 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 974 depthRegion = irbDepth->region; 975 } 976 else { 977 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE); 978 depthRegion = NULL; 979 } 980 } 981 else { 982 /* not using depth buffer */ 983 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 984 depthRegion = NULL; 985 } 986 987 /*** 988 *** Stencil buffer 989 *** This can only be hardware accelerated if we're using a 990 *** combined DEPTH_STENCIL buffer (for now anyway). 991 ***/ 992 if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { 993 irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); 994 if (irbStencil && irbStencil->region) { 995 ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); 996 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 997 /* need to re-compute stencil hw state */ 998 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); 999 if (!depthRegion) 1000 depthRegion = irbStencil->region; 1001 } 1002 else { 1003 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE); 1004 } 1005 } 1006 else { 1007 /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */ 1008 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 1009 /* need to re-compute stencil hw state */ 1010 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); 1011 } 1012 1013 /* 1014 * Update depth test state 1015 */ 1016 if (ctx->Depth.Test && fb->Visual.depthBits > 0) { 1017 ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_TRUE); 1018 } 1019 else { 1020 ctx->Driver.Enable(ctx, GL_DEPTH_TEST, GL_FALSE); 1021 } 1022 1023 intel->vtbl.set_draw_region(intel, colorRegion, depthRegion); 1024 1025 /* update viewport since it depends on window size */ 1026 ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y, 1027 ctx->Viewport.Width, ctx->Viewport.Height); 1028 1029 /* Update hardware scissor */ 1030 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, 1031 ctx->Scissor.Width, ctx->Scissor.Height); 1032} 1033 1034 1035static void 1036intelDrawBuffer(GLcontext * ctx, GLenum mode) 1037{ 1038 intel_draw_buffer(ctx, ctx->DrawBuffer); 1039} 1040 1041 1042static void 1043intelReadBuffer(GLcontext * ctx, GLenum mode) 1044{ 1045 if (ctx->ReadBuffer == ctx->DrawBuffer) { 1046 /* This will update FBO completeness status. 1047 * A framebuffer will be incomplete if the GL_READ_BUFFER setting 1048 * refers to a missing renderbuffer. Calling glReadBuffer can set 1049 * that straight and can make the drawing buffer complete. 1050 */ 1051 intel_draw_buffer(ctx, ctx->DrawBuffer); 1052 } 1053 /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc) 1054 * reference ctx->ReadBuffer and do appropriate state checks. 1055 */ 1056} 1057 1058 1059void 1060intelInitBufferFuncs(struct dd_function_table *functions) 1061{ 1062 functions->Clear = intelClear; 1063 functions->DrawBuffer = intelDrawBuffer; 1064 functions->ReadBuffer = intelReadBuffer; 1065} 1066