summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i915/intel_batchbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/i915/intel_batchbuffer.c')
-rw-r--r--src/mesa/drivers/dri/i915/intel_batchbuffer.c668
1 files changed, 668 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915/intel_batchbuffer.c b/src/mesa/drivers/dri/i915/intel_batchbuffer.c
new file mode 100644
index 0000000000..9146cbebd4
--- /dev/null
+++ b/src/mesa/drivers/dri/i915/intel_batchbuffer.c
@@ -0,0 +1,668 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ **************************************************************************/
+
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "mtypes.h"
+#include "context.h"
+#include "enums.h"
+
+#include "intel_reg.h"
+#include "intel_batchbuffer.h"
+#include "intel_context.h"
+
+
+
+
+/* ================================================================
+ * Performance monitoring functions
+ */
+
+static void intel_fill_box( intelContextPtr intel,
+ GLshort x, GLshort y,
+ GLshort w, GLshort h,
+ GLubyte r, GLubyte g, GLubyte b )
+{
+ intelEmitFillBlitLocked( intel,
+ intel->intelScreen->cpp,
+ intel->intelScreen->backPitch,
+ intel->intelScreen->frontOffset,
+ x, y, w, h,
+ INTEL_PACKCOLOR(intel->intelScreen->fbFormat,
+ r,g,b,0xff));
+}
+
+static void intel_draw_performance_boxes( intelContextPtr intel )
+{
+ /* Purple box for page flipping
+ */
+ if ( intel->perf_boxes & I830_BOX_FLIP )
+ intel_fill_box( intel, 4, 4, 8, 8, 255, 0, 255 );
+
+ /* Red box if we have to wait for idle at any point
+ */
+ if ( intel->perf_boxes & I830_BOX_WAIT )
+ intel_fill_box( intel, 16, 4, 8, 8, 255, 0, 0 );
+
+ /* Blue box: lost context?
+ */
+ if ( intel->perf_boxes & I830_BOX_LOST_CONTEXT )
+ intel_fill_box( intel, 28, 4, 8, 8, 0, 0, 255 );
+
+ /* Yellow box for texture swaps
+ */
+ if ( intel->perf_boxes & I830_BOX_TEXTURE_LOAD )
+ intel_fill_box( intel, 40, 4, 8, 8, 255, 255, 0 );
+
+ /* Green box if hardware never idles (as far as we can tell)
+ */
+ if ( !(intel->perf_boxes & I830_BOX_RING_EMPTY) )
+ intel_fill_box( intel, 64, 4, 8, 8, 0, 255, 0 );
+
+
+ /* Draw bars indicating number of buffers allocated
+ * (not a great measure, easily confused)
+ */
+#if 0
+ if (intel->dma_used) {
+ int bar = intel->dma_used / 10240;
+ if (bar > 100) bar = 100;
+ if (bar < 1) bar = 1;
+ intel_fill_box( intel, 4, 16, bar, 4, 196, 128, 128 );
+ intel->dma_used = 0;
+ }
+#endif
+
+ intel->perf_boxes = 0;
+}
+
+
+
+
+
+
+static int bad_prim_vertex_nr( int primitive, int nr )
+{
+ switch (primitive & PRIM3D_MASK) {
+ case PRIM3D_POINTLIST:
+ return nr < 1;
+ case PRIM3D_LINELIST:
+ return (nr & 1) || nr == 0;
+ case PRIM3D_LINESTRIP:
+ return nr < 2;
+ case PRIM3D_TRILIST:
+ case PRIM3D_RECTLIST:
+ return nr % 3 || nr == 0;
+ case PRIM3D_POLY:
+ case PRIM3D_TRIFAN:
+ case PRIM3D_TRISTRIP:
+ case PRIM3D_TRISTRIP_RVRSE:
+ return nr < 3;
+ default:
+ return 1;
+ }
+}
+
+static void intel_flush_inline_primitive( GLcontext *ctx )
+{
+ intelContextPtr intel = INTEL_CONTEXT( ctx );
+ GLuint used = intel->batch.ptr - intel->prim.start_ptr;
+ GLuint vertcount;
+
+ assert(intel->prim.primitive != ~0);
+
+ if (1) {
+ /* Check vertex size against the vertex we're specifying to
+ * hardware. If it's wrong, ditch the primitive.
+ */
+ if (!intel->vtbl.check_vertex_size( intel, intel->vertex_size ))
+ goto do_discard;
+
+ vertcount = (used - 4)/ (intel->vertex_size * 4);
+
+ if (!vertcount)
+ goto do_discard;
+
+ if (vertcount * intel->vertex_size * 4 != used - 4) {
+ fprintf(stderr, "vertex size confusion %d %d\n", used,
+ intel->vertex_size * vertcount * 4);
+ goto do_discard;
+ }
+
+ if (bad_prim_vertex_nr( intel->prim.primitive, vertcount )) {
+ fprintf(stderr, "bad_prim_vertex_nr %x %d\n", intel->prim.primitive,
+ vertcount);
+ goto do_discard;
+ }
+ }
+
+ if (used < 8)
+ goto do_discard;
+
+ *(int *)intel->prim.start_ptr = (_3DPRIMITIVE |
+ intel->prim.primitive |
+ (used/4-2));
+
+ goto finished;
+
+ do_discard:
+ intel->batch.ptr -= used;
+ intel->batch.space += used;
+ assert(intel->batch.space >= 0);
+
+ finished:
+ intel->prim.primitive = ~0;
+ intel->prim.start_ptr = 0;
+ intel->prim.flush = 0;
+}
+
+
+/* Emit a primitive referencing vertices in a vertex buffer.
+ */
+void intelStartInlinePrimitive( intelContextPtr intel, GLuint prim )
+{
+ BATCH_LOCALS;
+
+ if (0)
+ fprintf(stderr, "%s %x\n", __FUNCTION__, prim);
+
+
+ /* Finish any in-progress primitive:
+ */
+ INTEL_FIREVERTICES( intel );
+
+ /* Emit outstanding state:
+ */
+ intel->vtbl.emit_state( intel );
+
+ /* Make sure there is some space in this buffer:
+ */
+ if (intel->vertex_size * 10 * sizeof(GLuint) >= intel->batch.space)
+ intelFlushBatch(intel, GL_TRUE);
+
+
+#if 1
+ if (((int)intel->batch.ptr) & 0x4) {
+ BEGIN_BATCH(1);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+#endif
+
+ /* Emit a slot which will be filled with the inline primitive
+ * command later.
+ */
+ BEGIN_BATCH(2);
+ OUT_BATCH( 0 );
+
+ intel->prim.start_ptr = batch_ptr;
+ intel->prim.primitive = prim;
+ intel->prim.flush = intel_flush_inline_primitive;
+
+ OUT_BATCH( 0 );
+ ADVANCE_BATCH();
+}
+
+
+void intelRestartInlinePrimitive( intelContextPtr intel )
+{
+ GLuint prim = intel->prim.primitive;
+
+ intel_flush_inline_primitive( &intel->ctx );
+ if (1) intelFlushBatch(intel, GL_TRUE); /* GL_TRUE - is critical */
+ intelStartInlinePrimitive( intel, prim );
+}
+
+
+
+void intelWrapInlinePrimitive( intelContextPtr intel )
+{
+ GLuint prim = intel->prim.primitive;
+
+ if (0)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ intel_flush_inline_primitive( &intel->ctx );
+ intelFlushBatch(intel, GL_TRUE);
+ intelStartInlinePrimitive( intel, prim );
+}
+
+
+/* Emit a primitive with space for inline vertices.
+ */
+GLuint *intelEmitInlinePrimitiveLocked(intelContextPtr intel,
+ int primitive,
+ int dwords,
+ int vertex_size )
+{
+ GLuint *tmp = 0;
+ BATCH_LOCALS;
+
+ if (0)
+ fprintf(stderr, "%s 0x%x %d\n", __FUNCTION__, primitive, dwords);
+
+ /* Emit outstanding state:
+ */
+ intel->vtbl.emit_state( intel );
+
+
+ if (1) {
+ int used = dwords * 4;
+ int vertcount;
+
+ /* Check vertex size against the vertex we're specifying to
+ * hardware. If it's wrong, ditch the primitive.
+ */
+ if (!intel->vtbl.check_vertex_size( intel, vertex_size ))
+ goto do_discard;
+
+ vertcount = dwords / vertex_size;
+
+ if (dwords % vertex_size) {
+ fprintf(stderr, "did not request a whole number of vertices\n");
+ goto do_discard;
+ }
+
+ if (bad_prim_vertex_nr( primitive, vertcount )) {
+ fprintf(stderr, "bad_prim_vertex_nr %x %d\n", primitive, vertcount);
+ goto do_discard;
+ }
+
+ if (used < 8)
+ goto do_discard;
+ }
+
+ /* Emit 3D_PRIMITIVE commands:
+ */
+ BEGIN_BATCH(1 + dwords);
+ OUT_BATCH( _3DPRIMITIVE |
+ primitive |
+ (dwords-1) );
+
+ tmp = (GLuint *)batch_ptr;
+ batch_ptr += dwords * 4;
+
+ ADVANCE_BATCH();
+
+ do_discard:
+ return tmp;
+}
+
+
+
+/*
+ * Copy the back buffer to the front buffer.
+ */
+void intelCopyBuffer( const __DRIdrawablePrivate *dPriv )
+{
+ intelContextPtr intel;
+
+ if (0)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate;
+
+ intelFlush( &intel->ctx );
+ LOCK_HARDWARE( intel );
+ {
+ intelScreenPrivate *intelScreen = intel->intelScreen;
+ __DRIdrawablePrivate *dPriv = intel->driDrawable;
+ int nbox = dPriv->numClipRects;
+ drm_clip_rect_t *pbox = dPriv->pClipRects;
+ int pitch = intelScreen->frontPitch;
+ int cpp = intelScreen->cpp;
+ int i;
+ GLuint CMD, BR13;
+ BATCH_LOCALS;
+
+ switch(cpp) {
+ case 2:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ case 4:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
+ CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ break;
+ default:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ }
+
+ if (0)
+ intel_draw_performance_boxes( intel );
+
+ for (i = 0 ; i < nbox; i++, pbox++)
+ {
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > intelScreen->width ||
+ pbox->y2 > intelScreen->height)
+ continue;
+
+ BEGIN_BATCH( 8);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
+ OUT_BATCH( (pbox->y2 << 16) | pbox->x2 );
+
+ if (intel->sarea->pf_current_page == 0)
+ OUT_BATCH( intelScreen->frontOffset );
+ else
+ OUT_BATCH( intelScreen->backOffset );
+
+ OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
+ OUT_BATCH( BR13 & 0xffff );
+
+ if (intel->sarea->pf_current_page == 0)
+ OUT_BATCH( intelScreen->backOffset );
+ else
+ OUT_BATCH( intelScreen->frontOffset );
+
+ ADVANCE_BATCH();
+ }
+ }
+ intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE );
+ UNLOCK_HARDWARE( intel );
+}
+
+
+
+
+void intelEmitFillBlitLocked( intelContextPtr intel,
+ GLuint cpp,
+ GLshort dst_pitch,
+ GLuint dst_offset,
+ GLshort x, GLshort y,
+ GLshort w, GLshort h,
+ GLuint color )
+{
+ GLuint BR13, CMD;
+ BATCH_LOCALS;
+
+ dst_pitch *= cpp;
+
+ switch(cpp) {
+ case 1:
+ case 2:
+ case 3:
+ BR13 = dst_pitch | (0xF0 << 16) | (1<<24);
+ CMD = XY_COLOR_BLT_CMD;
+ break;
+ case 4:
+ BR13 = dst_pitch | (0xF0 << 16) | (1<<24) | (1<<25);
+ CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ break;
+ default:
+ return;
+ }
+
+ BEGIN_BATCH( 6);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (y << 16) | x );
+ OUT_BATCH( ((y+h) << 16) | (x+w) );
+ OUT_BATCH( dst_offset );
+ OUT_BATCH( color );
+ ADVANCE_BATCH();
+}
+
+
+/* Copy BitBlt
+ */
+void intelEmitCopyBlitLocked( intelContextPtr intel,
+ GLuint cpp,
+ GLshort src_pitch,
+ GLuint src_offset,
+ GLshort dst_pitch,
+ GLuint dst_offset,
+ GLshort src_x, GLshort src_y,
+ GLshort dst_x, GLshort dst_y,
+ GLshort w, GLshort h )
+{
+ GLuint CMD, BR13;
+ int dst_y2 = dst_y + h;
+ int dst_x2 = dst_x + w;
+ BATCH_LOCALS;
+
+ src_pitch *= cpp;
+ dst_pitch *= cpp;
+
+ switch(cpp) {
+ case 1:
+ case 2:
+ case 3:
+ BR13 = dst_pitch | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ case 4:
+ BR13 = dst_pitch | (0xCC << 16) | (1<<24) | (1<<25);
+ CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ break;
+ default:
+ return;
+ }
+
+ if (dst_y2 < dst_y ||
+ dst_x2 < dst_x) {
+ return;
+ }
+
+ BEGIN_BATCH( 12);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (dst_y << 16) | dst_x );
+ OUT_BATCH( (dst_y2 << 16) | dst_x2 );
+ OUT_BATCH( dst_offset );
+ OUT_BATCH( (src_y << 16) | src_x );
+ OUT_BATCH( src_pitch );
+ OUT_BATCH( src_offset );
+ ADVANCE_BATCH();
+}
+
+
+
+void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all,
+ GLint cx1, GLint cy1, GLint cw, GLint ch)
+{
+ intelContextPtr intel = INTEL_CONTEXT( ctx );
+ intelScreenPrivate *intelScreen = intel->intelScreen;
+ GLuint clear_depth, clear_color;
+ GLint cx, cy;
+ GLint pitch = intelScreen->frontPitch;
+ GLint cpp = intelScreen->cpp;
+ GLint i;
+ GLuint BR13, CMD, D_CMD;
+ BATCH_LOCALS;
+
+
+ clear_color = intel->ClearColor;
+ clear_depth = 0;
+
+ if (flags & DD_DEPTH_BIT) {
+ clear_depth = (GLuint)(ctx->Depth.Clear * intel->ClearDepth);
+ }
+
+ if (flags & DD_STENCIL_BIT) {
+ clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
+ }
+
+ switch(cpp) {
+ case 2:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+ D_CMD = CMD = XY_COLOR_BLT_CMD;
+ break;
+ case 4:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
+ CMD = (XY_COLOR_BLT_CMD |
+ XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ D_CMD = XY_COLOR_BLT_CMD;
+ if (flags & DD_DEPTH_BIT) D_CMD |= XY_COLOR_BLT_WRITE_RGB;
+ if (flags & DD_STENCIL_BIT) D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
+ break;
+ default:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+ D_CMD = CMD = XY_COLOR_BLT_CMD;
+ break;
+ }
+
+ intelFlush( &intel->ctx );
+ LOCK_HARDWARE( intel );
+ {
+ /* flip top to bottom */
+ cy = intel->driDrawable->h-cy1-ch;
+ cx = cx1 + intel->drawX;
+ cy += intel->drawY;
+
+ /* adjust for page flipping */
+ if ( intel->sarea->pf_current_page == 1 ) {
+ GLuint tmp = flags;
+
+ flags &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
+ if ( tmp & DD_FRONT_LEFT_BIT ) flags |= DD_BACK_LEFT_BIT;
+ if ( tmp & DD_BACK_LEFT_BIT ) flags |= DD_FRONT_LEFT_BIT;
+ }
+
+ for (i = 0 ; i < intel->numClipRects ; i++)
+ {
+ drm_clip_rect_t *box = &intel->pClipRects[i];
+ drm_clip_rect_t b;
+
+ if (!all) {
+ GLint x = box[i].x1;
+ GLint y = box[i].y1;
+ GLint w = box[i].x2 - x;
+ GLint h = box[i].y2 - y;
+
+ if (x < cx) w -= cx - x, x = cx;
+ if (y < cy) h -= cy - y, y = cy;
+ if (x + w > cx + cw) w = cx + cw - x;
+ if (y + h > cy + ch) h = cy + ch - y;
+ if (w <= 0) continue;
+ if (h <= 0) continue;
+
+ b.x1 = x;
+ b.y1 = y;
+ b.x2 = x + w;
+ b.y2 = y + h;
+ } else {
+ b = *box;
+ }
+
+
+ if (b.x1 > b.x2 ||
+ b.y1 > b.y2 ||
+ b.x2 > intelScreen->width ||
+ b.y2 > intelScreen->height)
+ continue;
+
+ if ( flags & DD_FRONT_LEFT_BIT ) {
+ BEGIN_BATCH( 6);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (b.y1 << 16) | b.x1 );
+ OUT_BATCH( (b.y2 << 16) | b.x2 );
+ OUT_BATCH( intelScreen->frontOffset );
+ OUT_BATCH( clear_color );
+ ADVANCE_BATCH();
+ }
+
+ if ( flags & DD_BACK_LEFT_BIT ) {
+ BEGIN_BATCH( 6);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (b.y1 << 16) | b.x1 );
+ OUT_BATCH( (b.y2 << 16) | b.x2 );
+ OUT_BATCH( intelScreen->backOffset );
+ OUT_BATCH( clear_color );
+ ADVANCE_BATCH();
+ }
+
+ if ( flags & (DD_STENCIL_BIT | DD_DEPTH_BIT) ) {
+ BEGIN_BATCH( 6);
+ OUT_BATCH( D_CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (b.y1 << 16) | b.x1 );
+ OUT_BATCH( (b.y2 << 16) | b.x2 );
+ OUT_BATCH( intelScreen->depthOffset );
+ OUT_BATCH( clear_depth );
+ ADVANCE_BATCH();
+ }
+ }
+ }
+ intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE );
+ UNLOCK_HARDWARE( intel );
+}
+
+
+
+
+void intelDestroyBatchBuffer( GLcontext *ctx )
+{
+ intelContextPtr intel = INTEL_CONTEXT(ctx);
+
+ if (intel->alloc.ptr) {
+ intelFreeAGP( intel, intel->alloc.ptr );
+ intel->alloc.ptr = 0;
+ }
+}
+
+
+void intelInitBatchBuffer( GLcontext *ctx )
+{
+ intelContextPtr intel = INTEL_CONTEXT(ctx);
+
+ if (!intel->intelScreen->allow_batchbuffer || getenv("INTEL_NO_BATCH")) {
+ intel->alloc.size = 8 * 1024;
+ intel->alloc.ptr = malloc( intel->alloc.size );
+ intel->alloc.offset = 0;
+ }
+ else {
+ switch (intel->intelScreen->deviceID) {
+ case PCI_CHIP_I865_G:
+ /* HW bug? Seems to crash if batchbuffer crosses 4k boundary.
+ */
+ intel->alloc.size = 8 * 1024;
+ break;
+ default:
+ /* This is the smallest amount of memory the kernel deals with.
+ * We'd ideally like to make this smaller.
+ */
+ intel->alloc.size = 1 << intel->intelScreen->logTextureGranularity;
+ break;
+ }
+
+ intel->alloc.ptr = intelAllocateAGP( intel, intel->alloc.size );
+ if (intel->alloc.ptr)
+ intel->alloc.offset =
+ intelAgpOffsetFromVirtual( intel, intel->alloc.ptr );
+ }
+
+ if (!intel->alloc.ptr) {
+ FALLBACK(intel, INTEL_FALLBACK_NO_BATCHBUFFER, 1);
+ }
+ else {
+ intel->prim.flush = 0;
+ intel->vtbl.emit_invarient_state( intel );
+
+ /* Make sure this gets to the hardware, even if we have no cliprects:
+ */
+ LOCK_HARDWARE( intel );
+ intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE );
+ UNLOCK_HARDWARE( intel );
+ }
+}