intel_blit.c revision 33487c15ba8324bf0b635293214cad246661915e
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 29#include <stdio.h> 30#include <errno.h> 31 32#include "mtypes.h" 33#include "context.h" 34#include "enums.h" 35 36#include "intel_batchbuffer.h" 37#include "intel_blit.h" 38#include "intel_buffers.h" 39#include "intel_context.h" 40#include "intel_fbo.h" 41#include "intel_reg.h" 42#include "intel_regions.h" 43 44#define FILE_DEBUG_FLAG DEBUG_BLIT 45 46/** 47 * Copy the back color buffer to the front color buffer. 48 * Used for SwapBuffers(). 49 */ 50void 51intelCopyBuffer(const __DRIdrawablePrivate * dPriv, 52 const drm_clip_rect_t * rect) 53{ 54 55 struct intel_context *intel; 56 const intelScreenPrivate *intelScreen; 57 58 DBG("%s\n", __FUNCTION__); 59 60 assert(dPriv); 61 62 intel = intelScreenContext(dPriv->driScreenPriv->private); 63 if (!intel) 64 return; 65 66 intelScreen = intel->intelScreen; 67 68 if (intel->last_swap_fence) { 69 dri_fence_wait(intel->last_swap_fence); 70 dri_fence_unreference(intel->last_swap_fence); 71 intel->last_swap_fence = NULL; 72 } 73 intel->last_swap_fence = intel->first_swap_fence; 74 intel->first_swap_fence = NULL; 75 76 /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets 77 * should work regardless. 78 */ 79 LOCK_HARDWARE(intel); 80 81 if (dPriv && dPriv->numClipRects) { 82 struct intel_framebuffer *intel_fb = dPriv->driverPrivate; 83 struct intel_region *src, *dst; 84 int nbox = dPriv->numClipRects; 85 drm_clip_rect_t *pbox = dPriv->pClipRects; 86 int cpp; 87 int src_pitch, dst_pitch; 88 int BR13, CMD; 89 int i; 90 91 src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT); 92 dst = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT); 93 94 src_pitch = src->pitch * src->cpp; 95 dst_pitch = dst->pitch * dst->cpp; 96 97 cpp = src->cpp; 98 99 ASSERT(intel_fb); 100 ASSERT(intel_fb->Base.Name == 0); /* Not a user-created FBO */ 101 ASSERT(frontRegion); 102 ASSERT(backRegion); 103 ASSERT(frontRegion->pitch == backRegion->pitch); 104 ASSERT(frontRegion->cpp == backRegion->cpp); 105 106 if (cpp == 2) { 107 BR13 = (0xCC << 16) | (1 << 24); 108 CMD = XY_SRC_COPY_BLT_CMD; 109 } 110 else { 111 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25); 112 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; 113 } 114 115#ifndef I915 116 if (src->tiled) { 117 CMD |= XY_SRC_TILED; 118 src_pitch /= 4; 119 } 120 if (dst->tiled) { 121 CMD |= XY_DST_TILED; 122 dst_pitch /= 4; 123 } 124#endif 125 126 for (i = 0; i < nbox; i++, pbox++) { 127 drm_clip_rect_t box = *pbox; 128 129 if (rect) { 130 if (!intel_intersect_cliprects(&box, &box, rect)) 131 continue; 132 } 133 134 if (box.x1 >= box.x2 || 135 box.y1 >= box.y2 || 136 box.x2 > intelScreen->width || 137 box.y2 > intelScreen->height) 138 continue; 139 140 assert(box.x1 < box.x2); 141 assert(box.y1 < box.y2); 142 143 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); 144 OUT_BATCH(CMD); 145 OUT_BATCH(BR13 | dst_pitch); 146 OUT_BATCH((box.y1 << 16) | box.x1); 147 OUT_BATCH((box.y2 << 16) | box.x2); 148 149 OUT_RELOC(dst->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 0); 150 OUT_BATCH((box.y1 << 16) | box.x1); 151 OUT_BATCH(src_pitch); 152 OUT_RELOC(src->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 0); 153 ADVANCE_BATCH(); 154 } 155 156 if (intel->first_swap_fence) 157 dri_fence_unreference(intel->first_swap_fence); 158 intel_batchbuffer_flush(intel->batch); 159 intel->first_swap_fence = intel->batch->last_fence; 160 if (intel->first_swap_fence) 161 dri_fence_reference(intel->first_swap_fence); 162 } 163 164 UNLOCK_HARDWARE(intel); 165} 166 167 168 169 170void 171intelEmitFillBlit(struct intel_context *intel, 172 GLuint cpp, 173 GLshort dst_pitch, 174 dri_bo *dst_buffer, 175 GLuint dst_offset, 176 GLboolean dst_tiled, 177 GLshort x, GLshort y, 178 GLshort w, GLshort h, 179 GLuint color) 180{ 181 GLuint BR13, CMD; 182 BATCH_LOCALS; 183 184 dst_pitch *= cpp; 185 186 switch (cpp) { 187 case 1: 188 case 2: 189 case 3: 190 BR13 = (0xF0 << 16) | (1 << 24); 191 CMD = XY_COLOR_BLT_CMD; 192 break; 193 case 4: 194 BR13 = (0xF0 << 16) | (1 << 24) | (1 << 25); 195 CMD = XY_COLOR_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; 196 break; 197 default: 198 return; 199 } 200#ifndef I915 201 if (dst_tiled) { 202 CMD |= XY_DST_TILED; 203 dst_pitch /= 4; 204 } 205#endif 206 207 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", 208 __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h); 209 210 assert(w > 0); 211 assert(h > 0); 212 213 BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); 214 OUT_BATCH(CMD); 215 OUT_BATCH(BR13 | dst_pitch); 216 OUT_BATCH((y << 16) | x); 217 OUT_BATCH(((y + h) << 16) | (x + w)); 218 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, dst_offset); 219 OUT_BATCH(color); 220 ADVANCE_BATCH(); 221} 222 223static GLuint translate_raster_op(GLenum logicop) 224{ 225 switch(logicop) { 226 case GL_CLEAR: return 0x00; 227 case GL_AND: return 0x88; 228 case GL_AND_REVERSE: return 0x44; 229 case GL_COPY: return 0xCC; 230 case GL_AND_INVERTED: return 0x22; 231 case GL_NOOP: return 0xAA; 232 case GL_XOR: return 0x66; 233 case GL_OR: return 0xEE; 234 case GL_NOR: return 0x11; 235 case GL_EQUIV: return 0x99; 236 case GL_INVERT: return 0x55; 237 case GL_OR_REVERSE: return 0xDD; 238 case GL_COPY_INVERTED: return 0x33; 239 case GL_OR_INVERTED: return 0xBB; 240 case GL_NAND: return 0x77; 241 case GL_SET: return 0xFF; 242 default: return 0; 243 } 244} 245 246 247/* Copy BitBlt 248 */ 249void 250intelEmitCopyBlit(struct intel_context *intel, 251 GLuint cpp, 252 GLshort src_pitch, 253 dri_bo *src_buffer, 254 GLuint src_offset, 255 GLboolean src_tiled, 256 GLshort dst_pitch, 257 dri_bo *dst_buffer, 258 GLuint dst_offset, 259 GLboolean dst_tiled, 260 GLshort src_x, GLshort src_y, 261 GLshort dst_x, GLshort dst_y, 262 GLshort w, GLshort h, 263 GLenum logic_op) 264{ 265 GLuint CMD, BR13; 266 int dst_y2 = dst_y + h; 267 int dst_x2 = dst_x + w; 268 BATCH_LOCALS; 269 270 271 DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", 272 __FUNCTION__, 273 src_buffer, src_pitch, src_offset, src_x, src_y, 274 dst_buffer, dst_pitch, dst_offset, dst_x, dst_y, w, h); 275 276 src_pitch *= cpp; 277 dst_pitch *= cpp; 278 279 BR13 = translate_raster_op(logic_op) << 16; 280 281 switch (cpp) { 282 case 1: 283 case 2: 284 case 3: 285 BR13 |= (1 << 24); 286 CMD = XY_SRC_COPY_BLT_CMD; 287 break; 288 case 4: 289 BR13 |= (1 << 24) | (1 << 25); 290 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; 291 break; 292 default: 293 return; 294 } 295 296#ifndef I915 297 if (dst_tiled) { 298 CMD |= XY_DST_TILED; 299 dst_pitch /= 4; 300 } 301 if (src_tiled) { 302 CMD |= XY_SRC_TILED; 303 src_pitch /= 4; 304 } 305#endif 306 307 if (dst_y2 <= dst_y || dst_x2 <= dst_x) { 308 return; 309 } 310 311 dst_pitch &= 0xffff; 312 src_pitch &= 0xffff; 313 314 /* Initial y values don't seem to work with negative pitches. If 315 * we adjust the offsets manually (below), it seems to work fine. 316 * 317 * On the other hand, if we always adjust, the hardware doesn't 318 * know which blit directions to use, so overlapping copypixels get 319 * the wrong result. 320 */ 321 if (dst_pitch > 0 && src_pitch > 0) { 322 assert(dst_x < dst_x2); 323 assert(dst_y < dst_y2); 324 325 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); 326 OUT_BATCH(CMD); 327 OUT_BATCH(BR13 | dst_pitch); 328 OUT_BATCH((dst_y << 16) | dst_x); 329 OUT_BATCH((dst_y2 << 16) | dst_x2); 330 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 331 dst_offset); 332 OUT_BATCH((src_y << 16) | src_x); 333 OUT_BATCH(src_pitch); 334 OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 335 src_offset); 336 ADVANCE_BATCH(); 337 } 338 else { 339 assert(dst_x < dst_x2); 340 assert(h > 0); 341 342 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); 343 OUT_BATCH(CMD); 344 OUT_BATCH(BR13 | dst_pitch); 345 OUT_BATCH((0 << 16) | dst_x); 346 OUT_BATCH((h << 16) | dst_x2); 347 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 348 dst_offset + dst_y * dst_pitch); 349 OUT_BATCH((0 << 16) | src_x); 350 OUT_BATCH(src_pitch); 351 OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 352 src_offset + src_y * src_pitch); 353 ADVANCE_BATCH(); 354 } 355} 356 357 358/** 359 * Use blitting to clear the renderbuffers named by 'flags'. 360 * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field 361 * since that might include software renderbuffers or renderbuffers 362 * which we're clearing with triangles. 363 * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear 364 */ 365void 366intelClearWithBlit(GLcontext *ctx, GLbitfield mask) 367{ 368 struct intel_context *intel = intel_context(ctx); 369 struct gl_framebuffer *fb = ctx->DrawBuffer; 370 GLuint clear_depth; 371 GLbitfield skipBuffers = 0; 372 BATCH_LOCALS; 373 374 /* 375 * Compute values for clearing the buffers. 376 */ 377 clear_depth = 0; 378 if (mask & BUFFER_BIT_DEPTH) { 379 clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); 380 } 381 if (mask & BUFFER_BIT_STENCIL) { 382 clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; 383 } 384 385 /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in 386 * the loop below. 387 */ 388 if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) { 389 skipBuffers = BUFFER_BIT_STENCIL; 390 } 391 392 /* XXX Move this flush/lock into the following conditional? */ 393 intelFlush(&intel->ctx); 394 LOCK_HARDWARE(intel); 395 396 if (intel->numClipRects) { 397 GLint cx, cy, cw, ch; 398 drm_clip_rect_t clear; 399 int i; 400 401 /* Get clear bounds after locking */ 402 cx = fb->_Xmin; 403 cy = fb->_Ymin; 404 cw = fb->_Xmax - cx; 405 ch = fb->_Ymax - cy; 406 407 if (fb->Name == 0) { 408 /* clearing a window */ 409 410 /* flip top to bottom */ 411 clear.x1 = cx + intel->drawX; 412 clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch; 413 clear.x2 = clear.x1 + cw; 414 clear.y2 = clear.y1 + ch; 415 } 416 else { 417 /* clearing FBO */ 418 assert(intel->numClipRects == 1); 419 assert(intel->pClipRects == &intel->fboRect); 420 clear.x1 = cx; 421 clear.y1 = cy; 422 clear.x2 = clear.x1 + cw; 423 clear.y2 = clear.y1 + ch; 424 /* no change to mask */ 425 } 426 427 for (i = 0; i < intel->numClipRects; i++) { 428 const drm_clip_rect_t *box = &intel->pClipRects[i]; 429 drm_clip_rect_t b; 430 GLuint buf; 431 GLuint clearMask = mask; /* use copy, since we modify it below */ 432 GLboolean all = (cw == fb->Width && ch == fb->Height); 433 434 if (!all) { 435 intel_intersect_cliprects(&b, &clear, box); 436 } 437 else { 438 b = *box; 439 } 440 441 if (b.x1 >= b.x2 || b.y1 >= b.y2) 442 continue; 443 444 if (0) 445 _mesa_printf("clear %d,%d..%d,%d, mask %x\n", 446 b.x1, b.y1, b.x2, b.y2, mask); 447 448 /* Loop over all renderbuffers */ 449 for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) { 450 const GLbitfield bufBit = 1 << buf; 451 if ((clearMask & bufBit) && !(bufBit & skipBuffers)) { 452 /* OK, clear this renderbuffer */ 453 struct intel_region *irb_region = 454 intel_get_rb_region(fb, buf); 455 dri_bo *write_buffer = 456 intel_region_buffer(intel, irb_region, 457 all ? INTEL_WRITE_FULL : 458 INTEL_WRITE_PART); 459 460 GLuint clearVal; 461 GLint pitch, cpp; 462 GLuint BR13, CMD; 463 464 ASSERT(irb_region); 465 466 pitch = irb_region->pitch; 467 cpp = irb_region->cpp; 468 469 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", 470 __FUNCTION__, 471 irb_region->buffer, (pitch * cpp), 472 irb_region->draw_offset, 473 b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1); 474 475 BR13 = 0xf0 << 16; 476 CMD = XY_COLOR_BLT_CMD; 477 478 /* Setup the blit command */ 479 if (cpp == 4) { 480 BR13 |= (1 << 24) | (1 << 25); 481 if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { 482 if (clearMask & BUFFER_BIT_DEPTH) 483 CMD |= XY_BLT_WRITE_RGB; 484 if (clearMask & BUFFER_BIT_STENCIL) 485 CMD |= XY_BLT_WRITE_ALPHA; 486 } 487 else { 488 /* clearing RGBA */ 489 CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; 490 } 491 } 492 else { 493 ASSERT(cpp == 2 || cpp == 0); 494 BR13 |= (1 << 24); 495 } 496 497#ifndef I915 498 if (irb_region->tiled) { 499 CMD |= XY_DST_TILED; 500 pitch /= 4; 501 } 502#endif 503 BR13 |= (pitch * cpp); 504 505 if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { 506 clearVal = clear_depth; 507 } 508 else { 509 clearVal = (cpp == 4) 510 ? intel->ClearColor8888 : intel->ClearColor565; 511 } 512 /* 513 _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n", 514 buf, irb->Base.Name); 515 */ 516 intel_wait_flips(intel, INTEL_BATCH_NO_CLIPRECTS); 517 518 assert(b.x1 < b.x2); 519 assert(b.y1 < b.y2); 520 521 BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); 522 OUT_BATCH(CMD); 523 OUT_BATCH(BR13); 524 OUT_BATCH((b.y1 << 16) | b.x1); 525 OUT_BATCH((b.y2 << 16) | b.x2); 526 OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 527 irb_region->draw_offset); 528 OUT_BATCH(clearVal); 529 ADVANCE_BATCH(); 530 clearMask &= ~bufBit; /* turn off bit, for faster loop exit */ 531 } 532 } 533 } 534 intel_batchbuffer_flush(intel->batch); 535 } 536 537 UNLOCK_HARDWARE(intel); 538} 539