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