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
)
52 intelEmitFillBlitLocked( intel
,
53 intel
->intelScreen
->cpp
,
54 intel
->intelScreen
->backPitch
,
55 intel
->intelScreen
->frontOffset
,
57 INTEL_PACKCOLOR(intel
->intelScreen
->fbFormat
,
61 static void intel_draw_performance_boxes( intelContextPtr intel
)
63 /* Purple box for page flipping
65 if ( intel
->perf_boxes
& I830_BOX_FLIP
)
66 intel_fill_box( intel
, 4, 4, 8, 8, 255, 0, 255 );
68 /* Red box if we have to wait for idle at any point
70 if ( intel
->perf_boxes
& I830_BOX_WAIT
)
71 intel_fill_box( intel
, 16, 4, 8, 8, 255, 0, 0 );
73 /* Blue box: lost context?
75 if ( intel
->perf_boxes
& I830_BOX_LOST_CONTEXT
)
76 intel_fill_box( intel
, 28, 4, 8, 8, 0, 0, 255 );
78 /* Yellow box for texture swaps
80 if ( intel
->perf_boxes
& I830_BOX_TEXTURE_LOAD
)
81 intel_fill_box( intel
, 40, 4, 8, 8, 255, 255, 0 );
83 /* Green box if hardware never idles (as far as we can tell)
85 if ( !(intel
->perf_boxes
& I830_BOX_RING_EMPTY
) )
86 intel_fill_box( intel
, 64, 4, 8, 8, 0, 255, 0 );
89 /* Draw bars indicating number of buffers allocated
90 * (not a great measure, easily confused)
93 if (intel
->dma_used
) {
94 int bar
= intel
->dma_used
/ 10240;
95 if (bar
> 100) bar
= 100;
97 intel_fill_box( intel
, 4, 16, bar
, 4, 196, 128, 128 );
102 intel
->perf_boxes
= 0;
110 static int bad_prim_vertex_nr( int primitive
, int nr
)
112 switch (primitive
& PRIM3D_MASK
) {
113 case PRIM3D_POINTLIST
:
115 case PRIM3D_LINELIST
:
116 return (nr
& 1) || nr
== 0;
117 case PRIM3D_LINESTRIP
:
120 case PRIM3D_RECTLIST
:
121 return nr
% 3 || nr
== 0;
124 case PRIM3D_TRISTRIP
:
125 case PRIM3D_TRISTRIP_RVRSE
:
132 static void intel_flush_inline_primitive( GLcontext
*ctx
)
134 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
135 GLuint used
= intel
->batch
.ptr
- intel
->prim
.start_ptr
;
138 assert(intel
->prim
.primitive
!= ~0);
141 /* Check vertex size against the vertex we're specifying to
142 * hardware. If it's wrong, ditch the primitive.
144 if (!intel
->vtbl
.check_vertex_size( intel
, intel
->vertex_size
))
147 vertcount
= (used
- 4)/ (intel
->vertex_size
* 4);
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);
158 if (bad_prim_vertex_nr( intel
->prim
.primitive
, vertcount
)) {
159 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", intel
->prim
.primitive
,
168 *(int *)intel
->prim
.start_ptr
= (_3DPRIMITIVE
|
169 intel
->prim
.primitive
|
175 intel
->batch
.ptr
-= used
;
176 intel
->batch
.space
+= used
;
177 assert(intel
->batch
.space
>= 0);
180 intel
->prim
.primitive
= ~0;
181 intel
->prim
.start_ptr
= 0;
182 intel
->prim
.flush
= 0;
186 /* Emit a primitive referencing vertices in a vertex buffer.
188 void intelStartInlinePrimitive( intelContextPtr intel
, GLuint prim
)
193 fprintf(stderr
, "%s %x\n", __FUNCTION__
, prim
);
196 /* Finish any in-progress primitive:
198 INTEL_FIREVERTICES( intel
);
200 /* Emit outstanding state:
202 intel
->vtbl
.emit_state( intel
);
204 /* Make sure there is some space in this buffer:
206 if (intel
->vertex_size
* 10 * sizeof(GLuint
) >= intel
->batch
.space
)
207 intelFlushBatch(intel
, GL_TRUE
);
211 if (((int)intel
->batch
.ptr
) & 0x4) {
218 /* Emit a slot which will be filled with the inline primitive
224 intel
->prim
.start_ptr
= batch_ptr
;
225 intel
->prim
.primitive
= prim
;
226 intel
->prim
.flush
= intel_flush_inline_primitive
;
233 void intelRestartInlinePrimitive( intelContextPtr intel
)
235 GLuint prim
= intel
->prim
.primitive
;
237 intel_flush_inline_primitive( &intel
->ctx
);
238 if (1) intelFlushBatch(intel
, GL_TRUE
); /* GL_TRUE - is critical */
239 intelStartInlinePrimitive( intel
, prim
);
244 void intelWrapInlinePrimitive( intelContextPtr intel
)
246 GLuint prim
= intel
->prim
.primitive
;
249 fprintf(stderr
, "%s\n", __FUNCTION__
);
250 intel_flush_inline_primitive( &intel
->ctx
);
251 intelFlushBatch(intel
, GL_TRUE
);
252 intelStartInlinePrimitive( intel
, prim
);
256 /* Emit a primitive with space for inline vertices.
258 GLuint
*intelEmitInlinePrimitiveLocked(intelContextPtr intel
,
267 fprintf(stderr
, "%s 0x%x %d\n", __FUNCTION__
, primitive
, dwords
);
269 /* Emit outstanding state:
271 intel
->vtbl
.emit_state( intel
);
275 int used
= dwords
* 4;
278 /* Check vertex size against the vertex we're specifying to
279 * hardware. If it's wrong, ditch the primitive.
281 if (!intel
->vtbl
.check_vertex_size( intel
, vertex_size
))
284 vertcount
= dwords
/ vertex_size
;
286 if (dwords
% vertex_size
) {
287 fprintf(stderr
, "did not request a whole number of vertices\n");
291 if (bad_prim_vertex_nr( primitive
, vertcount
)) {
292 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", primitive
, vertcount
);
300 /* Emit 3D_PRIMITIVE commands:
302 BEGIN_BATCH(1 + dwords
);
303 OUT_BATCH( _3DPRIMITIVE
|
307 tmp
= (GLuint
*)batch_ptr
;
308 batch_ptr
+= dwords
* 4;
319 * Copy the back buffer to the front buffer.
321 void intelCopyBuffer( const __DRIdrawablePrivate
*dPriv
)
323 intelContextPtr intel
;
326 fprintf(stderr
, "%s\n", __FUNCTION__
);
329 assert(dPriv
->driContextPriv
);
330 assert(dPriv
->driContextPriv
->driverPrivate
);
332 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
334 intelFlush( &intel
->ctx
);
335 LOCK_HARDWARE( intel
);
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
->frontPitch
;
342 int cpp
= intelScreen
->cpp
;
349 BR13
= (pitch
* cpp
) | (0xCC << 16) | (1<<24);
350 CMD
= XY_SRC_COPY_BLT_CMD
;
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
);
358 BR13
= (pitch
* cpp
) | (0xCC << 16) | (1<<24);
359 CMD
= XY_SRC_COPY_BLT_CMD
;
364 intel_draw_performance_boxes( intel
);
366 for (i
= 0 ; i
< nbox
; i
++, pbox
++)
368 if (pbox
->x1
> pbox
->x2
||
369 pbox
->y1
> pbox
->y2
||
370 pbox
->x2
> intelScreen
->width
||
371 pbox
->y2
> intelScreen
->height
)
377 OUT_BATCH( (pbox
->y1
<< 16) | pbox
->x1
);
378 OUT_BATCH( (pbox
->y2
<< 16) | pbox
->x2
);
380 if (intel
->sarea
->pf_current_page
== 0)
381 OUT_BATCH( intelScreen
->frontOffset
);
383 OUT_BATCH( intelScreen
->backOffset
);
385 OUT_BATCH( (pbox
->y1
<< 16) | pbox
->x1
);
386 OUT_BATCH( BR13
& 0xffff );
388 if (intel
->sarea
->pf_current_page
== 0)
389 OUT_BATCH( intelScreen
->backOffset
);
391 OUT_BATCH( intelScreen
->frontOffset
);
396 intelFlushBatchLocked( intel
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
397 UNLOCK_HARDWARE( intel
);
403 void intelEmitFillBlitLocked( intelContextPtr intel
,
407 GLshort x
, GLshort y
,
408 GLshort w
, GLshort h
,
420 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24);
421 CMD
= XY_COLOR_BLT_CMD
;
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
);
435 OUT_BATCH( (y
<< 16) | x
);
436 OUT_BATCH( ((y
+h
) << 16) | (x
+w
) );
437 OUT_BATCH( dst_offset
);
445 void intelEmitCopyBlitLocked( intelContextPtr intel
,
451 GLshort src_x
, GLshort src_y
,
452 GLshort dst_x
, GLshort dst_y
,
453 GLshort w
, GLshort h
)
456 int dst_y2
= dst_y
+ h
;
457 int dst_x2
= dst_x
+ w
;
467 BR13
= dst_pitch
| (0xCC << 16) | (1<<24);
468 CMD
= XY_SRC_COPY_BLT_CMD
;
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
);
479 if (dst_y2
< dst_y
||
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
);
498 void intelClearWithBlit(GLcontext
*ctx
, GLbitfield flags
, GLboolean all
,
499 GLint cx1
, GLint cy1
, GLint cw
, GLint ch
)
501 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
502 intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
503 GLuint clear_depth
, clear_color
;
505 GLint pitch
= intelScreen
->frontPitch
;
506 GLint cpp
= intelScreen
->cpp
;
508 GLuint BR13
, CMD
, D_CMD
;
512 clear_color
= intel
->ClearColor
;
515 if (flags
& DD_DEPTH_BIT
) {
516 clear_depth
= (GLuint
)(ctx
->Depth
.Clear
* intel
->ClearDepth
);
519 if (flags
& DD_STENCIL_BIT
) {
520 clear_depth
|= (ctx
->Stencil
.Clear
& 0xff) << 24;
525 BR13
= (0xF0 << 16) | (pitch
* cpp
) | (1<<24);
526 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
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
& DD_DEPTH_BIT
) D_CMD
|= XY_COLOR_BLT_WRITE_RGB
;
535 if (flags
& DD_STENCIL_BIT
) D_CMD
|= XY_COLOR_BLT_WRITE_ALPHA
;
538 BR13
= (0xF0 << 16) | (pitch
* cpp
) | (1<<24);
539 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
543 intelFlush( &intel
->ctx
);
544 LOCK_HARDWARE( intel
);
546 /* flip top to bottom */
547 cy
= intel
->driDrawable
->h
-cy1
-ch
;
548 cx
= cx1
+ intel
->drawX
;
551 /* adjust for page flipping */
552 if ( intel
->sarea
->pf_current_page
== 1 ) {
555 flags
&= ~(DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
);
556 if ( tmp
& DD_FRONT_LEFT_BIT
) flags
|= DD_BACK_LEFT_BIT
;
557 if ( tmp
& DD_BACK_LEFT_BIT
) flags
|= DD_FRONT_LEFT_BIT
;
560 for (i
= 0 ; i
< intel
->numClipRects
; i
++)
562 drm_clip_rect_t
*box
= &intel
->pClipRects
[i
];
568 GLint w
= box
[i
].x2
- x
;
569 GLint h
= box
[i
].y2
- y
;
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;
589 b
.x2
> intelScreen
->width
||
590 b
.y2
> intelScreen
->height
)
593 if ( flags
& DD_FRONT_LEFT_BIT
) {
597 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
598 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
599 OUT_BATCH( intelScreen
->frontOffset
);
600 OUT_BATCH( clear_color
);
604 if ( flags
& DD_BACK_LEFT_BIT
) {
608 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
609 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
610 OUT_BATCH( intelScreen
->backOffset
);
611 OUT_BATCH( clear_color
);
615 if ( flags
& (DD_STENCIL_BIT
| DD_DEPTH_BIT
) ) {
619 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
620 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
621 OUT_BATCH( intelScreen
->depthOffset
);
622 OUT_BATCH( clear_depth
);
627 intelFlushBatchLocked( intel
, GL_TRUE
, GL_FALSE
, GL_TRUE
);
628 UNLOCK_HARDWARE( intel
);
634 void intelDestroyBatchBuffer( GLcontext
*ctx
)
636 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
638 if (intel
->alloc
.ptr
) {
639 intelFreeAGP( intel
, intel
->alloc
.ptr
);
640 intel
->alloc
.ptr
= 0;
645 void intelInitBatchBuffer( GLcontext
*ctx
)
647 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
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;
655 switch (intel
->intelScreen
->deviceID
) {
656 case PCI_CHIP_I865_G
:
657 /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
659 intel
->alloc
.size
= 8 * 1024;
662 /* This is the smallest amount of memory the kernel deals with.
663 * We'd ideally like to make this smaller.
665 intel
->alloc
.size
= 1 << intel
->intelScreen
->logTextureGranularity
;
669 intel
->alloc
.ptr
= intelAllocateAGP( intel
, intel
->alloc
.size
);
670 if (intel
->alloc
.ptr
)
671 intel
->alloc
.offset
=
672 intelAgpOffsetFromVirtual( intel
, intel
->alloc
.ptr
);
675 if (!intel
->alloc
.ptr
) {
676 FALLBACK(intel
, INTEL_FALLBACK_NO_BATCHBUFFER
, 1);
679 intel
->prim
.flush
= 0;
680 intel
->vtbl
.emit_invarient_state( intel
);
682 /* Make sure this gets to the hardware, even if we have no cliprects:
684 LOCK_HARDWARE( intel
);
685 intelFlushBatchLocked( intel
, GL_TRUE
, GL_FALSE
, GL_TRUE
);
686 UNLOCK_HARDWARE( intel
);