本文首先研究以下GraphicBuffer到底是什么buffer,然后分析下android GraphicBuffer的分配过程。
先贴上几篇我学习的好文章
Android P 图像显示系统(二)GraphicBuffer和Gralloc分析主要对Android P及以后的版本的GraphicBuffer的分配进行了研究
Android图形缓冲区分配过程源码分析主要对Android P以前的版本的GraphicBuffer的分配进行了研究。
首先从宏观上了解下GraphicBuffer具体是什么buffer。
通过高通关于GPU Memory Management的文档中的示意图,如下:
可以清楚的看到:
Android GraphicBuffer是通过ION 在不同heap上分配的内存,其可以通过内存映射实现和GPU共享内存
文档描述如下:
可以比较详细的了解到:
GraphicBuffer是通过ION在不同heap上分配的内存,其需要通过
内存映射(IOCTL_KGSL_MAP_USER_MEM)映射到GPU,GPU就可以获取该buffer
另外还可以了解到,GPU的command buffer、texture、vertex buffer是通过IOCTL_KGSL_GPUMEM_ALLOC在GPU上分配的内存,只了解一下,不做详细研究了。
下边从代码上了解下GraphicBuffer的定义及具体分配过程,
GraphicBuffer其实是一个ANativeWindowBuffer型buffer,类定义如下:
//frameworks\native\libs\ui\include\ui\GraphicBuffer.h
class GraphicBuffer
: public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
public Flattenable<GraphicBuffer>
GraphicBuffer分配发生在Surface::dequeueBuffer,在满足条件时Surface会去申请分配一份新的GraphicBuffer
//frameworks\native\libs\gui
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
..
status_t result = mGraphicBufferProducer->dequeueBuffer(...)
}
其中mGraphicBufferProducer是BpGraphicBufferProducer代理对象,其对应的本地对象BnGraphicBufferProducer在SurfaceFlinger服务端,实现类为BufferQueueProducer
//frameworks\native\libs\gui\BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(.....) {
....
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
width, height, format, BQ_LAYER_COUNT, usage,
{
mConsumerName.string(), mConsumerName.size()});
....
}
在BufferQueueProducer的returnFlags为BUFFER_NEEDS_REALLOCATION会创建一个新的GraphicBuffer对象
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
: GraphicBuffer()
{
mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
usage, std::move(requestorName));
}
创建新的GraphicBuffer时,通过GraphicBuffer::initWithSize中会向[email protected]服务申请GraphicBuffer申请,中间详细过程不再分析了,只列出三个主要函数
第一步,申请入口
status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
std::string requestorName)
{
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
inUsage, &handle, &outStride, mId,
std::move(requestorName));
...
}
第二步,通过mMapper创建buffer的descriptor,然后继续发起申请
//frameworks\native\libs\ui\include\ui\Gralloc2.h
Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
uint32_t* outStride, buffer_handle_t* outBufferHandles) const
{
BufferDescriptor descriptor;
Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
error = allocate(descriptor, count, outStride, outBufferHandles);
}
第三步,通过Allocator::allocate向[email protected]服务发起申请,然后将申请到的内存通过mMapper.importBuffer方法映射到SurfaceFlinger进程
//frameworks\native\libs\ui\Gralloc2.cpp
Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
uint32_t* outStride, buffer_handle_t* outBufferHandles) const
{
...
auto ret = mAllocator->allocate(descriptor, count,
[&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
// import buffers
for (uint32_t i = 0; i < count; i++) {
...
//mMapper又是一个代理对象,对应的服务启动比较贴别
//代码在frameworks\native\libs\ui\Gralloc2.cpp
error = mMapper.importBuffer(tmpBuffers[i], &outBufferHandles[i]);
}
});
....
}
[email protected]服务中对的的allocate方法为Gralloc1Allocator::allocate
进程入口:
//hardware\interfaces\graphics\allocator\2.0\default\Gralloc1Allocator.cpp
Return<void> Gralloc1Allocator::allocate(const BufferDescriptor& descriptor,
uint32_t count, allocate_cb hidl_cb){
}
Gralloc1Allocator会通过gralloc HAL来完成GraphicBuffer的分配,gralloc HAL定义在
//hardware\qcom\display\libgralloc1\gr_device_impl.cpp
struct gralloc_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = GRALLOC_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = GRALLOC_HARDWARE_MODULE_ID,
.name = "Graphics Memory Module",
.author = "Code Aurora Forum",
.methods = &gralloc_module_methods,
.dso = 0,
.reserved = {
0},
},
};
gralloc HAL对应Gralloc1Allocator::allocate的接口为
//hardware\qcom\display\libgralloc1\gr_device_impl.cpp
gralloc1_error_t GrallocImpl::AllocateBuffers(gralloc1_device_t *device, uint32_t num_descriptors,
const gralloc1_buffer_descriptor_t *descriptors,
buffer_handle_t *out_buffers) {
...
gralloc1_error_t status = dev->buf_mgr_->AllocateBuffers(num_descriptors, descriptors,
out_buffers);
return status;
}
gralloc HAL最终是使用ION分配GraphicBuffer的,代码如下
//hardware\qcom\display\libgralloc1\gr_ion_alloc.cpp
int IonAlloc::AllocBuffer(AllocData *data) {
ATRACE_CALL();
int err = 0;
struct ion_handle_data handle_data;
struct ion_fd_data fd_data;
struct ion_allocation_data ion_alloc_data;
ion_alloc_data.len = data->size;
ion_alloc_data.align = data->align;
ion_alloc_data.heap_id_mask = data->heap_id;//不同heap
ion_alloc_data.flags = data->flags;//
ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED;
std::string tag_name{
};
if (ATRACE_ENABLED()) {
tag_name = "ION_IOC_ALLOC size: " + std::to_string(data->size);
}
ATRACE_BEGIN(tag_name.c_str());
if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) {
err = -errno;
ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));
return err;
}
ATRACE_END();
fd_data.handle = ion_alloc_data.handle;
handle_data.handle = ion_alloc_data.handle;
ATRACE_BEGIN("ION_IOC_MAP");
if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) {
err = -errno;
ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno));
ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data);
return err;
}
ATRACE_END();
data->fd = fd_data.fd;
data->ion_handle = handle_data.handle;
ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x",
ion_alloc_data.len, data->fd, data->ion_handle);
return 0;
}
另外,最新发现一个完整的Graphicbuffer分配的demo,感觉比较好,记录下
//\chi-cdk\test\camx-hal3-test
int BufferManager::AllocateOneBuffer(
uint32_t width,
uint32_t height,
uint32_t format,
uint64_t producerUsageFlags,
uint64_t consumerUsageFlags,
buffer_handle_t* pAllocatedBuffer,
uint32_t* pStride,
uint32_t index)
{
int32_t result = 0;
#ifdef USE_GRALLOC1
result = GRALLOC1_ERROR_NONE;
gralloc1_buffer_descriptor_t gralloc1BufferDescriptor;
result = mGrallocInterface.CreateDescriptor(mGralloc1Device, &gralloc1BufferDescriptor);
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.SetDimensions(mGralloc1Device, gralloc1BufferDescriptor, width, height);
}
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.SetFormat(mGralloc1Device, gralloc1BufferDescriptor, format);
}
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.SetProducerUsage(mGralloc1Device, gralloc1BufferDescriptor, producerUsageFlags);
}
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.SetConsumerUsage(mGralloc1Device, gralloc1BufferDescriptor, consumerUsageFlags);
}
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.Allocate(mGralloc1Device, 1, &gralloc1BufferDescriptor, &pAllocatedBuffer[0]);
}
if (GRALLOC1_ERROR_NONE == result)
{
result = mGrallocInterface.GetStride(mGralloc1Device, *pAllocatedBuffer, pStride);
}
if (GRALLOC1_ERROR_NONE != result)
{
ALOGE("allocate buffer failed\n");
return result;
}
private_handle_t *hnl = ((private_handle_t *)(*pAllocatedBuffer));
mBufferinfo[index].vaddr= mmap(NULL, hnl->size, PROT_READ | PROT_WRITE, MAP_SHARED, hnl->fd, 0);
mBufferinfo[index].size = hnl->size;
ALOGE("vaddr: %p fd: %d", mBufferinfo[index].vaddr, ((private_handle_t *)(*pAllocatedBuffer))->fd);
mGrallocInterface.DestroyDescriptor(mGralloc1Device, gralloc1BufferDescriptor);
#else
struct ion_allocation_data alloc;
struct ion_fd_data ion_info_fd;
struct ion_fd_data data2;
native_handle_t* nh = nullptr;
int rc;
size_t buf_size;
if (mIonFd <= 0) {
mIonFd = open("/dev/ion", O_RDONLY);
}
if (mIonFd <= 0) {
ALOGE("Ion dev open failed %s\n", strerror(errno));
return NULL;
}
memset(&alloc, 0, sizeof(alloc));
if (height == 1) {
// Blob
buf_size = (size_t)width;
} else {
buf_size = (size_t)(width * height * 2);
}
alloc.len = (size_t)(buf_size);
alloc.len = (alloc.len + 4095U) & (~4095U);
alloc.align = 4096;
alloc.flags = ION_FLAG_CACHED;
alloc.heap_id_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
rc = ioctl(mIonFd, ION_IOC_ALLOC, &alloc);
if (rc < 0) {
ALOGE("ION allocation failed %s with rc = %d fd:%d\n", strerror(errno), rc, mIonFd);
return NULL;
}
memset(&ion_info_fd, 0, sizeof(ion_info_fd));
ion_info_fd.handle = alloc.handle;
rc = ioctl(mIonFd, ION_IOC_SHARE, &ion_info_fd);
if (rc < 0) {
ALOGE("ION map failed %s\n", strerror(errno));
return NULL;
}
ALOGD("%s ION FD %d len %d\n", __func__, ion_info_fd.fd, alloc.len);
if (!mIsMetaBuf) {
*pAllocatedBuffer = native_handle_create(2, 4);
nh = (native_handle_t*)(*pAllocatedBuffer);
(nh)->data[0] = ion_info_fd.fd;
(nh)->data[1] = 0;
(nh)->data[2] = 0;
(nh)->data[3] = 0;
(nh)->data[4] = alloc.len;
(nh)->data[5] = 0;
} else {
/*alloc private handle_t */
/*(buffer_handler_t **)*/
if (!mIsUBWC) {
*pAllocatedBuffer = native_handle_create(1, 2);
nh = (native_handle_t*)(*pAllocatedBuffer);
(nh)->data[0] = ion_info_fd.fd;
(nh)->data[1] = 0;
(nh)->data[2] = alloc.len;
} else {
/*UBWC Mode*/
#if 0
private_handle_t *pnh = new private_handle_t(ion_info_fd.fd,
alloc.len,
0,
0,
0,
width,
height);
*pAllocatedBuffer = (native_handle_t *)pnh;
pnh->flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
pnh->width = width;
pnh->height = height;
pnh->size = alloc.len;
pnh->unaligned_width = width;
pnh->unaligned_height = height;
pnh->fd = ion_info_fd.fd;
pnh->format = format;
#endif
}
}
data2.handle = ion_info_fd.handle;
rc = ioctl(mIonFd, ION_IOC_MAP, &data2);
if (rc) {
ALOGE("ION MAP failed %s\n", strerror(errno));
return NULL;
}
mBufferinfo[index].vaddr = mmap(NULL, alloc.len, PROT_READ | PROT_WRITE, MAP_SHARED, data2.fd, 0);
ALOGI("Alloc buffer fd:%d len:%d vaddr:%p\n",data2.fd,alloc.len,mBufferinfo[index].vaddr);
mBufferinfo[index].size = alloc.len;
mBufferinfo[index].allocData = alloc;
mBufferinfo[index].fd = ion_info_fd.fd;
#endif
return result;
}
/************************************************************************
* name : FreeAllBuffers
* function: free buffers
************************************************************************/
void BufferManager::FreeAllBuffers()
{
for (uint32_t i = 0; i < mNumBuffers; i++)
{
if (NULL != mBuffers[i])
{
munmap(mBufferinfo[i].vaddr, mBufferinfo[i].size);
#ifdef USE_GRALLOC1
mGrallocInterface.Release(mGralloc1Device, mBuffers[i]);
#else
ioctl(mIonFd, ION_IOC_FREE,mBufferinfo[i].allocData.handle);
close(mBufferinfo[i].fd);
native_handle_close((native_handle_t *)mBuffers[i]);
native_handle_delete((native_handle_t *)mBuffers[i]);
#endif
mBuffers[i] = NULL;
}
}
}