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 + -
显示快捷键?