savage_state.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,166 行 · 第 1/3 页

C
1,166
字号
			DMA_COMMIT();		}		idx += count;		n -= count;		prim |= BCI_CMD_DRAW_CONT;	}	return 0;}static int savage_dispatch_clear(drm_savage_private_t * dev_priv,				 const drm_savage_cmd_header_t * cmd_header,				 const drm_savage_cmd_header_t *data,				 unsigned int nbox,				 const drm_clip_rect_t *boxes){	unsigned int flags = cmd_header->clear0.flags;	unsigned int clear_cmd;	unsigned int i, nbufs;	DMA_LOCALS;	if (nbox == 0)		return 0;	clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |	    BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;	BCI_CMD_SET_ROP(clear_cmd, 0xCC);	nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +	    ((flags & SAVAGE_BACK) ? 1 : 0) + ((flags & SAVAGE_DEPTH) ? 1 : 0);	if (nbufs == 0)		return 0;	if (data->clear1.mask != 0xffffffff) {		/* set mask */		BEGIN_DMA(2);		DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);		DMA_WRITE(data->clear1.mask);		DMA_COMMIT();	}	for (i = 0; i < nbox; ++i) {		unsigned int x, y, w, h;		unsigned int buf;		x = boxes[i].x1, y = boxes[i].y1;		w = boxes[i].x2 - boxes[i].x1;		h = boxes[i].y2 - boxes[i].y1;		BEGIN_DMA(nbufs * 6);		for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {			if (!(flags & buf))				continue;			DMA_WRITE(clear_cmd);			switch (buf) {			case SAVAGE_FRONT:				DMA_WRITE(dev_priv->front_offset);				DMA_WRITE(dev_priv->front_bd);				break;			case SAVAGE_BACK:				DMA_WRITE(dev_priv->back_offset);				DMA_WRITE(dev_priv->back_bd);				break;			case SAVAGE_DEPTH:				DMA_WRITE(dev_priv->depth_offset);				DMA_WRITE(dev_priv->depth_bd);				break;			}			DMA_WRITE(data->clear1.value);			DMA_WRITE(BCI_X_Y(x, y));			DMA_WRITE(BCI_W_H(w, h));		}		DMA_COMMIT();	}	if (data->clear1.mask != 0xffffffff) {		/* reset mask */		BEGIN_DMA(2);		DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);		DMA_WRITE(0xffffffff);		DMA_COMMIT();	}	return 0;}static int savage_dispatch_swap(drm_savage_private_t * dev_priv,				unsigned int nbox, const drm_clip_rect_t *boxes){	unsigned int swap_cmd;	unsigned int i;	DMA_LOCALS;	if (nbox == 0)		return 0;	swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |	    BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;	BCI_CMD_SET_ROP(swap_cmd, 0xCC);	for (i = 0; i < nbox; ++i) {		BEGIN_DMA(6);		DMA_WRITE(swap_cmd);		DMA_WRITE(dev_priv->back_offset);		DMA_WRITE(dev_priv->back_bd);		DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));		DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));		DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1,				  boxes[i].y2 - boxes[i].y1));		DMA_COMMIT();	}	return 0;}static int savage_dispatch_draw(drm_savage_private_t * dev_priv,				const drm_savage_cmd_header_t *start,				const drm_savage_cmd_header_t *end,				const drm_buf_t * dmabuf,				const unsigned int *vtxbuf,				unsigned int vb_size, unsigned int vb_stride,				unsigned int nbox,				const drm_clip_rect_t *boxes){	unsigned int i, j;	int ret;	for (i = 0; i < nbox; ++i) {		const drm_savage_cmd_header_t *cmdbuf;		dev_priv->emit_clip_rect(dev_priv, &boxes[i]);		cmdbuf = start;		while (cmdbuf < end) {			drm_savage_cmd_header_t cmd_header;			cmd_header = *cmdbuf;			cmdbuf++;			switch (cmd_header.cmd.cmd) {			case SAVAGE_CMD_DMA_PRIM:				ret = savage_dispatch_dma_prim(					dev_priv, &cmd_header, dmabuf);				break;			case SAVAGE_CMD_VB_PRIM:				ret = savage_dispatch_vb_prim(					dev_priv, &cmd_header,					vtxbuf, vb_size, vb_stride);				break;			case SAVAGE_CMD_DMA_IDX:				j = (cmd_header.idx.count + 3) / 4;				/* j was check in savage_bci_cmdbuf */				ret = savage_dispatch_dma_idx(dev_priv,					&cmd_header, (const uint16_t *)cmdbuf,					dmabuf);				cmdbuf += j;				break;			case SAVAGE_CMD_VB_IDX:				j = (cmd_header.idx.count + 3) / 4;				/* j was check in savage_bci_cmdbuf */				ret = savage_dispatch_vb_idx(dev_priv,					&cmd_header, (const uint16_t *)cmdbuf,					(const uint32_t *)vtxbuf, vb_size, 					vb_stride);				cmdbuf += j;				break;			default:				/* What's the best return code? EFAULT? */				DRM_ERROR("IMPLEMENTATION ERROR: "					  "non-drawing-command %d\n",					  cmd_header.cmd.cmd);				return DRM_ERR(EINVAL);			}			if (ret != 0)				return ret;		}	}	return 0;}int savage_bci_cmdbuf(DRM_IOCTL_ARGS){	DRM_DEVICE;	drm_savage_private_t *dev_priv = dev->dev_private;	drm_device_dma_t *dma = dev->dma;	drm_buf_t *dmabuf;	drm_savage_cmdbuf_t cmdbuf;	drm_savage_cmd_header_t *kcmd_addr = NULL;	drm_savage_cmd_header_t *first_draw_cmd;	unsigned int *kvb_addr = NULL;	drm_clip_rect_t *kbox_addr = NULL;	unsigned int i, j;	int ret = 0;	DRM_DEBUG("\n");	LOCK_TEST_WITH_RETURN(dev, filp);	DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *) data,				 sizeof(cmdbuf));	if (dma && dma->buflist) {		if (cmdbuf.dma_idx > dma->buf_count) {			DRM_ERROR			    ("vertex buffer index %u out of range (0-%u)\n",			     cmdbuf.dma_idx, dma->buf_count - 1);			return DRM_ERR(EINVAL);		}		dmabuf = dma->buflist[cmdbuf.dma_idx];	} else {		dmabuf = NULL;	}	/* Copy the user buffers into kernel temporary areas.  This hasn't been	 * a performance loss compared to VERIFYAREA_READ/	 * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct	 * for locking on FreeBSD.	 */	if (cmdbuf.size) {		kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);		if (kcmd_addr == NULL)			return ENOMEM;		if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,				       cmdbuf.size * 8))		{			drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);			return DRM_ERR(EFAULT);		}		cmdbuf.cmd_addr = kcmd_addr;	}	if (cmdbuf.vb_size) {		kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER);		if (kvb_addr == NULL) {			ret = DRM_ERR(ENOMEM);			goto done;		}		if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr,				       cmdbuf.vb_size)) {			ret = DRM_ERR(EFAULT);			goto done;		}		cmdbuf.vb_addr = kvb_addr;	}	if (cmdbuf.nbox) {		kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t),				       DRM_MEM_DRIVER);		if (kbox_addr == NULL) {			ret = DRM_ERR(ENOMEM);			goto done;		}		if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,				       cmdbuf.nbox * sizeof(drm_clip_rect_t))) {			ret = DRM_ERR(EFAULT);			goto done;		}	cmdbuf.box_addr = kbox_addr;	}	/* Make sure writes to DMA buffers are finished before sending	 * DMA commands to the graphics hardware. */	DRM_MEMORYBARRIER();	/* Coming from user space. Don't know if the Xserver has	 * emitted wait commands. Assuming the worst. */	dev_priv->waiting = 1;	i = 0;	first_draw_cmd = NULL;	while (i < cmdbuf.size) {		drm_savage_cmd_header_t cmd_header;		cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr;		cmdbuf.cmd_addr++;		i++;		/* Group drawing commands with same state to minimize		 * iterations over clip rects. */		j = 0;		switch (cmd_header.cmd.cmd) {		case SAVAGE_CMD_DMA_IDX:		case SAVAGE_CMD_VB_IDX:			j = (cmd_header.idx.count + 3) / 4;			if (i + j > cmdbuf.size) {				DRM_ERROR("indexed drawing command extends "					  "beyond end of command buffer\n");				DMA_FLUSH();				return DRM_ERR(EINVAL);			}			/* fall through */		case SAVAGE_CMD_DMA_PRIM:		case SAVAGE_CMD_VB_PRIM:			if (!first_draw_cmd)				first_draw_cmd = cmdbuf.cmd_addr - 1;			cmdbuf.cmd_addr += j;			i += j;			break;		default:			if (first_draw_cmd) {				ret = savage_dispatch_draw(				      dev_priv, first_draw_cmd,				      cmdbuf.cmd_addr - 1,				      dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size,				      cmdbuf.vb_stride,				      cmdbuf.nbox, cmdbuf.box_addr);				if (ret != 0)					return ret;				first_draw_cmd = NULL;			}		}		if (first_draw_cmd)			continue;		switch (cmd_header.cmd.cmd) {		case SAVAGE_CMD_STATE:			j = (cmd_header.state.count + 1) / 2;			if (i + j > cmdbuf.size) {				DRM_ERROR("command SAVAGE_CMD_STATE extends "					  "beyond end of command buffer\n");				DMA_FLUSH();				ret = DRM_ERR(EINVAL);				goto done;			}			ret = savage_dispatch_state(dev_priv, &cmd_header,				(const uint32_t *)cmdbuf.cmd_addr);			cmdbuf.cmd_addr += j;			i += j;			break;		case SAVAGE_CMD_CLEAR:			if (i + 1 > cmdbuf.size) {				DRM_ERROR("command SAVAGE_CMD_CLEAR extends "					  "beyond end of command buffer\n");				DMA_FLUSH();				ret = DRM_ERR(EINVAL);				goto done;			}			ret = savage_dispatch_clear(dev_priv, &cmd_header,						    cmdbuf.cmd_addr,						    cmdbuf.nbox, cmdbuf.box_addr);			cmdbuf.cmd_addr++;			i++;			break;		case SAVAGE_CMD_SWAP:			ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox,						   cmdbuf.box_addr);			break;		default:			DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);			DMA_FLUSH();			ret = DRM_ERR(EINVAL);			goto done;		}		if (ret != 0) {			DMA_FLUSH();			goto done;		}	}	if (first_draw_cmd) {		ret = savage_dispatch_draw (			dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf,			cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride,			cmdbuf.nbox, cmdbuf.box_addr);		if (ret != 0) {			DMA_FLUSH();			goto done;		}	}	DMA_FLUSH();	if (dmabuf && cmdbuf.discard) {		drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;		uint16_t event;		event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);		SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);		savage_freelist_put(dev, dmabuf);	}done:	/* If we didn't need to allocate them, these'll be NULL */	drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);	drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);	drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t),		 DRM_MEM_DRIVER);	return ret;}

⌨️ 快捷键说明

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