📄 savage_state.c
字号:
/* savage_state.c -- State and drawing support for Savage * * Copyright 2004 Felix Kuehling * 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, sub license, * 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 * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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. */#include "drmP.h"#include "savage_drm.h"#include "savage_drv.h"void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, drm_clip_rect_t * pbox){ uint32_t scstart = dev_priv->state.s3d.new_scstart; uint32_t scend = dev_priv->state.s3d.new_scend; scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) | ((uint32_t) pbox->x1 & 0x000007ff) | (((uint32_t) pbox->y1 << 16) & 0x07ff0000); scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) | (((uint32_t) pbox->x2 - 1) & 0x000007ff) | ((((uint32_t) pbox->y2 - 1) << 16) & 0x07ff0000); if (scstart != dev_priv->state.s3d.scstart || scend != dev_priv->state.s3d.scend) { DMA_LOCALS; BEGIN_DMA(4); DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2); DMA_WRITE(scstart); DMA_WRITE(scend); dev_priv->state.s3d.scstart = scstart; dev_priv->state.s3d.scend = scend; dev_priv->waiting = 1; DMA_COMMIT(); }}void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, drm_clip_rect_t * pbox){ uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) | ((uint32_t) pbox->x1 & 0x000007ff) | (((uint32_t) pbox->y1 << 12) & 0x00fff000); drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) | (((uint32_t) pbox->x2 - 1) & 0x000007ff) | ((((uint32_t) pbox->y2 - 1) << 12) & 0x00fff000); if (drawctrl0 != dev_priv->state.s4.drawctrl0 || drawctrl1 != dev_priv->state.s4.drawctrl1) { DMA_LOCALS; BEGIN_DMA(4); DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2); DMA_WRITE(drawctrl0); DMA_WRITE(drawctrl1); dev_priv->state.s4.drawctrl0 = drawctrl0; dev_priv->state.s4.drawctrl1 = drawctrl1; dev_priv->waiting = 1; DMA_COMMIT(); }}static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, uint32_t addr){ if ((addr & 6) != 2) { /* reserved bits */ DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr); return DRM_ERR(EINVAL); } if (!(addr & 1)) { /* local */ addr &= ~7; if (addr < dev_priv->texture_offset || addr >= dev_priv->texture_offset + dev_priv->texture_size) { DRM_ERROR ("bad texAddr%d %08x (local addr out of range)\n", unit, addr); return DRM_ERR(EINVAL); } } else { /* AGP */ if (!dev_priv->agp_textures) { DRM_ERROR("bad texAddr%d %08x (AGP not available)\n", unit, addr); return DRM_ERR(EINVAL); } addr &= ~7; if (addr < dev_priv->agp_textures->offset || addr >= (dev_priv->agp_textures->offset + dev_priv->agp_textures->size)) { DRM_ERROR ("bad texAddr%d %08x (AGP addr out of range)\n", unit, addr); return DRM_ERR(EINVAL); } } return 0;}#define SAVE_STATE(reg,where) \ if(start <= reg && start+count > reg) \ DRM_GET_USER_UNCHECKED(dev_priv->state.where, ®s[reg-start])#define SAVE_STATE_MASK(reg,where,mask) do { \ if(start <= reg && start+count > reg) { \ uint32_t tmp; \ DRM_GET_USER_UNCHECKED(tmp, ®s[reg-start]); \ dev_priv->state.where = (tmp & (mask)) | \ (dev_priv->state.where & ~(mask)); \ } \} while (0)static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, unsigned int start, unsigned int count, const uint32_t __user * regs){ if (start < SAVAGE_TEXPALADDR_S3D || start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", start, start + count - 1); return DRM_ERR(EINVAL); } SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart, ~SAVAGE_SCISSOR_MASK_S3D); SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend, ~SAVAGE_SCISSOR_MASK_S3D); /* if any texture regs were changed ... */ if (start <= SAVAGE_TEXCTRL_S3D && start + count > SAVAGE_TEXPALADDR_S3D) { /* ... check texture state */ SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl); SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) return savage_verify_texaddr(dev_priv, 0, dev_priv->state.s3d. texaddr); } return 0;}static int savage_verify_state_s4(drm_savage_private_t * dev_priv, unsigned int start, unsigned int count, const uint32_t __user * regs){ int ret = 0; if (start < SAVAGE_DRAWLOCALCTRL_S4 || start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) { DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", start, start + count - 1); return DRM_ERR(EINVAL); } SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0, ~SAVAGE_SCISSOR_MASK_S4); SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1, ~SAVAGE_SCISSOR_MASK_S4); /* if any texture regs were changed ... */ if (start <= SAVAGE_TEXDESCR_S4 && start + count > SAVAGE_TEXPALADDR_S4) { /* ... check texture state */ SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) ret |= savage_verify_texaddr(dev_priv, 0, dev_priv->state.s4.texaddr0); if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) ret |= savage_verify_texaddr(dev_priv, 1, dev_priv->state.s4.texaddr1); } return ret;}#undef SAVE_STATE#undef SAVE_STATE_MASKstatic int savage_dispatch_state(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, const uint32_t __user * regs){ unsigned int count = cmd_header->state.count; unsigned int start = cmd_header->state.start; unsigned int count2 = 0; unsigned int bci_size; int ret; DMA_LOCALS; if (!count) return 0; if (DRM_VERIFYAREA_READ(regs, count * 4)) return DRM_ERR(EFAULT); if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { ret = savage_verify_state_s3d(dev_priv, start, count, regs); if (ret != 0) return ret; /* scissor regs are emitted in savage_dispatch_draw */ if (start < SAVAGE_SCSTART_S3D) { if (start + count > SAVAGE_SCEND_S3D + 1) count2 = count - (SAVAGE_SCEND_S3D + 1 - start); if (start + count > SAVAGE_SCSTART_S3D) count = SAVAGE_SCSTART_S3D - start; } else if (start <= SAVAGE_SCEND_S3D) { if (start + count > SAVAGE_SCEND_S3D + 1) { count -= SAVAGE_SCEND_S3D + 1 - start; start = SAVAGE_SCEND_S3D + 1; } else return 0; } } else { ret = savage_verify_state_s4(dev_priv, start, count, regs); if (ret != 0) return ret; /* scissor regs are emitted in savage_dispatch_draw */ if (start < SAVAGE_DRAWCTRL0_S4) { if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) count2 = count - (SAVAGE_DRAWCTRL1_S4 + 1 - start); if (start + count > SAVAGE_DRAWCTRL0_S4) count = SAVAGE_DRAWCTRL0_S4 - start; } else if (start <= SAVAGE_DRAWCTRL1_S4) { if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) { count -= SAVAGE_DRAWCTRL1_S4 + 1 - start; start = SAVAGE_DRAWCTRL1_S4 + 1; } else return 0; } } bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255; if (cmd_header->state.global) { BEGIN_DMA(bci_size + 1); DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); dev_priv->waiting = 1; } else { BEGIN_DMA(bci_size); } do { while (count > 0) { unsigned int n = count < 255 ? count : 255; DMA_SET_REGISTERS(start, n); DMA_COPY_FROM_USER(regs, n); count -= n; start += n; regs += n; } start += 2; regs += 2; count = count2; count2 = 0; } while (count); DMA_COMMIT(); return 0;}static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, const drm_buf_t * dmabuf){ unsigned char reorder = 0; unsigned int prim = cmd_header->prim.prim; unsigned int skip = cmd_header->prim.skip; unsigned int n = cmd_header->prim.count; unsigned int start = cmd_header->prim.start; unsigned int i; BCI_LOCALS; if (!dmabuf) { DRM_ERROR("called without dma buffers!\n"); return DRM_ERR(EINVAL); } if (!n) return 0; switch (prim) { case SAVAGE_PRIM_TRILIST_201: reorder = 1; prim = SAVAGE_PRIM_TRILIST; case SAVAGE_PRIM_TRILIST: if (n % 3 != 0) { DRM_ERROR("wrong number of vertices %u in TRILIST\n", n); return DRM_ERR(EINVAL); } break; case SAVAGE_PRIM_TRISTRIP: case SAVAGE_PRIM_TRIFAN: if (n < 3) { DRM_ERROR ("wrong number of vertices %u in TRIFAN/STRIP\n", n); return DRM_ERR(EINVAL); } break; default: DRM_ERROR("invalid primitive type %u\n", prim); return DRM_ERR(EINVAL); } if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { if (skip != 0) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); return DRM_ERR(EINVAL); } } else { unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); return DRM_ERR(EINVAL); } if (reorder) { DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); return DRM_ERR(EINVAL); } } if (start + n > dmabuf->total / 32) { DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", start, start + n - 1, dmabuf->total / 32); return DRM_ERR(EINVAL); } /* Vertex DMA doesn't work with command DMA at the same time, * so we use BCI_... to submit commands here. Flush buffered * faked DMA first. */ DMA_FLUSH(); if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { BEGIN_BCI(2); BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); dev_priv->state.common.vbaddr = dmabuf->bus_address; } if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { /* Workaround for what looks like a hardware bug. If a * WAIT_3D_IDLE was emitted some time before the * indexed drawing command then the engine will lock * up. There are two known workarounds: * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ BEGIN_BCI(63); for (i = 0; i < 63; ++i) BCI_WRITE(BCI_CMD_WAIT); dev_priv->waiting = 0; } prim <<= 25; while (n != 0) { /* Can emit up to 255 indices (85 triangles) at once. */ unsigned int count = n > 255 ? 255 : n; if (reorder) { /* Need to reorder indices for correct flat * shading while preserving the clock sense * for correct culling. Only on Savage3D. */ int reorder[3] = { -1, -1, -1 }; reorder[start % 3] = 2; BEGIN_BCI((count + 1 + 1) / 2); BCI_DRAW_INDICES_S3D(count, prim, start + 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -