84ec70e2b9eaba6003e91bf333e9ca041e173658
[mesa.git] / src / mesa / drivers / dri / i915 / intel_batchbuffer.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_reg.h"
37 #include "intel_batchbuffer.h"
38 #include "intel_context.h"
39
40
41
42
43 /* ================================================================
44 * Performance monitoring functions
45 */
46
47 static void intel_fill_box( intelContextPtr intel,
48 GLshort x, GLshort y,
49 GLshort w, GLshort h,
50 GLubyte r, GLubyte g, GLubyte b )
51 {
52 intelEmitFillBlitLocked( intel,
53 intel->intelScreen->cpp,
54 intel->intelScreen->back.pitch,
55 intel->intelScreen->front.offset,
56 x, y, w, h,
57 INTEL_PACKCOLOR(intel->intelScreen->fbFormat,
58 r,g,b,0xff));
59 }
60
61 static void intel_draw_performance_boxes( intelContextPtr intel )
62 {
63 /* Purple box for page flipping
64 */
65 if ( intel->perf_boxes & I830_BOX_FLIP )
66 intel_fill_box( intel, 4, 4, 8, 8, 255, 0, 255 );
67
68 /* Red box if we have to wait for idle at any point
69 */
70 if ( intel->perf_boxes & I830_BOX_WAIT )
71 intel_fill_box( intel, 16, 4, 8, 8, 255, 0, 0 );
72
73 /* Blue box: lost context?
74 */
75 if ( intel->perf_boxes & I830_BOX_LOST_CONTEXT )
76 intel_fill_box( intel, 28, 4, 8, 8, 0, 0, 255 );
77
78 /* Yellow box for texture swaps
79 */
80 if ( intel->perf_boxes & I830_BOX_TEXTURE_LOAD )
81 intel_fill_box( intel, 40, 4, 8, 8, 255, 255, 0 );
82
83 /* Green box if hardware never idles (as far as we can tell)
84 */
85 if ( !(intel->perf_boxes & I830_BOX_RING_EMPTY) )
86 intel_fill_box( intel, 64, 4, 8, 8, 0, 255, 0 );
87
88
89 /* Draw bars indicating number of buffers allocated
90 * (not a great measure, easily confused)
91 */
92 #if 0
93 if (intel->dma_used) {
94 int bar = intel->dma_used / 10240;
95 if (bar > 100) bar = 100;
96 if (bar < 1) bar = 1;
97 intel_fill_box( intel, 4, 16, bar, 4, 196, 128, 128 );
98 intel->dma_used = 0;
99 }
100 #endif
101
102 intel->perf_boxes = 0;
103 }
104
105
106
107
108
109
110 static int bad_prim_vertex_nr( int primitive, int nr )
111 {
112 switch (primitive & PRIM3D_MASK) {
113 case PRIM3D_POINTLIST:
114 return nr < 1;
115 case PRIM3D_LINELIST:
116 return (nr & 1) || nr == 0;
117 case PRIM3D_LINESTRIP:
118 return nr < 2;
119 case PRIM3D_TRILIST:
120 case PRIM3D_RECTLIST:
121 return nr % 3 || nr == 0;
122 case PRIM3D_POLY:
123 case PRIM3D_TRIFAN:
124 case PRIM3D_TRISTRIP:
125 case PRIM3D_TRISTRIP_RVRSE:
126 return nr < 3;
127 default:
128 return 1;
129 }
130 }
131
132 static void intel_flush_inline_primitive( GLcontext *ctx )
133 {
134 intelContextPtr intel = INTEL_CONTEXT( ctx );
135 GLuint used = intel->batch.ptr - intel->prim.start_ptr;
136 GLuint vertcount;
137
138 assert(intel->prim.primitive != ~0);
139
140 if (1) {
141 /* Check vertex size against the vertex we're specifying to
142 * hardware. If it's wrong, ditch the primitive.
143 */
144 if (!intel->vtbl.check_vertex_size( intel, intel->vertex_size ))
145 goto do_discard;
146
147 vertcount = (used - 4)/ (intel->vertex_size * 4);
148
149 if (!vertcount)
150 goto do_discard;
151
152 if (vertcount * intel->vertex_size * 4 != used - 4) {
153 fprintf(stderr, "vertex size confusion %d %d\n", used,
154 intel->vertex_size * vertcount * 4);
155 goto do_discard;
156 }
157
158 if (bad_prim_vertex_nr( intel->prim.primitive, vertcount )) {
159 fprintf(stderr, "bad_prim_vertex_nr %x %d\n", intel->prim.primitive,
160 vertcount);
161 goto do_discard;
162 }
163 }
164
165 if (used < 8)
166 goto do_discard;
167
168 *(int *)intel->prim.start_ptr = (_3DPRIMITIVE |
169 intel->prim.primitive |
170 (used/4-2));
171
172 goto finished;
173
174 do_discard:
175 intel->batch.ptr -= used;
176 intel->batch.space += used;
177 assert(intel->batch.space >= 0);
178
179 finished:
180 intel->prim.primitive = ~0;
181 intel->prim.start_ptr = 0;
182 intel->prim.flush = 0;
183 }
184
185
186 /* Emit a primitive referencing vertices in a vertex buffer.
187 */
188 void intelStartInlinePrimitive( intelContextPtr intel, GLuint prim )
189 {
190 BATCH_LOCALS;
191
192 if (0)
193 fprintf(stderr, "%s %x\n", __FUNCTION__, prim);
194
195
196 /* Finish any in-progress primitive:
197 */
198 INTEL_FIREVERTICES( intel );
199
200 /* Emit outstanding state:
201 */
202 intel->vtbl.emit_state( intel );
203
204 /* Make sure there is some space in this buffer:
205 */
206 if (intel->vertex_size * 10 * sizeof(GLuint) >= intel->batch.space)
207 intelFlushBatch(intel, GL_TRUE);
208
209
210 #if 1
211 if (((int)intel->batch.ptr) & 0x4) {
212 BEGIN_BATCH(1);
213 OUT_BATCH(0);
214 ADVANCE_BATCH();
215 }
216 #endif
217
218 /* Emit a slot which will be filled with the inline primitive
219 * command later.
220 */
221 BEGIN_BATCH(2);
222 OUT_BATCH( 0 );
223
224 intel->prim.start_ptr = batch_ptr;
225 intel->prim.primitive = prim;
226 intel->prim.flush = intel_flush_inline_primitive;
227
228 OUT_BATCH( 0 );
229 ADVANCE_BATCH();
230 }
231
232
233 void intelRestartInlinePrimitive( intelContextPtr intel )
234 {
235 GLuint prim = intel->prim.primitive;
236
237 intel_flush_inline_primitive( &intel->ctx );
238 if (1) intelFlushBatch(intel, GL_TRUE); /* GL_TRUE - is critical */
239 intelStartInlinePrimitive( intel, prim );
240 }
241
242
243
244 void intelWrapInlinePrimitive( intelContextPtr intel )
245 {
246 GLuint prim = intel->prim.primitive;
247
248 if (0)
249 fprintf(stderr, "%s\n", __FUNCTION__);
250 intel_flush_inline_primitive( &intel->ctx );
251 intelFlushBatch(intel, GL_TRUE);
252 intelStartInlinePrimitive( intel, prim );
253 }
254
255
256 /* Emit a primitive with space for inline vertices.
257 */
258 GLuint *intelEmitInlinePrimitiveLocked(intelContextPtr intel,
259 int primitive,
260 int dwords,
261 int vertex_size )
262 {
263 GLuint *tmp = 0;
264 BATCH_LOCALS;
265
266 if (0)
267 fprintf(stderr, "%s 0x%x %d\n", __FUNCTION__, primitive, dwords);
268
269 /* Emit outstanding state:
270 */
271 intel->vtbl.emit_state( intel );
272
273
274 if (1) {
275 int used = dwords * 4;
276 int vertcount;
277
278 /* Check vertex size against the vertex we're specifying to
279 * hardware. If it's wrong, ditch the primitive.
280 */
281 if (!intel->vtbl.check_vertex_size( intel, vertex_size ))
282 goto do_discard;
283
284 vertcount = dwords / vertex_size;
285
286 if (dwords % vertex_size) {
287 fprintf(stderr, "did not request a whole number of vertices\n");
288 goto do_discard;
289 }
290
291 if (bad_prim_vertex_nr( primitive, vertcount )) {
292 fprintf(stderr, "bad_prim_vertex_nr %x %d\n", primitive, vertcount);
293 goto do_discard;
294 }
295
296 if (used < 8)
297 goto do_discard;
298 }
299
300 /* Emit 3D_PRIMITIVE commands:
301 */
302 BEGIN_BATCH(1 + dwords);
303 OUT_BATCH( _3DPRIMITIVE |
304 primitive |
305 (dwords-1) );
306
307 tmp = (GLuint *)batch_ptr;
308 batch_ptr += dwords * 4;
309
310 ADVANCE_BATCH();
311
312 do_discard:
313 return tmp;
314 }
315
316
317
318 /*
319 * Copy the back buffer to the front buffer.
320 */
321 void intelCopyBuffer( const __DRIdrawablePrivate *dPriv )
322 {
323 intelContextPtr intel;
324
325 if (0)
326 fprintf(stderr, "%s\n", __FUNCTION__);
327
328 assert(dPriv);
329 assert(dPriv->driContextPriv);
330 assert(dPriv->driContextPriv->driverPrivate);
331
332 intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate;
333
334 intelFlush( &intel->ctx );
335 LOCK_HARDWARE( intel );
336 {
337 intelScreenPrivate *intelScreen = intel->intelScreen;
338 __DRIdrawablePrivate *dPriv = intel->driDrawable;
339 int nbox = dPriv->numClipRects;
340 drm_clip_rect_t *pbox = dPriv->pClipRects;
341 int pitch = intelScreen->front.pitch;
342 int cpp = intelScreen->cpp;
343 int i;
344 GLuint CMD, BR13;
345 BATCH_LOCALS;
346
347 switch(cpp) {
348 case 2:
349 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
350 CMD = XY_SRC_COPY_BLT_CMD;
351 break;
352 case 4:
353 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
354 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
355 XY_SRC_COPY_BLT_WRITE_RGB);
356 break;
357 default:
358 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
359 CMD = XY_SRC_COPY_BLT_CMD;
360 break;
361 }
362
363 if (0)
364 intel_draw_performance_boxes( intel );
365
366 for (i = 0 ; i < nbox; i++, pbox++)
367 {
368 if (pbox->x1 > pbox->x2 ||
369 pbox->y1 > pbox->y2 ||
370 pbox->x2 > intelScreen->width ||
371 pbox->y2 > intelScreen->height)
372 continue;
373
374 BEGIN_BATCH( 8);
375 OUT_BATCH( CMD );
376 OUT_BATCH( BR13 );
377 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
378 OUT_BATCH( (pbox->y2 << 16) | pbox->x2 );
379
380 if (intel->sarea->pf_current_page == 0)
381 OUT_BATCH( intelScreen->front.offset );
382 else
383 OUT_BATCH( intelScreen->back.offset );
384
385 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
386 OUT_BATCH( BR13 & 0xffff );
387
388 if (intel->sarea->pf_current_page == 0)
389 OUT_BATCH( intelScreen->back.offset );
390 else
391 OUT_BATCH( intelScreen->front.offset );
392
393 ADVANCE_BATCH();
394 }
395 }
396 intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE );
397 UNLOCK_HARDWARE( intel );
398 }
399
400
401
402
403 void intelEmitFillBlitLocked( intelContextPtr intel,
404 GLuint cpp,
405 GLshort dst_pitch,
406 GLuint dst_offset,
407 GLshort x, GLshort y,
408 GLshort w, GLshort h,
409 GLuint color )
410 {
411 GLuint BR13, CMD;
412 BATCH_LOCALS;
413
414 dst_pitch *= cpp;
415
416 switch(cpp) {
417 case 1:
418 case 2:
419 case 3:
420 BR13 = dst_pitch | (0xF0 << 16) | (1<<24);
421 CMD = XY_COLOR_BLT_CMD;
422 break;
423 case 4:
424 BR13 = dst_pitch | (0xF0 << 16) | (1<<24) | (1<<25);
425 CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
426 XY_COLOR_BLT_WRITE_RGB);
427 break;
428 default:
429 return;
430 }
431
432 BEGIN_BATCH( 6);
433 OUT_BATCH( CMD );
434 OUT_BATCH( BR13 );
435 OUT_BATCH( (y << 16) | x );
436 OUT_BATCH( ((y+h) << 16) | (x+w) );
437 OUT_BATCH( dst_offset );
438 OUT_BATCH( color );
439 ADVANCE_BATCH();
440 }
441
442
443 /* Copy BitBlt
444 */
445 void intelEmitCopyBlitLocked( intelContextPtr intel,
446 GLuint cpp,
447 GLshort src_pitch,
448 GLuint src_offset,
449 GLshort dst_pitch,
450 GLuint dst_offset,
451 GLshort src_x, GLshort src_y,
452 GLshort dst_x, GLshort dst_y,
453 GLshort w, GLshort h )
454 {
455 GLuint CMD, BR13;
456 int dst_y2 = dst_y + h;
457 int dst_x2 = dst_x + w;
458 BATCH_LOCALS;
459
460 src_pitch *= cpp;
461 dst_pitch *= cpp;
462
463 switch(cpp) {
464 case 1:
465 case 2:
466 case 3:
467 BR13 = dst_pitch | (0xCC << 16) | (1<<24);
468 CMD = XY_SRC_COPY_BLT_CMD;
469 break;
470 case 4:
471 BR13 = dst_pitch | (0xCC << 16) | (1<<24) | (1<<25);
472 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
473 XY_SRC_COPY_BLT_WRITE_RGB);
474 break;
475 default:
476 return;
477 }
478
479 if (dst_y2 < dst_y ||
480 dst_x2 < dst_x) {
481 return;
482 }
483
484 BEGIN_BATCH( 12);
485 OUT_BATCH( CMD );
486 OUT_BATCH( BR13 );
487 OUT_BATCH( (dst_y << 16) | dst_x );
488 OUT_BATCH( (dst_y2 << 16) | dst_x2 );
489 OUT_BATCH( dst_offset );
490 OUT_BATCH( (src_y << 16) | src_x );
491 OUT_BATCH( src_pitch );
492 OUT_BATCH( src_offset );
493 ADVANCE_BATCH();
494 }
495
496
497
498 void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all,
499 GLint cx1, GLint cy1, GLint cw, GLint ch)
500 {
501 intelContextPtr intel = INTEL_CONTEXT( ctx );
502 intelScreenPrivate *intelScreen = intel->intelScreen;
503 GLuint clear_depth, clear_color;
504 GLint cx, cy;
505 GLint pitch = intelScreen->front.pitch;
506 GLint cpp = intelScreen->cpp;
507 GLint i;
508 GLuint BR13, CMD, D_CMD;
509 BATCH_LOCALS;
510
511
512 clear_color = intel->ClearColor;
513 clear_depth = 0;
514
515 if (flags & BUFFER_BIT_DEPTH) {
516 clear_depth = (GLuint)(ctx->Depth.Clear * intel->ClearDepth);
517 }
518
519 if (flags & BUFFER_BIT_STENCIL) {
520 clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
521 }
522
523 switch(cpp) {
524 case 2:
525 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
526 D_CMD = CMD = XY_COLOR_BLT_CMD;
527 break;
528 case 4:
529 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
530 CMD = (XY_COLOR_BLT_CMD |
531 XY_COLOR_BLT_WRITE_ALPHA |
532 XY_COLOR_BLT_WRITE_RGB);
533 D_CMD = XY_COLOR_BLT_CMD;
534 if (flags & BUFFER_BIT_DEPTH) D_CMD |= XY_COLOR_BLT_WRITE_RGB;
535 if (flags & BUFFER_BIT_STENCIL) D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
536 break;
537 default:
538 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
539 D_CMD = CMD = XY_COLOR_BLT_CMD;
540 break;
541 }
542
543 intelFlush( &intel->ctx );
544 LOCK_HARDWARE( intel );
545 {
546 /* flip top to bottom */
547 cy = intel->driDrawable->h-cy1-ch;
548 cx = cx1 + intel->drawX;
549 cy += intel->drawY;
550
551 /* adjust for page flipping */
552 if ( intel->sarea->pf_current_page == 1 ) {
553 GLuint tmp = flags;
554
555 flags &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT);
556 if ( tmp & BUFFER_BIT_FRONT_LEFT ) flags |= BUFFER_BIT_BACK_LEFT;
557 if ( tmp & BUFFER_BIT_BACK_LEFT ) flags |= BUFFER_BIT_FRONT_LEFT;
558 }
559
560 for (i = 0 ; i < intel->numClipRects ; i++)
561 {
562 drm_clip_rect_t *box = &intel->pClipRects[i];
563 drm_clip_rect_t b;
564
565 if (!all) {
566 GLint x = box[i].x1;
567 GLint y = box[i].y1;
568 GLint w = box[i].x2 - x;
569 GLint h = box[i].y2 - y;
570
571 if (x < cx) w -= cx - x, x = cx;
572 if (y < cy) h -= cy - y, y = cy;
573 if (x + w > cx + cw) w = cx + cw - x;
574 if (y + h > cy + ch) h = cy + ch - y;
575 if (w <= 0) continue;
576 if (h <= 0) continue;
577
578 b.x1 = x;
579 b.y1 = y;
580 b.x2 = x + w;
581 b.y2 = y + h;
582 } else {
583 b = *box;
584 }
585
586
587 if (b.x1 > b.x2 ||
588 b.y1 > b.y2 ||
589 b.x2 > intelScreen->width ||
590 b.y2 > intelScreen->height)
591 continue;
592
593 if ( flags & BUFFER_BIT_FRONT_LEFT ) {
594 BEGIN_BATCH( 6);
595 OUT_BATCH( CMD );
596 OUT_BATCH( BR13 );
597 OUT_BATCH( (b.y1 << 16) | b.x1 );
598 OUT_BATCH( (b.y2 << 16) | b.x2 );
599 OUT_BATCH( intelScreen->front.offset );
600 OUT_BATCH( clear_color );
601 ADVANCE_BATCH();
602 }
603
604 if ( flags & BUFFER_BIT_BACK_LEFT ) {
605 BEGIN_BATCH( 6);
606 OUT_BATCH( CMD );
607 OUT_BATCH( BR13 );
608 OUT_BATCH( (b.y1 << 16) | b.x1 );
609 OUT_BATCH( (b.y2 << 16) | b.x2 );
610 OUT_BATCH( intelScreen->back.offset );
611 OUT_BATCH( clear_color );
612 ADVANCE_BATCH();
613 }
614
615 if ( flags & (BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH) ) {
616 BEGIN_BATCH( 6);
617 OUT_BATCH( D_CMD );
618 OUT_BATCH( BR13 );
619 OUT_BATCH( (b.y1 << 16) | b.x1 );
620 OUT_BATCH( (b.y2 << 16) | b.x2 );
621 OUT_BATCH( intelScreen->depth.offset );
622 OUT_BATCH( clear_depth );
623 ADVANCE_BATCH();
624 }
625 }
626 }
627 intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE );
628 UNLOCK_HARDWARE( intel );
629 }
630
631
632
633
634 void intelDestroyBatchBuffer( GLcontext *ctx )
635 {
636 intelContextPtr intel = INTEL_CONTEXT(ctx);
637
638 if (intel->alloc.ptr) {
639 intelFreeAGP( intel, intel->alloc.ptr );
640 intel->alloc.ptr = 0;
641 }
642 }
643
644
645 void intelInitBatchBuffer( GLcontext *ctx )
646 {
647 intelContextPtr intel = INTEL_CONTEXT(ctx);
648
649 if (!intel->intelScreen->allow_batchbuffer || getenv("INTEL_NO_BATCH")) {
650 intel->alloc.size = 8 * 1024;
651 intel->alloc.ptr = malloc( intel->alloc.size );
652 intel->alloc.offset = 0;
653 }
654 else {
655 switch (intel->intelScreen->deviceID) {
656 case PCI_CHIP_I865_G:
657 /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
658 */
659 intel->alloc.size = 8 * 1024;
660 break;
661 default:
662 /* This is the smallest amount of memory the kernel deals with.
663 * We'd ideally like to make this smaller.
664 */
665 intel->alloc.size = 1 << intel->intelScreen->logTextureGranularity;
666 break;
667 }
668
669 intel->alloc.ptr = intelAllocateAGP( intel, intel->alloc.size );
670 if (intel->alloc.ptr)
671 intel->alloc.offset =
672 intelAgpOffsetFromVirtual( intel, intel->alloc.ptr );
673 }
674
675 if (!intel->alloc.ptr) {
676 FALLBACK(intel, INTEL_FALLBACK_NO_BATCHBUFFER, 1);
677 }
678 else {
679 intel->prim.flush = 0;
680 intel->vtbl.emit_invarient_state( intel );
681
682 /* Make sure this gets to the hardware, even if we have no cliprects:
683 */
684 LOCK_HARDWARE( intel );
685 intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE );
686 UNLOCK_HARDWARE( intel );
687 }
688 }