PXA300/310的2D图形加速

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

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

2d

最下层是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调用的。

This entry was posted in Android and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>