intel: use new mipmap generation hooks in driver.
[mesa.git] / src / mesa / drivers / dri / intel / intel_blit.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
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 */
50 void
51 intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
52 const drm_clip_rect_t * rect)
53 {
54
55 struct intel_context *intel;
56 const intelScreenPrivate *intelScreen;
57 int ret;
58
59 DBG("%s\n", __FUNCTION__);
60
61 assert(dPriv);
62
63 intel = intelScreenContext(dPriv->driScreenPriv->private);
64 if (!intel)
65 return;
66
67 intelScreen = intel->intelScreen;
68
69 if (intel->last_swap_fence) {
70 dri_fence_wait(intel->last_swap_fence);
71 dri_fence_unreference(intel->last_swap_fence);
72 intel->last_swap_fence = NULL;
73 }
74 intel->last_swap_fence = intel->first_swap_fence;
75 intel->first_swap_fence = NULL;
76
77 /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
78 * should work regardless.
79 */
80 LOCK_HARDWARE(intel);
81
82 if (dPriv && dPriv->numClipRects) {
83 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
84 struct intel_region *src, *dst;
85 int nbox = dPriv->numClipRects;
86 drm_clip_rect_t *pbox = dPriv->pClipRects;
87 int cpp;
88 int src_pitch, dst_pitch;
89 unsigned short src_x, src_y;
90 int BR13, CMD;
91 int i;
92
93 src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
94 dst = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
95
96 src_pitch = src->pitch * src->cpp;
97 dst_pitch = dst->pitch * dst->cpp;
98
99 cpp = src->cpp;
100
101 ASSERT(intel_fb);
102 ASSERT(intel_fb->Base.Name == 0); /* Not a user-created FBO */
103 ASSERT(src);
104 ASSERT(dst);
105 ASSERT(src->cpp == dst->cpp);
106
107 if (cpp == 2) {
108 BR13 = (0xCC << 16) | (1 << 24);
109 CMD = XY_SRC_COPY_BLT_CMD;
110 }
111 else {
112 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
113 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
114 }
115
116 #ifndef I915
117 if (src->tiled) {
118 CMD |= XY_SRC_TILED;
119 src_pitch /= 4;
120 }
121 if (dst->tiled) {
122 CMD |= XY_DST_TILED;
123 dst_pitch /= 4;
124 }
125 #endif
126
127 again:
128 ret = dri_bufmgr_check_aperture_space(dst->buffer);
129 ret |= dri_bufmgr_check_aperture_space(src->buffer);
130
131 if (ret) {
132 intel_batchbuffer_flush(intel->batch);
133 goto again;
134 }
135
136 for (i = 0; i < nbox; i++, pbox++) {
137 drm_clip_rect_t box = *pbox;
138
139 if (rect) {
140 if (!intel_intersect_cliprects(&box, &box, rect))
141 continue;
142 }
143
144 if (box.x1 >= box.x2 ||
145 box.y1 >= box.y2)
146 continue;
147
148 assert(box.x1 < box.x2);
149 assert(box.y1 < box.y2);
150 src_x = box.x1 - dPriv->x + dPriv->backX;
151 src_y = box.y1 - dPriv->y + dPriv->backY;
152
153 BEGIN_BATCH(8, REFERENCES_CLIPRECTS);
154 OUT_BATCH(CMD);
155 OUT_BATCH(BR13 | dst_pitch);
156 OUT_BATCH((box.y1 << 16) | box.x1);
157 OUT_BATCH((box.y2 << 16) | box.x2);
158
159 OUT_RELOC(dst->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 0);
160 OUT_BATCH((src_y << 16) | src_x);
161 OUT_BATCH(src_pitch);
162 OUT_RELOC(src->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 0);
163 ADVANCE_BATCH();
164 }
165
166 if (intel->first_swap_fence)
167 dri_fence_unreference(intel->first_swap_fence);
168 intel_batchbuffer_flush(intel->batch);
169 intel->first_swap_fence = intel->batch->last_fence;
170 if (intel->first_swap_fence)
171 dri_fence_reference(intel->first_swap_fence);
172 }
173
174 UNLOCK_HARDWARE(intel);
175 }
176
177
178
179
180 void
181 intelEmitFillBlit(struct intel_context *intel,
182 GLuint cpp,
183 GLshort dst_pitch,
184 dri_bo *dst_buffer,
185 GLuint dst_offset,
186 GLboolean dst_tiled,
187 GLshort x, GLshort y,
188 GLshort w, GLshort h,
189 GLuint color)
190 {
191 GLuint BR13, CMD;
192 BATCH_LOCALS;
193
194 dst_pitch *= cpp;
195
196 switch (cpp) {
197 case 1:
198 case 2:
199 case 3:
200 BR13 = (0xF0 << 16) | (1 << 24);
201 CMD = XY_COLOR_BLT_CMD;
202 break;
203 case 4:
204 BR13 = (0xF0 << 16) | (1 << 24) | (1 << 25);
205 CMD = XY_COLOR_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
206 break;
207 default:
208 return;
209 }
210 #ifndef I915
211 if (dst_tiled) {
212 CMD |= XY_DST_TILED;
213 dst_pitch /= 4;
214 }
215 #endif
216
217 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
218 __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h);
219
220 assert(w > 0);
221 assert(h > 0);
222
223 BEGIN_BATCH(6, NO_LOOP_CLIPRECTS);
224 OUT_BATCH(CMD);
225 OUT_BATCH(BR13 | dst_pitch);
226 OUT_BATCH((y << 16) | x);
227 OUT_BATCH(((y + h) << 16) | (x + w));
228 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, dst_offset);
229 OUT_BATCH(color);
230 ADVANCE_BATCH();
231 }
232
233 static GLuint translate_raster_op(GLenum logicop)
234 {
235 switch(logicop) {
236 case GL_CLEAR: return 0x00;
237 case GL_AND: return 0x88;
238 case GL_AND_REVERSE: return 0x44;
239 case GL_COPY: return 0xCC;
240 case GL_AND_INVERTED: return 0x22;
241 case GL_NOOP: return 0xAA;
242 case GL_XOR: return 0x66;
243 case GL_OR: return 0xEE;
244 case GL_NOR: return 0x11;
245 case GL_EQUIV: return 0x99;
246 case GL_INVERT: return 0x55;
247 case GL_OR_REVERSE: return 0xDD;
248 case GL_COPY_INVERTED: return 0x33;
249 case GL_OR_INVERTED: return 0xBB;
250 case GL_NAND: return 0x77;
251 case GL_SET: return 0xFF;
252 default: return 0;
253 }
254 }
255
256
257 /* Copy BitBlt
258 */
259 void
260 intelEmitCopyBlit(struct intel_context *intel,
261 GLuint cpp,
262 GLshort src_pitch,
263 dri_bo *src_buffer,
264 GLuint src_offset,
265 GLboolean src_tiled,
266 GLshort dst_pitch,
267 dri_bo *dst_buffer,
268 GLuint dst_offset,
269 GLboolean dst_tiled,
270 GLshort src_x, GLshort src_y,
271 GLshort dst_x, GLshort dst_y,
272 GLshort w, GLshort h,
273 GLenum logic_op)
274 {
275 GLuint CMD, BR13;
276 int dst_y2 = dst_y + h;
277 int dst_x2 = dst_x + w;
278 int ret;
279 BATCH_LOCALS;
280
281 again:
282 ret = dri_bufmgr_check_aperture_space(dst_buffer);
283 ret |= dri_bufmgr_check_aperture_space(src_buffer);
284 if (ret) {
285 intel_batchbuffer_flush(intel->batch);
286 goto again;
287 }
288
289 DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
290 __FUNCTION__,
291 src_buffer, src_pitch, src_offset, src_x, src_y,
292 dst_buffer, dst_pitch, dst_offset, dst_x, dst_y, w, h);
293
294 src_pitch *= cpp;
295 dst_pitch *= cpp;
296
297 BR13 = translate_raster_op(logic_op) << 16;
298
299 switch (cpp) {
300 case 1:
301 case 2:
302 case 3:
303 BR13 |= (1 << 24);
304 CMD = XY_SRC_COPY_BLT_CMD;
305 break;
306 case 4:
307 BR13 |= (1 << 24) | (1 << 25);
308 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
309 break;
310 default:
311 return;
312 }
313
314 #ifndef I915
315 if (dst_tiled) {
316 CMD |= XY_DST_TILED;
317 dst_pitch /= 4;
318 }
319 if (src_tiled) {
320 CMD |= XY_SRC_TILED;
321 src_pitch /= 4;
322 }
323 #endif
324
325 if (dst_y2 <= dst_y || dst_x2 <= dst_x) {
326 return;
327 }
328
329 dst_pitch &= 0xffff;
330 src_pitch &= 0xffff;
331
332 /* Initial y values don't seem to work with negative pitches. If
333 * we adjust the offsets manually (below), it seems to work fine.
334 *
335 * On the other hand, if we always adjust, the hardware doesn't
336 * know which blit directions to use, so overlapping copypixels get
337 * the wrong result.
338 */
339 if (dst_pitch > 0 && src_pitch > 0) {
340 assert(dst_x < dst_x2);
341 assert(dst_y < dst_y2);
342
343 BEGIN_BATCH(8, NO_LOOP_CLIPRECTS);
344 OUT_BATCH(CMD);
345 OUT_BATCH(BR13 | dst_pitch);
346 OUT_BATCH((dst_y << 16) | dst_x);
347 OUT_BATCH((dst_y2 << 16) | dst_x2);
348 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
349 dst_offset);
350 OUT_BATCH((src_y << 16) | src_x);
351 OUT_BATCH(src_pitch);
352 OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
353 src_offset);
354 ADVANCE_BATCH();
355 }
356 else {
357 assert(dst_x < dst_x2);
358 assert(h > 0);
359
360 BEGIN_BATCH(8, NO_LOOP_CLIPRECTS);
361 OUT_BATCH(CMD);
362 OUT_BATCH(BR13 | dst_pitch);
363 OUT_BATCH((0 << 16) | dst_x);
364 OUT_BATCH((h << 16) | dst_x2);
365 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
366 dst_offset + dst_y * dst_pitch);
367 OUT_BATCH((0 << 16) | src_x);
368 OUT_BATCH(src_pitch);
369 OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
370 src_offset + src_y * src_pitch);
371 ADVANCE_BATCH();
372 }
373 }
374
375
376 /**
377 * Use blitting to clear the renderbuffers named by 'flags'.
378 * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes field
379 * since that might include software renderbuffers or renderbuffers
380 * which we're clearing with triangles.
381 * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear
382 */
383 void
384 intelClearWithBlit(GLcontext *ctx, GLbitfield mask)
385 {
386 struct intel_context *intel = intel_context(ctx);
387 struct gl_framebuffer *fb = ctx->DrawBuffer;
388 GLuint clear_depth;
389 GLbitfield skipBuffers = 0;
390 BATCH_LOCALS;
391
392 /*
393 * Compute values for clearing the buffers.
394 */
395 clear_depth = 0;
396 if (mask & BUFFER_BIT_DEPTH) {
397 clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear);
398 }
399 if (mask & BUFFER_BIT_STENCIL) {
400 clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
401 }
402
403 /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in
404 * the loop below.
405 */
406 if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) {
407 skipBuffers = BUFFER_BIT_STENCIL;
408 }
409
410 /* XXX Move this flush/lock into the following conditional? */
411 intelFlush(&intel->ctx);
412 LOCK_HARDWARE(intel);
413
414 if (intel->numClipRects) {
415 GLint cx, cy, cw, ch;
416 drm_clip_rect_t clear;
417 int i;
418
419 /* Get clear bounds after locking */
420 cx = fb->_Xmin;
421 cy = fb->_Ymin;
422 cw = fb->_Xmax - cx;
423 ch = fb->_Ymax - cy;
424
425 if (fb->Name == 0) {
426 /* clearing a window */
427
428 /* flip top to bottom */
429 clear.x1 = cx + intel->drawX;
430 clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch;
431 clear.x2 = clear.x1 + cw;
432 clear.y2 = clear.y1 + ch;
433 }
434 else {
435 /* clearing FBO */
436 assert(intel->numClipRects == 1);
437 assert(intel->pClipRects == &intel->fboRect);
438 clear.x1 = cx;
439 clear.y1 = cy;
440 clear.x2 = clear.x1 + cw;
441 clear.y2 = clear.y1 + ch;
442 /* no change to mask */
443 }
444
445 for (i = 0; i < intel->numClipRects; i++) {
446 const drm_clip_rect_t *box = &intel->pClipRects[i];
447 drm_clip_rect_t b;
448 GLuint buf;
449 GLuint clearMask = mask; /* use copy, since we modify it below */
450 GLboolean all = (cw == fb->Width && ch == fb->Height);
451
452 if (!all) {
453 intel_intersect_cliprects(&b, &clear, box);
454 }
455 else {
456 b = *box;
457 }
458
459 if (b.x1 >= b.x2 || b.y1 >= b.y2)
460 continue;
461
462 if (0)
463 _mesa_printf("clear %d,%d..%d,%d, mask %x\n",
464 b.x1, b.y1, b.x2, b.y2, mask);
465
466 /* Loop over all renderbuffers */
467 for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) {
468 const GLbitfield bufBit = 1 << buf;
469 if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
470 /* OK, clear this renderbuffer */
471 struct intel_region *irb_region =
472 intel_get_rb_region(fb, buf);
473 dri_bo *write_buffer =
474 intel_region_buffer(intel, irb_region,
475 all ? INTEL_WRITE_FULL :
476 INTEL_WRITE_PART);
477
478 GLuint clearVal;
479 GLint pitch, cpp;
480 GLuint BR13, CMD;
481
482 ASSERT(irb_region);
483
484 pitch = irb_region->pitch;
485 cpp = irb_region->cpp;
486
487 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
488 __FUNCTION__,
489 irb_region->buffer, (pitch * cpp),
490 irb_region->draw_offset,
491 b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
492
493 BR13 = 0xf0 << 16;
494 CMD = XY_COLOR_BLT_CMD;
495
496 /* Setup the blit command */
497 if (cpp == 4) {
498 BR13 |= (1 << 24) | (1 << 25);
499 if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
500 if (clearMask & BUFFER_BIT_DEPTH)
501 CMD |= XY_BLT_WRITE_RGB;
502 if (clearMask & BUFFER_BIT_STENCIL)
503 CMD |= XY_BLT_WRITE_ALPHA;
504 }
505 else {
506 /* clearing RGBA */
507 CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
508 }
509 }
510 else {
511 ASSERT(cpp == 2 || cpp == 0);
512 BR13 |= (1 << 24);
513 }
514
515 #ifndef I915
516 if (irb_region->tiled) {
517 CMD |= XY_DST_TILED;
518 pitch /= 4;
519 }
520 #endif
521 BR13 |= (pitch * cpp);
522
523 if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
524 clearVal = clear_depth;
525 }
526 else {
527 clearVal = (cpp == 4)
528 ? intel->ClearColor8888 : intel->ClearColor565;
529 }
530 /*
531 _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
532 buf, irb->Base.Name);
533 */
534 intel_wait_flips(intel);
535
536 assert(b.x1 < b.x2);
537 assert(b.y1 < b.y2);
538
539 BEGIN_BATCH(6, REFERENCES_CLIPRECTS);
540 OUT_BATCH(CMD);
541 OUT_BATCH(BR13);
542 OUT_BATCH((b.y1 << 16) | b.x1);
543 OUT_BATCH((b.y2 << 16) | b.x2);
544 OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
545 irb_region->draw_offset);
546 OUT_BATCH(clearVal);
547 ADVANCE_BATCH();
548 clearMask &= ~bufBit; /* turn off bit, for faster loop exit */
549 }
550 }
551 }
552 intel_batchbuffer_flush(intel->batch);
553 }
554
555 UNLOCK_HARDWARE(intel);
556 }
557
558 void
559 intelEmitImmediateColorExpandBlit(struct intel_context *intel,
560 GLuint cpp,
561 GLubyte *src_bits, GLuint src_size,
562 GLuint fg_color,
563 GLshort dst_pitch,
564 dri_bo *dst_buffer,
565 GLuint dst_offset,
566 GLboolean dst_tiled,
567 GLshort x, GLshort y,
568 GLshort w, GLshort h,
569 GLenum logic_op)
570 {
571 int dwords = ALIGN(src_size, 8) / 4;
572 uint32_t opcode, br13, blit_cmd;
573
574 assert( logic_op - GL_CLEAR >= 0 );
575 assert( logic_op - GL_CLEAR < 0x10 );
576
577 if (w < 0 || h < 0)
578 return;
579
580 dst_pitch *= cpp;
581
582 if (dst_tiled)
583 dst_pitch /= 4;
584
585 DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d, %d bytes %d dwords\n",
586 __FUNCTION__,
587 dst_buffer, dst_pitch, dst_offset, x, y, w, h, src_size, dwords);
588
589 intel_batchbuffer_require_space( intel->batch,
590 (8 * 4) +
591 (3 * 4) +
592 dwords,
593 NO_LOOP_CLIPRECTS );
594
595 opcode = XY_SETUP_BLT_CMD;
596 if (cpp == 4)
597 opcode |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
598 if (dst_tiled)
599 opcode |= XY_DST_TILED;
600
601 br13 = dst_pitch | (translate_raster_op(logic_op) << 16) | (1 << 29);
602 if (cpp == 2)
603 br13 |= BR13_565;
604 else
605 br13 |= BR13_8888;
606
607 blit_cmd = XY_TEXT_IMMEDIATE_BLIT_CMD | XY_TEXT_BYTE_PACKED; /* packing? */
608 if (dst_tiled)
609 blit_cmd |= XY_DST_TILED;
610
611 BEGIN_BATCH(8 + 3, NO_LOOP_CLIPRECTS);
612 OUT_BATCH(opcode);
613 OUT_BATCH(br13);
614 OUT_BATCH((0 << 16) | 0); /* clip x1, y1 */
615 OUT_BATCH((100 << 16) | 100); /* clip x2, y2 */
616 OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, dst_offset);
617 OUT_BATCH(0); /* bg */
618 OUT_BATCH(fg_color); /* fg */
619 OUT_BATCH(0); /* pattern base addr */
620
621 OUT_BATCH(blit_cmd | ((3 - 2) + dwords));
622 OUT_BATCH((y << 16) | x);
623 OUT_BATCH(((y + h) << 16) | (x + w));
624 ADVANCE_BATCH();
625
626 intel_batchbuffer_data( intel->batch,
627 src_bits,
628 dwords * 4,
629 NO_LOOP_CLIPRECTS );
630 }