radeon_state.c

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

C
2,231
字号
/* radeon_state.c -- State support for Radeon -*- linux-c -*- *//* * Copyright 2000 VA Linux Systems, Inc., Fremont, California. * 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, 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: *    Gareth Hughes <gareth@valinux.com> *    Kevin E. Martin <martin@valinux.com> */#include "drmP.h"#include "drm.h"#include "drm_sarea.h"#include "radeon_drm.h"#include "radeon_drv.h"/* ================================================================ * Helper functions for client state checking and fixup */static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *						    dev_priv,						    drm_file_t * filp_priv,						    u32 *offset){	u32 off = *offset;	struct drm_radeon_driver_file_fields *radeon_priv;	/* Hrm ... the story of the offset ... So this function converts	 * the various ideas of what userland clients might have for an	 * offset in the card address space into an offset into the card	 * address space :) So with a sane client, it should just keep	 * the value intact and just do some boundary checking. However,	 * not all clients are sane. Some older clients pass us 0 based	 * offsets relative to the start of the framebuffer and some may	 * assume the AGP aperture it appended to the framebuffer, so we	 * try to detect those cases and fix them up.	 *	 * Note: It might be a good idea here to make sure the offset lands	 * in some "allowed" area to protect things like the PCIE GART...	 */	/* First, the best case, the offset already lands in either the	 * framebuffer or the GART mapped space	 */	if ((off >= dev_priv->fb_location &&	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||	    (off >= dev_priv->gart_vm_start &&	     off < (dev_priv->gart_vm_start + dev_priv->gart_size)))		return 0;	/* Ok, that didn't happen... now check if we have a zero based	 * offset that fits in the framebuffer + gart space, apply the	 * magic offset we get from SETPARAM or calculated from fb_location	 */	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {		radeon_priv = filp_priv->driver_priv;		off += radeon_priv->radeon_fb_delta;	}	/* Finally, assume we aimed at a GART offset if beyond the fb */	if (off > (dev_priv->fb_location + dev_priv->fb_size))		off = off - (dev_priv->fb_location + dev_priv->fb_size) +			dev_priv->gart_vm_start;	/* Now recheck and fail if out of bounds */	if ((off >= dev_priv->fb_location &&	     off < (dev_priv->fb_location + dev_priv->fb_size)) ||	    (off >= dev_priv->gart_vm_start &&	     off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {		DRM_DEBUG("offset fixed up to 0x%x\n", off);		*offset = off;		return 0;	}	return DRM_ERR(EINVAL);}static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *						     dev_priv,						     drm_file_t * filp_priv,						     int id, u32 *data){	switch (id) {	case RADEON_EMIT_PP_MISC:		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,		    &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {			DRM_ERROR("Invalid depth buffer offset\n");			return DRM_ERR(EINVAL);		}		break;	case RADEON_EMIT_PP_CNTL:		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,		    &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {			DRM_ERROR("Invalid colour buffer offset\n");			return DRM_ERR(EINVAL);		}		break;	case R200_EMIT_PP_TXOFFSET_0:	case R200_EMIT_PP_TXOFFSET_1:	case R200_EMIT_PP_TXOFFSET_2:	case R200_EMIT_PP_TXOFFSET_3:	case R200_EMIT_PP_TXOFFSET_4:	case R200_EMIT_PP_TXOFFSET_5:		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,						  &data[0])) {			DRM_ERROR("Invalid R200 texture offset\n");			return DRM_ERR(EINVAL);		}		break;	case RADEON_EMIT_PP_TXFILTER_0:	case RADEON_EMIT_PP_TXFILTER_1:	case RADEON_EMIT_PP_TXFILTER_2:		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,		    &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {			DRM_ERROR("Invalid R100 texture offset\n");			return DRM_ERR(EINVAL);		}		break;	case R200_EMIT_PP_CUBIC_OFFSETS_0:	case R200_EMIT_PP_CUBIC_OFFSETS_1:	case R200_EMIT_PP_CUBIC_OFFSETS_2:	case R200_EMIT_PP_CUBIC_OFFSETS_3:	case R200_EMIT_PP_CUBIC_OFFSETS_4:	case R200_EMIT_PP_CUBIC_OFFSETS_5:{			int i;			for (i = 0; i < 5; i++) {				if (radeon_check_and_fixup_offset(dev_priv,								  filp_priv,								  &data[i])) {					DRM_ERROR					    ("Invalid R200 cubic texture offset\n");					return DRM_ERR(EINVAL);				}			}			break;		}	case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:	case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:	case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{			int i;			for (i = 0; i < 5; i++) {				if (radeon_check_and_fixup_offset(dev_priv,								  filp_priv,								  &data[i])) {					DRM_ERROR					    ("Invalid R100 cubic texture offset\n");					return DRM_ERR(EINVAL);				}			}		}		break;	case RADEON_EMIT_RB3D_COLORPITCH:	case RADEON_EMIT_RE_LINE_PATTERN:	case RADEON_EMIT_SE_LINE_WIDTH:	case RADEON_EMIT_PP_LUM_MATRIX:	case RADEON_EMIT_PP_ROT_MATRIX_0:	case RADEON_EMIT_RB3D_STENCILREFMASK:	case RADEON_EMIT_SE_VPORT_XSCALE:	case RADEON_EMIT_SE_CNTL:	case RADEON_EMIT_SE_CNTL_STATUS:	case RADEON_EMIT_RE_MISC:	case RADEON_EMIT_PP_BORDER_COLOR_0:	case RADEON_EMIT_PP_BORDER_COLOR_1:	case RADEON_EMIT_PP_BORDER_COLOR_2:	case RADEON_EMIT_SE_ZBIAS_FACTOR:	case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:	case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:	case R200_EMIT_PP_TXCBLEND_0:	case R200_EMIT_PP_TXCBLEND_1:	case R200_EMIT_PP_TXCBLEND_2:	case R200_EMIT_PP_TXCBLEND_3:	case R200_EMIT_PP_TXCBLEND_4:	case R200_EMIT_PP_TXCBLEND_5:	case R200_EMIT_PP_TXCBLEND_6:	case R200_EMIT_PP_TXCBLEND_7:	case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:	case R200_EMIT_TFACTOR_0:	case R200_EMIT_VTX_FMT_0:	case R200_EMIT_VAP_CTL:	case R200_EMIT_MATRIX_SELECT_0:	case R200_EMIT_TEX_PROC_CTL_2:	case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:	case R200_EMIT_PP_TXFILTER_0:	case R200_EMIT_PP_TXFILTER_1:	case R200_EMIT_PP_TXFILTER_2:	case R200_EMIT_PP_TXFILTER_3:	case R200_EMIT_PP_TXFILTER_4:	case R200_EMIT_PP_TXFILTER_5:	case R200_EMIT_VTE_CNTL:	case R200_EMIT_OUTPUT_VTX_COMP_SEL:	case R200_EMIT_PP_TAM_DEBUG3:	case R200_EMIT_PP_CNTL_X:	case R200_EMIT_RB3D_DEPTHXY_OFFSET:	case R200_EMIT_RE_AUX_SCISSOR_CNTL:	case R200_EMIT_RE_SCISSOR_TL_0:	case R200_EMIT_RE_SCISSOR_TL_1:	case R200_EMIT_RE_SCISSOR_TL_2:	case R200_EMIT_SE_VAP_CNTL_STATUS:	case R200_EMIT_SE_VTX_STATE_CNTL:	case R200_EMIT_RE_POINTSIZE:	case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:	case R200_EMIT_PP_CUBIC_FACES_0:	case R200_EMIT_PP_CUBIC_FACES_1:	case R200_EMIT_PP_CUBIC_FACES_2:	case R200_EMIT_PP_CUBIC_FACES_3:	case R200_EMIT_PP_CUBIC_FACES_4:	case R200_EMIT_PP_CUBIC_FACES_5:	case RADEON_EMIT_PP_TEX_SIZE_0:	case RADEON_EMIT_PP_TEX_SIZE_1:	case RADEON_EMIT_PP_TEX_SIZE_2:	case R200_EMIT_RB3D_BLENDCOLOR:	case R200_EMIT_TCL_POINT_SPRITE_CNTL:	case RADEON_EMIT_PP_CUBIC_FACES_0:	case RADEON_EMIT_PP_CUBIC_FACES_1:	case RADEON_EMIT_PP_CUBIC_FACES_2:	case R200_EMIT_PP_TRI_PERF_CNTL:	case R200_EMIT_PP_AFS_0:	case R200_EMIT_PP_AFS_1:	case R200_EMIT_ATF_TFACTOR:	case R200_EMIT_PP_TXCTLALL_0:	case R200_EMIT_PP_TXCTLALL_1:	case R200_EMIT_PP_TXCTLALL_2:	case R200_EMIT_PP_TXCTLALL_3:	case R200_EMIT_PP_TXCTLALL_4:	case R200_EMIT_PP_TXCTLALL_5:		/* These packets don't contain memory offsets */		break;	default:		DRM_ERROR("Unknown state packet ID %d\n", id);		return DRM_ERR(EINVAL);	}	return 0;}static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *						     dev_priv,						     drm_file_t *filp_priv,						     drm_radeon_kcmd_buffer_t *						     cmdbuf,						     unsigned int *cmdsz){	u32 *cmd = (u32 *) cmdbuf->buf;	*cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);	if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {		DRM_ERROR("Not a type 3 packet\n");		return DRM_ERR(EINVAL);	}	if (4 * *cmdsz > cmdbuf->bufsz) {		DRM_ERROR("Packet size larger than size of data provided\n");		return DRM_ERR(EINVAL);	}	/* Check client state and fix it up if necessary */	if (cmd[0] & 0x8000) {	/* MSB of opcode: next DWORD GUI_CNTL */		u32 offset;		if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {			offset = cmd[2] << 10;			if (radeon_check_and_fixup_offset			    (dev_priv, filp_priv, &offset)) {				DRM_ERROR("Invalid first packet offset\n");				return DRM_ERR(EINVAL);			}			cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;		}		if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&		    (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {			offset = cmd[3] << 10;			if (radeon_check_and_fixup_offset			    (dev_priv, filp_priv, &offset)) {				DRM_ERROR("Invalid second packet offset\n");				return DRM_ERR(EINVAL);			}			cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;		}	}	return 0;}/* ================================================================ * CP hardware state programming functions */static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,					     drm_clip_rect_t * box){	RING_LOCALS;	DRM_DEBUG("   box:  x1=%d y1=%d  x2=%d y2=%d\n",		  box->x1, box->y1, box->x2, box->y2);	BEGIN_RING(4);	OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));	OUT_RING((box->y1 << 16) | box->x1);	OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));	OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));	ADVANCE_RING();}/* Emit 1.1 state */static int radeon_emit_state(drm_radeon_private_t * dev_priv,			     drm_file_t * filp_priv,			     drm_radeon_context_regs_t * ctx,			     drm_radeon_texture_regs_t * tex,			     unsigned int dirty){	RING_LOCALS;	DRM_DEBUG("dirty=0x%08x\n", dirty);	if (dirty & RADEON_UPLOAD_CONTEXT) {		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,						  &ctx->rb3d_depthoffset)) {			DRM_ERROR("Invalid depth buffer offset\n");			return DRM_ERR(EINVAL);		}		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,						  &ctx->rb3d_coloroffset)) {			DRM_ERROR("Invalid depth buffer offset\n");			return DRM_ERR(EINVAL);		}		BEGIN_RING(14);		OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));		OUT_RING(ctx->pp_misc);		OUT_RING(ctx->pp_fog_color);		OUT_RING(ctx->re_solid_color);		OUT_RING(ctx->rb3d_blendcntl);		OUT_RING(ctx->rb3d_depthoffset);		OUT_RING(ctx->rb3d_depthpitch);		OUT_RING(ctx->rb3d_zstencilcntl);		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));		OUT_RING(ctx->pp_cntl);		OUT_RING(ctx->rb3d_cntl);		OUT_RING(ctx->rb3d_coloroffset);		OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));		OUT_RING(ctx->rb3d_colorpitch);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_VERTFMT) {		BEGIN_RING(2);		OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));		OUT_RING(ctx->se_coord_fmt);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_LINE) {		BEGIN_RING(5);		OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));		OUT_RING(ctx->re_line_pattern);		OUT_RING(ctx->re_line_state);		OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));		OUT_RING(ctx->se_line_width);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_BUMPMAP) {		BEGIN_RING(5);		OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));		OUT_RING(ctx->pp_lum_matrix);		OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));		OUT_RING(ctx->pp_rot_matrix_0);		OUT_RING(ctx->pp_rot_matrix_1);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_MASKS) {		BEGIN_RING(4);		OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));		OUT_RING(ctx->rb3d_stencilrefmask);		OUT_RING(ctx->rb3d_ropcntl);		OUT_RING(ctx->rb3d_planemask);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_VIEWPORT) {		BEGIN_RING(7);		OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));		OUT_RING(ctx->se_vport_xscale);		OUT_RING(ctx->se_vport_xoffset);		OUT_RING(ctx->se_vport_yscale);		OUT_RING(ctx->se_vport_yoffset);		OUT_RING(ctx->se_vport_zscale);		OUT_RING(ctx->se_vport_zoffset);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_SETUP) {		BEGIN_RING(4);		OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));		OUT_RING(ctx->se_cntl);		OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));		OUT_RING(ctx->se_cntl_status);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_MISC) {		BEGIN_RING(2);		OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));		OUT_RING(ctx->re_misc);		ADVANCE_RING();	}	if (dirty & RADEON_UPLOAD_TEX0) {		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,						  &tex[0].pp_txoffset)) {			DRM_ERROR("Invalid texture offset for unit 0\n");			return DRM_ERR(EINVAL);		}		BEGIN_RING(9);

⌨️ 快捷键说明

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