diff options
Diffstat (limited to 'modules/vulkan')
34 files changed, 6748 insertions, 0 deletions
diff --git a/modules/vulkan/Makefile.am b/modules/vulkan/Makefile.am new file mode 100644 index 0000000..22763f0 --- /dev/null +++ b/modules/vulkan/Makefile.am @@ -0,0 +1,76 @@ +lib_LTLIBRARIES = libxcam_vulkan.la + +XCAM_VK_CXXFLAGS = \ + $(XCAM_CXXFLAGS) \ + $(LIBVULKAN_CFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules \ + -I$(top_builddir)/shaders/spv \ + $(NULL) + +XCAM_VK_LIBS = \ + $(LIBVULKAN_LIBS) \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +if HAVE_OPENCV +XCAM_VK_LIBS += $(top_builddir)/modules/ocv/libxcam_ocv.la +endif + +xcam_vulkan_sources = \ + vk_cmdbuf.cpp \ + vk_descriptor.cpp \ + vk_device.cpp \ + vk_handler.cpp \ + vk_instance.cpp \ + vk_memory.cpp \ + vk_pipeline.cpp \ + vk_shader.cpp \ + vk_sync.cpp \ + vk_video_buf_allocator.cpp \ + vk_worker.cpp \ + vulkan_common.cpp \ + vk_copy_handler.cpp \ + vk_geomap_handler.cpp \ + vk_blender.cpp \ + vk_stitcher.cpp \ + $(NULL) + +libxcam_vulkan_la_SOURCES = \ + $(xcam_vulkan_sources) \ + $(NULL) + +libxcam_vulkan_la_CXXFLAGS = \ + $(XCAM_VK_CXXFLAGS) \ + $(NULL) + +libxcam_vulkan_la_LIBADD = \ + $(XCAM_VK_LIBS) \ + $(NULL) + +libxcam_vulkan_la_LDFLAGS = \ + $(XCAM_LT_LDFLAGS) \ + $(NULL) + +libxcam_vulkanincludedir = $(includedir)/xcam/vulkan + +nobase_libxcam_vulkaninclude_HEADERS = \ + vk_cmdbuf.h \ + vk_descriptor.h \ + vk_device.h \ + vk_handler.h \ + vk_instance.h \ + vk_memory.h \ + vk_pipeline.h \ + vk_shader.h \ + vk_sync.h \ + vk_video_buf_allocator.h \ + vk_worker.h \ + vulkan_common.h \ + vk_copy_handler.h \ + vk_geomap_handler.h \ + vk_blender.h \ + vk_stitcher.h \ + $(NULL) + +libxcam_vulkan_la_LIBTOOLFLAGS = --tag=disable-static 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> (); +} + +} diff --git a/modules/vulkan/vk_blender.h b/modules/vulkan/vk_blender.h new file mode 100644 index 0000000..223b48f --- /dev/null +++ b/modules/vulkan/vk_blender.h @@ -0,0 +1,120 @@ +/* + * vk_blender.h - vulkan blender class + * + * 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> + */ + +#ifndef XCAM_VK_BLENDER_H +#define XCAM_VK_BLENDER_H + +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_handler.h> +#include <interface/blender.h> + +#define VK_BLENDER_ALIGN_X 8 +#define VK_BLENDER_ALIGN_Y 4 + +#define XCAM_VK_MAX_LEVEL 4 +#define XCAM_VK_DEFAULT_LEVEL 2 + +namespace XCam { + +namespace VKBlenderPriv { +class BlenderImpl; +} + +class VKBlender + : public VKHandler, public Blender +{ + friend class VKBlenderPriv::BlenderImpl; + friend SmartPtr<VKHandler> create_vk_blender (const SmartPtr<VKDevice> &dev); + +public: + struct BlenderParam : ImageHandler::Parameters { + SmartPtr<VideoBuffer> in1_buf; + + BlenderParam ( + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + const SmartPtr<VideoBuffer> &out) + : Parameters (in0, out) + , in1_buf (in1) + {} + }; + + class Sync + { + public: + Sync (uint32_t threshold) + : _count (0), _threshold (threshold) + {} + + void increment () { + ++_count; + } + void reset () { + _count = 0; + } + bool is_synced () { + return (_threshold == _count); + } + + private: + uint32_t _count; + const uint32_t _threshold; + }; + + enum BufIdx { + BufIdx0 = 0, + BufIdx1, + BufIdxMax + }; + +public: + ~VKBlender (); + + void gauss_scale_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + void lap_trans_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + void blend_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + void reconstruct_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + +protected: + explicit VKBlender (const SmartPtr<VKDevice> dev, const char *name = "VKBlender"); + + // derived from Blender interface + XCamReturn blend ( + const SmartPtr<VideoBuffer> &in0, const SmartPtr<VideoBuffer> &in1, SmartPtr<VideoBuffer> &out); + + // derived from VKHandler + XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + XCamReturn start_work (const SmartPtr<Parameters> ¶m); + + XCamReturn set_output_info (const SmartPtr<ImageHandler::Parameters> ¶m); + +private: + SmartPtr<VKBlenderPriv::BlenderImpl> _impl; +}; + +extern SmartPtr<VKHandler> create_vk_blender (const SmartPtr<VKDevice> &dev); + +} + +#endif // XCAM_VK_BLENDER_H diff --git a/modules/vulkan/vk_cmdbuf.cpp b/modules/vulkan/vk_cmdbuf.cpp new file mode 100644 index 0000000..1bc33be --- /dev/null +++ b/modules/vulkan/vk_cmdbuf.cpp @@ -0,0 +1,172 @@ +/* + * vk_cmdbuf.cpp - Vulkan command buffer + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_cmdbuf.h" +#include "vulkan_common.h" +#include "vk_pipeline.h" + +namespace XCam { + +VKCmdBuf::Pool::Pool (const SmartPtr<VKDevice> dev, VkCommandPool id) + : _pool_id (id) + , _dev (dev) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id)); +} + +VKCmdBuf::Pool::~Pool () +{ + if (XCAM_IS_VALID_VK_ID (_pool_id)) + _dev->destroy_cmd_pool (_pool_id); +} + +SmartPtr<VKCmdBuf> +VKCmdBuf::Pool::allocate_buffer () +{ + //VkCommandBufferAllocateInfo info {}; + VkCommandBuffer cmd_buf_id = _dev->allocate_cmd_buffer (_pool_id); + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (cmd_buf_id), NULL, + "VKCmdBuf allocate cmd buffer failed"); + return new VKCmdBuf (this, cmd_buf_id); +} + +void +VKCmdBuf::Pool::free_buffer (VkCommandBuffer buf_id) +{ + XCAM_ASSERT (_dev.ptr ()); + _dev->free_cmd_buffer (_pool_id, buf_id); +} + +SmartPtr<VKCmdBuf::Pool> +VKCmdBuf::create_pool (const SmartPtr<VKDevice> dev, VkFlags queue_flag) +{ + VkCommandPool pool_id = dev->create_cmd_pool (queue_flag); + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (pool_id), NULL, + "VKCmdBuf create_pool failed"); + SmartPtr<VKCmdBuf::Pool> pool = new VKCmdBuf::Pool (dev, pool_id); + return pool; +} + +SmartPtr<VKCmdBuf> +VKCmdBuf::create_command_buffer ( + const SmartPtr<VKDevice> dev, + const SmartPtr<VKCmdBuf::Pool> pool) +{ + XCAM_FAIL_RETURN ( + ERROR, dev.ptr (), NULL, + "VKCmdBuf create command buffer failed"); + + SmartPtr<VKCmdBuf::Pool> cmdbuf_pool = pool; + if (!pool.ptr()) { + cmdbuf_pool = create_pool (dev, VK_QUEUE_COMPUTE_BIT); + } + + XCAM_FAIL_RETURN ( + ERROR, cmdbuf_pool.ptr (), NULL, + "VKCmdBuf create command pool failed"); + + return cmdbuf_pool->allocate_buffer (); +} + +VKCmdBuf::VKCmdBuf (const SmartPtr<VKCmdBuf::Pool> pool, VkCommandBuffer buf_id) + : _cmd_buf_id (buf_id) + , _pool (pool) +{ +} + +VKCmdBuf::~VKCmdBuf () +{ + if (_pool.ptr () && XCAM_IS_VALID_VK_ID (_cmd_buf_id)) + _pool->free_buffer (_cmd_buf_id); +} + +VKCmdBuf::DispatchParam::DispatchParam (const SmartPtr<VKPipeline> &p, uint32_t x, uint32_t y, uint32_t z) + : _group_size (x, y, z) + , _pipeline (p) +{ +} + +VKCmdBuf::DispatchParam::~DispatchParam () +{ +} + +bool +VKCmdBuf::DispatchParam::update_push_consts (VKConstRange::VKPushConstArgs & push_consts) +{ + _push_consts = push_consts; + return true; +} + +XCamReturn +VKCmdBuf::DispatchParam::fill_cmd_buf (VKCmdBuf &buf) +{ + XCamReturn ret = _pipeline->bind_by (buf); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), + ret, "VKCmdBuf DispatchParam fill command buffer failed when binding pipeline"); + + for (size_t i = 0; i < _push_consts.size (); ++i) { + XCAM_RETURN_CHECK ( + ERROR, _pipeline->push_consts_by (buf, _push_consts[i]), + "VKCmdBuf DispatchParam fill command buffer failed when push consts (:%d)", i); + } + return buf.dispatch (_group_size); +} + +XCamReturn +VKCmdBuf::record (const SmartPtr<DispatchParam> param) +{ + VkCommandBufferBeginInfo buf_begin_info = {}; + buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + buf_begin_info.pInheritanceInfo = NULL; + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_cmd_buf_id)); + XCAM_VK_CHECK_RETURN ( + ERROR, vkBeginCommandBuffer (_cmd_buf_id, &buf_begin_info), + XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf begin command buffer failed"); + + XCamReturn ret = param->fill_cmd_buf (*this); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), + ret, "VKCmdBuf dispatch params failed"); + + XCAM_VK_CHECK_RETURN ( + ERROR, vkEndCommandBuffer (_cmd_buf_id), + XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf begin command buffer failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKCmdBuf::dispatch (const GroupSize &group) +{ + XCAM_FAIL_RETURN ( + ERROR, group.x * group.y * group.z > 0, + XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf dispatch params failed"); + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_cmd_buf_id)); + vkCmdDispatch (_cmd_buf_id, group.x, group.y, group.z); + return XCAM_RETURN_NO_ERROR; +} + +} diff --git a/modules/vulkan/vk_cmdbuf.h b/modules/vulkan/vk_cmdbuf.h new file mode 100644 index 0000000..458bea3 --- /dev/null +++ b/modules/vulkan/vk_cmdbuf.h @@ -0,0 +1,106 @@ +/* + * vk_cmdbuf.h - Vulkan command buffer + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_CMD_BUF_H +#define XCAM_VK_CMD_BUF_H + +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_descriptor.h> +#include <vulkan/vk_device.h> + +namespace XCam { + +class VKCmdBuf +{ +public: + struct GroupSize { + uint32_t x; + uint32_t y; + uint32_t z; + GroupSize (uint32_t x_, uint32_t y_, uint32_t z_) + : x (x_) + , y (y_) + , z (z_) + {} + }; + + class DispatchParam { + friend class VKCmdBuf; + public: + DispatchParam (const SmartPtr<VKPipeline> &p, uint32_t x, uint32_t y = 1, uint32_t z = 1); + virtual ~DispatchParam (); + bool update_push_consts (VKConstRange::VKPushConstArgs & push_consts); + protected: + virtual XCamReturn fill_cmd_buf (VKCmdBuf &buf); + XCAM_DEAD_COPY (DispatchParam); + + protected: + GroupSize _group_size; + const SmartPtr<VKPipeline> _pipeline; + VKConstRange::VKPushConstArgs _push_consts; + }; + + class Pool + : public RefObj + { + friend class VKCmdBuf; + public: + ~Pool (); + SmartPtr<VKCmdBuf> allocate_buffer (); + void free_buffer (VkCommandBuffer buf_id); + + private: + explicit Pool (const SmartPtr<VKDevice> dev, VkCommandPool id); + XCAM_DEAD_COPY (Pool); + private: + VkCommandPool _pool_id; + SmartPtr<VKDevice> _dev; + }; + +public: + static SmartPtr<VKCmdBuf> + create_command_buffer (const SmartPtr<VKDevice> dev, const SmartPtr<Pool> pool = NULL); + static SmartPtr<Pool> create_pool (const SmartPtr<VKDevice> dev, VkFlags queue_flag); + virtual ~VKCmdBuf (); + + VkCommandBuffer get_cmd_buf_id () const { + return _cmd_buf_id; + } + + XCamReturn record (const SmartPtr<DispatchParam> param); + + // for fill_cmd_buf + XCamReturn dispatch (const GroupSize &group); + +protected: + explicit VKCmdBuf (const SmartPtr<Pool> pool, VkCommandBuffer buf_id); + +private: + XCAM_DEAD_COPY (VKCmdBuf); + +protected: + VkCommandBuffer _cmd_buf_id; + + SmartPtr<Pool> _pool; +}; + +} + +#endif //XCAM_VK_CMD_BUF_H diff --git a/modules/vulkan/vk_copy_handler.cpp b/modules/vulkan/vk_copy_handler.cpp new file mode 100644 index 0000000..4a89446 --- /dev/null +++ b/modules/vulkan/vk_copy_handler.cpp @@ -0,0 +1,270 @@ +/* + * vk_copy_handler.cpp - vulkan copy handler + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include <vulkan/vulkan_std.h> +#include "vk_copy_handler.h" +#include "vk_video_buf_allocator.h" +#include "vk_shader.h" +#include "vk_memory.h" +#include "vk_worker.h" +#include "vk_device.h" + +#define COPY_SHADER_BINDING_COUNT 2 +#define INVALID_INDEX (uint32_t)(-1) + +namespace XCam { + +namespace { + +DECLARE_WORK_CALLBACK (CbCopyShader, VKCopyHandler, copy_done); + +class CopyArgs + : public VKWorker::VKArguments +{ +public: + explicit CopyArgs (const SmartPtr<ImageHandler::Parameters> ¶m) + : _param (param) + { + XCAM_ASSERT (param.ptr ()); + } + const SmartPtr<ImageHandler::Parameters> &get_param () const { + return _param; + } + +private: + SmartPtr<ImageHandler::Parameters> _param; +}; + +class VKCopyPushConst + : public VKConstRange::VKPushConstArg +{ +public: + VKCopyPushConst (const VKCopyHandler::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; + } + +private: + VKCopyHandler::PushConstsProp _prop; +}; + +}; + +static const VKShaderInfo copy_shader_info ( + "main", +std::vector<uint32_t> { +#include "shader_copy.comp.spv" +}); + +#if 0 +VKCopyArguments::VKCopyArguments (const SmartPtr<VKBuffer> in, SmartPtr<VKBuffer> out) + : _in_buf (in) + , _out_buf (out) +{ + XCAM_ASSERT (in.ptr()); + XCAM_ASSERT (out.ptr()); +} + +XCamReturn +VKCopyArguments::prepare_bindings (VKDescriptor::SetBindInfoArray &binding_array) +{ + XCAM_FAIL_RETURN ( + ERROR, _in_buf.ptr () && _out_buf.ptr (), XCAM_RETURN_ERROR_PARAM, + "VKCopyArguments input or output buffer is empty."); + + binding_array.resize (2); + binding_array[0].layout = new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0); + binding_array[0].desc = VKBufDesc (_in_buf); + + binding_array[0].layout = new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); + binding_array[0].desc = VKBufDesc (_out_buf); + return XCAM_RETURN_NO_ERROR; +} +#endif + +VKCopyHandler::PushConstsProp::PushConstsProp () + : in_img_width (0) + , in_x_offset (0) + , out_img_width (0) + , out_x_offset (0) + , copy_width (0) +{ +} + +VKCopyHandler::VKCopyHandler (const SmartPtr<VKDevice> &dev, const char* name) + : VKHandler (dev, name) + , _index (INVALID_INDEX) +{ +} + +bool +VKCopyHandler::set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area) +{ + XCAM_FAIL_RETURN ( + ERROR, + idx != INVALID_INDEX && + in_area.width && in_area.height && + in_area.width == out_area.width && in_area.height == out_area.height, + false, + "VKCopyHandler(%s): set copy area(idx:%d) failed, input size:%dx%d output size:%dx%d", + XCAM_STR (get_name ()), idx, in_area.width, in_area.height, out_area.width, out_area.height); + + _index = idx; + _in_area = in_area; + _out_area = out_area; + + XCAM_LOG_DEBUG ("VKCopyHandler: copy area(idx:%d) input area(%d, %d, %d, %d) output area(%d, %d, %d, %d)", + idx, + in_area.pos_x, in_area.pos_y, in_area.width, in_area.height, + out_area.pos_x, out_area.pos_y, out_area.width, out_area.height); + + return true; +} + +#define UNIT_BYTES (4*sizeof(uint32_t)) + +XCamReturn +VKCopyHandler::configure_resource (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (!_worker.ptr ()); + + XCAM_FAIL_RETURN ( + ERROR, param->in_buf.ptr (), XCAM_RETURN_ERROR_VULKAN, + "VKCopyHandler(%s) param.in_buf is empty.", XCAM_STR (get_name ())); + XCAM_FAIL_RETURN ( + ERROR, _index != INVALID_INDEX, XCAM_RETURN_ERROR_PARAM, + "VKCopyHandler(%s) invalid copy area, need set copy area first", XCAM_STR (get_name ())); + + VideoBufferInfo in_info = param->in_buf->get_video_info (); + VideoBufferInfo out_info; + if (param->out_buf.ptr ()) + out_info = param->out_buf->get_video_info (); + else + out_info = get_out_video_info (); + XCAM_FAIL_RETURN ( + ERROR, out_info.is_valid (), XCAM_RETURN_ERROR_PARAM, + "VKCopyHandler(%s) invalid out info.", XCAM_STR (get_name ())); + + _image_prop.in_img_width = in_info.aligned_width / UNIT_BYTES; + _image_prop.in_x_offset = _in_area.pos_x / UNIT_BYTES; + _image_prop.out_img_width = out_info.aligned_width / UNIT_BYTES; + _image_prop.out_x_offset = _out_area.pos_x / UNIT_BYTES; + _image_prop.copy_width = _in_area.width / UNIT_BYTES; + WorkSize global_size ( + XCAM_ALIGN_UP (_image_prop.copy_width, 8 ) / 8, + XCAM_ALIGN_UP (_in_area.height * 3 / 2, 8 ) / 8); + + _binding_layout.clear (); + for (int i = 0; i < COPY_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + _binding_layout.push_back (binding); + } + + if (!_worker.ptr ()) { + _worker = new VKWorker(get_vk_device(), "CbCopyShader", new CbCopyShader (this)); + XCAM_ASSERT (_worker.ptr()); + + _worker->set_global_size (global_size); + + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKCopyPushConst (_image_prop)); + ret = _worker->build (copy_shader_info, _binding_layout, push_consts); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_VULKAN, + "VKCopyHandler(%s) build copy shader failed.", XCAM_STR (get_name ())); + } + + return ret; +} + +XCamReturn +VKCopyHandler::start_work (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCAM_ASSERT (_binding_layout.size () == COPY_SHADER_BINDING_COUNT); + SmartPtr<VKVideoBuffer> in_vk = param->in_buf.dynamic_cast_ptr<VKVideoBuffer> (); + SmartPtr<VKVideoBuffer> out_vk = param->out_buf.dynamic_cast_ptr<VKVideoBuffer> (); + + XCAM_FAIL_RETURN ( + ERROR, in_vk.ptr () && out_vk.ptr(), XCAM_RETURN_ERROR_VULKAN, + "VKCopyHandler(%s) param.in_buf or param.out_buf is not vk buf.", XCAM_STR (get_name ())); + + VKDescriptor::SetBindInfoArray bindings (_binding_layout.size ()); + bindings[0].layout = _binding_layout[0]; + bindings[0].desc = VKBufDesc (in_vk->get_vk_buf ()); + bindings[1].layout = _binding_layout[1]; + bindings[1].desc = VKBufDesc (out_vk->get_vk_buf ()); + + SmartPtr<CopyArgs> args = new CopyArgs (param); + args->set_bindings (bindings); + args->add_push_const (new VKCopyPushConst (_image_prop)); + return _worker->work (args); +} + +void +VKCopyHandler::copy_done ( + const SmartPtr<Worker> &worker, + const SmartPtr<Worker::Arguments> &base, + const XCamReturn error) +{ + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("VKCopyHandler(%s) copy failed.", XCAM_STR (get_name ())); + } + + SmartPtr<VKWorker> vk_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (vk_worker.ptr ()); + vk_worker->wait_fence (); + + SmartPtr<CopyArgs> args = base.dynamic_cast_ptr<CopyArgs> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + XCAM_ASSERT (param.ptr ()); + + execute_done (param, error); +} + +XCamReturn +VKCopyHandler::copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf) +{ + SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf); + XCAM_ASSERT (param.ptr ()); + + XCamReturn ret = execute_buffer (param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "VKCopyHandler(%s) copy failed", XCAM_STR (get_name ())); + + if (!out_buf.ptr ()) { + out_buf = param->out_buf; + } + + return ret; +} + +}; diff --git a/modules/vulkan/vk_copy_handler.h b/modules/vulkan/vk_copy_handler.h new file mode 100644 index 0000000..8c71bae --- /dev/null +++ b/modules/vulkan/vk_copy_handler.h @@ -0,0 +1,90 @@ +/* + * vk_copy_handler.h - vulkan copy handler + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_COPY_HANDLER_H +#define XCAM_VK_COPY_HANDLER_H + +#include <xcam_utils.h> +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_worker.h> +#include <vulkan/vk_handler.h> +#include <vulkan/vk_descriptor.h> + +namespace XCam { + +#if 0 +class VKCopyArguments + : public VKWorker::VKArguments +{ +public: + explicit VKCopyArguments (const SmartPtr<VKBuffer> in, SmartPtr<VKBuffer> out); + +private: + virtual XCamReturn prepare_bindings (VKDescriptor::SetBindInfoArray &binding_array); +private: + SmartPtr<VKBuffer> _in_buf; + SmartPtr<VKBuffer> _out_buf; +}; +#endif + +class VKCopyHandler + : public VKHandler +{ +public: + struct PushConstsProp { + uint in_img_width; + uint in_x_offset; + uint out_img_width; + uint out_x_offset; + uint copy_width; + + PushConstsProp (); + }; + +public: + explicit VKCopyHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-copy-handler"); + + bool set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area); + uint32_t get_index () { + return _index; + } + + XCamReturn copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf); + void copy_done ( + const SmartPtr<Worker> &worker, + const SmartPtr<Worker::Arguments> &base, + const XCamReturn error); + +private: + virtual XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + virtual XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + SmartPtr<VKWorker> _worker; + PushConstsProp _image_prop; + VKDescriptor::BindingArray _binding_layout; + + uint32_t _index; + Rect _in_area; + Rect _out_area; +}; + +} +#endif //XCAM_VK_COPY_HANDLER_H diff --git a/modules/vulkan/vk_descriptor.cpp b/modules/vulkan/vk_descriptor.cpp new file mode 100644 index 0000000..888d3d6 --- /dev/null +++ b/modules/vulkan/vk_descriptor.cpp @@ -0,0 +1,220 @@ +/* + * vk_descriptor.cpp - Vulkan descriptor + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_descriptor.h" +#include "vk_device.h" + +namespace XCam { + +namespace VKDescriptor { + +SetLayoutBinding::SetLayoutBinding ( + VkDescriptorType type, VkShaderStageFlags stage, uint32_t idx, uint32_t count) +{ + xcam_mem_clear (_binding); + _binding.binding = idx; + _binding.descriptorType = type; + _binding.descriptorCount = count; + _binding.stageFlags = stage; + _binding.pImmutableSamplers = NULL; +} + +SetLayoutBinding::~SetLayoutBinding () +{ +} + +VkBindingArray +get_vk_layoutbindings (const BindingArray &array) +{ + VkBindingArray ret; + ret.reserve (array.size ()); + for (size_t i = 0; i < array.size (); ++i) { + ret.push_back(array[i]->get_vk_binding ()); + } + return ret; +} + +Pool::Pool (const SmartPtr<VKDevice> dev) + : _pool_id (VK_NULL_HANDLE) + , _set_size (0) + , _dev (dev) +{} + +Pool::~Pool () +{ + if (XCAM_IS_VALID_VK_ID (_pool_id)) { + _dev->destroy_desc_pool (_pool_id); + } +} + +void +Pool::add_binding (const SmartPtr<SetLayoutBinding> &bind) +{ + VkDescriptorSetLayoutBinding vk_binding = bind->get_vk_binding (); + Pool::TypeTable::iterator i = _types.find (vk_binding.descriptorType); + if (i == _types.end ()) + _types.insert (i, Pool::TypeTable::value_type (vk_binding.descriptorType, vk_binding.descriptorCount)); + else + i->second += vk_binding.descriptorCount; +} + +bool +Pool::add_set_bindings (const BindingArray &binds) +{ + XCAM_FAIL_RETURN ( + ERROR, !XCAM_IS_VALID_VK_ID (_pool_id), false, + "vk desriptor pool was inited, cannot add new binding."); + + for (BindingArray::const_iterator i = binds.begin (); i != binds.end (); ++i) { + add_binding (*i); + } + ++_set_size; + + return true; +} + +XCamReturn +Pool::create () +{ + XCAM_FAIL_RETURN ( + ERROR, !_types.empty (), XCAM_RETURN_ERROR_PARAM, + "vk desriptor pool cannot create since no types added."); + + XCAM_FAIL_RETURN ( + ERROR, _dev.ptr (), XCAM_RETURN_ERROR_PARAM, + "vk desriptor pool cannot create, device is null"); + + std::vector<VkDescriptorPoolSize> pool_sizes; + pool_sizes.reserve (_types.size ()); + for (Pool::TypeTable::iterator i = _types.begin (); i != _types.end(); ++i) { + VkDescriptorPoolSize new_size = {}; + new_size.type = i->first; + new_size.descriptorCount = i->second; + pool_sizes.push_back (new_size); + } + + XCAM_ASSERT (_set_size); + VkDescriptorPoolCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + create_info.maxSets = _set_size; + create_info.poolSizeCount = pool_sizes.size (); + create_info.pPoolSizes = pool_sizes.data (); + + _pool_id = _dev->create_desc_pool (create_info); + + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (_pool_id), XCAM_RETURN_ERROR_VULKAN, + "vk desriptor pool create pool_id failed"); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<Set> +Pool::allocate_set (const SetBindInfoArray &bind_array, VkDescriptorSetLayout layout) +{ + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (_pool_id), NULL, + "vk desriptor pool allocate set failed, pool was not ready"); + +#if 0 + XCAM_FAIL_RETURN ( + ERROR, bind_array.size () == bufs.size (), NULL, + "vk desriptor pool allocate set failed, bindings and bufs sizes are not matched"); +#endif + + XCAM_FAIL_RETURN ( + ERROR, _set_size > 0, NULL, + "vk desriptor pool allocate set failed, bindings and bufs sizes are not matched"); + + //TODO remove binds types from _types + + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = _pool_id; + alloc_info.pSetLayouts = &layout; + alloc_info.descriptorSetCount = 1; + + VkDescriptorSet desc_set_id = _dev->allocate_desc_set (alloc_info); + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (desc_set_id) > 0, NULL, + "vk desriptor pool allocate set failed"); + SmartPtr<Set> new_set = new Set (desc_set_id, this); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (new_set->update_set (bind_array)), NULL, + "vk descriptor pool update set failed"); + + --_set_size; + return new_set; +} + +void +Pool::destroy_desc_set (VkDescriptorSet set_id) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_pool_id)); + if (xcam_ret_is_ok (_dev->free_desc_set (set_id, _pool_id))) + ++_set_size; +} + +Set::Set (VkDescriptorSet set_id, const SmartPtr<Pool> pool) + : _set_id (set_id) + , _pool (pool) +{ +} + +Set::~Set () +{ + if (XCAM_IS_VALID_VK_ID (_set_id)) { + _pool->destroy_desc_set (_set_id); + } +} + +XCamReturn +Set::update_set (const SetBindInfoArray &bind_array) +{ + std::vector<VkWriteDescriptorSet> write_desc_info (bind_array.size ()); + for (uint32_t i = 0; i < bind_array.size (); ++i) { + const SetBindInfo &bind_info = bind_array[i]; + SmartPtr<SetLayoutBinding> bind = bind_info.layout; + XCAM_ASSERT (bind.ptr () && bind_info.desc.buf.ptr ()); + + VkWriteDescriptorSet &info = write_desc_info[i]; + xcam_mem_clear (info); + info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + info.dstSet = _set_id; + info.dstBinding = bind->get_index (); + info.descriptorCount = 1; + info.descriptorType = bind->get_desc_type(); + info.pBufferInfo = &bind_info.desc.desc_info; + } + SmartPtr<VKDevice> dev = _pool->get_device (); + XCAM_ASSERT (dev.ptr ()); + XCamReturn ret = dev->update_desc_set (write_desc_info); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk descriptor pool update set failed"); + + _bind_array = bind_array; + return ret; +} + +} + +} diff --git a/modules/vulkan/vk_descriptor.h b/modules/vulkan/vk_descriptor.h new file mode 100644 index 0000000..63eff6a --- /dev/null +++ b/modules/vulkan/vk_descriptor.h @@ -0,0 +1,163 @@ +/* + * vk_descriptor.h - Vulkan descriptor + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_DESCRIPTOR_H +#define XCAM_VK_DESCRIPTOR_H + +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_memory.h> +#include <map> + +namespace XCam { + +class VKDevice; + +namespace VKDescriptor { + +class SetLayoutBinding +{ +public: + virtual ~SetLayoutBinding (); + const VkDescriptorSetLayoutBinding &get_vk_binding () const { + return _binding; + } + VkDescriptorType get_desc_type () const { + return _binding.descriptorType; + } + uint32_t get_index () const { + return _binding.binding; + } + +protected: + explicit SetLayoutBinding ( + VkDescriptorType type, VkShaderStageFlags stage, uint32_t idx, uint32_t count); + +private: + XCAM_DEAD_COPY (SetLayoutBinding); +protected: + VkDescriptorSetLayoutBinding _binding; +}; + +template <VkShaderStageFlags stage> +class LayoutBinding + : public SetLayoutBinding +{ +public: + explicit LayoutBinding (VkDescriptorType type, uint32_t idx) + : SetLayoutBinding (type, stage, idx, 1) + {} +}; + +typedef LayoutBinding<VK_SHADER_STAGE_COMPUTE_BIT> ComputeLayoutBinding; +typedef LayoutBinding<VK_SHADER_STAGE_VERTEX_BIT> VetexLayoutBinding; +typedef LayoutBinding<VK_SHADER_STAGE_FRAGMENT_BIT> FragmentLayoutBinding; + +typedef std::vector<SmartPtr<SetLayoutBinding>> BindingArray; + +typedef std::vector<VkDescriptorSetLayoutBinding> VkBindingArray; + +VkBindingArray get_vk_layoutbindings (const BindingArray &array); + +struct SetBindInfo { + SmartPtr<SetLayoutBinding> layout; + VKBufDesc desc; +}; + +typedef std::vector<SetBindInfo> SetBindInfoArray; + +class Pool; +class Set { +public: + explicit Set (VkDescriptorSet set_id, const SmartPtr<Pool> pool); + ~Set (); + XCamReturn update_set (const SetBindInfoArray &bind_array); + VkDescriptorSet get_set_id () const { + return _set_id; + } + +private: + XCAM_DEAD_COPY (Set); + + VkDescriptorSet _set_id; + SetBindInfoArray _bind_array; + SmartPtr<Pool> _pool; +}; + +class Pool + : public RefObj +{ + friend class Set; +public: + explicit Pool (const SmartPtr<VKDevice> dev); + ~Pool (); + bool add_set_bindings (const BindingArray &binds); + XCamReturn create (); + const SmartPtr<VKDevice> &get_device() const { + return _dev; + } + + SmartPtr<Set> allocate_set ( + const SetBindInfoArray &bind_array, VkDescriptorSetLayout layout); + +private: + XCAM_DEAD_COPY (Pool); + void add_binding (const SmartPtr<SetLayoutBinding> &bind); + void destroy_desc_set (VkDescriptorSet set_id); + +private: + typedef std::map<VkDescriptorType, uint32_t> TypeTable; + + VkDescriptorPool _pool_id; + uint32_t _set_size; + TypeTable _types; + const SmartPtr<VKDevice> _dev; +}; + +} + +namespace VKConstRange { + +class VKPushConstArg { +public: + virtual ~VKPushConstArg () {} + virtual bool get_const_data (VkPushConstantRange &range, void *& ptr) = 0; +}; + +typedef std::vector<SmartPtr<VKPushConstArg>> VKPushConstArgs; + +typedef std::vector<VkPushConstantRange> VKConstantArray; + +template <VkShaderStageFlags stage> +VkPushConstantRange +get_constants (uint32_t size, uint32_t offset) +{ + VkPushConstantRange range = {}; + range.stageFlags = stage; + range.offset = offset; + range.size = size; + return range; +} + +#define get_compute_consts get_constants<VK_SHADER_STAGE_COMPUTE_BIT> +} + +} + +#endif //XCAM_VK_DESCRIPTOR_H diff --git a/modules/vulkan/vk_device.cpp b/modules/vulkan/vk_device.cpp new file mode 100644 index 0000000..bf5e68e --- /dev/null +++ b/modules/vulkan/vk_device.cpp @@ -0,0 +1,471 @@ +/* + * vk_device.cpp - vulkan device + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vulkan_common.h" +#include "vk_device.h" +#include "vk_shader.h" +#include "vk_instance.h" +#include "vk_sync.h" +#include "vk_cmdbuf.h" +#include "file_handle.h" + +namespace XCam { + +SmartPtr<VKDevice> VKDevice::_default_dev; +Mutex VKDevice::_default_mutex; + +VKDevice::~VKDevice () +{ + if (_dev_id) + vkDestroyDevice (_dev_id, _allocator.ptr ()); +} + +VKDevice::VKDevice (VkDevice id, const SmartPtr<VKInstance> &instance) + : _dev_id (id) + , _instance (instance) +{ + XCAM_ASSERT (instance.ptr ()); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id)); + _allocator = instance->get_allocator (); +} + +SmartPtr<VKDevice> +VKDevice::default_device () +{ + SmartLock lock (_default_mutex); + if (!_default_dev.ptr()) { + _default_dev = create_device (); + } + XCAM_FAIL_RETURN ( + ERROR, _default_dev.ptr (), NULL, + "VKDevice prepare default device failed."); + return _default_dev; +} + +SmartPtr<VKDevice> +VKDevice::create_device () +{ + SmartPtr<VKInstance> instance = VKInstance::get_instance (); + XCAM_FAIL_RETURN ( + ERROR, instance.ptr (), NULL, + "vk create device failed"); + + VkPhysicalDevice phy_dev = instance->get_physical_dev (); + uint32_t compute_idx = instance->get_compute_queue_family_idx (); + SmartPtr<VkAllocationCallbacks> allocator = instance->get_allocator (); + + float priority = 1.0f; //TODO, queue priority change? + VkDeviceQueueCreateInfo dev_queue_info = {}; + dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + dev_queue_info.queueFamilyIndex = compute_idx; // default use compute idx + dev_queue_info.queueCount = 1; + dev_queue_info.pQueuePriorities = &priority; + + VkDeviceCreateInfo dev_create_info = {}; + dev_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + //TODO, add graphics queue info + dev_create_info.queueCreateInfoCount = 1; + dev_create_info.pQueueCreateInfos = &dev_queue_info; + + VkDevice dev_id = 0; + XCAM_VK_CHECK_RETURN ( + ERROR, + vkCreateDevice (phy_dev, &dev_create_info, allocator.ptr (), &dev_id), + NULL, "create vk device failed"); + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (dev_id)); + SmartPtr<VKDevice> device = new VKDevice (dev_id, instance); + XCAM_ASSERT (device.ptr ()); + + XCamReturn ret = device->prepare_compute_queue (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), NULL, + "VKDevice prepare compute queue failed."); + + return device; +} + +XCamReturn +VKDevice::prepare_compute_queue () +{ + uint32_t compute_idx = _instance->get_compute_queue_family_idx (); + vkGetDeviceQueue (_dev_id, compute_idx, 0, &_compute_queue); + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<VKShader> +VKDevice::create_shader (const char *file_name) +{ + FileHandle file (file_name, "rb"); + XCAM_FAIL_RETURN ( + ERROR, file.is_valid (), NULL, + "VKDevice load shader failed when opend shader file:%s.", + XCAM_STR (file_name)); + + size_t file_size; + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (file.get_file_size (file_size)) || file_size == 0, NULL, + "VKDevice load shader failed when read shader file:%s.", + XCAM_STR (file_name)); + std::vector<uint32_t> content (XCAM_ALIGN_UP (file_size, 4) / 4, 0); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (file.read_file ((void *)content.data (), file_size)), NULL, + "VKDevice load shader failed when read shader file:%s.", + XCAM_STR (file_name)); + file.close (); + + SmartPtr<VKShader> shader = create_shader (content); + if (shader.ptr ()) + shader->set_name (file_name); + return shader; +} + +SmartPtr<VKShader> +VKDevice::create_shader (const std::vector<uint32_t> &binary) +{ + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (_dev_id), NULL, + "VKDevice load shader failed with error of null device ready."); + XCAM_FAIL_RETURN ( + ERROR, binary.size () > 5, NULL, + "VKDevice load shader failed since binary is corrupt."); + + VkShaderModule shader_id; + VkShaderModuleCreateInfo module_create_info = {}; + module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + module_create_info.pNext = NULL; + module_create_info.codeSize = binary.size() * sizeof (binary[0]); + module_create_info.pCode = binary.data(); + module_create_info.flags = 0; + + XCAM_VK_CHECK_RETURN ( + ERROR, vkCreateShaderModule (_dev_id, &module_create_info, NULL, &shader_id), + NULL, "VKDevice create shader module failed."); + + XCAM_IS_VALID_VK_ID (shader_id); + return new VKShader (this, shader_id); +} + +void +VKDevice::destroy_shader_id (VkShaderModule shader) +{ + if (XCAM_IS_VALID_VK_ID(_dev_id) && XCAM_IS_VALID_VK_ID (shader)) + vkDestroyShaderModule (_dev_id, shader, _allocator.ptr()); +} + +VkDeviceMemory +VKDevice::allocate_mem_id (VkDeviceSize size, VkMemoryPropertyFlags memory_prop) +{ + VkDeviceMemory mem_id; + VkMemoryAllocateInfo mem_alloc_info = {}; + mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc_info.allocationSize = size; + mem_alloc_info.memoryTypeIndex = _instance->get_mem_type_index (memory_prop); + + XCAM_FAIL_RETURN ( + ERROR, mem_alloc_info.memoryTypeIndex != (uint32_t)(-1), VK_NULL_HANDLE, + "VKDevice create mem id failed, can NOT find memory type:0x%08x.", (uint32_t)memory_prop); + + XCAM_VK_CHECK_RETURN ( + ERROR, vkAllocateMemory (_dev_id, &mem_alloc_info, _allocator.ptr (), &mem_id), + VK_NULL_HANDLE, "create vk buffer failed in allocating memory"); + return mem_id; +} + +void +VKDevice::free_mem_id (VkDeviceMemory mem) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem)); + + vkFreeMemory (_dev_id, mem, _allocator.ptr ()); +} + +XCamReturn +VKDevice::map_mem (VkDeviceMemory mem, VkDeviceSize size, VkDeviceSize offset, void *&ptr) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem)); + XCAM_VK_CHECK_RETURN ( + ERROR, vkMapMemory (_dev_id, mem, offset, size, 0, &ptr), XCAM_RETURN_ERROR_VULKAN, + "vk device map mem failed. size:%lld", size); + return XCAM_RETURN_NO_ERROR; +} + +void +VKDevice::unmap_mem (VkDeviceMemory mem) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem)); + vkUnmapMemory (_dev_id, mem); +} + +VkBuffer +VKDevice::create_buf_id (VkBufferUsageFlags usage, uint32_t size) +{ + VkBufferCreateInfo buf_create_info = {}; + buf_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buf_create_info.size = size; + buf_create_info.usage = usage; + buf_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer buf_id; + XCAM_VK_CHECK_RETURN ( + ERROR, vkCreateBuffer (_dev_id, &buf_create_info, _allocator.ptr (), &buf_id), + VK_NULL_HANDLE, "create vk buffer failed"); + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf_id)); + return buf_id; +} + +void +VKDevice::destroy_buf_id (VkBuffer buf) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf)); + + vkDestroyBuffer (_dev_id, buf, _allocator.ptr ()); +} + +XCamReturn +VKDevice::bind_buffer (VkBuffer buf, VkDeviceMemory mem, VkDeviceSize offset) +{ + XCAM_VK_CHECK_RETURN ( + ERROR, vkBindBufferMemory (_dev_id, buf, mem, offset), + XCAM_RETURN_ERROR_VULKAN, "vkdevice bind buffer to mem failed"); + + return XCAM_RETURN_NO_ERROR; +} + +VkDescriptorPool +VKDevice::create_desc_pool (const VkDescriptorPoolCreateInfo &info) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + + VkDescriptorPool pool_id; + XCAM_VK_CHECK_RETURN ( + ERROR, + vkCreateDescriptorPool (_dev_id, &info, _allocator.ptr (), &pool_id), + VK_NULL_HANDLE, + "vkdevice create desriptor pool failed"); + return pool_id; +} + +void +VKDevice::destroy_desc_pool (VkDescriptorPool pool) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool)); + vkDestroyDescriptorPool (_dev_id, pool, _allocator.ptr ()); +} + +VkDescriptorSet +VKDevice::allocate_desc_set (const VkDescriptorSetAllocateInfo &info) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + + VkDescriptorSet set_id; + XCAM_VK_CHECK_RETURN ( + ERROR, + vkAllocateDescriptorSets (_dev_id, &info, &set_id), + VK_NULL_HANDLE, + "vkdevice create desriptor set failed"); + return set_id; + +} + +XCamReturn +VKDevice::free_desc_set (VkDescriptorSet set, VkDescriptorPool pool) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (set)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool)); + + XCAM_VK_CHECK_RETURN ( + ERROR, + vkFreeDescriptorSets (_dev_id, pool, 1, &set), + XCAM_RETURN_ERROR_VULKAN, + "vkdevice free desriptor set from pool failed"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKDevice::update_desc_set (const std::vector<VkWriteDescriptorSet> &sets) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + vkUpdateDescriptorSets (_dev_id, sets.size (), sets.data (), 0, NULL); + + return XCAM_RETURN_NO_ERROR; +} + +VkCommandPool +VKDevice::create_cmd_pool (VkFlags queue_flag) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (_instance.ptr ()); + VkCommandPool pool_id = VK_NULL_HANDLE; + + VkCommandPoolCreateInfo create_pool_info = {}; + create_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + create_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + if (queue_flag == VK_QUEUE_COMPUTE_BIT) + create_pool_info.queueFamilyIndex = _instance->get_compute_queue_family_idx (); + else if (queue_flag == VK_QUEUE_GRAPHICS_BIT) + create_pool_info.queueFamilyIndex = _instance->get_graphics_queue_family_idx (); + else { + XCAM_LOG_WARNING ("VKDevice create command pool failed, queue_flag(%d) not supported.", queue_flag); + return VK_NULL_HANDLE; + } + + XCAM_VK_CHECK_RETURN ( + ERROR, vkCreateCommandPool (_dev_id, &create_pool_info, _allocator.ptr (), &pool_id), + VK_NULL_HANDLE, "VKDevice create command pool failed."); + return pool_id; +} + +void +VKDevice::destroy_cmd_pool (VkCommandPool pool) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool)); + vkDestroyCommandPool (_dev_id, pool, _allocator.ptr ()); +} + +VkCommandBuffer +VKDevice::allocate_cmd_buffer (VkCommandPool pool) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool)); + + VkCommandBufferAllocateInfo allocate_info = {}; + allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocate_info.commandPool = pool; + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocate_info.commandBufferCount = 1; + + VkCommandBuffer buf_id = VK_NULL_HANDLE; + + XCAM_VK_CHECK_RETURN ( + ERROR, vkAllocateCommandBuffers (_dev_id, &allocate_info, &buf_id), + VK_NULL_HANDLE, "VKDevice create command buffers failed."); + return buf_id; +} + +void +VKDevice::free_cmd_buffer (VkCommandPool pool, VkCommandBuffer buf) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf)); + + vkFreeCommandBuffers (_dev_id, pool, 1, &buf); +} + +SmartPtr<VKFence> +VKDevice::create_fence (VkFenceCreateFlags flags) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.flags = flags; + + VkFence fence_id = VK_NULL_HANDLE; + XCAM_VK_CHECK_RETURN ( + ERROR, vkCreateFence (_dev_id, &fence_info, _allocator.ptr (), &fence_id), + NULL, "VKDevice create fence failed."); + return new VKFence (this, fence_id); +} + +void +VKDevice::destroy_fence (VkFence fence) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence)); + + vkDestroyFence (_dev_id, fence, _allocator.ptr ()); +} + +XCamReturn +VKDevice::reset_fence (VkFence fence) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence)); + + XCAM_VK_CHECK_RETURN ( + ERROR, vkResetFences (_dev_id, 1, &fence), + XCAM_RETURN_ERROR_VULKAN, "VKDevice reset fence failed."); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKDevice::wait_for_fence (VkFence fence, uint64_t timeout) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence)); + + VkResult ret = vkWaitForFences (_dev_id, 1, &fence, VK_TRUE, timeout); + if (ret == VK_TIMEOUT) { + XCAM_LOG_DEBUG ("VKDevice wait for fence timeout"); + return XCAM_RETURN_ERROR_TIMEOUT; + } + + XCAM_FAIL_RETURN ( + ERROR, ret == VK_SUCCESS, + XCAM_RETURN_ERROR_VULKAN, "VKDevice wait for fence failed."); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKDevice::compute_queue_submit (const SmartPtr<VKCmdBuf> cmd_buf, const SmartPtr<VKFence> fence) +{ + XCAM_FAIL_RETURN ( + ERROR, cmd_buf.ptr (), + XCAM_RETURN_ERROR_PARAM, "VKDevice compute queue submit failed, cmd_buf is empty."); + + VkCommandBuffer buf_id = cmd_buf->get_cmd_buf_id (); + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &buf_id; + + VkFence fence_id = VK_NULL_HANDLE; + if (fence.ptr ()) + fence_id = fence->get_fence_id (); + XCAM_VK_CHECK_RETURN ( + ERROR, vkQueueSubmit (_compute_queue, 1, &submit_info, fence_id), + XCAM_RETURN_ERROR_VULKAN, "VKDevice compute queue submit failed."); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKDevice::compute_queue_wait_idle () +{ + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (_compute_queue), + XCAM_RETURN_ERROR_PARAM, "VKDevice compute queue wait idle failed, queue_id is null"); + + XCAM_VK_CHECK_RETURN ( + ERROR, vkQueueWaitIdle (_compute_queue), + XCAM_RETURN_ERROR_VULKAN, "VKDevice compute queue wait idle failed"); + + return XCAM_RETURN_NO_ERROR; +} + +} diff --git a/modules/vulkan/vk_device.h b/modules/vulkan/vk_device.h new file mode 100644 index 0000000..27a07a1 --- /dev/null +++ b/modules/vulkan/vk_device.h @@ -0,0 +1,120 @@ +/* + * vk_device.h - vulkan device + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_DEVICE_H +#define XCAM_VK_DEVICE_H + +#include <vulkan/vulkan_std.h> +#include <xcam_mutex.h> + +namespace XCam { + +class VKPipeline; +class VKShader; +class VKFence; +class VKCmdBuf; +class VKInstance; +class VKMemory; +class VKBuffer; + +namespace VKDescriptor { +class Pool; +class Set; +}; + +class VKDevice + : public RefObj +{ + friend class VKFence; + friend class VKShader; + friend class VKPipeline; + friend class VKCmdBuf; + friend class VKDescriptor::Pool; + friend class VKDescriptor::Set; + friend class VKMemory; + friend class VKBuffer; +public: + ~VKDevice (); + static SmartPtr<VKDevice> default_device (); + static SmartPtr<VKDevice> create_device (); + + VkDevice get_dev_id () const { + return _dev_id; + } + SmartPtr<VkAllocationCallbacks> + get_allocation_cb () const { + return _allocator; + } + + SmartPtr<VKShader> create_shader (const char *file_name); + SmartPtr<VKShader> create_shader (const std::vector<uint32_t> &binary); + //SmartPtr<VKPipeline> create_pipeline (const SmartPtr<VKShader> shader); + SmartPtr<VKFence> create_fence (VkFenceCreateFlags flags = VK_FENCE_CREATE_SIGNALED_BIT); + XCamReturn compute_queue_submit (const SmartPtr<VKCmdBuf> cmd_buf, const SmartPtr<VKFence> fence); + XCamReturn compute_queue_wait_idle (); + +protected: + void destroy_shader_id (VkShaderModule shader); + VkDeviceMemory allocate_mem_id (VkDeviceSize size, VkMemoryPropertyFlags memory_prop); + void free_mem_id (VkDeviceMemory mem); + XCamReturn map_mem (VkDeviceMemory mem, VkDeviceSize size, VkDeviceSize offset, void *&ptr); + void unmap_mem (VkDeviceMemory mem); + VkBuffer create_buf_id (VkBufferUsageFlags usage, uint32_t size); + void destroy_buf_id (VkBuffer buf); + XCamReturn bind_buffer (VkBuffer buf, VkDeviceMemory mem, VkDeviceSize offset = 0); + + VkDescriptorPool create_desc_pool (const VkDescriptorPoolCreateInfo &info); + void destroy_desc_pool (VkDescriptorPool pool); + + VkDescriptorSet allocate_desc_set (const VkDescriptorSetAllocateInfo &info); + XCamReturn free_desc_set (VkDescriptorSet set, VkDescriptorPool pool); + + XCamReturn update_desc_set (const std::vector<VkWriteDescriptorSet> &sets); + VkCommandPool create_cmd_pool (VkFlags queue_flag = VK_QUEUE_COMPUTE_BIT); + void destroy_cmd_pool (VkCommandPool pool); + + VkCommandBuffer allocate_cmd_buffer (VkCommandPool pool); + void free_cmd_buffer (VkCommandPool pool, VkCommandBuffer buf); + + void destroy_fence (VkFence fence); + XCamReturn reset_fence (VkFence fence); + XCamReturn wait_for_fence (VkFence fence, uint64_t timeout); + +protected: + explicit VKDevice (VkDevice id, const SmartPtr<VKInstance> &instance); + XCamReturn prepare_compute_queue (); + //SmartPtr<VKLayout> create_desc_set_layout (); + +private: + XCAM_DEAD_COPY (VKDevice); + +private: + static SmartPtr<VKDevice> _default_dev; + static Mutex _default_mutex; + + VkDevice _dev_id; + VkQueue _compute_queue; + SmartPtr<VkAllocationCallbacks> _allocator; + SmartPtr<VKInstance> _instance; +}; + +} + +#endif //XCAM_VK_DEVICE_H diff --git a/modules/vulkan/vk_geomap_handler.cpp b/modules/vulkan/vk_geomap_handler.cpp new file mode 100644 index 0000000..4b65a44 --- /dev/null +++ b/modules/vulkan/vk_geomap_handler.cpp @@ -0,0 +1,314 @@ +/* + * vk_geomap_handler.cpp - vulkan geometry map handler 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 "vk_geomap_handler.h" +#include "vk_video_buf_allocator.h" +#include "vk_device.h" + +#define GEOMAP_SHADER_BINDING_COUNT 5 + +#define XCAM_VK_GEOMAP_ALIGN_X 4 +#define XCAM_VK_GEOMAP_ALIGN_Y 2 + +namespace XCam { + +namespace { + +DECLARE_WORK_CALLBACK (CbGeoMapShader, VKGeoMapHandler, geomap_done); + +class GeoMapArgs + : public VKWorker::VKArguments +{ +public: + explicit GeoMapArgs (const SmartPtr<ImageHandler::Parameters> ¶m) + : _param (param) + { + XCAM_ASSERT (param.ptr ()); + } + const SmartPtr<ImageHandler::Parameters> &get_param () const { + return _param; + } + +private: + SmartPtr<ImageHandler::Parameters> _param; +}; + +class VKGeoMapPushConst + : public VKConstRange::VKPushConstArg +{ +public: + VKGeoMapPushConst (const VKGeoMapHandler::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; + } + +private: + VKGeoMapHandler::PushConstsProp _prop; +}; + +static const VKShaderInfo geomap_shader_info ( + "main", +std::vector<uint32_t> { +#include "shader_geomap.comp.spv" +}); + +} + +VKGeoMapHandler::PushConstsProp::PushConstsProp () + : in_img_width (0) + , in_img_height (0) + , out_img_width (0) + , out_img_height (0) + , lut_width (0) + , lut_height (0) +{ + xcam_mem_clear (lut_step); + xcam_mem_clear (lut_std_step); +} + +VKGeoMapHandler::VKGeoMapHandler (const SmartPtr<VKDevice> &dev, const char* name) + : VKHandler (dev, name) +{ +} + +bool +VKGeoMapHandler::set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height) +{ + XCAM_FAIL_RETURN ( + ERROR, data && width && height, false, + "VKGeoMapHandler(%s) set look up table failed, data ptr:%p, width:%d, height:%d", + XCAM_STR (get_name ()), data, width, height); + XCAM_ASSERT (!_lut_buf.ptr ()); + + _lut_width = width; + _lut_height = height; + + uint32_t lut_size = width * height * 2 * sizeof (float); + SmartPtr<VKBuffer> buf = VKBuffer::create_buffer ( + get_vk_device (), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, lut_size); + XCAM_ASSERT (buf.ptr ()); + + float *ptr = (float *) buf->map (lut_size, 0); + XCAM_FAIL_RETURN (ERROR, ptr, false, "VKGeoMapHandler(%s) map range failed", XCAM_STR (get_name ())); + for (uint32_t i = 0; i < height; ++i) { + float *ret = &ptr[i * width * 2]; + const PointFloat2 *line = &data[i * width]; + + for (uint32_t j = 0; j < width; ++j) { + ret[j * 2] = line[j].x; + ret[j * 2 + 1] = line[j].y; + } + } + buf->unmap (); + _lut_buf = buf; + + return true; +} + +bool +VKGeoMapHandler::init_factors () +{ + XCAM_ASSERT (_lut_width && _lut_height); + + float factor_x, factor_y; + get_factors (factor_x, factor_y); + + if (!XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f)) + return true; + + return auto_calculate_factors (_lut_width, _lut_height); +} + +#define UNIT_BYTES (sizeof (uint32_t)) + +XCamReturn +VKGeoMapHandler::configure_resource (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCAM_ASSERT (param.ptr () && param->in_buf.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, _lut_buf.ptr (), XCAM_RETURN_ERROR_PARAM, + "VKGeoMapHandler(%s) configure resource failed, look up table is empty", XCAM_STR (get_name ())); + + const VideoBufferInfo &in_info = param->in_buf->get_video_info (); + XCAM_FAIL_RETURN ( + ERROR, in_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "VKGeoMapHandler(%s) only support NV12 format, but input format is %s", + XCAM_STR (get_name ()), xcam_fourcc_to_string (in_info.format)); + + uint32_t out_width, out_height; + get_output_size (out_width, out_height); + VideoBufferInfo out_info; + out_info.init ( + in_info.format, out_width, out_height, + XCAM_ALIGN_UP (out_width, XCAM_VK_GEOMAP_ALIGN_X), + XCAM_ALIGN_UP (out_height, XCAM_VK_GEOMAP_ALIGN_Y)); + set_out_video_info (out_info); + + init_factors (); + + float factor_x, factor_y; + get_factors (factor_x, factor_y); + XCAM_FAIL_RETURN ( + ERROR, + !XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && + !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f), + XCAM_RETURN_ERROR_PARAM, + "VKGeoMapHandler(%s) invalid standard factors: x:%f, y:%f", + XCAM_STR (get_name ()), factor_x, factor_y); + + _image_prop.in_img_width = in_info.aligned_width / UNIT_BYTES; + _image_prop.in_img_height = in_info.aligned_height; + _image_prop.out_img_width = out_info.aligned_width / UNIT_BYTES; + _image_prop.out_img_height = out_info.aligned_height; + _image_prop.lut_width = _lut_width; + _image_prop.lut_height = _lut_height; + _image_prop.lut_std_step[0] = 1.0f / factor_x; + _image_prop.lut_std_step[1] = 1.0f / factor_y; + + WorkSize global_size ( + XCAM_ALIGN_UP (_image_prop.out_img_width, 8) / 8, + XCAM_ALIGN_UP (_image_prop.out_img_height, 16) / 16); + + _binding_layout.clear (); + for (int i = 0; i < GEOMAP_SHADER_BINDING_COUNT; ++i) { + SmartPtr<VKDescriptor::SetLayoutBinding> binding = + new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i); + _binding_layout.push_back (binding); + } + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!_worker.ptr ()) { + _worker = new VKWorker (get_vk_device(), "CbGeoMapShader", new CbGeoMapShader (this)); + XCAM_ASSERT (_worker.ptr ()); + + _worker->set_global_size (global_size); + + VKConstRange::VKPushConstArgs push_consts; + push_consts.push_back (new VKGeoMapPushConst (_image_prop)); + ret = _worker->build (geomap_shader_info, _binding_layout, push_consts); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_VULKAN, + "VKGeoMapHandler(%s) build geomap shader failed.", XCAM_STR (get_name ())); + } + + return ret; +} + +XCamReturn +VKGeoMapHandler::start_work (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCAM_ASSERT (_lut_buf.ptr ()); + XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ()); + XCAM_ASSERT (_binding_layout.size () == GEOMAP_SHADER_BINDING_COUNT); + + SmartPtr<VKVideoBuffer> in_vk = param->in_buf.dynamic_cast_ptr<VKVideoBuffer> (); + SmartPtr<VKVideoBuffer> out_vk = param->out_buf.dynamic_cast_ptr<VKVideoBuffer> (); + XCAM_FAIL_RETURN ( + ERROR, in_vk.ptr () && out_vk.ptr(), XCAM_RETURN_ERROR_VULKAN, + "VKGeoMapHandler(%s) param.in_buf or param.out_buf is not vk buffer", XCAM_STR (get_name ())); + + VKDescriptor::SetBindInfoArray bindings (_binding_layout.size ()); + bindings[0].layout = _binding_layout[0]; + bindings[0].desc = VKBufDesc (in_vk->get_vk_buf (), NV12PlaneYIdx); + bindings[1].layout = _binding_layout[1]; + bindings[1].desc = VKBufDesc (in_vk->get_vk_buf (), NV12PlaneUVIdx); + bindings[2].layout = _binding_layout[2]; + bindings[2].desc = VKBufDesc (out_vk->get_vk_buf (), NV12PlaneYIdx); + bindings[3].layout = _binding_layout[3]; + bindings[3].desc = VKBufDesc (out_vk->get_vk_buf (), NV12PlaneUVIdx); + bindings[4].layout = _binding_layout[4]; + bindings[4].desc = VKBufDesc (_lut_buf); + + float factor_x, factor_y; + get_factors (factor_x, factor_y); + _image_prop.lut_step[0] = 1.0f / factor_x; + _image_prop.lut_step[1] = 1.0f / factor_y; + _image_prop.lut_step[2] = _image_prop.lut_step[0]; + _image_prop.lut_step[3] = _image_prop.lut_step[1]; + + SmartPtr<GeoMapArgs> args = new GeoMapArgs (param); + XCAM_ASSERT (args.ptr ()); + args->set_bindings (bindings); + args->add_push_const (new VKGeoMapPushConst (_image_prop)); + + return _worker->work (args); +} + +void +VKGeoMapHandler::geomap_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + if (!xcam_ret_is_ok (error)) { + XCAM_LOG_ERROR ("VKGeoMapHandler(%s) geometry map failed.", XCAM_STR (get_name ())); + } + + SmartPtr<VKWorker> vk_worker = worker.dynamic_cast_ptr<VKWorker> (); + XCAM_ASSERT (vk_worker.ptr ()); + vk_worker->wait_fence (); + + SmartPtr<GeoMapArgs> args = base.dynamic_cast_ptr<GeoMapArgs> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + XCAM_ASSERT (param.ptr ()); + + execute_done (param, error); +} + +XCamReturn +VKGeoMapHandler::remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf) +{ + SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf); + XCAM_ASSERT (param.ptr ()); + + XCamReturn ret = execute_buffer (param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "VKGeoMapHandler(%s) remap failed", XCAM_STR (get_name ())); + + if (!out_buf.ptr ()) { + out_buf = param->out_buf; + } + + return ret; +} + +SmartPtr<VKHandler> create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name) +{ + SmartPtr<VKHandler> mapper = new VKGeoMapHandler (dev, name); + XCAM_ASSERT (mapper.ptr ()); + + return mapper; +} + +SmartPtr<GeoMapper> +GeoMapper::create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name) +{ + SmartPtr<VKHandler> handler = XCam::create_vk_geo_mapper (dev, name); + return handler.dynamic_cast_ptr<GeoMapper> (); +} + +}; diff --git a/modules/vulkan/vk_geomap_handler.h b/modules/vulkan/vk_geomap_handler.h new file mode 100644 index 0000000..bf8d4d3 --- /dev/null +++ b/modules/vulkan/vk_geomap_handler.h @@ -0,0 +1,78 @@ +/* + * vk_geomap_handler.h - vulkan geometry map handler class + * + * 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> + */ + +#ifndef XCAM_VK_GEOMAP_HANDLER_H +#define XCAM_VK_GEOMAP_HANDLER_H + +#include <xcam_utils.h> +#include <interface/geo_mapper.h> +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_worker.h> +#include <vulkan/vk_handler.h> + +namespace XCam { + +class VKGeoMapHandler + : public VKHandler, public GeoMapper +{ +public: + struct PushConstsProp { + uint in_img_width; + uint in_img_height; + uint out_img_width; + uint out_img_height; + uint lut_width; + uint lut_height; + float lut_step[4]; + float lut_std_step[2]; + + PushConstsProp (); + }; + +public: + explicit VKGeoMapHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-geomap-handler"); + + bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height); + + XCamReturn remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf); + void geomap_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + +private: + virtual XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + virtual XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + virtual bool init_factors (); + +private: + SmartPtr<VKWorker> _worker; + PushConstsProp _image_prop; + VKDescriptor::BindingArray _binding_layout; + + SmartPtr<VKBuffer> _lut_buf; + uint32_t _lut_width; + uint32_t _lut_height; +}; + +extern SmartPtr<VKHandler> create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name); + +} +#endif // XCAM_VK_GEOMAP_HANDLER_H diff --git a/modules/vulkan/vk_handler.cpp b/modules/vulkan/vk_handler.cpp new file mode 100644 index 0000000..6aa1a83 --- /dev/null +++ b/modules/vulkan/vk_handler.cpp @@ -0,0 +1,60 @@ +/* + * vk_handler.cpp - vulkan image handler class + * + * Copyright (c) 2017 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 "vk_handler.h" +#include "vk_device.h" +#include "vk_video_buf_allocator.h" + +namespace XCam { + +VKHandler::VKHandler (const SmartPtr<VKDevice> &dev, const char* name) + : ImageHandler (name) + , _device (dev) +{ +} + +VKHandler::~VKHandler () +{ +} + + +XCamReturn +VKHandler::finish () +{ + if (_device.ptr ()) + _device->compute_queue_wait_idle (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKHandler::terminate () +{ + finish (); + return ImageHandler::terminate (); +} + +SmartPtr<BufferPool> +VKHandler::create_allocator () +{ + return new VKVideoBufAllocator (_device); +} + +} diff --git a/modules/vulkan/vk_handler.h b/modules/vulkan/vk_handler.h new file mode 100644 index 0000000..3d80fa0 --- /dev/null +++ b/modules/vulkan/vk_handler.h @@ -0,0 +1,57 @@ +/* + * vk_handler.h - vulkan image handler class + * + * Copyright (c) 2017 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> + */ + +#ifndef XCAM_VK_HANDLER_H +#define XCAM_VK_HANDLER_H + +#include <vulkan/vulkan_std.h> +#include <image_handler.h> + +namespace XCam { + +class VKDevice; + +class VKHandler + : public ImageHandler +{ +public: + explicit VKHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-handler"); + ~VKHandler (); + const SmartPtr<VKDevice> &get_vk_device () const { + return _device; + } + + // derive from ImageHandler + virtual XCamReturn finish (); + virtual XCamReturn terminate (); + +protected: + SmartPtr<BufferPool> create_allocator (); + +private: + XCAM_DEAD_COPY (VKHandler); + +protected: + SmartPtr<VKDevice> _device; +}; + +} + +#endif //XCAM_VK_HANDLER_H diff --git a/modules/vulkan/vk_instance.cpp b/modules/vulkan/vk_instance.cpp new file mode 100644 index 0000000..81b3e6d --- /dev/null +++ b/modules/vulkan/vk_instance.cpp @@ -0,0 +1,230 @@ +/* + * vk_instance.cpp - vulkan instance + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_instance.h" +#include "vulkan_common.h" + +#define APP_NAME "xcam" +#define ENGINE_NAME "xcam" + +#define XCAM_INVALID_VK_QUEUE_IDX UINT32_MAX + +namespace XCam { + +extern void vk_init_error_string (); + +SmartPtr<VKInstance> VKInstance::_instance; +Mutex VKInstance::_instance_mutex; + +VKInstance::~VKInstance () +{ + if (XCAM_IS_VALID_VK_ID (_instance_id)) + vkDestroyInstance (_instance_id, _allocator.ptr ()); +} + +VKInstance::VKInstance (VkInstance id, VkAllocationCallbacks *allocator) + : _instance_id (id) + , _allocator (allocator) + , _physical_device (NULL) + , _compute_queue_family_idx (XCAM_INVALID_VK_QUEUE_IDX) + , _graphics_queue_family_idx (XCAM_INVALID_VK_QUEUE_IDX) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id)); + xcam_mem_clear (_device_properties); + xcam_mem_clear (_dev_mem_properties); +} + +SmartPtr<VKInstance> +VKInstance::get_instance () +{ + SmartLock locker (_instance_mutex); + if (!_instance.ptr ()) { + vk_init_error_string (); + _instance = create_instance (); + } + return _instance; +} + +SmartPtr<VKInstance> +VKInstance::create_instance () +{ + VkApplicationInfo app_info = {}; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pApplicationName = APP_NAME; + app_info.applicationVersion = 0; + app_info.pEngineName = ENGINE_NAME; + app_info.engineVersion = xcam_version (); + app_info.apiVersion = VK_API_VERSION_1_0; + + VkInstance id; + VkInstanceCreateInfo inst_create_info = {}; + inst_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + inst_create_info.pApplicationInfo = &app_info; + inst_create_info.enabledExtensionCount = 0; // TODO, add extensions + XCAM_VK_CHECK_RETURN( + ERROR, vkCreateInstance (&inst_create_info, NULL, &id), + NULL, "create vk instance failed"); + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id)); + SmartPtr<VKInstance> vk_instance = new VKInstance (id, NULL); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (vk_instance->query_physical_info ()), NULL, + "vk instance query physical info failed"); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (vk_instance->query_queue_info ()), NULL, + "vk instance query queue info failed"); + + return vk_instance; +} + +static const char *s_device_types[] = { + "OTHER_DEVICE", + "INTEGRATED_GPU", + "DISCRETE_GPU", + "VIRTUAL_GPU", + "CPU_TYPE", +}; + +static const char* +device_type_to_str(VkPhysicalDeviceType type) +{ + size_t number = sizeof (s_device_types) / sizeof (s_device_types[0]); + assert (number == 5); + if ((size_t)type < number) + return s_device_types [type]; + return "UNKNOWN_TYPE"; +} + +XCamReturn +VKInstance::query_physical_info () +{ +#define MAX_DEV_NUM 256 + VkPhysicalDevice devs[MAX_DEV_NUM]; + uint32_t dev_num = 0; + XCAM_VK_CHECK_RETURN ( + ERROR, vkEnumeratePhysicalDevices (_instance_id, &dev_num, NULL), + XCAM_RETURN_ERROR_VULKAN, "enum vk physical devices failed"); + XCAM_FAIL_RETURN ( + ERROR, dev_num, XCAM_RETURN_ERROR_VULKAN, + "There is NO vk physical devices"); + + dev_num = XCAM_MIN (dev_num, MAX_DEV_NUM); + vkEnumeratePhysicalDevices (_instance_id, &dev_num, devs); + + VkPhysicalDevice gpu_dev[VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE] = {}; + + VkPhysicalDeviceProperties dev_prop; + for (uint32_t i = 0; i < dev_num; ++i) { + vkGetPhysicalDeviceProperties (devs[i], &dev_prop); + + if (dev_prop.deviceType < VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE || + dev_prop.deviceType > VK_PHYSICAL_DEVICE_TYPE_END_RANGE) { + continue; + } + if (gpu_dev[dev_prop.deviceType]) { + XCAM_LOG_WARNING ( + "double vk physical dev, type:%d, name:%s", + dev_prop.deviceType, dev_prop.deviceName); + continue; + } + gpu_dev[dev_prop.deviceType] = devs[i]; +#if 0 + printf ("found vk physical dev_id:%d, name:%s, type:%d, API:%d\n", + dev_prop.deviceID, dev_prop.deviceName, + device_type_to_str (dev_prop.deviceType), dev_prop.apiVersion); +#endif + } + + if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU]) + _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU]; + else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]) + _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]; + else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU]) + _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU]; + else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_CPU]) { + _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_CPU]; + XCAM_LOG_WARNING ("vk device select physical CPU, performance may slow down"); + } else { + XCAM_LOG_ERROR ("did NOT find available vk physical device"); + return XCAM_RETURN_ERROR_VULKAN; + } + + vkGetPhysicalDeviceProperties (_physical_device, &dev_prop); + XCAM_LOG_INFO ("choose vk physical dev properties dev_id:%d, name:%s, type:%s, API:%d\n", + dev_prop.deviceID, dev_prop.deviceName, + device_type_to_str (dev_prop.deviceType), dev_prop.apiVersion); + _device_properties = dev_prop; + vkGetPhysicalDeviceMemoryProperties (_physical_device, &_dev_mem_properties); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKInstance::query_queue_info () +{ + XCAM_ASSERT (_physical_device); + // get queue family porperties + uint32_t queue_count = 0; +#define MAX_QUEUE_FAMILY_NUM 256 + VkQueueFamilyProperties queue_family[MAX_QUEUE_FAMILY_NUM]; + + vkGetPhysicalDeviceQueueFamilyProperties ( + _physical_device, &queue_count, NULL); + XCAM_FAIL_RETURN ( + ERROR, queue_count, XCAM_RETURN_ERROR_VULKAN, + "There is NO vk physical devices"); + + if (queue_count > MAX_QUEUE_FAMILY_NUM) + queue_count = MAX_QUEUE_FAMILY_NUM; + + vkGetPhysicalDeviceQueueFamilyProperties ( + _physical_device, &queue_count, queue_family); + + for (uint32_t i = 0; i < queue_count; ++i) { + if (queue_family[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + _compute_queue_family_idx = i; + } + if (queue_family[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + _graphics_queue_family_idx = i; + } + } + + XCAM_FAIL_RETURN ( + ERROR, + _compute_queue_family_idx != XCAM_INVALID_VK_QUEUE_IDX && + _graphics_queue_family_idx != XCAM_INVALID_VK_QUEUE_IDX, + XCAM_RETURN_ERROR_VULKAN, + "There is NO vk compute/graphics queue family"); + + return XCAM_RETURN_NO_ERROR; +} + +uint32_t +VKInstance::get_mem_type_index (VkMemoryPropertyFlags prop) const +{ + for (uint32_t i = 0; i < _dev_mem_properties.memoryTypeCount; ++i) { + if (((uint32_t)(_dev_mem_properties.memoryTypes[i].propertyFlags) & prop) == prop) + return i; + } + return (uint32_t)(-1); +} + +} diff --git a/modules/vulkan/vk_instance.h b/modules/vulkan/vk_instance.h new file mode 100644 index 0000000..b4b51d4 --- /dev/null +++ b/modules/vulkan/vk_instance.h @@ -0,0 +1,77 @@ +/* + * vk_instance.h - vulkan instance + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_INSTANCE_H +#define XCAM_VK_INSTANCE_H + +#include <vulkan/vulkan_std.h> +#include <xcam_mutex.h> + +namespace XCam { + +class VKInstance +{ +public: + ~VKInstance (); + static SmartPtr<VKInstance> get_instance (); + + VkInstance get_id () const { + return _instance_id; + } + VkPhysicalDevice get_physical_dev () const { + return _physical_device; + } + uint32_t get_compute_queue_family_idx () const { + return _compute_queue_family_idx; + } + uint32_t get_graphics_queue_family_idx () const { + return _graphics_queue_family_idx; + } + uint32_t get_mem_type_index (VkMemoryPropertyFlags prop) const; + + SmartPtr<VkAllocationCallbacks> get_allocator () const { + return _allocator; + } + +private: + explicit VKInstance (VkInstance id, VkAllocationCallbacks *allocator); + static SmartPtr<VKInstance> create_instance (); + XCamReturn query_physical_info (); + XCamReturn query_queue_info (); + +private: + XCAM_DEAD_COPY (VKInstance); + +private: + static SmartPtr<VKInstance> _instance; + static Mutex _instance_mutex; + + VkInstance _instance_id; + SmartPtr<VkAllocationCallbacks> _allocator; + VkPhysicalDevice _physical_device; + VkPhysicalDeviceProperties _device_properties; + VkPhysicalDeviceMemoryProperties _dev_mem_properties; + uint32_t _compute_queue_family_idx; + uint32_t _graphics_queue_family_idx; +}; + +} + +#endif //XCAM_VK_INSTANCE_H diff --git a/modules/vulkan/vk_memory.cpp b/modules/vulkan/vk_memory.cpp new file mode 100644 index 0000000..09af690 --- /dev/null +++ b/modules/vulkan/vk_memory.cpp @@ -0,0 +1,182 @@ +/* + * vk_memory.cpp - Vulkan memory + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_memory.h" +#include "vk_device.h" + +namespace XCam { + +VKBufInfo::VKBufInfo () + : format (V4L2_PIX_FMT_NV12) + , width (0) + , height (0) + , aligned_width (0) + , aligned_height (0) + , size (0) +{ + xcam_mem_clear (strides); + xcam_mem_clear (offsets); + xcam_mem_clear (slice_size); +} + +VKMemory::VKMemory ( + const SmartPtr<VKDevice> dev, + VkDeviceMemory id, + uint32_t size, + VkMemoryPropertyFlags mem_prop) + : _dev (dev) + , _mem_id (id) + , _mem_prop (mem_prop) + , _size (size) + , _mapped_ptr (NULL) +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id)); +} + +VKMemory::~VKMemory () +{ + if (XCAM_IS_VALID_VK_ID (_mem_id) && _dev.ptr ()) { + _dev->free_mem_id (_mem_id); + } +} + +void * +VKMemory::map (VkDeviceSize size, VkDeviceSize offset) +{ + if (_mapped_ptr) + return _mapped_ptr; + + XCAM_FAIL_RETURN ( + ERROR, + xcam_ret_is_ok (_dev->map_mem (_mem_id, size, offset, _mapped_ptr)), NULL, + "VK memory map failed"); + + return _mapped_ptr; +} + +void +VKMemory::unmap () +{ + if (_mapped_ptr) { + _dev->unmap_mem (_mem_id); + _mapped_ptr = NULL; + } +} + +VKBuffer::VKBuffer ( + const SmartPtr<VKDevice> dev, + VkBuffer buf_id, + VkDeviceMemory mem_id, + uint32_t size, + VkBufferUsageFlags usage, + VkMemoryPropertyFlags prop) + : VKMemory (dev, mem_id, size, prop) + , _buffer_id (buf_id) + , _usage_flags (usage) + , _prop_flags (prop) +{ +} + +VKBuffer::~VKBuffer () +{ + if (XCAM_IS_VALID_VK_ID (_buffer_id) && _dev.ptr ()) { + _dev->destroy_buf_id (_buffer_id); + } +} + +XCamReturn +VKBuffer::bind () +{ + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_buffer_id)); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_mem_id)); + + return _dev->bind_buffer (_buffer_id, _mem_id, 0); +} + +SmartPtr<VKBuffer> +VKBuffer::create_buffer ( + const SmartPtr<VKDevice> dev, + VkBufferUsageFlags usage, + uint32_t size, void *data, + VkMemoryPropertyFlags mem_prop) +{ + XCAM_FAIL_RETURN ( + ERROR, dev.ptr () && size, NULL, + "vk create buffer failed because of dev or size errors"); + + VkBuffer buf_id = dev->create_buf_id (usage, size); + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (buf_id), NULL, + "vk create buffer failed"); + + VkDevice dev_id = dev->get_dev_id (); + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements (dev_id, buf_id, &mem_reqs); + VkDeviceMemory mem_id = dev->allocate_mem_id (mem_reqs.size, mem_prop); + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (mem_id), NULL, + "vk create buffer failed in mem allocation"); + + // size == mem_reqs.size or size? + SmartPtr<VKBuffer> buf = new VKBuffer (dev, buf_id, mem_id, size, usage, mem_prop); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (buf->bind ()), NULL, + "vk create bufer failed when bind with memory"); + if (!data) + return buf; + + void *ptr = buf->map (); + XCAM_FAIL_RETURN ( + ERROR, ptr, NULL, + "vk create bufer failed when map the buf"); + memcpy (ptr, data, size); + buf->unmap (); + + return buf; + +} + +VKBufDesc::VKBufDesc () +{ + xcam_mem_clear (desc_info); +} + +VKBufDesc::VKBufDesc (const SmartPtr<VKBuffer> &buffer, NV12PlaneIdx plane) + : buf (buffer) +{ + xcam_mem_clear (desc_info); + const VKBufInfo info = buffer->get_buf_info (); + + desc_info.buffer = buffer->get_buf_id (); + desc_info.offset = info.offsets[plane]; + desc_info.range = info.slice_size[plane]; +} + +VKBufDesc::VKBufDesc (const SmartPtr<VKBuffer> &buffer, uint32_t offset, size_t size) + : buf (buffer) +{ + xcam_mem_clear (desc_info); + desc_info.buffer = buffer->get_buf_id (); + desc_info.offset = offset; + desc_info.range = size; +} + +} diff --git a/modules/vulkan/vk_memory.h b/modules/vulkan/vk_memory.h new file mode 100644 index 0000000..3eba942 --- /dev/null +++ b/modules/vulkan/vk_memory.h @@ -0,0 +1,134 @@ +/* + * vk_memory.h - Vulkan memory + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_MEMORY_H +#define XCAM_VK_MEMORY_H + +#include <vulkan/vulkan_std.h> + +#define XCAM_VK_MAX_COMPONENTS 4 + +namespace XCam { + +struct VKBufInfo { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t aligned_width; + uint32_t aligned_height; + uint32_t size; + uint32_t strides[XCAM_VK_MAX_COMPONENTS]; + uint32_t offsets[XCAM_VK_MAX_COMPONENTS]; + uint32_t slice_size[XCAM_VK_MAX_COMPONENTS]; + + VKBufInfo (); + bool operator == (const VKBufInfo &info) const; +}; + +class VKDevice; + +class VKMemory +{ +public: + virtual ~VKMemory (); + void *map (VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); + void unmap (); + +protected: + explicit VKMemory ( + const SmartPtr<VKDevice> dev, VkDeviceMemory id, + uint32_t size, VkMemoryPropertyFlags mem_prop); + VkDeviceMemory get_mem_id () const { + return _mem_id; + } + +private: + XCAM_DEAD_COPY (VKMemory); + +protected: + const SmartPtr<VKDevice> _dev; + VkDeviceMemory _mem_id; + VkMemoryPropertyFlags _mem_prop; + uint32_t _size; + void *_mapped_ptr; +}; + +class VKBuffer + : public VKMemory +{ +public: + ~VKBuffer (); + + // usage can be VK_BUFFER_USAGE_STORAGE_BUFFER_BIT or VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + static SmartPtr<VKBuffer> + create_buffer ( + const SmartPtr<VKDevice> dev, + VkBufferUsageFlags usage, + uint32_t size, void *data = NULL, + VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + VkBuffer get_buf_id () const { + return _buffer_id; + } + VkBufferUsageFlags get_usage_flags () const { + return _usage_flags; + } + VkMemoryPropertyFlags get_mem_flags () const { + return _prop_flags; + } + + void set_buf_info (const VKBufInfo &info) { + _buf_info = info; + } + const VKBufInfo &get_buf_info () const { + return _buf_info; + } + +private: + explicit VKBuffer ( + const SmartPtr<VKDevice> dev, VkBuffer buf_id, + VkDeviceMemory mem_id, uint32_t size, + VkBufferUsageFlags usage, VkMemoryPropertyFlags prop); + XCamReturn bind (); + +private: + XCAM_DEAD_COPY (VKBuffer); + +private: + VkBuffer _buffer_id; + VkBufferUsageFlags _usage_flags; + VkMemoryPropertyFlags _prop_flags; + VKBufInfo _buf_info; +}; + +struct VKBufDesc { + SmartPtr<VKBuffer> buf; + VkDescriptorBufferInfo desc_info; + + VKBufDesc (); + VKBufDesc (const SmartPtr<VKBuffer> &buffer, NV12PlaneIdx plane); + VKBufDesc (const SmartPtr<VKBuffer> &buffer, uint32_t offset = 0, size_t size = VK_WHOLE_SIZE); +}; + +typedef std::vector<SmartPtr<VKBuffer>> VKBufferArray; + +} + +#endif //XCAM_VK_MEMORY_H diff --git a/modules/vulkan/vk_pipeline.cpp b/modules/vulkan/vk_pipeline.cpp new file mode 100644 index 0000000..5483582 --- /dev/null +++ b/modules/vulkan/vk_pipeline.cpp @@ -0,0 +1,293 @@ +/* + * vk_pipeline.cpp - Vulkan pipeline + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_pipeline.h" +#include "vulkan_common.h" +#include "vk_cmdbuf.h" + +namespace XCam { + +VKPipeline::VKPipeline ( + const SmartPtr<VKDevice> dev, + const ShaderVec &shaders, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts) + : _pipe_id (VK_NULL_HANDLE) + , _dev (dev) + , _shaders (shaders) + , _bindings (bindings) + , _push_consts (consts) +{ + _allocator = _dev->get_allocation_cb (); + xcam_mem_clear (_name); +} + +VKPipeline::~VKPipeline () +{ + if (!_dev.ptr ()) + return; + + VkDevice dev_id = _dev->get_dev_id (); + if (XCAM_IS_VALID_VK_ID (_pipe_id)) + vkDestroyPipeline (dev_id, _pipe_id, _allocator.ptr ()); +} + +void +VKPipeline::set_desc_pool (const SmartPtr<VKDescriptor::Pool> pool) +{ + _pool = pool; + + //TODO, check pool status and allocate set, need or not? +} + +VkDescriptorSetLayout +VKPipeline::create_desc_set_layout ( + const VKDescriptor::BindingArray &bindings) +{ + VKDescriptor::VkBindingArray array = VKDescriptor::get_vk_layoutbindings (bindings); + + VkDescriptorSetLayoutCreateInfo descriptor_layout = {}; + descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptor_layout.bindingCount = array.size (); + descriptor_layout.pBindings = array.data (); + + VkDescriptorSetLayout layout = NULL; + XCAM_VK_CHECK_RETURN ( + ERROR, + vkCreateDescriptorSetLayout ( + _dev->get_dev_id (), &descriptor_layout, _allocator.ptr (), &layout), + NULL, "VkPipeline create descriptor set layout failed"); + + return layout; +} + + +VkPipelineLayout +VKPipeline::create_pipeline_layout ( + VkDescriptorSetLayout desc_layout, + const VKConstRange::VKConstantArray &consts) +{ + VkPipelineLayoutCreateInfo pipe_layout_create_info = {}; + pipe_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipe_layout_create_info.flags = 0; + pipe_layout_create_info.setLayoutCount = 1; + pipe_layout_create_info.pSetLayouts = &desc_layout; + if (!consts.empty()) { + pipe_layout_create_info.pushConstantRangeCount = consts.size (); + pipe_layout_create_info.pPushConstantRanges = consts.data (); + } + + VkPipelineLayout layout = NULL; + XCAM_VK_CHECK_RETURN ( + ERROR, + vkCreatePipelineLayout ( + _dev->get_dev_id (), &pipe_layout_create_info, NULL, &layout), + NULL, "VkPipeline create descriptor set layout failed"); + + return layout; +} + +SmartPtr<VKPipeline> +VKPipeline::create_compute_pipeline ( + const SmartPtr<VKDevice> dev, + const SmartPtr<VKShader> shader, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts) +{ + XCAM_FAIL_RETURN ( + ERROR, dev.ptr () && shader.ptr (), NULL, + "VKDevice create pipeline with error of null device ready."); + + ShaderVec shaders = {shader}; + SmartPtr<VKPipeline> pipe = new VKComputePipeline (dev, shaders, bindings, consts); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (pipe->ensure_layouts ()), NULL, + "vk pipeline ensure layouts failed"); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (pipe->ensure_pipeline ()), NULL, + "vk pipeline ensure pipeline failed"); + + return pipe; +} + +VKComputePipeline::VKComputePipeline ( + const SmartPtr<VKDevice> dev, + const ShaderVec &shaders, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts) + : VKPipeline (dev, shaders, bindings, consts) + , _pipe_layout (VK_NULL_HANDLE) + , _desc_layout (VK_NULL_HANDLE) +{ +} + +VKComputePipeline::~VKComputePipeline () +{ + if (!_dev.ptr ()) + return; + + VkDevice dev_id = _dev->get_dev_id (); + if (XCAM_IS_VALID_VK_ID (_pipe_layout)) + vkDestroyPipelineLayout (dev_id, _pipe_layout, _allocator.ptr ()); + if (XCAM_IS_VALID_VK_ID (_desc_layout)) + vkDestroyDescriptorSetLayout (dev_id, _desc_layout, _allocator.ptr ()); +} + +XCamReturn +VKComputePipeline::ensure_layouts () +{ + if (!XCAM_IS_VALID_VK_ID (_desc_layout)) { + _desc_layout = create_desc_set_layout (_bindings); + } + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID(_desc_layout), XCAM_RETURN_ERROR_VULKAN, + "vk compute pipeline create desc layout failed"); + + if (!XCAM_IS_VALID_VK_ID (_pipe_layout)) { + _pipe_layout = create_pipeline_layout (_desc_layout, _push_consts); + } + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID(_pipe_layout), XCAM_RETURN_ERROR_VULKAN, + "vk compute pipeline create pipeline layout failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKComputePipeline::ensure_pipeline () +{ + XCAM_FAIL_RETURN ( + ERROR, XCAM_IS_VALID_VK_ID (_desc_layout) && XCAM_IS_VALID_VK_ID (_pipe_layout), + XCAM_RETURN_ERROR_PARAM, + "vk compute ensure pipeline failed. need ensure desc_layout and pipe_layout first"); + + XCAM_FAIL_RETURN ( + ERROR, !_shaders.empty (), XCAM_RETURN_ERROR_PARAM, + "vk compute ensure pipeline failed, shader was empty"); + + VkComputePipelineCreateInfo pipeline_create_info = + get_compute_create_info (_shaders[0], _pipe_layout); + + VkPipeline pipe_id; + XCAM_VK_CHECK_RETURN ( + ERROR, vkCreateComputePipelines ( + _dev->get_dev_id (), 0, 1, &pipeline_create_info, 0, &pipe_id), + XCAM_RETURN_ERROR_VULKAN, "VK create compute pipeline failed."); + + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pipe_id)); + _pipe_id = pipe_id; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKComputePipeline::update_bindings (const VKDescriptor::SetBindInfoArray &bind_array) +{ + XCAM_FAIL_RETURN ( + ERROR, _pool.ptr () && XCAM_IS_VALID_VK_ID (_desc_layout), XCAM_RETURN_ERROR_PARAM, + "vk compute pipeline update bindins failed, pool was not set or desc_layout not ensured"); + + if (_desc_set.ptr ()) + _desc_set.release (); + + _desc_set = _pool->allocate_set (bind_array, _desc_layout); + XCAM_FAIL_RETURN ( + ERROR, _desc_set.ptr (), XCAM_RETURN_ERROR_UNKNOWN, + "vk compute pipeline update bindins failed to allocate desc_set or update bindings"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKComputePipeline::bind_by (VKCmdBuf &cmd_buf) +{ + + VkCommandBuffer buf_id = cmd_buf.get_cmd_buf_id (); + VkPipeline pipe_id = get_pipeline_id (); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf_id)); + XCAM_FAIL_RETURN ( + ERROR, + XCAM_IS_VALID_VK_ID (pipe_id) && XCAM_IS_VALID_VK_ID (_pipe_layout) && _desc_set.ptr (), + XCAM_RETURN_ERROR_PARAM, + "vk compute pipeline bind command buffer failed, please check pipe_id, pipe_layout and desc_layout."); + + // // bind pipeline sets + vkCmdBindPipeline (buf_id, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_id); + + // bind descriptor sets + VkDescriptorSet desc_set_id = _desc_set->get_set_id (); + vkCmdBindDescriptorSets ( + buf_id, VK_PIPELINE_BIND_POINT_COMPUTE, _pipe_layout, + 0, 1, &desc_set_id, 0, NULL); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKComputePipeline::push_consts_by ( + VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const) +{ + VkCommandBuffer cmd_buf_id = cmd_buf.get_cmd_buf_id (); + XCAM_FAIL_RETURN ( + ERROR, + XCAM_IS_VALID_VK_ID (cmd_buf_id) && XCAM_IS_VALID_VK_ID (_pipe_layout), + XCAM_RETURN_ERROR_PARAM, + "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id."); + + XCAM_ASSERT (push_const.ptr ()); + VkPushConstantRange const_range; + xcam_mem_clear (const_range); + void *ptr = NULL; + push_const->get_const_data (const_range, ptr); + + XCAM_FAIL_RETURN ( + ERROR, + const_range.stageFlags == VK_SHADER_STAGE_COMPUTE_BIT, + XCAM_RETURN_ERROR_PARAM, + "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id."); + + vkCmdPushConstants( + cmd_buf_id, _pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, const_range.offset, const_range.size, ptr); + return XCAM_RETURN_NO_ERROR; +} + +VkComputePipelineCreateInfo +VKComputePipeline::get_compute_create_info ( + const SmartPtr<VKShader> &shader, + VkPipelineLayout &layout) +{ + VkPipelineShaderStageCreateInfo shader_stage_create_info = {}; + shader_stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stage_create_info.flags = 0; + shader_stage_create_info.stage = shader->get_shader_stage_flags (); + shader_stage_create_info.module = shader->get_shader_id (); + shader_stage_create_info.pName = shader->get_func_name (); + + VkComputePipelineCreateInfo pipeline_create_info = { }; + pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipeline_create_info.pNext = NULL; + pipeline_create_info.flags = 0; + pipeline_create_info.stage = shader_stage_create_info; + pipeline_create_info.layout = layout; + + return pipeline_create_info; +} + +} diff --git a/modules/vulkan/vk_pipeline.h b/modules/vulkan/vk_pipeline.h new file mode 100644 index 0000000..cecb99b --- /dev/null +++ b/modules/vulkan/vk_pipeline.h @@ -0,0 +1,127 @@ +/* + * vk_pipeline.h - Vulkan pipeline + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_PIPELINE_H +#define XCAM_VK_PIPELINE_H + +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_descriptor.h> +#include <vulkan/vk_device.h> +#include <vulkan/vk_shader.h> + +namespace XCam { + +class VKPipeline +{ +public: + static SmartPtr<VKPipeline> + create_compute_pipeline ( + const SmartPtr<VKDevice> dev, + const SmartPtr<VKShader> shader, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts); + + virtual ~VKPipeline (); + + VkPipeline get_pipeline_id () const { + return _pipe_id; + } + const char *get_name () const { + return _name; + } + void set_desc_pool (const SmartPtr<VKDescriptor::Pool> pool); + //interface + virtual XCamReturn update_bindings (const VKDescriptor::SetBindInfoArray &bind_array) = 0; + + // inter-functions, called by VKCmdBuf + virtual XCamReturn bind_by (VKCmdBuf &cmd_buf) = 0; + virtual XCamReturn push_consts_by ( + VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const) = 0; + +protected: + explicit VKPipeline ( + const SmartPtr<VKDevice> dev, + const ShaderVec &shaders, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts); + + VkDescriptorSetLayout create_desc_set_layout ( + const VKDescriptor::BindingArray &bindings); + + VkPipelineLayout create_pipeline_layout ( + VkDescriptorSetLayout desc_layout, + const VKConstRange::VKConstantArray &consts); + + // intra virtual functions + virtual XCamReturn ensure_layouts () = 0; + virtual XCamReturn ensure_pipeline () = 0; + +private: + XCAM_DEAD_COPY (VKPipeline); + +protected: + VkPipeline _pipe_id; + char _name [XCAM_VK_NAME_LENGTH]; + + SmartPtr<VKDevice> _dev; + SmartPtr<VkAllocationCallbacks> _allocator; + ShaderVec _shaders; + VKDescriptor::BindingArray _bindings; + VKConstRange::VKConstantArray _push_consts; + SmartPtr<VKDescriptor::Pool> _pool; +}; + +class VKComputePipeline + : public VKPipeline +{ + friend class VKPipeline; + +public: + static VkComputePipelineCreateInfo + get_compute_create_info (const SmartPtr<VKShader> &shader, VkPipelineLayout &layout); + + ~VKComputePipeline (); + + //inherit from VKPipeline + XCamReturn update_bindings (const VKDescriptor::SetBindInfoArray &bind_array); + +protected: + explicit VKComputePipeline ( + const SmartPtr<VKDevice> dev, + const ShaderVec &shaders, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKConstantArray &consts); + + //virtual functions from VKPipeline + XCamReturn ensure_layouts (); + XCamReturn ensure_pipeline (); + XCamReturn bind_by (VKCmdBuf &cmd_buf); + XCamReturn push_consts_by ( + VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const); + +private: + VkPipelineLayout _pipe_layout; + VkDescriptorSetLayout _desc_layout; + SmartPtr<VKDescriptor::Set> _desc_set; +}; + +} + +#endif //XCAM_VK_PIPELINE_H diff --git a/modules/vulkan/vk_shader.cpp b/modules/vulkan/vk_shader.cpp new file mode 100644 index 0000000..96e0427 --- /dev/null +++ b/modules/vulkan/vk_shader.cpp @@ -0,0 +1,60 @@ +/* + * vk_shader.cpp - vulkan shader module + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_shader.h" +#include "vk_device.h" +#include "file_handle.h" + +namespace XCam { + +VKShader::VKShader (SmartPtr<VKDevice> dev, VkShaderModule id, const char *name) + : _device (dev) + , _shader_id (id) + , _shader_stage (VK_SHADER_STAGE_COMPUTE_BIT) +{ + XCAM_IS_VALID_VK_ID (id); + xcam_mem_clear (_name); + if (name) + strncpy (_name, name, XCAM_VK_NAME_LENGTH - 1); + strncpy (_func_name, "main", XCAM_VK_NAME_LENGTH - 1); +} + +VKShader::~VKShader () +{ + if (XCAM_IS_VALID_VK_ID (_shader_id)) + _device->destroy_shader_id (_shader_id); +} + +void +VKShader::set_func_name (const char *name) +{ + XCAM_ASSERT (name); + strncpy (_func_name, name, XCAM_VK_NAME_LENGTH - 1); +} + +void +VKShader::set_name (const char *name) +{ + XCAM_ASSERT (name); + strncpy (_name, name, XCAM_VK_NAME_LENGTH - 1); +} + + +} diff --git a/modules/vulkan/vk_shader.h b/modules/vulkan/vk_shader.h new file mode 100644 index 0000000..fd243bb --- /dev/null +++ b/modules/vulkan/vk_shader.h @@ -0,0 +1,71 @@ +/* + * vk_shader.h - Vulkan shader module + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_SHADER_H +#define XCAM_VK_SHADER_H + +#include <vulkan/vulkan_std.h> + +namespace XCam { + +class VKDevice; + +class VKShader +{ + friend class VKDevice; +public: + ~VKShader (); + + VkShaderModule get_shader_id () const { + return _shader_id; + } + VkShaderStageFlagBits get_shader_stage_flags () const { + return _shader_stage; + } + void set_func_name (const char *name); + void set_name (const char *name); + const char *get_func_name () const { + return _func_name; + } + const char *get_name () const { + return _name; + } + +private: + explicit VKShader (SmartPtr<VKDevice> dev, VkShaderModule id, const char *name = "null"); + +private: + XCAM_DEAD_COPY (VKShader); + +private: + //static ShaderTable _shader_cache; + //static Mutex _cache_mutex; + SmartPtr<VKDevice> _device; + VkShaderModule _shader_id; + VkShaderStageFlagBits _shader_stage; + char _func_name [XCAM_VK_NAME_LENGTH]; + char _name [XCAM_VK_NAME_LENGTH]; +}; + +typedef std::vector<SmartPtr<VKShader>> ShaderVec; + +} + +#endif //XCAM_VK_SHADER_H diff --git a/modules/vulkan/vk_stitcher.cpp b/modules/vulkan/vk_stitcher.cpp new file mode 100644 index 0000000..f074e48 --- /dev/null +++ b/modules/vulkan/vk_stitcher.cpp @@ -0,0 +1,824 @@ +/* + * vk_stitcher.cpp - Vulkan stitcher 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 "surview_fisheye_dewarp.h" +#include "vk_video_buf_allocator.h" +#include "vk_geomap_handler.h" +#include "vk_blender.h" +#include "vk_copy_handler.h" +#include "vk_stitcher.h" +#include "interface/feature_match.h" + +#define DUMP_BUFFER 0 + +#define GEOMAP_POOL_SIZE 1 + +#define VK_STITCHER_ALIGNMENT_X 16 +#define VK_STITCHER_ALIGNMENT_Y 4 + +#define MAP_FACTOR_X 16 +#define MAP_FACTOR_Y 16 + +#define CHECK_RET(ret, format, ...) \ + if (!xcam_ret_is_ok (ret)) { \ + XCAM_LOG_ERROR (format, ## __VA_ARGS__); \ + } + +namespace XCam { + +#if DUMP_BUFFER +static void +dump_buf (const SmartPtr<VideoBuffer> &buf, uint32_t idx, const char *prefix) +{ + XCAM_ASSERT (buf.ptr () && prefix); + + char name[256]; + snprintf (name, 256, "%s-%d", prefix, idx); + dump_buf_perfix_path (buf, name); +} +#endif + +namespace VKSitcherPriv { + +DECLARE_HANDLER_CALLBACK (CbGeoMap, VKStitcher, geomap_done); + +struct GeoMapParam + : ImageHandler::Parameters +{ + SmartPtr<VKStitcher::StitcherParam> stitch_param; + uint32_t idx; + + GeoMapParam (uint32_t i) + : idx (i) + {} +}; + +struct Factor { + float x, y; + + Factor () : x (1.0f), y (1.0f) {} + void reset () { + x = 1.0f; + y = 1.0f; + } +}; + +struct GeoMapFactors { + Factor left; + Factor right; +}; + +typedef std::vector<SmartPtr<VKCopyHandler>> Copiers; + +struct StitcherResource { + SmartPtr<VKBlender::Sync> blender_sync[XCAM_STITCH_MAX_CAMERAS]; + SmartPtr<BufferPool> mapper_pool[XCAM_STITCH_MAX_CAMERAS]; + + SmartPtr<GeoMapParam> mapper_param[XCAM_STITCH_MAX_CAMERAS]; + SmartPtr<VKBlender::BlenderParam> blender_param[XCAM_STITCH_MAX_CAMERAS]; + SmartPtr<ImageHandler::Parameters> copier_param[XCAM_STITCH_MAX_CAMERAS]; + + SmartPtr<VKGeoMapHandler> mapper[XCAM_STITCH_MAX_CAMERAS]; + SmartPtr<VKBlender> blender[XCAM_STITCH_MAX_CAMERAS]; + Copiers copiers; + + SmartPtr<FeatureMatch> matcher[XCAM_STITCH_MAX_CAMERAS]; + GeoMapFactors mapper_factors[XCAM_STITCH_MAX_CAMERAS]; + + StitcherResource (); +}; + +class StitcherImpl { + friend class XCam::VKStitcher; + +public: + StitcherImpl (VKStitcher *handler) + : _stitcher (handler) + {} + + XCamReturn init_resource (); + + XCamReturn start_geo_mappers (const SmartPtr<VKStitcher::StitcherParam> ¶m); + XCamReturn start_blenders (const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx); + XCamReturn start_copier (const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx); + XCamReturn start_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx); + + XCamReturn stop (); + +private: + SmartPtr<VKGeoMapHandler> create_geo_mapper ( + const SmartPtr<VKDevice> &dev, const Stitcher::RoundViewSlice &view_slice); + + XCamReturn init_geo_mappers (const SmartPtr<VKDevice> &dev); + XCamReturn init_blenders (const SmartPtr<VKDevice> &dev); + XCamReturn init_copiers (const SmartPtr<VKDevice> &dev); + void init_feature_matchers (); + + void calc_geomap_factors ( + uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor, + Factor &cur_left, Factor &cur_right); + bool update_geomap_factors (uint32_t idx); + XCamReturn create_geomap_pool (const SmartPtr<VKDevice> &dev, uint32_t idx); + XCamReturn set_geomap_table ( + const SmartPtr<VKGeoMapHandler> &mapper, const CameraInfo &cam_info, + const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl); + XCamReturn generate_geomap_table (const SmartPtr<VKGeoMapHandler> &mapper, uint32_t idx); + + void update_blender_sync (uint32_t idx); + XCamReturn start_blender (const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx); + +private: + StitcherResource _res; + VKStitcher *_stitcher; +}; + +StitcherResource::StitcherResource () +{ +} + +SmartPtr<VKGeoMapHandler> +StitcherImpl::create_geo_mapper ( + const SmartPtr<VKDevice> &dev, const Stitcher::RoundViewSlice &view_slice) +{ + XCAM_UNUSED (view_slice); + + SmartPtr<VKGeoMapHandler> mapper; + if (_stitcher->get_scale_mode () == ScaleSingleConst) { + mapper = new VKGeoMapHandler (dev, "sitcher_singleconst_remapper"); + } else { + XCAM_LOG_ERROR ( + "vk-stitcher(%s) unsupported scale mode:%d", + XCAM_STR (_stitcher->get_name ()), _stitcher->get_scale_mode ()); + } + XCAM_ASSERT (mapper.ptr ()); + + return mapper; +} + +void +StitcherImpl::update_blender_sync (uint32_t idx) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + uint32_t pre_idx = (idx + cam_num - 1) % cam_num; + + _res.blender_sync[pre_idx]->increment (); + _res.blender_sync[idx]->increment (); +} + +void +StitcherImpl::calc_geomap_factors ( + uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor, + Factor &cur_left, Factor &cur_right) +{ + const Factor &fm_left_factor = _res.mapper_factors[idx].left; + const Factor &fm_right_factor = _res.mapper_factors[idx].right; + + cur_left.x = last_left_factor.x * fm_left_factor.x; + cur_left.y = last_left_factor.y * fm_left_factor.y; + cur_right.x = last_right_factor.x * fm_right_factor.x; + cur_right.y = last_right_factor.y * fm_right_factor.y; + + _res.mapper_factors[idx].left.reset (); + _res.mapper_factors[idx].right.reset (); +} + +bool +StitcherImpl::update_geomap_factors (uint32_t idx) +{ + SmartPtr<VKGeoMapHandler> &mapper = _res.mapper[idx]; + XCAM_FAIL_RETURN ( + ERROR, mapper.ptr (), false, + "vk-stitcher(%s) geomap handler is empty, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + + if (_stitcher->get_scale_mode () == ScaleSingleConst) { + Factor unify_factor, cur_left, cur_right; + + mapper->get_factors (unify_factor.x, unify_factor.y); + if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) || + XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started. + return true; + } + + calc_geomap_factors (idx, unify_factor, unify_factor, cur_left, cur_right); + unify_factor.x = (cur_left.x + cur_right.x) / 2.0f; + unify_factor.y = (cur_left.y + cur_right.y) / 2.0f; + + mapper->set_factors (unify_factor.x, unify_factor.y); + } else { + XCAM_LOG_ERROR ( + "vk-stitcher(%s) unsupported scale mode:%d", + XCAM_STR (_stitcher->get_name ()), _stitcher->get_scale_mode ()); + return false; + } + + return true; +} + +XCamReturn +StitcherImpl::create_geomap_pool (const SmartPtr<VKDevice> &dev, uint32_t idx) +{ + uint32_t output_width, output_height; + _res.mapper[idx]->get_output_size (output_width, output_height); + + VideoBufferInfo out_info; + out_info.init ( + V4L2_PIX_FMT_NV12, output_width, output_height, + XCAM_ALIGN_UP (output_width, VK_STITCHER_ALIGNMENT_X), + XCAM_ALIGN_UP (output_height, VK_STITCHER_ALIGNMENT_Y)); + + SmartPtr<BufferPool> pool = create_vk_buffer_pool (dev); + XCAM_ASSERT (pool.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, pool->set_video_info (out_info) && pool->reserve (GEOMAP_POOL_SIZE), + XCAM_RETURN_ERROR_MEM, + "vk-stitcher(%s) create buffer pool failed, buffer size:%dx%d, idx:%d", + XCAM_STR (_stitcher->get_name ()), out_info.width, out_info.height, idx); + + _res.mapper_pool[idx] = pool; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::set_geomap_table ( + const SmartPtr<VKGeoMapHandler> &mapper, const CameraInfo &cam_info, + const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl) +{ + PolyFisheyeDewarp fd; + fd.set_intrinsic_param (cam_info.calibration.intrinsic); + fd.set_extrinsic_param (cam_info.calibration.extrinsic); + + uint32_t table_width, table_height; + table_width = view_slice.width / MAP_FACTOR_X; + table_height = view_slice.height / MAP_FACTOR_Y; + + SurViewFisheyeDewarp::MapTable map_table (table_width * table_height); + fd.fisheye_dewarp ( + map_table, table_width, table_height, + view_slice.width, view_slice.height, bowl); + + bool ret = mapper->set_lookup_table (map_table.data (), table_width, table_height); + XCAM_FAIL_RETURN ( + ERROR, ret, XCAM_RETURN_ERROR_UNKNOWN, + "vk-stitcher(%s) set geomap lookup table failed", XCAM_STR (_stitcher->get_name ())); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::generate_geomap_table ( + const SmartPtr<VKGeoMapHandler> &mapper, uint32_t idx) +{ + CameraInfo cam_info; + _stitcher->get_camera_info (idx, cam_info); + Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx); + + BowlDataConfig bowl = _stitcher->get_bowl_config (); + bowl.angle_start = view_slice.hori_angle_start; + bowl.angle_end = format_angle (view_slice.hori_angle_start + view_slice.hori_angle_range); + if (bowl.angle_end < bowl.angle_start) + bowl.angle_start -= 360.0f; + + XCAM_LOG_DEBUG ( + "vk-stitcher(%s) camera(idx:%d) info(angle start:%.2f, range:%.2f), bowl info(angle start:%.2f, end:%.2f)", + XCAM_STR (_stitcher->get_name ()), idx, + view_slice.hori_angle_start, view_slice.hori_angle_range, + bowl.angle_start, bowl.angle_end); + + XCamReturn ret = set_geomap_table (mapper, cam_info, view_slice, bowl); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) set geometry map table failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::init_geo_mappers (const SmartPtr<VKDevice> &dev) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + SmartPtr<ImageHandler::Callback> cb = new CbGeoMap (_stitcher); + + for (uint32_t idx = 0; idx < cam_num; ++idx) { + Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx); + + SmartPtr<VKGeoMapHandler> &mapper = _res.mapper[idx]; + mapper = create_geo_mapper (dev, view_slice); + mapper->set_callback (cb); + mapper->set_output_size (view_slice.width, view_slice.height); + + create_geomap_pool (dev, idx); + + SmartPtr<GeoMapParam> &mapper_param = _res.mapper_param[idx]; + mapper_param = new GeoMapParam (idx); + XCAM_ASSERT (mapper_param.ptr ()); + + mapper_param->out_buf = _res.mapper_pool[idx]->get_buffer (); + XCAM_ASSERT (mapper_param->out_buf.ptr ()); + + XCamReturn ret = generate_geomap_table (mapper, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) generate geomap table failed", XCAM_STR (_stitcher->get_name ())); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::init_blenders (const SmartPtr<VKDevice> &dev) +{ + uint32_t out_width, out_height; + _stitcher->get_output_size (out_width, out_height); + uint32_t cam_num = _stitcher->get_camera_num (); + + for (uint32_t idx = 0; idx < cam_num; ++idx) { + SmartPtr<VKBlender> &blender = _res.blender[idx]; + blender = create_vk_blender (dev).dynamic_cast_ptr<VKBlender> (); + XCAM_ASSERT (blender.ptr ()); + + const Stitcher::ImageOverlapInfo &overlap = _stitcher->get_overlap (idx); + blender->set_output_size (out_width, out_height); + blender->set_merge_window (overlap.out_area); + blender->set_input_valid_area (overlap.left, 0); + blender->set_input_valid_area (overlap.right, 1); + blender->set_input_merge_area (overlap.left, 0); + blender->set_input_merge_area (overlap.right, 1); + + SmartPtr<VKBlender::BlenderParam> &blender_param = _res.blender_param[idx]; + blender_param = new VKBlender::BlenderParam (NULL, NULL, NULL); + XCAM_ASSERT (blender_param.ptr ()); + + uint32_t next_idx = (idx + 1) % cam_num; + blender_param->in_buf = _res.mapper_param[idx]->out_buf; + blender_param->in1_buf = _res.mapper_param[next_idx]->out_buf; + XCAM_ASSERT (blender_param->in_buf.ptr () && blender_param->in1_buf.ptr ()); + + _res.blender_sync[idx] = new VKBlender::Sync (2); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::init_copiers (const SmartPtr<VKDevice> &dev) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + for (uint32_t idx = 0; idx < cam_num; ++idx) { + SmartPtr<ImageHandler::Parameters> &copier_param = _res.copier_param[idx]; + copier_param = new ImageHandler::Parameters (); + XCAM_ASSERT (copier_param.ptr ()); + + copier_param->in_buf = _res.mapper_param[idx]->out_buf; + XCAM_ASSERT (copier_param->in_buf.ptr ()); + } + + Stitcher::CopyAreaArray areas = _stitcher->get_copy_area (); + uint32_t size = areas.size (); + for (uint32_t idx = 0; idx < size; ++idx) { + XCAM_ASSERT (areas[idx].in_idx < size); + + SmartPtr<VKCopyHandler> copier = new VKCopyHandler (dev); + XCAM_ASSERT (copier.ptr ()); + copier->enable_allocator (false); + copier->set_copy_area (areas[idx].in_idx, areas[idx].in_area, areas[idx].out_area); + + _res.copiers.push_back (copier); + } + + return XCAM_RETURN_NO_ERROR; +} + +void +StitcherImpl::init_feature_matchers () +{ +#if HAVE_OPENCV + FeatureMatchMode fm_mode = _stitcher->get_fm_mode (); + if (fm_mode == FMNone) + return ; + + uint32_t cam_num = _stitcher->get_camera_num (); + for (uint32_t idx = 0; idx < cam_num; ++idx) { + SmartPtr<FeatureMatch> &matcher = _res.matcher[idx]; +#ifndef ANDROID + if (fm_mode == FMDefault) + matcher = FeatureMatch::create_default_feature_match (); + else if (fm_mode == FMCluster) + matcher = FeatureMatch::create_cluster_feature_match (); + else if (fm_mode == FMCapi) + matcher = FeatureMatch::create_capi_feature_match (); + else { + XCAM_LOG_ERROR ( + "vk-stitcher(%s) unsupported FeatureMatchMode: %d", + XCAM_STR (_stitcher->get_name ()), fm_mode); + } +#else + matcher = FeatureMatch::create_capi_feature_match (); +#endif + XCAM_ASSERT (matcher.ptr ()); + + FMConfig config; + config.sitch_min_width = 136; + config.min_corners = 4; + config.offset_factor = 0.8f; + config.delta_mean_offset = 120.0f; + config.recur_offset_error = 8.0f; + config.max_adjusted_offset = 24.0f; + config.max_valid_offset_y = 20.0f; + config.max_track_error = 28.0f; +#ifdef ANDROID + config.max_track_error = 3600.0f; +#endif + matcher->set_config (config); + matcher->set_fm_index (idx); + + const BowlDataConfig bowl = _stitcher->get_bowl_config (); + const Stitcher::ImageOverlapInfo &info = _stitcher->get_overlap (idx); + Rect left_ovlap = info.left; + Rect right_ovlap = info.right; + left_ovlap.pos_y = 0; + left_ovlap.height = int32_t (bowl.wall_height / (bowl.wall_height + bowl.ground_length) * left_ovlap.height); + right_ovlap.pos_y = 0; + right_ovlap.height = left_ovlap.height; + matcher->set_crop_rect (left_ovlap, right_ovlap); + } +#else + XCAM_LOG_ERROR ("vk-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ())); + XCAM_ASSERT (false); +#endif +} + +XCamReturn +StitcherImpl::init_resource () +{ + const SmartPtr<VKDevice> &dev = _stitcher->get_vk_device (); + XCAM_ASSERT (dev.ptr ()); + + XCamReturn ret = init_geo_mappers (dev); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) init dewarps failed", XCAM_STR (_stitcher->get_name ())); + +#if HAVE_OPENCV + init_feature_matchers (); +#endif + + ret = init_blenders (dev); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) init blenders failed", XCAM_STR (_stitcher->get_name ())); + + ret = init_copiers (dev); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) init copiers failed", XCAM_STR (_stitcher->get_name ())); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_geo_mappers (const SmartPtr<VKStitcher::StitcherParam> ¶m) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + + for (uint32_t idx = 0; idx < cam_num; ++idx) { + if (_stitcher->get_fm_mode ()) + update_geomap_factors (idx); + + SmartPtr<GeoMapParam> &mapper_param = _res.mapper_param[idx]; + mapper_param->in_buf = param->in_bufs[idx]; + mapper_param->stitch_param = param; + + XCamReturn ret = _res.mapper[idx]->execute_buffer (mapper_param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) execute geo mapper failed, idx:%d", + XCAM_STR (_stitcher->get_name ()), idx); + +#if DUMP_BUFFER + dump_buf (mapper_param->out_buf, idx, "stitcher-geomap"); +#endif + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx) +{ +#if HAVE_OPENCV + _res.matcher[idx]->reset_offsets (); + _res.matcher[idx]->feature_match (left_buf, right_buf); + + Rect left_ovlap, right_ovlap; + _res.matcher[idx]->get_crop_rect (left_ovlap, right_ovlap); + float left_offsetx = _res.matcher[idx]->get_current_left_offset_x (); + + uint32_t left_idx = idx; + Factor left_factor, right_factor; + float center_x = (float) _stitcher->get_center (left_idx).slice_center_x; + float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f); + float range = feature_center_x - center_x; + XCAM_ASSERT (range > 1.0f); + right_factor.x = (range + left_offsetx / 2.0f) / range; + right_factor.y = 1.0f; + XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f); + + uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num (); + center_x = (float) _stitcher->get_center (right_idx).slice_center_x; + feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f); + range = center_x - feature_center_x; + XCAM_ASSERT (range > 1.0f); + left_factor.x = (range + left_offsetx / 2.0f) / range; + left_factor.y = 1.0f; + XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f); + + _res.mapper_factors[left_idx].right = right_factor; + _res.mapper_factors[right_idx].left = left_factor; + + return XCAM_RETURN_NO_ERROR; +#else + XCAM_LOG_ERROR ("vk-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ())); + return XCAM_RETURN_ERROR_PARAM; +#endif +} + +XCamReturn +StitcherImpl::start_blender ( + const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx) +{ + SmartPtr<VKBlender::Sync> &sync = _res.blender_sync[idx]; + if (!sync->is_synced ()) + return XCAM_RETURN_NO_ERROR; + sync->reset (); + + SmartPtr<VKBlender::BlenderParam> &blend_param = _res.blender_param[idx]; + blend_param->out_buf = param->out_buf; + + XCamReturn ret = _res.blender[idx]->execute_buffer (blend_param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) execute blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + +#if DUMP_BUFFER + dump_buf (param->out_buf, idx, "stitcher-blend"); +#endif + +#if HAVE_OPENCV + if (_stitcher->get_fm_mode ()) { + ret = start_feature_match (blend_param->in_buf, blend_param->in1_buf, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) start feature match failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + } +#endif + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_blenders (const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + uint32_t pre_idx = (idx + cam_num - 1) % cam_num; + + XCamReturn ret = start_blender (param, pre_idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) start blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), pre_idx); + + ret = start_blender (param, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) start blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_copier ( + const SmartPtr<VKStitcher::StitcherParam> ¶m, uint32_t idx) +{ + uint32_t size = _stitcher->get_copy_area ().size (); + + for (uint32_t i = 0; i < size; ++i) { + if(_res.copiers[i]->get_index () != idx) + continue; + + SmartPtr<ImageHandler::Parameters> ©_param = _res.copier_param[idx]; + copy_param->out_buf = param->out_buf; + + XCamReturn ret = _res.copiers[i]->execute_buffer (copy_param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) execute copier failed, i:%d idx:%d", + XCAM_STR (_stitcher->get_name ()), i, idx); + +#if DUMP_BUFFER + dump_buf (copy_param->out_buf, i, "stitcher-copy"); +#endif + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::stop () +{ + uint32_t cam_num = _stitcher->get_camera_num (); + for (uint32_t i = 0; i < cam_num; ++i) { + if (_res.mapper[i].ptr ()) { + _res.mapper[i]->terminate (); + _res.mapper[i].release (); + } + if (_res.mapper_pool[i].ptr ()) { + _res.mapper_pool[i]->stop (); + } + + if (_res.blender[i].ptr ()) { + _res.blender[i]->terminate (); + _res.blender[i].release (); + } + } + + for (Copiers::iterator i = _res.copiers.begin (); i != _res.copiers.end (); ++i) { + SmartPtr<VKCopyHandler> &copier = *i; + if (copier.ptr ()) { + copier->terminate (); + copier.release (); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +}; + +VKStitcher::VKStitcher (const SmartPtr<VKDevice> &dev, const char *name) + : VKHandler (dev, name) + , Stitcher (VK_STITCHER_ALIGNMENT_X, VK_STITCHER_ALIGNMENT_X) +{ + SmartPtr<VKSitcherPriv::StitcherImpl> impl = new VKSitcherPriv::StitcherImpl (this); + XCAM_ASSERT (impl.ptr ()); + _impl = impl; +} + +VKStitcher::~VKStitcher () +{ + _impl.release (); +} + +XCamReturn +VKStitcher::terminate () +{ + _impl->stop (); + return VKHandler::terminate (); +} + +XCamReturn +VKStitcher::stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf) +{ + XCAM_FAIL_RETURN ( + ERROR, !in_bufs.empty (), XCAM_RETURN_ERROR_PARAM, + "vk-stitcher(%s) input buffers is empty", XCAM_STR (get_name ())); + + SmartPtr<StitcherParam> param = new StitcherParam (); + XCAM_ASSERT (param.ptr ()); + + uint32_t buf_num = 0; + for (VideoBufferList::const_iterator iter = in_bufs.begin(); iter != in_bufs.end (); ++iter) { + XCAM_ASSERT ((*iter).ptr ()); + param->in_bufs[buf_num++] = *iter; + } + param->in_buf_num = buf_num; + param->out_buf = out_buf; + + XCamReturn ret = execute_buffer (param, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) execute buffer failed", XCAM_STR (get_name ())); + + finish (); + if (!out_buf.ptr ()) { + out_buf = param->out_buf; + } + + return ret; +} + +XCamReturn +VKStitcher::configure_resource (const SmartPtr<Parameters> ¶m) +{ + XCAM_UNUSED (param); + XCAM_ASSERT (_impl.ptr ()); + + XCamReturn ret = estimate_round_slices (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) estimate round view slices failed", XCAM_STR (get_name ())); + + ret = estimate_coarse_crops (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) estimate coarse crops failed", XCAM_STR (get_name ())); + + ret = mark_centers (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) mark centers failed", XCAM_STR (get_name ())); + + ret = estimate_overlap (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) estimake coarse overlap failed", XCAM_STR (get_name ())); + + ret = update_copy_areas (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) update copy areas failed", XCAM_STR (get_name ())); + + ret = _impl->init_resource (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk-stitcher(%s) initialize private config failed", XCAM_STR (get_name ())); + + VideoBufferInfo out_info; + 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-stitcher(%s) output size was not set", XCAM_STR (get_name ())); + + out_info.init ( + V4L2_PIX_FMT_NV12, out_width, out_height, + XCAM_ALIGN_UP (out_width, VK_STITCHER_ALIGNMENT_X), + XCAM_ALIGN_UP (out_height, VK_STITCHER_ALIGNMENT_Y)); + set_out_video_info (out_info); + + return ret; +} + +XCamReturn +VKStitcher::start_work (const SmartPtr<Parameters> &base) +{ + XCAM_ASSERT (base.ptr ()); + + SmartPtr<StitcherParam> param = base.dynamic_cast_ptr<StitcherParam> (); + XCAM_ASSERT (param.ptr () && param->in_buf_num > 0); + + XCamReturn ret = _impl->start_geo_mappers (param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM, + "vk_stitcher(%s) start geometry map failed", XCAM_STR (get_name ())); + + return ret; +} + +void +VKStitcher::geomap_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> &base, const XCamReturn error) +{ + XCAM_UNUSED (handler); + XCAM_UNUSED (error); + + SmartPtr<VKSitcherPriv::GeoMapParam> param = base.dynamic_cast_ptr<VKSitcherPriv::GeoMapParam> (); + XCAM_ASSERT (param.ptr ()); + SmartPtr<VKStitcher::StitcherParam> &stitch_param = param->stitch_param; + XCAM_ASSERT (stitch_param.ptr ()); + + _impl->update_blender_sync (param->idx); + + XCamReturn ret = _impl->start_blenders (stitch_param, param->idx); + CHECK_RET (ret, "vk-stitcher(%s) start blenders failed, idx:%d", XCAM_STR (get_name ()), param->idx); + + ret = _impl->start_copier (stitch_param, param->idx); + CHECK_RET (ret, "vk-stitcher(%s) start copier failed, idx:%d", XCAM_STR (get_name ()), param->idx); +} + +SmartPtr<Stitcher> +Stitcher::create_vk_stitcher (const SmartPtr<VKDevice> dev) +{ + return new VKStitcher (dev); +} + +} diff --git a/modules/vulkan/vk_stitcher.h b/modules/vulkan/vk_stitcher.h new file mode 100644 index 0000000..c59f013 --- /dev/null +++ b/modules/vulkan/vk_stitcher.h @@ -0,0 +1,80 @@ +/* + * vk_stitcher.h - Vulkan stitcher class + * + * 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> + */ + +#ifndef XCAM_VK_STITCHER_H +#define XCAM_VK_STITCHER_H + +#include <interface/stitcher.h> +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_handler.h> + +namespace XCam { + +namespace VKSitcherPriv { +class StitcherImpl; +class CbGeoMap; +}; + +class VKStitcher + : public VKHandler + , public Stitcher +{ + friend class VKSitcherPriv::StitcherImpl; + friend class VKSitcherPriv::CbGeoMap; + +public: + struct StitcherParam + : ImageHandler::Parameters + { + uint32_t in_buf_num; + SmartPtr<VideoBuffer> in_bufs[XCAM_STITCH_MAX_CAMERAS]; + + StitcherParam () + : Parameters (NULL, NULL) + , in_buf_num (0) + {} + }; + +public: + explicit VKStitcher (const SmartPtr<VKDevice> &dev, const char *name = "VKStitcher"); + ~VKStitcher (); + + // derived from VKHandler + virtual XCamReturn terminate (); + +protected: + // interface derive from Stitcher + XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf); + + // derived from VKHandler + XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + void geomap_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> ¶m, const XCamReturn error); + +private: + SmartPtr<VKSitcherPriv::StitcherImpl> _impl; +}; + +} +#endif // XCAM_VK_STITCHER_H diff --git a/modules/vulkan/vk_sync.cpp b/modules/vulkan/vk_sync.cpp new file mode 100644 index 0000000..f5ea6c6 --- /dev/null +++ b/modules/vulkan/vk_sync.cpp @@ -0,0 +1,55 @@ +/* + * vk_sync.cpp - Vulkan sync + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_sync.h" +#include "vk_device.h" + +namespace XCam { + +VKFence::~VKFence () +{ + if (_dev.ptr () && XCAM_IS_VALID_VK_ID (_fence_id)) + _dev->destroy_fence (_fence_id); +} + +VKFence::VKFence (const SmartPtr<VKDevice> dev, VkFence id) + : _fence_id (id) + , _dev (dev) +{ +} + +XCamReturn +VKFence::reset () +{ + XCAM_ASSERT (_dev.ptr ()); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_fence_id)); + + return _dev->reset_fence (_fence_id); +} + +XCamReturn +VKFence::wait (uint64_t timeout) +{ + XCAM_ASSERT (_dev.ptr ()); + XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_fence_id)); + return _dev->wait_for_fence (_fence_id, timeout); +} + +} diff --git a/modules/vulkan/vk_sync.h b/modules/vulkan/vk_sync.h new file mode 100644 index 0000000..e2a7d34 --- /dev/null +++ b/modules/vulkan/vk_sync.h @@ -0,0 +1,56 @@ +/* + * vk_sync.h - Vulkan sync + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_SYNC_H +#define XCAM_VK_SYNC_H + +#include <vulkan/vulkan_std.h> + +namespace XCam { + +class VKDevice; + +class VKFence +{ + friend class VKDevice; +public: + virtual ~VKFence (); + + XCamReturn reset (); + XCamReturn wait (uint64_t timeout = UINT64_MAX); + + VkFence get_fence_id () const { + return _fence_id; + } + +protected: + explicit VKFence (const SmartPtr<VKDevice> dev, VkFence id); + +private: + XCAM_DEAD_COPY (VKFence); + +protected: + VkFence _fence_id; + SmartPtr<VKDevice> _dev; +}; + +} + +#endif //XCAM_VK_SYNC_H diff --git a/modules/vulkan/vk_video_buf_allocator.cpp b/modules/vulkan/vk_video_buf_allocator.cpp new file mode 100644 index 0000000..c60476a --- /dev/null +++ b/modules/vulkan/vk_video_buf_allocator.cpp @@ -0,0 +1,164 @@ +/* + * vk_video_buf_allocator.cpp - vulkan video buffer allocator implementation + * + * Copyright (c) 2017 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 "vk_video_buf_allocator.h" +#include "vk_memory.h" +#include "vk_device.h" + +namespace XCam { + +class VKVideoData + : public BufferData +{ + friend class VKVideoBuffer; +public: + explicit VKVideoData (const SmartPtr<VKBuffer> vk_buf); + virtual ~VKVideoData (); + + //derive from BufferData + virtual uint8_t *map (); + virtual bool unmap (); + + bool is_valid (); + +private: + uint8_t *_mem_ptr; + SmartPtr<VKBuffer> _vk_buf; +}; + +VKVideoData::VKVideoData (const SmartPtr<VKBuffer> vk_buf) + : _mem_ptr (NULL) + , _vk_buf (vk_buf) +{ + XCAM_ASSERT (vk_buf.ptr ()); +} + +VKVideoData::~VKVideoData () +{ +} + +bool +VKVideoData::is_valid () +{ + return _vk_buf.ptr () && XCAM_IS_VALID_VK_ID (_vk_buf->get_buf_id ()); +} + +uint8_t * +VKVideoData::map () +{ + if (!_mem_ptr) { + _mem_ptr = (uint8_t *)_vk_buf->map (); + } + return _mem_ptr; +} + +bool +VKVideoData::unmap () +{ + if (!_mem_ptr) + return false; + + _mem_ptr = NULL; + _vk_buf->unmap (); + return true; +} + +VKVideoBufAllocator::VKVideoBufAllocator (const SmartPtr<VKDevice> dev) + : _dev (dev) +{ +} + +VKVideoBufAllocator::~VKVideoBufAllocator () +{ +} + +SmartPtr<BufferData> +VKVideoBufAllocator::allocate_data (const VideoBufferInfo &buffer_info) +{ + XCAM_FAIL_RETURN ( + ERROR, buffer_info.size, NULL, + "VKVideoBufAllocator allocate data failed. buf_size is zero"); + + SmartPtr<VKBuffer> vk_buf = + VKBuffer::create_buffer (_dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buffer_info.size); + + XCAM_FAIL_RETURN ( + ERROR, vk_buf.ptr (), NULL, + "VKVideoBufAllocator create vk memory failed. buf_size :%d", buffer_info.size); + + VKBufInfo info; + info.format = buffer_info.format; + info.width = buffer_info.width; + info.height = buffer_info.height; + info.aligned_width = buffer_info.aligned_width; + info.aligned_height = buffer_info.aligned_height; + info.size = buffer_info.size; + info.strides[0] = buffer_info.strides[0]; + info.strides[1] = buffer_info.strides[1]; + info.offsets[0] = buffer_info.offsets[0]; + info.offsets[1] = buffer_info.offsets[1]; + info.slice_size[0] = buffer_info.strides[0] * buffer_info.aligned_height; + info.slice_size[1] = buffer_info.size - buffer_info.offsets[1]; + vk_buf->set_buf_info (info); + + SmartPtr<VKVideoData> data = new VKVideoData (vk_buf); + XCAM_FAIL_RETURN ( + ERROR, data.ptr () && data->is_valid (), NULL, + "VKVideoBufAllocator allocate data failed. buf_size:%d", buffer_info.size); + + return data; +} + +SmartPtr<BufferProxy> +VKVideoBufAllocator::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + const VideoBufferInfo &info = get_video_info (); + + XCAM_ASSERT (data.ptr ()); + return new VKVideoBuffer (info, data); +} + +VKVideoBuffer::VKVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data) + : BufferProxy (info, data) +{ +} + +SmartPtr<VKBuffer> +VKVideoBuffer::get_vk_buf () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<VKVideoData> vk_data = data.dynamic_cast_ptr<VKVideoData> (); + XCAM_FAIL_RETURN ( + ERROR, vk_data.ptr () && vk_data->_vk_buf.ptr (), VK_NULL_HANDLE, + "VKVideoBuffer get buf_id failed, data is empty"); + + return vk_data->_vk_buf; +} + +SmartPtr<BufferPool> +create_vk_buffer_pool (const SmartPtr<VKDevice> &dev) +{ + XCAM_FAIL_RETURN ( + ERROR, dev.ptr () && XCAM_IS_VALID_VK_ID(dev->get_dev_id()), NULL, + "create_vk_buffer_pool failed since vk device is invalid"); + return new VKVideoBufAllocator (dev); +} + +} diff --git a/modules/vulkan/vk_video_buf_allocator.h b/modules/vulkan/vk_video_buf_allocator.h new file mode 100644 index 0000000..af56f94 --- /dev/null +++ b/modules/vulkan/vk_video_buf_allocator.h @@ -0,0 +1,58 @@ +/* + * vk_video_buf_allocator.h - vulkan video buffer allocator class + * + * Copyright (c) 2017 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> + */ + +#ifndef XCAM_VK_VIDEO_BUF_ALLOCATOR_H +#define XCAM_VK_VIDEO_BUF_ALLOCATOR_H + +#include <buffer_pool.h> + +namespace XCam { + +class VKDevice; +class VKBuffer; + +class VKVideoBufAllocator + : public BufferPool +{ +public: + explicit VKVideoBufAllocator (const SmartPtr<VKDevice> dev); + virtual ~VKVideoBufAllocator (); + +private: + //derive from BufferPool + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + +private: + SmartPtr<VKDevice> _dev; +}; + +class VKVideoBuffer + : public BufferProxy +{ +public: + explicit VKVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data); + SmartPtr<VKBuffer> get_vk_buf (); +}; + +} + +#endif //XCAM_VK_VIDEO_BUF_ALLOCATOR_H + diff --git a/modules/vulkan/vk_worker.cpp b/modules/vulkan/vk_worker.cpp new file mode 100644 index 0000000..f40a81a --- /dev/null +++ b/modules/vulkan/vk_worker.cpp @@ -0,0 +1,218 @@ +/* + * vk_worker.cpp - vulkan worker class + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vk_worker.h" +#include "vk_sync.h" +#include "vk_pipeline.h" +#include "vk_cmdbuf.h" +#include "vk_device.h" +#include "vulkan_common.h" + +namespace XCam { + +XCamReturn +VKWorker::VKArguments::prepare_bindings ( + VKDescriptor::SetBindInfoArray &binding_array, + VKConstRange::VKPushConstArgs &push_consts) +{ + XCAM_ASSERT (_binding_bufs.size ()); + XCAM_FAIL_RETURN ( + ERROR, _binding_bufs.size (), XCAM_RETURN_ERROR_PARAM, + "VKArguments found bindings empty, please check settings or derive interface prepare_bindings"); + + binding_array = _binding_bufs; + push_consts = _push_consts; + return XCAM_RETURN_NO_ERROR; +} + +bool +VKWorker::VKArguments::set_bindings (const VKDescriptor::SetBindInfoArray &arr) +{ + _binding_bufs = arr; + return true; +} + +bool +VKWorker::VKArguments::add_binding (const VKDescriptor::SetBindInfo &info) +{ + _binding_bufs.push_back (info); + return true; +} + +bool +VKWorker::VKArguments::add_push_const (const SmartPtr<VKConstRange::VKPushConstArg> &push_const) +{ + _push_consts.push_back (push_const); + return true; +} + +VKWorker::VKWorker (SmartPtr<VKDevice> dev, const char *name, const SmartPtr<Callback> &cb) + : Worker (name, cb) + , _device (dev) +{ +} + +VKWorker::~VKWorker () +{ +} + +XCamReturn +VKWorker::build ( + const VKShaderInfo &info, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKPushConstArgs &consts) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_FAIL_RETURN ( + ERROR, _device.ptr (), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed since vk_device is null.", XCAM_STR (get_name ())); + + SmartPtr<VKShader> shader; + if (info.type == VKSahderInfoSpirVPath) { + const char *dir_env = std::getenv (XCAM_VK_SHADER_PATH); + std::string vk_dir (dir_env, (dir_env ? strlen (dir_env) : 0)); + if (vk_dir.empty () || !vk_dir.length()) + vk_dir = XCAM_DEFAULT_VK_SHADER_PATH; + std::string spirv_path = vk_dir + "/" + info.spirv_path; + shader = _device->create_shader (spirv_path.c_str ()); + } else if (info.type == VKSahderInfoSpirVBinary) { + shader = _device->create_shader (info.spirv_bin); + } + XCAM_FAIL_RETURN ( + ERROR, shader.ptr (), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed when creating shader.", XCAM_STR (get_name ())); + shader->set_func_name (info.func_name.c_str ()); + + _desc_pool = new VKDescriptor::Pool (_device); + XCAM_ASSERT (_desc_pool.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, _desc_pool->add_set_bindings (bindings), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed to add bindings to desc_pool", XCAM_STR (get_name ())); + ret = _desc_pool->create (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk woker(%s) build failed to craete bindings in desc_pool", XCAM_STR (get_name ())); + + VKConstRange::VKConstantArray const_array; + for (size_t i = 0; i < consts.size(); ++i) { + VkPushConstantRange data_const = {0, 0, 0}; + void *ptr = NULL; + consts[i]->get_const_data (data_const, ptr); + const_array.push_back (data_const); + } + _pipeline = VKPipeline::create_compute_pipeline (_device, shader, bindings, const_array); + XCAM_FAIL_RETURN ( + ERROR, _pipeline.ptr (), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed when creating pipelines.", XCAM_STR (get_name ())); + + _pipeline->set_desc_pool (_desc_pool); + + _cmdbuf = VKCmdBuf::create_command_buffer (_device); + XCAM_FAIL_RETURN ( + ERROR, _cmdbuf.ptr (), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed when creating command buffers.", XCAM_STR (get_name ())); + + _fence = _device->create_fence (VK_FENCE_CREATE_SIGNALED_BIT); + XCAM_FAIL_RETURN ( + ERROR, _fence.ptr (), XCAM_RETURN_ERROR_VULKAN, + "vk woker(%s) build failed when creating fence.", XCAM_STR (get_name ())); + return XCAM_RETURN_NO_ERROR; +} + +// derived from Worker +XCamReturn +VKWorker::work (const SmartPtr<Worker::Arguments> &args) +{ + SmartPtr<VKArguments> vk_args = args.dynamic_cast_ptr<VKArguments>(); + XCAM_FAIL_RETURN ( + ERROR, vk_args.ptr(), XCAM_RETURN_ERROR_PARAM, + "vk woker(%s) work argements error.", XCAM_STR (get_name ())); + + VKDescriptor::SetBindInfoArray binding_array; + VKConstRange::VKPushConstArgs push_consts; + XCamReturn ret = vk_args->prepare_bindings (binding_array, push_consts); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk woker(%s) prepare argements failed.", XCAM_STR (get_name ())); + + XCAM_FAIL_RETURN ( + ERROR, !binding_array.empty (), XCAM_RETURN_ERROR_PARAM, + "vk woker(%s) binding_array is empty.", XCAM_STR (get_name ())); + + ret = _pipeline->update_bindings (binding_array); + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk woker(%s) update binding argements failed.", XCAM_STR (get_name ())); + + const WorkSize global = get_global_size (); + SmartPtr<VKCmdBuf::DispatchParam> dispatch = + new VKCmdBuf::DispatchParam (_pipeline, global.value[0], global.value[1], global.value[2]); + if (!push_consts.empty()) { + XCAM_FAIL_RETURN ( + ERROR, dispatch->update_push_consts (push_consts), XCAM_RETURN_ERROR_PARAM, + "vk woker(%s) update push-consts failed.", XCAM_STR (get_name ())); + } + + ret = _cmdbuf->record (dispatch); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk woker(%s) record cmdbuf failed.", XCAM_STR (get_name ())); + + ret = _device->compute_queue_submit (_cmdbuf, _fence); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "vk woker(%s) submit compute queue failed.", XCAM_STR (get_name ())); + + status_check (args, ret); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKWorker::stop () +{ + if (_pipeline.ptr () && _device.ptr ()) { + if (_fence.ptr ()) { + _fence->wait (); + _fence->reset (); + } + _device->compute_queue_wait_idle (); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +VKWorker::wait_fence () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (_fence.ptr ()) { + ret = _fence->wait (); + if (!xcam_ret_is_ok (ret)) { + XCAM_LOG_ERROR ("vk woker(%s) wait fence failed.", XCAM_STR (get_name ())); + } + _fence->reset (); + } + + return ret; +} + +} diff --git a/modules/vulkan/vk_worker.h b/modules/vulkan/vk_worker.h new file mode 100644 index 0000000..c23bd4d --- /dev/null +++ b/modules/vulkan/vk_worker.h @@ -0,0 +1,112 @@ +/* + * vk_worker.h - vulkan worker class + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_WORKER_H +#define XCAM_VK_WORKER_H + +#include <vulkan/vulkan_std.h> +#include <vulkan/vk_descriptor.h> +#include <worker.h> +#include <string> + +namespace XCam { + +class VKPipeline; +class VKDevice; +class VKFence; +class VKCmdBuf; + +enum VKSahderInfoType { + VKSahderInfoSpirVBinary = 0, + VKSahderInfoSpirVPath = 1, +}; + +struct VKShaderInfo { + VKSahderInfoType type; + std::string func_name; + std::string spirv_path; + std::vector<uint32_t> spirv_bin; + + VKShaderInfo () {} + VKShaderInfo (const char *func, const char *path) + : type (VKSahderInfoSpirVPath) + , func_name (func) + , spirv_path (path) + {} + VKShaderInfo (const char *func, const std::vector<uint32_t> &binary) + : type (VKSahderInfoSpirVBinary) + , func_name (func) + , spirv_bin (binary) + {} +}; + +class VKWorker + : public Worker +{ +public: + class VKArguments: + public Worker::Arguments + { + friend class VKWorker; + public: + VKArguments () {} + VKArguments (VKDescriptor::SetBindInfoArray &arr) + : _binding_bufs (arr) + {} + bool set_bindings (const VKDescriptor::SetBindInfoArray &arr); + bool add_binding (const VKDescriptor::SetBindInfo &info); + bool add_push_const (const SmartPtr<VKConstRange::VKPushConstArg> &push_const); + + protected: + virtual XCamReturn prepare_bindings ( + VKDescriptor::SetBindInfoArray &binding_array, + VKConstRange::VKPushConstArgs &push_consts); + private: + VKDescriptor::SetBindInfoArray _binding_bufs; + VKConstRange::VKPushConstArgs _push_consts; + }; + +public: + explicit VKWorker (SmartPtr<VKDevice> dev, const char *name, const SmartPtr<Callback> &cb = NULL); + virtual ~VKWorker (); + + XCamReturn build ( + const VKShaderInfo &info, + const VKDescriptor::BindingArray &bindings, + const VKConstRange::VKPushConstArgs &consts); + + // derived from Worker + virtual XCamReturn work (const SmartPtr<Arguments> &args); + virtual XCamReturn stop (); + XCamReturn wait_fence (); + +private: + XCAM_DEAD_COPY (VKWorker); + +private: + SmartPtr<VKDevice> _device; + SmartPtr<VKDescriptor::Pool> _desc_pool; + SmartPtr<VKPipeline> _pipeline; + SmartPtr<VKFence> _fence; + SmartPtr<VKCmdBuf> _cmdbuf; +}; + +} +#endif //XCAM_VK_WORKER_H diff --git a/modules/vulkan/vulkan_common.cpp b/modules/vulkan/vulkan_common.cpp new file mode 100644 index 0000000..6e7ec66 --- /dev/null +++ b/modules/vulkan/vulkan_common.cpp @@ -0,0 +1,77 @@ +/* + * vulkan_common.cpp - vulkan common + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#include "vulkan_common.h" +#include <map> + +#define VK_STR_INSERT(ERR) \ + vk_errors.insert (VkErrorMap::value_type(VK_ ##ERR, #ERR)) + +namespace XCam { + +typedef std::map <uint32_t, const char*> VkErrorMap; + +static VkErrorMap vk_errors; + +void vk_init_error_string () +{ + if (!vk_errors.empty ()) + return; + + VK_STR_INSERT (SUCCESS); + VK_STR_INSERT (NOT_READY); + VK_STR_INSERT (TIMEOUT); + VK_STR_INSERT (EVENT_SET); + VK_STR_INSERT (EVENT_RESET); + VK_STR_INSERT (INCOMPLETE); + VK_STR_INSERT (ERROR_OUT_OF_HOST_MEMORY); + VK_STR_INSERT (ERROR_OUT_OF_DEVICE_MEMORY); + VK_STR_INSERT (ERROR_INITIALIZATION_FAILED); + VK_STR_INSERT (ERROR_DEVICE_LOST); + VK_STR_INSERT (ERROR_MEMORY_MAP_FAILED); + VK_STR_INSERT (ERROR_LAYER_NOT_PRESENT); + VK_STR_INSERT (ERROR_FEATURE_NOT_PRESENT); + VK_STR_INSERT (ERROR_INCOMPATIBLE_DRIVER); + VK_STR_INSERT (ERROR_TOO_MANY_OBJECTS); + VK_STR_INSERT (ERROR_FORMAT_NOT_SUPPORTED); + VK_STR_INSERT (ERROR_FRAGMENTED_POOL); +} + +const char* +vk_error_str(VkResult id) +{ + VkErrorMap::iterator i = vk_errors.find (id); + if (i == vk_errors.end ()) + return "VkUnKnown"; + return i->second; +} + +const std::string +xcam_default_shader_path () +{ + std::string home = "~"; + const char *env = std::getenv ("HOME"); + if (env) + home.assign (env, strlen (env)); + + return home + "/.xcam/vk"; +} + +} diff --git a/modules/vulkan/vulkan_common.h b/modules/vulkan/vulkan_common.h new file mode 100644 index 0000000..8093029 --- /dev/null +++ b/modules/vulkan/vulkan_common.h @@ -0,0 +1,33 @@ +/* + * vulkan_common.h - vulkan common + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_COMMON_H +#define XCAM_VK_COMMON_H + +#include <vulkan/vulkan_std.h> +#include <string> + +namespace XCam { + +const char* vk_error_str(VkResult id); +const std::string xcam_default_shader_path (); +} + +#endif diff --git a/modules/vulkan/vulkan_std.h b/modules/vulkan/vulkan_std.h new file mode 100644 index 0000000..952645e --- /dev/null +++ b/modules/vulkan/vulkan_std.h @@ -0,0 +1,43 @@ +/* + * vulkan_std.h - vulkan common + * + * 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: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VK_STD_H +#define XCAM_VK_STD_H + +#include <xcam_std.h> +#include <vulkan/vulkan.h> + +#define XCAM_VK_CHECK_RETURN(LEVEL, vk_exp, failed_value, format, ...) \ + do { \ + VkResult err = vk_exp; \ + XCAM_FAIL_RETURN (LEVEL, err == VK_SUCCESS, failed_value, \ + format ", vk_error(%d:%s)", ## __VA_ARGS__, \ + (int)err, vk_error_str(err)); \ + } while (0) + + +#define XCAM_VK_NAME_LENGTH 256 + +#define XCAM_IS_VALID_VK_ID(id) (VK_NULL_HANDLE != (id)) + +#define XCAM_VK_SHADER_PATH "XCAM_VK_SHADER_PATH" +#define XCAM_DEFAULT_VK_SHADER_PATH xcam_default_shader_path() + +#endif |