Your SlideShare is downloading. ×
Surface flingerservice(서피스 출력 요청 jb)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Surface flingerservice(서피스 출력 요청 jb)

2,249
views

Published on


0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,249
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. SurfaceFlingerService(서피스 출력 요청-JB) 박철희 1
  • 2. 1.노말 서피스 출력(서비스 클라이언트)그래픽 버퍼의 가상 주소를 획득한 후 그래픽 버퍼의 메모리에 랜더링 하여 서피스 플링거로 출력 요청하게 된다. 노말 서피스의 출력 요청 과정SurfaceTextureClient의 queueBuffer함수는 서피스 플링거에게 출력할 버퍼를 알려준다.int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); 해당 버퍼의 마지막 출력 요청 시간. int i = getSlotFromBufferLocked(buffer); 출력 요청할 버퍼의 인덱스를 검색한다. ISurfaceTexture::QueueBufferOutput output; ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode, mTransform); status_t err = mSurfaceTexture->queueBuffer(i, input, &output); BufferQueue의 queueBuffer를 호출한다. ( i : 출력할 버퍼 인덱스, input(timestamp:해당 버퍼의 출력 요청 시간등), output:서버에 저장된 그래픽 버퍼의 가로,세로 값을 저장함. 이 값은 애플리케이션에서 다음 그래픽 버퍼 획득 시 기본 값으로 사용 됨.)} 2
  • 3. 2.노말 서피스 출력(서비스 서버)출력 방식은 동기, 비동기 2가지의 경우가 있다.1.동기식:애플리케이션에서 출력 요청이 한번 발생하면 서피스 플링거 서비스에서도 한번의 출력이 발생 됨.2.비동기식:출력 요청이 발생한 횟수에 관계없이 서피스 플링거 서비스의 합성에 맞추어 화면 출력이 됨.status_t BufferQueue::queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output) { if (mSynchronousMode) {  동기식일 경우 mQueue.push_back(buf);  출력 대기 큐의 제일 마지막에 넣는다.(FIFO 방식) listener = mConsumerListener; mConsumerListener 는 SurfaceTexture 생성자에서 BufferQueue::ProxyConsumerListener 로 설정되어 있음. 이 lister는 출력 가능한 버퍼가 대기 하고 있다는 것을 서피스 플링거에게 알려줌. } else 비동기식 { if (mQueue.empty()) 출력 대기 큐에 대기하는 버퍼가 없다면 { mQueue.push_back(buf);  현재 요청된 버퍼를 대기 큐에 저장함. listener = mConsumerListener; } else {  출력 대기 하고 있는 버퍼가 있다면 Fifo::iterator front(mQueue.begin()); 출력 대기 큐의 첫번째 인덱스를 획득해서, mSlots[*front].mBufferState = BufferSlot::FREE; 슬롯의 상태를 FREE로 만든다. *front = buf;  출력 대기 큐의 첫번째 인덱스에 새롭게 요청한 인덱스를 넣는다. } mSlots[buf].mBufferState = BufferSlot::QUEUED;  버퍼의 상태를 QUEUED로 바꿈.  즉, 클라이언트는 출력 요청 하였고,서피스 플링거 서비스는 해당 버퍼를 아직 합성하지 않았다는 의미 임. mDequeueCondition.broadcast();  FREE상태를 기다리는 dequeueBuffer 함수를 깨운다. if (listener != 0) { listener->onFrameAvailable(); 서피스 플링거에게 합성 신호를 보내게 요청 함. } 3
  • 4. 2.노말 서피스 출력(서비스 서버)void BufferQueue::ProxyConsumerListener::onFrameAvailable() { sp<BufferQueue::ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(); }} SurfaceTexture는 BufferQueue::ConsumerListener 를 상속 받기 때문에 SurfaceTexture::onFrameAvailable가 호출 된다.SurfaceTexture.cppvoid SurfaceTexture::onFrameAvailable() { if (listener != NULL) { ST_LOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(); }}Layer.cppstruct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener { FrameQueuedListener(Layer* layer) : mLayer(layer) { } virtual void onFrameAvailable() { if (that != 0) { that->onFrameQueued(); } }};void Layer::onFrameQueued() { android_atomic_inc(&mQueuedFrames);  mQueuedFrames는 출력 요청이 발생한 횟수를 저장함. mFlinger->signalLayerUpdate(); 서피스 플링거에게 합성 시그널을 보냄.} 4
  • 5. 3.디스플레이 이벤트 동기화젤리빈부터 하드웨어에서 발생하는 Vsync 이벤트에 맞춰 렌더링을 시작하도록 변경 됨.서피스 플링거 역시 Vsync 에 맞춰 합성을 시작 함.Vsync Event1.연속적 통지: Vsync 이벤트 발생 시 마다 이벤트 통지2. 일회성 통지: Vsync 이벤트 요청 시 마다 이벤트 통지서피스 플링거는 일회성 통지를 사용, 즉 출력 버퍼 큐에 새로운 버퍼가 추가되면 Vsync 에 맞춰 합성 시그널이 발생됨.SurfaceFlinger.cppvoid SurfaceFlinger::signalLayerUpdate() { mEventQueue.invalidate();}Messagequeue.cppvoid MessageQueue::invalidate() { mEvents->requestNextVsync();  mEvents 는 EventThread 의 Connection class를 가르킨다.}EventThread.cppvoid EventThread::Connection::requestNextVsync() { mEventThread->requestNextVsync(this);  mEventThread 는 EventThread를 가르킨다.}void EventThread::requestNextVsync( const sp<EventThread::Connection>& connection) { if (connection->count < 0) {  count의 초기 값이 -1이다. connection->count = 0;  count 값이 0 이면 일회성 통지를 의미함. mCondition.broadcast();  EventThread::threadLoop() 에서 기다리는 thread를 깨움. }} 5
  • 6. 3.디스플레이 이벤트 동기화 EventThread::threadLoop() 에서 Vsync가 발생 할때 까지 대기 하다 mCondition.broadcast(); 가 불리면 깨어 난다.bool EventThread::threadLoop() {do { do { timestamp = mVSyncTimestamp;  mVSyncTimestamp는 HWComposer로 부터 Vsync가 전달되면 갱신된다. 즉, HWComposer 로 부터 전달된 Vsync로 깨어난 경우가 아니라면, mVSyncTimestamp 은 0 이다. 현재 경우는, requestNextVsync 에 의해 깨어 났기 때문에 mVSyncTimestamp 가 0 이다. mVSyncTimestamp = 0; bool waitForNextVsync = false; size_t count = mDisplayEventConnections.size(); VSync 이벤트를 기다리는 수신자들(서피스 플링거)을 획득한다. for (size_t i=0 ; i<count ; i++) { sp<Connection> connection =mDisplayEventConnections.itemAt(i).promote(); connectionList.add(connection); if (connection!=0 && connection->count >= 0) {  EventThread::requestNextVsync 에서 count 값을 0으로 설정했다. 이 의미는 Vsync 를 받아 출력해야 할 Event가 있다는 의미이다. waitForNextVsync = true; Vsync가 필요하다는 의미로 waitForNextVsync 를 설정 한다. break; } if (timestamp) {  timestamp 가 0 보다 크다는 것은 HWComposer 로 부터 Vsync가 발생 되었다는 의미이다.  현재 경우는 Vsync가 전달되지 않았기 때문에 0 이다. if (!waitForNextVsync) { } else { 이 경우는 HWComposer 로 부터 Vsync가 발생된 경우임으로 첫번째 do while문을 빠져 나간다. break; } } 6
  • 7. 3.디스플레이 이벤트 동기화 else {  HWComposer 로 부터 Vsync 가 발생 되지 않을 경우 if (waitForNextVsync) {  Vsync가 필요 함으로 enableVSyncLocked();  HWCompser에게 Vsync 발생 요청 } mCondition.wait(mLock);  HWCompser로 부터 Vsync 가 발생되기를 기다림. } while(true); // 첫번째 do while문 const size_t count = mDisplayEventConnections.size();  이벤트 쓰레드에 등록된 Vsync 이벤트 수신자를 획득한다. for (size_t i=0 ; i<count ; i++) { const int32_t count = connection->count; if (count >= 1) { reportVsync = true;  수신자의 모드가 연속(count =1) 일 경우 reportVsync 를 수신 할 수 있다. } else if (count >= -1) { If (count == 0) { reportVsync = true; 수신자의 모드가 일회성(count =0) 일 경우 reportVsync 를 수신 할 수 있다. } if (reportVsync) { displayEventConnections.add(connection);  Vsync를 수신 받을 수신자를 displayEventConnections 에 추가한다. } } while (!displayEventConnections.size());  Vsync를 수신 받을 수신자가 있기 때문에 두번째 do while 문을 벗어난다. vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; 수신자에게 보낼 이벤트 타입 설정 vsync.header.timestamp = timestamp;  Vsync 발생 시간 const size_t count = displayEventConnections.size();  Vsync를 수신 받을 수신자의 개수를 가져온다. for (size_t i=0 ; i<count ; i++) { status_t err = conn->postEvent(vsync);  각 수신자에게 Vsync를 보낸다. } 7
  • 8. 3.디스플레이 이벤트 동기화 Vsync 수신시의 처리 애플리케이션 측에서는 choreographer class를 이용하면 Vsync 이벤트를 수신 할 수 있다. 서피스 플링거는 네이티브 루퍼에서 Vsync event를 수신한다. 네이티브 루퍼는 Vsync가 수신되면 MessageQueue::setEventThread 의 MessageQueue::cb_eventReceiver 가 불려진다.MessageQueue.cppvoid MessageQueue::setEventThread(const sp<EventThread>& eventThread){ mEventThread = eventThread; mEvents = eventThread->createEventConnection(); mEventTube = mEvents->getDataChannel(); mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT, MessageQueue::cb_eventReceiver, this);}int MessageQueue::cb_eventReceiver(int fd, int events, void* data) { MessageQueue* queue = reinterpret_cast<MessageQueue *>(data); return queue->eventReceiver(fd, events);}int MessageQueue::eventReceiver(int fd, int events) { while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) { for (int i=0 ; i<n ; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { mHandler->signalRefresh();  MessageQueue::Handler::signalRefresh 를 호출한다. break; } } } 8
  • 9. 3.디스플레이 이벤트 동기화void MessageQueue::Handler::signalRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); 네이티브 루퍼에 MessageQueue::REFRESH 를 보낸다. }}void MessageQueue::Handler::handleMessage(const Message& message) { case REFRESH: android_atomic_and(~eventMaskRefresh, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); Surfaceflinger의 onMessageReceived 를 호출한다. break; }} 9
  • 10. 4.레이어 합성과 화면 출력Surfaceflinger의 onMessageReceived 함수는 화면 출력 준비가 된 레이어들을 모아서 합성한 후 프레임 버퍼에 출력한다.void SurfaceFlinger::onMessageReceived(int32_t what){ switch (what) { case MessageQueue::INVALIDATE: case MessageQueue::REFRESH: { …. handlePageFlip(); 레이어에 할당된 그래픽 버퍼를 EGL Image로 만들어 텍스쳐로 사용할 수 있도록 만든다.---(1) handleRepaint();합성 hw.compositionComplete(); 합성이 완료 되었다는 것을 하드웨어에게 알려줌. postFramebuffer();  완료된 합성 이미지를 프레임 버퍼에 출력.------------(2)}(1) handlePageFlipvoid SurfaceFlinger::handlePageFlip(){ const bool visibleRegions = lockPageFlip(currentLayers);}bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers){ layer->lockPageFlip(recomputeVisibleRegions);}Layer.cppvoid Layer::lockPageFlip(bool& recomputeVisibleRegions){ if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { return;} 10
  • 11. 3.레이어 합성과 화면 출력status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { err = mBufferQueue->acquireBuffer(&item);  출력 대기 큐의 첫번째 요소에 저장된 버퍼를 획득한다. BufferQueue.cpp status_t BufferQueue::acquireBuffer(BufferItem *buffer) { if (!mQueue.empty()) { Fifo::iterator front(mQueue.begin()); int buf = *front; 출력 대기 큐의 첫번째 인덱스를 가져온다. buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; 그래픽 버퍼를 변수에 저장. buffer->mTimestamp = mSlots[buf].mTimestamp;  버퍼의 출력 요청 시간 저장. mSlots[buf].mBufferState = BufferSlot::ACQUIRED;  버퍼 상태를 ACQUIRED 로 바꾸어서, 다시 queuebuffer 할 수 없도록 함. mQueue.erase(front);  다음 버퍼를 위해 출력 대기 큐에서 삭제. } if (item.mGraphicBuffer != NULL) {  획득한 버퍼 인덱스의 GraphicBuffer 가 있으면 mEGLSlots[buf].mGraphicBuffer = 0;  기존 mEGLSlots 의 내용을 지운다. if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage); mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; } mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;  GraphicBuffer 다시 지정. } image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer);  EGL Image를 다시 만든다. mEGLSlots[buf].mEglImage = image;  만든 EGL Image를 mEGLSlots에 저장한다. 11
  • 12. 3.레이어 합성과 화면 출력glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);바인딩된 텍스쳐에 대한 소스를 생성한 EGL Image로 지정 한다. (즉, 어떤 EGL Image를 사용할지 결정 함.)if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,  이전 버퍼를 release한다. mEGLSlots[mCurrentTexture].mFence);} BufferQueue.cpp status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,EGLSyncKHR fence) { if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { mSlots[buf].mBufferState = BufferSlot::FREE; status를 FREE 로 만들고 } mDequeueCondition.broadcast();  FREE 인 버퍼가 있음을 broadcast한다. }mCurrentTexture = buf;  현재 index를 mCurrentTexture 에 저장 한다.mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;} 12
  • 13. 3.화면 출력 시 Buffer status 변경 BufferQueue::releaseBuffe에 의해 7 mslot의 4번 status가 FREE로 변경됨. mSlot출력 대기 큐에서 [0]4번 인덱스를 mQueue의 첫번 째 요소의삭제 mQueue 1 mSlot의 status를 FREE로 만든다. 4 [1] [0] 2->4 X [2] F D->F EGL Image [1] [3] 5 2 출력할 버퍼의 인덱스를 mQueue의 처음에 넣는다. A 그래픽 버퍼 출력할 그래픽 버퍼를 [2] [4] EGL Image로 만든다. D->A acquireBuffer에 의해 3 Status 를 ACQUIRED로 변경함 mEGLSlots [0] 6 mEGLSlots이 생성한 [1] EGL Image를 가리키게 한다. [2] [3] [4] 13
  • 14. 2.그래픽 버퍼 출력 요청(2) postFramebufferSurfaceflinger.cppvoid SurfaceFlinger::postFramebuffer(){ hw.flip(mSwapRegion);}DisplayHardware.cppvoid DisplayHardware::flip(const Region& dirty) const{ mHwc->commit();}HWComposer.cpp(surfaceflingerdisplayhardware)status_t HWComposer::commit() const { int err = mHwc->set(mHwc, mDpy, mSur, mList); mHwc는 HWC_HARDWARE_MODULE_ID 를 가지는 Module이다. return (status_t)err;}hwc.cpp(hardware/qcom/display/libhwcomposer)static int hwc_set(…){ eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);} 14
  • 15. 참고자료 안드로이드 미디어 프레임워크 –”개발자가 행복한 세상” Goolge Jelly bean Source 15