最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

surface

旗下网站admin7浏览0评论

surface

surface

-

2023年4月28日发(作者:心灰意冷的意思)

【转】android中的surface

默认分类 2010-07-30 10:03:03 阅读780 评论0 字号:大中小

在android中,对view及其子类,都是画在surface上的。每个window

对应一个surface,各surface对象通过surfaceflinger合成到

framebuffer,每个surface都是双缓冲,它有一个back buffer和一

个front buffer。back buffer就是画画的地方,front buffer是用来

合成的。

surface创建Canvas对象(用来管理surface绘图操作),Canvas对应

bitmap(存储surface内容)。当调用unlockCanvas()后,back buffer

开始变为可用,就开始显示了。有一套机制实现back buffer和front

buffer的互换,当要更新时,back buffer与front buffer互换,back

buffer变成front buffer,

流程

- create a bitmap

- attach a canvas to it

- do the rendering into that canvas

- lockCanvas

- draw your bitmap into the backbuffer

- unlockAndPost

frameworks/base/core/java/android/view/ —

Surface::Surface ()创建一个surface

public Surface(SurfaceSession s,

int pid, int display, int w, int h, int format, int

flags)

throws OutOfResourcesException {

mCanvas = new Canvas();

init(s,pid,display,w,h,format,flags);

}

frameworks/base/core/jni/android_view_ —

Surface_init ()。

在这个函数中SurfaceComposerClient 对象被创建。

frameworks/base/libs/ui/

—SurfaceComposerClient::SurfaceComposerClient ()这个函数非常

重要,在这里建立了client和server之间的桥梁。通过函数

_get_surface_manager()获得了一个指向server的IBinder 对象(具

有ISurfaceComposer接口),之后通过这个IBinder就可以跨进程访问

Server的功能。接着调用 ISurfaceComposer::createConnection()创

建并返回了一个ISurfaceFlingerClient的 IBinder。

frameworks/base/libs/ui/

—SurfaceComposerClient::createSurface().这个函数中,利用前面

获得的ISurfaceFlingerClient的IBinder,调用其createSurface接

frameworks/base/libs/surfaceflinger/ —

BClient::createSurface ()。Bclient由ISurfaceFlingerClient派生

而来

frameworks/base/libs/surfaceflinger/ —

SurfaceFlinger:: createSurface()。这个函数为Surface创建一个对

应的Layer。

Android GUI系统:

涉及JAVA框架层的内容:

cs 类 ,对应Skia底层库,提供绘图接口。

e 构建显示界面。

各种UI元素的基类。

es 标准的OpenGL接口。

Pixelflinger是一个底层的工具库。负责像素级别的基本处理。在

system/core/include/pixelflinger/ 和

/system/core/libpixelflinger/

libui是一个Andriod在本地层次的一个框架库,是GUI系统的中枢。

这个库提供接口,其它的库通过类的继承方式来实现。包含颜色格式,

Egl窗口,按键及事件处理,surface,overlay ,camera等多个方面

的定义。

在framework/base/include/ui/ 和framework/base/libs/ui/中。

包含以下部分:

format(颜色格式)部分:需要用pixelflinger中的一些关

于数据格式的定义。头文件为PixelFormat.h

Point.h Region.h Rect.h DispleyInfo.h

Native Windows (本地窗口)部分:主要是实现下个

egl_native_window_t 的类。程序通过调用这个类来完成基本的显示功

能。头文件为: EGLNativeSurface.h EGLDisplaySurface.h

EGLNativeWindowSurface.h

Key/Event(按键和事件处理)部分:系统输入的基础,定义按

键映射,通过Event事件设备来实现系统输入,头文件为:EventHub.h

KeycodeLabels.h KeyCharacterMap.h

Surface(显示界面)部分:本部分定义显示界面较高层次的

接口,包含显示界面的管理功能,头文件为带有Surface字符串的所有

文件,这部分只是定义了Surface部分的框架,具体实现是

SurfaceFlinger。

Overlay(显示部分的叠加层)部分:定义一个叠加的显示输

出层接口,覆盖在主显示层之上,通常用于视频输出,主要在

SurfaceFlinger中实现。头文件为:IOverlay.h Overlay.h

Camera部分:定义摄像头的框架和接口,主要在CameraService

部分实现。头文件为带有Camera定符串的所有文件。

输入输出的接口:(主要和linux驱动打交道的)使用FrameBuffer的

标准显示驱动和标准事件Input驱动,在libui中使用标准方式实现:

1。显示输出的硬件接口:

对于andriod的显示部分,需要实现的接口是

egl_native_window_t,它是一个OpenGL结构,也是给libEGL使用的。

EGLNativeSurface.h定义了类EGLNativeSurface,这个类继承

了egl_native_windows_t.

EGLDisplaySurface.h定义了类EGLDisplaySurface,继承了

EGLNativeSurface,它是最终的实现类。

在所实现的构造函数中调用

mapFrameBuffer()函数对驱动程序进行操作如:

status_t EGLDisplaySurface::mapFrameBuffer()

{

char const * const device_template[] = {

"/dev/graphics/fb%u",

"/dev/fb%u",

0 };

while ((fd==-1) && device_template[i]) {

snprintf(name, 64, device_template[i], 0);

fd = open(name, O_RDWR, 0);

i++;

}

struct fb_fix_screeninfo finfo;

if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)

return -errno;

struct fb_var_screeninfo info;

if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)

return -errno;

void* buffer = (uint16_t*) mmap(

0, _len,

PROT_READ | PROT_WRITE,

MAP_SHARED,

fd, 0);

if (buffer == MAP_FAILED)

return -errno;

// at least for now, always clear the fb

memset(buffer, 0, _len);

//省略了部分内容

2.输入的硬件接口:

对andriod的事件处理部分,主要是向上层提供统一的按键码

(KeyCode),是一个整数,上层的Java程序中主要通过这个值来判断

系统的实现。在libui中通过对标准的Input驱动的处理来将input值

转换成andriod系统的按键码,按键码参考KeyCharacterMay.h头文件。

文件是输入部分的硬件抽象定义设备节点所在的路

径。

Static const char *device_path = “/dev/input”; //输入

设备目录

处理过程中将搜索路径下面所有input驱动设备节点,这在

openPlatformInput()中通过调用scan_dir()来实现,scan_dir()将会

从目录中查找设备,找到后调用open_device()将其打开。

bool EventHub::openPlatformInput(void)

{

//省略了部分内容

res = scan_dir(device_path);

if(res < 0) {

LOGE("scan dir failed for %sn", device_path);

//open_device("/dev/input/event0");

}

return true;

}

主要事件处理有getEvent()中完成,处理过程是在一个无限循环

内,调用阻塞的函数等待事件到来。

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,

int32_t* outScancode, int32_t* outKeycode, uint32_t

*outFlags,

int32_t* outValue, nsecs_t* outWhen)

{

while(1) {

//省略了部分内容

for(i = 1; i < mFDCount; i++) {

if(mFDs[i].revents) {

if(mFDs[i].revents & POLLIN) {

res = read(mFDs[i].fd, &iev, sizeof(iev));

}

//省略了部分内容

}

}

poll()函数会阻塞程序的运行,直到Input设备的相应事件发生,事

件发生后poll()将返回,然后通过read()读取input设备发生的

事件代码。

实现事件处理实际经过两个步骤:

1,将input设备的整数类型事件转换成表示按键的字条串。

2。将表示按键的字符串转换成android的按键码。

键盘布局文件(*.kl)将完成第一步转换,运行时的文本文件在

system/usr/keylayout目录中。

源文件的development/emulator/keymaps/目录中有多个布局文

件。

第二步是通过查找KEYCODES数组,将literal字符串转换成value

的整数值。

(在keyCharacterMap.h文件中KEYCODES表示的数值和

nt类中数值是一致的,这个java类的路径为

frameworks/base/core/java/android/view/)

开发过程中对不同的硬件,只要定不同的键盘布局文件就OK了。

Android中一般不需要增加新的按键码。

(在andriod的输入处理经过了两次映射,第一次将Event驱动中的整

数按键码映射成字符串,第二次将字符串映射成Java的UI 程序中使用

的整数值。如要增加按键在用户程序 中进行处理除了

KeyCharacterMap.h和两个文件 ,还要改两个文件

tools/puppet_master/_和

frameworks/base/core/res/res/values/

Surface系统:

包括本地代码和java代码部分,关系如下:

libui提供本地的Surface系统框架

surfaceflinger完成本地接口实现

java框架层次主要调用Surface向UI 提供接口

本地部分可以使用ISurface接口。

Surface系统本地接口

在libui中定义Surface的本地接口,路径

frameworks/base/include/ui,主要有以下几个文件;

Surface.h

SurfaceComposerClient.h

ISurface.h

ISurfaceFlingerClient.h

IsurfaceComposer.h

Surface.h和 SurfaceComposerClient.h是为上层提供的调用接口通过

surface系统的JNI提供给java层使用。ISurface.h

IsurfaceFlingerClient.h IsurfaceComposer.h 是需要下层去继承和

实现的接口,其中 Isurface.h 中的接口可以给本地程序来调用,进而

实现图形数据输出功能。

在isurfaceComposeer.h接口中,定义了Surface系统的各种枚举值和

接口,

class ISurfaceComposer : public IInterface

{

public:

DECLARE_META_INTERFACE(SurfaceComposer);

enum { // (keep in sync with )

eHidden = 0x00000004,

//省略了部分内容

};

//省略了部分内容

调用createConnection()接口将构建一个ISurfaceFlingerClient,而

eFXSurfaceNormal eFXSurfaceBlur eFXSurfaceDim 和

eFXSurfaceMask 表示不同类型的Surface层次,它们和java代码是对

应的(对应文件)

SurfaceFlinger本地代码:

SurfaceFlinger是Surface的本地实现。实现Surface的建立。控制,

管理等功能。其路径为:

frameworks/base/libs/surfaceflinger

在surfaceFlinger.h和 文件中,

SurfaceFlinger类继承IsurfaceComposer,是一个核心的实现。

SurfaceFlinger::BClient类继承了ISurfaceFlingerClient。另一个

重要的部分就是提供不同的层(layer),用于构建不同的显示界面。

在surfaceflinger内部有一个表示surface层次的类,就是LayerBase,

它提供了与上层相关的通用接口,LayerBaseClient继承LayerBase,

而LayerBaseClient的内部类Surface又继承Bnsurface。

这个LayBaseClient是各种层的一个基类,它被以下其它几个类继承:

Layer,LayerBuffer,LayerDim,和LayerBlur。这几个类则表示了几

种不同的“层”,

以上几个类中,LayerBuffer中的surfaceBuffer继承了本地的

ISurface接口,也就是说,本地使用的ISurface接口在android的图

形系统中只有LayerBuffer中的一个实现。

在上层的程序调用过程中,创建一个surface过程如下:

1。调用libui接口SurfaceComposerClient::createSurface();

2。调用ISurfaceFlingerClient::creatSurface();

3。由于继承关系,实际上调用 的是SurfaceFlinger中的接口,

即BClient::creatSurface();

4。继续调用SurfaceFlinger::createSurface()函数,其处理过

程如下:

sp SurfaceFlinger::createSurface(ClientID clientId,

int pid,

ISurfaceFlingerClient::surface_data_t* params,

DisplayID d, uint32_t w, uint32_t h, PixelFormat format,

uint32_t flags)

{

LayerBaseClient* layer = 0;

sp surfaceHandle;

Mutex::Autolock _l(mStateLock);

Client* const c = or(clientId);

if (UNLIKELY(!c)) {

LOGE("createSurface() failed, client not found (id=%d)",

clientId);

return surfaceHandle;

}

//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);

int32_t id = c->generateId(pid);

if (uint32_t(id) >= NUM_LAYERS_MAX) {

LOGE("createSurface() failed, generateId = %d", id);

return surfaceHandle;

}

switch (flags & eFXSurfaceMask) {

case eFXSurfaceNormal:

if (UNLIKELY(flags & ePushBuffers)) {

layer = createPushBuffersSurfaceLocked(c, d,

id, w, h, flags);

} else {

layer = createNormalSurfaceLocked(c, d, id, w,

h, format, flags);

}

break;

case eFXSurfaceBlur:

layer = createBlurSurfaceLocked(c, d, id, w, h,

flags);

break;

case eFXSurfaceDim:

layer = createDimSurfaceLocked(c, d, id, w, h,

flags);

break;

}

if (layer) {

setTransactionFlags(eTransactionNeeded);

surfaceHandle = layer->getSurface();

if (surfaceHandle != 0)

surfaceHandle->getSurfaceData(params);

}

return surfaceHandle;

}

创建surface时,调用 createSurface(),创建各个层后,分别调用

不同层中的getSurface()接口来得到一个ISurface类型的实例,然

后在SurfaceComposerClient::createSurface()中得到surface并

将其返回。

实际是根据参数flags选择使用不同的层:eFXSurfaceNormal对应的层

是Layer,LayerBuffer; eFXSurfaceBlur对应的层是LayerBlur;

eFXSurfaceDim对应 的层是LayerDim。

如果将参数指定为普通,一般情况下会建立Layer类,当ePushBuffers

为真时才会建立LayerBuffer类。建立 Layer和LayerBuffer分别调用

的是createNormalSurfaceLocked()函数和

createPushBufferSurfacLocked()函数。

createNormalSurfaceLocked()先要建立一个Layer类,再向其中设

置一个Buffer,然后增加层。

createPushBufferSurfacLocked()情况比较简单,只要建立 一个

LayerBuffer的类将其加入层即可。

二者的区别是:LayBuffer是一个push类型的层,通常要使用队列的方

式将显示的内容“推”入其中,Layer是一个普通 的层,建立时要将一

个内存设置到其中 。

以设置大小 为例 ;

对一个Surface进行设置的过程如下:

1,调用libui的surface接口 setSize();

2, 实际调用 的是surfacecomposerClient::setSize(),在其

中的参数surface的大小,并将其成员what设置为eSizeChanged。

3, 由于逻辑关系,由IsurfaceFlingerClient::setState()函

数进行处理。

4,由于继承关系,实际调用 的是类SurfaceFlinger中的

BClient::setState()。

5, 进一步调用surfaceFlinger::setClientState()函数。

在代码处理中,根据不同的状态变化命令来进行处理,最终调用的是各

个“层”的setSize()函数,之后的内容由几个层的不同实现来进行

处理。

Surfaceflinger和显示硬件的接口

显示设备由DisplayHardware目录中的文件来实

现的,其中创建了一个DisplayHardware来作为主要的显示界面。

mDisplaySurface = new EGLDisplaySurface();

EGLDisplaySurface类是在libui中实现的,它直接操作FrameBuffer

的硬件驱动。在中,将创建类DisplayHardware

为实例,从而获取实际的显示设备,在上面进行显示输出。

此外,surfaceflinger可以使用可选的硬件模块copybit作为2D图形

处理部分的加速器。这部分的接口在

frameworks/base/include/core/java/android/hardware目录的

copybit.h文件定义 的相关接口。作为硬件模块使用,这个模块在

DisplayHardware初始化的过程中被打开。

Surface的java和JNI代码

Surface部分的JNI代码路径是:

frameworks/base/core/jni/android_view_

它主要提供了eSession和

e两个java类,分别调用SurfaceComposerClient

和Surface两个本地类来完成实现。

Surface部分的Java代码的路径是:

frameworks/base/core/java/android/view/

由此对应的java类在包中,除了上面提到的类

surfaceSession和Surface之外,与其相关的还有接口SurfaceHolder

和类SurfaceView。

e 表示一个可以绘制图形的界面,它实际上是调

用 底层的Surface接口来实现控制的硬件载体。

实际上,在java框架中,所有UI元素的基类都是,

这些UI元素本身也是基于Surface及2D绘图函数来实现的,如果要在

java程序中使用一个可以进行自由绘制的界面,那么就需要使用类

eView,这个类也继承了,因此

也是android中的一个UI元素,eHolder是

eView 中包含的一个接口,用于处理Surface相

关的事件。

(中定义的整数常量和本地的ISurfaceComposer.h是具

有对应关系的)

Skia和2D图形系统:

skia是一个C++本地代码库,路径为external/skia/

包含3个库

Core Cg 核心图形库:

GL (Skia 图形库):

skia-opengl glue library :

核心库是它是skia中最基础的库,其源代码主要在

src/core/目录中,提供一系列基本功能,

Skia 图形库:是skia系统主要的库,它包含移植层,图

形绘制,图像编解码,效果等方面内容。其源代码主要在src/effects ,

src/images/ , src/ports/, src/core/ , src/utils/ 目录 中。

需要连接,以及被其调用 的图像的编解码

库,字体处理的库等。

是skia和OpenGL 相关联的库,其源代码在src/gl目录

中。

skia对上层有众多的接口,接口头文件在include目录 中,skia 的

API中最主要的SKCavans类,这个类提供了众多的绘制功能。事实上,

整个android的GUI系统的底层绘制,就是这个类来完成的。其头文件

和源代码路径分别是:include/core/SkCavans.h 和

src/core/

SkCanvas 类有两个构造函数,其参数类型分别是SkBitmap和

SkDevice,分别表示Skia进行绘制的目标。事实上,Skia的基本功能 就

是一个绘制工具,这个绘制工具和绘制的目标是无关的。SkBitmap可以

视为一个表示位图区域的内存,除了一般的内存首指针和大小 之外,

还包括宽,高和像素格式等信息,在这块内存上,可以进行skia图形

系统的绘制工作。

SkCanvas的主要绘制功能有3种: 基本图形绘制 (如drawARGB ,

drawLine 函数)图像文件绘制(如drawBitmap函数)和文本绘制(如

drawText函数).

Skia的图像编码部分:

skia的图像编码部分是一个相对独立 的部分,其接口分别在

include/image目录下的SkImageDecoder.h 和skImageEnc

oder.h中定义:

SkImageDecoder既可以作为动态类使用,又可以使用静态函数,也支持

同步和异步方式解码,它可以把图像文件或者流解码到skia的内部内

存SkBitmap中。

SkImageEncoder和解码器类似,完成 的是编码工作,

skia的解码器和编码器都是接口,需要具体的类去实现,在src/images

中的几个源文件通过继承SkImageDecoder和SkImageEncoder来实现解

码器和编码器,如 SkImageDecoder_ 通过调用libjpeg 库

实现了JPEG的解码。

如有其它 的解码器和编码器,也可以通过 SkImageEncoder和

SkImageDecoder的类来实现。

Android图形系统的JNI接口

android图形系统和skia底层库联系比较紧密,android图形系统的JNI

提供 了从skia底层到java层的支持,JNI代码路径为:

frameworks/base/core/jni/android/grphic/

是JNI中的核心接口,为java上层的

类提供了支持,其中 ,initRaster()和

initGL()两个函数将和Skia本地库联系起来。即通过建立skia本地

库的Cavvas来建立给java层使用的Canvas,除此外,图形JNI还通过

JNI接口,提供 , ,

e , 等多个java

类的支持,这一般调用的是skia中同名文件中的函数。

Android的图形包:

android图形类的包是cs它通过调用图形系统的JNI

提供了对java框架中的图形系统的支持,代码路径为:

frameworks/graphic/java/android/graphics/

定义了android图形系统中最为重要的一个类:

. Canvas类处理“draw“的调用,当绘制

(draw)内容时需要4个基本组件,一个保持像素的Bitmap,一个处理

绘制调用 的canvas(写入Bitmap),绘制 的内容(如,Rect,Path,

text,Bitmap)和一个paint(用开描述颜色和样式)。文

件实现了类, 它表示内存中的一个位图。

Canvas是一个比较基础的图形类,android中的UI 元素也是通过调用

Canvas类来构建的。在文件 中,实现的类是

, 通过建立这个Canvas类来构建绘画的基础。

Android系统的OpenGL系统与3D图形系统

分本地代码和java框架代码两部分。

本地代码实现OpenGL接口的库,java框架层,

es是java标准的OpenGL包。

本地整体结构:

主要内容在frameworks/base/opengl/中,本地代码头文件 路径为:

frameworks/base/opengl/include/EGL/

frameworks/base/opengl/include/GLES/

源代码目录:

frameworks/base/opengl/libagl/

frameworks/base/opengl/libs/

编绎后生成3个库:

libGLESv1_: OpenGL Es库的封装,对应libs/GLES_CM目录

中的文件

:EGL库,OpenGL Es库的封装,对应libs/EGL目录 中

的文件

: OpenGL的软件实现库,对应libagl目录中的文件。

Android的OpenGL实现方式:

OpenGL本地库可使用软件库和硬件库这两种不同的 方式来实现。如果

是软件实现,则用库,如果是硬件实现,则使用

库。

在libs/EGL/文件中,选择使用这两个库中的一个,主要操作

在eglGetDisplay()函数中实现。

load_driver()函数实际上将通过dlopen()方式打开库,默认先去找

OpenGL的软件实现当设置使用OpenGL的硬件实现(在

中设置属性)时,则使用OpenGL的硬件实现

.然后用dlsysm方式打开其中支持API的符号,

gl_hooks_t 结构描述了OpenGL系统所支持的各种API。实际的符号将

在gl_和egl_两个文件中定义。各种函数以

GL_ENTRY和EGL_ENTRY的方式来进行描述。

Android的openGL的本地测试代码:

路径为:frameworks/base/opengl/tests 包含几个独立 的测试程序,

openGL的JNI代码:

openGL向上提供的JNI接口,主要由以下两个文件提供:

frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.c

pp

frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.

cpp

这是包_jni中的两个类,分别是EGLImpl和

GLImpl,分别对应egl和gl的实现。

其中,EGLImpl中的各个接口负责一些管理功能,而GLImpl中的各个接

口对应于OpenGL的GLES/gl.h头文件中定义的各个OpenGL功能函数。

OpenGL的java类

在andriod中使用openGL常要结合使用

es和包。

实现方法是使用一个类来继承OpenGL java的标准类,通过实现这个类

来实现,在java层只要使用标准类。

OpenGL 的java类是javax中的一部分,这个包是

s路径为:

opengl/java/javax/microedition/khronos/egl/

opengl/java/javax/microedition/khronos/opengles/

在egl类中主要的文件是 和 ;在opengles中主

要的文件 是;

android 使用继承的方法实现opengl这个继承的包为

_jni 其路径为:

opengl/java/com/google/andriod/gles_jni/

事实上,EGLImpl和GLImpl的大部分函数是通过JNI调用本地的OpenGL

程序来实现的。

在java应用层不会调_jni包中的类,只会

调用标准包es中的接口。

另个,包提供了openGL的标准接口到android系统的

媒介,路径为:

opengl/java/android/opengl/

其中主要的类调用_jni包中的类和android

的基础GUI系统的类实现GLSurfaceView

GLSurfaceView继承了SurfaceView。 surfaceView又继承View,因此

GLSurfaceView本身也是个UI元素,在android的java应用程序层使

用OpenGL,具体的实现其实是继承GLSurfaceView类并调用OpenGL标

准的接口。

-

windows平板电脑

发布评论

评论列表(0)

  1. 暂无评论