diff options
Diffstat (limited to 'modules/vulkan/vk_blender.cpp')
-rw-r--r-- | modules/vulkan/vk_blender.cpp | 1537 |
1 files changed, 1537 insertions, 0 deletions
diff --git a/modules/vulkan/vk_blender.cpp b/modules/vulkan/vk_blender.cpp new file mode 100644 index 0000000..f880649 --- /dev/null +++ b/modules/vulkan/vk_blender.cpp @@ -0,0 +1,1537 @@ +/* + * vk_blender.cpp - vulkan blender implementation + * + * Copyright (c) 2018 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: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "xcam_utils.h" + +#include "vk_device.h" +#include "vk_worker.h" +#include "vk_blender.h" +#include "vk_video_buf_allocator.h" + +#define DUMP_BUFFER 0 + +#define GAUSS_RADIUS 2 +#define GAUSS_DIAMETER ((GAUSS_RADIUS)*2+1) + +const float gauss_coeffs[GAUSS_DIAMETER] = {0.152f, 0.222f, 0.252f, 0.222f, 0.152f}; + +#define GS_SHADER_BINDING_COUNT 4 +#define LAP_SHADER_BINDING_COUNT 6 +#define BLEND_SHADER_BINDING_COUNT 7 +#define RECONSTRUCT_SHADER_BINDING_COUNT 9 + +#define CHECK_RET(ret, format, ...) \ + if (!xcam_ret_is_ok (ret)) { \ + XCAM_LOG_ERROR (format, ## __VA_ARGS__); \ + } + +#define DECLARE_VK_PUSH_CONST(PushConstClass, PushConstsProp) \ + class PushConstClass : public VKConstRange::VKPushConstArg { \ + private: PushConstsProp _prop; \ + public: \ + PushConstClass (const PushConstsProp &prop) : _prop (prop) {} \ + bool get_const_data (VkPushConstantRange &range, void *& ptr) { \ + range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; \ + range.offset = 0; \ + range.size = sizeof (_prop); \ + ptr = &_prop; \ + return true; } \ + } + +namespace XCam { + +#if DUMP_BUFFER +static void +dump_vkbuf_with_perfix (const SmartPtr<VKBuffer> &buf, const char *perfix_name) +{ + XCAM_ASSERT (buf.ptr ()); + XCAM_ASSERT (perfix_name); + + const VKBufInfo &info = buf->get_buf_info (); + char file_name[XCAM_VK_NAME_LENGTH]; + snprintf ( + file_name, XCAM_VK_NAME_LENGTH, "%s-%dx%d.%s", + perfix_name, info.width, info.height, xcam_fourcc_to_string (info.format)); + + FILE *fp = fopen (file_name, "wb"); + if (!fp) { + XCAM_LOG_ERROR ( "vk-blend open file(%s) failed", file_name); + } + + uint8_t *ptr = (uint8_t *)buf->map (); + for (uint32_t i = 0; i < info.height * 3 / 2; ++i) { + uint8_t *start = ptr + info.aligned_width * i; + fwrite (start, info.width, 1, fp); + } + buf->unmap (); + fclose (fp); +} +#define dump_vkbuf dump_vkbuf_with_perfix + +static void +dump_level_vkbuf (const SmartPtr<VKBuffer> &buf, const char *name, uint32_t level, uint32_t idx) +{ + char file_name[XCAM_VK_NAME_LENGTH]; + snprintf (file_name, XCAM_VK_NAME_LENGTH, "%s-L%d-Idx%d", name, level, idx); + + dump_vkbuf_with_perfix (buf, file_name); +} +#endif + +namespace VKBlenderPriv { + +enum ShaderID { + ShaderGaussScalePyr = 0, + ShaderLapTransPyr, + ShaderBlendPyr, + ShaderReconstructPyr +}; + +static const VKShaderInfo shaders_info[] = { + VKShaderInfo ( + "main", + std::vector<uint32_t> { +#include "shader_gauss_scale_pyr.comp.spv" + }), + VKShaderInfo ( + "main", + std::vector<uint32_t> { +#include "shader_lap_trans_pyr.comp.spv" + }), + VKShaderInfo ( + "main", + std::vector<uint32_t> { +#include "shader_blend_pyr.comp.spv" + }), + VKShaderInfo ( + "main", + std::vector<uint32_t> { +#include "shader_reconstruct_pyr.comp.spv" + }) +}; + +struct GaussScalePushConstsProp { + uint in_img_width; + uint in_img_height; + uint in_offset_x; + uint out_img_width; + uint out_img_height; + uint merge_width; + + GaussScalePushConstsProp () + : in_img_width (0) + , in_img_height (0) + , in_offset_x (0) + , out_img_width (0) + , out_img_height (0) + , merge_width (0) + {} +}; + +struct LapPushConstsProp { + uint in_img_width; + uint in_img_height; + uint in_offset_x; + uint gaussscale_img_width; + uint gaussscale_img_height; + uint merge_width; + + LapPushConstsProp () + : in_img_width (0) + , in_img_height (0) + , in_offset_x (0) + , gaussscale_img_width (0) + , gaussscale_img_height (0) + , merge_width (0) + {} +}; + +struct BlendPushConstsProp { + uint in_img_width; + + BlendPushConstsProp () + : in_img_width (0) + {} +}; + +struct ReconstructPushConstsProp { + uint lap_img_width; + uint lap_img_height; + uint out_img_width; + uint out_offset_x; + uint prev_blend_img_width; + uint prev_blend_img_height; + + ReconstructPushConstsProp () + : lap_img_width (0) + , lap_img_height (0) + , out_img_width (0) + , out_offset_x (0) + , prev_blend_img_width (0) + , prev_blend_img_height (0) + {} +}; + +DECLARE_VK_PUSH_CONST (VKGaussScalePushConst, GaussScalePushConstsProp); +DECLARE_VK_PUSH_CONST (VKLapPushConst, LapPushConstsProp); +DECLARE_VK_PUSH_CONST (VKBlendPushConst, BlendPushConstsProp); +DECLARE_VK_PUSH_CONST (VKReconstructPushConst, ReconstructPushConstsProp); + +DECLARE_WORK_CALLBACK (CbGaussScalePyr, VKBlender, gauss_scale_done); +DECLARE_WORK_CALLBACK (CbLapTransPyr, VKBlender, lap_trans_done); +DECLARE_WORK_CALLBACK (CbBlendPyr, VKBlender, blend_done); +DECLARE_WORK_CALLBACK (CbReconstructPyr, VKBlender, reconstruct_done); + +class BlendArgs + : public VKWorker::VKArguments +{ +public: + BlendArgs (uint32_t lv, VKBlender::BufIdx i = VKBlender::BufIdx0); + + uint32_t get_level () { + return _level; + } + VKBlender::BufIdx get_idx () { + return _idx; + } + +private: + uint32_t _level; + VKBlender::BufIdx _idx; +}; + +struct PyrLayer { + uint32_t blend_width; + uint32_t blend_height; + + SmartPtr<VKBlender::Sync> lap_sync[VKBlender::BufIdxMax]; + SmartPtr<VKBlender::Sync> blend_sync; + SmartPtr<VKBlender::Sync> reconstruct_sync; + + SmartPtr<VKBuffer> gs_buf[VKBlender::BufIdxMax]; + SmartPtr<VKBuffer> lap_buf[VKBlender::BufIdxMax]; + SmartPtr<VKBuffer> mask; + SmartPtr<VKBuffer> blend_buf; + SmartPtr<VKBuffer> reconstruct_buf; + + VKDescriptor::SetBindInfoArray gs_bindings[VKBlender::BufIdxMax]; + VKDescriptor::SetBindInfoArray lap_bindings[VKBlender::BufIdxMax]; + VKDescriptor::SetBindInfoArray blend_bindings; + VKDescriptor::SetBindInfoArray reconstruct_bindings; + + SmartPtr<VKConstRange::VKPushConstArg> gs_consts[VKBlender::BufIdxMax]; + SmartPtr<VKConstRange::VKPushConstArg> lap_consts[VKBlender::BufIdxMax]; + SmartPtr<VKConstRange::VKPushConstArg> blend_consts; + SmartPtr<VKConstRange::VKPushConstArg> reconstruct_consts; + + WorkSize gs_global_size[VKBlender::BufIdxMax]; + WorkSize lap_global_size[VKBlender::BufIdxMax]; + WorkSize blend_global_size; + WorkSize reconstruct_global_size; + + VKWorker *gauss_scale[VKBlender::BufIdxMax]; + VKWorker *lap_trans[VKBlender::BufIdxMax]; + VKWorker *blend; + VKWorker *reconstruct; + + PyrLayer (); +}; + +typedef std::map<ShaderID, SmartPtr<VKWorker>> VKWorkers; + +class BlenderImpl { +public: + PyrLayer pyr_layer[XCAM_VK_MAX_LEVEL]; + uint32_t pyr_layers_num; + +private: + VKBlender *_blender; + VKWorkers _workers; + +public: + BlenderImpl (VKBlender *blender, uint32_t layers_num) + : pyr_layers_num (layers_num) + , _blender (blender) + { + XCAM_ASSERT (layers_num >= 2 && layers_num <= XCAM_VK_MAX_LEVEL); + } + + XCamReturn start_gauss_scale (uint32_t level, VKBlender::BufIdx idx); + XCamReturn start_lap_trans (uint32_t level, VKBlender::BufIdx idx); + XCamReturn start_top_blend (); + XCamReturn start_reconstruct (uint32_t level); + XCamReturn stop (); + + void init_syncs (); + XCamReturn init_layers_bufs (const SmartPtr<ImageHandler::Parameters> &base); + XCamReturn bind_io_bufs_to_layer0 ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output); + XCamReturn bind_io_vkbufs_to_desc (); + XCamReturn fix_parameters (); + XCamReturn create_workers (const SmartPtr<VKBlender> &blender); + XCamReturn redirect_workers (); + +private: + XCamReturn start_lap_tran (uint32_t level, VKBlender::BufIdx idx); + + XCamReturn layer0_allocate_bufs (SmartPtr<VKDevice> dev); + XCamReturn layer0_init_mask (SmartPtr<VKDevice> dev); + + XCamReturn layerx_allocate_bufs (SmartPtr<VKDevice> dev, uint32_t level); + XCamReturn allocate_vk_bufs (SmartPtr<VKDevice> dev, uint32_t level); + XCamReturn scale_down_mask (SmartPtr<VKDevice> dev, uint32_t level); + + XCamReturn fix_gs_params (uint32_t level, VKBlender::BufIdx idx); + XCamReturn fix_lap_trans_params (uint32_t level, VKBlender::BufIdx idx); + XCamReturn fix_blend_params (); + XCamReturn fix_reconstruct_params (uint32_t level); +}; + +BlendArgs::BlendArgs (uint32_t lv, VKBlender::BufIdx i) + : _level (lv) + , _idx (i) +{ + XCAM_ASSERT (lv < XCAM_VK_DEFAULT_LEVEL); + XCAM_ASSERT (i < VKBlender::BufIdxMax); +} + +PyrLayer::PyrLayer () + : blend_width (0) + , blend_height (0) +{ +} + +void +BlenderImpl::init_syncs () +{ + for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) { + PyrLayer &layer = pyr_layer[i]; + + layer.lap_sync[VKBlender::BufIdx0] = new VKBlender::Sync (2); + XCAM_ASSERT (layer.lap_sync[VKBlender::BufIdx0].ptr ()); + layer.lap_sync[VKBlender::BufIdx1] = new VKBlender::Sync (2); + XCAM_ASSERT (layer.lap_sync[VKBlender::BufIdx1].ptr ()); + + layer.reconstruct_sync = new VKBlender::Sync (3); + XCAM_ASSERT (layer.reconstruct_sync.ptr ()); + } + + pyr_layer[pyr_layers_num - 1].blend_sync = new VKBlender::Sync (2); + XCAM_ASSERT (pyr_layer[pyr_layers_num - 1].blend_sync.ptr ()); +} + +XCamReturn +BlenderImpl::bind_io_bufs_to_layer0 ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output) +{ + XCAM_ASSERT (input0.ptr () && input1.ptr ()); + + SmartPtr<VKVideoBuffer> in0_vk = input0.dynamic_cast_ptr<VKVideoBuffer> (); + SmartPtr<VKVideoBuffer> in1_vk = input1.dynamic_cast_ptr<VKVideoBuffer> (); + + PyrLayer &layer0 = pyr_layer[0]; + layer0.gs_buf[VKBlender::BufIdx0] = in0_vk->get_vk_buf (); + layer0.gs_buf[VKBlender::BufIdx1] = in1_vk->get_vk_buf (); + XCAM_ASSERT (layer0.gs_buf[VKBlender::BufIdx0].ptr () && layer0.gs_buf[VKBlender::BufIdx1].ptr ()); + + if (!output.ptr ()) + return XCAM_RETURN_NO_ERROR; + + SmartPtr<VKVideoBuffer> out_vk = output.dynamic_cast_ptr<VKVideoBuffer> (); + XCAM_ASSERT (out_vk.ptr ()); + + layer0.reconstruct_buf = out_vk->get_vk_buf (); + XCAM_ASSERT (layer0.reconstruct_buf.ptr ()); + layer0.blend_buf = layer0.reconstruct_buf; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::bind_io_vkbufs_to_desc () +{ + PyrLayer &layer0 = pyr_layer[0]; + PyrLayer &layer1 = pyr_layer[1]; + XCAM_ASSERT (layer0.gs_buf[VKBlender::BufIdx0].ptr () && layer0.gs_buf[VKBlender::BufIdx1].ptr ()); + XCAM_ASSERT (layer0.reconstruct_buf.ptr ()); + + VKDescriptor::SetBindInfoArray &gs_bindings0 = layer1.gs_bindings[VKBlender::BufIdx0]; + VKDescriptor::SetBindInfoArray &gs_bindings1 = layer1.gs_bindings[VKBlender::BufIdx1]; + gs_bindings0[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx); + gs_bindings0[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx); + gs_bindings1[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx); + gs_bindings1[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx); + + VKDescriptor::SetBindInfoArray &lap_bindings0 = layer0.lap_bindings[VKBlender::BufIdx0]; + VKDescriptor::SetBindInfoArray &lap_bindings1 = layer0.lap_bindings[VKBlender::BufIdx1]; + lap_bindings0[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx); + lap_bindings0[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx); + lap_bindings1[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx); + lap_bindings1[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx); + + layer0.reconstruct_bindings[4].desc = VKBufDesc (layer0.reconstruct_buf, NV12PlaneYIdx); + layer0.reconstruct_bindings[5].desc = VKBufDesc (layer0.reconstruct_buf, NV12PlaneUVIdx); + + return XCAM_RETURN_NO_ERROR; +} + +static void +convert_to_vkinfo (const VideoBufferInfo &info, VKBufInfo &vk_info) +{ + vk_info.format = info.format; + vk_info.width = info.width; + vk_info.height = info.height; + vk_info.aligned_width = info.aligned_width; + vk_info.aligned_height = info.aligned_height; + vk_info.size = info.size; + vk_info.strides[0] = info.strides[0]; + vk_info.strides[1] = info.strides[1]; + vk_info.offsets[0] = info.offsets[0]; + vk_info.offsets[1] = info.offsets[1]; + vk_info.slice_size[0] = info.strides[0] * info.aligned_height; + vk_info.slice_size[1] = info.size - info.offsets[1]; +} + +XCamReturn +BlenderImpl::layer0_allocate_bufs (SmartPtr<VKDevice> dev) +{ + if (pyr_layers_num == 1) + return XCAM_RETURN_NO_ERROR; + + PyrLayer &layer0 = pyr_layer[0]; + XCAM_FAIL_RETURN ( + ERROR, layer0.blend_width && layer0.blend_height, XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid blend size:%dx%d", layer0.blend_width, layer0.blend_height); + + VideoBufferInfo info; + info.init ( + V4L2_PIX_FMT_NV12, layer0.blend_width, layer0.blend_height, + XCAM_ALIGN_UP (layer0.blend_width, VK_BLENDER_ALIGN_X), + XCAM_ALIGN_UP (layer0.blend_height, VK_BLENDER_ALIGN_X)); + + VKBufInfo vk_info; + convert_to_vkinfo (info, vk_info); + + for (int idx = 0; idx < VKBlender::BufIdxMax; ++idx) { + layer0.lap_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size); + XCAM_ASSERT (layer0.lap_buf[idx].ptr ()); + layer0.lap_buf[idx]->set_buf_info (vk_info); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::allocate_vk_bufs (SmartPtr<VKDevice> dev, uint32_t level) +{ + XCAM_ASSERT (level >= 1 && level < pyr_layers_num); + + PyrLayer &layer = pyr_layer[level]; + VideoBufferInfo info; + info.init ( + V4L2_PIX_FMT_NV12, layer.blend_width, layer.blend_height, + XCAM_ALIGN_UP (layer.blend_width, VK_BLENDER_ALIGN_X), + XCAM_ALIGN_UP (layer.blend_height, VK_BLENDER_ALIGN_X)); + + VKBufInfo vk_info; + convert_to_vkinfo (info, vk_info); + + bool top_layer = (level == pyr_layers_num - 1); + for (int idx = 0; idx < VKBlender::BufIdxMax; ++idx) { + layer.gs_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size); + XCAM_ASSERT (layer.gs_buf[idx].ptr ()); + layer.gs_buf[idx]->set_buf_info (vk_info); + + if (top_layer) + continue; + + layer.lap_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size); + XCAM_ASSERT (layer.lap_buf[idx].ptr ()); + layer.lap_buf[idx]->set_buf_info (vk_info); + } + + layer.reconstruct_buf = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size); + XCAM_ASSERT (layer.reconstruct_buf.ptr ()); + layer.reconstruct_buf->set_buf_info (vk_info); + + if (top_layer) + layer.blend_buf = layer.reconstruct_buf; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::layer0_init_mask (SmartPtr<VKDevice> dev) +{ + PyrLayer &layer = pyr_layer[0]; + XCAM_ASSERT (layer.blend_width && ((layer.blend_width % VK_BLENDER_ALIGN_X) == 0)); + + uint32_t buf_size = layer.blend_width * sizeof (uint8_t); + SmartPtr<VKBuffer> buf = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buf_size); + XCAM_ASSERT (buf.ptr ()); + + VKBufInfo info; + info.width = layer.blend_width; + info.height = 1; + info.size = buf_size; + buf->set_buf_info (info); + + std::vector<float> gauss_table; + uint32_t quater = info.width / 4; + + get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false); + for (uint32_t i = 0; i < gauss_table.size (); ++i) { + float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i])); + value = XCAM_CLAMP (value, 0.0f, 255.0f); + gauss_table[i] = value; + } + + uint8_t *mask_ptr = (uint8_t *) buf->map (buf_size, 0); + XCAM_FAIL_RETURN (ERROR, mask_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed"); + + uint32_t gauss_start_pos = (info.width - gauss_table.size ()) / 2; + uint32_t idx = 0; + for (idx = 0; idx < gauss_start_pos; ++idx) { + mask_ptr[idx] = 255; + } + for (uint32_t i = 0; i < gauss_table.size (); ++idx, ++i) { + mask_ptr[idx] = (uint8_t) gauss_table[i]; + } + for (; idx < info.width; ++idx) { + mask_ptr[idx] = 0; + } + buf->unmap (); + + layer.mask = buf; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::scale_down_mask (SmartPtr<VKDevice> dev, uint32_t level) +{ + XCAM_ASSERT (level >= 1 && level < pyr_layers_num); + + PyrLayer &layer = pyr_layer[level]; + PyrLayer &prev_layer = pyr_layer[level - 1]; + + XCAM_ASSERT (prev_layer.mask.ptr ()); + XCAM_ASSERT (layer.blend_width && ((layer.blend_width % VK_BLENDER_ALIGN_X) == 0)); + + uint32_t buf_size = layer.blend_width * sizeof (uint8_t); + SmartPtr<VKBuffer> buf = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buf_size); + XCAM_ASSERT (buf.ptr ()); + + VKBufInfo info; + info.width = layer.blend_width; + info.height = 1; + info.size = buf_size; + buf->set_buf_info (info); + + const VKBufInfo prev_info = prev_layer.mask->get_buf_info (); + uint8_t *prev_ptr = (uint8_t *) prev_layer.mask->map (prev_info.size, 0); + XCAM_FAIL_RETURN (ERROR, prev_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed"); + + uint8_t *cur_ptr = (uint8_t *) buf->map (info.size, 0); + XCAM_FAIL_RETURN (ERROR, cur_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed"); + + for (uint32_t i = 0; i < info.width; ++i) { + int prev_start = i * 2 - 2; + float sum = 0.0f; + + for (int j = 0; j < GAUSS_DIAMETER; ++j) { + int prev_idx = XCAM_CLAMP (prev_start + j, 0, (int)prev_info.width); + sum += prev_ptr[prev_idx] * gauss_coeffs[j]; + } + + cur_ptr[i] = XCAM_CLAMP (sum, 0.0f, 255.0f); + } + + buf->unmap (); + prev_layer.mask->unmap (); + + layer.mask = buf; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::layerx_allocate_bufs (SmartPtr<VKDevice> dev, uint32_t level) +{ + XCAM_ASSERT (level >= 1 && level < pyr_layers_num); + + PyrLayer &layer = pyr_layer[level]; + PyrLayer &prev_layer = pyr_layer[level - 1]; + XCAM_FAIL_RETURN ( + ERROR, prev_layer.blend_width && prev_layer.blend_height, XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid blend size:%dx%d", prev_layer.blend_width, prev_layer.blend_height); + + layer.blend_width = XCAM_ALIGN_UP ((prev_layer.blend_width + 1) / 2, VK_BLENDER_ALIGN_X); + layer.blend_height = XCAM_ALIGN_UP ((prev_layer.blend_height + 1) / 2, VK_BLENDER_ALIGN_Y); + + XCamReturn ret = allocate_vk_bufs (dev, level); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend build vk buffers failed, level:%d", level); + + ret = scale_down_mask (dev, level); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend scale down mask failed, level:%d", level); + + return ret; +} + +static XCamReturn +check_desc ( + const VideoBufferInfo &in0_info, const VideoBufferInfo &in1_info, + const Rect &merge0_area, const Rect &merge1_area) +{ + XCAM_FAIL_RETURN ( + ERROR, + in0_info.width && in0_info.height && in1_info.width && + in0_info.height == in1_info.height, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid buffer size: in0:%dx%d in1:%dx%d out:%dx%d", + in0_info.width, in0_info.height, in1_info.width, in1_info.height); + + XCAM_FAIL_RETURN ( + ERROR, + merge0_area.width && merge0_area.width == merge1_area.width && + merge0_area.pos_y == 0 && merge1_area.pos_y == 0 && + merge0_area.height == merge1_area.height && merge0_area.height == (int32_t)in0_info.height, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid merge area: merge0(%d, %d, %d, %d) merge1(%d, %d, %d, %d)", + merge0_area.pos_x, merge0_area.pos_y, merge0_area.width, merge0_area.height, + merge1_area.pos_x, merge1_area.pos_y, merge1_area.width, merge1_area.height); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::init_layers_bufs (const SmartPtr<ImageHandler::Parameters> &base) +{ + XCAM_ASSERT (base.ptr ()); + SmartPtr<VKBlender::BlenderParam> param = base.dynamic_cast_ptr<VKBlender::BlenderParam> (); + XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->in1_buf.ptr ()); + + const VideoBufferInfo &in0_info = param->in_buf->get_video_info (); + const VideoBufferInfo &in1_info = param->in1_buf->get_video_info (); + const Rect merge0_area = _blender->get_input_merge_area (VKBlender::BufIdx0); + const Rect merge1_area = _blender->get_input_merge_area (VKBlender::BufIdx1); + + XCamReturn ret = check_desc (in0_info, in1_info, merge0_area, merge1_area); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend check desc failed"); + + PyrLayer &layer0 = pyr_layer[0]; + layer0.blend_width = XCAM_ALIGN_UP (merge0_area.width, VK_BLENDER_ALIGN_X); + layer0.blend_height = XCAM_ALIGN_UP (merge0_area.height, VK_BLENDER_ALIGN_Y); + + SmartPtr<VKDevice> dev = _blender->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + ret = bind_io_bufs_to_layer0 (param->in_buf, param->in1_buf, param->out_buf); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend bind bufs to layer0 failed"); + ret = layer0_allocate_bufs (dev); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend layer0 build buffers failed"); + ret = layer0_init_mask (dev); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend layer0 init mask failed"); + + for (uint32_t level = 1; level < pyr_layers_num; ++level) { + layerx_allocate_bufs (dev, level); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-blend build buffers failed, level:%d", level); + } + + return XCAM_RETURN_NO_ERROR; +} + +static SmartPtr<VKWorker> +create_gauss_scale_pyr_shader (const SmartPtr<VKBlender> &blender) +{ + SmartPtr<VKDevice> dev = blender->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + GaussScalePushConstsProp prop; + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKGaussScalePushConst (prop)); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < GS_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + SmartPtr<VKWorker> worker = new VKWorker (dev, "VKGaussScaleShader", new CbGaussScalePyr (blender)); + XCAM_ASSERT (worker.ptr ()); + + XCamReturn ret = worker->build (shaders_info[ShaderGaussScalePyr], binding_layout, push_consts); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKGaussScaleShader failed"); + + return worker; +} + +static SmartPtr<VKWorker> +create_lap_trans_pyr_shader (const SmartPtr<VKBlender> &blender) +{ + SmartPtr<VKDevice> dev = blender->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + LapPushConstsProp prop; + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKLapPushConst (prop)); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < LAP_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + SmartPtr<VKWorker> worker = new VKWorker (dev, "VKLapTransShader", new CbLapTransPyr (blender)); + XCAM_ASSERT (worker.ptr ()); + + XCamReturn ret = worker->build (shaders_info[ShaderLapTransPyr], binding_layout, push_consts); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKLapTransShader failed"); + + return worker; +} + +static SmartPtr<VKWorker> +create_blend_pyr_shader (const SmartPtr<VKBlender> &blender) +{ + SmartPtr<VKDevice> dev = blender->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + BlendPushConstsProp prop; + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKBlendPushConst (prop)); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < BLEND_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + SmartPtr<VKWorker> worker = new VKWorker (dev, "VKBlendPyrShader", new CbBlendPyr (blender)); + XCAM_ASSERT (worker.ptr ()); + + XCamReturn ret = worker->build (shaders_info[ShaderBlendPyr], binding_layout, push_consts); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKBlendPyrShader failed"); + + return worker; +} + +static SmartPtr<VKWorker> +create_reconstruct_pyr_shader (const SmartPtr<VKBlender> &blender) +{ + SmartPtr<VKDevice> dev = blender->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + ReconstructPushConstsProp prop; + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKReconstructPushConst (prop)); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < RECONSTRUCT_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + SmartPtr<VKWorker> worker = new VKWorker (dev, "VKReconstructShader", new CbReconstructPyr (blender)); + XCAM_ASSERT (worker.ptr ()); + + XCamReturn ret = worker->build (shaders_info[ShaderReconstructPyr], binding_layout, push_consts); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKReconstructShader failed"); + + return worker; +} + +XCamReturn +BlenderImpl::create_workers (const SmartPtr<VKBlender> &blender) +{ + XCAM_ASSERT (blender.ptr ()); + + VKWorkers::iterator i = _workers.find (ShaderGaussScalePyr); + if (i == _workers.end ()) { + SmartPtr<VKWorker> gauss_scale = create_gauss_scale_pyr_shader (blender); + XCAM_ASSERT (gauss_scale.ptr ()); + _workers.insert (std::make_pair (ShaderGaussScalePyr, gauss_scale)); + } + + i = _workers.find (ShaderLapTransPyr); + if (i == _workers.end ()) { + SmartPtr<VKWorker> lap_trans = create_lap_trans_pyr_shader (blender); + XCAM_ASSERT (lap_trans.ptr ()); + _workers.insert (std::make_pair (ShaderLapTransPyr, lap_trans)); + } + + i = _workers.find (ShaderBlendPyr); + if (i == _workers.end ()) { + SmartPtr<VKWorker> blend = create_blend_pyr_shader (blender); + XCAM_ASSERT (blend.ptr ()); + _workers.insert (std::make_pair (ShaderBlendPyr, blend)); + } + + i = _workers.find (ShaderReconstructPyr); + if (i == _workers.end ()) { + SmartPtr<VKWorker> reconstruct = create_reconstruct_pyr_shader (blender); + XCAM_ASSERT (reconstruct.ptr ()); + _workers.insert (std::make_pair (ShaderReconstructPyr, reconstruct)); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::redirect_workers () +{ + VKWorkers::iterator i = _workers.find (ShaderGaussScalePyr); + XCAM_ASSERT (i != _workers.end ()); + SmartPtr<VKWorker> gauss_scale = i->second; + + i = _workers.find (ShaderLapTransPyr); + XCAM_ASSERT (i != _workers.end ()); + SmartPtr<VKWorker> lap_trans = i->second; + + i = _workers.find (ShaderBlendPyr); + XCAM_ASSERT (i != _workers.end ()); + SmartPtr<VKWorker> top_blend = i->second; + + i = _workers.find (ShaderReconstructPyr); + XCAM_ASSERT (i != _workers.end ()); + SmartPtr<VKWorker> reconstruct = i->second; + + XCAM_ASSERT (gauss_scale.ptr () && lap_trans.ptr () && reconstruct.ptr () && top_blend.ptr ()); + for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) { + PyrLayer &layer_next = pyr_layer[i + 1]; + layer_next.gauss_scale[VKBlender::BufIdx0] = gauss_scale.ptr (); + layer_next.gauss_scale[VKBlender::BufIdx1] = gauss_scale.ptr (); + + PyrLayer &layer = pyr_layer[i]; + layer.lap_trans[VKBlender::BufIdx0] = lap_trans.ptr (); + layer.lap_trans[VKBlender::BufIdx1] = lap_trans.ptr (); + layer.reconstruct = reconstruct.ptr (); + } + + PyrLayer &top_layer = pyr_layer[pyr_layers_num - 1]; + top_layer.blend = top_blend.ptr (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::fix_parameters () +{ + for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) { + fix_gs_params (i + 1, VKBlender::BufIdx0); + fix_gs_params (i + 1, VKBlender::BufIdx1); + + fix_lap_trans_params (i, VKBlender::BufIdx0); + fix_lap_trans_params (i, VKBlender::BufIdx1); + + fix_reconstruct_params (i); + } + + fix_blend_params (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::fix_gs_params (uint32_t level, VKBlender::BufIdx idx) +{ + XCAM_ASSERT (level >= 1); + + uint32_t level_in = level - 1; + PyrLayer &layer_in = pyr_layer[level_in]; + PyrLayer &layer_out = pyr_layer[level]; + XCAM_ASSERT (layer_out.gs_buf[idx].ptr () && (layer_in.gs_buf[idx].ptr () || level == 1)); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < GS_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + VKDescriptor::SetBindInfoArray bindings (GS_SHADER_BINDING_COUNT); + bindings[0].layout = binding_layout[0]; + bindings[1].layout = binding_layout[1]; + if (layer_in.gs_buf[idx].ptr ()) { + bindings[0].desc = VKBufDesc (layer_in.gs_buf[idx], NV12PlaneYIdx); + bindings[1].desc = VKBufDesc (layer_in.gs_buf[idx], NV12PlaneUVIdx); + } + bindings[2].layout = binding_layout[2]; + bindings[2].desc = VKBufDesc (layer_out.gs_buf[idx], NV12PlaneYIdx); + bindings[3].layout = binding_layout[3]; + bindings[3].desc = VKBufDesc (layer_out.gs_buf[idx], NV12PlaneUVIdx); + layer_out.gs_bindings[idx] = bindings; + + const VKBufInfo in_info = layer_in.gs_buf[idx]->get_buf_info (); + const VKBufInfo out_info = layer_out.gs_buf[idx]->get_buf_info (); + + size_t unit_bytes = sizeof (uint32_t); + GaussScalePushConstsProp prop; + prop.in_img_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes; + prop.in_img_height = in_info.height; + prop.out_img_width = XCAM_ALIGN_UP (out_info.width, unit_bytes) / unit_bytes; + prop.out_img_height = out_info.height; + if (level == 1) { + const Rect area = _blender->get_input_merge_area (idx); + prop.in_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes; + prop.merge_width = XCAM_ALIGN_UP (area.width, unit_bytes) / unit_bytes; + } else { + prop.in_offset_x = 0; + prop.merge_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes; + } + layer_out.gs_consts[idx] = new VKGaussScalePushConst (prop); + + layer_out.gs_global_size[idx] = WorkSize ( + XCAM_ALIGN_UP (prop.out_img_width, 8) / 8, + XCAM_ALIGN_UP (out_info.height, 16) / 16); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::fix_lap_trans_params (uint32_t level, VKBlender::BufIdx idx) +{ + XCAM_ASSERT (level < pyr_layers_num - 1); + + PyrLayer &layer = pyr_layer[level]; + PyrLayer &layer_next = pyr_layer[level + 1]; + XCAM_ASSERT ((layer.gs_buf[idx].ptr () || level == 0) && layer_next.gs_buf[idx].ptr ()); + XCAM_ASSERT (layer.lap_buf[idx].ptr ()); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < LAP_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + VKDescriptor::SetBindInfoArray bindings (LAP_SHADER_BINDING_COUNT); + bindings[0].layout = binding_layout[0]; + bindings[1].layout = binding_layout[1]; + if (layer.gs_buf[idx].ptr ()) { + bindings[0].desc = VKBufDesc (layer.gs_buf[idx], NV12PlaneYIdx); + bindings[1].desc = VKBufDesc (layer.gs_buf[idx], NV12PlaneUVIdx); + } + bindings[2].layout = binding_layout[2]; + bindings[2].desc = VKBufDesc (layer_next.gs_buf[idx], NV12PlaneYIdx); + bindings[3].layout = binding_layout[3]; + bindings[3].desc = VKBufDesc (layer_next.gs_buf[idx], NV12PlaneUVIdx); + bindings[4].layout = binding_layout[4]; + bindings[4].desc = VKBufDesc (layer.lap_buf[idx], NV12PlaneYIdx); + bindings[5].layout = binding_layout[5]; + bindings[5].desc = VKBufDesc (layer.lap_buf[idx], NV12PlaneUVIdx); + layer.lap_bindings[idx] = bindings; + + const VKBufInfo in_info = layer.gs_buf[idx]->get_buf_info (); + const VKBufInfo gs_info = layer_next.gs_buf[idx]->get_buf_info (); + + size_t unit_bytes = sizeof (uint32_t) * 2; + LapPushConstsProp prop; + prop.in_img_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes; + prop.in_img_height = in_info.height; + prop.gaussscale_img_width = XCAM_ALIGN_UP (gs_info.width, sizeof (uint32_t)) / sizeof (uint32_t); + prop.gaussscale_img_height = gs_info.height; + if (level == 0) { + const Rect area = _blender->get_input_merge_area (idx); + prop.in_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes; + prop.merge_width = XCAM_ALIGN_UP (area.width, unit_bytes) / unit_bytes; + } else { + prop.in_offset_x = 0; + prop.merge_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes; + } + layer.lap_consts[idx] = new VKLapPushConst (prop); + + layer.lap_global_size[idx] = WorkSize ( + XCAM_ALIGN_UP (prop.merge_width, 8) / 8, + XCAM_ALIGN_UP (in_info.height, 32) / 32); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::fix_blend_params () +{ + PyrLayer &top_layer = pyr_layer[pyr_layers_num - 1]; + XCAM_ASSERT (top_layer.gs_buf[VKBlender::BufIdx0].ptr () && top_layer.gs_buf[VKBlender::BufIdx1].ptr ()); + XCAM_ASSERT (top_layer.mask.ptr ()); + XCAM_ASSERT (top_layer.blend_buf.ptr ()); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < BLEND_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + VKDescriptor::SetBindInfoArray bindings (BLEND_SHADER_BINDING_COUNT); + bindings[0].layout = binding_layout[0]; + bindings[0].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx); + bindings[1].layout = binding_layout[1]; + bindings[1].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx); + bindings[2].layout = binding_layout[2]; + bindings[2].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx); + bindings[3].layout = binding_layout[3]; + bindings[3].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx); + bindings[4].layout = binding_layout[4]; + bindings[4].desc = VKBufDesc (top_layer.blend_buf, NV12PlaneYIdx); + bindings[5].layout = binding_layout[5]; + bindings[5].desc = VKBufDesc (top_layer.blend_buf, NV12PlaneUVIdx); + bindings[6].layout = binding_layout[6]; + bindings[6].desc = VKBufDesc (top_layer.mask); + top_layer.blend_bindings = bindings; + + const VKBufInfo in0_info = top_layer.gs_buf[VKBlender::BufIdx0]->get_buf_info (); + size_t unit_bytes = sizeof (uint32_t) * 2; + BlendPushConstsProp prop; + prop.in_img_width = XCAM_ALIGN_UP (in0_info.width, unit_bytes) / unit_bytes; + top_layer.blend_consts = new VKBlendPushConst (prop); + + top_layer.blend_global_size = WorkSize ( + XCAM_ALIGN_UP (prop.in_img_width, 8) / 8, + XCAM_ALIGN_UP (in0_info.height, 16) / 16); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::fix_reconstruct_params (uint32_t level) +{ + XCAM_ASSERT (level < pyr_layers_num - 1); + + PyrLayer &layer = pyr_layer[level]; + PyrLayer &prev_layer = pyr_layer[level + 1]; + + XCAM_ASSERT (layer.lap_buf[VKBlender::BufIdx0].ptr ()); + XCAM_ASSERT (layer.lap_buf[VKBlender::BufIdx1].ptr ()); + XCAM_ASSERT (prev_layer.reconstruct_buf.ptr () && (layer.reconstruct_buf.ptr () || level == 0)); + XCAM_ASSERT (layer.mask.ptr ()); + + VKDescriptor::BindingArray binding_layout; + binding_layout.clear (); + for (int i = 0; i < RECONSTRUCT_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + binding_layout.push_back (binding); + } + + VKDescriptor::SetBindInfoArray bindings (RECONSTRUCT_SHADER_BINDING_COUNT); + bindings[0].layout = binding_layout[0]; + bindings[0].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx0], NV12PlaneYIdx); + bindings[1].layout = binding_layout[1]; + bindings[1].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx0], NV12PlaneUVIdx); + bindings[2].layout = binding_layout[2]; + bindings[2].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx1], NV12PlaneYIdx); + bindings[3].layout = binding_layout[3]; + bindings[3].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx1], NV12PlaneUVIdx); + bindings[4].layout = binding_layout[4]; + bindings[5].layout = binding_layout[5]; + if (layer.reconstruct_buf.ptr ()) { + bindings[4].desc = VKBufDesc (layer.reconstruct_buf, NV12PlaneYIdx); + bindings[5].desc = VKBufDesc (layer.reconstruct_buf, NV12PlaneUVIdx); + } + bindings[6].layout = binding_layout[6]; + bindings[6].desc = VKBufDesc (prev_layer.reconstruct_buf, NV12PlaneYIdx); + bindings[7].layout = binding_layout[7]; + bindings[7].desc = VKBufDesc (prev_layer.reconstruct_buf, NV12PlaneUVIdx); + bindings[8].layout = binding_layout[8]; + bindings[8].desc = VKBufDesc (layer.mask); + layer.reconstruct_bindings = bindings; + + const VKBufInfo lap0_info = layer.lap_buf[VKBlender::BufIdx0]->get_buf_info (); + const VKBufInfo prev_recons_info = prev_layer.reconstruct_buf->get_buf_info (); + + size_t unit_bytes = sizeof (uint32_t) * 2; + ReconstructPushConstsProp prop; + prop.lap_img_width = XCAM_ALIGN_UP (lap0_info.width, unit_bytes) / unit_bytes; + prop.lap_img_height = lap0_info.height; + prop.prev_blend_img_width = XCAM_ALIGN_UP (prev_recons_info.width, sizeof (uint32_t)) / sizeof (uint32_t); + prop.prev_blend_img_height = prev_recons_info.height; + if (level == 0) { + const VideoBufferInfo info = _blender->get_out_video_info (); + prop.out_img_width = XCAM_ALIGN_UP (info.width, unit_bytes) / unit_bytes; + + const Rect area = _blender->get_merge_window (); + prop.out_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes; + } else { + const VKBufInfo info = layer.reconstruct_buf->get_buf_info (); + prop.out_img_width = XCAM_ALIGN_UP (info.width, unit_bytes) / unit_bytes; + prop.out_offset_x = 0; + } + layer.reconstruct_consts = new VKReconstructPushConst (prop); + + layer.reconstruct_global_size = WorkSize ( + XCAM_ALIGN_UP (prop.lap_img_width, 8) / 8, + XCAM_ALIGN_UP (lap0_info.height, 32) / 32); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::start_gauss_scale (uint32_t level, VKBlender::BufIdx idx) +{ + XCAM_ASSERT (level >= 1 && level < pyr_layers_num); + + PyrLayer &layer = pyr_layer[level]; + layer.gauss_scale[idx]->set_global_size (layer.gs_global_size[idx]); + + SmartPtr<BlendArgs> args = new BlendArgs (level, idx); + args->set_bindings (layer.gs_bindings[idx]); + args->add_push_const (layer.gs_consts[idx]); + + return layer.gauss_scale[idx]->work (args); +} + +XCamReturn +BlenderImpl::start_lap_tran (uint32_t level, VKBlender::BufIdx idx) +{ + PyrLayer &layer = pyr_layer[level]; + + SmartPtr<VKBlender::Sync> &sync = layer.lap_sync[idx]; + if (!sync->is_synced ()) + return XCAM_RETURN_NO_ERROR; + sync->reset (); + + layer.lap_trans[idx]->set_global_size (layer.lap_global_size[idx]); + + SmartPtr<BlendArgs> args = new BlendArgs (level, idx); + args->set_bindings (layer.lap_bindings[idx]); + args->add_push_const (layer.lap_consts[idx]); + + return layer.lap_trans[idx]->work (args); +} + +XCamReturn +BlenderImpl::start_lap_trans (uint32_t level, VKBlender::BufIdx idx) +{ + XCAM_ASSERT (level >= 1 && level < pyr_layers_num); + + uint32_t pre_level = level - 1; + pyr_layer[pre_level].lap_sync[idx]->increment (); + + XCamReturn ret = start_lap_tran (pre_level, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-blend start lap tran failed, level:%d idx:%d", pre_level, idx); + + if (level == pyr_layers_num - 1) + return XCAM_RETURN_NO_ERROR; + pyr_layer[level].lap_sync[idx]->increment (); + + ret = start_lap_tran (level, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-blend start lap tran failed, level:%d idx:%d", level, idx); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +BlenderImpl::start_top_blend () +{ + uint32_t level = pyr_layers_num - 1; + PyrLayer &layer = pyr_layer[level]; + + SmartPtr<VKBlender::Sync> &sync = layer.blend_sync; + if (!sync->is_synced ()) + return XCAM_RETURN_NO_ERROR; + sync->reset (); + + SmartPtr<VKWorker::VKArguments> args = new VKWorker::VKArguments; + args->set_bindings (layer.blend_bindings); + args->add_push_const (layer.blend_consts); + + layer.blend->set_global_size (layer.blend_global_size); + + return layer.blend->work (args); +} + +XCamReturn +BlenderImpl::start_reconstruct (uint32_t level) +{ + XCAM_ASSERT (level < pyr_layers_num - 1); + PyrLayer &layer = pyr_layer[level]; + + SmartPtr<VKBlender::Sync> &sync = layer.reconstruct_sync; + if (!sync->is_synced ()) + return XCAM_RETURN_NO_ERROR; + sync->reset (); + + SmartPtr<BlendArgs> args = new BlendArgs (level); + args->set_bindings (layer.reconstruct_bindings); + args->add_push_const (layer.reconstruct_consts); + + layer.reconstruct->set_global_size (layer.reconstruct_global_size); + + return layer.reconstruct->work (args); +} + +XCamReturn +BlenderImpl::stop () +{ + for (uint32_t lv = 0; lv < pyr_layers_num; ++lv) { + pyr_layer[lv].gs_buf[VKBlender::BufIdx0].release (); + pyr_layer[lv].gs_buf[VKBlender::BufIdx1].release (); + pyr_layer[lv].lap_buf[VKBlender::BufIdx0].release (); + pyr_layer[lv].lap_buf[VKBlender::BufIdx1].release (); + pyr_layer[lv].reconstruct_buf.release (); + pyr_layer[lv].blend_buf.release (); + + pyr_layer[lv].gs_consts[VKBlender::BufIdx0].release (); + pyr_layer[lv].gs_consts[VKBlender::BufIdx1].release (); + pyr_layer[lv].lap_consts[VKBlender::BufIdx0].release (); + pyr_layer[lv].lap_consts[VKBlender::BufIdx1].release (); + pyr_layer[lv].reconstruct_consts.release (); + pyr_layer[lv].blend_consts.release (); + } + + return XCAM_RETURN_NO_ERROR; +} + +} + +VKBlender::VKBlender (const SmartPtr<VKDevice> dev, const char *name) + : VKHandler (dev, name) + , Blender (VK_BLENDER_ALIGN_X, VK_BLENDER_ALIGN_Y) +{ + SmartPtr<VKBlenderPriv::BlenderImpl> impl = + new VKBlenderPriv::BlenderImpl (this, XCAM_VK_DEFAULT_LEVEL); + XCAM_ASSERT (impl.ptr ()); + + _impl = impl; +} + +VKBlender::~VKBlender () +{ +} + +XCamReturn +VKBlender::blend ( + const SmartPtr<VideoBuffer> &in0, const SmartPtr<VideoBuffer> &in1, SmartPtr<VideoBuffer> &out_buf) +{ + XCAM_ASSERT (in0.ptr () && in1.ptr ()); + + SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf); + XCAM_ASSERT (param.ptr ()); + + XCamReturn ret = execute_buffer (param, true); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend execute buffer failed"); + + finish (); + if (!out_buf.ptr ()) { + out_buf = param->out_buf; + } + + return ret; +} + +static XCamReturn +check_merge_area (const SmartPtr<VKBlender> &blender) +{ + Rect in0_area, in1_area, out_area; + + in0_area = blender->get_input_merge_area (VKBlender::BufIdx0); + XCAM_FAIL_RETURN ( + ERROR, + in0_area.pos_y == 0 && in0_area.width && in0_area.height && + in0_area.pos_x % VK_BLENDER_ALIGN_X == 0 && + in0_area.width % VK_BLENDER_ALIGN_X == 0 && + in0_area.height % VK_BLENDER_ALIGN_Y == 0, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid input0 merge area, pos_x:%d, pos_y:%d, width:%d, height:%d", + in0_area.pos_x, in0_area.pos_y, in0_area.width, in0_area.height); + + in1_area = blender->get_input_merge_area (VKBlender::BufIdx1); + XCAM_FAIL_RETURN ( + ERROR, + in1_area.pos_y == 0 && in1_area.width && in1_area.height && + in1_area.pos_x % VK_BLENDER_ALIGN_X == 0 && + in1_area.width % VK_BLENDER_ALIGN_X == 0 && + in1_area.height % VK_BLENDER_ALIGN_Y == 0, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid input1 merge area, pos_x:%d, pos_y:%d, width:%d, height:%d", + in1_area.pos_x, in1_area.pos_y, in1_area.width, in1_area.height); + + out_area = blender->get_merge_window (); + XCAM_FAIL_RETURN ( + ERROR, + out_area.pos_y == 0 && out_area.width && out_area.height && + out_area.pos_x % VK_BLENDER_ALIGN_X == 0 && + out_area.width % VK_BLENDER_ALIGN_X == 0 && + out_area.height % VK_BLENDER_ALIGN_Y == 0, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid output merge area, pos_x:%d, pos_y:%d, width:%d, height:%d", + out_area.pos_x, out_area.pos_y, out_area.width, out_area.height); + + XCAM_FAIL_RETURN ( + ERROR, + in0_area.width == in1_area.width && in0_area.height == in1_area.height && + in0_area.width == out_area.width && in0_area.height == out_area.height, + XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid input or output overlap area, input0:%dx%d, input1:%dx%d, output:%dx%d", + in0_area.width, in0_area.height, in1_area.width, in1_area.height, out_area.width, out_area.height); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKBlender::set_output_info (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + const VideoBufferInfo &in0_info = param->in_buf->get_video_info (); + XCAM_FAIL_RETURN ( + ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "vk-blend only support NV12 format, but input format is %s", + xcam_fourcc_to_string (in0_info.format)); + + uint32_t out_width, out_height; + get_output_size (out_width, out_height); + XCAM_FAIL_RETURN ( + ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM, + "vk-blend invalid output size:%dx%d", out_width, out_height); + + VideoBufferInfo out_info; + out_info.init ( + in0_info.format, out_width, out_height, + XCAM_ALIGN_UP (out_width, VK_BLENDER_ALIGN_X), + XCAM_ALIGN_UP (out_height, VK_BLENDER_ALIGN_Y)); + set_out_video_info (out_info); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKBlender::configure_resource (const SmartPtr<Parameters> ¶m) +{ + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (_impl->pyr_layers_num <= XCAM_VK_MAX_LEVEL); + + SmartPtr<BlenderParam> blend_param = param.dynamic_cast_ptr<BlenderParam> (); + XCAM_ASSERT (blend_param.ptr () && blend_param->in_buf.ptr () && blend_param->in1_buf.ptr ()); + + XCamReturn ret = set_output_info (param); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend set output video info failed"); + + ret = check_merge_area (this); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend check merge area failed"); + + _impl->init_syncs (); + + ret = _impl->init_layers_bufs (param); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend init buffers failed"); + + ret = _impl->fix_parameters (); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend fix parameters failed"); + + ret = _impl->create_workers (this); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend create workers failed"); + + ret = _impl->redirect_workers (); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend redirect workers failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKBlender::start_work (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + SmartPtr<VKBlender::BlenderParam> blend_param = param.dynamic_cast_ptr<BlenderParam> (); + XCAM_ASSERT (blend_param.ptr ()); + XCAM_ASSERT (blend_param->in_buf.ptr () && blend_param->in1_buf.ptr () && blend_param->out_buf.ptr ()); + +#if DUMP_BUFFER + SmartPtr<VKVideoBuffer> in0_vk = blend_param->in_buf.dynamic_cast_ptr<VKVideoBuffer> (); + SmartPtr<VKVideoBuffer> in1_vk = blend_param->in1_buf.dynamic_cast_ptr<VKVideoBuffer> (); + XCAM_ASSERT (in0_vk.ptr () && in1_vk.ptr ()); + dump_level_vkbuf (in0_vk->get_vk_buf (), "blend-in", 0, VKBlender::BufIdx0); + dump_level_vkbuf (in1_vk->get_vk_buf (), "blend-in", 0, VKBlender::BufIdx1); +#endif + + _impl->bind_io_bufs_to_layer0 (blend_param->in_buf, blend_param->in1_buf, blend_param->out_buf); + _impl->bind_io_vkbufs_to_desc (); + + _impl->pyr_layer[0].lap_sync[BufIdx0]->increment (); + _impl->pyr_layer[0].lap_sync[BufIdx1]->increment (); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + ret = _impl->start_gauss_scale (1, BufIdx0); + CHECK_RET (ret, "vk-blend start gauss scale failed, level:1 index:0\n"); + + ret = _impl->start_gauss_scale (1, BufIdx1); + CHECK_RET (ret, "vk-blend start gauss scale failed, level:1 index:1\n"); + + execute_done (param, ret); + + return ret; +} + +void +VKBlender::gauss_scale_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("vk-blend gauss scale failed"); + return ; + } + + SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> (); + XCAM_ASSERT (args.ptr ()); + uint32_t level = args->get_level (); + uint32_t next_level = level + 1; + BufIdx idx = args->get_idx (); + + SmartPtr<VKWorker> gs_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (gs_worker.ptr ()); + gs_worker->wait_fence (); + +#if DUMP_BUFFER + dump_level_vkbuf (_impl->pyr_layer[level].gs_buf[idx], "gauss-scale", level, idx); +#endif + + XCamReturn ret = _impl->start_lap_trans (level, idx); + CHECK_RET (ret, "vk-blend execute laplace transformation failed, level:%d idx:%d", level, idx); + + if (next_level == _impl->pyr_layers_num) { + _impl->pyr_layer[level].blend_sync->increment (); + + ret = _impl->start_top_blend (); + CHECK_RET (ret, "vk-blend execute top blend failed, level:%d idx:%d", level, idx); + } else { + ret = _impl->start_gauss_scale (next_level, idx); + CHECK_RET (ret, "vk-blend execute gauss scale failed, level:%d idx:%d", next_level, idx); + } +} + +void +VKBlender::lap_trans_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (base); + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("vk-blend laplace transformation failed"); + return ; + } + + SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> (); + XCAM_ASSERT (args.ptr ()); + uint32_t level = args->get_level (); + + SmartPtr<VKWorker> laptrans_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (laptrans_worker.ptr ()); + laptrans_worker->wait_fence (); + +#if DUMP_BUFFER + BufIdx idx = args->get_idx (); + dump_level_vkbuf (_impl->pyr_layer[level].lap_buf[idx], "lap", level, idx); +#endif + + _impl->pyr_layer[level].reconstruct_sync->increment (); + + XCamReturn ret = _impl->start_reconstruct (level); + CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", level); +} + +void +VKBlender::blend_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (base); + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("vk-blend blend failed"); + return ; + } + + SmartPtr<VKWorker> blend_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (blend_worker.ptr ()); + blend_worker->wait_fence (); + +#if DUMP_BUFFER + dump_vkbuf (_impl->pyr_layer[_impl->pyr_layers_num - 1].blend_buf, "blend-top"); +#endif + + uint32_t pre_level = _impl->pyr_layers_num - 2; + _impl->pyr_layer[pre_level].reconstruct_sync->increment (); + + XCamReturn ret = _impl->start_reconstruct (pre_level); + CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", pre_level); +} + +void +VKBlender::reconstruct_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (base); + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("vk-blend reconstruct failed"); + return ; + } + + SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> (); + XCAM_ASSERT (args.ptr ()); + uint32_t level = args->get_level (); + + SmartPtr<VKWorker> reconstruct_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (reconstruct_worker.ptr ()); + reconstruct_worker->wait_fence (); + +#if DUMP_BUFFER + BufIdx idx = args->get_idx (); + dump_level_vkbuf (_impl->pyr_layer[level].reconstruct_buf, "reconstruct", level, idx); +#endif + + if (level == 0) { + return; + } + + uint32_t pre_level = level - 1; + _impl->pyr_layer[pre_level].reconstruct_sync->increment (); + + XCamReturn ret = _impl->start_reconstruct (pre_level); + CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", pre_level); +} + +SmartPtr<VKHandler> +create_vk_blender (const SmartPtr<VKDevice> &dev) +{ + SmartPtr<VKBlender> blender = new VKBlender (dev); + XCAM_ASSERT (blender.ptr ()); + + return blender; +} + +SmartPtr<Blender> +Blender::create_vk_blender (const SmartPtr<VKDevice> &dev) +{ + SmartPtr<VKHandler> handler = XCam::create_vk_blender (dev); + return handler.dynamic_cast_ptr<Blender> (); +} + +} |