这一节我们进行探寻内存如何连接硬件HAL层进行分配
显示设备测试代码
...
int main(int argc, char** argv)
{
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
160, 240, PIXEL_FORMAT_RGB_565, 0);
sp<Surface> surface = surfaceControl->getSurface();
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
surface->lock(&outBuffer, NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
surface->lock(&outBuffer, NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
for (int i = 0; i < 100; i++) {
surface->lock(&outBuffer, NULL);
printf("%03d buff addr = 0x%x\n", i, (unsigned int)outBuffer.bits);
surface->unlockAndPost();
}
IPCThreadState::self()->joinThreadPool();
return 0;
}
复用上一届代码继续讲
Surface::lock()
surface->lock(&outBuffer, NULL);
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
if (mLockedBuffer != 0) {
ALOGE("Surface::lock failed, already locked");
return INVALID_OPERATION;
}
if (!mConnectedToCpu) {
//获取一些分辨率信息
int err = Surface::connect(NATIVE_WINDOW_API_CPU);
if (err) {
return err;
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
}
ANativeWindowBuffer* out;
int fenceFd = -1;
//重点分析
//将out赋值,此时out指向一块buffer
status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
//将生成的buffer赋值给backBuffer,这个是后面buffer,一个surface有多个buffer,具体有当前显示的buffer后面处理的buffer
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
newDirtyRegion.set(bounds);
}
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion.set(bounds);
mDirtyRegion.clear();
Mutex::Autolock lock(mMutex);
for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
mSlots[i].dirtyRegion.clear();
}
}
{ // scope for the lock
Mutex::Autolock lock(mMutex);
int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
if (backBufferSlot >= 0) {
Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
mDirtyRegion.subtract(dirtyRegion);
dirtyRegion = newDirtyRegion;
}
}
mDirtyRegion.orSelf(newDirtyRegion);
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
//在这里将backbuffer进行提交
//其中backbufferr得到vaddr一个虚拟地址并且赋值给outBuffer->bits
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
ALOGW_IF(res, "failed locking buffer (handle = %p)",
backBuffer->handle);
if (res != 0) {
err = INVALID_OPERATION;
} else {
mLockedBuffer = backBuffer;
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
outBuffer->bits = vaddr;
}
}
return err;
}
dequeueBuffer()
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd)
{
ATRACE_CALL();
ALOGV("Surface::dequeueBuffer");
uint32_t reqWidth;
uint32_t reqHeight;
bool swapIntervalZero;
PixelFormat reqFormat;
uint32_t reqUsage;
{
Mutex::Autolock lock(mMutex);
reqWidth = mReqWidth ? mReqWidth : mUserWidth;
reqHeight = mReqHeight ? mReqHeight : mUserHeight;
swapIntervalZero = mSwapIntervalZero;
reqFormat = mReqFormat;
reqUsage = mReqUsage;
} // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
int buf = -1;
sp<Fence> fence;
//向surfaceFlinger发出buffer申请导致对端分配内存
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
reqWidth, reqHeight, reqFormat, reqUsage);
if (result < 0) {
IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)"
"failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat,
reqUsage, result);
return result;
}
Mutex::Autolock lock(mMutex);
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
//使用生产者的代理对象向surfaceFlinger请求返回文件句柄fd然后在app这段mmap
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
mGraphicBufferProducer->cancelBuffer(buf, fence);
return result;
}
}
if (fence->isValid()) {
*fenceFd = fence->dup();
} else {
*fenceFd = -1;
}
*buffer = gbuf.get();
return OK;
}
到目前我们回顾一下调用过程:
surface->lock(&outBuffer, NULL);
status_t err = dequeueBuffer(&out, &fenceFd);
mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,reqWidth, reqHeight, reqFormat, reqUsage);
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
我们通过dequeueBuffer获取buffer,具体是通过mGraphicBufferProducer远程调用dequeueBuffer与requestBuffer两个方法
- dequeueBuffer是分配内存
- requestBuffer是将返回的fd进行mmap
我们下面继续分析
mGraphicBufferProducer->dequeueBuffer()
int buf = -1;
sp<Fence> fence;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,reqWidth, reqHeight, reqFormat, reqUsage);
这里得到下标buf这个下标是mSlot[buf]表明这个数组的buffer已经分配了
下面我们看一看具体导致对端的什么函数被调用
BpGraphicBufferProducer
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, PixelFormat format,
uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(static_cast<int32_t>(async));
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint32(usage);
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
}
*buf = reply.readInt32();
bool nonNull = reply.readInt32();
if (nonNull) {
*fence = new Fence();
reply.read(**fence);
}
result = reply.readInt32();
return result;
}
BnGraphicBufferProducer
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = static_cast<bool>(data.readInt32());
uint32_t width = data.readUint32();
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
uint32_t usage = data.readUint32();
int buf;
sp<Fence> fence;
int result = dequeueBuffer(&buf, &fence, async, width, height,
format, usage);
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
reply->write(*fence);
}
reply->writeInt32(result);
return NO_ERROR;
}
会调用子类的dequeueBuffer方法
class BufferQueueProducer : public BnGraphicBufferProducer,
private IBinder::DeathRecipient {
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, bool async,
uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) {
{
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
} // Autolock scope
BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
async ? "true" : "false", width, height, format, usage);
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
return BAD_VALUE;
}
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
//等待空闲内存
mCore->waitWhileAllocatingLocked();
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
//等待空闲Slot
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
&found, &returnFlags);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, usage)) {
mCore->freeBufferLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
//当申请buffer是null或者申请的参数不一样,则标记flag为BUFFER_NEEDS_REALLOCATION需要重新分配
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge =
mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
mCore->mBufferAge);
if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
}
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->validateConsistencyLocked();
} // Autolock scope
//如果需要重新分配的话在这里进行分配
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence);
}
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
*outSlot,
mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
我们在这里关注的核心
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,&found, &returnFlags);
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error));
}
我们注意一下参数,其中mCore是生产者消费者都会指向一个BufferQueueCore,在这里面使用mCore里面的IGraphicBufferAlloc对象
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {
sp<GraphicBuffer> graphicBuffer(
new GraphicBuffer(width, height, format, usage));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
"failed (%s), handle=%p",
width, height, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;
}
做的事情是:
- sp<GraphicBuffer> graphicBuffer(
new GraphicBuffer(width, height, format, usage)); - status_t err = graphicBuffer->initCheck();
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId())
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);
}
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage)
{
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,&handle, &outStride);
if (err == NO_ERROR) {
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
usage = static_cast<int>(inUsage);
stride = static_cast<int>(outStride);
}
return err;
}
GraphicBufferAllocator构造打开gralloc HAL模块分配内存
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
}
}
通过hw_get_module打开对应硬件模块
status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
uint32_t* stride)
{
ATRACE_CALL();
// make sure to not allocate a N x 0 or 0 x N buffer, since this is
// allowed from an API stand-point allocate a 1x1 buffer instead.
if (!width || !height)
width = height = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
// Filter out any usage bits that should not be passed to the gralloc module
usage &= GRALLOC_USAGE_ALLOC_MASK;
int outStride = 0;
err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
static_cast<int>(height), format, static_cast<int>(usage), handle,
&outStride);
*stride = static_cast<uint32_t>(outStride);
ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
width, height, format, usage, err, strerror(-err));
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
alloc_rec_t rec;
rec.width = width;
rec.height = height;
rec.stride = *stride;
rec.format = format;
rec.usage = usage;
rec.size = static_cast<size_t>(height * (*stride) * bpp);
list.add(*handle, rec);
}
return err;
}
打开HAL之后通过HAL模块的mAllocDev->alloc函数最后会调用什么呢?
其实这里已经不用分析了因为HAL每个厂商都不一样.
最后通过fd = ashmem_create_region("gralloc-buffer",size);
然后通过new private_handle(fd,size);最后通过mapBuffer(handle),最后mapBuffer最终调用mmap
小结:
surface->lock(&outBuffer, NULL);
status_t err = dequeueBuffer(&out, &fenceFd);
mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,reqWidth, reqHeight, reqFormat, reqUsage);
//开始对端
mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error)
new GraphicBuffer(width, height, format, usage)
initSize()
allocator.alloc()
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
也就是我们在initSize()中通过分配匿名共享内存,然后进行mmap处理,其中mmap提供的虚拟地址供给SurfaceFlinger
我们在回顾一下mSlot是什么东西
BufferQueueConsumer.h
BufferQueueDefs::SlotsType& mSlots;
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
sp<GraphicBuffer> mGraphicBuffer
hanlde
fd(文件句柄)
base(是mmap的结果)
上面分析的mSlot就在对端创建了,在应用程序这边也存在一个mSlot,每一个Surface都有mSlots[]与之对应。
上面我们对应了buf的下表这个下标就是mSlots[buf]的下标