当前位置: 首页 > news >正文

Android 图像显示框架三——演示demo以及解析

目录

1.应用demo演示

2.应用demo代码解析

上面重点的函数是onFirstRef,详细讲解下此函数:

首先main函数详细解析如下:

1. ​​缓冲区队列管理(核心机制)​​

出队-渲染-入队模式

2. ​​同步机制(Fence系统)​​

3. ​​CPU渲染技术​​

软件渲染实现

4. ​​颜色动画逻辑​​


1.应用demo演示

        首先要知道应用层与SurfaceFlinger如何交互,就要知道应用层用哪些api与SurfaceFlinger进行交互的,最快的方式是实现一个应用与SurfaceFlinger交互的演示demo,演示demo详细流程如下:

Android 12(S) 图像显示系统 - 示例应用(二) - 二的次方 - 博客园

2.应用demo代码解析

上述的demo可以实现一秒钟切换一种颜色,demo中源代码有NativeSurfaceWrapper.h、NativeSurfaceWrapper.cpp、main_NativeSFDemo.cpp三个文件,我们进行详细解析:

首先是NativeSurfaceWrapper.h文件:

/** Copyright (C) 2021 The Android Open Source Project* * Native Surface包装器头文件* 功能:声明用于创建和管理Android Surface的包装类* 该类封装了与SurfaceFlinger交互的复杂逻辑,提供简化的接口*/#ifndef SURFACE_WRAPPER_H
#define SURFACE_WRAPPER_H// BLASTBufferQueue - 现代缓冲区队列实现,用于高效的缓冲区管理
#include <gui/BLASTBufferQueue.h>// IGraphicBufferProducer - 图形缓冲区生产者接口,用于向Surface提交图形数据
#include <gui/IGraphicBufferProducer.h>// Surface相关头文件
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>// 系统窗口相关定义
#include <system/window.h>// RefBase - Android引用计数基类,提供自动内存管理
#include <utils/RefBase.h>namespace android {/*** @brief Native Surface包装器类* * 这个类封装了创建和管理Android Surface的复杂逻辑,提供简化的接口用于:* - 创建全屏Surface* - 配置显示属性(层级、尺寸、格式等)* - 管理图形缓冲区队列* - 与SurfaceFlinger服务交互* * 继承自RefBase,支持Android智能指针系统,实现自动内存管理*/
class NativeSurfaceWrapper : public RefBase {
public:/*** @brief 构造函数* @param name Surface的名称标识,用于调试和日志* @param layerStack 显示层栈ID,默认为0(主显示器)*            用于多显示器配置,指定Surface显示在哪个显示器上*/NativeSurfaceWrapper(const String8& name, uint32_t layerStack=0);/*** @brief 虚析构函数* * 声明为虚函数以确保正确的多态销毁* 使用默认实现,由智能指针系统自动管理资源释放*/virtual ~NativeSurfaceWrapper() {}/*** @brief 首次引用回调函数* * 当对象首次被sp<>智能指针引用时自动调用* 在此方法中完成实际的Surface创建和配置工作,包括:* - 连接SurfaceFlinger服务* - 获取显示器配置信息* - 创建SurfaceControl对象* - 初始化BLASTBufferQueue* - 配置Surface显示属性*/virtual void onFirstRef();/*** @brief 设置图形缓冲区生产者* @param producer 输出的生产者接口引用* * 获取配置好的IGraphicBufferProducer接口,供外部进行图形渲染:* - 从BLASTBufferQueue获取生产者接口* - 配置缓冲区队列参数(如双缓冲设置)* - 连接生产者到Surface*/void setUpProducer(sp<IGraphicBufferProducer>& producer);/*** @brief 获取Surface宽度* @return Surface的像素宽度*/int width() { return mWidth; }/*** @brief 获取Surface高度  * @return Surface的像素高度*/int height() { return mHeight; }private:// 禁止拷贝构造和赋值操作,确保单例性DISALLOW_COPY_AND_ASSIGN(NativeSurfaceWrapper);/*** @brief 根据系统限制调整Surface尺寸* @param width 原始宽度* @param height 原始高度* @return 调整后的尺寸,保持宽高比* * 检查系统属性中的最大图形尺寸限制,防止创建过大的Surface* 系统属性:* - ro.surface_flinger.max_graphics_width* - ro.surface_flinger.max_graphics_height*/ui::Size limitSurfaceSize(int width, int height) const;// 成员变量sp<BLASTBufferQueue> mBlastBufferQueue;  ///< BLAST缓冲区队列,管理图形缓冲区生命周期sp<SurfaceControl> mSurfaceControl;       ///< Surface控制对象,管理Surface属性和状态int mWidth;                               ///< Surface宽度(像素)int mHeight;                              ///< Surface高度(像素)String8 mName;                            ///< Surface名称,用于调试识别uint32_t mLayerStack;                     ///< 显示层栈ID,用于多显示器配置
};} // namespace android#endif // SURFACE_WRAPPER_H

然后来看下NativeSurfaceWrapper.cpp文件的详细解析:

/** Copyright (C) 2021 The Android Open Source Project* * Native Surface包装器实现文件* 功能:封装Surface创建、配置和管理的复杂逻辑*/#define LOG_TAG "NativeSurfaceWrapper"#include <android-base/properties.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <utils/Log.h>#include "NativeSurfaceWrapper.h"namespace android {/*** @brief 构造函数* @param name Surface名称(用于调试识别)* @param layerStack 显示层栈ID*/
NativeSurfaceWrapper::NativeSurfaceWrapper(const String8& name, uint32_t layerStack) : mName(name), mLayerStack(layerStack) {}/*** @brief 首次引用时的初始化回调* * 这是Android智能指针系统的标准模式,在对象首次被sp<>引用时自动调用* 完成Surface创建、显示配置和缓冲区队列初始化等关键操作*/
void NativeSurfaceWrapper::onFirstRef() {// 创建SurfaceComposerClient,建立与SurfaceFlinger服务的连接sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;status_t err = surfaceComposerClient->initCheck();if (err != NO_ERROR) {ALOGD("SurfaceComposerClient::initCheck error: %#x\n", err);return;}// 获取主显示器的标识令牌sp<IBinder> displayToken = SurfaceComposerClient::getInternalDisplayToken();if (displayToken == nullptr) {ALOGE("Failed to get internal display token");return;}// 获取当前显示模式信息(分辨率、刷新率等)ui::DisplayMode displayMode;const status_t error = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);if (error != NO_ERROR) {ALOGE("Failed to get active display mode: %#x", error);return;}// 根据系统限制调整Surface尺寸ui::Size resolution = displayMode.resolution;resolution = limitSurfaceSize(resolution.width, resolution.height);// 创建SurfaceControl对象,管理Surface的生命周期// eFXSurfaceBufferState表示使用现代BufferState图层类型sp<SurfaceControl> surfaceControl = surfaceComposerClient->createSurface(mName,                          // Surface名称resolution.getWidth(),          // 宽度resolution.getHeight(),         // 高度  PIXEL_FORMAT_RGBA_8888,         // 像素格式ISurfaceComposerClient::eFXSurfaceBufferState,  // Surface类型/*parent*/ nullptr              // 父Surface(无));if (surfaceControl == nullptr) {ALOGE("Failed to create surface control");return;}// 配置Surface的显示属性SurfaceComposerClient::Transaction{}.setLayer(surfaceControl, std::numeric_limits<int32_t>::max())  // 设置最高层级(最前面).show(surfaceControl)                                           // 显示Surface.setBackgroundColor(surfaceControl, half3{0, 0, 0}, 1.0f, ui::Dataspace::UNKNOWN) // 黑色背景.setAlpha(surfaceControl, 1.0f)                                 // 不透明度100%.setLayerStack(surfaceControl, mLayerStack)                     // 设置显示层栈.apply();                                                       // 应用所有配置// 保存Surface尺寸信息mWidth = resolution.getWidth();mHeight = resolution.getHeight();// 创建BLASTBufferQueue(BufferQueue的现代实现)// BLAST = Buffer Layout and Surface ControlmBlastBufferQueue = new BLASTBufferQueue("DemoBLASTBufferQueue",        // 队列名称surfaceControl,                // 关联的SurfaceControlresolution.getWidth(),         // 缓冲区宽度resolution.getHeight(),        // 缓冲区高度PIXEL_FORMAT_RGBA_8888        // 缓冲区格式);mSurfaceControl = surfaceControl;  // 保存SurfaceControl引用
}/*** @brief 设置并配置图形缓冲区生产者* @param producer 输出的生产者接口指针* * 配置缓冲区队列的生产者端,供应用进行图形渲染*/
void NativeSurfaceWrapper::setUpProducer(sp<IGraphicBufferProducer>& producer) {// 获取BLASTBufferQueue的生产者接口producer = mBlastBufferQueue->getIGraphicBufferProducer();// 设置最大出队缓冲区数量(双缓冲配置)producer->setMaxDequeuedBufferCount(2);// 连接生产者,注册为CPU渲染客户端IGraphicBufferProducer::QueueBufferOutput qbOutput;producer->connect(new StubProducerListener,  // 空的监听器(简化实现)NATIVE_WINDOW_API_CPU,     // 使用CPU进行渲染false,                     // 不启用生产者受控缓冲&qbOutput                  // 输出队列配置信息);
}/*** @brief 根据系统属性限制Surface尺寸* @param width 原始宽度* @param height 原始高度* @return 调整后的尺寸* * 防止创建过大的Surface消耗过多系统资源,保持宽高比不变*/
ui::Size NativeSurfaceWrapper::limitSurfaceSize(int width, int height) const {ui::Size limited(width, height);bool wasLimited = false;const float aspectRatio = float(width) / float(height);// 从系统属性读取最大允许的图形尺寸int maxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);int maxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);// 如果宽度超过限制,按比例调整高度if (maxWidth != 0 && width > maxWidth) {limited.height = maxWidth / aspectRatio;limited.width = maxWidth;wasLimited = true;}// 如果调整后的高度仍然超过限制,按比例调整宽度if (maxHeight != 0 && limited.height > maxHeight) {limited.height = maxHeight;limited.width = maxHeight * aspectRatio;wasLimited = true;}// 记录尺寸调整日志(调试用)SLOGV_IF(wasLimited, "Surface size has been limited to [%dx%d] from [%dx%d]",limited.width, limited.height, width, height);return limited;
}} // namespace android

上面重点的函数是onFirstRef,详细讲解下此函数:

  1. 创建一个SurfaceComposerClient对象,这个是SurfaceFlinger的Client端,用于和SurfaceFlinger进行跨进程通信的
  2. 进行主显示器token令牌校验以及当前屏幕显示模式信息(分辨率、刷新率等)校验,都校验通过进行下面的流程
  3. 获取屏幕参数,SurfaceComposerClient::getActiveDisplayMode获取当前的DisplayMode,其中可以得到resolution信息,并根据当前系统限制调用limitSurfaceSize函数进行resolution的调整
  4. 创建Surface & SurfaceControl,然后将resolution中获取的宽高信息以及设置像素信息传递给createSurface函数,createSurface函数会进行与SurfaceFlinger进行binder跨进程通信,此时SurfaceFlinger会创建Layer等操作并返回SurfaceControl对象
  5. setLayer,设置视图在当窗口的z-order,最大值则在最前面,SurfaceFlinger根据当前设置的z-order决定窗口的可见性以及显示区域大小
  6. show,让当前的视图显示出来
  7. apply,提交事务,使透过Transaction进行设置的属性生效,一次性调用传递给SurfaceFlinger

然后再来看看main.cpp文件的详细解析:

/** Copyright (C) 2021 The Android Open Source Project* * Native SurfaceFlinger 演示程序 - 主程序文件* 功能:创建一个全屏窗口并循环显示红绿蓝三种颜色*/#define LOG_TAG "NativeSFDemo"#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <hardware/gralloc.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>#include "NativeSurfaceWrapper.h"using namespace android;// 全局控制变量
bool mQuit = false;        // 程序退出标志
int mLayerStack = 0;       // 显示层栈(用于多显示器配置)/*** @brief 使用指定颜色填充RGBA8888格式的图像缓冲区* @param img 指向图像数据的指针* @param width 图像宽度* @param height 图像高度* @param stride 图像行跨度(可能包含填充字节)* @param r 红色分量 (0-255)* @param g 绿色分量 (0-255)* @param b 蓝色分量 (0-255)* * 该函数通过CPU直接写入像素数据,适用于软件渲染场景*/
void fillRGBA8Buffer(uint8_t* img, int width, int height, int stride, int r, int g, int b) {// 遍历每个像素点进行填充for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// 计算当前像素位置(每个像素4字节:RGBA)uint8_t* pixel = img + (4 * (y*stride + x));pixel[0] = r;  // Redpixel[1] = g;  // Greenpixel[2] = b;  // Bluepixel[3] = 0;  // Alpha(设置为0表示不透明)}}
}/*** @brief 主绘制函数,负责图形缓冲区的循环渲染* @param nativeSurface NativeSurfaceWrapper实例* @return 错误状态码* * 实现典型的图形渲染流水线:* 1. 出队缓冲区 → 2. CPU渲染 → 3. 入队显示*/
int drawNativeSurface(sp<NativeSurfaceWrapper> nativeSurface) {status_t err = NO_ERROR;int countFrame = 0;  // 帧计数器,用于颜色循环// 获取图形缓冲区生产者接口sp<IGraphicBufferProducer> igbProducer;nativeSurface->setUpProducer(igbProducer);// 主渲染循环:每秒绘制一帧,直到收到退出信号while(!mQuit) {int slot;           // 缓冲区槽位索引sp<Fence> fence;   // 同步栅栏,确保缓冲区可用sp<GraphicBuffer> buf;  // 图形缓冲区对象// 步骤1: 从生产者队列中获取一个可用的缓冲区igbProducer->dequeueBuffer(&slot, &fence, nativeSurface->width(), nativeSurface->height(),PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,nullptr, nullptr);// 获取对应槽位的缓冲区对象igbProducer->requestBuffer(slot, &buf);// 等待缓冲区就绪(同步操作,避免竞争条件)int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");if (waitResult != OK) {ALOGE("dequeueBuffer_EmptyNative: Fence::wait returned an error: %d", waitResult);break;}// 步骤2: 锁定缓冲区并进行CPU渲染uint8_t* img = nullptr;err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));if (err != NO_ERROR) {ALOGE("error: lock failed: %s (%d)", strerror(-err), -err);break;}// 计算当前帧颜色(红绿蓝循环)countFrame = (countFrame+1)%3;fillRGBA8Buffer(img, nativeSurface->width(), nativeSurface->height(), buf->getStride(),countFrame == 0 ? 255 : 0,  // 红countFrame == 1 ? 255 : 0,  // 绿  countFrame == 2 ? 255 : 0); // 蓝// 解锁缓冲区,提交渲染结果err = buf->unlock();if (err != NO_ERROR) {ALOGE("error: unlock failed: %s (%d)", strerror(-err), -err);break;}// 步骤3: 将渲染完成的缓冲区提交到显示队列IGraphicBufferProducer::QueueBufferOutput qbOutput;IGraphicBufferProducer::QueueBufferInput input(systemTime(),                    // 时间戳true,                            // 自动时间戳HAL_DATASPACE_UNKNOWN,           // 数据空间{},                              // 裁剪区域(全屏)NATIVE_WINDOW_SCALING_MODE_FREEZE, // 缩放模式0,                               // 变换Fence::NO_FENCE                  // 同步栅栏);igbProducer->queueBuffer(slot, input, &qbOutput);// 控制帧率:每秒一帧sleep(1);}return err;
}/*** @brief 信号处理函数,用于优雅退出程序* @param num 信号编号*/
void sighandler(int num) {if(num == SIGINT) {printf("\nSIGINT: Force to stop !\n");mQuit = true;  // 设置退出标志,终止渲染循环}
}/*** @brief 显示程序使用说明* @param me 程序名称*/
static void usage(const char *me)
{fprintf(stderr, "\nusage: \t%s [options]\n""\t--------------------------------------- options ------------------------------------------------\n""\t[-h] help\n""\t[-d] layer stack(In the case of multi-display, NativeSFDemo shows on the specified displays \n""\t                 in addition to the primary display)\n""\t------------------------------------------------------------------------------------------------\n",me);exit(1);
}/*** @brief 解析命令行参数* @param argc 参数个数* @param argv 参数数组*/
void parseOptions(int argc, char **argv) {const char *me = argv[0];int res;while((res = getopt(argc, argv, "d:")) >= 0) {switch(res) {case 'd':mLayerStack = atoi(optarg);  // 设置显示层栈break;case 'h':default:{usage(me);  // 显示帮助信息}}}
}/*** @brief 程序主入口* @param argc 命令行参数个数* @param argv 命令行参数数组* @return 程序退出码* * 程序执行流程:* 1. 解析参数 → 2. 设置信号处理 → 3. 创建Surface → 4. 进入渲染循环*/
int main(int argc, char ** argv) {// 初始化阶段parseOptions(argc, argv);        // 解析命令行参数signal(SIGINT, sighandler);      // 注册Ctrl+C信号处理// 创建Native Surface包装器实例sp<NativeSurfaceWrapper> nativeSurface(new NativeSurfaceWrapper(String8("NativeSFDemo"), mLayerStack));// 进入主渲染循环drawNativeSurface(nativeSurface);return 0;
}

首先main函数详细解析如下:

  1. signal函数注册监听SIGINT信号的handler,注册Ctrl+C信号处理,使其可以优雅的退出程序
  2. 创建NativeSurfaceWrapper对象,并调用drawNativeSurface进行图片的绘制

# 终端默认的键盘信号映射:
Ctrl+C    → SIGINT  (中断进程)
Ctrl+Z    → SIGTSTP (暂停进程)  
Ctrl+\    → SIGQUIT (退出并核心转储)
Ctrl+D    → EOF     (文件结束)

然后来解析下drawNativeSurface函数中执行的流程以及重点内容

首先主要流程如下:

主循环开始
    ↓
dequeueBuffer() 获取空闲缓冲区
    ↓
requestBuffer() 获取缓冲区对象  
    ↓
fence->wait() 等待缓冲区可用
    ↓
buf->lock() 锁定缓冲区
    ↓
fillRGBA8Buffer() CPU渲染颜色
    ↓
buf->unlock() 解锁缓冲区
    ↓
queueBuffer() 提交显示
    ↓
sleep(1) 控制帧率
    ↓
检查mQuit标志 → 继续循环或退出

整体架构图

应用进程 (本程序)
    ↓ 通过igbProducer (Binder IPC)
SurfaceFlinger进程
    ↓ 
显示硬件

具体角色定位

// igbProducer是连接应用和SurfaceFlinger的桥梁
应用层 (Producer) ←→ igbProducer ←→ BufferQueue ←→ SurfaceFlinger (Consumer)
                      (生产者接口)      (缓冲区队列)    (消费者)

重点内容提取:

1. ​​缓冲区队列管理(核心机制)​

出队-渲染-入队模式
// 步骤1:出队缓冲区(获取可用的缓冲区)
igbProducer->dequeueBuffer(&slot, &fence, width, height, format, usage);// 步骤2:获取缓冲区对象
igbProducer->requestBuffer(slot, &buf);// 步骤3:渲染内容到缓冲区
// ... 渲染操作 ...// 步骤4:入队缓冲区(提交显示)
igbProducer->queueBuffer(slot, input, &qbOutput);

​关键技术点​​:

  • ​双缓冲/三缓冲机制​​:避免显示撕裂

  • ​Slot管理​​:缓冲区槽位复用

  • ​生产者-消费者模式​​:解耦渲染和显示

2. ​​同步机制(Fence系统)​

// 等待缓冲区就绪的同步操作
int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");// Fence的作用:
// - 确保GPU已完成对缓冲区的操作
// - 防止CPU和GPU访问冲突
// - 实现渲染流水线的正确同步

​重要概念​​:

  • ​GPU-CPU同步​​:避免资源竞争

  • ​流水线控制​​:保证渲染时序正确

  • ​超时处理​​:waitForevervs wait(带超时)

3. ​​CPU渲染技术​

软件渲染实现
// 等待缓冲区就绪的同步操作
int waitResult = fence->waitForever("dequeueBuffer_EmptyNative");// Fence的作用:
// - 确保GPU已完成对缓冲区的操作
// - 防止CPU和GPU访问冲突
// - 实现渲染流水线的正确同步

​渲染细节​​:

  • ​内存布局​​:RGBA8888格式(每个像素4字节)

  • ​步长(Stride)处理​​:可能包含内存对齐的填充字节

  • ​颜色格式​​:RGBA颜色空间,Alpha通道未使用

4. ​​颜色动画逻辑​

// 简单的颜色循环算法
countFrame = (countFrame+1)%3;
fillRGBA8Buffer(..., countFrame == 0 ? 255 : 0,  // 红countFrame == 1 ? 255 : 0,  // 绿  countFrame == 2 ? 255 : 0); // 蓝

​动画特性​​:

  • ​三色循环​​:红→绿→蓝→红...

  • ​帧率控制​​:每秒1帧(sleep(1))

  • ​状态保持​​:countFrame维护动画状态

上述就是对demo的解析

http://www.dtcms.com/a/568407.html

相关文章:

  • Python实用技巧:批量处理Excel数据并生成销售报表(含实战案例)
  • nodered 下载 excel 文件
  • Java: 如何在Excel中添加或删除分页符?
  • 处理wangEditor编辑器缩进问题
  • linux挂载系统盘[ubuntu22 2025年11月]
  • 如何修改Linux下screenfetch的默认ASCII 艺术logo ?
  • 用于 Liferay 的 ONLYOFFICE 连接器已更新至 3.1.0 版本:升级后的编辑器、图表查看器和更多支持的文件格式
  • 山东正元建设网站企业门户网站开发费用
  • 网站关键词优化的价格软件开发周期
  • 在 Windows 中基于 WSL 子系统 Ubuntu 安装配置 conda 示例
  • 怎么做饲料电商网站网络推广平台cpa
  • php网站本地搭建wordpress 密码 算法
  • 咖啡网站建设设计规划书公众号二次开发
  • 网站建设服务市场分析高中信息技术课网站怎么做
  • 合肥企业建站程序建筑网站图片
  • 泉州网站制作网页名表网站
  • 温州seo网站管理网站建设遇到的问题
  • 泰安市两学一做网站扬州网站开发
  • 图片在线制作加字现在的seo1发布页在哪里
  • 营销网站建设报价付费查看wordpress
  • 天津网站优化公司电话未来网站建设想法
  • 动易6.8网站头怎么做电商卖东西
  • 电子商务网站建设合同wordpress临时关闭站点
  • 建设网站收取广告费用产品宣传短视频
  • 做婚纱摄影网站多少钱企业一站式网站建设
  • 网站中的ppt链接怎么做的大学生网站建设小结
  • 个人网站建设模板企业创建网站
  • 网页站点的用途做网站图
  • 响应式网站开发源码网络强国建设的未来
  • 做视频网站容易收录吗wordpress搭建方案