Xorg屏幕旋转实现方式
正常显示流程
Xorg无旋转时显示流程如下图所示:
FB Root为屏幕对应的帧存,屏幕显示的最终效果渲染到该帧存中。CRTC负责读取FB Root的数据,并按照用户设置的分辨率时序参数进行输出。VGA或者DVI作为output,将CRTC的输出进行A/D转换或者编码后送给显示器显示,对FB Root的更新会实时显示到屏幕上。
旋转显示流程
Xorg带旋转时显示流程如下图所示:
旋转模式下,屏幕显示内容先渲染到FB Root中,然后由Xorg Block Handler(关于Xorg Handler的介绍可以参考另一篇文章:Xorg Handler简介)将FB Root的数据旋转后存入FB Rotate中,CRTC绑定到FB Rotate进行显示。很明显这种情况下,比正常显示多了一个帧存和无休止的旋转操作,而且对FB Root的更新不会实时显示到屏幕上,必须等旋转操作完成后才能显示出最终效果。
驱动对旋转的支持
驱动要支持旋转功能必须要实现以下4个xf86CrtcFuncsRec结构体成员函数:
- shadow_allocate: 负责分配FB Rotate帧存;
- shadow_create: Xorg无法直接操作帧存,该函数创建一个Xorg可操作的Pixmap对象,并将FB Rotate绑定到其中;
- shadow_destroy: 销毁FB Rotate和对应的Pixmap;
- set_mode_major: 初始化旋转参数、安装用于旋转的Block Handler;配置CRTC分辨率,并绑定到FB Rotate;配置output并绑定到CRTC;
xf86CrtcRotate函数
set_mode_major函数中要实现的初始化旋转参数和安装旋转Block Handler由Xorg xf86CrtcRotate函数实现。
该函数先根据屏幕宽高、旋转方向、输入矩阵等参数计算出旋转相关的参数:
Bool
xf86CrtcRotate(xf86CrtcPtr crtc)
{ScrnInfoPtr pScrn = crtc->scrn;xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);ScreenPtr pScreen = xf86ScrnToScreen(pScrn);PictTransform crtc_to_fb;struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;xFixed *new_params = NULL;int new_nparams = 0;PictFilterPtr new_filter = NULL;int new_width = 0;int new_height = 0;RRTransformPtr transform = NULL;Bool damage = FALSE;if (pScreen->isGPU)return TRUE;if (crtc->transformPresent)transform = &crtc->transform;if (!RRTransformCompute(crtc->x, crtc->y,crtc->mode.HDisplay, crtc->mode.VDisplay,crtc->rotation,transform,&crtc_to_fb,&f_crtc_to_fb,&f_fb_to_crtc) &&xf86CrtcFitsScreen(crtc, &f_crtc_to_fb)) {/** If the untranslated transformation is the identity,* disable the shadow buffer*/xf86RotateDestroy(crtc);crtc->transform_in_use = FALSE;free(new_params);new_params = NULL;new_nparams = 0;new_filter = NULL;new_width = 0;new_height = 0;}else {
接着调用驱动的shadow_allocate函数分配FB Rotate帧存:
/* Allocate memory for rotation */
if (old_width != width || old_height != height) {if (shadow || shadowData) {crtc->funcs->shadow_destroy(crtc, shadow, shadowData);crtc->rotatedPixmap = NULL;crtc->rotatedData = NULL;}shadowData = crtc->funcs->shadow_allocate(crtc, width, height);if (!shadowData)goto bail1;crtc->rotatedData = shadowData;/* shadow will be damaged in xf86RotatePrepare */
}
最后将xf86RotateBlockHandler注册成为Screen的Block Handler用于完成旋转:
/* Wrap block handler */
if (!xf86_config->BlockHandler) {xf86_config->BlockHandler = pScreen->BlockHandler;pScreen->BlockHandler = xf86RotateBlockHandler;
}
xf86RotateBlockHandler函数
static void
xf86RotateBlockHandler(ScreenPtr pScreen,void *pTimeout, void *pReadmask)
{ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);/* Unwrap before redisplay in case the software* cursor layer wants to add its block handler to the* chain*/pScreen->BlockHandler = xf86_config->BlockHandler;xf86RotateRedisplay(pScreen);(*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);/* Re-wrap if we still need this hook */if (xf86_config->rotation_damage != NULL) {xf86_config->BlockHandler = pScreen->BlockHandler;pScreen->BlockHandler = xf86RotateBlockHandler;} elsexf86_config->BlockHandler = NULL;
}
xf86RotateBlockHandler先调用xf86RotateRedisplay完成旋转功能,再调用Screen原始的Block Handler,最后判断是否还处于旋转状态,来决定是否继续注册为Screen Block Handler完成后续旋转操作。
xf86RotateCrtcRedisplay函数
xf86RotateBlockHandler调用xf86RotateRedisplay函数进行旋转,xf86RotateRedisplay函数完成一些准备工作后,最后会调用xf86RotateCrtcRedisplay函数完成旋转操作。
static void
xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
{ScrnInfoPtr scrn = crtc->scrn;ScreenPtr screen = scrn->pScreen;WindowPtr root = screen->root;PixmapPtr dst_pixmap = crtc->rotatedPixmap;PictFormatPtr format = PictureWindowFormat(screen->root);int error;PicturePtr src, dst;int n = RegionNumRects(region);BoxPtr b = RegionRects(region);XID include_inferiors = IncludeInferiors;if (crtc->driverIsPerformingTransform)return;src = CreatePicture(None,&root->drawable,format,CPSubwindowMode,&include_inferiors, serverClient, &error);if (!src)return;dst = CreatePicture(None,&dst_pixmap->drawable,format, 0L, NULL, serverClient, &error);if (!dst)return;error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);if (error)return;if (crtc->transform_in_use && crtc->filter)SetPicturePictFilter(src, crtc->filter, crtc->params, crtc->nparams);if (crtc->shadowClear) {CompositePicture(PictOpSrc,src, NULL, dst,0, 0, 0, 0, 0, 0,crtc->mode.HDisplay, crtc->mode.VDisplay);crtc->shadowClear = FALSE;}else {while (n--) {BoxRec dst_box;dst_box = *b;dst_box.x1 -= crtc->filter_width >> 1;dst_box.x2 += crtc->filter_width >> 1;dst_box.y1 -= crtc->filter_height >> 1;dst_box.y2 += crtc->filter_height >> 1;pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &dst_box);CompositePicture(PictOpSrc,src, NULL, dst,dst_box.x1, dst_box.y1, 0, 0, dst_box.x1,dst_box.y1, dst_box.x2 - dst_box.x1,dst_box.y2 - dst_box.y1);b++;}}FreePicture(src, None);FreePicture(dst, None);
}
xf86RotateCrtcRedisplay函数会使用FB Root创建一个源Picture,并设置源的transform和filter属性。使用FB Rotate创建一个目标Picture,最后调用CompositePicture将源融合到目标上去。如果硬件支持这种类型的操作,将会由驱动的Composite函数完成该操作,如果硬件不支持,将会由软件完成。
总结
- 驱动要支持旋转操作,必须要实现上述的4个xf86CrtcFuncsRec结构体成员函数;
- 旋转操作实际由源到目标的Composite操作完成,源带transform和filter属性;
- 旋转操作是持续不断进行的;
- 如果硬件不支持这种类型的Composite,将会由软件实现,性能影响较大;
Xorg屏幕旋转实现方式相关推荐
- iOS 屏幕旋转常用方式
//此方法在进入应用和当屏幕旋转的额时候,会调用 - (UIInterfaceOrientationMask)application:(UIApplication *)application supp ...
- 通过广播获取Android屏幕旋转事件
Android获取系统屏幕旋转的方式有几种,其中比较常见的是通过重写Activity中的onConfigurationChanged方法,但是这种方法有个缺陷,当测试程序在后台运行的时候不能 ...
- ios 旋转屏幕试图切换_总结iOS App开发中控制屏幕旋转的几种方式
在iOS6之前的版本中,通常使用 shouldAutorotateToInterfaceOrientation 来单独控制某个UIViewController的方向,需要哪个viewControlle ...
- iOS传感器:实现一个随屏幕旋转的图片
作者 非典型技术宅 关注 2017.05.24 17:22* 字数 1568 阅读 351评论 7喜欢 14 在写上一个动画系列的时候学到了非常多的知识,也认识了很多人.例如受邀进入了某个神秘的动效组 ...
- Android 设定横屏,禁止屏幕旋转,Activity重置 [更新视频播放器相关]
1. 设定屏幕方向 当指定了屏幕的方向后(非SCREEN_ORIENTATION_UNSPECIFIED),屏幕就不会自己主动的旋转了 有2中方式控制屏幕方向: 1.1 改动AndroidManife ...
- 【Android RTMP】NV21 图像旋转处理 ( 问题描述 | 图像顺时针旋转 90 度方案 | YUV 图像旋转细节 | 手机屏幕旋转方向 )
文章目录 安卓直播推流专栏博客总结 一. NV21 图像格式与 Camera图像传感器方向问题 二. NV21 图像格式视频旋转 1. 图像旋转问题及解决方案 ( 顺时针旋转 90 度 ) 2. NV ...
- Android 屏幕旋转时Activity的变化
Android开发文档上专门有一小节解释这个问题.简单来说,Activity是负责与用户交互的最主要机制,任何"设置"(Configuration)的改变都可能对Activity的 ...
- iOS屏幕旋转 浅析
一.两种orientation 了解屏幕旋转首先需要区分两种orientation 1.device orientation 设备的物理方向,由类型UIDeviceOrientation表示,当前设备 ...
- 怎么设置苹果手机的小圆点_iPhone屏幕旋转怎么设置?关于苹果手机设置的一些小技巧...
阅读本文前,请您先点击上面的"蓝色字体",再点击"关注",这样您就可以继续免费收到文章了.每天都会有分享,都是免费订阅,请您放心关注. 注:本文转载自网络,不代 ...
- IOS6屏幕旋转详解(自动旋转、手动旋转、兼容IOS6之前系统)
转自 http://blog.csdn.net/zzfsuiye/article/details/8251060 概述: 在iOS6之前的版本中,通常使用 shouldAutorotateToInte ...
最新文章
- 快来学习Redis 分布式锁的背后原理
- 手把手教你写移动端瀑布流控件布局篇
- centos升级python_CentOS 升级Python3
- 【AI-1000问】人脸的4个方向,你还分的清楚吗?
- 二十四、数据挖掘时序模式
- php sqlsrv 分页,Php+SqlServer如何实现分页显示
- 逆向so_安卓逆向 | 分析调试与so调用实战
- 搞定面试算法系列 | 分治算法三步走
- 【今日CV 计算机视觉论文速览】Tue, 12 Mar 2019
- c++ 项目_罗纳尔多相信C罗从事技巧类项目,其成就不会亚于他在足坛的成绩
- jmeter 跨线程执行变量
- 通过掌握谷歌成为更好的程序员
- 计算机如何驱动无线网络,笔记本电脑无线网卡驱动怎么安装?
- HTML+CSS+JS实现十款好看的登录注册界面模板,赶紧收藏起来吧!
- TinyPNG压缩图片的网站
- 无法启动此程序 因为计算机中丢失msvcr71.dll,msvcr71.dll丢失怎样修复?计算机中丢失msvcr71.dll的解决方法...
- 对于Linux内核tty设备的一点理解 【转】
- 【安安教具】-【数学】-【一阶线性齐次方程】模拟器 教你如何用python制作一阶线性齐次方程模拟器 python项目小发明
- openwrt procd启动流程和脚本分析
- WiFi温湿度传感器开发
热门文章
- 李沐动手学深度学习V2-RNN循环神经网络原理
- 题目内容: 班级第一次列队,通常老师会让同学按身高排成一列,然后1、2报数,喊到1的同学向前一 步,就这样,队伍就变成两列了。假设现在一个班级有n个同学,并且他们已经按身高排成 了一列,同学按身高从1
- 确定部分分式中待定系数的留数方法
- vue+环信客服前端对接
- 如何在html中加入动图,如何在PS图像中插入动图(gif)?
- 潘悟云方言计算机,山东方言精组与见晓组声母的分合研究
- java clh_AQS基础——多图详解CLH锁的原理与实现
- 电阻电容电感二极管三极管在电路中的作用
- 机器学习:考试预测实战(特征隐射,独热编码,特征重要性选择,网格搜索调参)
- 学之思开源考试系统 - 数据库设计文档