📄 radeon_state.c
字号:
/* 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; if (off >= dev_priv->fb_location && off < (dev_priv->gart_vm_start + dev_priv->gart_size)) return 0; radeon_priv = filp_priv->driver_priv; off += radeon_priv->radeon_fb_delta; DRM_DEBUG("offset fixed up to 0x%x\n", off); if (off < dev_priv->fb_location || off >= (dev_priv->gart_vm_start + dev_priv->gart_size)) return DRM_ERR(EINVAL); *offset = off; return 0;}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); OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5)); OUT_RING(tex[0].pp_txfilter); OUT_RING(tex[0].pp_txformat); OUT_RING(tex[0].pp_txoffset); OUT_RING(tex[0].pp_txcblend); OUT_RING(tex[0].pp_txablend); OUT_RING(tex[0].pp_tfactor); OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0)); OUT_RING(tex[0].pp_border_color); ADVANCE_RING(); } if (dirty & RADEON_UPLOAD_TEX1) { if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex[1].pp_txoffset)) { DRM_ERROR("Invalid texture offset for unit 1\n"); return DRM_ERR(EINVAL); } BEGIN_RING(9); OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5)); OUT_RING(tex[1].pp_txfilter); OUT_RING(tex[1].pp_txformat); OUT_RING(tex[1].pp_txoffset); OUT_RING(tex[1].pp_txcblend); OUT_RING(tex[1].pp_txablend); OUT_RING(tex[1].pp_tfactor); OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0)); OUT_RING(tex[1].pp_border_color); ADVANCE_RING(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -