PAD默认屏幕显示方向是竖着显示,改成默认横屏显示需要将屏幕的默认显示方向顺时针旋转90度.
android显示系统的核心是surfaceflinger,它为所有的应用程序提供显示服务,它能够将各种应用程序的2D,3D surface进行组合,合并最终得到的一个main surface数据送入framebuffer,显示的翻转和旋转也是由surfaceflinger完成的,我们大致分析下surfaceflinger的旋转流程:
1.surfaceflinger启动后首先进行初始化操作,设置surfaceflinger的相关属性并创建了DisplayDevice对象
void SurfaceFlinger::init() {
...
#ifdef MTK_AOSP_ENHANCEMENT
// make sure 3D init success
if (mEGLContext == EGL_NO_CONTEXT)
{
ALOGE("FATAL: couldn't create EGLContext");
delete mHwc;
eglTerminate(mEGLDisplay);
exit(0);
}
// init properties setting first
setMTKProperties(); //设置MTK相关属性
#else
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
#endif
...
// initialize our non-virtual displays
for (size_t i=0 ; iisConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
// All non-virtual displays are currently considered secure.
bool isSecure = true;
createBuiltinDisplayLocked(type);
wp token = mBuiltinDisplays[i];
sp producer;
sp consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc());
sp fbs = new FramebufferSurface(*mHwc, i,
consumer);
int32_t hwcId = allocateHwcDisplayId(type);
sp hw = new DisplayDevice(this, //初始化各个DisplayDevice对象
type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
fbs, producer,
mRenderEngine->getEGLConfig());
if (i > DisplayDevice::DISPLAY_PRIMARY) {
// FIXME: currently we don't get blank/unblank requests
// for displays other than the main display, so we always
// assume a connected display is unblanked.
ALOGD("marking display %zu as acquired/unblanked", i);
hw->setPowerMode(HWC_POWER_MODE_NORMAL);
}
mDisplays.add(token, hw);
}
}
}
setMTKProperties()中会设置surfaceflinger的相关属性:
void SurfaceFlinger::setMTKProperties(String8 &result) {
...
// get info for panel physical rotation
property_get("ro.sf.hwrotation", value, "0");
sPropertiesState.mHwRotation = atoi(value);
snprintf(buffer, sizeof(buffer), " ro.sf.hwrotation (mHwRotation): %d\n", sPropertiesState.mHwRotation);
result.append(buffer);
...
}
此处会读取
ro.sf.hwrotation系统属性,这个系统属性决定了显示屏的初始旋转方向,并保存到全局变量sPropertiesState.mHwRotation中DisplayDevice::DisplayDevice(
const sp& flinger,
DisplayType type,
int32_t hwcId,
int format,
bool isSecure,
const wp& displayToken,
const sp& displaySurface,
const sp& producer,
EGLConfig config)(
...
#ifdef MTK_AOSP_ENHANCEMENT
mHwOrientation = DisplayState::eOrientationDefault; //读取默认的显示屏方向
// Name the display. The name will be replaced shortly if the display
// was created with createDisplay().
switch (mType) {
case DISPLAY_PRIMARY:
mDisplayName = "Built-in Screen";
#ifdef MTK_AOSP_ENHANCEMENT
switch (mFlinger->sPropertiesState.mHwRotation) { //读取显示屏初始旋转方向
case 90:
mHwOrientation = DisplayState::eOrientation90;
break;
case 180:
mHwOrientation = DisplayState::eOrientation180;
break;
case 270:
mHwOrientation = DisplayState::eOrientation270;
break;
}
#endif
break;
case DISPLAY_EXTERNAL:
mDisplayName = "HDMI Screen";
break;
default:
mDisplayName = "Virtual Screen"; // e.g. Overlay #n
break;
}
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); //设置显示屏初始旋转方向
}
void DisplayDevice::setProjection(int orientation,
const Rect& newViewport, const Rect& newFrame) {
Rect viewport(newViewport);
Rect frame(newFrame);
const int w = mDisplayWidth;
const int h = mDisplayHeight;
Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
if (!frame.isValid()) {
// the destination frame can be invalid if it has never been set,
// in that case we assume the whole display frame.
frame = Rect(w, h);
}
if (viewport.isEmpty()) {
// viewport can be invalid if it has never been set, in that case
// we assume the whole display size.
// it's also invalid to have an empty viewport, so we handle that
// case in the same way.
viewport = Rect(w, h);
if (R.getOrientation() & Transform::ROT_90) {
// viewport is always specified in the logical orientation
// of the display (ie: post-rotation).
swap(viewport.right, viewport.bottom);
}
}
dirtyRegion.set(getBounds());
#ifdef MTK_AOSP_ENHANCEMENT
// for boot animation black screen issue
if ((false == mFlinger->getBootFinished()) && (DISPLAY_PRIMARY == mType)) {
ALOGI("[%s] clear DisplayDevice(type:%d) dirty region while booting",
__FUNCTION__, mType);
dirtyRegion.clear();
}
#endif
Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
float dst_width = frame.width();
float dst_height = frame.height();
if (src_width != dst_width || src_height != dst_height) {
float sx = dst_width / src_width;
float sy = dst_height / src_height;
S.set(sx, 0, 0, sy);
}
float src_x = viewport.left;
float src_y = viewport.top;
float dst_x = frame.left;
float dst_y = frame.top;
TL.set(-src_x, -src_y);
TP.set(dst_x, dst_y);
#ifdef MTK_AOSP_ENHANCEMENT
// need to take care of HW rotation for mGlobalTransform
// for case if the panel is not installed align with device orientation
if (DisplayState::eOrientationDefault != mHwOrientation) {
DisplayDevice::orientationToTransfrom(
(orientation + mHwOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
}
#endif
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
mGlobalTransform = R * TP * S * TL;
const uint8_t type = mGlobalTransform.getType();
mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
(type >= Transform::SCALE));
mScissor = mGlobalTransform.transform(viewport);
if (mScissor.isEmpty()) {
mScissor = getBounds();
}
mOrientation = orientation;
mViewport = viewport;
mFrame = frame;
}
接着调用DisplayDevice类的orientationToTransfrom()方法构造成一个变换矩阵R,然后得到mGlobalTransform这个全局变换矩阵,最后通过mGlobalTransform.transform()这个方法进行显示的旋转
status_t DisplayDevice::orientationToTransfrom(
int orientation, int w, int h, Transform* tr)
{
uint32_t flags = 0;
switch (orientation) {
case DisplayState::eOrientationDefault:
flags = Transform::ROT_0;
break;
case DisplayState::eOrientation90:
flags = Transform::ROT_90;
break;
case DisplayState::eOrientation180:
flags = Transform::ROT_180;
break;
case DisplayState::eOrientation270:
flags = Transform::ROT_270;
break;
default:
return BAD_VALUE;
}
tr->set(flags, w, h);
return NO_ERROR;
}
这里调用Transform::set()方法设置矩阵,有兴趣可以深入分析