/*
|
* cl_memory.cpp - CL memory
|
*
|
* Copyright (c) 2015 Intel Corporation
|
*
|
* 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.
|
*
|
* Author: Wind Yuan <feng.yuan@intel.com>
|
*/
|
|
#include "cl_utils.h"
|
#include "cl_memory.h"
|
#if HAVE_LIBDRM
|
#include "intel/cl_va_memory.h"
|
#endif
|
|
namespace XCam {
|
|
CLImageDesc::CLImageDesc ()
|
: format {CL_R, CL_UNORM_INT8}
|
, width (0)
|
, height (0)
|
, row_pitch (0)
|
, slice_pitch (0)
|
, array_size (0)
|
, size (0)
|
{
|
}
|
|
bool
|
CLImageDesc::operator == (const CLImageDesc& desc) const
|
{
|
if (desc.format.image_channel_data_type == this->format.image_channel_data_type &&
|
desc.format.image_channel_order == this->format.image_channel_order &&
|
desc.width == this->width &&
|
desc.height == this->height &&
|
desc.row_pitch == this->row_pitch &&
|
desc.slice_pitch == this->slice_pitch &&
|
desc.array_size == this->array_size)// &&
|
//desc.size == this->size)
|
return true;
|
return false;
|
}
|
|
CLMemory::CLMemory (const SmartPtr<CLContext> &context)
|
: _context (context)
|
, _mem_id (NULL)
|
, _mem_fd (-1)
|
, _mem_need_destroy (true)
|
, _mapped_ptr (NULL)
|
{
|
XCAM_ASSERT (context.ptr () && context->is_valid ());
|
}
|
|
CLMemory::~CLMemory ()
|
{
|
release_fd ();
|
|
if (_mapped_ptr)
|
enqueue_unmap (_mapped_ptr);
|
|
if (_mem_id && _mem_need_destroy) {
|
_context->destroy_mem (_mem_id);
|
}
|
}
|
|
int32_t
|
CLMemory::export_fd ()
|
{
|
if (_mem_fd >= 0)
|
return _mem_fd;
|
|
#if HAVE_LIBDRM
|
SmartPtr<CLIntelContext> context = _context.dynamic_cast_ptr<CLIntelContext> ();
|
_mem_fd = context->export_mem_fd (_mem_id);
|
#endif
|
if (_mem_fd < 0)
|
XCAM_LOG_ERROR ("invalid fd:%d", _mem_fd);
|
|
return _mem_fd;
|
}
|
|
void
|
CLMemory::release_fd ()
|
{
|
if (_mem_fd <= 0)
|
return;
|
|
close (_mem_fd);
|
_mem_fd = -1;
|
}
|
|
XCamReturn
|
CLMemory::enqueue_unmap (
|
void *ptr,
|
CLEventList &event_waits,
|
SmartPtr<CLEvent> &event_out)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
cl_mem mem_id = get_mem_id ();
|
|
XCAM_ASSERT (is_valid ());
|
if (!is_valid ())
|
return XCAM_RETURN_ERROR_PARAM;
|
|
XCAM_ASSERT (ptr == _mapped_ptr);
|
if (ptr == _mapped_ptr)
|
_mapped_ptr = NULL;
|
|
return context->enqueue_unmap (mem_id, ptr, event_waits, event_out);
|
}
|
|
bool CLMemory::get_cl_mem_info (
|
cl_image_info param_name, size_t param_size,
|
void *param, size_t *param_size_ret)
|
{
|
cl_mem mem_id = get_mem_id ();
|
cl_int error_code = CL_SUCCESS;
|
if (!mem_id)
|
return false;
|
|
error_code = clGetMemObjectInfo (mem_id, param_name, param_size, param, param_size_ret);
|
XCAM_FAIL_RETURN(
|
WARNING,
|
error_code == CL_SUCCESS,
|
false,
|
"clGetMemObjectInfo failed on param:%d, errno:%d", param_name, error_code);
|
return true;
|
}
|
|
CLBuffer::CLBuffer (const SmartPtr<CLContext> &context)
|
: CLMemory (context)
|
{
|
}
|
|
CLBuffer::CLBuffer (
|
const SmartPtr<CLContext> &context, uint32_t size,
|
cl_mem_flags flags, void *host_ptr)
|
: CLMemory (context)
|
, _flags (flags)
|
, _size (size)
|
{
|
init_buffer (context, size, flags, host_ptr);
|
}
|
|
bool
|
CLBuffer::init_buffer (
|
const SmartPtr<CLContext> &context, uint32_t size,
|
cl_mem_flags flags, void *host_ptr)
|
{
|
cl_mem mem_id = NULL;
|
|
mem_id = context->create_buffer (size, flags, host_ptr);
|
if (mem_id == NULL) {
|
XCAM_LOG_WARNING ("CLBuffer create buffer failed");
|
return false;
|
}
|
|
set_mem_id (mem_id);
|
return true;
|
}
|
|
CLSubBuffer::CLSubBuffer (
|
const SmartPtr<CLContext> &context, SmartPtr<CLBuffer> main_buf,
|
cl_mem_flags flags, uint32_t offset, uint32_t size)
|
: CLBuffer (context)
|
, _main_buf (main_buf)
|
, _flags (flags)
|
, _size (size)
|
{
|
init_sub_buffer (context, main_buf, flags, offset, size);
|
}
|
|
bool
|
CLSubBuffer::init_sub_buffer (
|
const SmartPtr<CLContext> &context,
|
SmartPtr<CLBuffer> main_buf,
|
cl_mem_flags flags,
|
uint32_t offset,
|
uint32_t size)
|
{
|
cl_mem sub_mem = NULL;
|
cl_mem main_mem = main_buf->get_mem_id ();
|
XCAM_FAIL_RETURN (ERROR, main_mem != NULL, false, "get memory from main image failed");
|
|
cl_buffer_region region;
|
region.origin = offset;
|
region.size = size;
|
|
sub_mem = context->create_sub_buffer (main_mem, region, flags);
|
if (sub_mem == NULL) {
|
XCAM_LOG_WARNING ("CLBuffer create sub buffer failed");
|
return false;
|
}
|
|
set_mem_id (sub_mem);
|
return true;
|
}
|
|
XCamReturn
|
CLBuffer::enqueue_read (
|
void *ptr, uint32_t offset, uint32_t size,
|
CLEventList &event_waits,
|
SmartPtr<CLEvent> &event_out)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
cl_mem mem_id = get_mem_id ();
|
|
XCAM_ASSERT (is_valid ());
|
if (!is_valid ())
|
return XCAM_RETURN_ERROR_PARAM;
|
|
return context->enqueue_read_buffer (mem_id, ptr, offset, size, true, event_waits, event_out);
|
}
|
|
XCamReturn
|
CLBuffer::enqueue_write (
|
void *ptr, uint32_t offset, uint32_t size,
|
CLEventList &event_waits,
|
SmartPtr<CLEvent> &event_out)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
cl_mem mem_id = get_mem_id ();
|
|
XCAM_ASSERT (is_valid ());
|
if (!is_valid ())
|
return XCAM_RETURN_ERROR_PARAM;
|
|
return context->enqueue_write_buffer (mem_id, ptr, offset, size, true, event_waits, event_out);
|
}
|
|
XCamReturn
|
CLBuffer::enqueue_map (
|
void *&ptr, uint32_t offset, uint32_t size,
|
cl_map_flags map_flags,
|
CLEventList &event_waits,
|
SmartPtr<CLEvent> &event_out)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
cl_mem mem_id = get_mem_id ();
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
|
XCAM_ASSERT (is_valid ());
|
if (!is_valid ())
|
return XCAM_RETURN_ERROR_PARAM;
|
|
ret = context->enqueue_map_buffer (mem_id, ptr, offset, size, true, map_flags, event_waits, event_out);
|
XCAM_FAIL_RETURN (
|
WARNING,
|
ret == XCAM_RETURN_NO_ERROR,
|
ret,
|
"enqueue_map failed ");
|
|
set_mapped_ptr (ptr);
|
return ret;
|
}
|
|
CLImage::CLImage (const SmartPtr<CLContext> &context)
|
: CLMemory (context)
|
{
|
}
|
|
uint32_t
|
CLImage::get_pixel_bytes () const
|
{
|
return calculate_pixel_bytes(_image_desc.format);
|
}
|
|
bool
|
CLImage::get_cl_image_info (cl_image_info param_name, size_t param_size, void *param, size_t *param_size_ret)
|
{
|
cl_mem mem_id = get_mem_id ();
|
cl_int error_code = CL_SUCCESS;
|
if (!mem_id)
|
return false;
|
|
error_code = clGetImageInfo (mem_id, param_name, param_size, param, param_size_ret);
|
XCAM_FAIL_RETURN(
|
WARNING,
|
error_code == CL_SUCCESS,
|
false,
|
"clGetImageInfo failed on param:%d, errno:%d", param_name, error_code);
|
return true;
|
}
|
|
uint32_t
|
CLImage::calculate_pixel_bytes (const cl_image_format &fmt)
|
{
|
uint32_t a = 0, b = 0;
|
switch (fmt.image_channel_order) {
|
case CL_R:
|
case CL_A:
|
case CL_Rx:
|
a = 1;
|
break;
|
case CL_RG:
|
case CL_RA:
|
case CL_RGx:
|
a = 2;
|
break;
|
case CL_RGB:
|
case CL_RGBx:
|
a = 3;
|
break;
|
case CL_RGBA:
|
case CL_BGRA:
|
case CL_ARGB:
|
a = 4;
|
break;
|
default:
|
XCAM_LOG_DEBUG ("calculate_pixel_bytes with wrong channel_order:0x%04x", fmt.image_channel_order);
|
return 0;
|
}
|
|
switch (fmt.image_channel_data_type) {
|
case CL_UNORM_INT8:
|
case CL_SNORM_INT8:
|
case CL_SIGNED_INT8:
|
case CL_UNSIGNED_INT8:
|
b = 1;
|
break;
|
case CL_SNORM_INT16:
|
case CL_UNORM_INT16:
|
case CL_SIGNED_INT16:
|
case CL_UNSIGNED_INT16:
|
case CL_HALF_FLOAT:
|
b = 2;
|
break;
|
case CL_UNORM_INT24:
|
b = 3;
|
break;
|
case CL_SIGNED_INT32:
|
case CL_UNSIGNED_INT32:
|
case CL_FLOAT:
|
b = 4;
|
break;
|
default:
|
XCAM_LOG_DEBUG ("calculate_pixel_bytes with wrong channel_data_type:0x%04x", fmt.image_channel_data_type);
|
return 0;
|
}
|
|
return a * b;
|
}
|
|
bool
|
CLImage::video_info_2_cl_image_desc (
|
const VideoBufferInfo & video_info,
|
CLImageDesc &image_desc)
|
{
|
image_desc.width = video_info.width;
|
image_desc.height = video_info.height;
|
image_desc.array_size = 0;
|
image_desc.row_pitch = video_info.strides[0];
|
XCAM_ASSERT (image_desc.row_pitch >= image_desc.width);
|
image_desc.slice_pitch = 0;
|
|
switch (video_info.format) {
|
case XCAM_PIX_FMT_RGB48:
|
//cl_image_info.fmt.image_channel_order = CL_RGB;
|
//cl_image_info.fmt.image_channel_data_type = CL_UNORM_INT16;
|
XCAM_LOG_WARNING (
|
"video_info to cl_image_info doesn't support XCAM_PIX_FMT_RGB48, maybe try XCAM_PIX_FMT_RGBA64 instread\n"
|
" **** XCAM_PIX_FMT_RGB48 need check with cl implementation ****");
|
return false;
|
break;
|
case V4L2_PIX_FMT_GREY:
|
image_desc.format.image_channel_order = CL_R;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
|
case XCAM_PIX_FMT_RGBA64:
|
image_desc.format.image_channel_order = CL_RGBA;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT16;
|
break;
|
|
case V4L2_PIX_FMT_RGB24:
|
image_desc.format.image_channel_order = CL_RGB;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
|
case V4L2_PIX_FMT_RGB565:
|
image_desc.format.image_channel_order = CL_RGB;
|
image_desc.format.image_channel_data_type = CL_UNORM_SHORT_565;
|
break;
|
case V4L2_PIX_FMT_XBGR32:
|
case V4L2_PIX_FMT_ABGR32:
|
case V4L2_PIX_FMT_BGR32:
|
image_desc.format.image_channel_order = CL_BGRA;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
// cl doesn'tn support ARGB32 up to now, how about consider V4L2_PIX_FMT_RGBA32
|
case V4L2_PIX_FMT_RGB32:
|
case V4L2_PIX_FMT_ARGB32:
|
case V4L2_PIX_FMT_XRGB32:
|
image_desc.format.image_channel_order = CL_ARGB;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
|
case V4L2_PIX_FMT_RGBA32:
|
image_desc.format.image_channel_order = CL_RGBA;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
|
case V4L2_PIX_FMT_SBGGR10:
|
case V4L2_PIX_FMT_SGBRG10:
|
case V4L2_PIX_FMT_SGRBG10:
|
case V4L2_PIX_FMT_SRGGB10:
|
case V4L2_PIX_FMT_SBGGR12:
|
case V4L2_PIX_FMT_SGBRG12:
|
case V4L2_PIX_FMT_SGRBG12:
|
case V4L2_PIX_FMT_SRGGB12:
|
case V4L2_PIX_FMT_SBGGR16:
|
case XCAM_PIX_FMT_SGRBG16:
|
image_desc.format.image_channel_order = CL_R;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT16;
|
break;
|
|
case V4L2_PIX_FMT_SBGGR8:
|
case V4L2_PIX_FMT_SGBRG8:
|
case V4L2_PIX_FMT_SGRBG8:
|
case V4L2_PIX_FMT_SRGGB8:
|
image_desc.format.image_channel_order = CL_R;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
break;
|
|
case V4L2_PIX_FMT_NV12:
|
image_desc.format.image_channel_order = CL_R;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
image_desc.array_size = 2;
|
image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height;
|
break;
|
|
case V4L2_PIX_FMT_YUYV:
|
image_desc.format.image_channel_order = CL_RGBA;
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
image_desc.width /= 2;
|
break;
|
|
case XCAM_PIX_FMT_LAB:
|
image_desc.format.image_channel_order = CL_R;
|
image_desc.format.image_channel_data_type = CL_FLOAT;
|
break;
|
|
case XCAM_PIX_FMT_RGB48_planar:
|
case XCAM_PIX_FMT_RGB24_planar:
|
image_desc.format.image_channel_order = CL_RGBA;
|
if (XCAM_PIX_FMT_RGB48_planar == video_info.format)
|
image_desc.format.image_channel_data_type = CL_UNORM_INT16;
|
else
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
image_desc.width = video_info.aligned_width / 4;
|
image_desc.array_size = 3;
|
image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height;
|
break;
|
|
case XCAM_PIX_FMT_SGRBG16_planar:
|
case XCAM_PIX_FMT_SGRBG8_planar:
|
image_desc.format.image_channel_order = CL_RGBA;
|
if (XCAM_PIX_FMT_SGRBG16_planar == video_info.format)
|
image_desc.format.image_channel_data_type = CL_UNORM_INT16;
|
else
|
image_desc.format.image_channel_data_type = CL_UNORM_INT8;
|
image_desc.width = video_info.aligned_width / 4;
|
image_desc.array_size = 4;
|
image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height;
|
break;
|
|
default:
|
XCAM_LOG_WARNING (
|
"video_info to cl_image_info doesn't support format:%s",
|
xcam_fourcc_to_string (video_info.format));
|
return false;
|
}
|
|
return true;
|
}
|
|
void
|
CLImage::init_desc_by_image ()
|
{
|
size_t width = 0, height = 0, row_pitch = 0, slice_pitch = 0, array_size = 0, mem_size = 0;
|
cl_image_format format = {CL_R, CL_UNORM_INT8};
|
|
get_cl_image_info (CL_IMAGE_FORMAT, sizeof(format), &format);
|
get_cl_image_info (CL_IMAGE_WIDTH, sizeof(width), &width);
|
get_cl_image_info (CL_IMAGE_HEIGHT, sizeof(height), &height);
|
get_cl_image_info (CL_IMAGE_ROW_PITCH, sizeof(row_pitch), &row_pitch);
|
get_cl_image_info (CL_IMAGE_SLICE_PITCH, sizeof(slice_pitch), &slice_pitch);
|
get_cl_image_info (CL_IMAGE_ARRAY_SIZE, sizeof(array_size), &array_size);
|
get_cl_mem_info (CL_MEM_SIZE, sizeof(mem_size), &mem_size);
|
|
_image_desc.format = format;
|
_image_desc.width = width;
|
_image_desc.height = height;
|
_image_desc.row_pitch = row_pitch;
|
_image_desc.slice_pitch = slice_pitch;
|
_image_desc.array_size = array_size;
|
_image_desc.size = mem_size;
|
}
|
|
XCamReturn
|
CLImage::enqueue_map (
|
void *&ptr,
|
size_t *origin, size_t *region,
|
size_t *row_pitch, size_t *slice_pitch,
|
cl_map_flags map_flags,
|
CLEventList &event_waits,
|
SmartPtr<CLEvent> &event_out)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
cl_mem mem_id = get_mem_id ();
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
|
XCAM_ASSERT (is_valid ());
|
if (!is_valid ())
|
return XCAM_RETURN_ERROR_PARAM;
|
|
ret = context->enqueue_map_image (mem_id, ptr, origin, region, row_pitch, slice_pitch, true, map_flags, event_waits, event_out);
|
XCAM_FAIL_RETURN (
|
WARNING,
|
ret == XCAM_RETURN_NO_ERROR,
|
ret,
|
"enqueue_map failed ");
|
|
set_mapped_ptr (ptr);
|
return ret;
|
}
|
|
CLImage2D::CLImage2D (
|
const SmartPtr<CLContext> &context,
|
const VideoBufferInfo &video_info,
|
cl_mem_flags flags)
|
: CLImage (context)
|
{
|
CLImageDesc cl_desc;
|
|
if (!video_info_2_cl_image_desc (video_info, cl_desc)) {
|
XCAM_LOG_WARNING ("CLVaImage create va image failed on default videoinfo");
|
return;
|
}
|
|
init_image_2d (context, cl_desc, flags);
|
}
|
|
CLImage2D::CLImage2D (
|
const SmartPtr<CLContext> &context,
|
const CLImageDesc &cl_desc,
|
cl_mem_flags flags,
|
SmartPtr<CLBuffer> bind_buf)
|
: CLImage (context)
|
{
|
_bind_buf = bind_buf;
|
init_image_2d (context, cl_desc, flags);
|
}
|
|
bool CLImage2D::init_image_2d (
|
const SmartPtr<CLContext> &context,
|
const CLImageDesc &desc,
|
cl_mem_flags flags)
|
{
|
cl_mem mem_id = 0;
|
cl_image_desc cl_desc;
|
|
xcam_mem_clear (cl_desc);
|
cl_desc.image_type = CL_MEM_OBJECT_IMAGE2D;
|
cl_desc.image_width = desc.width;
|
cl_desc.image_height = desc.height;
|
cl_desc.image_depth = 1;
|
cl_desc.image_array_size = 0;
|
cl_desc.image_row_pitch = 0;
|
cl_desc.image_slice_pitch = 0;
|
cl_desc.num_mip_levels = 0;
|
cl_desc.num_samples = 0;
|
cl_desc.buffer = NULL;
|
if (_bind_buf.ptr ()) {
|
if (desc.row_pitch)
|
cl_desc.image_row_pitch = desc.row_pitch;
|
else {
|
cl_desc.image_row_pitch = calculate_pixel_bytes(desc.format) * desc.width;
|
}
|
XCAM_ASSERT (cl_desc.image_row_pitch);
|
cl_desc.buffer = _bind_buf->get_mem_id ();
|
XCAM_ASSERT (cl_desc.buffer);
|
}
|
|
mem_id = context->create_image (flags, desc.format, cl_desc);
|
if (mem_id == NULL) {
|
XCAM_LOG_WARNING ("CLImage2D create image 2d failed");
|
return false;
|
}
|
set_mem_id (mem_id);
|
init_desc_by_image ();
|
return true;
|
}
|
|
CLImage2DArray::CLImage2DArray (
|
const SmartPtr<CLContext> &context,
|
const VideoBufferInfo &video_info,
|
cl_mem_flags flags,
|
uint32_t extra_array_size)
|
: CLImage (context)
|
{
|
CLImageDesc cl_desc;
|
|
XCAM_ASSERT (video_info.components >= 2);
|
|
if (!video_info_2_cl_image_desc (video_info, cl_desc)) {
|
XCAM_LOG_WARNING ("CLVaImage create va image failed on default videoinfo");
|
return;
|
}
|
XCAM_ASSERT (cl_desc.array_size >= 2);
|
|
//special process for BYT platform for slice-pitch
|
//if (video_info.format == V4L2_PIX_FMT_NV12)
|
cl_desc.height = XCAM_ALIGN_UP (cl_desc.height, 16);
|
|
cl_desc.array_size += extra_array_size;
|
|
init_image_2d_array (context, cl_desc, flags);
|
}
|
|
bool CLImage2DArray::init_image_2d_array (
|
const SmartPtr<CLContext> &context,
|
const CLImageDesc &desc,
|
cl_mem_flags flags)
|
{
|
cl_mem mem_id = 0;
|
cl_image_desc cl_desc;
|
|
xcam_mem_clear (cl_desc);
|
cl_desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY;
|
cl_desc.image_width = desc.width;
|
cl_desc.image_height = desc.height;
|
cl_desc.image_depth = 1;
|
cl_desc.image_array_size = desc.array_size;
|
cl_desc.image_row_pitch = 0;
|
cl_desc.image_slice_pitch = 0;
|
cl_desc.num_mip_levels = 0;
|
cl_desc.num_samples = 0;
|
cl_desc.buffer = NULL;
|
|
mem_id = context->create_image (flags, desc.format, cl_desc);
|
if (mem_id == NULL) {
|
XCAM_LOG_WARNING ("CLImage2D create image 2d failed");
|
return false;
|
}
|
set_mem_id (mem_id);
|
init_desc_by_image ();
|
return true;
|
}
|
|
|
};
|