android_hardware_aw/hwc/octopus/hwc_ion.cpp
2016-08-06 18:02:22 -04:00

244 lines
6.4 KiB
C++
Executable file

/*
* Copyright (C) Allwinner Tech All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#include "hwc.h"
ion_user_handle_t ion_alloc_buffer(int iAllocBytes, unsigned int heap_mask)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
int ret = -1;
struct ion_allocation_data sAllocInfo =
{
.len = (size_t)ALIGN(iAllocBytes, 4096),
.align = 4096,
.heap_id_mask = heap_mask,
.flags = 0,
.handle = 0,
};
ret = ioctl(Globctx->IonFd, ION_IOC_ALLOC, &sAllocInfo);
if(ret < 0)
{
ALOGW("%s: ION_IOC_ALLOC failed (ret=%d)", __func__, ret);
return (ion_user_handle_t) -1;
}
return sAllocInfo.handle;
}
int ion_free_buffer(ion_user_handle_t handle)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
ion_handle_data freedata;
int ret = -1;
freedata.handle = handle;
ret = ioctl(Globctx->IonFd, ION_IOC_FREE, &freedata);
if(ret < 0)
{
ALOGE("%s: ION_IOC_FREE failed (ret=%d)", __func__, ret);
}
return ret;
}
unsigned int ion_get_addr_fromfd(int sharefd)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
int ret = -1;
struct ion_custom_data custom_data;
sunxi_phys_data phys_data;
ion_handle_data freedata;
struct ion_fd_data data ;
data.fd = sharefd;
ret = ioctl(Globctx->IonFd, ION_IOC_IMPORT, &data);
if (ret < 0)
{
ALOGE("%s: ION_IOC_IMPORT failed(ret=%d)", __func__, ret);
return 0;
}
custom_data.cmd = ION_IOC_SUNXI_PHYS_ADDR;
phys_data.handle = data.handle;
custom_data.arg = (unsigned long)&phys_data;
ret = ioctl(Globctx->IonFd, ION_IOC_CUSTOM, &custom_data);
if(ret < 0)
{
ALOGE("%s: ION_IOC_CUSTOM failed(ret=%d)", __func__, ret);
return 0;
}
freedata.handle = data.handle;
ret = ioctl(Globctx->IonFd, ION_IOC_FREE, &freedata);
if(ret < 0)
{
ALOGE("%s: ION_IOC_FREE failed(ret=%d)", __func__, ret);
return 0;
}
return phys_data.phys_addr;
}
unsigned long ion_get_addr_from_handle(ion_user_handle_t handle)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
struct ion_custom_data custom_data;
sunxi_phys_data phys_data;
int ret = -1;
phys_data.handle = handle;
custom_data.cmd = ION_IOC_SUNXI_PHYS_ADDR;
custom_data.arg = (unsigned long)&phys_data;
ret = ioctl(Globctx->IonFd, ION_IOC_CUSTOM, &custom_data);
if(ret < 0)
{
ALOGE("%s: ION_IOC_CUSTOM failed (ret=%d)", __func__, ret);
return 0;
}
return phys_data.phys_addr;
}
ion_user_handle_t ion_handle_add_ref(int sharefd)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
struct ion_fd_data data;
data.fd = sharefd;
int ret;
ret = ioctl(Globctx->IonFd, ION_IOC_IMPORT, &data);
if (ret < 0)
{
ALOGE("%s: ION_IOC_IMPORT failed(ret=%d)", __func__, ret);
return -1;
}
return data.handle;
}
void ion_handle_dec_ref(ion_user_handle_t handle_id)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
ion_handle_data freedata;
freedata.handle = handle_id;
int ret;
ret = ioctl(Globctx->IonFd, ION_IOC_FREE, &freedata);
if(ret < 0)
{
ALOGE("%s: ION_IOC_FREE failed(ret=%d)", __func__, ret);
}
}
static inline hwc_ion_hold_t *ion_find_least(void)
{
SUNXI_hwcdev_context_t *Globctx = &gSunxiHwcDevice;
int i, cnt = 0;
hwc_ion_hold_t *ion_cache = NULL;
unsigned int little_sync = Globctx->HWCFramecount;
for(i = 0; i < ION_HOLD_CNT; i++)
{
ion_cache = &Globctx->ion_hold[i];
if(little_sync > ion_cache->sync_count)
{
little_sync = ion_cache->sync_count;
cnt = i;
if(little_sync == 0)
{
break;
}
}
}
return &Globctx->ion_hold[cnt];
}
void ion_free_cache(hwc_ion_hold_t *ion_cache)
{
int i;
int *handle_id = NULL;
handle_id = ion_cache->handle_array;
for(i = 0; (i < ion_cache->num_array) && (handle_id != NULL); i++, handle_id++)
{
if(*handle_id >= 0)
{
close(*handle_id);
}
*handle_id = -1;
}
ion_cache->num_used = 0;
}
bool hwc_manage_ref_cache(bool cache, hwc_dispc_data_t *dispc_data)
{
hwc_ion_hold_t *ion_cache = NULL;
int i, little_sync, cnt = 0, size = 0;
hwc_commit_layer_t *commit_layer = NULL;
int *_array = NULL;
if(!cache)
{
for(i = 0; i < NUMBEROFDISPLAY; i++)
{
for(cnt = 0; cnt < dispc_data->layer_num_inused[i]; cnt++)
{
commit_layer = &dispc_data->hwc_layer_info[i][cnt];
if(commit_layer->share_fd >= 0)
{
close(commit_layer->share_fd);
commit_layer->share_fd = -1;
}
}
}
goto manage_ok;
}
ion_cache = ion_find_least();
ion_free_cache(ion_cache);
cnt = NUMBEROFDISPLAY;
size = 0;
while(cnt--)
{
size += dispc_data->layer_num_inused[cnt];
}
if((ion_cache->handle_array == NULL) || (ion_cache->num_array < size))
{
if(ion_cache->handle_array != NULL)
{
free(ion_cache->handle_array);
ion_cache->handle_array = NULL;
}
ion_cache->handle_array = (int* )calloc(size, sizeof(int));
if(ion_cache->handle_array == NULL)
{
ALOGD("calloc ion_user_handle_t err");
return 0;
}
memset(ion_cache->handle_array, -1, size * sizeof(int));
ion_cache->num_array = size;
}
_array = ion_cache->handle_array;
for(i = 0; i < NUMBEROFDISPLAY; i++)
{
commit_layer = dispc_data->hwc_layer_info[i];
for(cnt = 0; cnt < dispc_data->layer_num_inused[i]; cnt++, _array++, commit_layer++)
{
*_array = commit_layer->share_fd;
}
}
ion_cache->num_used = size;
ion_cache->sync_count = dispc_data->sync_count;
manage_ok:
return 1;
}