⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 savage_state.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* savage_state.c -- State and drawing support for Savage * * Copyright 2004  Felix Kuehling * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#include "drmP.h"#include "savage_drm.h"#include "savage_drv.h"void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,			       drm_clip_rect_t * pbox){	uint32_t scstart = dev_priv->state.s3d.new_scstart;	uint32_t scend = dev_priv->state.s3d.new_scend;	scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |	    ((uint32_t) pbox->x1 & 0x000007ff) |	    (((uint32_t) pbox->y1 << 16) & 0x07ff0000);	scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) |	    (((uint32_t) pbox->x2 - 1) & 0x000007ff) |	    ((((uint32_t) pbox->y2 - 1) << 16) & 0x07ff0000);	if (scstart != dev_priv->state.s3d.scstart ||	    scend != dev_priv->state.s3d.scend) {		DMA_LOCALS;		BEGIN_DMA(4);		DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);		DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);		DMA_WRITE(scstart);		DMA_WRITE(scend);		dev_priv->state.s3d.scstart = scstart;		dev_priv->state.s3d.scend = scend;		dev_priv->waiting = 1;		DMA_COMMIT();	}}void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,			      drm_clip_rect_t * pbox){	uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;	uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;	drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |	    ((uint32_t) pbox->x1 & 0x000007ff) |	    (((uint32_t) pbox->y1 << 12) & 0x00fff000);	drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |	    (((uint32_t) pbox->x2 - 1) & 0x000007ff) |	    ((((uint32_t) pbox->y2 - 1) << 12) & 0x00fff000);	if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||	    drawctrl1 != dev_priv->state.s4.drawctrl1) {		DMA_LOCALS;		BEGIN_DMA(4);		DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);		DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);		DMA_WRITE(drawctrl0);		DMA_WRITE(drawctrl1);		dev_priv->state.s4.drawctrl0 = drawctrl0;		dev_priv->state.s4.drawctrl1 = drawctrl1;		dev_priv->waiting = 1;		DMA_COMMIT();	}}static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,				 uint32_t addr){	if ((addr & 6) != 2) {	/* reserved bits */		DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);		return DRM_ERR(EINVAL);	}	if (!(addr & 1)) {	/* local */		addr &= ~7;		if (addr < dev_priv->texture_offset ||		    addr >= dev_priv->texture_offset + dev_priv->texture_size) {			DRM_ERROR			    ("bad texAddr%d %08x (local addr out of range)\n",			     unit, addr);			return DRM_ERR(EINVAL);		}	} else {		/* AGP */		if (!dev_priv->agp_textures) {			DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",				  unit, addr);			return DRM_ERR(EINVAL);		}		addr &= ~7;		if (addr < dev_priv->agp_textures->offset ||		    addr >= (dev_priv->agp_textures->offset +			     dev_priv->agp_textures->size)) {			DRM_ERROR			    ("bad texAddr%d %08x (AGP addr out of range)\n",			     unit, addr);			return DRM_ERR(EINVAL);		}	}	return 0;}#define SAVE_STATE(reg,where)			\	if(start <= reg && start+count > reg)	\		DRM_GET_USER_UNCHECKED(dev_priv->state.where, &regs[reg-start])#define SAVE_STATE_MASK(reg,where,mask) do {			\	if(start <= reg && start+count > reg) {			\		uint32_t tmp;					\		DRM_GET_USER_UNCHECKED(tmp, &regs[reg-start]);	\		dev_priv->state.where = (tmp & (mask)) |	\			(dev_priv->state.where & ~(mask));	\	}							\} while (0)static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,				   unsigned int start, unsigned int count,				   const uint32_t __user * regs){	if (start < SAVAGE_TEXPALADDR_S3D ||	    start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {		DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",			  start, start + count - 1);		return DRM_ERR(EINVAL);	}	SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,			~SAVAGE_SCISSOR_MASK_S3D);	SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,			~SAVAGE_SCISSOR_MASK_S3D);	/* if any texture regs were changed ... */	if (start <= SAVAGE_TEXCTRL_S3D &&	    start + count > SAVAGE_TEXPALADDR_S3D) {		/* ... check texture state */		SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);		SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);		if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)			return savage_verify_texaddr(dev_priv, 0,						     dev_priv->state.s3d.						     texaddr);	}	return 0;}static int savage_verify_state_s4(drm_savage_private_t * dev_priv,				  unsigned int start, unsigned int count,				  const uint32_t __user * regs){	int ret = 0;	if (start < SAVAGE_DRAWLOCALCTRL_S4 ||	    start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {		DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",			  start, start + count - 1);		return DRM_ERR(EINVAL);	}	SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,			~SAVAGE_SCISSOR_MASK_S4);	SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,			~SAVAGE_SCISSOR_MASK_S4);	/* if any texture regs were changed ... */	if (start <= SAVAGE_TEXDESCR_S4 && start + count > SAVAGE_TEXPALADDR_S4) {		/* ... check texture state */		SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);		SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);		SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);		if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)			ret |=			    savage_verify_texaddr(dev_priv, 0,						  dev_priv->state.s4.texaddr0);		if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)			ret |=			    savage_verify_texaddr(dev_priv, 1,						  dev_priv->state.s4.texaddr1);	}	return ret;}#undef SAVE_STATE#undef SAVE_STATE_MASKstatic int savage_dispatch_state(drm_savage_private_t * dev_priv,				 const drm_savage_cmd_header_t * cmd_header,				 const uint32_t __user * regs){	unsigned int count = cmd_header->state.count;	unsigned int start = cmd_header->state.start;	unsigned int count2 = 0;	unsigned int bci_size;	int ret;	DMA_LOCALS;	if (!count)		return 0;	if (DRM_VERIFYAREA_READ(regs, count * 4))		return DRM_ERR(EFAULT);	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {		ret = savage_verify_state_s3d(dev_priv, start, count, regs);		if (ret != 0)			return ret;		/* scissor regs are emitted in savage_dispatch_draw */		if (start < SAVAGE_SCSTART_S3D) {			if (start + count > SAVAGE_SCEND_S3D + 1)				count2 = count - (SAVAGE_SCEND_S3D + 1 - start);			if (start + count > SAVAGE_SCSTART_S3D)				count = SAVAGE_SCSTART_S3D - start;		} else if (start <= SAVAGE_SCEND_S3D) {			if (start + count > SAVAGE_SCEND_S3D + 1) {				count -= SAVAGE_SCEND_S3D + 1 - start;				start = SAVAGE_SCEND_S3D + 1;			} else				return 0;		}	} else {		ret = savage_verify_state_s4(dev_priv, start, count, regs);		if (ret != 0)			return ret;		/* scissor regs are emitted in savage_dispatch_draw */		if (start < SAVAGE_DRAWCTRL0_S4) {			if (start + count > SAVAGE_DRAWCTRL1_S4 + 1)				count2 =				    count - (SAVAGE_DRAWCTRL1_S4 + 1 - start);			if (start + count > SAVAGE_DRAWCTRL0_S4)				count = SAVAGE_DRAWCTRL0_S4 - start;		} else if (start <= SAVAGE_DRAWCTRL1_S4) {			if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) {				count -= SAVAGE_DRAWCTRL1_S4 + 1 - start;				start = SAVAGE_DRAWCTRL1_S4 + 1;			} else				return 0;		}	}	bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255;	if (cmd_header->state.global) {		BEGIN_DMA(bci_size + 1);		DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);		dev_priv->waiting = 1;	} else {		BEGIN_DMA(bci_size);	}	do {		while (count > 0) {			unsigned int n = count < 255 ? count : 255;			DMA_SET_REGISTERS(start, n);			DMA_COPY_FROM_USER(regs, n);			count -= n;			start += n;			regs += n;		}		start += 2;		regs += 2;		count = count2;		count2 = 0;	} while (count);	DMA_COMMIT();	return 0;}static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,				    const drm_savage_cmd_header_t * cmd_header,				    const drm_buf_t * dmabuf){	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 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 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 != 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);		}	}	if (start + n > dmabuf->total / 32) {		DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",			  start, start + n - 1, dmabuf->total / 32);		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;		if (reorder) {			/* Need to reorder indices 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_BCI((count + 1 + 1) / 2);			BCI_DRAW_INDICES_S3D(count, prim, start + 2);

⌨️ 快捷键说明

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