顯示框架之SurfaceFlinger Refresh流程

當(dāng)有事務(wù)的更新或者有Buffer的更新便會(huì)觸發(fā)后面刷新的流程帽揪。

onMessageRefresh

文件:frameworks/native/services/surfaceflinger/Surfaceflinger.cpp
void SurfaceFlinger::onMessageRefresh() {
    ATRACE_CALL();

    mRefreshPending = false;

    compositionengine::CompositionRefreshArgs refreshArgs;
    const auto& displays = ON_MAIN_THREAD(mDisplays);
     // display 的數(shù)量锈玉,把當(dāng)前displaydevice 記錄下來
    refreshArgs.outputs.reserve(displays.size());
    for (const auto& [_, display] : displays) {
        refreshArgs.outputs.push_back(display->getCompositionDisplay());
    }
    // 把當(dāng)前l(fā)ayer記錄下來
    mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
        if (auto layerFE = layer->getCompositionEngineLayerFE())
            refreshArgs.layers.push_back(layerFE);
    });
    // 把當(dāng)前有queueframe的layer記錄下來, 有Buffer的layer
    refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
    for (sp<Layer> layer : mLayersWithQueuedFrames) {
        if (auto layerFE = layer->getCompositionEngineLayerFE())
            refreshArgs.layersWithQueuedFrames.push_back(layerFE);
    }
 
    ...
    // 主要邏輯在present里面
    mCompositionEngine->present(refreshArgs);
   }

刷新的主要邏輯在present里面。

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp

void CompositionEngine::present(CompositionRefreshArgs& args) {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);
    // 根據(jù)是否還有l(wèi)ayer沒有消費(fèi)掉炕贵,判斷再調(diào)起一次刷新
    preComposition(args);

    {
        // latchedLayers is used to track the set of front-end layer state that
        // has been latched across all outputs for the prepare step, and is not
        // needed for anything else.
        LayerFESet latchedLayers;

        for (const auto& output : args.outputs) {
            // 計(jì)算各個(gè)區(qū)域大小以及創(chuàng)建hwc layer
            output->prepare(args, latchedLayers);
        }
    }
    // 更新layerCompositionState
    updateLayerStateFromFE(args);

    for (const auto& output : args.outputs) {
        // 邏輯在output.cpp的present里面
        output->present(args);
    }
}

prepare主要的作用是計(jì)算各個(gè)區(qū)域大小以及創(chuàng)建hwc layer策菜,主要邏輯在ensureOutputLayerIfVisible 里面褥芒。

ensureOutputLayerIfVisible

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE,
                                        compositionengine::Output::CoverageState& coverage) {
    ...
    /*
     * opaqueRegion: area of a surface that is fully opaque.
     */
    Region opaqueRegion;

    /*
     * visibleRegion: area of a surface that is visible on screen and not fully
     * transparent. This is essentially the layer's footprint minus the opaque
     * regions above it. Areas covered by a translucent surface are considered
     * visible.
     */
    Region visibleRegion;

    /*
     * coveredRegion: area of a surface that is covered by all visible regions
     * above it (which includes the translucent areas).
     */
    Region coveredRegion;

    /*
     * transparentRegion: area of a surface that is hinted to be completely
     * transparent. This is only used to tell when the layer has no visible non-
     * transparent regions and can be removed from the layer list. It does not
     * affect the visibleRegion of this layer or any layers beneath it. The hint
     * may not be correct if apps don't respect the SurfaceView restrictions
     * (which, sadly, some don't).
     */
    Region transparentRegion;

    /*
     * shadowRegion: Region cast by the layer's shadow.
     */
    Region shadowRegion;
    ....
    // 創(chuàng)建OutputLayer
    auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
    ...
 }

各個(gè)layer區(qū)域的計(jì)算結(jié)果可以通過adb shell dumpsys SurfaceFlinger看到,通過區(qū)域的計(jì)算把區(qū)域?yàn)榭盏膌ayer過濾掉


區(qū)域.png

ensureOutputLayer將創(chuàng)建Output layer猾普,這些layer最后是要顯示到屏幕上的袜炕。

文件: frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h

OutputLayer* ensureOutputLayer(std::optional<size_t> prevIndex,
                                       const sp<LayerFE>& layerFE) {

            // 判斷當(dāng)前的outputlayer 集合里面有沒有當(dāng)前的layer,如果沒有則新創(chuàng)建一個(gè)
            auto outputLayer = (prevIndex && *prevIndex <= mCurrentOutputLayersOrderedByZ.size())
                    ? std::move(mCurrentOutputLayersOrderedByZ[*prevIndex])
                    : BaseOutput::createOutputLayer(layerFE);
            auto result = outputLayer.get();
            mPendingOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
            return result;
        }


文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Display.cpp

std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
        const sp<compositionengine::LayerFE>& layerFE) const {
    auto result = impl::createOutputLayer(*this, layerFE);

    if (result && mId) {
        auto& hwc = getCompositionEngine().getHwComposer();
        auto displayId = *mId;
        // 創(chuàng)建hwclayer
        auto hwcLayer = std::shared_ptr<HWC2::Layer>(hwc.createLayer(displayId),
                                                     [&hwc, displayId](HWC2::Layer* layer) {
                                                         hwc.destroyLayer(displayId, layer);
                                                     });
        ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s",
                 getName().c_str());
        // 更新state.hwc
        result->setHwcLayer(std::move(hwcLayer));
    }
    return result;
}

可以看到prepare主要的作用是遍歷layer計(jì)算各個(gè)區(qū)域大小抬闷,過濾掉空區(qū)域的layer以及創(chuàng)建hwc layer妇蛀。

updateLayerStateFromFE

更新OutputlayerState的參數(shù),即layer的狀態(tài)信息笤成。

文件:frameworks/native/services/surfaceflinger/Layer.cpp

void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {
    using StateSubset = compositionengine::LayerFE::StateSubset;

    switch (subset) {
        case StateSubset::BasicGeometry:
            prepareBasicGeometryCompositionState();
            break;

        case StateSubset::GeometryAndContent:
            prepareBasicGeometryCompositionState();
            prepareGeometryCompositionState();
            preparePerFrameCompositionState();
            break;

        case StateSubset::Content:
            preparePerFrameCompositionState();
            break;

        case StateSubset::Cursor:
            prepareCursorCompositionState();
            break;
    }
}

這部分也可以通過adb shell dumpsys SurfaceFlinger看出來有哪些屬性评架。



接下來看下present的邏輯。

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);
     //設(shè)置 Display的dataspace, colormode
    updateColorProfile(refreshArgs);
    // 設(shè)置outputlayer的dispFrame和sourceCrop等以及將outputlayer屬性設(shè)給hwc
    updateAndWriteCompositionState(refreshArgs);
    // 設(shè)置display的顏色矩陣炕泳,對(duì)全屏有效
    setColorTransform(refreshArgs);
    // FrameBuffer里面沒做啥操作
    beginFrame();
     // 選擇合成策略纵诞,判斷是device還是GPU合成,如果是device合成培遵,直接present浙芙,如果要走GPU合成則需要validate
    prepareFrame();
    // 一般不走
    devOptRepaintFlash(refreshArgs);
    // GPU合成主要邏輯在此登刺,device合成沒做啥
    finishFrame(refreshArgs);
    // device合成設(shè)置release fence,GPU合成需要present給hwc
    postFramebuffer();
}

先關(guān)注device合成嗡呼,涉及GPU部分單獨(dú)分析纸俭。

updateAndWriteCompositionState

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::updateAndWriteCompositionState(
        const compositionengine::CompositionRefreshArgs& refreshArgs) {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);

    if (!getState().isEnabled) {
        return;
    }

    mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition();
    // 如果是有背景模糊的layer則強(qiáng)制使用GPU合成
    bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr;

    for (auto* layer : getOutputLayersOrderedByZ()) {
        // 遍歷outputlayer,計(jì)算DisplayFrame南窗, SourceCrop 等參數(shù)
        layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
                                      refreshArgs.devOptForceClientComposition ||
                                              forceClientComposition,
                                      refreshArgs.internalDisplayRotationFlags);

        if (mLayerRequestingBackgroundBlur == layer) {
            forceClientComposition = false;
        }

        // 將layer屬性設(shè)給hwc
        layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
    }

這部分參數(shù)也可以通過adb shell dumpsys SurfaceFlinger看到


屏幕顯示區(qū)域.png

setColorTransform

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Display.cpp

void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
    Output::setColorTransform(args);

    if (!mId || CC_LIKELY(!args.colorTransformMatrix)) {
        return;
    }

    auto& hwc = getCompositionEngine().getHwComposer();
    // 將上層設(shè)的colorTransformMatrix 設(shè)給hwc揍很,這個(gè)效果作用于全屏,比如護(hù)眼模式下万伤,改變的就是這個(gè)colorTransformMatrix
    status_t result = hwc.setColorTransform(*mId, *args.colorTransformMatrix);
    ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
             mId ? to_string(*mId).c_str() : "", result);
}

setColorTransform 設(shè)置顏色矩陣給屏幕窒悔,作用于屏幕顯示,所有的layer都受影響敌买,護(hù)眼效果就是改變的這個(gè)值简珠。

prepareFrame

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::prepareFrame() {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);

    const auto& outputState = getState();
    if (!outputState.isEnabled) {
        return;
    }
    // 選擇合成類型,如果是device合成虹钮,則跳過validate聋庵,直接present送顯
    chooseCompositionStrategy();
    // 把合成類型送到frameBufferSurface,沒啥邏輯
    mRenderSurface->prepareFrame(outputState.usesClientComposition,
                                 outputState.usesDeviceComposition);
}

void Output::chooseCompositionStrategy() {
    // The base output implementation can only do client composition
    // 默認(rèn)使用GPU合成,針對(duì)沒有hwc的設(shè)備
    auto& outputState = editState();
    outputState.usesClientComposition = true;
    outputState.usesDeviceComposition = false;
    outputState.reusedClientComposition = false;
}

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Display.cpp

void Display::chooseCompositionStrategy() {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);

    // Default to the base settings -- client composition only.
    Output::chooseCompositionStrategy();

    // If we don't have a HWC display, then we are done
    if (!mId) {
        return;
    }

    // Get any composition changes requested by the HWC device, and apply them.
    std::optional<android::HWComposer::DeviceRequestedChanges> changes;
    auto& hwc = getCompositionEngine().getHwComposer();
    // 從HWC device獲得合成類型的改變芜抒,這個(gè)根據(jù)hwc能力來選擇device還是GPU合成
    if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
                                                          &changes);
        result != NO_ERROR) {
        ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
              strerror(-result));
        return;
    }
    //如果有變化則設(shè)置給對(duì)應(yīng)的layer
    if (changes) {
        applyChangedTypesToLayers(changes->changedTypes);
        applyDisplayRequests(changes->displayRequests);
        applyLayerRequestsToLayers(changes->layerRequests);
        applyClientTargetRequests(changes->clientTargetProperty);
    }

    // Determine what type of composition we are doing from the final state
    // 決定最后的合成類型
    auto& state = editState();
    state.usesClientComposition = anyLayersRequireClientComposition();
    state.usesDeviceComposition = !allLayersRequireClientComposition();
}

文件:frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

status_t HWComposer::getDeviceCompositionChanges(
        DisplayId displayId, bool frameUsesClientComposition,
        std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
    ATRACE_CALL();

    ...
    if (!frameUsesClientComposition) {
        sp<Fence> outPresentFence;
        uint32_t state = UINT32_MAX;
         // 如果所有的layer都能走device合成珍策,則在hwc里面直接present,若有不支持device合成的情況宅倒,則走GPU合成攘宙,會(huì)走validate邏輯
        error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
        if (!hasChangesError(error)) {
            RETURN_IF_HWC_ERROR_FOR("presentOrValidate", error, displayId, UNKNOWN_ERROR);
        }
        if (state == 1) { //Present Succeeded.
            // present成功,數(shù)據(jù)直接提交給了hwc
            std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
            error = hwcDisplay->getReleaseFences(&releaseFences);
            displayData.releaseFences = std::move(releaseFences);
            displayData.lastPresentFence = outPresentFence;
            displayData.validateWasSkipped = true;
            displayData.presentError = error;
            return NO_ERROR;
        }
 // Present failed but Validate ran.
    } else {
        // 若有GPU合成拐迁,則走validate邏輯
        error = hwcDisplay->validate(&numTypes, &numRequests);
    }
   // 接收hwc過來的change蹭劈,對(duì)于device合成不走,GPU合成走的邏輯
   ...

prepareFrame 的作用是根據(jù)hwc的能力選擇合成方式线召,如果是device合成則直接走h(yuǎn)wc present上屏铺韧,如果是GPU合成則走h(yuǎn)wc validate,然后根據(jù)hwc過來的變化改變layer的合成方式缓淹。

finishFrame

文件: frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);

    if (!getState().isEnabled) {
        return;
    }

    // Repaint the framebuffer (if needed), getting the optional fence for when
    // the composition completes.
    // 主要針對(duì)GPU合成的邏輯
    auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs);
    // device合成直接return
    if (!optReadyFence) {
        return;
    }

    // swap buffers (presentation)
    mRenderSurface->queueBuffer(std::move(*optReadyFence));
}

composeSurfaces主要的邏輯是針對(duì)GPU合成哈打,對(duì)于device合成,直接return了讯壶。

postFramebuffer

文件:frameworks/native/services/surfaceflinger/CompositionEngine/src/Output.cpp

void Output::postFramebuffer() {
   ...
    // device合成獲取release fence
    auto frame = presentAndGetFrameFences();
   
    mRenderSurface->onPresentDisplayCompleted();

    for (auto* layer : getOutputLayersOrderedByZ()) {
        // The layer buffer from the previous frame (if any) is released
        // by HWC only when the release fence from this frame (if any) is
        // signaled.  Always get the release fence from HWC first.
        sp<Fence> releaseFence = Fence::NO_FENCE;

        if (auto hwcLayer = layer->getHwcLayer()) {
            if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
                releaseFence = f->second;
            }
        }
        if (outputState.usesClientComposition) {
            releaseFence =
                    Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
        }
       // 將releasefence放到mslot里面料仗,這個(gè)是dequeueBuffer等的fence
        layer->getLayerFE().onLayerDisplayed(releaseFence);
    }
...
}

文件:frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
    ATRACE_CALL();
    
    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
    
    auto& displayData = mDisplayData[displayId];
    auto& hwcDisplay = displayData.hwcDisplay;
     // device合成直接return
    if (displayData.validateWasSkipped) {
        // explicitly flush all pending commands
        auto error = static_cast<hal::Error>(mComposer->executeCommands()); 
        RETURN_IF_HWC_ERROR_FOR("executeCommands", error, displayId, UNKNOWN_ERROR);
        RETURN_IF_HWC_ERROR_FOR("present", displayData.presentError, displayId, UNKNOWN_ERROR);
        return NO_ERROR;
    }
    //GPU 合成走present
    auto error = hwcDisplay->present(&displayData.lastPresentFence);
    RETURN_IF_HWC_ERROR_FOR("present", error, displayId, UNKNOWN_ERROR);

    std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
    error = hwcDisplay->getReleaseFences(&releaseFences);
    RETURN_IF_HWC_ERROR_FOR("getReleaseFences", error, displayId, UNKNOWN_ERROR);

    displayData.releaseFences = std::move(releaseFences);

    return NO_ERROR;
}

postComposition

文件: frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::postComposition()
{
    ATRACE_CALL();
    ALOGV("postComposition");

    nsecs_t dequeueReadyTime = systemTime();
     // release Bufferqueuelayer
    for (auto& layer : mLayersWithQueuedFrames) {
        layer->releasePendingBuffer(dequeueReadyTime);
    }
    ...
     // mPreviousPresentFences[0]是這一幀的present fence,mPreviousPresentFences[1]是上一幀的present fence
    mPreviousPresentFences[1] = mPreviousPresentFences[0];
    mPreviousPresentFences[0] =
            display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
    ...
     // 這個(gè)有關(guān)vsync伏蚊,是校驗(yàn)presentfence釋放的時(shí)間戳
     if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
        presentFenceTime->isValid()) {
        mScheduler->addPresentFence(presentFenceTime);
    }
   ....
}

postComposition的作用就是釋放上一幀顯示的Buffer立轧,然后重新設(shè)置當(dāng)前幀的present fence,以及根據(jù)presentfence時(shí)間戳判斷是否重新打開HW Vsync和軟件Vsync進(jìn)行校準(zhǔn)。至此氛改,SurfaceFlinger刷新的主體函數(shù)分析完了帐萎,可以看出來,如果是走device合成胜卤,SurfaceFlinger是直接把layer信息提交給hwc疆导,由hwc去合成,涉及到GPU部分瑰艘,下篇進(jìn)行分析是鬼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市紫新,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌李剖,老刑警劉巖芒率,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異篙顺,居然都是意外死亡偶芍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門德玫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匪蟀,“玉大人,你說我怎么就攤上這事宰僧〔谋耄” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵琴儿,是天一觀的道長(zhǎng)段化。 經(jīng)常有香客問我,道長(zhǎng)造成,這世上最難降的妖魔是什么显熏? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮晒屎,結(jié)果婚禮上喘蟆,老公的妹妹穿的比我還像新娘。我一直安慰自己鼓鲁,他們只是感情好蕴轨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坐桩,像睡著了一般尺棋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天膘螟,我揣著相機(jī)與錄音成福,去河邊找鬼。 笑死荆残,一個(gè)胖子當(dāng)著我的面吹牛奴艾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播内斯,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蕴潦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了俘闯?” 一聲冷哼從身側(cè)響起潭苞,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎真朗,沒想到半個(gè)月后此疹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遮婶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蝗碎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旗扑。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹦骑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臀防,到底是詐尸還是另有隱情眠菇,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布清钥,位于F島的核電站琼锋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祟昭。R本人自食惡果不足惜缕坎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篡悟。 院中可真熱鬧谜叹,春花似錦、人聲如沸搬葬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽急凰。三九已至女仰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疾忍。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工乔外, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人一罩。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓杨幼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親聂渊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子差购,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容