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 **************************************************************************/
37 #include "intel_reg.h"
38 #include "intel_batchbuffer.h"
39 #include "intel_context.h"
44 /* ================================================================
45 * Performance monitoring functions
48 static void intel_fill_box( intelContextPtr intel
,
51 GLubyte r
, GLubyte g
, GLubyte b
)
56 if (x
>= 0 && y
>= 0 &&
57 x
+w
< intel
->intelScreen
->width
&&
58 y
+h
< intel
->intelScreen
->height
)
59 intelEmitFillBlitLocked( intel
,
60 intel
->intelScreen
->cpp
,
61 intel
->intelScreen
->back
.pitch
,
62 intel
->intelScreen
->back
.offset
,
64 INTEL_PACKCOLOR(intel
->intelScreen
->fbFormat
,
68 static void intel_draw_performance_boxes( intelContextPtr intel
)
70 /* Purple box for page flipping
72 if ( intel
->perf_boxes
& I830_BOX_FLIP
)
73 intel_fill_box( intel
, 4, 4, 8, 8, 255, 0, 255 );
75 /* Red box if we have to wait for idle at any point
77 if ( intel
->perf_boxes
& I830_BOX_WAIT
)
78 intel_fill_box( intel
, 16, 4, 8, 8, 255, 0, 0 );
80 /* Blue box: lost context?
82 if ( intel
->perf_boxes
& I830_BOX_LOST_CONTEXT
)
83 intel_fill_box( intel
, 28, 4, 8, 8, 0, 0, 255 );
85 /* Yellow box for texture swaps
87 if ( intel
->perf_boxes
& I830_BOX_TEXTURE_LOAD
)
88 intel_fill_box( intel
, 40, 4, 8, 8, 255, 255, 0 );
90 /* Green box if hardware never idles (as far as we can tell)
92 if ( !(intel
->perf_boxes
& I830_BOX_RING_EMPTY
) )
93 intel_fill_box( intel
, 64, 4, 8, 8, 0, 255, 0 );
96 /* Draw bars indicating number of buffers allocated
97 * (not a great measure, easily confused)
100 if (intel
->dma_used
) {
101 int bar
= intel
->dma_used
/ 10240;
102 if (bar
> 100) bar
= 100;
103 if (bar
< 1) bar
= 1;
104 intel_fill_box( intel
, 4, 16, bar
, 4, 196, 128, 128 );
109 intel
->perf_boxes
= 0;
117 static int bad_prim_vertex_nr( int primitive
, int nr
)
119 switch (primitive
& PRIM3D_MASK
) {
120 case PRIM3D_POINTLIST
:
122 case PRIM3D_LINELIST
:
123 return (nr
& 1) || nr
== 0;
124 case PRIM3D_LINESTRIP
:
127 case PRIM3D_RECTLIST
:
128 return nr
% 3 || nr
== 0;
131 case PRIM3D_TRISTRIP
:
132 case PRIM3D_TRISTRIP_RVRSE
:
139 static void intel_flush_inline_primitive( GLcontext
*ctx
)
141 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
142 GLuint used
= intel
->batch
.ptr
- intel
->prim
.start_ptr
;
145 assert(intel
->prim
.primitive
!= ~0);
148 /* Check vertex size against the vertex we're specifying to
149 * hardware. If it's wrong, ditch the primitive.
151 if (!intel
->vtbl
.check_vertex_size( intel
, intel
->vertex_size
))
154 vertcount
= (used
- 4)/ (intel
->vertex_size
* 4);
159 if (vertcount
* intel
->vertex_size
* 4 != used
- 4) {
160 fprintf(stderr
, "vertex size confusion %d %d\n", used
,
161 intel
->vertex_size
* vertcount
* 4);
165 if (bad_prim_vertex_nr( intel
->prim
.primitive
, vertcount
)) {
166 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", intel
->prim
.primitive
,
175 *(int *)intel
->prim
.start_ptr
= (_3DPRIMITIVE
|
176 intel
->prim
.primitive
|
182 intel
->batch
.ptr
-= used
;
183 intel
->batch
.space
+= used
;
184 assert(intel
->batch
.space
>= 0);
187 intel
->prim
.primitive
= ~0;
188 intel
->prim
.start_ptr
= 0;
189 intel
->prim
.flush
= 0;
193 /* Emit a primitive referencing vertices in a vertex buffer.
195 void intelStartInlinePrimitive( intelContextPtr intel
, GLuint prim
)
200 fprintf(stderr
, "%s %x\n", __FUNCTION__
, prim
);
203 /* Finish any in-progress primitive:
205 INTEL_FIREVERTICES( intel
);
207 /* Emit outstanding state:
209 intel
->vtbl
.emit_state( intel
);
211 /* Make sure there is some space in this buffer:
213 if (intel
->vertex_size
* 10 * sizeof(GLuint
) >= intel
->batch
.space
) {
214 intelFlushBatch(intel
, GL_TRUE
);
215 intel
->vtbl
.emit_state( intel
);
219 if (((unsigned long)intel
->batch
.ptr
) & 0x4) {
226 /* Emit a slot which will be filled with the inline primitive
232 intel
->prim
.start_ptr
= batch_ptr
;
233 intel
->prim
.primitive
= prim
;
234 intel
->prim
.flush
= intel_flush_inline_primitive
;
235 intel
->batch
.contains_geometry
= 1;
242 void intelRestartInlinePrimitive( intelContextPtr intel
)
244 GLuint prim
= intel
->prim
.primitive
;
246 intel_flush_inline_primitive( &intel
->ctx
);
247 if (1) intelFlushBatch(intel
, GL_TRUE
); /* GL_TRUE - is critical */
248 intelStartInlinePrimitive( intel
, prim
);
253 void intelWrapInlinePrimitive( intelContextPtr intel
)
255 GLuint prim
= intel
->prim
.primitive
;
258 fprintf(stderr
, "%s\n", __FUNCTION__
);
259 intel_flush_inline_primitive( &intel
->ctx
);
260 intelFlushBatch(intel
, GL_TRUE
);
261 intelStartInlinePrimitive( intel
, prim
);
265 /* Emit a primitive with space for inline vertices.
267 GLuint
*intelEmitInlinePrimitiveLocked(intelContextPtr intel
,
276 fprintf(stderr
, "%s 0x%x %d\n", __FUNCTION__
, primitive
, dwords
);
278 /* Emit outstanding state:
280 intel
->vtbl
.emit_state( intel
);
282 if ((1+dwords
)*4 >= intel
->batch
.space
) {
283 intelFlushBatch(intel
, GL_TRUE
);
284 intel
->vtbl
.emit_state( intel
);
289 int used
= dwords
* 4;
292 /* Check vertex size against the vertex we're specifying to
293 * hardware. If it's wrong, ditch the primitive.
295 if (!intel
->vtbl
.check_vertex_size( intel
, vertex_size
))
298 vertcount
= dwords
/ vertex_size
;
300 if (dwords
% vertex_size
) {
301 fprintf(stderr
, "did not request a whole number of vertices\n");
305 if (bad_prim_vertex_nr( primitive
, vertcount
)) {
306 fprintf(stderr
, "bad_prim_vertex_nr %x %d\n", primitive
, vertcount
);
314 /* Emit 3D_PRIMITIVE commands:
316 BEGIN_BATCH(1 + dwords
);
317 OUT_BATCH( _3DPRIMITIVE
|
321 tmp
= (GLuint
*)batch_ptr
;
322 batch_ptr
+= dwords
* 4;
326 intel
->batch
.contains_geometry
= 1;
333 static void intelWaitForFrameCompletion( intelContextPtr intel
)
335 drm_i915_sarea_t
*sarea
= (drm_i915_sarea_t
*)intel
->sarea
;
337 if (intel
->do_irqs
) {
338 if (intelGetLastFrame(intel
) < sarea
->last_dispatch
) {
339 if (!intel
->irqsEmitted
) {
340 while (intelGetLastFrame (intel
) < sarea
->last_dispatch
)
344 intelWaitIrq( intel
, intel
->alloc
.irq_emitted
);
346 intel
->irqsEmitted
= 10;
349 if (intel
->irqsEmitted
) {
350 LOCK_HARDWARE( intel
);
351 intelEmitIrqLocked( intel
);
352 intel
->irqsEmitted
--;
353 UNLOCK_HARDWARE( intel
);
357 while (intelGetLastFrame (intel
) < sarea
->last_dispatch
) {
358 if (intel
->do_usleeps
)
365 * Copy the back buffer to the front buffer.
367 void intelCopyBuffer( const __DRIdrawablePrivate
*dPriv
,
368 const drm_clip_rect_t
*rect
)
370 intelContextPtr intel
;
371 const intelScreenPrivate
*intelScreen
;
372 GLboolean missed_target
;
376 fprintf(stderr
, "%s\n", __FUNCTION__
);
379 assert(dPriv
->driContextPriv
);
380 assert(dPriv
->driContextPriv
->driverPrivate
);
382 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
384 intelFlush( &intel
->ctx
);
386 intelScreen
= intel
->intelScreen
;
388 if (!rect
&& !intel
->swap_scheduled
&& intelScreen
->drmMinor
>= 6 &&
389 !(intel
->vblank_flags
& VBLANK_FLAG_NO_IRQ
) &&
390 intelScreen
->current_rotation
== 0) {
391 unsigned int interval
= driGetVBlankInterval(dPriv
, intel
->vblank_flags
);
393 drm_i915_vblank_swap_t swap
;
395 swap
.drawable
= dPriv
->hHWDrawable
;
396 swap
.seqtype
= DRM_VBLANK_ABSOLUTE
;
397 target
= swap
.sequence
= intel
->vbl_seq
+ interval
;
399 if (intel
->vblank_flags
& VBLANK_FLAG_SYNC
) {
400 swap
.seqtype
|= DRM_VBLANK_NEXTONMISS
;
401 } else if (interval
== 0) {
405 if ( intel
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
406 swap
.seqtype
|= DRM_VBLANK_SECONDARY
;
409 if (!drmCommandWriteRead(intel
->driFd
, DRM_I915_VBLANK_SWAP
, &swap
,
411 intel
->swap_scheduled
= 1;
412 intel
->vbl_seq
= swap
.sequence
;
413 swap
.sequence
-= target
;
414 missed_target
= swap
.sequence
> 0 && swap
.sequence
<= (1 << 23);
417 intel
->swap_scheduled
= 0;
421 if (!intel
->swap_scheduled
) {
422 intelWaitForFrameCompletion( intel
);
423 LOCK_HARDWARE( intel
);
427 UNLOCK_HARDWARE( intel
);
428 driWaitForVBlank( dPriv
, &intel
->vbl_seq
, intel
->vblank_flags
, & missed_target
);
429 LOCK_HARDWARE( intel
);
432 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
433 const __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
434 const int nbox
= dPriv
->numClipRects
;
435 const drm_clip_rect_t
*pbox
= dPriv
->pClipRects
;
437 const int cpp
= intelScreen
->cpp
;
438 const int pitch
= intelScreen
->front
.pitch
; /* in bytes */
445 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
446 CMD
= XY_SRC_COPY_BLT_CMD
;
449 BR13
= (pitch
) | (0xCC << 16) | (1<<24) | (1<<25);
450 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
451 XY_SRC_COPY_BLT_WRITE_RGB
);
454 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
455 CMD
= XY_SRC_COPY_BLT_CMD
;
460 intel_draw_performance_boxes( intel
);
462 for (i
= 0 ; i
< nbox
; i
++, pbox
++)
464 if (pbox
->x1
> pbox
->x2
||
465 pbox
->y1
> pbox
->y2
||
466 pbox
->x2
> intelScreen
->width
||
467 pbox
->y2
> intelScreen
->height
) {
468 _mesa_warning(&intel
->ctx
, "Bad cliprect in intelCopyBuffer()");
476 if (rect
->x1
> box
.x1
)
478 if (rect
->y1
> box
.y1
)
480 if (rect
->x2
< box
.x2
)
482 if (rect
->y2
< box
.y2
)
485 if (box
.x1
> box
.x2
|| box
.y1
> box
.y2
)
492 OUT_BATCH( (box
.y1
<< 16) | box
.x1
);
493 OUT_BATCH( (box
.y2
<< 16) | box
.x2
);
495 if (intel
->sarea
->pf_current_page
== 0)
496 OUT_BATCH( intelScreen
->front
.offset
);
498 OUT_BATCH( intelScreen
->back
.offset
);
500 OUT_BATCH( (box
.y1
<< 16) | box
.x1
);
501 OUT_BATCH( BR13
& 0xffff );
503 if (intel
->sarea
->pf_current_page
== 0)
504 OUT_BATCH( intelScreen
->back
.offset
);
506 OUT_BATCH( intelScreen
->front
.offset
);
511 intelFlushBatchLocked( intel
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
512 UNLOCK_HARDWARE( intel
);
518 (*dri_interface
->getUST
)(&ust
);
520 intel
->swap_missed_count
++;
521 intel
->swap_missed_ust
= ust
- intel
->swap_ust
;
524 intel
->swap_ust
= ust
;
531 void intelEmitFillBlitLocked( intelContextPtr intel
,
533 GLshort dst_pitch
, /* in bytes */
535 GLshort x
, GLshort y
,
536 GLshort w
, GLshort h
,
546 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24);
547 CMD
= XY_COLOR_BLT_CMD
;
550 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24) | (1<<25);
551 CMD
= (XY_COLOR_BLT_CMD
| XY_COLOR_BLT_WRITE_ALPHA
|
552 XY_COLOR_BLT_WRITE_RGB
);
561 OUT_BATCH( (y
<< 16) | x
);
562 OUT_BATCH( ((y
+h
) << 16) | (x
+w
) );
563 OUT_BATCH( dst_offset
);
571 void intelEmitCopyBlitLocked( intelContextPtr intel
,
577 GLshort src_x
, GLshort src_y
,
578 GLshort dst_x
, GLshort dst_y
,
579 GLshort w
, GLshort h
)
582 int dst_y2
= dst_y
+ h
;
583 int dst_x2
= dst_x
+ w
;
593 BR13
= dst_pitch
| (0xCC << 16) | (1<<24);
594 CMD
= XY_SRC_COPY_BLT_CMD
;
597 BR13
= dst_pitch
| (0xCC << 16) | (1<<24) | (1<<25);
598 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
599 XY_SRC_COPY_BLT_WRITE_RGB
);
605 if (dst_y2
< dst_y
||
613 OUT_BATCH( (dst_y
<< 16) | dst_x
);
614 OUT_BATCH( (dst_y2
<< 16) | dst_x2
);
615 OUT_BATCH( dst_offset
);
616 OUT_BATCH( (src_y
<< 16) | src_x
);
617 OUT_BATCH( src_pitch
);
618 OUT_BATCH( src_offset
);
624 void intelClearWithBlit(GLcontext
*ctx
, GLbitfield flags
, GLboolean all
,
625 GLint cx1
, GLint cy1
, GLint cw
, GLint ch
)
627 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
628 intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
629 GLuint clear_depth
, clear_color
;
632 GLint cpp
= intelScreen
->cpp
;
634 GLuint BR13
, CMD
, D_CMD
;
637 intelFlush( &intel
->ctx
);
638 LOCK_HARDWARE( intel
);
640 pitch
= intelScreen
->front
.pitch
;
642 clear_color
= intel
->ClearColor
;
645 if (flags
& BUFFER_BIT_DEPTH
) {
646 clear_depth
= (GLuint
)(ctx
->Depth
.Clear
* intel
->ClearDepth
);
649 if (flags
& BUFFER_BIT_STENCIL
) {
650 clear_depth
|= (ctx
->Stencil
.Clear
& 0xff) << 24;
655 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
656 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
659 BR13
= (0xF0 << 16) | (pitch
) | (1<<24) | (1<<25);
660 CMD
= (XY_COLOR_BLT_CMD
|
661 XY_COLOR_BLT_WRITE_ALPHA
|
662 XY_COLOR_BLT_WRITE_RGB
);
663 D_CMD
= XY_COLOR_BLT_CMD
;
664 if (flags
& BUFFER_BIT_DEPTH
) D_CMD
|= XY_COLOR_BLT_WRITE_RGB
;
665 if (flags
& BUFFER_BIT_STENCIL
) D_CMD
|= XY_COLOR_BLT_WRITE_ALPHA
;
668 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
669 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
674 /* flip top to bottom */
675 cy
= intel
->driDrawable
->h
-cy1
-ch
;
676 cx
= cx1
+ intel
->drawX
;
679 /* adjust for page flipping */
680 if ( intel
->sarea
->pf_current_page
== 1 ) {
683 flags
&= ~(BUFFER_BIT_FRONT_LEFT
| BUFFER_BIT_BACK_LEFT
);
684 if ( tmp
& BUFFER_BIT_FRONT_LEFT
) flags
|= BUFFER_BIT_BACK_LEFT
;
685 if ( tmp
& BUFFER_BIT_BACK_LEFT
) flags
|= BUFFER_BIT_FRONT_LEFT
;
688 for (i
= 0 ; i
< intel
->numClipRects
; i
++)
690 drm_clip_rect_t
*box
= &intel
->pClipRects
[i
];
696 GLint w
= box
->x2
- x
;
697 GLint h
= box
->y2
- y
;
699 if (x
< cx
) w
-= cx
- x
, x
= cx
;
700 if (y
< cy
) h
-= cy
- y
, y
= cy
;
701 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
702 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
703 if (w
<= 0) continue;
704 if (h
<= 0) continue;
717 b
.x2
> intelScreen
->width
||
718 b
.y2
> intelScreen
->height
)
721 if ( flags
& BUFFER_BIT_FRONT_LEFT
) {
725 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
726 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
727 OUT_BATCH( intelScreen
->front
.offset
);
728 OUT_BATCH( clear_color
);
732 if ( flags
& BUFFER_BIT_BACK_LEFT
) {
736 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
737 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
738 OUT_BATCH( intelScreen
->back
.offset
);
739 OUT_BATCH( clear_color
);
743 if ( flags
& (BUFFER_BIT_STENCIL
| BUFFER_BIT_DEPTH
) ) {
747 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
748 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
749 OUT_BATCH( intelScreen
->depth
.offset
);
750 OUT_BATCH( clear_depth
);
755 intelFlushBatchLocked( intel
, GL_TRUE
, GL_FALSE
, GL_TRUE
);
756 UNLOCK_HARDWARE( intel
);
762 void intelDestroyBatchBuffer( GLcontext
*ctx
)
764 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
766 if (intel
->alloc
.offset
) {
767 intelFreeAGP( intel
, intel
->alloc
.ptr
);
768 intel
->alloc
.ptr
= NULL
;
769 intel
->alloc
.offset
= 0;
771 else if (intel
->alloc
.ptr
) {
772 free(intel
->alloc
.ptr
);
773 intel
->alloc
.ptr
= NULL
;
776 memset(&intel
->batch
, 0, sizeof(intel
->batch
));
780 void intelInitBatchBuffer( GLcontext
*ctx
)
782 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
784 /* This path isn't really safe with rotate:
786 if (getenv("INTEL_BATCH") && intel
->intelScreen
->allow_batchbuffer
) {
787 switch (intel
->intelScreen
->deviceID
) {
788 case PCI_CHIP_I865_G
:
789 /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
791 intel
->alloc
.size
= 8 * 1024;
794 /* This is the smallest amount of memory the kernel deals with.
795 * We'd ideally like to make this smaller.
797 intel
->alloc
.size
= 1 << intel
->intelScreen
->logTextureGranularity
;
801 intel
->alloc
.ptr
= intelAllocateAGP( intel
, intel
->alloc
.size
);
802 if (intel
->alloc
.ptr
)
803 intel
->alloc
.offset
=
804 intelAgpOffsetFromVirtual( intel
, intel
->alloc
.ptr
);
806 intel
->alloc
.offset
= 0; /* OK? */
809 /* The default is now to use a local buffer and pass that to the
810 * kernel. This is also a fallback if allocation fails on the
813 if (!intel
->alloc
.ptr
) {
814 intel
->alloc
.size
= 8 * 1024;
815 intel
->alloc
.ptr
= malloc( intel
->alloc
.size
);
816 intel
->alloc
.offset
= 0;
819 assert(intel
->alloc
.ptr
);