/* * 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; } };