Home | History | Annotate | Download | only in ocl
      1 /*
      2  * cl_utils.cpp - CL Utilities
      3  *
      4  *  Copyright (c) 2016 Intel Corporation
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Wind Yuan <feng.yuan (at) intel.com>
     19  */
     20 
     21 #include "cl_utils.h"
     22 #include "image_file_handle.h"
     23 #if HAVE_LIBDRM
     24 #include "intel/cl_intel_context.h"
     25 #include "intel/cl_va_memory.h"
     26 #endif
     27 
     28 namespace XCam {
     29 
     30 struct NV12Pixel {
     31     float x_pos;
     32     float y_pos;
     33 
     34     float y;
     35     float u;
     36     float v;
     37 
     38     NV12Pixel ()
     39         : x_pos (0.0f), y_pos (0.0f)
     40         , y (0.0f), u (0.0f), v (0.0f)
     41     {}
     42 };
     43 
     44 static inline void
     45 clamp (float &value, float min, float max)
     46 {
     47     value = (value < min) ? min : ((value > max) ? max : value);
     48 }
     49 
     50 bool
     51 dump_image (SmartPtr<CLImage> image, const char *file_name)
     52 {
     53     XCAM_ASSERT (file_name);
     54 
     55     const CLImageDesc &desc = image->get_image_desc ();
     56     void *ptr = NULL;
     57     size_t origin[3] = {0, 0, 0};
     58     size_t region[3] = {desc.width, desc.height, 1};
     59     size_t row_pitch;
     60     size_t slice_pitch;
     61 
     62     XCamReturn ret = image->enqueue_map (ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ);
     63     XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "dump image failed in enqueue_map");
     64     XCAM_ASSERT (ptr);
     65     XCAM_ASSERT (row_pitch == desc.row_pitch);
     66     uint8_t *buf_start = (uint8_t *)ptr;
     67     uint32_t width = image->get_pixel_bytes () * desc.width;
     68 
     69     FILE *fp = fopen (file_name, "wb");
     70     XCAM_FAIL_RETURN (ERROR, fp, false, "open file(%s) failed", file_name);
     71 
     72     for (uint32_t i = 0; i < desc.height; ++i) {
     73         uint8_t *buf_line = buf_start + row_pitch * i;
     74         fwrite (buf_line, width, 1, fp);
     75     }
     76     image->enqueue_unmap (ptr);
     77     fclose (fp);
     78     XCAM_LOG_INFO ("write image:%s\n", file_name);
     79     return true;
     80 }
     81 
     82 SmartPtr<CLBuffer>
     83 convert_to_clbuffer (
     84     const SmartPtr<CLContext> &context,
     85     const SmartPtr<VideoBuffer> &buf)
     86 {
     87     SmartPtr<CLBuffer> cl_buf;
     88 
     89     SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> ();
     90     if (cl_video_buf.ptr ()) {
     91         cl_buf = cl_video_buf;
     92     }
     93 #if HAVE_LIBDRM
     94     else {
     95         SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> ();
     96         SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> ();
     97         XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ());
     98 
     99         cl_buf = new CLVaBuffer (ctx, bo_buf);
    100     }
    101 #else
    102     XCAM_UNUSED (context);
    103 #endif
    104 
    105     XCAM_FAIL_RETURN (WARNING, cl_buf.ptr (), NULL, "convert to clbuffer failed");
    106     return cl_buf;
    107 }
    108 
    109 SmartPtr<CLImage>
    110 convert_to_climage (
    111     const SmartPtr<CLContext> &context,
    112     SmartPtr<VideoBuffer> &buf,
    113     const CLImageDesc &desc,
    114     uint32_t offset,
    115     cl_mem_flags flags)
    116 {
    117     SmartPtr<CLImage> cl_image;
    118 
    119     SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> ();
    120     if (cl_video_buf.ptr ()) {
    121         SmartPtr<CLBuffer> cl_buf;
    122 
    123         if (offset == 0) {
    124             cl_buf = cl_video_buf;
    125         } else {
    126             uint32_t row_pitch = CLImage::calculate_pixel_bytes (desc.format) *
    127                                  XCAM_ALIGN_UP (desc.width, XCAM_CL_IMAGE_ALIGNMENT_X);
    128             uint32_t size = row_pitch * desc.height;
    129 
    130             cl_buf = new CLSubBuffer (context, cl_video_buf, flags, offset, size);
    131         }
    132 
    133         cl_image = new CLImage2D (context, desc, flags, cl_buf);
    134     }
    135 #if HAVE_LIBDRM
    136     else {
    137         SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> ();
    138         SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> ();
    139         XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ());
    140 
    141         cl_image = new CLVaImage (ctx, bo_buf, desc, offset);
    142     }
    143 #endif
    144 
    145     XCAM_FAIL_RETURN (WARNING, cl_image.ptr (), NULL, "convert to climage failed");
    146     return cl_image;
    147 }
    148 
    149 XCamReturn
    150 convert_nv12_mem_to_video_buffer (
    151     void *nv12_mem, uint32_t width, uint32_t height, uint32_t row_pitch, uint32_t offset_uv,
    152     SmartPtr<VideoBuffer> &buf)
    153 {
    154     XCAM_ASSERT (nv12_mem);
    155     XCAM_ASSERT (row_pitch >= width);
    156 
    157     VideoBufferPlanarInfo planar;
    158     const VideoBufferInfo info = buf->get_video_info ();
    159     XCAM_FAIL_RETURN (
    160         DEBUG, (width == info.width) && (height == info.height), XCAM_RETURN_ERROR_PARAM,
    161         "convert mem to video buffer failed since image sizes are not matched.");
    162 
    163     uint8_t *out_mem = buf->map ();
    164     XCAM_FAIL_RETURN (ERROR, out_mem, XCAM_RETURN_ERROR_MEM, "map buffer failed");
    165 
    166     uint8_t *src = (uint8_t *)nv12_mem;
    167     uint8_t *dest = NULL;
    168     for (uint32_t index = 0; index < info.components; index++) {
    169         info.get_planar_info (planar, index);
    170 
    171         dest = out_mem + info.offsets[index];
    172         for (uint32_t i = 0; i < planar.height; i++) {
    173             memcpy (dest, src, width);
    174             src += row_pitch;
    175             dest += info.strides[index];
    176         }
    177 
    178         src = (uint8_t *)nv12_mem + offset_uv;
    179     }
    180 
    181     buf->unmap ();
    182     return XCAM_RETURN_NO_ERROR;
    183 }
    184 
    185 XCamReturn
    186 interpolate_pixel_value (
    187     uint8_t* stitch_mem,
    188     float image_coord_x, float image_coord_y,
    189     float &y, float &u, float &v,
    190     const VideoBufferInfo& stitch_info)
    191 {
    192     XCAM_ASSERT (image_coord_y < stitch_info.height && image_coord_x < stitch_info.width);
    193 
    194     uint8_t y00, y01, y10, y11;
    195     uint8_t u00, u01, u10, u11;
    196     uint8_t v00, v01, v10, v11;
    197 
    198     uint32_t x0 = (uint32_t) image_coord_x;
    199     uint32_t x1 = (x0 < stitch_info.width - 1) ? (x0 + 1) : x0;
    200     uint32_t y0 = (uint32_t) image_coord_y;
    201     uint32_t y1 = (y0 < stitch_info.height - 1) ? (y0 + 1) : y0;
    202 
    203     float rate00 = (x0 + 1 - image_coord_x) * (y0 + 1 - image_coord_y);
    204     float rate01 = (x0 + 1 - image_coord_x) * (image_coord_y - y0);
    205     float rate10 = (image_coord_x - x0) * (y0 + 1 - image_coord_y);
    206     float rate11 = (image_coord_x - x0) * (image_coord_y - y0);
    207 
    208     y00 = stitch_mem[y0 * stitch_info.strides[0] + x0];
    209     y01 = stitch_mem[y1 * stitch_info.strides[0] + x0];
    210     y10 = stitch_mem[y0 * stitch_info.strides[0] + x1];
    211     y11 = stitch_mem[y1 * stitch_info.strides[0] + x1];
    212 
    213     u00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)];
    214     u01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)];
    215     u10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)];
    216     u11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)];
    217 
    218     v00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1];
    219     v01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1];
    220     v10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1];
    221     v11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1];
    222 
    223     y = y00 * rate00 + y01 * rate01 + y10 * rate10 + y11 * rate11;
    224     u = u00 * rate00 + u01 * rate01 + u10 * rate10 + u11 * rate11;
    225     v = v00 * rate00 + v01 * rate01 + v10 * rate10 + v11 * rate11;
    226 
    227     return XCAM_RETURN_NO_ERROR;
    228 }
    229 
    230 XCamReturn
    231 map_to_specific_view (
    232     uint8_t *specific_view_mem, uint8_t* stitch_mem,
    233     uint32_t row, uint32_t col,
    234     float image_coord_x, float image_coord_y,
    235     const VideoBufferInfo& specific_view_info, const VideoBufferInfo& stitch_info)
    236 {
    237     XCAM_ASSERT (row < specific_view_info.height && col < specific_view_info.width);
    238 
    239     float y, u, v;
    240 
    241     interpolate_pixel_value (stitch_mem, image_coord_x, image_coord_y, y, u, v, stitch_info);
    242 
    243     uint32_t y_index = row * specific_view_info.strides[0] + col;
    244     uint32_t u_index = specific_view_info.offsets[1] + row / 2 * specific_view_info.strides[1] + XCAM_ALIGN_DOWN (col, 2);
    245 
    246     specific_view_mem[y_index] = (uint8_t)y;
    247     specific_view_mem[u_index] = (uint8_t)u;
    248     specific_view_mem[u_index + 1] = (uint8_t)v;
    249 
    250     return XCAM_RETURN_NO_ERROR;
    251 }
    252 
    253 XCamReturn
    254 generate_topview_map_table (
    255     const VideoBufferInfo &stitch_info,
    256     const BowlDataConfig &config,
    257     std::vector<PointFloat2> &map_table,
    258     int width, int height)
    259 {
    260     int center_x = width / 2;
    261     int center_y = height / 2;
    262 
    263     float show_width_mm = 5000.0f;
    264     float length_per_pixel = show_width_mm / height;
    265 
    266     map_table.resize (height * width);
    267 
    268     for(int row = 0; row < height; row++) {
    269         for(int col = 0; col < width; col++) {
    270             PointFloat3 world;
    271             world.x = (col - center_x) * length_per_pixel;
    272             world.y = (center_y - row) * length_per_pixel;
    273             world.z = 0.0f;
    274 
    275             PointFloat2 image_pos =
    276                 bowl_view_coords_to_image (config, world, stitch_info.width, stitch_info.height);
    277 
    278             map_table[row * width + col] = image_pos;
    279         }
    280     }
    281 
    282     return XCAM_RETURN_NO_ERROR;
    283 }
    284 
    285 XCamReturn
    286 generate_rectifiedview_map_table (
    287     const VideoBufferInfo &stitch_info,
    288     const BowlDataConfig &config,
    289     std::vector<PointFloat2> &map_table,
    290     float angle_start, float angle_end,
    291     int width, int height)
    292 {
    293     float center_x = width / 2;
    294 
    295     float focal_plane_dist = 6000.0f;
    296 
    297     float angle_center = (angle_start + angle_end) / 2.0f;
    298     float theta = degree2radian((angle_end - angle_start)) / 2.0f;
    299     float length_per_pixel_x = 2 * focal_plane_dist * tan (theta) / width;
    300 
    301     float fov_up = degree2radian (20.0f);
    302     float fov_down = degree2radian (35.0f);
    303 
    304     float length_per_pixel_y = (focal_plane_dist * tan (fov_up) + focal_plane_dist * tan (fov_down)) / height;
    305 
    306     float center_y = tan (fov_up) / (tan (fov_up) + tan (fov_down)) * height;
    307 
    308     PointFloat3 world_pos;
    309     float plane_center_coords[3];
    310 
    311     plane_center_coords[0] = focal_plane_dist * cos (degree2radian (angle_center));
    312     plane_center_coords[1] = -focal_plane_dist * sin (degree2radian (angle_center));
    313     plane_center_coords[2] = 0.0f;
    314 
    315     map_table.resize (width * height);
    316 
    317     for (int row = 0; row < height; row++) {
    318         for (int col = 0; col < width; col++) {
    319             float plane_point_coords[3];
    320             plane_point_coords[0] = (center_x - col) * length_per_pixel_x * cos (PI / 2 - degree2radian (angle_center)) + plane_center_coords[0];
    321             plane_point_coords[1] = (center_x - col) * length_per_pixel_x * sin (PI / 2 - degree2radian (angle_center)) + plane_center_coords[1];
    322             plane_point_coords[2] = (center_y - row) * length_per_pixel_y + plane_center_coords[2];
    323 
    324             float rate_xz, rate_yz;
    325             if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f) && XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[1], 0.0f)) {
    326                 world_pos.x = config.a;
    327                 world_pos.y = 0;
    328                 world_pos.z = 0;
    329             } else if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f)) {
    330                 world_pos.z = 0.0f;
    331 
    332                 float rate_xy = plane_point_coords[0] / plane_point_coords[1];
    333                 float square_y = 1 / (rate_xy * rate_xy / (config.a * config.a) + 1 / (config.b * config.b));
    334                 world_pos.y = (plane_point_coords[1] > 0) ? sqrt (square_y) : -sqrt (square_y);
    335                 world_pos.x = rate_xy * world_pos.y;
    336             } else {
    337                 rate_xz = plane_point_coords[0] / plane_point_coords[2];
    338                 rate_yz = plane_point_coords[1] / plane_point_coords[2];
    339 
    340                 float square_z = 1 / (rate_xz * rate_xz / (config.a * config.a) + rate_yz * rate_yz / (config.b * config.b) + 1 / (config.c * config.c));
    341                 world_pos.z = (plane_point_coords[2] > 0) ? sqrt (square_z) : -sqrt (square_z);
    342                 world_pos.z = (world_pos.z <= -config.center_z) ? -config.center_z : world_pos.z;
    343                 world_pos.x = rate_xz * world_pos.z;
    344                 world_pos.y = rate_yz * world_pos.z;
    345             }
    346 
    347             world_pos.z += config.center_z;
    348 
    349             PointFloat2 image_coord =
    350                 bowl_view_coords_to_image (config, world_pos, stitch_info.width, stitch_info.height);
    351 
    352             map_table[row * width + col] = image_coord;
    353         }
    354     }
    355 
    356     return XCAM_RETURN_NO_ERROR;
    357 }
    358 
    359 XCamReturn
    360 sample_generate_top_view (
    361     SmartPtr<VideoBuffer> &stitch_buf,
    362     SmartPtr<VideoBuffer> top_view_buf,
    363     const BowlDataConfig &config,
    364     std::vector<PointFloat2> &map_table)
    365 {
    366     const VideoBufferInfo top_view_info = top_view_buf->get_video_info ();
    367     const VideoBufferInfo stitch_info = stitch_buf->get_video_info ();
    368 
    369     int top_view_resolution_w = top_view_buf->get_video_info ().width;
    370     int top_view_resolution_h = top_view_buf->get_video_info ().height;
    371 
    372     if((int)map_table.size () != top_view_resolution_w * top_view_resolution_h) {
    373         map_table.clear ();
    374         generate_topview_map_table (stitch_info, config, map_table, top_view_resolution_w, top_view_resolution_h);
    375     }
    376 
    377     uint8_t *top_view_mem = NULL;
    378     uint8_t *stitch_mem = NULL;
    379     top_view_mem = top_view_buf->map ();
    380     stitch_mem = stitch_buf->map ();
    381 
    382     for(int row = 0; row < top_view_resolution_h; row++) {
    383         for(int col = 0; col < top_view_resolution_w; col++) {
    384             PointFloat2 image_coord = map_table[row * top_view_resolution_w + col];
    385 
    386             map_to_specific_view (top_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, top_view_info, stitch_info);
    387         }
    388     }
    389 
    390     top_view_buf->unmap();
    391     stitch_buf->unmap();
    392 
    393     return XCAM_RETURN_NO_ERROR;
    394 }
    395 
    396 XCamReturn
    397 sample_generate_rectified_view (
    398     SmartPtr<VideoBuffer> &stitch_buf,
    399     SmartPtr<VideoBuffer> rectified_view_buf,
    400     const BowlDataConfig &config,
    401     float angle_start, float angle_end,
    402     std::vector<PointFloat2> &map_table)
    403 {
    404     const VideoBufferInfo rectified_view_info = rectified_view_buf->get_video_info ();
    405     const VideoBufferInfo stitch_info = stitch_buf->get_video_info ();
    406 
    407     int rectified_view_resolution_w = rectified_view_buf->get_video_info ().width;
    408     int rectified_view_resolution_h = rectified_view_buf->get_video_info ().height;
    409 
    410     if((int)map_table.size () != rectified_view_resolution_w * rectified_view_resolution_h) {
    411         map_table.clear ();
    412         generate_rectifiedview_map_table (stitch_info, config, map_table, angle_start, angle_end, rectified_view_resolution_w, rectified_view_resolution_h);
    413     }
    414 
    415     uint8_t *rectified_view_mem = NULL;
    416     uint8_t *stitch_mem = NULL;
    417     rectified_view_mem = rectified_view_buf->map ();
    418     stitch_mem = stitch_buf->map ();
    419 
    420     for(int row = 0; row < rectified_view_resolution_h; row++) {
    421         for(int col = 0; col < rectified_view_resolution_w; col++) {
    422             PointFloat2 image_coord = map_table[row * rectified_view_resolution_w + col];
    423 
    424             map_to_specific_view (rectified_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, rectified_view_info, stitch_info);
    425         }
    426     }
    427 
    428     rectified_view_buf->unmap();
    429     stitch_buf->unmap();
    430 
    431     return XCAM_RETURN_NO_ERROR;
    432 }
    433 
    434 }
    435