savage_state.c

来自「底层驱动开发」· C语言 代码 · 共 1,147 行 · 第 1/3 页

C
1,147
字号
			for (i = start+1; i+1 < start+count; i += 2)				BCI_WRITE((i + reorder[i % 3]) |					  ((i+1 + reorder[(i+1) % 3]) << 16));			if (i < start+count)				BCI_WRITE(i + reorder[i%3]);		} else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {			BEGIN_BCI((count+1+1)/2);			BCI_DRAW_INDICES_S3D(count, prim, start);			for (i = start+1; i+1 < start+count; i += 2)				BCI_WRITE(i | ((i+1) << 16));			if (i < start+count)				BCI_WRITE(i);		} else {			BEGIN_BCI((count+2+1)/2);			BCI_DRAW_INDICES_S4(count, prim, skip);			for (i = start; i+1 < start+count; i += 2)				BCI_WRITE(i | ((i+1) << 16));			if (i < start+count)				BCI_WRITE(i);		}		start += count;		n -= count;		prim |= BCI_CMD_DRAW_CONT;	}	return 0;}static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv,				   const drm_savage_cmd_header_t *cmd_header,				   const uint32_t __user *vtxbuf,				   unsigned int vb_size,				   unsigned int vb_stride){	unsigned char reorder = 0;	unsigned int prim = cmd_header->prim.prim;	unsigned int skip = cmd_header->prim.skip;	unsigned int n = cmd_header->prim.count;	unsigned int start = cmd_header->prim.start;	unsigned int vtx_size;	unsigned int i;	DMA_LOCALS;	if (!n)		return 0;	switch (prim) {	case SAVAGE_PRIM_TRILIST_201:		reorder = 1;		prim = SAVAGE_PRIM_TRILIST;	case SAVAGE_PRIM_TRILIST:		if (n % 3 != 0) {			DRM_ERROR("wrong number of vertices %u in TRILIST\n",				  n);			return DRM_ERR(EINVAL);		}		break;	case SAVAGE_PRIM_TRISTRIP:	case SAVAGE_PRIM_TRIFAN:		if (n < 3) {			DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",				  n);			return DRM_ERR(EINVAL);		}		break;	default:		DRM_ERROR("invalid primitive type %u\n", prim);		return DRM_ERR(EINVAL);	}	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {		if (skip > SAVAGE_SKIP_ALL_S3D) {			DRM_ERROR("invalid skip flags 0x%04x\n", skip);			return DRM_ERR(EINVAL);		}		vtx_size = 8; /* full vertex */	} else {		if (skip > SAVAGE_SKIP_ALL_S4) {			DRM_ERROR("invalid skip flags 0x%04x\n", skip);			return DRM_ERR(EINVAL);		}		vtx_size = 10; /* full vertex */	}	vtx_size -= (skip & 1) + (skip >> 1 & 1) +		(skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +		(skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);	if (vtx_size > vb_stride) {		DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",			  vtx_size, vb_stride);		return DRM_ERR(EINVAL);	}	if (start + n > vb_size / (vb_stride*4)) {		DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",			  start, start + n - 1, vb_size / (vb_stride*4));		return DRM_ERR(EINVAL);	}	prim <<= 25;	while (n != 0) {		/* Can emit up to 255 vertices (85 triangles) at once. */		unsigned int count = n > 255 ? 255 : n;		if (reorder) {			/* Need to reorder vertices for correct flat			 * shading while preserving the clock sense			 * for correct culling. Only on Savage3D. */			int reorder[3] = {-1, -1, -1};			reorder[start%3] = 2;			BEGIN_DMA(count*vtx_size+1);			DMA_DRAW_PRIMITIVE(count, prim, skip);			for (i = start; i < start+count; ++i) {				unsigned int j = i + reorder[i % 3];				DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],						   vtx_size);			}			DMA_COMMIT();		} else {			BEGIN_DMA(count*vtx_size+1);			DMA_DRAW_PRIMITIVE(count, prim, skip);			if (vb_stride == vtx_size) {				DMA_COPY_FROM_USER(&vtxbuf[vb_stride*start],						   vtx_size*count);			} else {				for (i = start; i < start+count; ++i) {					DMA_COPY_FROM_USER(						&vtxbuf[vb_stride*i],						vtx_size);				}			}			DMA_COMMIT();		}		start += count;		n -= count;		prim |= BCI_CMD_DRAW_CONT;	}	return 0;}static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv,				   const drm_savage_cmd_header_t *cmd_header,				   const uint16_t __user *usr_idx,				   const drm_buf_t *dmabuf){	unsigned char reorder = 0;	unsigned int prim = cmd_header->idx.prim;	unsigned int skip = cmd_header->idx.skip;	unsigned int n = cmd_header->idx.count;	unsigned int i;	BCI_LOCALS;	if (!dmabuf) {	    DRM_ERROR("called without dma buffers!\n");	    return DRM_ERR(EINVAL);	}	if (!n)		return 0;	switch (prim) {	case SAVAGE_PRIM_TRILIST_201:		reorder = 1;		prim = SAVAGE_PRIM_TRILIST;	case SAVAGE_PRIM_TRILIST:		if (n % 3 != 0) {			DRM_ERROR("wrong number of indices %u in TRILIST\n",				  n);			return DRM_ERR(EINVAL);		}		break;	case SAVAGE_PRIM_TRISTRIP:	case SAVAGE_PRIM_TRIFAN:		if (n < 3) {			DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",				  n);			return DRM_ERR(EINVAL);		}		break;	default:		DRM_ERROR("invalid primitive type %u\n", prim);		return DRM_ERR(EINVAL);	}	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {		if (skip != 0) {			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",				  skip);			return DRM_ERR(EINVAL);		}	} else {		unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -			(skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -			(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);		if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",				  skip);			return DRM_ERR(EINVAL);		}		if (reorder) {			DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");			return DRM_ERR(EINVAL);		}	}	/* Vertex DMA doesn't work with command DMA at the same time,	 * so we use BCI_... to submit commands here. Flush buffered	 * faked DMA first. */	DMA_FLUSH();	if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {		BEGIN_BCI(2);		BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);		BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);		dev_priv->state.common.vbaddr = dmabuf->bus_address;	}	if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {		/* Workaround for what looks like a hardware bug. If a		 * WAIT_3D_IDLE was emitted some time before the		 * indexed drawing command then the engine will lock		 * up. There are two known workarounds:		 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */		BEGIN_BCI(63);		for (i = 0; i < 63; ++i)			BCI_WRITE(BCI_CMD_WAIT);		dev_priv->waiting = 0;	}	prim <<= 25;	while (n != 0) {		/* Can emit up to 255 indices (85 triangles) at once. */		unsigned int count = n > 255 ? 255 : n;		/* Is it ok to allocate 510 bytes on the stack in an ioctl? */		uint16_t idx[255];		/* Copy and check indices */		DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);		for (i = 0; i < count; ++i) {			if (idx[i] > dmabuf->total/32) {				DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",					  i, idx[i], dmabuf->total/32);				return DRM_ERR(EINVAL);			}		}		if (reorder) {			/* Need to reorder indices for correct flat			 * shading while preserving the clock sense			 * for correct culling. Only on Savage3D. */			int reorder[3] = {2, -1, -1};			BEGIN_BCI((count+1+1)/2);			BCI_DRAW_INDICES_S3D(count, prim, idx[2]);			for (i = 1; i+1 < count; i += 2)				BCI_WRITE(idx[i + reorder[i % 3]] |					  (idx[i+1 + reorder[(i+1) % 3]] << 16));			if (i < count)				BCI_WRITE(idx[i + reorder[i%3]]);		} else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {			BEGIN_BCI((count+1+1)/2);			BCI_DRAW_INDICES_S3D(count, prim, idx[0]);			for (i = 1; i+1 < count; i += 2)				BCI_WRITE(idx[i] | (idx[i+1] << 16));			if (i < count)				BCI_WRITE(idx[i]);		} else {			BEGIN_BCI((count+2+1)/2);			BCI_DRAW_INDICES_S4(count, prim, skip);			for (i = 0; i+1 < count; i += 2)				BCI_WRITE(idx[i] | (idx[i+1] << 16));			if (i < count)				BCI_WRITE(idx[i]);		}		usr_idx += count;		n -= count;		prim |= BCI_CMD_DRAW_CONT;	}	return 0;}static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv,				  const drm_savage_cmd_header_t *cmd_header,				  const uint16_t __user *usr_idx,				  const uint32_t __user *vtxbuf,				  unsigned int vb_size,				  unsigned int vb_stride){	unsigned char reorder = 0;	unsigned int prim = cmd_header->idx.prim;	unsigned int skip = cmd_header->idx.skip;	unsigned int n = cmd_header->idx.count;	unsigned int vtx_size;	unsigned int i;	DMA_LOCALS;	if (!n)		return 0;	switch (prim) {	case SAVAGE_PRIM_TRILIST_201:		reorder = 1;		prim = SAVAGE_PRIM_TRILIST;	case SAVAGE_PRIM_TRILIST:		if (n % 3 != 0) {			DRM_ERROR("wrong number of indices %u in TRILIST\n",				  n);			return DRM_ERR(EINVAL);		}		break;	case SAVAGE_PRIM_TRISTRIP:	case SAVAGE_PRIM_TRIFAN:		if (n < 3) {			DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",				  n);			return DRM_ERR(EINVAL);		}		break;	default:		DRM_ERROR("invalid primitive type %u\n", prim);		return DRM_ERR(EINVAL);	}	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {		if (skip > SAVAGE_SKIP_ALL_S3D) {			DRM_ERROR("invalid skip flags 0x%04x\n", skip);			return DRM_ERR(EINVAL);		}		vtx_size = 8; /* full vertex */	} else {		if (skip > SAVAGE_SKIP_ALL_S4) {			DRM_ERROR("invalid skip flags 0x%04x\n", skip);			return DRM_ERR(EINVAL);		}		vtx_size = 10; /* full vertex */	}	vtx_size -= (skip & 1) + (skip >> 1 & 1) +		(skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +		(skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);	if (vtx_size > vb_stride) {		DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",			  vtx_size, vb_stride);		return DRM_ERR(EINVAL);	}	prim <<= 25;	while (n != 0) {		/* Can emit up to 255 vertices (85 triangles) at once. */		unsigned int count = n > 255 ? 255 : n;		/* Is it ok to allocate 510 bytes on the stack in an ioctl? */		uint16_t idx[255];		/* Copy and check indices */		DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);		for (i = 0; i < count; ++i) {			if (idx[i] > vb_size / (vb_stride*4)) {				DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",					  i, idx[i],  vb_size / (vb_stride*4));				return DRM_ERR(EINVAL);			}		}		if (reorder) {			/* Need to reorder vertices for correct flat

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?