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 (((int)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 UNLOCK_HARDWARE( intel
);
345 intelWaitIrq( intel
, intel
->alloc
.irq_emitted
);
346 LOCK_HARDWARE( intel
);
348 intel
->irqsEmitted
= 10;
351 if (intel
->irqsEmitted
) {
352 intelEmitIrqLocked( intel
);
353 intel
->irqsEmitted
--;
357 while (intelGetLastFrame (intel
) < sarea
->last_dispatch
) {
358 UNLOCK_HARDWARE( intel
);
359 if (intel
->do_usleeps
)
361 LOCK_HARDWARE( intel
);
367 * Copy the back buffer to the front buffer.
369 void intelCopyBuffer( const __DRIdrawablePrivate
*dPriv
,
370 const drm_clip_rect_t
*rect
)
372 intelContextPtr intel
;
373 GLboolean missed_target
;
377 fprintf(stderr
, "%s\n", __FUNCTION__
);
380 assert(dPriv
->driContextPriv
);
381 assert(dPriv
->driContextPriv
->driverPrivate
);
383 intel
= (intelContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
385 intelFlush( &intel
->ctx
);
387 LOCK_HARDWARE( intel
);
388 intelWaitForFrameCompletion( intel
);
392 UNLOCK_HARDWARE( intel
);
393 driWaitForVBlank( dPriv
, &intel
->vbl_seq
, intel
->vblank_flags
, & missed_target
);
394 LOCK_HARDWARE( intel
);
397 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
398 const __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
399 const int nbox
= dPriv
->numClipRects
;
400 const drm_clip_rect_t
*pbox
= dPriv
->pClipRects
;
402 const int cpp
= intelScreen
->cpp
;
403 const int pitch
= intelScreen
->front
.pitch
; /* in bytes */
410 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
411 CMD
= XY_SRC_COPY_BLT_CMD
;
414 BR13
= (pitch
) | (0xCC << 16) | (1<<24) | (1<<25);
415 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
416 XY_SRC_COPY_BLT_WRITE_RGB
);
419 BR13
= (pitch
) | (0xCC << 16) | (1<<24);
420 CMD
= XY_SRC_COPY_BLT_CMD
;
425 intel_draw_performance_boxes( intel
);
427 for (i
= 0 ; i
< nbox
; i
++, pbox
++)
429 if (pbox
->x1
> pbox
->x2
||
430 pbox
->y1
> pbox
->y2
||
431 pbox
->x2
> intelScreen
->width
||
432 pbox
->y2
> intelScreen
->height
) {
433 _mesa_warning(&intel
->ctx
, "Bad cliprect in intelCopyBuffer()");
441 if (rect
->x1
> box
.x1
)
443 if (rect
->y1
> box
.y1
)
445 if (rect
->x2
< box
.x2
)
447 if (rect
->y2
< box
.y2
)
450 if (box
.x1
> box
.x2
|| box
.y1
> box
.y2
)
457 OUT_BATCH( (box
.y1
<< 16) | box
.x1
);
458 OUT_BATCH( (box
.y2
<< 16) | box
.x2
);
460 if (intel
->sarea
->pf_current_page
== 0)
461 OUT_BATCH( intelScreen
->front
.offset
);
463 OUT_BATCH( intelScreen
->back
.offset
);
465 OUT_BATCH( (box
.y1
<< 16) | box
.x1
);
466 OUT_BATCH( BR13
& 0xffff );
468 if (intel
->sarea
->pf_current_page
== 0)
469 OUT_BATCH( intelScreen
->back
.offset
);
471 OUT_BATCH( intelScreen
->front
.offset
);
476 intelFlushBatchLocked( intel
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
477 UNLOCK_HARDWARE( intel
);
482 (*dri_interface
->getUST
)(&ust
);
484 intel
->swap_missed_count
++;
485 intel
->swap_missed_ust
= ust
- intel
->swap_ust
;
488 intel
->swap_ust
= ust
;
495 void intelEmitFillBlitLocked( intelContextPtr intel
,
497 GLshort dst_pitch
, /* in bytes */
499 GLshort x
, GLshort y
,
500 GLshort w
, GLshort h
,
510 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24);
511 CMD
= XY_COLOR_BLT_CMD
;
514 BR13
= dst_pitch
| (0xF0 << 16) | (1<<24) | (1<<25);
515 CMD
= (XY_COLOR_BLT_CMD
| XY_COLOR_BLT_WRITE_ALPHA
|
516 XY_COLOR_BLT_WRITE_RGB
);
525 OUT_BATCH( (y
<< 16) | x
);
526 OUT_BATCH( ((y
+h
) << 16) | (x
+w
) );
527 OUT_BATCH( dst_offset
);
535 void intelEmitCopyBlitLocked( intelContextPtr intel
,
541 GLshort src_x
, GLshort src_y
,
542 GLshort dst_x
, GLshort dst_y
,
543 GLshort w
, GLshort h
)
546 int dst_y2
= dst_y
+ h
;
547 int dst_x2
= dst_x
+ w
;
557 BR13
= dst_pitch
| (0xCC << 16) | (1<<24);
558 CMD
= XY_SRC_COPY_BLT_CMD
;
561 BR13
= dst_pitch
| (0xCC << 16) | (1<<24) | (1<<25);
562 CMD
= (XY_SRC_COPY_BLT_CMD
| XY_SRC_COPY_BLT_WRITE_ALPHA
|
563 XY_SRC_COPY_BLT_WRITE_RGB
);
569 if (dst_y2
< dst_y
||
577 OUT_BATCH( (dst_y
<< 16) | dst_x
);
578 OUT_BATCH( (dst_y2
<< 16) | dst_x2
);
579 OUT_BATCH( dst_offset
);
580 OUT_BATCH( (src_y
<< 16) | src_x
);
581 OUT_BATCH( src_pitch
);
582 OUT_BATCH( src_offset
);
588 void intelClearWithBlit(GLcontext
*ctx
, GLbitfield flags
, GLboolean all
,
589 GLint cx1
, GLint cy1
, GLint cw
, GLint ch
)
591 intelContextPtr intel
= INTEL_CONTEXT( ctx
);
592 intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
593 GLuint clear_depth
, clear_color
;
596 GLint cpp
= intelScreen
->cpp
;
598 GLuint BR13
, CMD
, D_CMD
;
601 intelFlush( &intel
->ctx
);
602 LOCK_HARDWARE( intel
);
604 pitch
= intelScreen
->front
.pitch
;
606 clear_color
= intel
->ClearColor
;
609 if (flags
& BUFFER_BIT_DEPTH
) {
610 clear_depth
= (GLuint
)(ctx
->Depth
.Clear
* intel
->ClearDepth
);
613 if (flags
& BUFFER_BIT_STENCIL
) {
614 clear_depth
|= (ctx
->Stencil
.Clear
& 0xff) << 24;
619 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
620 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
623 BR13
= (0xF0 << 16) | (pitch
) | (1<<24) | (1<<25);
624 CMD
= (XY_COLOR_BLT_CMD
|
625 XY_COLOR_BLT_WRITE_ALPHA
|
626 XY_COLOR_BLT_WRITE_RGB
);
627 D_CMD
= XY_COLOR_BLT_CMD
;
628 if (flags
& BUFFER_BIT_DEPTH
) D_CMD
|= XY_COLOR_BLT_WRITE_RGB
;
629 if (flags
& BUFFER_BIT_STENCIL
) D_CMD
|= XY_COLOR_BLT_WRITE_ALPHA
;
632 BR13
= (0xF0 << 16) | (pitch
) | (1<<24);
633 D_CMD
= CMD
= XY_COLOR_BLT_CMD
;
638 /* flip top to bottom */
639 cy
= intel
->driDrawable
->h
-cy1
-ch
;
640 cx
= cx1
+ intel
->drawX
;
643 /* adjust for page flipping */
644 if ( intel
->sarea
->pf_current_page
== 1 ) {
647 flags
&= ~(BUFFER_BIT_FRONT_LEFT
| BUFFER_BIT_BACK_LEFT
);
648 if ( tmp
& BUFFER_BIT_FRONT_LEFT
) flags
|= BUFFER_BIT_BACK_LEFT
;
649 if ( tmp
& BUFFER_BIT_BACK_LEFT
) flags
|= BUFFER_BIT_FRONT_LEFT
;
652 for (i
= 0 ; i
< intel
->numClipRects
; i
++)
654 drm_clip_rect_t
*box
= &intel
->pClipRects
[i
];
660 GLint w
= box
->x2
- x
;
661 GLint h
= box
->y2
- y
;
663 if (x
< cx
) w
-= cx
- x
, x
= cx
;
664 if (y
< cy
) h
-= cy
- y
, y
= cy
;
665 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
666 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
667 if (w
<= 0) continue;
668 if (h
<= 0) continue;
681 b
.x2
> intelScreen
->width
||
682 b
.y2
> intelScreen
->height
)
685 if ( flags
& BUFFER_BIT_FRONT_LEFT
) {
689 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
690 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
691 OUT_BATCH( intelScreen
->front
.offset
);
692 OUT_BATCH( clear_color
);
696 if ( flags
& BUFFER_BIT_BACK_LEFT
) {
700 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
701 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
702 OUT_BATCH( intelScreen
->back
.offset
);
703 OUT_BATCH( clear_color
);
707 if ( flags
& (BUFFER_BIT_STENCIL
| BUFFER_BIT_DEPTH
) ) {
711 OUT_BATCH( (b
.y1
<< 16) | b
.x1
);
712 OUT_BATCH( (b
.y2
<< 16) | b
.x2
);
713 OUT_BATCH( intelScreen
->depth
.offset
);
714 OUT_BATCH( clear_depth
);
719 intelFlushBatchLocked( intel
, GL_TRUE
, GL_FALSE
, GL_TRUE
);
720 UNLOCK_HARDWARE( intel
);
726 void intelDestroyBatchBuffer( GLcontext
*ctx
)
728 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
730 if (intel
->alloc
.offset
) {
731 intelFreeAGP( intel
, intel
->alloc
.ptr
);
732 intel
->alloc
.ptr
= NULL
;
733 intel
->alloc
.offset
= 0;
735 else if (intel
->alloc
.ptr
) {
736 free(intel
->alloc
.ptr
);
737 intel
->alloc
.ptr
= NULL
;
740 memset(&intel
->batch
, 0, sizeof(intel
->batch
));
744 void intelInitBatchBuffer( GLcontext
*ctx
)
746 intelContextPtr intel
= INTEL_CONTEXT(ctx
);
748 /* This path isn't really safe with rotate:
750 if (getenv("INTEL_BATCH") && intel
->intelScreen
->allow_batchbuffer
) {
751 switch (intel
->intelScreen
->deviceID
) {
752 case PCI_CHIP_I865_G
:
753 /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
755 intel
->alloc
.size
= 8 * 1024;
758 /* This is the smallest amount of memory the kernel deals with.
759 * We'd ideally like to make this smaller.
761 intel
->alloc
.size
= 1 << intel
->intelScreen
->logTextureGranularity
;
765 /* KW: temporary - this make crashes & lockups more frequent, so
766 * leave in until they are solved.
768 intel
->alloc
.size
= 8 * 1024;
770 intel
->alloc
.ptr
= intelAllocateAGP( intel
, intel
->alloc
.size
);
771 if (intel
->alloc
.ptr
)
772 intel
->alloc
.offset
=
773 intelAgpOffsetFromVirtual( intel
, intel
->alloc
.ptr
);
775 intel
->alloc
.offset
= 0; /* OK? */
778 /* The default is now to use a local buffer and pass that to the
779 * kernel. This is also a fallback if allocation fails on the
782 if (!intel
->alloc
.ptr
) {
783 intel
->alloc
.size
= 8 * 1024;
784 intel
->alloc
.ptr
= malloc( intel
->alloc
.size
);
785 intel
->alloc
.offset
= 0;
788 assert(intel
->alloc
.ptr
);