r300_cmdbuf.c

来自「linux 内核源代码」· C语言 代码 · 共 956 行 · 第 1/2 页

C
956
字号
/* r300_cmdbuf.c -- Command buffer emission for R300 -*- linux-c -*- * * Copyright (C) The Weather Channel, Inc.  2002. * Copyright (C) 2004 Nicolai Haehnle. * All Rights Reserved. * * The Weather Channel (TM) funded Tungsten Graphics to develop the * initial release of the Radeon 8500 driver under the XFree86 license. * This notice must be preserved. * * 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, sublicense, * 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 NONINFRINGEMENT.  IN NO EVENT SHALL * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. * * Authors: *    Nicolai Haehnle <prefect_@gmx.net> */#include "drmP.h"#include "drm.h"#include "radeon_drm.h"#include "radeon_drv.h"#include "r300_reg.h"#define R300_SIMULTANEOUS_CLIPRECTS		4/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects */static const int r300_cliprect_cntl[4] = {	0xAAAA,	0xEEEE,	0xFEFE,	0xFFFE};/** * Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command * buffer, starting with index n. */static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,			       drm_radeon_kcmd_buffer_t *cmdbuf, int n){	struct drm_clip_rect box;	int nr;	int i;	RING_LOCALS;	nr = cmdbuf->nbox - n;	if (nr > R300_SIMULTANEOUS_CLIPRECTS)		nr = R300_SIMULTANEOUS_CLIPRECTS;	DRM_DEBUG("%i cliprects\n", nr);	if (nr) {		BEGIN_RING(6 + nr * 2);		OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));		for (i = 0; i < nr; ++i) {			if (DRM_COPY_FROM_USER_UNCHECKED			    (&box, &cmdbuf->boxes[n + i], sizeof(box))) {				DRM_ERROR("copy cliprect faulted\n");				return -EFAULT;			}			box.x1 =			    (box.x1 +			     R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;			box.y1 =			    (box.y1 +			     R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;			box.x2 =			    (box.x2 +			     R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;			box.y2 =			    (box.y2 +			     R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;			OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |				 (box.y1 << R300_CLIPRECT_Y_SHIFT));			OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |				 (box.y2 << R300_CLIPRECT_Y_SHIFT));		}		OUT_RING_REG(R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr - 1]);		/* TODO/SECURITY: Force scissors to a safe value, otherwise the		 * client might be able to trample over memory.		 * The impact should be very limited, but I'd rather be safe than		 * sorry.		 */		OUT_RING(CP_PACKET0(R300_RE_SCISSORS_TL, 1));		OUT_RING(0);		OUT_RING(R300_SCISSORS_X_MASK | R300_SCISSORS_Y_MASK);		ADVANCE_RING();	} else {		/* Why we allow zero cliprect rendering:		 * There are some commands in a command buffer that must be submitted		 * even when there are no cliprects, e.g. DMA buffer discard		 * or state setting (though state setting could be avoided by		 * simulating a loss of context).		 *		 * Now since the cmdbuf interface is so chaotic right now (and is		 * bound to remain that way for a bit until things settle down),		 * it is basically impossible to filter out the commands that are		 * necessary and those that aren't.		 *		 * So I choose the safe way and don't do any filtering at all;		 * instead, I simply set up the engine so that all rendering		 * can't produce any fragments.		 */		BEGIN_RING(2);		OUT_RING_REG(R300_RE_CLIPRECT_CNTL, 0);		ADVANCE_RING();	}	return 0;}static u8 r300_reg_flags[0x10000 >> 2];void r300_init_reg_flags(void){	int i;	memset(r300_reg_flags, 0, 0x10000 >> 2);#define ADD_RANGE_MARK(reg, count,mark) \		for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\			r300_reg_flags[i]|=(mark);#define MARK_SAFE		1#define MARK_CHECK_OFFSET	2#define ADD_RANGE(reg, count)	ADD_RANGE_MARK(reg, count, MARK_SAFE)	/* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */	ADD_RANGE(R300_SE_VPORT_XSCALE, 6);	ADD_RANGE(R300_VAP_CNTL, 1);	ADD_RANGE(R300_SE_VTE_CNTL, 2);	ADD_RANGE(0x2134, 2);	ADD_RANGE(R300_VAP_CNTL_STATUS, 1);	ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);	ADD_RANGE(0x21DC, 1);	ADD_RANGE(R300_VAP_UNKNOWN_221C, 1);	ADD_RANGE(R300_VAP_CLIP_X_0, 4);	ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1);	ADD_RANGE(R300_VAP_UNKNOWN_2288, 1);	ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);	ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);	ADD_RANGE(R300_GB_ENABLE, 1);	ADD_RANGE(R300_GB_MSPOS0, 5);	ADD_RANGE(R300_TX_CNTL, 1);	ADD_RANGE(R300_TX_ENABLE, 1);	ADD_RANGE(0x4200, 4);	ADD_RANGE(0x4214, 1);	ADD_RANGE(R300_RE_POINTSIZE, 1);	ADD_RANGE(0x4230, 3);	ADD_RANGE(R300_RE_LINE_CNT, 1);	ADD_RANGE(R300_RE_UNK4238, 1);	ADD_RANGE(0x4260, 3);	ADD_RANGE(R300_RE_SHADE, 4);	ADD_RANGE(R300_RE_POLYGON_MODE, 5);	ADD_RANGE(R300_RE_ZBIAS_CNTL, 1);	ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);	ADD_RANGE(R300_RE_OCCLUSION_CNTL, 1);	ADD_RANGE(R300_RE_CULL_CNTL, 1);	ADD_RANGE(0x42C0, 2);	ADD_RANGE(R300_RS_CNTL_0, 2);	ADD_RANGE(R300_RS_INTERP_0, 8);	ADD_RANGE(R300_RS_ROUTE_0, 8);	ADD_RANGE(0x43A4, 2);	ADD_RANGE(0x43E8, 1);	ADD_RANGE(R300_PFS_CNTL_0, 3);	ADD_RANGE(R300_PFS_NODE_0, 4);	ADD_RANGE(R300_PFS_TEXI_0, 64);	ADD_RANGE(0x46A4, 5);	ADD_RANGE(R300_PFS_INSTR0_0, 64);	ADD_RANGE(R300_PFS_INSTR1_0, 64);	ADD_RANGE(R300_PFS_INSTR2_0, 64);	ADD_RANGE(R300_PFS_INSTR3_0, 64);	ADD_RANGE(R300_RE_FOG_STATE, 1);	ADD_RANGE(R300_FOG_COLOR_R, 3);	ADD_RANGE(R300_PP_ALPHA_TEST, 2);	ADD_RANGE(0x4BD8, 1);	ADD_RANGE(R300_PFS_PARAM_0_X, 64);	ADD_RANGE(0x4E00, 1);	ADD_RANGE(R300_RB3D_CBLEND, 2);	ADD_RANGE(R300_RB3D_COLORMASK, 1);	ADD_RANGE(R300_RB3D_BLEND_COLOR, 3);	ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET);	/* check offset */	ADD_RANGE(R300_RB3D_COLORPITCH0, 1);	ADD_RANGE(0x4E50, 9);	ADD_RANGE(0x4E88, 1);	ADD_RANGE(0x4EA0, 2);	ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);	ADD_RANGE(R300_RB3D_ZSTENCIL_FORMAT, 4);	ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET);	/* check offset */	ADD_RANGE(R300_RB3D_DEPTHPITCH, 1);	ADD_RANGE(0x4F28, 1);	ADD_RANGE(0x4F30, 2);	ADD_RANGE(0x4F44, 1);	ADD_RANGE(0x4F54, 1);	ADD_RANGE(R300_TX_FILTER_0, 16);	ADD_RANGE(R300_TX_FILTER1_0, 16);	ADD_RANGE(R300_TX_SIZE_0, 16);	ADD_RANGE(R300_TX_FORMAT_0, 16);	ADD_RANGE(R300_TX_PITCH_0, 16);	/* Texture offset is dangerous and needs more checking */	ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);	ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);	/* Sporadic registers used as primitives are emitted */	ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1);	ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);	ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);	ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);}static __inline__ int r300_check_range(unsigned reg, int count){	int i;	if (reg & ~0xffff)		return -1;	for (i = (reg >> 2); i < (reg >> 2) + count; i++)		if (r300_reg_flags[i] != MARK_SAFE)			return 1;	return 0;}static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *							  dev_priv,							  drm_radeon_kcmd_buffer_t							  * cmdbuf,							  drm_r300_cmd_header_t							  header){	int reg;	int sz;	int i;	int values[64];	RING_LOCALS;	sz = header.packet0.count;	reg = (header.packet0.reghi << 8) | header.packet0.reglo;	if ((sz > 64) || (sz < 0)) {		DRM_ERROR		    ("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",		     reg, sz);		return -EINVAL;	}	for (i = 0; i < sz; i++) {		values[i] = ((int *)cmdbuf->buf)[i];		switch (r300_reg_flags[(reg >> 2) + i]) {		case MARK_SAFE:			break;		case MARK_CHECK_OFFSET:			if (!radeon_check_offset(dev_priv, (u32) values[i])) {				DRM_ERROR				    ("Offset failed range check (reg=%04x sz=%d)\n",				     reg, sz);				return -EINVAL;			}			break;		default:			DRM_ERROR("Register %04x failed check as flag=%02x\n",				  reg + i * 4, r300_reg_flags[(reg >> 2) + i]);			return -EINVAL;		}	}	BEGIN_RING(1 + sz);	OUT_RING(CP_PACKET0(reg, sz - 1));	OUT_RING_TABLE(values, sz);	ADVANCE_RING();	cmdbuf->buf += sz * 4;	cmdbuf->bufsz -= sz * 4;	return 0;}/** * Emits a packet0 setting arbitrary registers. * Called by r300_do_cp_cmdbuf. * * Note that checks are performed on contents and addresses of the registers */static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,					drm_radeon_kcmd_buffer_t *cmdbuf,					drm_r300_cmd_header_t header){	int reg;	int sz;	RING_LOCALS;	sz = header.packet0.count;	reg = (header.packet0.reghi << 8) | header.packet0.reglo;	if (!sz)		return 0;	if (sz * 4 > cmdbuf->bufsz)		return -EINVAL;	if (reg + sz * 4 >= 0x10000) {		DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,			  sz);		return -EINVAL;	}	if (r300_check_range(reg, sz)) {		/* go and check everything */		return r300_emit_carefully_checked_packet0(dev_priv, cmdbuf,							   header);	}	/* the rest of the data is safe to emit, whatever the values the user passed */	BEGIN_RING(1 + sz);	OUT_RING(CP_PACKET0(reg, sz - 1));	OUT_RING_TABLE((int *)cmdbuf->buf, sz);	ADVANCE_RING();	cmdbuf->buf += sz * 4;	cmdbuf->bufsz -= sz * 4;	return 0;}/** * Uploads user-supplied vertex program instructions or parameters onto * the graphics card. * Called by r300_do_cp_cmdbuf. */static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,				    drm_radeon_kcmd_buffer_t *cmdbuf,				    drm_r300_cmd_header_t header){	int sz;	int addr;	RING_LOCALS;	sz = header.vpu.count;	addr = (header.vpu.adrhi << 8) | header.vpu.adrlo;	if (!sz)		return 0;	if (sz * 16 > cmdbuf->bufsz)		return -EINVAL;	BEGIN_RING(5 + sz * 4);	/* Wait for VAP to come to senses.. */	/* there is no need to emit it multiple times, (only once before VAP is programmed,	   but this optimization is for later */	OUT_RING_REG(R300_VAP_PVS_WAITIDLE, 0);	OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr);	OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1));	OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4);	ADVANCE_RING();	cmdbuf->buf += sz * 16;	cmdbuf->bufsz -= sz * 16;	return 0;}/** * Emit a clear packet from userspace. * Called by r300_emit_packet3. */static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,				      drm_radeon_kcmd_buffer_t *cmdbuf){	RING_LOCALS;	if (8 * 4 > cmdbuf->bufsz)		return -EINVAL;	BEGIN_RING(10);	OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));	OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING |		 (1 << R300_PRIM_NUM_VERTICES_SHIFT));	OUT_RING_TABLE((int *)cmdbuf->buf, 8);	ADVANCE_RING();	cmdbuf->buf += 8 * 4;	cmdbuf->bufsz -= 8 * 4;	return 0;}static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,					       drm_radeon_kcmd_buffer_t *cmdbuf,					       u32 header){	int count, i, k;#define MAX_ARRAY_PACKET  64	u32 payload[MAX_ARRAY_PACKET];	u32 narrays;	RING_LOCALS;	count = (header >> 16) & 0x3fff;	if ((count + 1) > MAX_ARRAY_PACKET) {		DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",			  count);		return -EINVAL;	}	memset(payload, 0, MAX_ARRAY_PACKET * 4);	memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);	/* carefully check packet contents */	narrays = payload[0];	k = 0;	i = 1;	while ((k < narrays) && (i < (count + 1))) {		i++;		/* skip attribute field */		if (!radeon_check_offset(dev_priv, payload[i])) {			DRM_ERROR			    ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",			     k, i);			return -EINVAL;		}		k++;		i++;		if (k == narrays)			break;		/* have one more to process, they come in pairs */		if (!radeon_check_offset(dev_priv, payload[i])) {			DRM_ERROR			    ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",			     k, i);			return -EINVAL;		}		k++;		i++;	}	/* do the counts match what we expect ? */	if ((k != narrays) || (i != (count + 1))) {		DRM_ERROR		    ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",		     k, i, narrays, count + 1);		return -EINVAL;	}	/* all clear, output packet */	BEGIN_RING(count + 2);	OUT_RING(header);	OUT_RING_TABLE(payload, count + 1);	ADVANCE_RING();	cmdbuf->buf += (count + 2) * 4;	cmdbuf->bufsz -= (count + 2) * 4;	return 0;}static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,					     drm_radeon_kcmd_buffer_t *cmdbuf)

⌨️ 快捷键说明

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