您的位置:首页 > 移动开发 > Android开发

android屏幕旋转显示流程

2016-10-20 16:17 519 查看
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 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
// set-up the displays that are already connected
if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
// All non-virtual displays are currently considered secure.
bool isSecure = true;
createBuiltinDisplayLocked(type);
wp<IBinder> token = mBuiltinDisplays[i];

sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc());

sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer);
int32_t hwcId = allocateHwcDisplayId(type);
sp<DisplayDevice> 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中

2.DisplayDevice中会调用显示的旋转函数setProjection()

DisplayDevice::DisplayDevice(
        const sp<SurfaceFlinger>& flinger,
        DisplayType type,
        int32_t hwcId,
        int format,
        bool isSecure,
        const wp<IBinder>& displayToken,
        const sp<DisplaySurface>& displaySurface,
        const sp<IGraphicBufferProducer>& producer,
        EGLConfig config)(
<span style="font-family: Arial, Helvetica, sans-serif;">...
</span><pre code_snippet_id="1939821" snippet_file_name="blog_20161020_4_9852155" name="code" class="cpp">#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()方法设置矩阵,有兴趣可以深入分析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: