After using SurfaceComposerClient::createSurface to create a SurfaceControl, the SurfaceControl can create a Surface for drawing.
But what if you want to configure Surface’s zorder, position and other attributes?
Methods for configuring properties are provided in SurfaceComposerClient::Transaction.
SurfaceComposerClient::Transaction::setXXX()
For example, in “02 The Simplest SurfaceFlinger Application”, zorder is configured to be the largest, the display position is set to the middle of the screen, the current layer is set to visible, etc.
SurfaceComposerClient::Transaction{} .setLayer(surfaceControl, std::numeric_limits<int32_t>::max()) .setPosition(surfaceControl, (displayMode.resolution.getWidth() - 200) / 2, (displayMode.resolution.getHeight() - 200) / 2) .show(surfaceControl) .apply();
Take setLayer as an example to see how it works internally.
setLayer
1. First get LayerSate; it is actually layer_state_t in ComposerState; if it cannot be found in mComposerStates, create one, and return it directly if found.
2. Modify the value in state
SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setLayer( const sp<SurfaceControl> & amp; sc, int32_t z) { layer_state_t* s = getLayerState(sc); s->what |= layer_state_t::eLayerChanged; s->what & amp;= ~layer_state_t::eRelativeLayerChanged; s->z = z; }
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl> & amp; sc) { auto handle = sc->getLayerStateHandle(); if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list ComposerState s; s.state.surface = handle; s.state.layerId = sc->getLayerId(); mComposerStates[handle] = s; } return &(mComposerStates[handle].state); } sp<IBinder> SurfaceControl::getLayerStateHandle() const { return mHandle; }
setPosition
SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setPosition( const sp<SurfaceControl> & amp; sc, float x, float y) { layer_state_t* s = getLayerState(sc); s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; return *this; }
show
SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::show( const sp<SurfaceControl> & amp; sc) { return setFlags(sc, 0, layer_state_t::eLayerHidden); } SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setFlags( const sp<SurfaceControl> & amp; sc, uint32_t flags, uint32_t mask) { layer_state_t* s = getLayerState(sc); if ((mask & amp; layer_state_t::eLayerOpaque) || (mask & amp; layer_state_t::eLayerHidden) || (mask & amp; layer_state_t::eLayerSecure) || (mask & amp; layer_state_t::eLayerSkipScreenshot) || (mask & amp; layer_state_t::eEnableBackpressure)) { s->what |= layer_state_t::eFlagsChanged; } s->flags & amp;= ~mask; s->flags |= (flags & amp; mask); s->mask |= mask; return *this; }
The implementation of other setting properties is basically the same and will not be explained one by one.
apply
After setting a bunch of parameters, when will it take effect? The answer is to execute apply
apply function:
- Put mComposerStates with configured layer parameters into composerStates
- mDisplayStates into displayStates
- Call sf->setTransactionState to commit the transaction
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); Vector<ComposerState> composerStates; Vector<DisplayState> displayStates; for (auto const & amp; kv : mComposerStates){ composerStates.add(kv.second); } displayStates = std::move(mDisplayStates); sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, hasListenerCallbacks, listenerCallbacks, mId); }
Will call SurfaceFlinger’s setTransactionState
status_t SurfaceFlinger::setTransactionState( const FrameTimelineInfo & amp; frameTimelineInfo, const Vector<ComposerState> & amp; states, const Vector<DisplayState> & amp; displays, uint32_t flags, const sp<IBinder> & amp; applyToken, const InputWindowCommands & amp; inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t & uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks> & amp; listenerCallbacks, uint64_t transactionId) { TransactionState state{frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, permissions, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId}; queueTransaction(state); } void SurfaceFlinger::queueTransaction(TransactionState & amp; state) { mTransactionQueue.emplace(state); setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); }
setTransactionState
main effect:
1. Create a TransactionState with the parameters passed in
2. Use queueTransaction to put the created state into the mTransactionQueue queue, set the eTransactionFlushNeeded flag; wait for the next vsync to come and retrieve it.
Draw a picture to summarize:
- Judging from the code, each surfacecontrol will only have one ComposerState.
- If apply is not executed, none of the parameters set above will take effect.
- Each apply will create a TransactionState and add it to SurfaceFlinger’s mTransactionQueue
Now that SurfaceFliger has obtained all the information of the layer, it can perform synthesis and refresh based on this information.
Creation is not easy, please like and comment.