savage_state.c

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

C
1,147
字号
/* 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 + =
减小字号Ctrl + -
显示快捷键?