1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
36 #include "intel_reg.h"
37 #include "intel_batchbuffer.h"
38 #include "intel_context.h"
43 /* ================================================================
44 * Performance monitoring functions
47 static void intel_fill_box( intelContextPtr intel
,
50 GLubyte r
, GLubyte g
, GLubyte b
)
55 if (x
>= 0 && y
>= 0 &&
56 x
+w
< intel
->intelScreen
->width
&&
57 y
+h
< intel
->intelScreen
->height
)
58 intelEmitFillBlitLocked( intel
,
59 intel
->intelScreen
->cpp
,
60 intel
->intelScreen
->back
.pitch
,
61 intel
->intelScreen
->back
.offset
,
63 INTEL_PACKCOLOR(intel
->intelScreen
->fbFormat
,
67 static void intel_draw_performance_boxes( intelContextPtr intel
)
69 /* Purple box for page flipping
71 if ( intel
->perf_boxes
& I830_BOX_FLIP
)
72 intel_fill_box( intel
, 4, 4, 8, 8, 255, 0, 255 );
74 /* Red box if we have to wait for idle at any point
76 if ( intel
->perf_boxes
& I830_BOX_WAIT
)
77 intel_fill_box( intel
, 16, 4, 8, 8, 255, 0, 0 );
79 /* Blue box: lost context?
81 if ( intel
->perf_boxes
& I830_BOX_LOST_CONTEXT
)
82 intel_fill_box( intel
, 28, 4, 8, 8, 0, 0, 255 );
84 /* Yellow box for texture swaps
86 if ( intel
->perf_boxes
& I830_BOX_TEXTURE_LOAD
)
87 intel_fill_box( intel
, 40, 4, 8, 8, 255, 255, 0 );
89 /* Green box if hardware never idles (as far as we can tell)
91 if ( !(intel
->perf_boxes
& I830_BOX_RING_EMPTY
) )
92 intel_fill_box( intel
, 64, 4, 8, 8, 0, 255, 0 );
95 /* Draw bars indicating number of buffers allocated
96 * (not a great measure, easily confused)
99 if (intel
->dma_used
) {
100 int bar
= intel
->dma_used
/ 10240;
101 if (bar
> 100) bar
= 100;
102 if (bar
< 1) bar
= 1;
103 intel_fill_box( intel
, 4, 16, bar
, 4, 196, 128, 128 );
108 intel
->perf_boxes
= 0;
116 static int bad_prim_vertex_nr( int primitive
, int nr
)
118 switch (primitive
& PRIM3D_MASK
) {
119 case PRIM3D_POINTLIST
:
121 case PRIM3D_LINELIST
:
122 return (nr
& 1) || nr
== 0;
123 case PRIM3D_LINESTRIP
:
126 case PRIM3D_RECTLIST
:
127 return nr
% 3 || nr
== 0;
130 case PRIM3D_TRISTRIP
:
131 case PRIM3D_TRISTRIP_RVRSE
:
138 static void intel_flush_inline_primitive( GLcontext
*ctx
)
140 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
141 GLuint used
= intel
->batch
.ptr
- intel
->prim
.start_ptr
;
144 assert(intel
->prim
.primitive
!= ~0);
147 /* Check vertex size against the vertex we're specifying to
148 * hardware. If it's wrong, ditch the primitive.
150 if (!intel
->vtbl
.check_vertex_size( intel
, intel
->vertex_size
))
153 vertcount
= (used
- 4)/ (intel
->vertex_size
* 4);
158 if (vertcount
* intel
->vertex_size
* 4 != used
- 4) {
159 fprintf(stderr
, "vertex size confusion %d %d\n", used
,
160 intel
->vertex_size
* vertcount
* 4);
164 if (bad_prim_vertex_nr( intel
->prim
.primitive
, vertcount
)) {
165 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", intel
->prim
.primitive
,
174 *(int *)intel
->prim
.start_ptr
= (_3DPRIMITIVE
|
175 intel
->prim
.primitive
|
181 intel
->batch
.ptr
-= used
;
182 intel
->batch
.space
+= used
;
183 assert(intel
->batch
.space
>= 0);
186 intel
->prim
.primitive
= ~0;
187 intel
->prim
.start_ptr
= 0;
188 intel
->prim
.flush
= 0;
192 /* Emit a primitive referencing vertices in a vertex buffer.
194 void intelStartInlinePrimitive( intelContextPtr intel
, GLuint prim
)
199 fprintf(stderr
, "%s %x\n", __FUNCTION__
, prim
);
202 /* Finish any in-progress primitive:
204 INTEL_FIREVERTICES( intel
);
206 /* Emit outstanding state:
208 intel
->vtbl
.emit_state( intel
);
210 /* Make sure there is some space in this buffer:
212 if (intel
->vertex_size
* 10 * sizeof(GLuint
) >= intel
->batch
.space
) {
213 intelFlushBatch(intel
, GL_TRUE
);
214 intel
->vtbl
.emit_state( intel
);
218 if (((int)intel
->batch
.ptr
) & 0x4) {
225 /* Emit a slot which will be filled with the inline primitive
231 intel
->prim
.start_ptr
= batch_ptr
;
232 intel
->prim
.primitive
= prim
;
233 intel
->prim
.flush
= intel_flush_inline_primitive
;
234 intel
->batch
.contains_geometry
= 1;
241 void intelRestartInlinePrimitive( intelContextPtr intel
)
243 GLuint prim
= intel
->prim
.primitive
;
245 intel_flush_inline_primitive( &intel
->ctx
);
246 if (1) intelFlushBatch(intel
, GL_TRUE
); /* GL_TRUE - is critical */
247 intelStartInlinePrimitive( intel
, prim
);
252 void intelWrapInlinePrimitive( intelContextPtr intel
)
254 GLuint prim
= intel
->prim
.primitive
;
257 fprintf(stderr
, "%s\n", __FUNCTION__
);
258 intel_flush_inline_primitive( &intel
->ctx
);
259 intelFlushBatch(intel
, GL_TRUE
);
260 intelStartInlinePrimitive( intel
, prim
);
264 /* Emit a primitive with space for inline vertices.
266 GLuint
*intelEmitInlinePrimitiveLocked(intelContextPtr intel
,
275 fprintf(stderr
, "%s 0x%x %d\n", __FUNCTION__
, primitive
, dwords
);
277 /* Emit outstanding state:
279 intel
->vtbl
.emit_state( intel
);
281 if ((1+dwords
)*4 >= intel
->batch
.space
) {
282 intelFlushBatch(intel
, GL_TRUE
);
283 intel
->vtbl
.emit_state( intel
);
288 int used
= dwords
* 4;
291 /* Check vertex size against the vertex we're specifying to
292 * hardware. If it's wrong, ditch the primitive.
294 if (!intel
->vtbl
.check_vertex_size( intel
, vertex_size
))
297 vertcount
= dwords
/ vertex_size
;
299 if (dwords
% vertex_size
) {
300 fprintf(stderr
, "did not request a whole number of vertices\n");
304 if (bad_prim_vertex_nr( primitive
, vertcount
)) {
305 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", primitive
, vertcount
);
313 /* Emit 3D_PRIMITIVE commands:
315 BEGIN_BATCH(1 + dwords
);
316 OUT_BATCH( _3DPRIMITIVE
|
320 tmp
= (GLuint
*)batch_ptr
;
321 batch_ptr
+= dwords
* 4;
325 intel
->batch
.contains_geometry
= 1;
334 * Copy the back buffer to the front buffer.
336 void intelCopyBuffer( const __DRIdrawablePrivate
*dPriv
)
338 intelContextPtr intel
;
341 fprintf(stderr
, "%s\n", __FUNCTION__
);
344 assert(dPriv
->driContextPriv
);
345 assert(dPriv
->driContextPriv
->driverPrivate
);
347 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
349 intelFlush( &intel
->ctx
);
350 LOCK_HARDWARE( intel
);
352 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
353 const __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
354 const int nbox
= dPriv
->numClipRects
;
355 const drm_clip_rect_t
*pbox
= dPriv
->pClipRects
;
356 const int cpp
= intelScreen
->cpp
;
357 const int pitch
= intelScreen
->front
.pitch
; /* in bytes */
364 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
365 CMD
= XY_SRC_COPY_BLT_CMD
;
368 BR13
= (pitch
) | (0xCC << 16) | (1<<24) | (1<<25);
369 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
370 XY_SRC_COPY_BLT_WRITE_RGB
);
373 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
374 CMD
= XY_SRC_COPY_BLT_CMD
;
379 intel_draw_performance_boxes( intel
);
381 for (i
= 0 ; i
< nbox
; i
++, pbox
++)
383 if (pbox
->x1
> pbox
->x2
||
384 pbox
->y1
> pbox
->y2
||
385 pbox
->x2
> intelScreen
->width
||
386 pbox
->y2
> intelScreen
->height
) {
387 _mesa_warning(&intel
->ctx
, "Bad cliprect in intelCopyBuffer()");
394 OUT_BATCH( (pbox
->y1
<< 16) | pbox
->x1
);
395 OUT_BATCH( (pbox
->y2
<< 16) | pbox
->x2
);
397 if (intel
->sarea
->pf_current_page
== 0)
398 OUT_BATCH( intelScreen
->front
.offset
);
400 OUT_BATCH( intelScreen
->back
.offset
);
402 OUT_BATCH( (pbox
->y1
<< 16) | pbox
->x1
);
403 OUT_BATCH( BR13
& 0xffff );
405 if (intel
->sarea
->pf_current_page
== 0)
406 OUT_BATCH( intelScreen
->back
.offset
);
408 OUT_BATCH( intelScreen
->front
.offset
);
413 intelFlushBatchLocked( intel
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
414 UNLOCK_HARDWARE( intel
);
420 void intelEmitFillBlitLocked( intelContextPtr intel
,
422 GLshort dst_pitch
, /* in bytes */
424 GLshort x
, GLshort y
,
425 GLshort w
, GLshort h
,
435 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24);
436 CMD
= XY_COLOR_BLT_CMD
;
439 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24) | (1<<25);
440 CMD
= (XY_COLOR_BLT_CMD
| XY_COLOR_BLT_WRITE_ALPHA
|
441 XY_COLOR_BLT_WRITE_RGB
);
450 OUT_BATCH( (y
<< 16) | x
);
451 OUT_BATCH( ((y
+h
) << 16) | (x
+w
) );
452 OUT_BATCH( dst_offset
);
460 void intelEmitCopyBlitLocked( intelContextPtr intel
,
466 GLshort src_x
, GLshort src_y
,
467 GLshort dst_x
, GLshort dst_y
,
468 GLshort w
, GLshort h
)
471 int dst_y2
= dst_y
+ h
;
472 int dst_x2
= dst_x
+ w
;
482 BR13
= dst_pitch
| (0xCC << 16) | (1<<24);
483 CMD
= XY_SRC_COPY_BLT_CMD
;
486 BR13
= dst_pitch
| (0xCC << 16) | (1<<24) | (1<<25);
487 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
488 XY_SRC_COPY_BLT_WRITE_RGB
);
494 if (dst_y2
< dst_y
||
502 OUT_BATCH( (dst_y
<< 16) | dst_x
);
503 OUT_BATCH( (dst_y2
<< 16) | dst_x2
);
504 OUT_BATCH( dst_offset
);
505 OUT_BATCH( (src_y
<< 16) | src_x
);
506 OUT_BATCH( src_pitch
);
507 OUT_BATCH( src_offset
);
513 void intelClearWithBlit(GLcontext
*ctx
, GLbitfield flags
, GLboolean all
,
514 GLint cx1
, GLint cy1
, GLint cw
, GLint ch
)
516 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
517 intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
518 GLuint clear_depth
, clear_color
;
521 GLint cpp
= intelScreen
->cpp
;
523 GLuint BR13
, CMD
, D_CMD
;
526 intelFlush( &intel
->ctx
);
527 LOCK_HARDWARE( intel
);
529 pitch
= intelScreen
->front
.pitch
;
531 clear_color
= intel
->ClearColor
;
534 if (flags
& BUFFER_BIT_DEPTH
) {
535 clear_depth
= (GLuint
)(ctx
->Depth
.Clear
* intel
->ClearDepth
);
538 if (flags
& BUFFER_BIT_STENCIL
) {
539 clear_depth
|= (ctx
->Stencil
.Clear
& 0xff) << 24;
544 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
545 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
548 BR13
= (0xF0 << 16) | (pitch
) | (1<<24) | (1<<25);
549 CMD
= (XY_COLOR_BLT_CMD
|
550 XY_COLOR_BLT_WRITE_ALPHA
|
551 XY_COLOR_BLT_WRITE_RGB
);
552 D_CMD
= XY_COLOR_BLT_CMD
;
553 if (flags
& BUFFER_BIT_DEPTH
) D_CMD
|= XY_COLOR_BLT_WRITE_RGB
;
554 if (flags
& BUFFER_BIT_STENCIL
) D_CMD
|= XY_COLOR_BLT_WRITE_ALPHA
;
557 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
558 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
563 /* flip top to bottom */
564 cy
= intel
->driDrawable
->h
-cy1
-ch
;
565 cx
= cx1
+ intel
->drawX
;
568 /* adjust for page flipping */
569 if ( intel
->sarea
->pf_current_page
== 1 ) {
572 flags
&= ~(BUFFER_BIT_FRONT_LEFT
| BUFFER_BIT_BACK_LEFT
);
573 if ( tmp
& BUFFER_BIT_FRONT_LEFT
) flags
|= BUFFER_BIT_BACK_LEFT
;
574 if ( tmp
& BUFFER_BIT_BACK_LEFT
) flags
|= BUFFER_BIT_FRONT_LEFT
;
577 for (i
= 0 ; i
< intel
->numClipRects
; i
++)
579 drm_clip_rect_t
*box
= &intel
->pClipRects
[i
];
585 GLint w
= box
[i
].x2
- x
;
586 GLint h
= box
[i
].y2
- y
;
588 if (x
< cx
) w
-= cx
- x
, x
= cx
;
589 if (y
< cy
) h
-= cy
- y
, y
= cy
;
590 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
591 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
592 if (w
<= 0) continue;
593 if (h
<= 0) continue;
606 b
.x2
> intelScreen
->width
||
607 b
.y2
> intelScreen
->height
)
610 if ( flags
& BUFFER_BIT_FRONT_LEFT
) {
614 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
615 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
616 OUT_BATCH( intelScreen
->front
.offset
);
617 OUT_BATCH( clear_color
);
621 if ( flags
& BUFFER_BIT_BACK_LEFT
) {
625 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
626 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
627 OUT_BATCH( intelScreen
->back
.offset
);
628 OUT_BATCH( clear_color
);
632 if ( flags
& (BUFFER_BIT_STENCIL
| BUFFER_BIT_DEPTH
) ) {
636 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
637 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
638 OUT_BATCH( intelScreen
->depth
.offset
);
639 OUT_BATCH( clear_depth
);
644 intelFlushBatchLocked( intel
, GL_TRUE
, GL_FALSE
, GL_TRUE
);
645 UNLOCK_HARDWARE( intel
);
651 void intelDestroyBatchBuffer( GLcontext
*ctx
)
653 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
655 if (intel
->alloc
.offset
) {
656 intelFreeAGP( intel
, intel
->alloc
.ptr
);
657 intel
->alloc
.ptr
= NULL
;
658 intel
->alloc
.offset
= 0;
660 else if (intel
->alloc
.ptr
) {
661 free(intel
->alloc
.ptr
);
662 intel
->alloc
.ptr
= NULL
;
665 memset(&intel
->batch
, 0, sizeof(intel
->batch
));
669 void intelInitBatchBuffer( GLcontext
*ctx
)
671 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
673 /* This path isn't really safe with rotate:
675 if (getenv("INTEL_BATCH") && intel
->intelScreen
->allow_batchbuffer
) {
676 switch (intel
->intelScreen
->deviceID
) {
677 case PCI_CHIP_I865_G
:
678 /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
680 intel
->alloc
.size
= 8 * 1024;
683 /* This is the smallest amount of memory the kernel deals with.
684 * We'd ideally like to make this smaller.
686 intel
->alloc
.size
= 1 << intel
->intelScreen
->logTextureGranularity
;
690 /* KW: temporary - this make crashes & lockups more frequent, so
691 * leave in until they are solved.
693 intel
->alloc
.size
= 8 * 1024;
695 intel
->alloc
.ptr
= intelAllocateAGP( intel
, intel
->alloc
.size
);
696 if (intel
->alloc
.ptr
)
697 intel
->alloc
.offset
=
698 intelAgpOffsetFromVirtual( intel
, intel
->alloc
.ptr
);
700 intel
->alloc
.offset
= 0; /* OK? */
703 /* The default is now to use a local buffer and pass that to the
704 * kernel. This is also a fallback if allocation fails on the
707 if (!intel
->alloc
.ptr
) {
708 intel
->alloc
.size
= 8 * 1024;
709 intel
->alloc
.ptr
= malloc( intel
->alloc
.size
);
710 intel
->alloc
.offset
= 0;
713 assert(intel
->alloc
.ptr
);