patch-2.4.8 linux/drivers/char/drm/radeon_state.c

Next file: linux/drivers/char/drm/tdfx.h
Previous file: linux/drivers/char/drm/radeon_drv.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.7/linux/drivers/char/drm/radeon_state.c linux/drivers/char/drm/radeon_state.c
@@ -23,12 +23,12 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *    Kevin E. Martin <martin@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
- *
+ *    Kevin E. Martin <martin@valinux.com>
  */
 
 #define __NO_VERSION__
+#include "radeon.h"
 #include "drmP.h"
 #include "radeon_drv.h"
 #include "drm.h"
@@ -486,7 +486,8 @@
 }
 
 static void radeon_cp_dispatch_clear( drm_device_t *dev,
-				      drm_radeon_clear_t *clear )
+				      drm_radeon_clear_t *clear,
+				      drm_radeon_clear_rect_t *depth_boxes )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
@@ -497,8 +498,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 	if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) {
 		unsigned int tmp = flags;
 
@@ -525,7 +524,7 @@
 			RADEON_WAIT_UNTIL_3D_IDLE();
 
 			OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) );
-			OUT_RING( sarea_priv->context_state.rb3d_planemask );
+			OUT_RING( clear->color_mask );
 
 			ADVANCE_RING();
 
@@ -609,17 +608,17 @@
 				   RADEON_VTX_FMT_RADEON_MODE |
 				   (3 << RADEON_NUM_VERTICES_SHIFT)) );
 
-			OUT_RING( clear->rect.ui[CLEAR_X1] );
-			OUT_RING( clear->rect.ui[CLEAR_Y1] );
-			OUT_RING( clear->rect.ui[CLEAR_DEPTH] );
-
-			OUT_RING( clear->rect.ui[CLEAR_X1] );
-			OUT_RING( clear->rect.ui[CLEAR_Y2] );
-			OUT_RING( clear->rect.ui[CLEAR_DEPTH] );
-
-			OUT_RING( clear->rect.ui[CLEAR_X2] );
-			OUT_RING( clear->rect.ui[CLEAR_Y2] );
-			OUT_RING( clear->rect.ui[CLEAR_DEPTH] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+
+			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+
+			OUT_RING( depth_boxes[i].ui[CLEAR_X2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
 
 			ADVANCE_RING();
 
@@ -655,8 +654,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 #if RADEON_PERFORMANCE_BOXES
 	/* Do some trivial performance monitoring...
 	 */
@@ -724,8 +721,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "%s: page=%d\n", __FUNCTION__, dev_priv->current_page );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 #if RADEON_PERFORMANCE_BOXES
 	/* Do some trivial performance monitoring...
 	 */
@@ -776,8 +771,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "%s: nbox=%d\n", __FUNCTION__, sarea_priv->nbox );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 	if ( 0 )
 		radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty );
 
@@ -844,8 +837,6 @@
 	DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n",
 		   buf->idx, start, end );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 	if ( start != end ) {
 		int offset = (dev_priv->agp_buffers_offset
 			      + buf->offset + start);
@@ -908,8 +899,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 	if ( 0 )
 		radeon_print_dirty( "dispatch_indices", sarea_priv->dirty );
 
@@ -971,50 +960,67 @@
 	sarea_priv->nbox = 0;
 }
 
-static int radeon_cp_dispatch_blit( drm_device_t *dev,
-				    drm_radeon_blit_t *blit )
+#define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
+
+static int radeon_cp_dispatch_texture( drm_device_t *dev,
+				       drm_radeon_texture_t *tex,
+				       drm_radeon_tex_image_t *image )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
 	drm_radeon_buf_priv_t *buf_priv;
 	u32 format;
-	u32 *data;
-	int dword_shift, dwords;
+	u32 *buffer;
+	u8 *data;
+	int size, dwords, tex_width, blit_width;
+	u32 y, height;
+	int ret = 0, i;
 	RING_LOCALS;
-	DRM_DEBUG( "blit: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
-		   blit->offset >> 10, blit->pitch, blit->format,
-		   blit->x, blit->y, blit->width, blit->height );
 
-	radeon_update_ring_snapshot( dev_priv );
+	/* FIXME: Be smarter about this...
+	 */
+	buf = radeon_freelist_get( dev );
+	if ( !buf ) return -EAGAIN;
+
+	DRM_DEBUG( "tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
+		   tex->offset >> 10, tex->pitch, tex->format,
+		   image->x, image->y, image->width, image->height );
+
+	buf_priv = buf->dev_private;
 
 	/* The compiler won't optimize away a division by a variable,
 	 * even if the only legal values are powers of two.  Thus, we'll
 	 * use a shift instead.
 	 */
-	switch ( blit->format ) {
-	case RADEON_TXF_32BPP_ARGB8888:
-	case RADEON_TXF_32BPP_RGBA8888:
+	switch ( tex->format ) {
+	case RADEON_TXFORMAT_ARGB8888:
+	case RADEON_TXFORMAT_RGBA8888:
 		format = RADEON_COLOR_FORMAT_ARGB8888;
-		dword_shift = 0;
+		tex_width = tex->width * 4;
+		blit_width = image->width * 4;
 		break;
-	case RADEON_TXF_16BPP_AI88:
-	case RADEON_TXF_16BPP_ARGB1555:
-	case RADEON_TXF_16BPP_RGB565:
-	case RADEON_TXF_16BPP_ARGB4444:
+	case RADEON_TXFORMAT_AI88:
+	case RADEON_TXFORMAT_ARGB1555:
+	case RADEON_TXFORMAT_RGB565:
+	case RADEON_TXFORMAT_ARGB4444:
 		format = RADEON_COLOR_FORMAT_RGB565;
-		dword_shift = 1;
+		tex_width = tex->width * 2;
+		blit_width = image->width * 2;
 		break;
-	case RADEON_TXF_8BPP_I:
-	case RADEON_TXF_8BPP_RGB332:
+	case RADEON_TXFORMAT_I8:
+	case RADEON_TXFORMAT_RGB332:
 		format = RADEON_COLOR_FORMAT_CI8;
-		dword_shift = 2;
+		tex_width = tex->width * 1;
+		blit_width = image->width * 1;
 		break;
 	default:
-		DRM_ERROR( "invalid blit format %d\n", blit->format );
+		DRM_ERROR( "invalid texture format %d\n", tex->format );
 		return -EINVAL;
 	}
 
+	DRM_DEBUG( "   tex=%dx%d  blit=%d\n",
+		   tex_width, tex->height, blit_width );
+
 	/* Flush the pixel cache.  This ensures no pixel data gets mixed
 	 * up with the texture data from the host data blit, otherwise
 	 * part of the texture image may be corrupted.
@@ -1026,46 +1032,88 @@
 
 	ADVANCE_RING();
 
-	/* Dispatch the indirect buffer.
+	/* Make a copy of the parameters in case we have to update them
+	 * for a multi-pass texture blit.
 	 */
-	buf = dma->buflist[blit->idx];
-	buf_priv = buf->dev_private;
-
-	if ( buf->pid != current->pid ) {
-		DRM_ERROR( "process %d using buffer owned by %d\n",
-			   current->pid, buf->pid );
-		return -EINVAL;
-	}
-	if ( buf->pending ) {
-		DRM_ERROR( "sending pending buffer %d\n", blit->idx );
-		return -EINVAL;
+	y = image->y;
+	height = image->height;
+	data = (u8 *)image->data;
+
+	size = height * blit_width;
+
+	if ( size > RADEON_MAX_TEXTURE_SIZE ) {
+		/* Texture image is too large, do a multipass upload */
+		ret = -EAGAIN;
+
+		/* Adjust the blit size to fit the indirect buffer */
+		height = RADEON_MAX_TEXTURE_SIZE / blit_width;
+		size = height * blit_width;
+
+		/* Update the input parameters for next time */
+		image->y += height;
+		image->height -= height;
+		image->data = (char *)image->data + size;
+
+		if ( copy_to_user( tex->image, image, sizeof(*image) ) ) {
+			DRM_ERROR( "EFAULT on tex->image\n" );
+			return -EFAULT;
+		}
+	} else if ( size < 4 ) {
+		size = 4;
 	}
 
-	buf_priv->discard = 1;
-
-	dwords = (blit->width * blit->height) >> dword_shift;
-	if ( !dwords ) dwords = 1;
+	dwords = size / 4;
 
-	data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset);
+	/* Dispatch the indirect buffer.
+	 */
+	buffer = (u32 *)((char *)dev_priv->buffers->handle + buf->offset);
 
-	data[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 );
-	data[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
-		   RADEON_GMC_BRUSH_NONE |
-		   (format << 8) |
-		   RADEON_GMC_SRC_DATATYPE_COLOR |
-		   RADEON_ROP3_S |
-		   RADEON_DP_SRC_SOURCE_HOST_DATA |
-		   RADEON_GMC_CLR_CMP_CNTL_DIS |
-		   RADEON_GMC_WR_MSK_DIS);
-
-	data[2] = (blit->pitch << 22) | (blit->offset >> 10);
-	data[3] = 0xffffffff;
-	data[4] = 0xffffffff;
-	data[5] = (blit->y << 16) | blit->x;
-	data[6] = (blit->height << 16) | blit->width;
-	data[7] = dwords;
+	buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 );
+	buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+		     RADEON_GMC_BRUSH_NONE |
+		     (format << 8) |
+		     RADEON_GMC_SRC_DATATYPE_COLOR |
+		     RADEON_ROP3_S |
+		     RADEON_DP_SRC_SOURCE_HOST_DATA |
+		     RADEON_GMC_CLR_CMP_CNTL_DIS |
+		     RADEON_GMC_WR_MSK_DIS);
+
+	buffer[2] = (tex->pitch << 22) | (tex->offset >> 10);
+	buffer[3] = 0xffffffff;
+	buffer[4] = 0xffffffff;
+	buffer[5] = (y << 16) | image->x;
+	buffer[6] = (height << 16) | image->width;
+	buffer[7] = dwords;
+
+	buffer += 8;
+
+	if ( tex_width >= 32 ) {
+		/* Texture image width is larger than the minimum, so we
+		 * can upload it directly.
+		 */
+		if ( copy_from_user( buffer, data, dwords * sizeof(u32) ) ) {
+			DRM_ERROR( "EFAULT on data, %d dwords\n", dwords );
+			return -EFAULT;
+		}
+	} else {
+		/* Texture image width is less than the minimum, so we
+		 * need to pad out each image scanline to the minimum
+		 * width.
+		 */
+		for ( i = 0 ; i < tex->height ; i++ ) {
+			if ( copy_from_user( buffer, data, tex_width ) ) {
+				DRM_ERROR( "EFAULT on pad, %d bytes\n",
+					   tex_width );
+				return -EFAULT;
+			}
+			buffer += 8;
+			data += tex_width;
+		}
+	}
 
+	buf->pid = current->pid;
 	buf->used = (dwords + 8) * sizeof(u32);
+	buf_priv->discard = 1;
 
 	radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
 
@@ -1080,7 +1128,7 @@
 
 	ADVANCE_RING();
 
-	return 0;
+	return ret;
 }
 
 static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple )
@@ -1090,8 +1138,6 @@
 	RING_LOCALS;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	radeon_update_ring_snapshot( dev_priv );
-
 	BEGIN_RING( 35 );
 
 	OUT_RING( CP_PACKET0( RADEON_RE_STIPPLE_ADDR, 0 ) );
@@ -1118,22 +1164,25 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_radeon_clear_t clear;
+	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
+	LOCK_TEST_WITH_RETURN( dev );
 
-	if ( copy_from_user( &clear, (drm_radeon_clear_t *) arg,
+	if ( copy_from_user( &clear, (drm_radeon_clear_t *)arg,
 			     sizeof(clear) ) )
 		return -EFAULT;
 
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+
 	if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
 		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-	radeon_cp_dispatch_clear( dev, &clear );
+	if ( copy_from_user( &depth_boxes, clear.depth_boxes,
+			     sarea_priv->nbox * sizeof(depth_boxes[0]) ) )
+		return -EFAULT;
+
+	radeon_cp_dispatch_clear( dev, &clear, depth_boxes );
 
 	return 0;
 }
@@ -1147,11 +1196,9 @@
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
+	LOCK_TEST_WITH_RETURN( dev );
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
 	if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
 		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
@@ -1178,13 +1225,10 @@
 	drm_radeon_buf_priv_t *buf_priv;
 	drm_radeon_vertex_t vertex;
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
-	if ( !dev_priv || dev_priv->is_pci ) {
-		DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ );
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
 		return -EINVAL;
 	}
 
@@ -1207,7 +1251,8 @@
 		return -EINVAL;
 	}
 
-	VB_AGE_CHECK_WITH_RET( dev_priv );
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf = dma->buflist[vertex.idx];
 	buf_priv = buf->dev_private;
@@ -1243,13 +1288,10 @@
 	drm_radeon_indices_t elts;
 	int count;
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
-	if ( !dev_priv || dev_priv->is_pci ) {
-		DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ );
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
 		return -EINVAL;
 	}
 
@@ -1272,7 +1314,8 @@
 		return -EINVAL;
 	}
 
-	VB_AGE_CHECK_WITH_RET( dev_priv );
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf = dma->buflist[elts.idx];
 	buf_priv = buf->dev_private;
@@ -1308,37 +1351,34 @@
 	return 0;
 }
 
-int radeon_cp_blit( struct inode *inode, struct file *filp,
-		    unsigned int cmd, unsigned long arg )
+int radeon_cp_texture( struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg )
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_device_dma_t *dma = dev->dma;
-	drm_radeon_blit_t blit;
+	drm_radeon_texture_t tex;
+	drm_radeon_tex_image_t image;
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
+	LOCK_TEST_WITH_RETURN( dev );
 
-	if ( copy_from_user( &blit, (drm_radeon_blit_t *)arg,
-			     sizeof(blit) ) )
+	if ( copy_from_user( &tex, (drm_radeon_texture_t *)arg, sizeof(tex) ) )
 		return -EFAULT;
 
-	DRM_DEBUG( "%s: pid=%d index=%d\n",
-		   __FUNCTION__, current->pid, blit.idx );
-
-	if ( blit.idx < 0 || blit.idx > dma->buf_count ) {
-		DRM_ERROR( "sending %d buffers (of %d max)\n",
-			   blit.idx, dma->buf_count );
+	if ( tex.image == NULL ) {
+		DRM_ERROR( "null texture image!\n" );
 		return -EINVAL;
 	}
 
-	VB_AGE_CHECK_WITH_RET( dev_priv );
+	if ( copy_from_user( &image,
+			     (drm_radeon_tex_image_t *)tex.image,
+			     sizeof(image) ) )
+		return -EFAULT;
 
-	return radeon_cp_dispatch_blit( dev, &blit );
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+	return radeon_cp_dispatch_texture( dev, &tex, &image );
 }
 
 int radeon_cp_stipple( struct inode *inode, struct file *filp,
@@ -1346,23 +1386,21 @@
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_stipple_t stipple;
 	u32 mask[32];
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
+	LOCK_TEST_WITH_RETURN( dev );
 
 	if ( copy_from_user( &stipple, (drm_radeon_stipple_t *)arg,
 			     sizeof(stipple) ) )
 		return -EFAULT;
 
-	if ( copy_from_user( &mask, stipple.mask,
-			     32 * sizeof(u32) ) )
+	if ( copy_from_user( &mask, stipple.mask, 32 * sizeof(u32) ) )
 		return -EFAULT;
 
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+
 	radeon_cp_dispatch_stipple( dev, mask );
 
 	return 0;
@@ -1380,13 +1418,10 @@
 	drm_radeon_indirect_t indirect;
 	RING_LOCALS;
 
-	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||
-	     dev->lock.pid != current->pid ) {
-		DRM_ERROR( "%s called without lock held\n", __FUNCTION__ );
-		return -EINVAL;
-	}
-	if ( !dev_priv || dev_priv->is_pci ) {
-		DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ );
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
 		return -EINVAL;
 	}
 
@@ -1423,7 +1458,8 @@
 		return -EINVAL;
 	}
 
-	VB_AGE_CHECK_WITH_RET( dev_priv );
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf->used = indirect.end;
 	buf_priv->discard = indirect.discard;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)