📄 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"drm_ioctl_desc_t radeon_ioctls[] = { [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = { radeon_cp_init, 1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = { radeon_cp_start, 1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = { radeon_cp_resume, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = { radeon_cp_clear, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = { radeon_cp_vertex, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = { radeon_cp_texture, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = { radeon_cp_vertex2, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = { radeon_cp_cmdbuf, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = { radeon_cp_getparam, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = { radeon_cp_flip, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = { radeon_mem_init_heap,1, 1 }, [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = { radeon_surface_alloc,1, 0 }, [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = { radeon_surface_free, 1, 0 }};int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);/* ================================================================ * 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 __user *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_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: /* 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_cmd_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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -