您的位置:首页 > 移动开发 > Android开发

S3C6410 Copybit Android 模块设计心得

2011-11-18 09:29 411 查看
首先再来回顾下Copybit的接口函数,虽然简单,但功能一个都不少。



Copybit模块主要使用的硬件加速功能有:

bitBlit

Stretch

Rotate

Alpha blending

Color Transform


1、bit blit和stretch的实现

strctch并没有特殊去实现,因为所有的坐标数据都是Android的Surface和OpenGL ES层传下来的,主要还是实现bit blit,即块拷贝。

Android上层,主要是SurfaceFlinger,维护着几块重要的图形缓冲区。

这些图形缓冲区是通过Gralloc模块申请到的PMEM空间,因此都可以获取物理地址,提供给2D加速引擎。

为什么只有几片缓冲区呢?我估计800x480的屏幕大约只要10MB的PMEM空间即可,这么点的数据,如果连续传给LCD,肯定是不够的。

因此Android采用了部分更新策略,只更新屏幕是需要改变的部分,这一点很适合2D引擎,因为引擎可以只把改变的数据刷到屏幕上。

Copybit的上层会传递两个参数,一个是当前缓冲(屏幕)的总大小,比如800x480,另外是需要更新的窗口大小(x,y,w,h)。

最后需要注意,将数据提供给S3C6410的blit引擎前,需要区分src和dst的数据是什么(fb或者pmem),如果是fb,传递fb基址,否则传递pmem物理地址。


2、Rotate实现

Rotate很简单,坐标数据上层基本做好了,刷新矩形框可以直接使用msm模块的set_rects,配置下2D引擎的旋转模式即可。


3、Alpha blending实现

Alpha有两种模式,一种是全屏Alpha数值,另外一种是Android提供的RGBA数据进行Alpha渲染。


第一种比较简单,如果发现有全屏Alpha值,配置AMB寄存器为刷新全屏alpha,并填上alpha数据,不过我因为三星0值为0x0,而上层为0xff,所以需要做下转换,不过全屏alpha的机会很少,看不出。

第二种就是RGBA8888数据中带有alpha值,这种情况较多,主要体现在界面上。

Android的界面基本是贴两层图,一层为背景图片(RGB565),另外一层为图标(RGBA8888)。

一开始我无论如何配置,屏幕上背景都是黑色,郁闷了很长时间后才发现需要配置AMB寄存器为alpha with bitmap模式,但是驱动里面并没有写这个寄存器


4、Color Format Transform

颜色格式转换,因为screen是RGB565的,如果刷来RGBA8888数据,肯定要进行颜色格式转换,这块2D引擎肯定有支持。

可是,开始配置RGBA8888转RGB565时,发现屏幕是红色的?

调试了很长时间,发现Google Android的RGBA8888竟然是大印第安序的,也就是对应ARM的ABGR8888,这种颜色三星貌似不支持。

手动将颜色转换配置为ARGB8888,发现白色正常,绿色和蓝色反了呵呵,于是写了一个颜色格式软换的函数:

daddr[i] = ((saddr[i]) & 0xFF00FF00) | (((saddr[i])&0xFF)<<16) | (((saddr[i]) & 0xFF0000)>>16);

结果这个函数让界面的效果有所减低,为了这个转换我还用了另外一块PMEM。

昨天看三星Android1.5的内核驱动代码,竟然发现其操作了一个数据手册没有的地址(0x350)omg

在网上一搜,有的头文件将其标记位印第安序转换寄存器,顿时欣喜若狂,这样就支持ABGR颜色格式,不用再软件转换!

试过之后,果然有用,流畅感大升,三星你果然还留了一手啊,或许我看的数据手册太老了。


5、Cache的一致性问题

因为PMEM分配的内存上层也要使用,如果不能被cache,性能会有损失。

但是6410的cache是write back的,也就是不同步在内存中更新。

这样会导致如果图像缓存数据被cache了,屏幕上会出现一些细小的颜色错误。

目前的解决方法是启动2D引擎前flush下cache,不知道能够将cache配置为wirte through,哪个性能损失小呢?


Copybit模块在android2.0以后归OpenGL管理,在libagl中专门有一个copybit.cpp文件对其进 一步封装并进行管理。

当然,也有越狱的时候,这个我们在后面讨论,首先还是看看copybit.cpp。


注意在android.mk中有个宏定义,默认是打开的

#define LIBAGL_USE_GRALLOC_COPYBITS


1、libagl/copybit.cpp

//检查是否有copybit

static bool checkContext(ogles_context_t* c)


//copybit进一步封装

static bool copybit(GLint x, GLint y,

GLint w, GLint h,

EGLTextureObject* textureObject,

const GLint* crop_rect,

int transform,

ogles_context_t* c)

简单工作流程:

1)将texture转换为copybit格式

textureToCopyBitImage(&textureObject->surface, opFormat,textureObject->buffer, &src);

2)如果有alpha值需要倒三次

copybit->stretch(copybit, &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it);

copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);

copybit->stretch(copybit, &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it);

3)else如果没有alpha,只需要做一次

opybit->stretch(copybit, &dst, &src, &drect, &srect, &it);


//Try to draw a triangle fan with copybit画一个三角扇形,是对copybit函数的进一步封装,较复杂

bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)


//Try to drawTexiOESWithCopybit copybit的简单封装

bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)


2、libagl对copybit的调用

1)打开copybit模块

State.cpp


ogles_context_t *ogles_init(size_t extra)

|

hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module)

|

copybit_open(module, ©Bits)

c->copybits.blitEngine = copyBits;



2)操作copybit

Texture.cpp

void glDrawTexsvOES(const GLshort* coords)<----这个是API

void glDrawTexivOES(const GLint* coords)<----这个是API

void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h)<----这个是API

void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h)<----这个是API

|

drawTexiOES(x, y, z, w, h, c);

|

drawTexiOESWithCopybit(x, y, z, w, h, c)

|

drawTexiOESWithCopybit_impl(x, y, z, w, h, c)


void glDrawTexfvOES(const GLfloat* coords)<----这个是API

void glDrawTexxvOES(const GLfixed* coords)<----这个是API

void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h)<----这个是API

void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h)<----这个是API

|

drawTexxOES(x, y, z, w, h, c);

|

drawTexiOESWithCopybit(gglFixedToIntRound(x),

gglFixedToIntRound(y), gglFixedToIntRound(z),

gglFixedToIntRound(w), gglFixedToIntRound(h), c)

|

drawTexiOESWithCopybit_impl(x, y, z, w, h, c);


void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)

|

tex->try_copybit = true;




Array.cpp

void glDrawArrays(GLenum mode, GLint first, GLsizei count) <----这个是API

|

void drawPrimitivesTriangleFan(ogles_context_t* c, GLint first, GLsizei count) <----mode6

|

drawTriangleFanWithCopybit(c, first, count)

|

drawTriangleFanWithCopybit_impl(c, first, count)


3、copybit的越狱?

并不是所有代码都使用了封装好的copybit,也并不是仅有opengl能够使用copybit模块,看看下面的:


1)libagl/egl.cpp 有个copyBIt函数直接用了copybit的blit

void egl_window_surface_v2_t::copyBlt(

android_native_buffer_t* dst, void* dst_vaddr,

android_native_buffer_t* src, void const* src_vaddr,

const Region& clip)

{

// FIXME: use copybit if possible

// NOTE: dst and src must be the same format

status_t err = NO_ERROR;

copybit_device_t* const copybit = blitengine;

if (copybit) {

copybit_image_t simg;

simg.w = src->width;

simg.h = src->height;

simg.format = src->format;

simg.handle = const_cast<native_handle_t*>(src->handle);


copybit_image_t dimg;

dimg.w = dst->width;

dimg.h = dst->height;

dimg.format = dst->format;

dimg.handle = const_cast<native_handle_t*>(dst->handle);

copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);

copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);

copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);

region_iterator it(clip);

err = copybit->blit(copybit, &dimg, &simg, &it);

if (err != NO_ERROR) {

LOGE("copybit failed (%s)", strerror(err));

}

}

//如果没有则是软件处理的

if (!copybit || err) {

Region::const_iterator cur = clip.begin();

Region::const_iterator end = clip.end();

const size_t bpp = pixelFormatTable[src->format].size;

const size_t dbpr = dst->stride * bpp;

const size_t sbpr = src->stride * bpp;


uint8_t const * const src_bits = (uint8_t const *)src_vaddr;

uint8_t * const dst_bits = (uint8_t *)dst_vaddr;


while (cur != end) {

const Rect& r(*cur++);

ssize_t w = r.right - r.left;

ssize_t h = r.bottom - r.top;

if (w <= 0 || h<=0) continue;

size_t size = w * bpp;

uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;

uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;

if (dbpr==sbpr && size==sbpr) {

size *= h;

h = 1;

}

do {

memcpy(d, s, size);

d += dbpr;

s += sbpr;

} while (--h > 0);

}

}

}


2)frameworks\base\libs\surfaceflinger\Layerbuffer.cpp



20100610更新

确认播放视频时会调用到此处,但是传递来的src存在问题,并不包含offset,因此将这块注掉。

void LayerBuffer::onFirstRef()

|

hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module)

|

copybit_open(module, &mBlitEngine);


void LayerBuffer::BufferSource::onDraw(const Region& clip) const

...

#if defined(EGL_ANDROID_image_native_buffer)

if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {

copybit_device_t* copybit = mLayer.mBlitEngine;

if (copybit) {

// create our EGLImageKHR the first time

err = initTempBuffer();

if (err == NO_ERROR) {

// NOTE: Assume the buffer is allocated with the proper USAGE flags

const NativeBuffer& dst(mTempBuffer);

region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));

copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);

copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);

copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);

err = copybit->stretch(copybit, &dst.img, &src.img,

&dst.crop, &src.crop, &clip);


}

} else {

err = INVALID_OPERATION;

}

}

#endif

...


3)还有,比如高通的Gralloc模块里面也用到了copybit

4、调用频率

今天通过插装的方式测试了启动部分各函数对copybit模块调用频率

1)drawTexiOES 99% 主要调用copybit模块的函数

2)egl_window_surface_v2_t::copyBlt 仅有几次调用

3)LayerBuffer::BufferSource::onDraw 没有调用过,不保证以后不调用

总之,看了这么多,先写一个copybit模块试试吧。

btw 编译好的copybit.ky6410.so无法被系统识别?

修改build.prop ro.product.board=ky6410
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: