/** * 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_cmd_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 DRM_ERR(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 __user*)cmdbuf->buf, sz*4 ); ADVANCE_RING(); cmdbuf->buf += sz*16; cmdbuf->bufsz -= sz*16; return 0; }
static void RADEONFlush2D(PixmapPtr pPix) { RINFO_FROM_SCREEN(pPix->drawable.pScreen); TRACE; BEGIN_RING(2*2); OUT_RING_REG(RADEON_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL); OUT_RING_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE); ADVANCE_RING(); }
static int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; RING_LOCALS; atomic_inc(&dev_priv->swi_emitted); ret = atomic_read(&dev_priv->swi_emitted); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); ADVANCE_RING(); COMMIT_RING(); return ret; }
static void RADEONSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) { RINFO_FROM_SCREEN(pPix->drawable.pScreen); TRACE; if (CS_FULL(info->cs)) { RADEONFlush2D(info->accel_state->dst_pix); radeon_cs_flush_indirect(pScrn); } if (info->accel_state->vsync) RADEONWaitForVLine(pScrn, pPix, radeon_pick_best_crtc(pScrn, FALSE, x1, x2, y1, y2), y1, y2); BEGIN_RING(2*2); OUT_RING_REG(RADEON_DST_Y_X, (y1 << 16) | x1); OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, ((y2 - y1) << 16) | (x2 - x1)); ADVANCE_RING(); }
static void Emit2DState(ScrnInfoPtr pScrn, int op) { RADEONInfoPtr info = RADEONPTR(pScrn); int has_src; /* don't emit if no operation in progress */ if (info->state_2d.op == 0 && op == 0) return; has_src = info->state_2d.src_pitch_offset || info->state_2d.src_bo; if (has_src) { BEGIN_ACCEL_RELOC(10, 2); } else { BEGIN_ACCEL_RELOC(9, 1); } OUT_RING_REG(RADEON_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right); OUT_RING_REG(RADEON_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl); OUT_RING_REG(RADEON_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr); OUT_RING_REG(RADEON_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr); OUT_RING_REG(RADEON_DP_SRC_FRGD_CLR, info->state_2d.dp_src_frgd_clr); OUT_RING_REG(RADEON_DP_SRC_BKGD_CLR, info->state_2d.dp_src_bkgd_clr); OUT_RING_REG(RADEON_DP_WRITE_MASK, info->state_2d.dp_write_mask); OUT_RING_REG(RADEON_DP_CNTL, info->state_2d.dp_cntl); OUT_RING_REG(RADEON_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset); OUT_RING_RELOC(info->state_2d.dst_bo, 0, info->state_2d.dst_domain); if (has_src) { OUT_RING_REG(RADEON_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset); OUT_RING_RELOC(info->state_2d.src_bo, RADEON_GEM_DOMAIN_GTT|RADEON_GEM_DOMAIN_VRAM, 0); } ADVANCE_RING(); if (op) info->state_2d.op = op; info->reemit_current2d = Emit2DState; }
static void RADEONCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) { RINFO_FROM_SCREEN(pDst->drawable.pScreen); TRACE; if (CS_FULL(info->cs)) { RADEONFlush2D(info->accel_state->dst_pix); radeon_cs_flush_indirect(pScrn); } if (info->accel_state->xdir < 0) { srcX += w - 1; dstX += w - 1; } if (info->accel_state->ydir < 0) { srcY += h - 1; dstY += h - 1; } if (info->accel_state->vsync) RADEONWaitForVLine(pScrn, pDst, radeon_pick_best_crtc(pScrn, FALSE, dstX, dstX + w, dstY, dstY + h), dstY, dstY + h); BEGIN_RING(2*3); OUT_RING_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX); OUT_RING_REG(RADEON_DST_Y_X, (dstY << 16) | dstX); OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w); ADVANCE_RING(); }
/* Emit blit with arbitrary source and destination offsets and pitches */ static void RADEONBlitChunk(ScrnInfoPtr pScrn, struct radeon_bo *src_bo, struct radeon_bo *dst_bo, uint32_t datatype, uint32_t src_pitch_offset, uint32_t dst_pitch_offset, int srcX, int srcY, int dstX, int dstY, int w, int h, uint32_t src_domain, uint32_t dst_domain) { RADEONInfoPtr info = RADEONPTR(pScrn); if (src_bo && dst_bo) { BEGIN_ACCEL_RELOC(6, 2); } else if (src_bo && dst_bo == NULL) { BEGIN_ACCEL_RELOC(6, 1); } else { BEGIN_RING(2*6); } OUT_RING_REG(RADEON_DP_GUI_MASTER_CNTL, RADEON_GMC_DST_PITCH_OFFSET_CNTL | RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_BRUSH_NONE | (datatype << 8) | RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_S | RADEON_DP_SRC_SOURCE_MEMORY | RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); OUT_RING_REG(RADEON_SRC_PITCH_OFFSET, src_pitch_offset); if (src_bo) { OUT_RING_RELOC(src_bo, src_domain, 0); } OUT_RING_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset); if (dst_bo) { OUT_RING_RELOC(dst_bo, 0, dst_domain); } OUT_RING_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX); OUT_RING_REG(RADEON_DST_Y_X, (dstY << 16) | dstX); OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w); ADVANCE_RING(); BEGIN_RING(2*2); OUT_RING_REG(RADEON_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL); OUT_RING_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE); ADVANCE_RING(); }
/** * 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_cmd_buffer_t* cmdbuf, int n) { drm_clip_rect_t 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 DRM_ERR(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; }