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 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 intelWaitForFrameCompletion( intel );
388 LOCK_HARDWARE( 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 intel->alloc.ptr = intelAllocateAGP( intel, intel->alloc.size );
766 if (intel->alloc.ptr)
767 intel->alloc.offset =
768 intelAgpOffsetFromVirtual( intel, intel->alloc.ptr );
770 intel->alloc.offset = 0; /* OK? */
773 /* The default is now to use a local buffer and pass that to the
774 * kernel. This is also a fallback if allocation fails on the
777 if (!intel->alloc.ptr) {
778 intel->alloc.size = 8 * 1024;
779 intel->alloc.ptr = malloc( intel->alloc.size );
780 intel->alloc.offset = 0;
783 assert(intel->alloc.ptr);