3. 1.서피스 상태 변경 -서피스 추가/삭제
1.서피스 추가/삭제
2.개별 레이어 상태 변경(크기,zorder)
3.프레임 상태 변경(orientation변경)
1.서피스 추가/삭제
서피스가 추가 또는 삭제 되면 전역 레이어 목록이 변경되어야 한다.
이를 위해서 추가 또는 삭제 시에 mTransactionFlags 에 eTransactionNeeded을 설정하고
surfaceflinger의 threadloop으로 signal을 보낸다.
sp<ISurface> SurfaceFlinger::createSurface(…)
{
layer = createPushBuffersSurface(client, d, w, h, flags);
setTransactionFlags(eTransactionNeeded);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
status_t SurfaceFlinger::removeSurface() {
{ uint32_t old = android_atomic_or(flags, &mTransactionFlags);
… if ((old & flags)==0) { // wake the server up
setTransactionFlags(eTransactionNeeded); signalEvent();
} }
return old;
}
3
4. 1.서피스 상태 변경 종류-개별 레이어 상태 변경
2.개별 레이어 상태 변경(크기,zorder)
-레이어(서피스) 상태 변경은 트랜잭션 시작과 종료 사이에만 가능하다.
-다수의 상태 변경 함수를 동시에 중첩하여 설정 할 수 있다.
ex)fade out 의 기능과 같이 메뉴가 투명해 지면서 축소가 되고 위치가 변경이 되는 경우
“투명,축소,위치변경”이 동시에 실행 된다.
Bootanimation.cpp
status_t BootAnimation::readyToRun()
{
sp<SurfaceControl> control = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGBA_8888);
session()->openTransaction(); transaction 시작
control->setLayer(0x40000000); 서피스의 zorder 변경
session()->closeTransaction(); transaction 종료
}
1)Transaction 시작
status_t SurfaceComposerClient::openTransaction()
{
mTransactionOpen++; open된 transaction을 나타내는 mTransactionOpen을 1 증가 시킴.
}
2) 서피스의 zorder 변경
Surface.cpp
status_t SurfaceControl::setLayer(int32_t layer)
{
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
return client->setLayer(mToken, layer); 상태 변경의 대상이 되는 레이어를 알려 주기 위해 mToken을 넘겨 준다.
} (mToken은 SurfaceControl 생성자에서 생성된 layer를 가리키게 된다.)
4
5. 1.서피스 상태 변경 종류- 개별 레이어 상태 변경
SurfaceComposerClient.cpp
status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
{
layer_state_t* s = lockLayerState(id);
dummy layer state 구조체를 생성하고 return 받는다.
s->what |= ISurfaceComposer::eLayerChanged;
s->z = z;
dummy layer state 구조체에 what(상태 변경 이벤트),z(zoder값)을 저장한다.
unlockLayerState();
return NO_ERROR;
}
layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
{
s = get_state_l(id);
if (!s) mLock.unlock();
return s;
}
layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
{
layer_state_t& dummy(*mPrebuiltLayerState);
mPrebuiltLayerState는 onFirstRef에서 만들어진 dummy layer state 구조체
dummy.surface = index; dummy state 구조체에 상태 변경 대상의 layer의 index를 대입
ssize_t i = mStates.indexOf(dummy);
if (i < 0) {
// we don't have it, add an initialized layer_state to our list
i = mStates.add(dummy); mStates 에 dummy 구조체 추가. 이 mStates의 정보는 SurfaceFlinger쪽으로 전달 됨.
}
return mStates.editArray() + i; 추가된 dummy 구조체를 return
}
5
6. 1.서피스 상태 변경 종류- 개별 레이어 상태 변경
3. transaction 종료
SurfaceComposerClient.cpp
status_t SurfaceComposerClient::closeTransaction()
{
if (mTransactionOpen >= 2) {
transcation이 2개 이상일 경우에는 서피스 플링거에게 상태 변경을 요청하지 않고, mTransactionOpen만 1 감소
시키고 return 시킴(빈번한 transaction 처리를 방지하기 위해)
mTransactionOpen--;
return NO_ERROR;
}
mTransactionOpen = 0;
const ssize_t count = mStates.size();
if (count) {
mClient->setState(count, mStates.array());
mStates 에 추가된 dummy layer 구조체를 인자로 서피스 클라이언트의 setState함수를 호출 함.
mStates.clear();
}
return NO_ERROR;
}
status_t Client::setState(int32_t count, const layer_state_t* states)
{
return mFlinger->setClientState(this, count, states);
}
6
7. 1.서피스 상태 변경 종류- 개별 레이어 상태 변경
status_t SurfaceFlinger::setClientState(const sp<Client>& client, int32_t count,const layer_state_t* states)
{
if (what & eLayerChanged) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
if (layer->setLayer(s.z)) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed) AND transaction (list changed)
flags |= eTransactionNeeded|eTraversalNeeded;
zorder 변경은 개별 레이어의 상태 변경 (eTraversalNeeded) 및 전역 레이어 목록 변경(eTransactionNeeded)
이 필요함.
}
if (flags) {
setTransactionFlags(flags); surfaceflinger의 threadloop으로 signal을 보내서 상태 변경 처리를 한다.
}
7
8. 1.서피스 상태 변경 종류-프레임 상태 변경
3.프레임 상태 변경(orientation변경)
-전역 레이어 목록에 있는 모든 레이어를 회전 각도에 맞게 재 계산해야 함.
int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation, uint32_t flags)
{
sp<ISurfaceComposer> sm(getComposerService());
return sm->setOrientation(dpy, orientation, flags);
}
int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation, uint32_t flags)
{
if (mCurrentState.orientation != orientation) { 현재 상태 값과 다를 때에만 재 계산 함.
mCurrentState.orientation = orientation; mCurrentState와 mDrawingState의 orientation을 비교
setTransactionFlags(eTransactionNeeded); 전역 레이어 목록 변경
mTransactionCV.wait(mStateLock); 다른 레이어가 변경할 때 까지 기다림.
}
}
Surfaceflinger의 threadloop에서 transaction을 처리하기 위한 handleTransactionLocked에서 commitTransaction를 호출 함.
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
commitTransaction();
}
void SurfaceFlinger::commitTransaction()
{
mTransactionCV.broadcast(); setOrientation에서 기다리고 있는 conditionlock에게 signal 보냄.
}
8
9. 2.그래픽 버퍼 출력 요청
Ex)Cameraservice의 preview 출력
void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (!mUseOverlay) {
if (mSurface != 0) {
mSurface->postBuffer(offset);
}
}
}
void LayerBuffer::postBuffer(ssize_t offset)
{
source->postBuffer(offset);
}
void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
buffers = mBufferHeap;
sp<Buffer> buffer;
if (buffers.heap != 0) {
buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
1.offset에 해당하는 메모리 영역을 copybit을 이용할 수 있는 Nativebuffer에 저장
setBuffer(buffer);2.BufferSource객체의 mBuffer에 생성된 buffer class를 저장한다.
mLayer.invalidate(); 3.서피스 플링거에게 출력 요청 함.
}
9
10. 2.그래픽 버퍼 출력 요청
1.offset에 해당하는 메모리 영역을 copybit을 이용할 수 있는 Nativebuffer에 저장
buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize);
LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers,
ssize_t offset, size_t bufferSize) struct NativeBuffer {
: mBufferHeap(buffers), mCurrOffset(offset) copybit_image_t img;
{ copybit_rect_t crop;
int hor_stride;
NativeBuffer& src(mNativeBuffer); int ver_stride;
mNativeBuffer에 offset에 해당하는 메모리 영역을 저장함. };
src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
src.img.handle = 0;
2.BufferSource객체의 mBuffer에 생성된 buffer를 저장한다
void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
{
Mutex::Autolock _l(mBufferSourceLock);
mBuffer = buffer;
}
Cf.copybit
:그래픽 공유 메모리의 내용을 EGL_Image(Nativebuffer)로 고속으로 복사하기 위해 사용하는 hardware graphic module.
10
11. 2.그래픽 버퍼 출력 요청
surfaceflinger
layerbuffer buffersource
mBufferHeap
mSource mBuffer
buffer
mNativeBuffer
mBufferHeap
그래픽 공유
메모리 NativeBuffer
11
12. 2.그래픽 버퍼 출력 요청
3.서피스 플링거에게 출력 요청 함.
void LayerBase::invalidate()
{
mFlinger->signalEvent();
}
Surfaceflinger의 threadloop
void SurfaceFlinger::waitForEvent()
{
sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
switch (msg->what) {
case MessageQueue::INVALIDATE:
// invalidate message, just return to the main loop
return;
}
}
void SurfaceFlinger::handleRepaint()
{
layer->draw(clip);
}
Layerbase의 draw함수를 호출한다.
(각 layer의 텍스처 or EGL Image를 생성하고 프레임 버퍼에
이미지를 그려 넣는다.)
12
13. 2.그래픽 버퍼 출력 요청
Layerbase.cpp
void LayerBase::draw(const Region& clip) const
{
onDraw(clip);
}
LayerBuffer.cpp
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
sp<Buffer> ourBuffer(getBuffer()); postbuffer()에서 생성한 Buffer 인스턴스를 가져온다.
NativeBuffer src(ourBuffer->getBuffer());
Buffer class의 copybit 이미지로 사용 가능한 Nativebuffer type의 mNativeBuffer를 가져온다.
copybit_device_t* copybit = mLayer.mBlitEngine;copybit module을 가져온다.
err = initTempBuffer(); EGL Image를 생성하고 생성된 image를 NativeBuffer type인 mTempBuffer에 저장한다.
const NativeBuffer& dst(mTempBuffer);
err = copybit->stretch(copybit, &dst.img, &src.img,&dst.crop, &src.crop, &clip);
copybit을 이용하여 src(그래픽 공유 메모리)의 내용을 EGL Image를 가리키고 있는 dst로 copy한다.
mLayer.drawWithOpenGL(tempClip, mTexture);
생성된 EGL Image와 클립 정보(EGL image의 출력 영역)를 이용하여 각 레이어가 자신의 출력 영역에 그린다.
}
status_t LayerBuffer::BufferSource::initTempBuffer() const
{
sp<GraphicBuffer> buffer = new GraphicBuffer( w, h, HAL_PIXEL_FORMAT_RGB_565,
GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_HW_2D | GRALLOC_USAGE_PRIVATE_1);
EGL image를 위한 buffer 생성
13
14. 2.그래픽 버퍼 출력 요청
NativeBuffer& dst(mTempBuffer);
dst.img.handle = (native_handle_t *)buffer->handle;
NativeBuffer type인 dst에 GraphicBuffer로 생성된 buffer의 handle을 저장한다.
dst.crop.l = 0;
dst.crop.t = 0;
dst.crop.r = w;
dst.crop.b = h;
crop에 출력 범위를 지정한다.
err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
생성된 buffer를 EGL Image의 버퍼로 지정한다.
}
surfaceflinger
EGL
layerbuffer buffersource NativeBuffer
mBufferHeap Graphic
mSource mBuffer Buffer
buffer
mNativeBuffer EGL Image
mBufferHeap
dst
mTempBuffer
그래픽 공유
메모리 NativeBuffer Src
Copybit을 이용한 고속복사
14