现在的位置: 首页 > 综合 > 正文

Android4.0之显示部分HAL

2014年02月17日 ⁄ 综合 ⁄ 共 6112字 ⁄ 字号 评论关闭

一、原理分析

  Android中显示屏设备被抽象成一个帧缓冲区;Linux内核创建的"/dev/graphics/fb0"设备、就是用来描述系统中的一个帧缓冲区(也就是一个显示屏),Android系统grallocHAL模块封装了对帧缓冲区的所有访问操作。

  grallocHAL模块包含两个设备alloc和fb。

  Android应用程序通过SurfaceFlinger服务操作这两个设备,完成显示;首先通过gralloc设备申请一个图形缓冲区、并将该图形缓冲区映射到应用程序的地址空间,然后通过fb设备将前边已经绘制好的图形缓冲区渲染到帧缓冲区上去、完成显示。

  总结:

1.grallocHAL模块中alloc设备使用结构体alloc_device_t来描述;完成对图形缓冲区的管理:

2.grallocHAL模块中fb设备使用结构体framebuffer_device_t来描述;完成对Linux内核帧缓冲区的管理。

成员函数setSwapInterval用来设置帧缓冲区交换前后两个图形缓冲区的最小和最大时间间隔;

成员函数setUpdateRect用来设置帧缓冲区的更新区域;

成员函数post用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去;

成员函数compositionComplete用来通知fb设备device,图形缓冲区的组合工作已经完成,目前没有使用这个成员函数。

二、服务端调用流程

1.整体流程

frameworks/base/services/surfaceflinger/surfaceflinger.cpp

status_t SurfaceFlinger::readyToRun(){
  DisplayHardware* const hw = new DisplayHardware(this, dpy);
}

frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp

DisplayHardware::DisplayHardware(
        const sp<SurfaceFlinger>& flinger,
        uint32_t dpy)
    : DisplayHardwareBase(flinger, dpy),
      mFlinger(flinger), mFlags(0), mHwc(0)
{
  init(dpy);
}
void DisplayHardware::init(uint32_t dpy){
  mNativeWindow = new FramebufferNativeWindow();
  framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
  ......
  // initialize the H/W composer
  mHwc = new HWComposer(mFlinger);
  if (mHwc->initCheck() == NO_ERROR) {
    mHwc->setFrameBuffer(mDisplay, mSurface);
  }
}

frameworks/base/libs/ui/FramebufferNativeWindow.cpp

FramebufferNativeWindow::FramebufferNativeWindow()
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false){
  hw_module_t const* module;
  if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {  //获得gralloc模块
    err = framebuffer_open(module, &fbDev); //获得gralloc模块下的framebuffer设备,即屏幕
    err = gralloc_open(module, &grDev);  //获得gralloc模块下的gralloc设备,即显存
    // initialize the buffer FIFO
    mNumBuffers = NUM_FRAME_BUFFERS;
    mNumFreeBuffers = NUM_FRAME_BUFFERS;
    mBufferHead = mNumBuffers-1;


    for (i = 0; i < mNumBuffers; i++){
      buffers[i] = new NativeBuffer(fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
    }


    for (i = 0; i < mNumBuffers; i++){
      err = grDev->alloc(grDev,
                        fbDev->width, fbDev->height, fbDev->format,
                        GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); //申请帧缓冲区作为图形缓冲区


      LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
                        i, fbDev->width, fbDev->height, strerror(-err));


      if (err){
        mNumBuffers = i;
        mNumFreeBuffers = i;
        mBufferHead = mNumBuffers-1;
        break;
      }
    }
  }
}

2.fb设备流程

hardware/libhardware/include/hardware/fb.h

static inline int framebuffer_open(const struct hw_module_t* module,
        struct framebuffer_device_t** device) {
    return module->methods->open(module,
            GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
}

hardware/mstar/gralloc/gralloc_module.cpp

struct private_module_t HAL_MODULE_INFO_SYM = {
    base: {
        common: {
            tag: HARDWARE_MODULE_TAG,
            version_major: 1,
            version_minor: 0,
            id: GRALLOC_HARDWARE_MODULE_ID,
            name: "Graphics Memory Allocator Module",
            author: "ARM Ltd.",
            methods: &gralloc_module_methods,
            dso: NULL,
            reserved : {0,},
        },
        registerBuffer: gralloc_register_buffer,
        unregisterBuffer: gralloc_unregister_buffer,
        lock: gralloc_lock,
        unlock: gralloc_unlock,
        perform: NULL,
        reserved_proc: {0,},
    },
    framebuffer: NULL,
    flags: 0,
    numBuffers: 0,
    bufferMask: 0,
    lock: PTHREAD_MUTEX_INITIALIZER,
    currentBuffer: NULL,
};
static struct hw_module_methods_t gralloc_module_methods = {
  open: gralloc_device_open
};
static int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
{
  int status = -EINVAL;


  if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
    status = alloc_device_open(module, name, device);
  } else if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
    status = framebuffer_device_open(module, name, device);
  }
  return status;
}

hardware/mstar/gralloc/framebuffer_device.cpp

int framebuffer_device_open(hw_module_t const* module, const char* name,
                            hw_device_t** device)
{
  private_module_t* m = (private_module_t*)module;
  status = init_frame_buffer(m);
}
static int init_frame_buffer(struct private_module_t* module)
{
  pthread_mutex_lock(&module->lock);
  int err = init_frame_buffer_locked(module);
  pthread_mutex_unlock(&module->lock);
  return err;
}
int init_frame_buffer_locked(struct private_module_t* module)
{
  char const * const device_template[] = {
    "/dev/graphics/fb%u",
    "/dev/fb%u",
    NULL
  };
  int fd = -1;
  int i = 0;
  char name[64];
  while ((fd == -1) && device_template[i]) {
    snprintf(name, 64, device_template[i], 0);
    fd = fbdev_open(name, O_RDWR);
    i++;
  }


  //获得
  struct fb_fix_screeninfo finfo;
  if (fbdev_ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
    return -errno;
  struct fb_var_screeninfo info;
  if (fbdev_ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
    return -errno;
  //设置
  uint32_t flags = PAGE_FLIP;
  if (fbdev_ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
    info.yres_virtual = info.yres;
    flags &= ~PAGE_FLIP;
    LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
  }
  //映射framebuffer
  size_t fbSize = round_up_to_page_size(finfo.smem_len);
  void* vaddr = fbdev_mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  int hw_base = static_cast<int>(unsigned(finfo.smem_start) & MASK_MIU_PHYSADDRESS);
  module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, fbSize, intptr_t(vaddr),
                                               0, hw_base, channel, 0);
}

3.alloc设备流程

其他调用同上,不再分析

hardware/mstar/gralloc/alloc_device.cpp

static int alloc_device_alloc(alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* pHandle, int* pStride)
{
  if (usage & GRALLOC_USAGE_HW_FB)
    err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); //支持双framebuffer时
  else
    err = gralloc_alloc_buffer(dev, size, usage, pHandle);  //不支持时
}

4.alloc渲染到fb

hardware/mstar/gralloc/framebuffer_device.cpp

static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
  if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {  //如果显示设备支持双帧缓冲区,则切换驱动即可完成
    m->base.lock(&m->base, buffer,
                     private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
                     0, 0, m->info.xres, m->info.yres, NULL);


    const size_t offset = hnd->base - m->framebuffer->base;
    m->info.activate = FB_ACTIVATE_VBL;
    m->info.yoffset = offset / m->finfo.line_length;


    if (fbdev_ioctl(0, FBIOPUT_VSCREENINFO, &m->info) == -1) {
      LOGE("FBIOPUT_VSCREENINFO failed");
      m->base.unlock(&m->base, buffer);
      return -errno;
    }
    m->currentBuffer = buffer;
  }esle{ //如果显示设备不支持双帧缓冲区(也就是我们应用使用的图形缓冲区只是一块内存),则完成拷贝
    m->base.lock(&m->base, m->framebuffer,
                     GRALLOC_USAGE_SW_WRITE_RARELY,
                     0, 0, m->info.xres, m->info.yres,
                     &fb_vaddr);


    m->base.lock(&m->base, buffer,
                     GRALLOC_USAGE_SW_READ_RARELY,
                     0, 0, m->info.xres, m->info.yres,
                     &buffer_vaddr);
    //将buffer渲染到framebuffer
    memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);


    m->base.unlock(&m->base, buffer);
    m->base.unlock(&m->base, m->framebuffer);
  }
}

抱歉!评论已关闭.