转载时请注明出处和作者
作者:李先静 

Marvell的PXA300/310都有硬件2D图形加速单元,Broncho A1用是PXA300,但一直没有使用它的图形加速功能,前几天花了点时间研究它,这个里记个笔记:

在Android平台上,各个相关组件之间的关系如下:


最下层是Graphics Controller,这就是CPU提供的硬件加速单元,提供画直线,填充和各种blit功能。这个在Monahans_L_LV_Processor_Dev_Man_Vol_III.pdf里有详细描述。

再上层是驱动程序,它对Graphics Controller的寄存器进行包装,为应用程序提供设备文件/dev/m2d。

m2d_append 函数负责向命令队列中写入要执行的命令:

static int m2d_append(struct m2d_device *dev, void *usrbuf, size_t len) { volatile gcu_regs_t *gr = dev->gcu_regs; unsigned int tail_room, head_room; unsigned long exhead = gr->gcrbexhr; unsigned long tail = dev->ring_tail_dma; unsigned long base = dev->ring_addr_dma; unsigned long size = dev->ring_size; unsigned char *ring_addr = (unsigned char *)dev->ring_addr; if (tail >= exhead) { tail_room = size - (tail - base); head_room = exhead - base; } else { tail_room = exhead - tail; head_room = 0; } if (tail_room >= len) { if (copy_from_user(ring_addr + (tail - base), usrbuf, len)) return -EFAULT; tail += len; #ifdef FILL_NOP } else if (head_room >= len) { m2d_fill_nop(ring_addr + (tail - base), tail_room); #else } else if (head_room + tail_room >= len) { if (copy_from_user(ring_addr + (tail - base), usrbuf, tail_room)) return -EFAULT; usrbuf += tail_room; len -= tail_room; #endif if (copy_from_user(ring_addr, usrbuf, len)) return -EFAULT; tail = dev->ring_addr_dma + len; } else { return -ENOSPC; } if (tail - base == size) tail = base; switch_m2d_clk(1); dev->ring_tail_dma = tail; gr->gcrbtr = tail; return 0; }

执行完成后,GCU会通过中断通知CPU:
static int m2d_gcu_irq(int irq, void *dev_id) { struct m2d_device *dev = (struct m2d_device *)dev_id; volatile gcu_regs_t *gr = dev->gcu_regs; unsigned long status = gr->gciscr & gr->gciecr; if (irq != IRQ_GRPHICS) return IRQ_NONE; /* FIXME: what if this interrupt occurs with no current context * in execution */ if (status & (GCISCR_PF_INTST | GCISCR_IIN_INTST | GCISCR_IOP_INTST)) m2d_interrupt_err(dev, gr); if (status & GCISCR_EEOB_INTST) m2d_interrupt_eeob(dev, gr); return IRQ_HANDLED; }

再上层是函数库,它对Graphics Controller提供的基本功能进行包装,然后通过/dev/m2d的ioctrl把命令发给Graphics Controller。

这里的大部分函数的功能只是将数据打包,然后通过ioctrl把命令传递给驱动程序,如:

int m2d_color_fill( struct m2d_context *ctx, struct m2d_op_region *opr) { int len = 0; fprintf(stdout, "%s:%d/n", __func__, __LINE__); if (ctx == NULL) return -1; CHECK_BOUNDARY( opr->dx0, opr->dy0, opr->width, opr->height, ctx->dstbuf); SETUP_CFILL_IMM(ctx->cmdbuf.cb_ptr, len, opr->dx0, opr->dy0, opr->width, opr->height, ctx->fill_color_format, ctx->fill_color_value); UPDATE_CMDBUF(ctx, len); fprintf(stdout, "%s:%d/n", __func__, __LINE__); return len; }

打包数据:

#define SETUP_CFILL_IMM(buf, len, x, y, w, h, pf, c) / do { / fprintf(stdout, "SETUP_CFILL_IMM: x=%d y=%d w=%d h=%d/n",x, y, w, h); / uint32_t f = GCU_PXLFMT_FORMAT(pf); / if ((f) < 0x0a) { / buf[0] = GC_CFILL_IMM | ((f) << 8) | 0x04; len = 5; / buf[4] = (uint32_t)(c); / } else if ((f) <= 0x0B) { / buf[0] = GC_CFILL_IMM | ((f) << 8) | 0x05; len = 6; / buf[4] = (uint32_t)(c >> 32); / buf[5] = (uint32_t)(c); / } else { / len = -ERR_IPF; break; / } / buf[1] = (x); buf[2] = (y); / buf[3] = ((h) << 16) | ((w) & 0xffff); / } while (0)
提交数据:

#define UPDATE_CMDBUF(context, len) / do { / DUMP_CMDBUF((context)->cmdbuf.cb_ptr, (len)); / (context)->cmdbuf.cb_ptr += (len); / (context)->cmdbuf.cb_len += ((len) << 2); / if ((context)->cmdbuf.cb_len + CMDBUF_SAFE_ROOM > CMDBUF_SIZE) / _m2d_submit((context), 0); / } while (0)

再上层包括两个部分,gcu对m2d_lib进一步包装,给视频播放器调用的。copybit插件是给OpenGL调用的。