From 12357ce2ec2b929a3a12e6690f8060cb28669a7d Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 23 Jul 2025 20:06:28 -0700 Subject: [PATCH 01/34] Updating coments --- framework/include/vx_context.h | 1 - framework/include/vx_convolution.h | 1 - framework/include/vx_debug.h | 1 - framework/include/vx_distribution.h | 7 +++---- framework/include/vx_error.h | 2 -- framework/include/vx_graph.h | 1 - framework/include/vx_image.h | 1 - framework/include/vx_import.h | 1 - framework/include/vx_internal.h | 1 - framework/include/vx_kernel.h | 1 - framework/include/vx_log.h | 3 +-- framework/include/vx_lut.h | 1 - framework/include/vx_matrix.h | 1 - framework/include/vx_meta_format.h | 1 - framework/include/vx_node.h | 1 - framework/include/vx_osal.h | 1 - framework/include/vx_parameter.h | 2 -- framework/include/vx_pyramid.h | 1 - framework/include/vx_remap.h | 1 - framework/include/vx_scalar.h | 1 - framework/include/vx_target.h | 1 - framework/include/vx_threshold.h | 1 - framework/src/vx_helper.cpp | 1 - framework/src/vx_node_api.cpp | 1 - 24 files changed, 4 insertions(+), 30 deletions(-) diff --git a/framework/include/vx_context.h b/framework/include/vx_context.h index f8e4531a..23b6e081 100644 --- a/framework/include/vx_context.h +++ b/framework/include/vx_context.h @@ -25,7 +25,6 @@ /*! * \file * \brief - * \author Erik Rainey * * \defgroup group_int_context Internal Context API * \ingroup group_internal diff --git a/framework/include/vx_convolution.h b/framework/include/vx_convolution.h index c9537469..d0fcdbf2 100644 --- a/framework/include/vx_convolution.h +++ b/framework/include/vx_convolution.h @@ -23,7 +23,6 @@ /*! * \file * \brief The internal convolution implementation - * \author Erik Rainey * * \defgroup group_int_convolution Internal Convolution API * \ingroup group_internal diff --git a/framework/include/vx_debug.h b/framework/include/vx_debug.h index ce96afc5..8d0a2c0e 100644 --- a/framework/include/vx_debug.h +++ b/framework/include/vx_debug.h @@ -29,7 +29,6 @@ /*! * \file - * \author Erik Rainey * * \defgroup group_int_debug Internal Debugging API * \ingroup group_internal diff --git a/framework/include/vx_distribution.h b/framework/include/vx_distribution.h index e75e2c3b..1911d3c4 100644 --- a/framework/include/vx_distribution.h +++ b/framework/include/vx_distribution.h @@ -22,16 +22,15 @@ /*! * \file * \brief The internal distribution implementation - * \author Erik Rainey * * \defgroup group_int_distribution Internal Distribution API * \ingroup group_internal * \brief The Internal Distribution API. */ - /*! \brief A Distribution. - * \ingroup group_int_distribution - */ +/*! \brief A Distribution. + * \ingroup group_int_distribution + */ class Distribution : public Reference { public: diff --git a/framework/include/vx_error.h b/framework/include/vx_error.h index ca56e39f..e6b0c21e 100644 --- a/framework/include/vx_error.h +++ b/framework/include/vx_error.h @@ -21,14 +21,12 @@ /*! * \file * \brief The internal error implementation - * \author Erik Rainey * * \defgroup group_int_error Internal Error API * \ingroup group_internal * \brief The Internal Error API. */ - /*! \brief The internal representation of the error object. * \ingroup group_int_error */ diff --git a/framework/include/vx_graph.h b/framework/include/vx_graph.h index 23261696..807225bc 100644 --- a/framework/include/vx_graph.h +++ b/framework/include/vx_graph.h @@ -25,7 +25,6 @@ /*! * \file * \brief The internal graph implementation - * \author Erik Rainey * * \defgroup group_int_graph Internal Graph API * \ingroup group_internal diff --git a/framework/include/vx_image.h b/framework/include/vx_image.h index 4088900f..bbfa5260 100644 --- a/framework/include/vx_image.h +++ b/framework/include/vx_image.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal image implementation - * \author Erik Rainey * * \defgroup group_int_image Internal Image API * \ingroup group_internal diff --git a/framework/include/vx_import.h b/framework/include/vx_import.h index f1dc7eff..b6c96f7f 100644 --- a/framework/include/vx_import.h +++ b/framework/include/vx_import.h @@ -23,7 +23,6 @@ /*! * \file * \brief The Import Object Internal API. - * \author Jesse Villarreal * * \defgroup group_int_import Internal Import Object API * \ingroup group_internal diff --git a/framework/include/vx_internal.h b/framework/include/vx_internal.h index 941f305b..928199c9 100644 --- a/framework/include/vx_internal.h +++ b/framework/include/vx_internal.h @@ -20,7 +20,6 @@ /*! * \file vx_internal.h * \brief The internal implementation header. - * \author Erik Rainey * * \defgroup group_internal OpenVX Implementation * \brief The OpenVX Implementation. diff --git a/framework/include/vx_kernel.h b/framework/include/vx_kernel.h index 343ffd4d..3699e1c4 100644 --- a/framework/include/vx_kernel.h +++ b/framework/include/vx_kernel.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal kernel implementation. - * \author Erik Rainey * * \defgroup group_int_kernel Internal Kernel API * \ingroup group_internal diff --git a/framework/include/vx_log.h b/framework/include/vx_log.h index a7b7f28b..3cff8615 100644 --- a/framework/include/vx_log.h +++ b/framework/include/vx_log.h @@ -21,11 +21,10 @@ /*! * \file * \brief The internal log implementation - * \author Erik Rainey * * \defgroup group_int_log Internal Log API * \ingroup group_internal * \brief The Internal Log API */ - #endif /* VX_LOG_H */ +#endif /* VX_LOG_H */ diff --git a/framework/include/vx_lut.h b/framework/include/vx_lut.h index 56b233e5..4d74070b 100644 --- a/framework/include/vx_lut.h +++ b/framework/include/vx_lut.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal LUT implementation - * \author Erik Rainey * * \defgroup group_int_lut Internal LUT API * \ingroup group_internal diff --git a/framework/include/vx_matrix.h b/framework/include/vx_matrix.h index 15e3fc49..22cd872f 100644 --- a/framework/include/vx_matrix.h +++ b/framework/include/vx_matrix.h @@ -21,7 +21,6 @@ /*! * \file * \brief The internal matrix implementation - * \author Erik Rainey * * \defgroup group_int_matrix Internal Matrix API * \ingroup group_internal diff --git a/framework/include/vx_meta_format.h b/framework/include/vx_meta_format.h index 9a28fe2d..96d5ce5d 100644 --- a/framework/include/vx_meta_format.h +++ b/framework/include/vx_meta_format.h @@ -23,7 +23,6 @@ /*! * \file * \brief The internal meta format implementation - * \author Erik Rainey * * \defgroup group_int_meta_format Internal Meta-Format API * \ingroup group_internal diff --git a/framework/include/vx_node.h b/framework/include/vx_node.h index 22980fa6..2850fa72 100644 --- a/framework/include/vx_node.h +++ b/framework/include/vx_node.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal node implementation. - * \author Erik Rainey * * \defgroup group_int_node Internal Node API * \ingroup group_internal diff --git a/framework/include/vx_osal.h b/framework/include/vx_osal.h index d0f0d933..e4ff0034 100644 --- a/framework/include/vx_osal.h +++ b/framework/include/vx_osal.h @@ -23,7 +23,6 @@ /*! * \file * \brief The internal operating system abstraction layer. - * \author Erik Rainey * * \defgroup group_int_osal Internal OSAL API * \ingroup group_internal diff --git a/framework/include/vx_parameter.h b/framework/include/vx_parameter.h index 960c0790..d8f6d015 100644 --- a/framework/include/vx_parameter.h +++ b/framework/include/vx_parameter.h @@ -21,14 +21,12 @@ /*! * \file * \brief The internal parameter implementation - * \author Erik Rainey * * \defgroup group_int_parameter Internal Parameter API * \ingroup group_internal * \brief The Internal Parameter API */ - /*! \brief The internal representation of a parameter. * \ingroup group_int_parameter */ diff --git a/framework/include/vx_pyramid.h b/framework/include/vx_pyramid.h index 61ab9040..8a0e1cf8 100644 --- a/framework/include/vx_pyramid.h +++ b/framework/include/vx_pyramid.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal pyramid implementation - * \author Erik Rainey * * \defgroup group_int_pyramid Internal Pyramid API * \ingroup group_internal diff --git a/framework/include/vx_remap.h b/framework/include/vx_remap.h index 933be83f..3ae9fb51 100644 --- a/framework/include/vx_remap.h +++ b/framework/include/vx_remap.h @@ -22,7 +22,6 @@ /*! * \file * \brief The Internal Remap API - * \author Erik Rainey * \defgroup group_int_remap Internal Remap API * \ingroup group_internal * \brief The Internal Remap API diff --git a/framework/include/vx_scalar.h b/framework/include/vx_scalar.h index 21bbf8ea..14c69a10 100644 --- a/framework/include/vx_scalar.h +++ b/framework/include/vx_scalar.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal scalars implementation. - * \author Erik Rainey * \defgroup group_int_scalar Internal Scalar API * \ingroup group_internal * \brief The Internal Scalar API. diff --git a/framework/include/vx_target.h b/framework/include/vx_target.h index 60b19606..8db3866c 100644 --- a/framework/include/vx_target.h +++ b/framework/include/vx_target.h @@ -22,7 +22,6 @@ /*! * \file * \brief The internal target implementation. - * \author Erik Rainey * \defgroup group_int_target Internal Target API * \ingroup group_internal * \brief The Internal Target API. diff --git a/framework/include/vx_threshold.h b/framework/include/vx_threshold.h index bd9ff1cf..fa7a6d08 100644 --- a/framework/include/vx_threshold.h +++ b/framework/include/vx_threshold.h @@ -21,7 +21,6 @@ /*! * \file * \brief The internal thresholds implementation. - * \author Erik Rainey * \defgroup group_int_threshold Internal Threshold API * \ingroup group_internal * \brief The Internal Threshold API. diff --git a/framework/src/vx_helper.cpp b/framework/src/vx_helper.cpp index be7e2c10..4b983c0c 100644 --- a/framework/src/vx_helper.cpp +++ b/framework/src/vx_helper.cpp @@ -26,7 +26,6 @@ /*! \file vx_helper.cpp * \brief The OpenVX Helper Implementation. - * \author Erik Rainey */ // no clue if this belongs here, but i don't know where better to put it. needed by c_scale.c and vx_scale.c diff --git a/framework/src/vx_node_api.cpp b/framework/src/vx_node_api.cpp index af254e19..5e22fb9a 100644 --- a/framework/src/vx_node_api.cpp +++ b/framework/src/vx_node_api.cpp @@ -17,7 +17,6 @@ /*! * \file * \brief The Graph Mode Interface for all Base Kernels. - * \author Erik Rainey */ #include "vx_internal.h" From f448890af37b99cc78fcac018122474bc03ccc67 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 14:48:07 -0700 Subject: [PATCH 02/34] Added debug zone --- framework/include/vx_debug.h | 31 ++++++++++++++++--------------- framework/src/vx_debug.cpp | 26 +++++++------------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/framework/include/vx_debug.h b/framework/include/vx_debug.h index 8d0a2c0e..18b56211 100644 --- a/framework/include/vx_debug.h +++ b/framework/include/vx_debug.h @@ -43,26 +43,27 @@ enum vx_debug_zone_e { VX_ZONE_WARNING = 1, /*!< Used to warning developers of possible issues */ VX_ZONE_API = 2, /*!< Used to trace API calls and return values */ VX_ZONE_INFO = 3, /*!< Used to show run-time processing debug */ + VX_ZONE_DEBUG = 4, /*!< Used to show detailed debug information */ - VX_ZONE_PERF = 4, /*!< Used to show performance information */ - VX_ZONE_CONTEXT = 5, - VX_ZONE_OSAL = 6, - VX_ZONE_REFERENCE = 7, + VX_ZONE_PERF = 5, /*!< Used to show performance information */ + VX_ZONE_CONTEXT = 6, /*!< Used to show only context logs */ + VX_ZONE_OSAL = 7, /*!< Used to show only OSAL logs */ + VX_ZONE_REFERENCE = 8, /*!< Used to show only reference logs */ - VX_ZONE_ARRAY = 8, - VX_ZONE_IMAGE = 9, - VX_ZONE_SCALAR = 10, - VX_ZONE_KERNEL = 11, + VX_ZONE_ARRAY = 9, /*!< Used to show only array logs */ + VX_ZONE_IMAGE = 10, /*!< Used to show only image logs */ + VX_ZONE_SCALAR = 11, /*!< Used to show only scalar logs */ + VX_ZONE_KERNEL = 12, /*!< Used to show only kernel logs */ - VX_ZONE_GRAPH = 12, - VX_ZONE_NODE = 13, - VX_ZONE_PARAMETER = 14, - VX_ZONE_DELAY = 15, + VX_ZONE_GRAPH = 13, /*!< Used to show only graph logs */ + VX_ZONE_NODE = 14, /*!< Used to show only node logs */ + VX_ZONE_PARAMETER = 15, /*!< Used to show only parameter logs */ + VX_ZONE_DELAY = 16, /*!< Used to show only delay logs */ - VX_ZONE_TARGET = 16, - VX_ZONE_LOG = 17, + VX_ZONE_TARGET = 17, /*!< Used to show only target logs */ + VX_ZONE_LOG = 18, /*!< Used to show only log logs */ - VX_ZONE_MAX = 32 + VX_ZONE_MAX = 32 /*!< The maximum number of zones */ }; #if defined(_WIN32) && !defined(__GNUC__) diff --git a/framework/src/vx_debug.cpp b/framework/src/vx_debug.cpp index a2e5adfa..8e1f472c 100644 --- a/framework/src/vx_debug.cpp +++ b/framework/src/vx_debug.cpp @@ -46,25 +46,13 @@ struct vx_string_and_enum_e { }; struct vx_string_and_enum_e enumnames[] = { - _STR2(VX_ZONE_ERROR), - _STR2(VX_ZONE_WARNING), - _STR2(VX_ZONE_API), - _STR2(VX_ZONE_INFO), - _STR2(VX_ZONE_PERF), - _STR2(VX_ZONE_CONTEXT), - _STR2(VX_ZONE_OSAL), - _STR2(VX_ZONE_REFERENCE), - _STR2(VX_ZONE_ARRAY), - _STR2(VX_ZONE_IMAGE), - _STR2(VX_ZONE_SCALAR), - _STR2(VX_ZONE_KERNEL), - _STR2(VX_ZONE_GRAPH), - _STR2(VX_ZONE_NODE), - _STR2(VX_ZONE_PARAMETER), - _STR2(VX_ZONE_DELAY), - _STR2(VX_ZONE_TARGET), - _STR2(VX_ZONE_LOG), - {"UNKNOWN", -1}, // if the zone is not found, this will be returned. + _STR2(VX_ZONE_ERROR), _STR2(VX_ZONE_WARNING), _STR2(VX_ZONE_API), + _STR2(VX_ZONE_INFO), _STR2(VX_ZONE_DEBUG), _STR2(VX_ZONE_PERF), + _STR2(VX_ZONE_CONTEXT), _STR2(VX_ZONE_OSAL), _STR2(VX_ZONE_REFERENCE), + _STR2(VX_ZONE_ARRAY), _STR2(VX_ZONE_IMAGE), _STR2(VX_ZONE_SCALAR), + _STR2(VX_ZONE_KERNEL), _STR2(VX_ZONE_GRAPH), _STR2(VX_ZONE_NODE), + _STR2(VX_ZONE_PARAMETER), _STR2(VX_ZONE_DELAY), _STR2(VX_ZONE_TARGET), + _STR2(VX_ZONE_LOG), {"UNKNOWN", -1}, // if the zone is not found, this will be returned. }; void vx_set_debug_zone(vx_enum zone) From 56895139c63ccccec5cfb68f196bc142f9144295 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 15:00:02 -0700 Subject: [PATCH 03/34] Reworked array --- framework/include/vx_array.h | 52 ++++ framework/src/vx_array.cpp | 460 ++++++++++++++++++++--------------- 2 files changed, 313 insertions(+), 199 deletions(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index 826a3def..f134d37b 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -136,6 +136,58 @@ class Array : public Reference */ vx_bool initVirtualArray(vx_enum item_type, vx_size capacity); + /** + * @brief Add items to array + * + * @param count number of items to add + * @param ptr pointer to data + * @param stride size of stride + * @return vx_status + * @ingroup group_int_array + */ + vx_status addItems(vx_size count, const void *ptr, vx_size stride); + + /** + * @brief Truncate array to new number of items + * + * @param new_num_items new number of items + * @return vx_status + * @ingroup group_int_array + */ + vx_status truncate(vx_size new_num_items); + + /** + * @brief Get item type of array + * + * @return vx_enum + * @ingroup group_int_array + */ + vx_enum itemType() const; + + /** + * @brief Get number of items in array + * + * @return vx_size + * @ingroup group_int_array + */ + vx_size numItems() const; + + /** + * @brief Get capacity of array + * + * @return vx_size + * @ingroup group_int_array + */ + vx_size totalCapacity() const; + + /** + * @brief Get item size in array + * + * @return vx_size + * @ingroup group_int_array + */ + vx_size itemSize() const; + /** * @brief Access array range in object * diff --git a/framework/src/vx_array.cpp b/framework/src/vx_array.cpp index 208d0eb7..186a425e 100644 --- a/framework/src/vx_array.cpp +++ b/framework/src/vx_array.cpp @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "vx_internal.h" #include "vx_context.h" +#include "vx_internal.h" +#include "vx_log.h" /******************************************************************************/ /* INTERNAL INTERFACE */ @@ -120,6 +121,7 @@ vx_status Array::accessArrayRange(vx_size start, vx_size end, vx_size *pStride, (ptr == nullptr) || (start >= end) || (end > num_items)) { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to access array range\n"); return VX_ERROR_INVALID_PARAMETERS; } @@ -140,6 +142,7 @@ vx_status Array::accessArrayRange(vx_size start, vx_size end, vx_size *pStride, */ if (allocateArray() == vx_false_e) { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate array memory\n"); return VX_ERROR_NO_MEMORY; } @@ -200,6 +203,9 @@ vx_status Array::accessArrayRange(vx_size start, vx_size end, vx_size *pStride, else { status = VX_ERROR_NO_MEMORY; + VX_PRINT(VX_ZONE_ERROR, + "Failed to allocate memory for COPY-ON-READ! Size=" VX_FMT_SIZE "\n", + size); vxAddLogEntry((vx_reference)this, status, "Failed to allocate memory for COPY-ON-READ! Size=" VX_FMT_SIZE "\n", size); } } @@ -261,6 +267,8 @@ vx_status Array::accessArrayRange(vx_size start, vx_size end, vx_size *pStride, else { status = VX_ERROR_NO_MEMORY; + VX_PRINT(VX_ZONE_ERROR, + "Failed to allocate memory for COPY-ON-READ! Size=" VX_FMT_SIZE "\n", size); vxAddLogEntry((vx_reference)this, status, "Failed to allocate memory for COPY-ON-READ! Size=" VX_FMT_SIZE "\n", size); } } @@ -271,12 +279,17 @@ vx_status Array::accessArrayRange(vx_size start, vx_size end, vx_size *pStride, vx_status Array::commitArrayRange(vx_size start, vx_size end, const void *ptr) { vx_status status = VX_ERROR_INVALID_REFERENCE; - vx_bool external = vx_true_e; /* assume that it was an allocated buffer */ if ((ptr == nullptr) || (start > end) || (end > num_items)) { + /* bad parameters */ + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to commit array range\n"); + VX_PRINT(VX_ZONE_DEBUG, + "start=" VX_FMT_SIZE ", end=" VX_FMT_SIZE ", num_items=" VX_FMT_SIZE + " , ptr=" VX_FMT_SIZE "\n ", + start, end, num_items, ptr); return VX_ERROR_INVALID_PARAMETERS; } @@ -292,6 +305,13 @@ vx_status Array::commitArrayRange(vx_size start, vx_size end, const void *ptr) /* framework trying to access a virtual array, this is ok. */ } + /* Ensure memory is allocated */ + if (allocateArray() == vx_false_e) + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate array memory\n"); + return VX_ERROR_NO_MEMORY; + } + /* VARIABLES: * 1.) ZERO_AREA * 2.) CONSTANT - independant @@ -336,12 +356,15 @@ vx_status Array::commitArrayRange(vx_size start, vx_size end, const void *ptr) { vx_size stride = *(vx_size *)context->accessors[index].extra_data; - if (stride == item_size) { + if (stride == item_size) + { memcpy(&beg_ptr[offset], ptr, len); } - else { + else + { int i; - const vx_uint8 *pSrc; vx_uint8 *pDest; + const vx_uint8 *pSrc; + vx_uint8 *pDest; for (i = (int)start, pSrc = (const vx_uint8*)ptr, pDest= &beg_ptr[offset]; i < (int)end; @@ -354,7 +377,8 @@ vx_status Array::commitArrayRange(vx_size start, vx_size end, const void *ptr) /* a write only or read/write copy */ context->removeAccessor(index); } - else { + else + { memcpy(&beg_ptr[offset], ptr, len); } } @@ -392,6 +416,34 @@ vx_status Array::copyArrayRange(vx_size start, vx_size end, vx_size stride, void vx_status status = VX_FAILURE; (void)mem_type; +#ifdef OPENVX_USE_OPENCL_INTEROP + void *ptr_given = ptr; + vx_enum mem_type_given = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + /* get ptr from OpenCL buffer for HOST */ + size_t size = 0; + cl_mem opencl_buf = (cl_mem)ptr; + cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyArrayRange: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + ptr = clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyArrayRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", opencl_buf, + (int)size, ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + /* bad parameters */ if (((usage != VX_READ_ONLY) && (VX_WRITE_ONLY != usage)) || (ptr == nullptr) || (stride < item_size) || @@ -480,6 +532,15 @@ vx_status Array::copyArrayRange(vx_size start, vx_size end, vx_size stride, void } } +#ifdef OPENVX_USE_OPENCL_INTEROP + if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)ptr_given, ptr, 0, nullptr, + nullptr); + clFinish(context->opencl_command_queue); + } +#endif + return status; } @@ -488,11 +549,24 @@ vx_status Array::mapArrayRange(vx_size start, vx_size end, vx_map_id *map_id, vx { vx_status status = VX_FAILURE; +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_enum mem_type_requested = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + /* bad parameters */ if ((usage < VX_READ_ONLY) || (VX_READ_AND_WRITE < usage) || (ptr == nullptr) || (stride == nullptr) || (start >= end) || (end > num_items)) { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to map array range\n"); + VX_PRINT(VX_ZONE_DEBUG, + "usage=" VX_FMT_SIZE ", ptr=" VX_FMT_SIZE ", stride=" VX_FMT_SIZE + ", start=" VX_FMT_SIZE ", end=" VX_FMT_SIZE ", num_items=" VX_FMT_SIZE "\n", + usage, ptr, stride, start, end, num_items); return VX_ERROR_INVALID_PARAMETERS; } @@ -513,6 +587,7 @@ vx_status Array::mapArrayRange(vx_size start, vx_size end, vx_map_id *map_id, vx */ if (allocateArray() == vx_false_e) { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate memory for array\n"); return VX_ERROR_NO_MEMORY; } @@ -544,6 +619,7 @@ vx_status Array::mapArrayRange(vx_size start, vx_size end, vx_map_id *map_id, vx } else { + VX_PRINT(VX_ZONE_ERROR, "Failed to lock sem for array memory map\n"); status = VX_ERROR_NO_RESOURCES; } } @@ -558,9 +634,34 @@ vx_status Array::mapArrayRange(vx_size start, vx_size end, vx_map_id *map_id, vx } else { + VX_PRINT(VX_ZONE_ERROR, "Failed to memory map array range\n"); status = VX_FAILURE; } +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_size sze = (end - start) * *stride; + if ((status == VX_SUCCESS) && context->opencl_context && + (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && (sze > 0) && ptr && *ptr) + { + /* create OpenCL buffer using the host allocated pointer */ + cl_int cerr = 0; + cl_mem opencl_buf = clCreateBuffer( + context->opencl_context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, sze, *ptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapArrayRange: clCreateBuffer(%u) => %p (%d)\n", + (vx_uint32)sze, opencl_buf, cerr); + if (cerr == CL_SUCCESS) + { + context->memory_maps[*map_id].opencl_buf = opencl_buf; + *ptr = opencl_buf; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to create OpenCL buffer for array map\n"); + status = VX_FAILURE; + } + } +#endif + return status; } @@ -568,6 +669,21 @@ vx_status Array::unmapArrayRange(vx_map_id map_id) { vx_status status = VX_FAILURE; +#ifdef OPENVX_USE_OPENCL_INTEROP + if (context->opencl_context && context->memory_maps[map_id].opencl_buf && + context->memory_maps[map_id].ptr) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, + context->memory_maps[map_id].opencl_buf, + context->memory_maps[map_id].ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + cl_int cerr = clReleaseMemObject(context->memory_maps[map_id].opencl_buf); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapArrayRange: clReleaseMemObject(%p) => (%d)\n", + context->memory_maps[map_id].opencl_buf, cerr); + context->memory_maps[map_id].opencl_buf = nullptr; + } +#endif + /* determine if virtual before checking for memory */ if (is_virtual == vx_true_e) { @@ -682,64 +798,137 @@ void Array::initArrayMemory() memory.dims[0][1] = (vx_uint32)capacity; } +vx_enum Array::itemType() const +{ + return item_type; +} + +vx_size Array::numItems() const +{ + return num_items; +} + +vx_size Array::totalCapacity() const +{ + return capacity; +} + +vx_size Array::itemSize() const +{ + return item_size; +} + +vx_status Array::addItems(vx_size count, const void *ptr, vx_size stride) +{ + vx_status status = VX_ERROR_NO_MEMORY; + + if (allocateArray() == vx_true_e) + { + status = VX_ERROR_INVALID_PARAMETERS; + + if ((count > 0) && (ptr != nullptr) && (stride >= item_size)) + { + status = VX_FAILURE; + + if (num_items + count <= capacity) + { + vx_size offset = num_items * item_size; + vx_uint8 *dst_ptr = &memory.ptrs[0][offset]; + + vx_size i; + for (i = 0; i < count; ++i) + { + vx_uint8 *src_ptr = (vx_uint8 *)ptr; + memcpy(&dst_ptr[i * item_size], &src_ptr[i * stride], item_size); + } + + num_items += count; + + status = VX_SUCCESS; + } + } + } + + return status; +} + +vx_status Array::truncate(vx_size new_num_items) +{ + vx_status status = VX_FAILURE; + + if (new_num_items <= capacity && + new_num_items <= num_items) + { + num_items = new_num_items; + status = VX_SUCCESS; + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + + return status; +} + void Array::printArray(vx_array array) { - VX_PRINT(VX_ZONE_INFO, "Array:%p has %zu elements of %04x type of %zu size each.\n", array, array->capacity, array->item_type, array->item_size); + VX_PRINT(VX_ZONE_INFO, "Array:%p has %zu elements of %04x type of %zu size each.\n", array, + array->capacity, array->item_type, array->item_size); } /******************************************************************************/ /* PUBLIC INTERFACE */ /******************************************************************************/ -VX_API_ENTRY vx_array VX_API_CALL vxCreateArray(vx_context context, vx_enum item_type, vx_size capacity) +VX_API_ENTRY vx_array VX_API_CALL vxCreateArray(vx_context context, vx_enum item_type, + vx_size capacity) { vx_array arr = nullptr; - if (Context::isValidContext(context) == vx_true_e) + if (Context::isValidContext(context) == vx_true_e && + (Array::isValidArrayItemType(context, item_type) == vx_true_e) && (capacity > 0)) { - if ( (Array::isValidArrayItemType(context, item_type) == vx_true_e) && - (capacity > 0)) - { - arr = (vx_array)Array::createArray(context, item_type, capacity, vx_false_e, VX_TYPE_ARRAY); + arr = (vx_array)Array::createArray(context, item_type, capacity, vx_false_e, VX_TYPE_ARRAY); - if (arr == nullptr) - { - arr = (vx_array)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); - } - } - else + if (arr == nullptr) { - arr = (vx_array)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + arr = (vx_array)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); } } + else + { + arr = (vx_array)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } return arr; } -VX_API_ENTRY vx_array VX_API_CALL vxCreateVirtualArray(vx_graph graph, vx_enum item_type, vx_size capacity) +VX_API_ENTRY vx_array VX_API_CALL vxCreateVirtualArray(vx_graph graph, vx_enum item_type, + vx_size capacity) { vx_array arr = nullptr; - if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) + if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == + vx_true_e && + ((Array::isValidArrayItemType(graph->context, item_type) == vx_true_e) || + item_type == VX_TYPE_INVALID)) { - if (((Array::isValidArrayItemType(graph->context, item_type) == vx_true_e) || item_type == VX_TYPE_INVALID)) - { - arr = (vx_array)Array::createArray(graph->context, item_type, capacity, vx_true_e, VX_TYPE_ARRAY); + arr = (vx_array)Array::createArray(graph->context, item_type, capacity, vx_true_e, + VX_TYPE_ARRAY); - if (arr && arr->type == VX_TYPE_ARRAY) - { - arr->scope = (vx_reference)graph; - } - else - { - arr = (vx_array)vxGetErrorObject(graph->context, VX_ERROR_NO_MEMORY); - } + if (arr && arr->type == VX_TYPE_ARRAY) + { + arr->scope = (vx_reference)graph; } else { - arr = (vx_array)vxGetErrorObject(graph->context, VX_ERROR_INVALID_PARAMETERS); + arr = (vx_array)vxGetErrorObject(graph->context, VX_ERROR_NO_MEMORY); } } + else + { + arr = (vx_array)vxGetErrorObject(graph->context, VX_ERROR_INVALID_PARAMETERS); + } return arr; } @@ -754,14 +943,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxReleaseArray(vx_array *a) vx_array arr = *(a); if (Reference::isValidReference(arr, VX_TYPE_ARRAY) == vx_true_e) { - status = Reference::releaseReference((vx_reference*)a, VX_TYPE_ARRAY, VX_EXTERNAL, nullptr); + status = + Reference::releaseReference((vx_reference *)a, VX_TYPE_ARRAY, VX_EXTERNAL, nullptr); } } return status; } -VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, void *ptr, vx_size size) +VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, void *ptr, + vx_size size) { vx_status status = VX_ERROR_INVALID_REFERENCE; if (Array::isValidArray(arr) == vx_true_e) @@ -772,7 +963,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, case VX_ARRAY_ITEMTYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = arr->item_type; + *(vx_enum *)ptr = arr->itemType(); } else { @@ -783,7 +974,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, case VX_ARRAY_NUMITEMS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = arr->num_items; + *(vx_size *)ptr = arr->numItems(); } else { @@ -794,7 +985,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, case VX_ARRAY_CAPACITY: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = arr->capacity; + *(vx_size *)ptr = arr->totalCapacity(); } else { @@ -805,7 +996,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, case VX_ARRAY_ITEMSIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = arr->item_size; + *(vx_size *)ptr = arr->itemSize(); } else { @@ -822,66 +1013,34 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryArray(vx_array arr, vx_enum attribute, return status; } -VX_API_ENTRY vx_status VX_API_CALL vxAddArrayItems(vx_array arr, vx_size count, const void *ptr, vx_size stride) +VX_API_ENTRY vx_status VX_API_CALL vxAddArrayItems(vx_array arr, vx_size count, const void *ptr, + vx_size stride) { - vx_status status = VX_ERROR_INVALID_REFERENCE; - if (Array::isValidArray(arr) == vx_true_e) + /* bad references */ + if (Array::isValidArray(arr) == vx_false_e) { - status = VX_ERROR_NO_MEMORY; - - if (arr->allocateArray() == vx_true_e) - { - status = VX_ERROR_INVALID_PARAMETERS; - - if ((count > 0) && (ptr != nullptr) && (stride >= arr->item_size)) - { - status = VX_FAILURE; - - if (arr->num_items + count <= arr->capacity) - { - vx_size offset = arr->num_items * arr->item_size; - vx_uint8 *dst_ptr = &arr->memory.ptrs[0][offset]; - - vx_size i; - for (i = 0; i < count; ++i) - { - vx_uint8 *src_ptr = (vx_uint8 *)ptr; - memcpy(&dst_ptr[i * arr->item_size], &src_ptr[i * stride], arr->item_size); - } - - arr->num_items += count; - // ownWroteToReference(&arr->base); - - status = VX_SUCCESS; - } - } - } + VX_PRINT(VX_ZONE_ERROR, "Not a valid array!\n"); + return VX_ERROR_INVALID_REFERENCE; } - return status; + return arr->addItems(count, ptr, stride); } VX_API_ENTRY vx_status VX_API_CALL vxTruncateArray(vx_array arr, vx_size new_num_items) { - vx_status status = VX_ERROR_INVALID_REFERENCE; - if (Array::isValidArray(arr) == vx_true_e) + /* bad references */ + if (Array::isValidArray(arr) == vx_false_e) { - status = VX_ERROR_INVALID_PARAMETERS; - - if (new_num_items <= arr->num_items) - { - arr->num_items = new_num_items; - // ownWroteToReference(&arr->base); - - status = VX_SUCCESS; - } + VX_PRINT(VX_ZONE_ERROR, "Not a valid array!\n"); + return VX_ERROR_INVALID_REFERENCE; } - return status; + + return arr->truncate(new_num_items); } -VX_API_ENTRY vx_status VX_API_CALL vxAccessArrayRange(vx_array arr, vx_size start, vx_size end, vx_size *stride, void **ptr, vx_enum usage) +VX_API_ENTRY vx_status VX_API_CALL vxAccessArrayRange(vx_array arr, vx_size start, vx_size end, + vx_size *stride, void **ptr, vx_enum usage) { - vx_status status = VX_FAILURE; /* bad references */ if (Array::isValidArray(arr) == vx_false_e) { @@ -889,30 +1048,26 @@ VX_API_ENTRY vx_status VX_API_CALL vxAccessArrayRange(vx_array arr, vx_size star return VX_ERROR_INVALID_REFERENCE; } - /* bad parameters */ - if (stride == nullptr) - { - return VX_ERROR_INVALID_PARAMETERS; - } - - status = arr->accessArrayRange(start, end, stride, ptr, usage); - - return status; + return arr->accessArrayRange(start, end, stride, ptr, usage); } -VX_API_ENTRY vx_status VX_API_CALL vxCommitArrayRange(vx_array arr, vx_size start, vx_size end, const void *ptr) +VX_API_ENTRY vx_status VX_API_CALL vxCommitArrayRange(vx_array arr, vx_size start, vx_size end, + const void *ptr) { + /* bad references */ if (Array::isValidArray(arr) == vx_false_e) { + VX_PRINT(VX_ZONE_ERROR, "Not a valid array!\n"); return VX_ERROR_INVALID_REFERENCE; } + return arr->commitArrayRange(start, end, ptr); } -VX_API_ENTRY vx_status VX_API_CALL vxCopyArrayRange(vx_array arr, vx_size start, vx_size end, vx_size stride, - void *ptr, vx_enum usage, vx_enum mem_type) +VX_API_ENTRY vx_status VX_API_CALL vxCopyArrayRange(vx_array arr, vx_size start, vx_size end, + vx_size stride, void *ptr, vx_enum usage, + vx_enum mem_type) { - vx_status status = VX_FAILURE; /* bad references */ if (Array::isValidArray(arr) == vx_false_e) { @@ -920,52 +1075,13 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyArrayRange(vx_array arr, vx_size start, return VX_ERROR_INVALID_REFERENCE; } -#ifdef OPENVX_USE_OPENCL_INTEROP - void * ptr_given = ptr; - vx_enum mem_type_given = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - /* get ptr from OpenCL buffer for HOST */ - size_t size = 0; - cl_mem opencl_buf = (cl_mem)ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyArrayRange: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - ptr = clEnqueueMapBuffer(arr->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyArrayRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - - status = arr->copyArrayRange(start, end, stride, ptr, usage, mem_type); - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(arr->context->opencl_command_queue, - (cl_mem)ptr_given, ptr, 0, nullptr, nullptr); - clFinish(arr->context->opencl_command_queue); - } -#endif - - return status; + return arr->copyArrayRange(start, end, stride, ptr, usage, mem_type); } -VX_API_ENTRY vx_status VX_API_CALL vxMapArrayRange(vx_array arr, vx_size start, vx_size end, vx_map_id *map_id, vx_size *stride, - void **ptr, vx_enum usage, vx_enum mem_type, vx_uint32 flags) +VX_API_ENTRY vx_status VX_API_CALL vxMapArrayRange(vx_array arr, vx_size start, vx_size end, + vx_map_id *map_id, vx_size *stride, void **ptr, + vx_enum usage, vx_enum mem_type, vx_uint32 flags) { - vx_status status = VX_FAILURE; /* bad references */ if (Array::isValidArray(arr) == vx_false_e) { @@ -973,47 +1089,11 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapArrayRange(vx_array arr, vx_size start, return VX_ERROR_INVALID_REFERENCE; } -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_enum mem_type_requested = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - - status = arr->mapArrayRange(start, end, map_id, stride, ptr, usage, mem_type, flags); - -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_size size = (end - start) * *stride; - if ((status == VX_SUCCESS) && arr->context->opencl_context && - (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && - (size > 0) && ptr && *ptr) - { - /* create OpenCL buffer using the host allocated pointer */ - cl_int cerr = 0; - cl_mem opencl_buf = clCreateBuffer(arr->context->opencl_context, - CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, - size, *ptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapArrayRange: clCreateBuffer(%u) => %p (%d)\n", - (vx_uint32)size, opencl_buf, cerr); - if (cerr == CL_SUCCESS) - { - arr->context->memory_maps[*map_id].opencl_buf = opencl_buf; - *ptr = opencl_buf; - } - else - { - status = VX_FAILURE; - } - } -#endif - - return status; + return arr->mapArrayRange(start, end, map_id, stride, ptr, usage, mem_type, flags); } VX_API_ENTRY vx_status VX_API_CALL vxUnmapArrayRange(vx_array arr, vx_map_id map_id) { - vx_status status = VX_FAILURE; /* bad references */ if (Array::isValidArray(arr) == vx_false_e) { @@ -1021,23 +1101,5 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapArrayRange(vx_array arr, vx_map_id map return VX_ERROR_INVALID_REFERENCE; } -#ifdef OPENVX_USE_OPENCL_INTEROP - if (arr->context->opencl_context && - arr->context->memory_maps[map_id].opencl_buf && - arr->context->memory_maps[map_id].ptr) - { - clEnqueueUnmapMemObject(arr->context->opencl_command_queue, - arr->context->memory_maps[map_id].opencl_buf, - arr->context->memory_maps[map_id].ptr, 0, nullptr, nullptr); - clFinish(arr->context->opencl_command_queue); - cl_int cerr = clReleaseMemObject(arr->context->memory_maps[map_id].opencl_buf); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapArrayRange: clReleaseMemObject(%p) => (%d)\n", - arr->context->memory_maps[map_id].opencl_buf, cerr); - arr->context->memory_maps[map_id].opencl_buf = nullptr; - } -#endif - - status = arr->unmapArrayRange(map_id); - - return status; + return arr->unmapArrayRange(map_id); } From 3b08ba47e6bafbf0d8d08a48872dd0ebf64add0a Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 17:33:38 -0700 Subject: [PATCH 04/34] Reworked matrix and convolution --- framework/include/vx_convolution.h | 57 +++++- framework/include/vx_matrix.h | 71 ++++++- framework/src/vx_convolution.cpp | 318 +++++++++++++++++------------ framework/src/vx_matrix.cpp | 310 ++++++++++++++++------------ 4 files changed, 494 insertions(+), 262 deletions(-) diff --git a/framework/include/vx_convolution.h b/framework/include/vx_convolution.h index d0fcdbf2..63ba5770 100644 --- a/framework/include/vx_convolution.h +++ b/framework/include/vx_convolution.h @@ -44,6 +44,59 @@ class Convolution : public Matrix */ Convolution(vx_context context, vx_reference scope); + /** + * @brief Get the scale factor of the convolution + * + * @return vx_uint32 The scale factor + * @ingroup group_int_convolution + */ + vx_uint32 scaleFactor() const; + + /** + * @brief Get the size of the convolution in bytes + * + * @return vx_size The size in bytes + * @ingroup group_int_convolution + */ + vx_size size() const; + + /** + * @brief Set the scale factor of the convolution + * + * @param value The scale factor to set + * @ingroup group_int_convolution + */ + void setScale(vx_uint32 value); + + /** + * @brief Read the coefficients of the convolution + * + * @param array The array to read coefficients into + * @return vx_status The status of the operation + * @ingroup group_int_convolution + */ + vx_status readCoefficients(vx_int16 *array); + + /** + * @brief Write the coefficients of the convolution + * + * @param array The array containing coefficients to write + * @return vx_status The status of the operation + * @ingroup group_int_convolution + */ + vx_status writeCoefficients(const vx_int16 *array); + + /** + * @brief Copy the coefficients to a specified memory location + * + * @param ptr Pointer to the memory location + * @param usage Memory usage type + * @param mem_type Memory type (e.g., host, device) + * @return vx_status The status of the operation + * @ingroup group_int_convolution + */ + vx_status copyCoefficients(void *ptr, vx_enum usage, vx_enum mem_type); + /** * @brief Destroy the Convolution object * @ingroup group_int_convolution @@ -55,7 +108,9 @@ class Convolution : public Matrix */ void destruct() override final; - /*! \brief The Scale Factor. */ + /*! \brief The Scale Factor. + * \ingroup group_int_convolution + */ vx_uint32 scale; }; diff --git a/framework/include/vx_matrix.h b/framework/include/vx_matrix.h index 22cd872f..4bc1d39e 100644 --- a/framework/include/vx_matrix.h +++ b/framework/include/vx_matrix.h @@ -52,6 +52,75 @@ class Matrix : public Reference */ Matrix(vx_context context, vx_type_e type, vx_reference scope); + /** + * @brief Get the data type of the matrix + * + * @return vx_enum The data type of the matrix + * @ingroup group_int_matrix + */ + vx_enum dataType() const; + + /** + * @brief Get the number of rows in the matrix. + * + * @return vx_size The number of rows in the matrix. + * @ingroup group_int_matrix + */ + vx_size numRows() const; + + /** + * @brief Get the number of columns in the matrix. + * + * @return vx_size The number of columns in the matrix. + * @ingroup group_int_matrix + */ + vx_size numCols() const; + + /** + * @brief Get the origin coordinates of the matrix. + * + * @return vx_coordinates2d_t The origin coordinates of the matrix. + * @ingroup group_int_matrix + */ + vx_coordinates2d_t originCoord() const; + + /** + * @brief Get the pattern type of the matrix. + * + * @return vx_enum The pattern type of the matrix. + * @ingroup group_int_matrix + */ + vx_enum patternType() const; + + /** + * @brief Read the matrix data into an array. + * + * @param array The array to read the matrix data into. + * @return vx_status The status of the operation. + * @ingroup group_int_matrix + */ + vx_status read(void *array); + + /** + * @brief Write the matrix data from an array. + * + * @param array The array containing the matrix data to write. + * @return vx_status The status of the operation. + * @ingroup group_int_matrix + */ + vx_status write(const void *array); + + /** + * @brief Copy the matrix data to/from a pointer. + * + * @param ptr The pointer to copy the matrix data to/from. + * @param usage The usage flags for the memory operation. + * @param mem_type The type of memory used (e.g., OpenCL buffer). + * @return vx_status The status of the operation. + * @ingroup group_int_matrix + */ + vx_status copy(void *ptr, vx_enum usage, vx_enum mem_type); + /** * @brief Destroy the Matrix object * @ingroup group_int_matrix @@ -71,7 +140,7 @@ class Matrix : public Reference vx_size columns; /*! \brief Number of rows */ vx_size rows; - /*! \brief Origin */ + /*! \brief Origin Coordinates */ vx_coordinates2d_t origin; /*! \brief Pattern */ vx_enum pattern; diff --git a/framework/src/vx_convolution.cpp b/framework/src/vx_convolution.cpp index 606aab71..27c081d8 100644 --- a/framework/src/vx_convolution.cpp +++ b/framework/src/vx_convolution.cpp @@ -20,8 +20,8 @@ /******************************************************************************/ /* INTERNAL INTERFACE */ /******************************************************************************/ -Convolution::Convolution(vx_context context, vx_reference scope) : Matrix(context, VX_TYPE_CONVOLUTION, scope), -scale() +Convolution::Convolution(vx_context context, vx_reference scope) + : Matrix(context, VX_TYPE_CONVOLUTION, scope), scale() { } @@ -30,30 +30,166 @@ Convolution::~Convolution() { } -void Convolution::destruct() +vx_uint32 Convolution::scaleFactor() const { - Memory::freeMemory(context, &memory); + return scale; } -/******************************************************************************/ -/* PUBLIC INTERFACE */ -/******************************************************************************/ -VX_API_ENTRY vx_status VX_API_CALL vxReleaseConvolution(vx_convolution* convolution) +vx_size Convolution::size() const { - vx_status status = VX_FAILURE; + return columns * rows * sizeof(vx_int16); +} - if (nullptr != convolution) +void Convolution::setScale(vx_uint32 value) +{ + if (vxIsPowerOfTwo(scale) == vx_true_e) { - vx_convolution conv = *convolution; - if (vx_true_e == Reference::isValidReference(conv, VX_TYPE_CONVOLUTION)) + VX_PRINT(VX_ZONE_INFO, "Convolution Scale assigned to %u\n", scale); + scale = value; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Convolution Scale must be a power of two, got %u\n", value); + } +} + +vx_status Convolution::readCoefficients(vx_int16 *array) +{ + vx_status status = VX_ERROR_NO_MEMORY; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) + { + Osal::semWait(&lock); + if (array) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(array, memory.ptrs[0], size); + } + Osal::semPost(&lock); + // ownReadFromReference(&convolution); + status = VX_SUCCESS; + } + + return status; +} + +vx_status Convolution::writeCoefficients(const vx_int16 *array) +{ + vx_status status = VX_ERROR_NO_MEMORY; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) + { + Osal::semWait(&lock); + if (array) { - status = Reference::releaseReference((vx_reference*)convolution, VX_TYPE_CONVOLUTION, VX_EXTERNAL, nullptr); + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + + memcpy(memory.ptrs[0], array, size); } + Osal::semPost(&lock); + // ownWroteToReference(&convolution); + status = VX_SUCCESS; } return status; } +vx_status Convolution::copyCoefficients(void *ptr, vx_enum usage, vx_enum mem_type) +{ + vx_status status = VX_ERROR_NO_MEMORY; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) + { +#ifdef OPENVX_USE_OPENCL_INTEROP + void *ptr_given = ptr; + vx_enum mem_type_given = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + size_t size = 0; + cl_mem opencl_buf = (cl_mem)ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyConvolutionCoefficients: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT( + VX_ZONE_CONTEXT, + "OPENCL: vxCopyConvolutionCoefficients: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + + if (usage == VX_READ_ONLY) + { + Osal::semWait(&lock); + if (ptr) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(ptr, memory.ptrs[0], size); + } + Osal::semPost(&lock); + // ownReadFromReference(&convolution); + status = VX_SUCCESS; + } + else if (usage == VX_WRITE_ONLY) + { + Osal::semWait(&lock); + if (ptr) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + + memcpy(memory.ptrs[0], ptr, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&convolution); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for convolution\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)ptr_given, ptr, 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); + } +#endif + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate convolution\n"); + status = VX_ERROR_NO_MEMORY; + } + + return status; +} + +void Convolution::destruct() +{ + Memory::freeMemory(context, &memory); +} + +/******************************************************************************/ +/* PUBLIC INTERFACE */ +/******************************************************************************/ + VX_API_ENTRY vx_convolution VX_API_CALL vxCreateConvolution(vx_context context, vx_size columns, vx_size rows) { vx_convolution convolution = nullptr; @@ -85,6 +221,25 @@ VX_API_ENTRY vx_convolution VX_API_CALL vxCreateConvolution(vx_context context, return convolution; } +VX_API_ENTRY vx_convolution VX_API_CALL vxCreateVirtualConvolution(vx_graph graph, vx_size columns, + vx_size rows) +{ + vx_convolution convolution = nullptr; + + if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) + { + convolution = vxCreateConvolution(graph->context, columns, rows); + if (vxGetStatus((vx_reference)convolution) == VX_SUCCESS && + convolution->type == VX_TYPE_CONVOLUTION) + { + convolution->scope = (vx_reference)graph; + convolution->is_virtual = vx_true_e; + } + } + /* else, the graph is invalid, we can't get any context and then error object */ + return convolution; +} + VX_API_ENTRY vx_status VX_API_CALL vxQueryConvolution(vx_convolution convolution, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -97,7 +252,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryConvolution(vx_convolution convolution case VX_CONVOLUTION_ROWS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = convolution->rows; + *(vx_size *)ptr = convolution->numRows(); } else { @@ -107,7 +262,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryConvolution(vx_convolution convolution case VX_CONVOLUTION_COLUMNS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = convolution->columns; + *(vx_size *)ptr = convolution->numCols(); } else { @@ -117,7 +272,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryConvolution(vx_convolution convolution case VX_CONVOLUTION_SCALE: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = convolution->scale; + *(vx_uint32 *)ptr = convolution->scaleFactor(); } else { @@ -127,7 +282,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryConvolution(vx_convolution convolution case VX_CONVOLUTION_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = convolution->columns * convolution->rows * sizeof(vx_int16); + *(vx_size *)ptr = convolution->size(); } else { @@ -156,8 +311,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetConvolutionAttribute(vx_convolution conv vx_uint32 scale = *(vx_uint32 *)ptr; if (vxIsPowerOfTwo(scale) == vx_true_e) { - VX_PRINT(VX_ZONE_INFO, "Convolution Scale assigned to %u\n", scale); - convolution->scale = scale; + convolution->setScale(scale); } else { @@ -183,19 +337,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetConvolutionAttribute(vx_convolution conv VX_API_ENTRY vx_status VX_API_CALL vxReadConvolutionCoefficients(vx_convolution convolution, vx_int16 *array) { vx_status status = VX_ERROR_INVALID_REFERENCE; - if ((Reference::isValidReference(convolution, VX_TYPE_CONVOLUTION) == vx_true_e) && - (Memory::allocateMemory(convolution->context, &convolution->memory) == vx_true_e)) + if (Reference::isValidReference(convolution, VX_TYPE_CONVOLUTION) == vx_true_e) { - Osal::semWait(&convolution->lock); - if (array) - { - vx_size size = convolution->memory.strides[0][1] * - convolution->memory.dims[0][1]; - memcpy(array, convolution->memory.ptrs[0], size); - } - Osal::semPost(&convolution->lock); - // ownReadFromReference(&convolution); - status = VX_SUCCESS; + status = convolution->readCoefficients(array); } return status; } @@ -203,20 +347,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxReadConvolutionCoefficients(vx_convolution VX_API_ENTRY vx_status VX_API_CALL vxWriteConvolutionCoefficients(vx_convolution convolution, const vx_int16 *array) { vx_status status = VX_ERROR_INVALID_REFERENCE; - if ((Reference::isValidReference(convolution, VX_TYPE_CONVOLUTION) == vx_true_e) && - (Memory::allocateMemory(convolution->context, &convolution->memory) == vx_true_e)) + if (Reference::isValidReference(convolution, VX_TYPE_CONVOLUTION) == vx_true_e) { - Osal::semWait(&convolution->lock); - if (array) - { - vx_size size = convolution->memory.strides[0][1] * - convolution->memory.dims[0][1]; - - memcpy(convolution->memory.ptrs[0], array, size); - } - Osal::semPost(&convolution->lock); - // ownWroteToReference(&convolution); - status = VX_SUCCESS; + status = convolution->writeCoefficients(array); } return status; } @@ -224,87 +357,10 @@ VX_API_ENTRY vx_status VX_API_CALL vxWriteConvolutionCoefficients(vx_convolution vx_status VX_API_CALL vxCopyConvolutionCoefficients(vx_convolution convolution, void *ptr, vx_enum usage, vx_enum mem_type) { vx_status status = VX_ERROR_INVALID_REFERENCE; - (void)mem_type; if (Reference::isValidReference(convolution, VX_TYPE_CONVOLUTION) == vx_true_e) { - if (Memory::allocateMemory(convolution->context, &convolution->memory) == vx_true_e) - { -#ifdef OPENVX_USE_OPENCL_INTEROP - void * ptr_given = ptr; - vx_enum mem_type_given = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - // get ptr from OpenCL buffer for HOST - size_t size = 0; - cl_mem opencl_buf = (cl_mem)ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyConvolutionCoefficients: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - ptr = clEnqueueMapBuffer(convolution->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyConvolutionCoefficients: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - - if (usage == VX_READ_ONLY) - { - Osal::semWait(&convolution->lock); - if (ptr) - { - vx_size size = convolution->memory.strides[0][1] * - convolution->memory.dims[0][1]; - memcpy(ptr, convolution->memory.ptrs[0], size); - } - Osal::semPost(&convolution->lock); - // ownReadFromReference(&convolution); - status = VX_SUCCESS; - } - else if (usage == VX_WRITE_ONLY) - { - Osal::semWait(&convolution->lock); - if (ptr) - { - vx_size size = convolution->memory.strides[0][1] * - convolution->memory.dims[0][1]; - - memcpy(convolution->memory.ptrs[0], ptr, size); - } - Osal::semPost(&convolution->lock); - // ownWroteToReference(&convolution); - status = VX_SUCCESS; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for convolution\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(convolution->context->opencl_command_queue, - (cl_mem)ptr_given, ptr, 0, nullptr, nullptr); - clFinish(convolution->context->opencl_command_queue); - } -#endif - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate convolution\n"); - status = VX_ERROR_NO_MEMORY; - } + status = convolution->copyCoefficients(ptr, usage, mem_type); } else { @@ -313,19 +369,19 @@ vx_status VX_API_CALL vxCopyConvolutionCoefficients(vx_convolution convolution, return status; } -VX_API_ENTRY vx_convolution VX_API_CALL vxCreateVirtualConvolution(vx_graph graph, vx_size columns, vx_size rows) +VX_API_ENTRY vx_status VX_API_CALL vxReleaseConvolution(vx_convolution *convolution) { - vx_convolution convolution = nullptr; + vx_status status = VX_FAILURE; - if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) + if (nullptr != convolution) { - convolution = vxCreateConvolution(graph->context, columns, rows); - if (vxGetStatus((vx_reference)convolution) == VX_SUCCESS && convolution->type == VX_TYPE_CONVOLUTION) + vx_convolution conv = *convolution; + if (vx_true_e == Reference::isValidReference(conv, VX_TYPE_CONVOLUTION)) { - convolution->scope = (vx_reference)graph; - convolution->is_virtual = vx_true_e; + status = Reference::releaseReference((vx_reference *)convolution, VX_TYPE_CONVOLUTION, + VX_EXTERNAL, nullptr); } } - /* else, the graph is invalid, we can't get any context and then error object */ - return convolution; + + return status; } diff --git a/framework/src/vx_matrix.cpp b/framework/src/vx_matrix.cpp index 025d1c03..9dae5e28 100644 --- a/framework/src/vx_matrix.cpp +++ b/framework/src/vx_matrix.cpp @@ -42,35 +42,177 @@ pattern() } -Matrix::~Matrix() +vx_enum Matrix::dataType() const { + return data_type; +} +vx_size Matrix::numRows() const +{ + return rows; } -void Matrix::destruct() +vx_size Matrix::numCols() const { - Memory::freeMemory(context, &memory); + return columns; } -/******************************************************************************/ -/* PUBLIC INTERFACE */ -/******************************************************************************/ -VX_API_ENTRY vx_status VX_API_CALL vxReleaseMatrix(vx_matrix* mat) +vx_coordinates2d_t Matrix::originCoord() const { - vx_status status = VX_FAILURE; + return origin; +} - if (mat) +vx_enum Matrix::patternType() const +{ + return pattern; +} + +vx_status Matrix::read(void *array) +{ + vx_status status = VX_SUCCESS; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) { - vx_matrix matrix = *mat; - if (Reference::isValidReference(matrix, VX_TYPE_MATRIX)) + Osal::semWait(&lock); + if (array) { - status = Reference::releaseReference((vx_reference*)mat, VX_TYPE_MATRIX, VX_EXTERNAL, nullptr); + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(array, memory.ptrs[0], size); } + Osal::semPost(&lock); + // ownReadFromReference(&matrix); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); + status = VX_ERROR_NO_MEMORY; + } + + return status; +} + +vx_status Matrix::write(const void *array) +{ + vx_status status = VX_SUCCESS; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) + { + Osal::semWait(&lock); + if (array) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(memory.ptrs[0], array, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&matrix); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); + status = VX_ERROR_NO_MEMORY; } return status; } +vx_status Matrix::copy(void *ptr, vx_enum usage, vx_enum mem_type) +{ + vx_status status = VX_SUCCESS; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) + { +#ifdef OPENVX_USE_OPENCL_INTEROP + void *ptr_given = ptr; + vx_enum mem_type_given = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + size_t size = 0; + cl_mem opencl_buf = (cl_mem)ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyMatrix: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyMatrix: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", opencl_buf, + (int)size, ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + if (usage == VX_READ_ONLY) + { + Osal::semWait(&lock); + if (ptr) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(ptr, memory.ptrs[0], size); + } + Osal::semPost(&lock); + // ownReadFromReference(&matrix); + status = VX_SUCCESS; + } + else if (usage == VX_WRITE_ONLY) + { + Osal::semWait(&lock); + if (ptr) + { + vx_size size = memory.strides[0][1] * memory.dims[0][1]; + memcpy(memory.ptrs[0], ptr, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&matrix); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for matrix\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)ptr_given, ptr, 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); + } +#endif + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); + status = VX_ERROR_NO_MEMORY; + } + + return status; +} + +Matrix::~Matrix() +{ + +} + +void Matrix::destruct() +{ + Memory::freeMemory(context, &memory); +} + +/******************************************************************************/ +/* PUBLIC INTERFACE */ +/******************************************************************************/ VX_API_ENTRY vx_matrix VX_API_CALL vxCreateMatrix(vx_context context, vx_enum data_type, vx_size columns, vx_size rows) { vx_matrix matrix = nullptr; @@ -221,6 +363,7 @@ VX_API_ENTRY vx_matrix VX_API_CALL vxCreateMatrixFromPatternAndOrigin(vx_context } return matrix; } + VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -233,7 +376,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = matrix->data_type; + *(vx_enum *)ptr = matrix->dataType(); } else { @@ -243,7 +386,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_ROWS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = matrix->rows; + *(vx_size *)ptr = matrix->numRows(); } else { @@ -253,7 +396,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_COLUMNS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = matrix->columns; + *(vx_size *)ptr = matrix->numCols(); } else { @@ -263,7 +406,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = matrix->columns * matrix->rows * matrix->memory.dims[0][0]; + *(vx_size *)ptr = matrix->numCols() * matrix->numRows() * matrix->memory.dims[0][0]; } else { @@ -273,7 +416,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_ORIGIN: if (VX_CHECK_PARAM(ptr, size, vx_coordinates2d_t, 0x3)) { - *(vx_coordinates2d_t*)ptr = matrix->origin; + *(vx_coordinates2d_t*)ptr = matrix->originCoord(); } else { @@ -283,7 +426,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryMatrix(vx_matrix matrix, vx_enum attri case VX_MATRIX_PATTERN: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum*)ptr = matrix->pattern; + *(vx_enum*)ptr = matrix->patternType(); } else { @@ -302,24 +445,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxReadMatrix(vx_matrix matrix, void *array) vx_status status = VX_ERROR_INVALID_REFERENCE; if (Reference::isValidReference(matrix, VX_TYPE_MATRIX) == vx_true_e) { - if (Memory::allocateMemory(matrix->context, &matrix->memory) == vx_true_e) - { - Osal::semWait(&matrix->lock); - if (array) - { - vx_size size = matrix->memory.strides[0][1] * - matrix->memory.dims[0][1]; - memcpy(array, matrix->memory.ptrs[0], size); - } - Osal::semPost(&matrix->lock); - // ownReadFromReference(&matrix); - status = VX_SUCCESS; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); - status = VX_ERROR_NO_MEMORY; - } + status = matrix->read(array); } else { @@ -333,24 +459,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxWriteMatrix(vx_matrix matrix, const void *a vx_status status = VX_ERROR_INVALID_REFERENCE; if (Reference::isValidReference(matrix, VX_TYPE_MATRIX) == vx_true_e) { - if (Memory::allocateMemory(matrix->context, &matrix->memory) == vx_true_e) - { - Osal::semWait(&matrix->lock); - if (array) - { - vx_size size = matrix->memory.strides[0][1] * - matrix->memory.dims[0][1]; - memcpy(matrix->memory.ptrs[0], array, size); - } - Osal::semPost(&matrix->lock); - // ownWroteToReference(&matrix); - status = VX_SUCCESS; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); - status = VX_ERROR_NO_MEMORY; - } + status = matrix->write(array); } else { @@ -366,81 +475,7 @@ vx_status VX_API_CALL vxCopyMatrix(vx_matrix matrix, void *ptr, vx_enum usage, v if (Reference::isValidReference(matrix, VX_TYPE_MATRIX) == vx_true_e) { - if (Memory::allocateMemory(matrix->context, &matrix->memory) == vx_true_e) - { -#ifdef OPENVX_USE_OPENCL_INTEROP - void * ptr_given = ptr; - vx_enum mem_type_given = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - // get ptr from OpenCL buffer for HOST - size_t size = 0; - cl_mem opencl_buf = (cl_mem)ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyMatrix: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - ptr = clEnqueueMapBuffer(matrix->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyMatrix: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - if (usage == VX_READ_ONLY) - { - Osal::semWait(&matrix->lock); - if (ptr) - { - vx_size size = matrix->memory.strides[0][1] * - matrix->memory.dims[0][1]; - memcpy(ptr, matrix->memory.ptrs[0], size); - } - Osal::semPost(&matrix->lock); - // ownReadFromReference(&matrix); - status = VX_SUCCESS; - } - else if (usage == VX_WRITE_ONLY) - { - Osal::semWait(&matrix->lock); - if (ptr) - { - vx_size size = matrix->memory.strides[0][1] * - matrix->memory.dims[0][1]; - memcpy(matrix->memory.ptrs[0], ptr, size); - } - Osal::semPost(&matrix->lock); - // ownWroteToReference(&matrix); - status = VX_SUCCESS; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for matrix\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(matrix->context->opencl_command_queue, - (cl_mem)ptr_given, ptr, 0, nullptr, nullptr); - clFinish(matrix->context->opencl_command_queue); - } -#endif - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate matrix\n"); - status = VX_ERROR_NO_MEMORY; - } + status = matrix->copy(ptr, usage, mem_type); } else { @@ -448,3 +483,20 @@ vx_status VX_API_CALL vxCopyMatrix(vx_matrix matrix, void *ptr, vx_enum usage, v } return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseMatrix(vx_matrix *mat) +{ + vx_status status = VX_FAILURE; + + if (mat) + { + vx_matrix matrix = *mat; + if (Reference::isValidReference(matrix, VX_TYPE_MATRIX)) + { + status = Reference::releaseReference((vx_reference *)mat, VX_TYPE_MATRIX, VX_EXTERNAL, + nullptr); + } + } + + return status; +} From 5838066fcb4cfd1cf41a20d5341c2d27920ac88d Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 18:13:16 -0700 Subject: [PATCH 05/34] Reworked distribution --- framework/include/vx_distribution.h | 101 +++++ framework/src/vx_distribution.cpp | 681 ++++++++++++++++------------ 2 files changed, 483 insertions(+), 299 deletions(-) diff --git a/framework/include/vx_distribution.h b/framework/include/vx_distribution.h index 1911d3c4..e73b176c 100644 --- a/framework/include/vx_distribution.h +++ b/framework/include/vx_distribution.h @@ -43,6 +43,107 @@ class Distribution : public Reference */ Distribution(vx_context context, vx_reference scope); + /** + * @brief Get the number of dimensions in the distribution + * + * @return vx_size The number of dimensions + * @ingroup group_int_distribution + */ + vx_size dims() const; + + /** + * @brief Get the range of the distribution + * + * @return vx_uint32 The range value + * @ingroup group_int_distribution + */ + vx_uint32 range() const; + + /** + * @brief Get the number of bins in the distribution + * + * @return vx_size The number of bins + * @ingroup group_int_distribution + */ + vx_size bins() const; + + /** + * @brief Get the window size of the distribution + * + * @return vx_uint32 The window size + * @ingroup group_int_distribution + */ + vx_uint32 window() const; + + /** + * @brief Get the offset of the distribution + * + * @return vx_int32 The offset value + * @ingroup group_int_distribution + */ + vx_int32 offset() const; + + /** + * @brief Get the size of the distribution in bytes + * + * @return vx_size The size in bytes + * @ingroup group_int_distribution + */ + vx_uint32 size() const; + + /** + * @brief Access the distribution data + * + * @param ptr The pointer to the data to access + * @param usage The usage of the memory (read/write) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_distribution + */ + vx_status access(void **ptr, vx_enum usage); + + /** + * @brief Commit the distribution with the given data + * + * @param ptr The pointer to the data to commit + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_distribution + */ + vx_status commit(const void *ptr); + + /** + * @brief Copy the distribution data to/from user memory + * + * @param user_ptr The pointer to the user memory + * @param usage The usage of the memory (read/write) + * @param mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_distribution + */ + vx_status copy(void *user_ptr, vx_enum usage, vx_enum mem_type); + + /** + * @brief Map the distribution to a memory map + * + * @param map_id The map id to use + * @param ptr The pointer to the mapped memory + * @param usage The usage of the memory (read/write) + * @param mem_type The type of memory (host, opencl, etc.) + * @param flags Additional flags for mapping + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_distribution + */ + vx_status map(vx_map_id *map_id, void **ptr, vx_enum usage, vx_enum mem_type, + vx_bitfield flags); + + /** + * @brief Unmap the distribution from the memory map + * + * @param map_id The map id to unmap + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_distribution + */ + vx_status unmap(vx_map_id map_id); + /** * @brief Destroy the Distribution object * @ingroup group_int_distribution diff --git a/framework/src/vx_distribution.cpp b/framework/src/vx_distribution.cpp index 70005098..d3f22471 100644 --- a/framework/src/vx_distribution.cpp +++ b/framework/src/vx_distribution.cpp @@ -29,267 +29,119 @@ offset_y(0) { } -Distribution::~Distribution() +vx_size Distribution::dims() const { + return (vx_size)(memory.ndims - 1); } -void Distribution::destruct() +vx_uint32 Distribution::range() const { - Memory::freeMemory(context, &memory); + return (vx_uint32)(range_x); } -/******************************************************************************/ -/* PUBLIC INTERFACE */ -/******************************************************************************/ -VX_API_ENTRY vx_distribution VX_API_CALL vxCreateDistribution(vx_context context, vx_size numBins, vx_int32 offset, vx_uint32 range) +vx_size Distribution::bins() const { - vx_distribution distribution = nullptr; - - if (Context::isValidContext(context) == vx_true_e) - { - if ((numBins != 0) && (range != 0)) - { - distribution = (vx_distribution)Reference::createReference(context, VX_TYPE_DISTRIBUTION, VX_EXTERNAL, context); - if ( vxGetStatus((vx_reference)distribution) == VX_SUCCESS && - distribution->type == VX_TYPE_DISTRIBUTION) - { - distribution->memory.ndims = 2; - distribution->memory.nptrs = 1; - distribution->memory.strides[0][VX_DIM_C] = sizeof(vx_int32); - distribution->memory.dims[0][VX_DIM_C] = 1; - distribution->memory.dims[0][VX_DIM_X] = (vx_uint32)numBins; - distribution->memory.dims[0][VX_DIM_Y] = 1; - distribution->range_x = (vx_uint32)range; - distribution->range_y = 1; - distribution->offset_x = offset; - distribution->offset_y = 0; - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to distribution\n"); - vxAddLogEntry(context, VX_ERROR_INVALID_PARAMETERS, "Invalid parameters to distribution\n"); - distribution = (vx_distribution)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - } - } - - return distribution; -} - -VX_API_ENTRY vx_distribution VX_API_CALL vxCreateVirtualDistribution( vx_graph graph, vx_size numBins, vx_int32 offset, vx_uint32 range) -{ - vx_distribution distribution = nullptr; - vx_reference gref = (vx_reference)graph; - - if (Reference::isValidReference(gref, VX_TYPE_GRAPH) == vx_true_e) - { - distribution = vxCreateDistribution(gref->context, numBins, offset, range); - if (vxGetStatus((vx_reference)distribution) == VX_SUCCESS && distribution->type == VX_TYPE_DISTRIBUTION) - { - distribution->scope = (vx_reference)graph; - distribution->is_virtual = vx_true_e; - } - } - return distribution; + return (vx_size)memory.dims[0][VX_DIM_X]; } -vx_status vxReleaseDistributionInt(vx_distribution* distribution) +vx_uint32 Distribution::window() const { - vx_status status = VX_ERROR_INVALID_REFERENCE; - - if (nullptr != distribution) - { - vx_reference ref = *distribution; - if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_DISTRIBUTION)) - { - status = Reference::releaseReference((vx_reference*)distribution, VX_TYPE_DISTRIBUTION, VX_INTERNAL, nullptr); - } - } - - return status; + vx_size nbins = (vx_size)memory.dims[0][VX_DIM_X]; + vx_uint32 range = (vx_uint32)(range_x); + vx_uint32 window = (vx_uint32)(range / nbins); + if (window * nbins == range) + return window; + else + return 0; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseDistribution(vx_distribution *d) +vx_int32 Distribution::offset() const { - vx_status status = VX_ERROR_INVALID_REFERENCE; - - if (nullptr != d) - { - vx_reference ref = *d; - if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_DISTRIBUTION)) - { - status = Reference::releaseReference((vx_reference*)d, VX_TYPE_DISTRIBUTION, VX_EXTERNAL, nullptr); - } - } - - return status; + return offset_x; } -VX_API_ENTRY vx_status VX_API_CALL vxQueryDistribution(vx_distribution distribution, vx_enum attribute, void *ptr, vx_size size) +vx_uint32 Distribution::size() const { - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) == vx_false_e) - return VX_ERROR_INVALID_REFERENCE; - - switch (attribute) - { - case VX_DISTRIBUTION_DIMENSIONS: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) - { - *(vx_size*)ptr = (vx_size)(distribution->memory.ndims - 1); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_DISTRIBUTION_RANGE: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32*)ptr = (vx_uint32)(distribution->range_x); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_DISTRIBUTION_BINS: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) - { - *(vx_size*)ptr = (vx_size)distribution->memory.dims[0][VX_DIM_X]; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_DISTRIBUTION_WINDOW: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - vx_size nbins = (vx_size)distribution->memory.dims[0][VX_DIM_X]; - vx_uint32 range = (vx_uint32)(distribution->range_x); - vx_uint32 window = (vx_uint32)(range / nbins); - if (window*nbins == range) - *(vx_uint32*)ptr = window; - else - *(vx_uint32*)ptr = 0; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_DISTRIBUTION_OFFSET: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) - { - *(vx_int32*)ptr = distribution->offset_x; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_DISTRIBUTION_SIZE: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) - { - *(vx_size*)ptr = distribution->memory.strides[0][VX_DIM_C] * - distribution->memory.dims[0][VX_DIM_X]; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; - } - return status; + return memory.strides[0][VX_DIM_C] * memory.dims[0][VX_DIM_X]; } -VX_API_ENTRY vx_status VX_API_CALL vxAccessDistribution(vx_distribution distribution, void **ptr, vx_enum usage) +vx_status Distribution::access(void **ptr, vx_enum usage) { - vx_status status = VX_FAILURE; + vx_status status = VX_ERROR_NO_MEMORY; (void)usage; - if ((Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) == vx_true_e) && - (Memory::allocateMemory(distribution->context, &distribution->memory) == vx_true_e)) + if (Memory::allocateMemory(context, &memory) == vx_true_e) { if (ptr != nullptr) { - Osal::semWait(&distribution->lock); + Osal::semWait(&lock); { - vx_size size = Memory::computeMemorySize(&distribution->memory, 0); - Memory::printMemory(&distribution->memory); + vx_size size = Memory::computeMemorySize(&memory, 0); + Memory::printMemory(&memory); if (*ptr == nullptr) { - *ptr = distribution->memory.ptrs[0]; + *ptr = memory.ptrs[0]; } else if (*ptr != nullptr) { - memcpy(*ptr, distribution->memory.ptrs[0], size); + memcpy(*ptr, memory.ptrs[0], size); } } - Osal::semPost(&distribution->lock); - // ownReadFromReference(&distribution->base); + Osal::semPost(&lock); + // ownReadFromReference(&base); } - distribution->incrementReference(VX_EXTERNAL); + incrementReference(VX_EXTERNAL); status = VX_SUCCESS; } - else - { - VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); - } + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxCommitDistribution(vx_distribution distribution, const void *ptr) +vx_status Distribution::commit(const void *ptr) { - vx_status status = VX_FAILURE; - if ((Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) == vx_true_e) && - (Memory::allocateMemory(distribution->context, &distribution->memory) == vx_true_e)) + vx_status status = VX_ERROR_NO_MEMORY; + + if (Memory::allocateMemory(context, &memory) == vx_true_e) { if (ptr != nullptr) { - Osal::semWait(&distribution->lock); + Osal::semWait(&lock); { - if (ptr != distribution->memory.ptrs[0]) + if (ptr != memory.ptrs[0]) { - vx_size size = Memory::computeMemorySize(&distribution->memory, 0); - memcpy(distribution->memory.ptrs[0], ptr, size); - VX_PRINT(VX_ZONE_INFO, "Copied distribution from %p to %p for " VX_FMT_SIZE " bytes\n", ptr, distribution->memory.ptrs[0], size); + vx_size size = Memory::computeMemorySize(&memory, 0); + memcpy(memory.ptrs[0], ptr, size); + VX_PRINT(VX_ZONE_INFO, + "Copied distribution from %p to %p for " VX_FMT_SIZE " bytes\n", ptr, + memory.ptrs[0], size); } } - Osal::semPost(&distribution->lock); - // ownWroteToReference(&distribution->base); + Osal::semPost(&lock); + // ownWroteToReference(&base); } - distribution->decrementReference(VX_EXTERNAL); + decrementReference(VX_EXTERNAL); status = VX_SUCCESS; } - else - { - VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); - } + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxCopyDistribution(vx_distribution distribution, void *user_ptr, vx_enum usage, vx_enum mem_type) +vx_status Distribution::copy(void *user_ptr, vx_enum usage, vx_enum mem_type) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; vx_size size = 0; /* bad references */ - if ((Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) || - (Memory::allocateMemory(distribution->context, &distribution->memory) != vx_true_e)) + if (Memory::allocateMemory(context, &memory) != vx_true_e) { - status = VX_ERROR_INVALID_REFERENCE; - VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + status = VX_ERROR_NO_MEMORY; + VX_PRINT(VX_ZONE_ERROR, "Distribution object not allocated!\n"); return status; } /* bad parameters */ - if (((usage != VX_READ_ONLY) && (usage != VX_WRITE_ONLY)) || - (user_ptr == nullptr) || (mem_type != VX_MEMORY_TYPE_HOST)) + if (((usage != VX_READ_ONLY) && (usage != VX_WRITE_ONLY)) || (user_ptr == nullptr) || + (mem_type != VX_MEMORY_TYPE_HOST)) { status = VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to copy distribution\n"); @@ -297,11 +149,11 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyDistribution(vx_distribution distributi } /* copy data */ - size = Memory::computeMemorySize(&distribution->memory, 0); - Memory::printMemory(&distribution->memory); + size = Memory::computeMemorySize(&memory, 0); + Memory::printMemory(&memory); #ifdef OPENVX_USE_OPENCL_INTEROP - void * user_ptr_given = user_ptr; + void *user_ptr_given = user_ptr; vx_enum mem_type_given = mem_type; if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) { @@ -310,16 +162,17 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyDistribution(vx_distribution distributi cl_mem opencl_buf = (cl_mem)user_ptr; cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyDistribution: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); + opencl_buf, cerr); if (cerr != CL_SUCCESS) { return VX_ERROR_INVALID_PARAMETERS; } - user_ptr = clEnqueueMapBuffer(distribution->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyDistribution: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, user_ptr, cerr); + user_ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyDistribution: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", opencl_buf, + (int)size, user_ptr, cerr); if (cerr != CL_SUCCESS) { return VX_ERROR_INVALID_PARAMETERS; @@ -330,50 +183,50 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyDistribution(vx_distribution distributi switch (usage) { - case VX_READ_ONLY: - if (Osal::semWait(&distribution->lock) == vx_true_e) - { - memcpy(user_ptr, distribution->memory.ptrs[0], size); - Osal::semPost(&distribution->lock); + case VX_READ_ONLY: + if (Osal::semWait(&lock) == vx_true_e) + { + memcpy(user_ptr, memory.ptrs[0], size); + Osal::semPost(&lock); - // ownReadFromReference(&distribution->base); - status = VX_SUCCESS; - } - break; - case VX_WRITE_ONLY: - if (Osal::semWait(&distribution->lock) == vx_true_e) - { - memcpy(distribution->memory.ptrs[0], user_ptr, size); - Osal::semPost(&distribution->lock); + // ownReadFromReference(&base); + status = VX_SUCCESS; + } + break; + case VX_WRITE_ONLY: + if (Osal::semWait(&lock) == vx_true_e) + { + memcpy(memory.ptrs[0], user_ptr, size); + Osal::semPost(&lock); - // ownWroteToReference(&distribution->base); - status = VX_SUCCESS; - } - break; + // ownWroteToReference(&base); + status = VX_SUCCESS; + } + break; } #ifdef OPENVX_USE_OPENCL_INTEROP if (mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) { - clEnqueueUnmapMemObject(distribution->context->opencl_command_queue, - (cl_mem)user_ptr_given, user_ptr, 0, nullptr, nullptr); - clFinish(distribution->context->opencl_command_queue); + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)user_ptr_given, user_ptr, 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); } #endif return status; } -VX_API_ENTRY vx_status VX_API_CALL vxMapDistribution(vx_distribution distribution, vx_map_id *map_id, void **ptr, vx_enum usage, vx_enum mem_type, vx_bitfield flags) +vx_status Distribution::map(vx_map_id *map_id, void **ptr, vx_enum usage, vx_enum mem_type, + vx_bitfield flags) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; vx_size size = 0; /* bad references */ - if ((Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) || - (Memory::allocateMemory(distribution->context, &distribution->memory) != vx_true_e)) + if (Memory::allocateMemory(context, &memory) != vx_true_e) { - status = VX_ERROR_INVALID_REFERENCE; + status = VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); return status; } @@ -396,48 +249,46 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapDistribution(vx_distribution distributio } /* map data */ - size = Memory::computeMemorySize(&distribution->memory, 0); - Memory::printMemory(&distribution->memory); + size = Memory::computeMemorySize(&memory, 0); + Memory::printMemory(&memory); - if (distribution->context->memoryMap((vx_reference)distribution, size, usage, mem_type, flags, nullptr, ptr, map_id) == vx_true_e) + if (context->memoryMap((vx_reference)this, size, usage, mem_type, flags, nullptr, ptr, + map_id) == vx_true_e) { switch (usage) { - case VX_READ_ONLY: - case VX_READ_AND_WRITE: - if (Osal::semWait(&distribution->lock) == vx_true_e) - { - memcpy(*ptr, distribution->memory.ptrs[0], size); - Osal::semPost(&distribution->lock); + case VX_READ_ONLY: + case VX_READ_AND_WRITE: + if (Osal::semWait(&lock) == vx_true_e) + { + memcpy(*ptr, memory.ptrs[0], size); + Osal::semPost(&lock); - // ownReadFromReference(&distribution->base); + // ownReadFromReference(&base); + status = VX_SUCCESS; + } + break; + case VX_WRITE_ONLY: status = VX_SUCCESS; - } - break; - case VX_WRITE_ONLY: - status = VX_SUCCESS; - break; + break; } - if (status == VX_SUCCESS) - distribution->incrementReference(VX_EXTERNAL); + if (status == VX_SUCCESS) incrementReference(VX_EXTERNAL); } #ifdef OPENVX_USE_OPENCL_INTEROP - if ((status == VX_SUCCESS) && distribution->context->opencl_context && - (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && - (size > 0) && ptr && *ptr) + if ((status == VX_SUCCESS) && context->opencl_context && + (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && (size > 0) && ptr && *ptr) { /* create OpenCL buffer using the host allocated pointer */ cl_int cerr = 0; - cl_mem opencl_buf = clCreateBuffer(distribution->context->opencl_context, - CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, - size, *ptr, &cerr); + cl_mem opencl_buf = clCreateBuffer( + context->opencl_context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, size, *ptr, &cerr); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapDistribution: clCreateBuffer(%u) => %p (%d)\n", - (vx_uint32)size, opencl_buf, cerr); + (vx_uint32)size, opencl_buf, cerr); if (cerr == CL_SUCCESS) { - distribution->context->memory_maps[*map_id].opencl_buf = opencl_buf; + context->memory_maps[*map_id].opencl_buf = opencl_buf; *ptr = opencl_buf; } else @@ -450,76 +301,308 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapDistribution(vx_distribution distributio return status; } -VX_API_ENTRY vx_status VX_API_CALL vxUnmapDistribution(vx_distribution distribution, vx_map_id map_id) +vx_status Distribution::unmap(vx_map_id map_id) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; vx_size size = 0; - /* bad references */ - if ((Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) || - (Memory::allocateMemory(distribution->context, &distribution->memory) != vx_true_e)) + if (Memory::allocateMemory(context, &memory) != vx_true_e) { - status = VX_ERROR_INVALID_REFERENCE; - VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); - return status; + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate memory for distribution\n"); + return VX_ERROR_NO_MEMORY; } /* bad parameters */ - if (distribution->context->findMemoryMap((vx_reference)distribution, map_id) != vx_true_e) + if (context->findMemoryMap((vx_reference)this, map_id) != vx_true_e) { - status = VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to unmap distribution\n"); - return status; + return VX_ERROR_INVALID_PARAMETERS; } #ifdef OPENVX_USE_OPENCL_INTEROP - if (distribution->context->opencl_context && - distribution->context->memory_maps[map_id].opencl_buf && - distribution->context->memory_maps[map_id].ptr) + if (context->opencl_context && context->memory_maps[map_id].opencl_buf && + context->memory_maps[map_id].ptr) { - clEnqueueUnmapMemObject(distribution->context->opencl_command_queue, - distribution->context->memory_maps[map_id].opencl_buf, - distribution->context->memory_maps[map_id].ptr, 0, nullptr, nullptr); - clFinish(distribution->context->opencl_command_queue); - cl_int cerr = clReleaseMemObject(distribution->context->memory_maps[map_id].opencl_buf); + clEnqueueUnmapMemObject(context->opencl_command_queue, + context->memory_maps[map_id].opencl_buf, + context->memory_maps[map_id].ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + cl_int cerr = clReleaseMemObject(context->memory_maps[map_id].opencl_buf); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapDistribution: clReleaseMemObject(%p) => (%d)\n", - distribution->context->memory_maps[map_id].opencl_buf, cerr); - distribution->context->memory_maps[map_id].opencl_buf = nullptr; + context->memory_maps[map_id].opencl_buf, cerr); + context->memory_maps[map_id].opencl_buf = nullptr; } #endif /* unmap data */ - size = Memory::computeMemorySize(&distribution->memory, 0); - Memory::printMemory(&distribution->memory); + size = Memory::computeMemorySize(&memory, 0); + Memory::printMemory(&memory); { vx_uint32 id = (vx_uint32)map_id; - vx_memory_map_t* map = &distribution->context->memory_maps[id]; + vx_memory_map_t *map = &context->memory_maps[id]; switch (map->usage) { - case VX_READ_ONLY: - status = VX_SUCCESS; - break; - case VX_READ_AND_WRITE: - case VX_WRITE_ONLY: - if (Osal::semWait(&distribution->lock) == vx_true_e) - { - memcpy(distribution->memory.ptrs[0], map->ptr, size); - Osal::semPost(&distribution->lock); - - // ownWroteToReference(&distribution->base); + case VX_READ_ONLY: status = VX_SUCCESS; - } - break; + break; + case VX_READ_AND_WRITE: + case VX_WRITE_ONLY: + if (Osal::semWait(&lock) == vx_true_e) + { + memcpy(memory.ptrs[0], map->ptr, size); + Osal::semPost(&lock); + + // ownWroteToReference(&base); + status = VX_SUCCESS; + } + break; } - distribution->context->memoryUnmap((vx_uint32)map_id); + context->memoryUnmap((vx_uint32)map_id); /* regardless of the current status, if we're here, so previous call to vxMapDistribution() * was successful and thus ref was locked once by a call to ownIncrementReference() */ - distribution->decrementReference(VX_EXTERNAL); + decrementReference(VX_EXTERNAL); + } + + return status; +} + +Distribution::~Distribution() +{ +} + +void Distribution::destruct() +{ + Memory::freeMemory(context, &memory); +} + +/******************************************************************************/ +/* PUBLIC INTERFACE */ +/******************************************************************************/ +VX_API_ENTRY vx_distribution VX_API_CALL vxCreateDistribution(vx_context context, vx_size numBins, vx_int32 offset, vx_uint32 range) +{ + vx_distribution distribution = nullptr; + + if (Context::isValidContext(context) == vx_true_e) + { + if ((numBins != 0) && (range != 0)) + { + distribution = (vx_distribution)Reference::createReference(context, VX_TYPE_DISTRIBUTION, VX_EXTERNAL, context); + if ( vxGetStatus((vx_reference)distribution) == VX_SUCCESS && + distribution->type == VX_TYPE_DISTRIBUTION) + { + distribution->memory.ndims = 2; + distribution->memory.nptrs = 1; + distribution->memory.strides[0][VX_DIM_C] = sizeof(vx_int32); + distribution->memory.dims[0][VX_DIM_C] = 1; + distribution->memory.dims[0][VX_DIM_X] = (vx_uint32)numBins; + distribution->memory.dims[0][VX_DIM_Y] = 1; + distribution->range_x = (vx_uint32)range; + distribution->range_y = 1; + distribution->offset_x = offset; + distribution->offset_y = 0; + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to distribution\n"); + vxAddLogEntry(context, VX_ERROR_INVALID_PARAMETERS, "Invalid parameters to distribution\n"); + distribution = (vx_distribution)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } + } + + return distribution; +} + +VX_API_ENTRY vx_distribution VX_API_CALL vxCreateVirtualDistribution( vx_graph graph, vx_size numBins, vx_int32 offset, vx_uint32 range) +{ + vx_distribution distribution = nullptr; + vx_reference gref = (vx_reference)graph; + + if (Reference::isValidReference(gref, VX_TYPE_GRAPH) == vx_true_e) + { + distribution = vxCreateDistribution(gref->context, numBins, offset, range); + if (vxGetStatus((vx_reference)distribution) == VX_SUCCESS && distribution->type == VX_TYPE_DISTRIBUTION) + { + distribution->scope = (vx_reference)graph; + distribution->is_virtual = vx_true_e; + } + } + return distribution; +} + +VX_API_ENTRY vx_status VX_API_CALL vxQueryDistribution(vx_distribution distribution, vx_enum attribute, void *ptr, vx_size size) +{ + vx_status status = VX_SUCCESS; + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) == vx_false_e) + return VX_ERROR_INVALID_REFERENCE; + + switch (attribute) + { + case VX_DISTRIBUTION_DIMENSIONS: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + { + *(vx_size*)ptr = distribution->dims(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_DISTRIBUTION_RANGE: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32*)ptr = distribution->range(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_DISTRIBUTION_BINS: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + { + *(vx_size*)ptr = distribution->bins(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_DISTRIBUTION_WINDOW: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32*)ptr = distribution->window(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_DISTRIBUTION_OFFSET: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) + { + *(vx_int32*)ptr = distribution->offset(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_DISTRIBUTION_SIZE: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + { + *(vx_size*)ptr = distribution->size(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; + } + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxAccessDistribution(vx_distribution distribution, void **ptr, vx_enum usage) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + return status; + } + + return distribution->access(ptr, usage); +} + +VX_API_ENTRY vx_status VX_API_CALL vxCommitDistribution(vx_distribution distribution, const void *ptr) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + return status; + } + + return distribution->commit(ptr); +} + +VX_API_ENTRY vx_status VX_API_CALL vxCopyDistribution(vx_distribution distribution, void *user_ptr, vx_enum usage, vx_enum mem_type) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + return status; + } + + return distribution->copy(user_ptr, usage, mem_type); +} + +VX_API_ENTRY vx_status VX_API_CALL vxMapDistribution(vx_distribution distribution, vx_map_id *map_id, void **ptr, vx_enum usage, vx_enum mem_type, vx_bitfield flags) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + return status; + } + + return distribution->map(map_id, ptr, usage, mem_type, flags); +} + +VX_API_ENTRY vx_status VX_API_CALL vxUnmapDistribution(vx_distribution distribution, vx_map_id map_id) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (Reference::isValidReference(distribution, VX_TYPE_DISTRIBUTION) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid distribution object!\n"); + return status; + } + + return distribution->unmap(map_id); +} + + +vx_status vxReleaseDistributionInt(vx_distribution* distribution) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != distribution) + { + vx_reference ref = *distribution; + if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_DISTRIBUTION)) + { + status = Reference::releaseReference((vx_reference*)distribution, VX_TYPE_DISTRIBUTION, VX_INTERNAL, nullptr); + } } return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseDistribution(vx_distribution *d) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != d) + { + vx_reference ref = *d; + if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_DISTRIBUTION)) + { + status = Reference::releaseReference((vx_reference*)d, VX_TYPE_DISTRIBUTION, VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From 2fc6ebe8ece874d180fad5add5484a4b290ce0f7 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 18:30:34 -0700 Subject: [PATCH 06/34] Reworked pyramid --- framework/include/vx_pyramid.h | 70 +++++++++++++++++++++++++++++++++ framework/src/vx_pyramid.cpp | 71 +++++++++++++++++++++++++--------- 2 files changed, 123 insertions(+), 18 deletions(-) diff --git a/framework/include/vx_pyramid.h b/framework/include/vx_pyramid.h index 8a0e1cf8..debd167d 100644 --- a/framework/include/vx_pyramid.h +++ b/framework/include/vx_pyramid.h @@ -49,6 +49,76 @@ class Pyramid : public Reference */ ~Pyramid(); + /** + * @brief Create a Pyramid object + * + * @param context The context associated with this obj + * @param levels The number of levels in the pyramid + * @param scale The scale factor between levels + * @param width The width of the pyramid at level 0 + * @param height The height of the pyramid at level 0 + * @param format The format of the images in the pyramid + * @param is_virtual Whether the pyramid is virtual + * @return vx_pyramid The created pyramid object + * @ingroup group_int_pyramid + */ + static vx_pyramid createPyramid(vx_context context, + vx_size levels, + vx_float32 scale, + vx_uint32 width, + vx_uint32 height, + vx_df_image format, + vx_bool is_virtual); + + /** + * @brief Get the number of levels in the pyramid + * + * @return vx_size The number of levels + * @ingroup group_int_pyramid + */ + vx_size numLvls() const; + + /** + * @brief Get the scale factor of the pyramid + * + * @return vx_float32 The scale factor + * @ingroup group_int_pyramid + */ + vx_float32 scaleFactor() const; + + /** + * @brief Get the width of the pyramid at level 0 + * + * @return vx_uint32 The width + * @ingroup group_int_pyramid + */ + vx_uint32 wid() const; + + /** + * @brief Get the height of the pyramid at level 0 + * + * @return vx_uint32 The height + * @ingroup group_int_pyramid + */ + vx_uint32 hght() const; + + /** + * @brief Get the format of the pyramid images + * + * @return vx_enum The image format + * @ingroup group_int_pyramid + */ + vx_enum fmt() const; + + /** + * @brief Get the image at a specific level in the pyramid + * + * @param index The level index + * @return vx_image The image at the specified level + * @ingroup group_int_pyramid + */ + vx_image getAtLevel(vx_size index); + /*! \brief Initializes the internals of a pyramid structure * \ingroup group_int_pyramid */ diff --git a/framework/src/vx_pyramid.cpp b/framework/src/vx_pyramid.cpp index 8b181b0d..ce5f39b0 100644 --- a/framework/src/vx_pyramid.cpp +++ b/framework/src/vx_pyramid.cpp @@ -31,6 +31,50 @@ format() } +vx_size Pyramid::numLvls() const +{ + return numLevels; +} + +vx_float32 Pyramid::scaleFactor() const +{ + return scale; +} + +vx_uint32 Pyramid::wid() const +{ + return width; +} + +vx_uint32 Pyramid::hght() const +{ + return height; +} + +vx_enum Pyramid::fmt() const +{ + return format; +} + +vx_image Pyramid::getAtLevel(vx_size index) +{ + vx_image image = nullptr; + + if (index < numLevels) + { + image = levels[index]; + image->incrementReference(VX_EXTERNAL); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid pyramid level %d requested!\n", index); + vxAddLogEntry(this, VX_ERROR_INVALID_PARAMETERS, "Failed to get pyramid level %d\n", index); + image = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } + + return image; +} + Pyramid::~Pyramid() { } @@ -131,7 +175,7 @@ vx_status Pyramid::initPyramid(vx_size numLevels, return status; } -static vx_pyramid vxCreatePyramidInt(vx_context context, +vx_pyramid Pyramid::createPyramid(vx_context context, vx_size levels, vx_float32 scale, vx_uint32 width, @@ -203,7 +247,7 @@ VX_API_ENTRY vx_pyramid VX_API_CALL vxCreateVirtualPyramid(vx_graph graph, if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) { - pyramid = vxCreatePyramidInt(graph->context, levels, scale, + pyramid = Pyramid::createPyramid(graph->context, levels, scale, width, height, format, vx_true_e); if ( vxGetStatus((vx_reference)pyramid) == VX_SUCCESS && @@ -229,7 +273,7 @@ VX_API_ENTRY vx_pyramid VX_API_CALL vxCreatePyramid(vx_context context, vx_size } else { - pyr = (vx_pyramid)vxCreatePyramidInt(context, + pyr = (vx_pyramid)Pyramid::createPyramid(context, levels, scale, width, height, format, vx_false_e); } @@ -248,7 +292,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryPyramid(vx_pyramid pyramid, vx_enum at case VX_PYRAMID_LEVELS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = pyramid->numLevels; + *(vx_size *)ptr = pyramid->numLvls(); } else { @@ -258,7 +302,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryPyramid(vx_pyramid pyramid, vx_enum at case VX_PYRAMID_SCALE: if (VX_CHECK_PARAM(ptr, size, vx_float32, 0x3)) { - *(vx_float32 *)ptr = pyramid->scale; + *(vx_float32 *)ptr = pyramid->scaleFactor(); } else { @@ -268,7 +312,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryPyramid(vx_pyramid pyramid, vx_enum at case VX_PYRAMID_WIDTH: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = pyramid->width; + *(vx_uint32 *)ptr = pyramid->wid(); } else { @@ -278,7 +322,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryPyramid(vx_pyramid pyramid, vx_enum at case VX_PYRAMID_HEIGHT: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = pyramid->height; + *(vx_uint32 *)ptr = pyramid->hght(); } else { @@ -288,7 +332,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryPyramid(vx_pyramid pyramid, vx_enum at case VX_PYRAMID_FORMAT: if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) { - *(vx_df_image *)ptr = pyramid->format; + *(vx_df_image *)ptr = pyramid->fmt(); } else { @@ -308,16 +352,7 @@ VX_API_ENTRY vx_image VX_API_CALL vxGetPyramidLevel(vx_pyramid pyramid, vx_uint3 vx_image image = 0; if (Reference::isValidReference(pyramid, VX_TYPE_PYRAMID) == vx_true_e) { - if (index < pyramid->numLevels) - { - image = pyramid->levels[index]; - image->incrementReference(VX_EXTERNAL); - } - else - { - vxAddLogEntry(pyramid, VX_ERROR_INVALID_PARAMETERS, "Failed to get pyramid level %d\n", index); - image = (vx_image)vxGetErrorObject(pyramid->context, VX_ERROR_INVALID_PARAMETERS); - } + image = pyramid->getAtLevel(index); } return image; } From 3b68dc7a954e6a1455ca03106d96915cf2184f48 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 19:57:16 -0700 Subject: [PATCH 07/34] Reworked image --- framework/include/vx_image.h | 187 ++ framework/src/vx_image.cpp | 4270 ++++++++++++++++++---------------- 2 files changed, 2437 insertions(+), 2020 deletions(-) diff --git a/framework/include/vx_image.h b/framework/include/vx_image.h index bbfa5260..9c9ce284 100644 --- a/framework/include/vx_image.h +++ b/framework/include/vx_image.h @@ -173,6 +173,193 @@ class Image : public Reference */ static vx_size sizeOfChannel(vx_df_image color); + /** + * @brief Get the width of the image + * + * @return vx_uint32 The width in pixels + * @ingroup group_int_image + */ + vx_uint32 wdth() const; + + /** + * @brief Get the height of the image + * + * @return vx_uint32 The height in pixels + * @ingroup group_int_image + */ + vx_uint32 hght() const; + + /** + * @brief Get the format of the image + * + * @return vx_df_image The format of the image + * @ingroup group_int_image + */ + vx_df_image fmt() const; + + /** + * @brief Get the number of planes in the image + * + * @return vx_uint32 The number of planes + * @ingroup group_int_image + */ + vx_size numPlanes() const; + + /** + * @brief Get the color space of the image + * + * @return vx_enum The color space of the image + * @ingroup group_int_image + */ + vx_enum colorSpace() const; + + /** + * @brief Get the color range of the image + * + * @return vx_enum The color range of the image + * @ingroup group_int_image + */ + vx_enum colorRange() const; + + /** + * @brief Get size of image + * + * @return vx_size The size in bytes + * @ingroup group_int_image + */ + vx_size size() const; + + /** + * @brief Get the memory type + * + * @return vx_enum The memory type + * @ingroup group_int_image + */ + vx_enum memoryType() const; + + /** + * @brief Set the color space + * + * @param value The space value to set + * @ingroup group_int_image + */ + void setSpace(vx_enum value); + + /** + * @brief Swap the handle of the image + * + * @param new_ptrs The new pointers to the image planes + * @param prev_ptrs The previous pointers to the image planes + * @param num_planes The number of planes in the image + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status swapHandle(void *const new_ptrs[], void *prev_ptrs[], vx_size num_planes); + + /** + * @brief Get the Valid Region object + * + * @param rect The rectangle to fill with the valid region + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status getValidRegion(vx_rectangle_t *rect); + + /** + * @brief Set the Valid Region object + * + * @param rect The rectangle to set as the valid region + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status setValidRect(const vx_rectangle_t *rect); + + /** + * @brief Get the pixel values of the image + * + * @param pixel_value The pixel value structure to fill + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status setPixelValues(const vx_pixel_value_t *pixel_value); + + /** + * @brief Compute the size of the patch in bytes + * + * @param rect The rectangle to compute the size for + * @param plane_index The plane index to compute the size for + * @return vx_size The size in bytes + * @ingroup group_int_image + */ + vx_size computePatchSize(const vx_rectangle_t *rect, vx_uint32 plane_index); + + /** + * @brief Access the image patch + * + * @param rect The rectangle to access + * @param plane_index The plane index to access + * @param addr The addressing information for the patch + * @param ptr The pointer to the user memory + * @param mem_type The type of memory (host, opencl, etc.) + * @param usage The usage of the memory (read/write) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status accessPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + vx_imagepatch_addressing_t *addr, void **ptr, vx_enum usage); + + /** + * @brief Commit the image patch + * @param rect The rectangle to commit + * @param plane_index The plane index to commit + * @param addr The addressing information for the patch + * @param ptr The pointer to the user memory + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status commitPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + const vx_imagepatch_addressing_t *addr, const void *ptr); + + /** + * @brief Copy the image patch to/from user memory + * + * @param rect The rectangle to copy + * @param plane_index The plane index to copy + * @param addr The addressing information for the patch + * @param ptr The pointer to the user memory + * @param usage The usage of the memory (read/write) + * @param mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status copyPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + const vx_imagepatch_addressing_t *addr, void *ptr, vx_enum usage, + vx_enum mem_type); + + /*! \brief Used to map an image patch. + * \param [in] rect The rectangle to map. + * \param [in] plane_index The plane index to map. + * \param [out] map_id The map id to use. + * \param [out] addr The addressing information for the patch. + * \param [out] ptr The pointer to the mapped memory. + * \param [in] usage The usage of the memory (read/write). + * \param [in] mem_type The type of memory (host, opencl, etc.). + * \param [in] flags Additional flags for mapping. + * \ingroup group_int_image + */ + vx_status mapPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, vx_map_id *map_id, + vx_imagepatch_addressing_t *addr, void **ptr, vx_enum usage, + vx_enum mem_type, vx_uint32 flags); + + /** + * @brief Unmap an image patch + * + * @param map_id The map id to unmap + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_image + */ + vx_status unmapPatch(vx_map_id map_id); + /*! \brief Prints the values of the images. * \ingroup group_int_image */ diff --git a/framework/src/vx_image.cpp b/framework/src/vx_image.cpp index dc1f5c24..de8c540c 100644 --- a/framework/src/vx_image.cpp +++ b/framework/src/vx_image.cpp @@ -414,1191 +414,1407 @@ vx_bool Image::isValidDimensions(vx_uint32 width, vx_uint32 height, vx_df_image return vx_true_e; } -void Image::printImage(vx_image image) +vx_df_image Image::fmt() const { - vx_uint32 p = 0; - vx_char df_image[5]; - strncpy(df_image, (char *)&image->format, 4); - df_image[4] = '\0'; - Reference::printReference(image); - VX_PRINT(VX_ZONE_IMAGE, "vx_image:%p %s %ux%u (%s)\n", image, df_image, image->width, image->height, (image->constant?"CONSTANT":"MUTABLE")); - for (p = 0; p < image->planes; p++) - { - VX_PRINT(VX_ZONE_IMAGE, "\tplane[%u] ptr:%p dim={%u,%u,%u} stride={%d,%d,%d} stride_x_bits={%u} scale={%u,%u,%u} bounds={%u,%ux%u,%u}\n", - p, - image->memory.ptrs[p], - image->memory.dims[p][VX_DIM_C], - image->memory.dims[p][VX_DIM_X], - image->memory.dims[p][VX_DIM_Y], - image->memory.strides[p][VX_DIM_C], - image->memory.strides[p][VX_DIM_X], - image->memory.strides[p][VX_DIM_Y], - image->memory.stride_x_bits[p], - image->scale[p][VX_DIM_C], - image->scale[p][VX_DIM_X], - image->scale[p][VX_DIM_Y], - image->bounds[p][VX_DIM_X][VX_BOUND_START], - image->bounds[p][VX_DIM_X][VX_BOUND_END], - image->bounds[p][VX_DIM_Y][VX_BOUND_START], - image->bounds[p][VX_DIM_Y][VX_BOUND_END]); - } + return format; } -void Image::printImageAddressing(const vx_imagepatch_addressing_t *addr) +vx_uint32 Image::wdth() const { - if (addr) - { - VX_PRINT(VX_ZONE_IMAGE, "addr:%p dim={%u,%u} stride={%d,%d} stride_x_bits={%u} scale={%u,%u} step={%u,%u}\n", - addr, - addr->dim_x, addr->dim_y, - addr->stride_x, addr->stride_y, - addr->stride_x_bits, - addr->scale_x, addr->scale_y, - addr->step_x, addr->step_y); - } + return width; } -void Image::destruct() +vx_uint32 Image::hght() const { - /* if it's not imported and does not have a parent, free it */ - if ((memory_type == VX_MEMORY_TYPE_NONE) && (parent == nullptr)) - { - freeImage(); - } - else if (parent) + return height; +} + +vx_size Image::numPlanes() const +{ + return planes; +} + +vx_enum Image::colorSpace() const +{ + return space; +} + +vx_enum Image::colorRange() const +{ + return range; +} + +vx_size Image::size() const +{ + vx_size size = 0ul; + vx_uint32 p; + for (p = 0; p < planes; p++) { - Reference::releaseReference((vx_reference*)&parent, VX_TYPE_IMAGE, VX_INTERNAL, nullptr); + size += (abs(memory.strides[p][VX_DIM_Y]) * memory.dims[p][VX_DIM_Y]); } - else if (memory_type != VX_MEMORY_TYPE_NONE) + + return size; +} + +vx_enum Image::memoryType() const +{ + return memory_type; +} + +void Image::setSpace(vx_enum value) +{ + space = value; +} + +vx_status Image::swapHandle(void *const new_ptrs[], void *prev_ptrs[], vx_size num_planes) +{ + vx_status status = VX_SUCCESS; + (void)num_planes; + + if (memory_type != VX_MEMORY_TYPE_NONE) { - vx_uint32 p = 0u; + vx_uint32 i; + vx_uint32 p; + + if (new_ptrs != nullptr) + { + for (p = 0; p < planes; p++) + { + if (new_ptrs[p] == nullptr) return VX_ERROR_INVALID_PARAMETERS; + } + } + + if (prev_ptrs != nullptr && parent != nullptr) + { + /* do not return prev pointers for subimages */ + return VX_ERROR_INVALID_PARAMETERS; + } + + if (prev_ptrs != nullptr && parent == nullptr) + { + /* return previous image handles */ + for (p = 0; p < planes; p++) + { +#ifdef OPENVX_USE_OPENCL_INTEROP + if (memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, + memory.opencl_buf[p], memory.ptrs[p], 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); + prev_ptrs[p] = memory.opencl_buf[p]; + memory.opencl_buf[p] = nullptr; + memory.ptrs[p] = nullptr; + } + else +#endif + prev_ptrs[p] = memory.ptrs[p]; + } + } + + /* visit each subimage of this image and reclaim its pointers */ + for (i = 0; i < VX_INT_MAX_REF; i++) + { + if (subimages[i] != nullptr) + { + if (new_ptrs == nullptr) + status = + vxSwapImageHandle(subimages[i], nullptr, nullptr, planes); + else + { + vx_uint8 *ptrs[4]; + + for (p = 0; p < subimages[i]->planes; p++) + { + vx_uint32 offset = subimages[i]->memory.offset[p]; + ptrs[p] = (vx_uint8 *)new_ptrs[p] + offset; + } + + status = vxSwapImageHandle(subimages[i], (void **)ptrs, nullptr, + planes); + } + + break; + } + } + + /* reclaim previous and set new handles for this image */ for (p = 0; p < planes; p++) { - Osal::destroySem(&memory.locks[p]); - memory.ptrs[p] = nullptr; - memory.strides[p][VX_DIM_C] = 0; - memory.strides[p][VX_DIM_X] = 0; - memory.strides[p][VX_DIM_Y] = 0; - memory.stride_x_bits[p] = 0; + if (new_ptrs == nullptr) + memory.ptrs[p] = 0; + else + { + /* set new pointers for subimage */ +#ifdef OPENVX_USE_OPENCL_INTEROP + if (memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + memory.opencl_buf[p] = (cl_mem)new_ptrs[p]; + size_t size = 0; + cl_int cerr = clGetMemObjectInfo(memory.opencl_buf[p], CL_MEM_SIZE, + sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxSwapImageHandle: clGetMemObjectInfo(%p) => (%d)\n", + memory.opencl_buf[p], cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + memory.ptrs[p] = (vx_uint8 *)clEnqueueMapBuffer( + context->opencl_command_queue, memory.opencl_buf[p], CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxSwapImageHandle: clEnqueueMapBuffer(%p) => %p (%d)\n", + memory.opencl_buf[p], memory.ptrs[p], cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + } + else +#endif + memory.ptrs[p] = reinterpret_cast(new_ptrs[p]); + } } - memory.allocated = vx_false_e; + + /* clear flag if pointers were reclaimed */ + memory.allocated = (new_ptrs == nullptr) ? vx_false_e : vx_true_e; + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; } -} -/******************************************************************************/ -/* PUBLIC API */ -/******************************************************************************/ + return status; +} -VX_API_ENTRY vx_image VX_API_CALL vxCreateImage(vx_context context, vx_uint32 width, vx_uint32 height, vx_df_image format) +vx_status Image::getValidRegion(vx_rectangle_t *rect) { - if ((width == 0) || (height == 0) || - (Image::isSupportedFourcc(format) == vx_false_e) || (format == VX_DF_IMAGE_VIRT)) + vx_status status = VX_ERROR_INVALID_PARAMETERS; + + if (rect) { - return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + if ((region.start_x <= region.end_x) && (region.start_y <= region.end_y)) + { + rect->start_x = region.start_x; + rect->start_y = region.start_y; + rect->end_x = region.end_x; + rect->end_y = region.end_y; + } + else + { + rect->start_x = 0; + rect->start_y = 0; + rect->end_x = width; + rect->end_y = height; + } + status = VX_SUCCESS; } - return (vx_image)Image::createImage(context, width, height, format, vx_false_e); + + return status; } -VX_API_ENTRY vx_image VX_API_CALL vxCreateUniformImage(vx_context context, vx_uint32 width, vx_uint32 height, vx_df_image format, const vx_pixel_value_t *value) +vx_status Image::setValidRect(const vx_rectangle_t *rect) { - vx_image image = 0; + vx_status status = VX_FAILURE; - if (value == nullptr) + if (rect) { - return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + if ((rect->start_x <= rect->end_x) && (rect->start_y <= rect->end_y) && + (rect->end_x <= width) && (rect->end_y <= height)) + { + region.start_x = rect->start_x; + region.start_y = rect->start_y; + region.end_x = rect->end_x; + region.end_y = rect->end_y; + status = VX_SUCCESS; + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } } - - image = vxCreateImage(context, width, height, format); - if (vxGetStatus((vx_reference)image) == VX_SUCCESS) + else { - vx_uint32 x, y, p; - vx_size planes = 0; - vx_rectangle_t rect = {0, 0, width, height}; - vxQueryImage(image, VX_IMAGE_PLANES, &planes, sizeof(planes)); - for (p = 0; p < planes; p++) + region.start_x = 0; + region.start_y = 0; + region.end_x = width; + region.end_y = height; + status = VX_SUCCESS; + } + + return status; +} + +vx_status Image::setPixelValues(const vx_pixel_value_t *pixel_value) +{ + vx_status status = VX_SUCCESS; + vx_uint32 x, y, p, width, height; + vx_size planes = 0; + vx_rectangle_t rect = {0, 0, 0, 0}; + vxGetValidRegionImage(this, &rect); + vx_df_image format = 0; + vxQueryImage(this, VX_IMAGE_FORMAT, &format, sizeof(format)); + vxQueryImage(this, VX_IMAGE_PLANES, &planes, sizeof(planes)); + + for (p = 0; p < planes; p++) + { + vx_imagepatch_addressing_t addr; + void *base = nullptr; + if (vxAccessImagePatch(this, &rect, p, &addr, &base, VX_WRITE_ONLY) == VX_SUCCESS) { - vx_imagepatch_addressing_t addr; - void *base = nullptr; - if (vxAccessImagePatch(image, &rect, p, &addr, &base, VX_WRITE_ONLY) == VX_SUCCESS) + Image::printImageAddressing(&addr); + width = (format == VX_DF_IMAGE_U1) ? addr.dim_x - rect.start_x % 8 : addr.dim_x; + height = addr.dim_y; + for (y = 0; y < height; y += addr.step_y) { - Image::printImageAddressing(&addr); - for (y = 0; y < addr.dim_y; y+=addr.step_y) + for (x = 0; x < width; x += addr.step_x) { - for (x = 0; x < addr.dim_x; x+=addr.step_x) + if (format == VX_DF_IMAGE_U1) { - if (format == VX_DF_IMAGE_U1) - { - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - vx_uint8 offset = x % 8; - vx_uint8 mask = 1 << offset; - *ptr = (*ptr & ~mask) | ((value->U1 ? 1 : 0) << offset); - } - if (format == VX_DF_IMAGE_U8) - { - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = value->U8; - } - else if (format == VX_DF_IMAGE_U16) - { - vx_uint16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = value->U16; - } - else if (format == VX_DF_IMAGE_U32) + vx_uint32 xShftd = x + rect.start_x % 8; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, xShftd, y, &addr)); + vx_uint8 offset = xShftd % 8; + vx_uint8 mask = 1 << offset; + *ptr = (*ptr & ~mask) | ((pixel_value->U1 ? 1 : 0) << offset); + } + if (format == VX_DF_IMAGE_U8) + { + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel_value->U8; + } + else if (format == VX_DF_IMAGE_U16) + { + vx_uint16 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel_value->U16; + } + else if (format == VX_DF_IMAGE_U32) + { + vx_uint32 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel_value->U32; + } + else if (format == VX_DF_IMAGE_S16) + { + vx_int16 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel_value->S16; + } + else if (format == VX_DF_IMAGE_S32) + { + vx_int32 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel_value->S32; + } + else if ((format == VX_DF_IMAGE_RGB) || (format == VX_DF_IMAGE_RGBX)) + { + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = pixel_value->RGBX[0]; + ptr[1] = pixel_value->RGBX[1]; + ptr[2] = pixel_value->RGBX[2]; + if (format == VX_DF_IMAGE_RGBX) ptr[3] = pixel_value->RGBX[3]; + } + else if ((format == VX_DF_IMAGE_YUV4) || (format == VX_DF_IMAGE_IYUV)) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel[p]; + } + else if ((p == 0) && + ((format == VX_DF_IMAGE_NV12) || (format == VX_DF_IMAGE_NV21))) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel[0]; + } + else if ((p == 1) && (format == VX_DF_IMAGE_NV12)) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = pixel[1]; + ptr[1] = pixel[2]; + } + else if ((p == 1) && (format == VX_DF_IMAGE_NV21)) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = pixel[2]; + ptr[1] = pixel[1]; + } + else if (format == VX_DF_IMAGE_UYVY) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + if (x % 2 == 0) { - vx_uint32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = value->U32; + ptr[0] = pixel[1]; + ptr[1] = pixel[0]; } - else if (format == VX_DF_IMAGE_S16) + else { - vx_int16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = value->S16; + ptr[0] = pixel[2]; + ptr[1] = pixel[0]; } - else if (format == VX_DF_IMAGE_S32) + } + else if (format == VX_DF_IMAGE_YUYV) + { + vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; + vx_uint8 *ptr = reinterpret_cast( + vxFormatImagePatchAddress2d(base, x, y, &addr)); + if (x % 2 == 0) { - vx_int32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = value->S32; + ptr[0] = pixel[0]; + ptr[1] = pixel[1]; } - else if ((format == VX_DF_IMAGE_RGB) || - (format == VX_DF_IMAGE_RGBX)) + else { - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = value->RGBX[0]; - ptr[1] = value->RGBX[1]; - ptr[2] = value->RGBX[2]; - if (format == VX_DF_IMAGE_RGBX) - ptr[3] = value->RGBX[3]; - } - else if ((format == VX_DF_IMAGE_YUV4) || - (format == VX_DF_IMAGE_IYUV)) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel[p]; - } - else if ((p == 0) && - ((format == VX_DF_IMAGE_NV12) || - (format == VX_DF_IMAGE_NV21))) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel[0]; - } - else if ((p == 1) && (format == VX_DF_IMAGE_NV12)) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = pixel[1]; - ptr[1] = pixel[2]; - } - else if ((p == 1) && (format == VX_DF_IMAGE_NV21)) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = pixel[2]; - ptr[1] = pixel[1]; - } - else if (format == VX_DF_IMAGE_UYVY) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - if (x % 2 == 0) - { - ptr[0] = pixel[1]; - ptr[1] = pixel[0]; - } - else - { - ptr[0] = pixel[2]; - ptr[1] = pixel[0]; - } - } - else if (format == VX_DF_IMAGE_YUYV) - { - vx_uint8 *pixel = (vx_uint8 *)&value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - if (x % 2 == 0) - { - ptr[0] = pixel[0]; - ptr[1] = pixel[1]; - } - else - { - ptr[0] = pixel[0]; - ptr[1] = pixel[2]; - } + ptr[0] = pixel[0]; + ptr[1] = pixel[2]; } } } - if (vxCommitImagePatch(image, &rect, p, &addr, base) != VX_SUCCESS) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to set initial image patch on plane %u on const image!\n", p); - vxReleaseImage(&image); - image = (vx_image)vxGetErrorObject(context, VX_FAILURE); - break; - } } - else + if (vxCommitImagePatch(this, &rect, p, &addr, base) != VX_SUCCESS) { - VX_PRINT(VX_ZONE_ERROR, "Failed to get image patch on plane %u in const image!\n",p); - vxReleaseImage(&image); - image = (vx_image)vxGetErrorObject(context, VX_FAILURE); + VX_PRINT(VX_ZONE_ERROR, + "Failed to set initial image patch on plane %u on const image!\n", p); + status = VX_FAILURE; break; } - } /* for loop */ - if (vxGetStatus((vx_reference)image) == VX_SUCCESS) - { - /* lock the image from being modified again! */ - ((vx_image)image)->constant = vx_true_e; } - } - - return image; -} - -VX_API_ENTRY vx_image VX_API_CALL vxCreateVirtualImage(vx_graph graph, vx_uint32 width, vx_uint32 height, vx_df_image format) -{ - vx_image image = nullptr; - - if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) - { - image = Image::createImage(graph->context, width, height, format, vx_true_e); - if (vxGetStatus((vx_reference)image) == VX_SUCCESS && image->type == VX_TYPE_IMAGE) + else { - image->scope = (vx_reference)graph; + VX_PRINT(VX_ZONE_ERROR, "Failed to get image patch on plane %u in const image!\n", p); + status = VX_FAILURE; + break; } - } + } /* for loop */ - return image; + return status; } -VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromROI(vx_image image, const vx_rectangle_t* rect) +vx_size Image::computePatchSize(const vx_rectangle_t *rect, vx_uint32 plane_index) { - vx_image subimage = nullptr; + vx_size size = 0ul; + vx_uint32 start_x = 0u, start_y = 0u, end_x = 0u, end_y = 0u; - if (Image::isValidImage(image) == vx_true_e) + if (rect) { - if (!rect || - rect->start_x >= rect->end_x || - rect->start_y >= rect->end_y || - rect->end_x > image->width || - rect->end_y > image->height) - { - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - } - else if (image->format == VX_DF_IMAGE_U1 && (rect->start_x % 8) != 0) + start_x = rect->start_x; + start_y = rect->start_y; + end_x = rect->end_x; + end_y = rect->end_y; + + if (memory.ptrs[0] == nullptr) { - VX_PRINT(VX_ZONE_ERROR, "Attempted to create U1 image from ROI not starting at a byte boundary in the" - "parent image. U1 subimages must start on byte boundaries in the parent image.\n"); - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + if (allocateImage() == vx_false_e) + { + vxAddLogEntry((vx_reference)this, VX_ERROR_NO_MEMORY, + "Failed to allocate image!\n"); + return 0; + } } - else + if (plane_index < planes) { - /* perhaps the parent hasn't been allocated yet? */ - if (image->allocateImage() == vx_true_e) + vx_size pixelSize; + vx_size numPixels = ((end_x - start_x) / scale[plane_index][VX_DIM_X]) * + ((end_y - start_y) / scale[plane_index][VX_DIM_Y]); + Image::printImage(this); + if (memory.strides[plane_index][VX_DIM_X] == 0 && + memory.stride_x_bits[plane_index] != 0) { - subimage = (vx_image)Reference::createReference(image->context, VX_TYPE_IMAGE, VX_EXTERNAL, image->context); - if (vxGetStatus((vx_reference)subimage) == VX_SUCCESS) - { - vx_uint32 p = 0; - vx_rectangle_t image_rect; - - /* remember that the scope of the image is the parent image */ - subimage->scope = (vx_reference)image; - - /* refer to our parent image and internally refcount it */ - subimage->parent = image; - - for (p = 0; p < VX_INT_MAX_REF; p++) - { - if (image->subimages[p] == nullptr) - { - image->subimages[p] = subimage; - break; - } - } - - image->incrementReference(VX_INTERNAL); - - VX_PRINT(VX_ZONE_IMAGE, "Creating SubImage at {%u,%u},{%u,%u}\n", - rect->start_x, rect->start_y, rect->end_x, rect->end_y); - - /* duplicate the metadata */ - subimage->format = image->format; - subimage->memory_type = image->memory_type; - subimage->range = image->range; - subimage->space = image->space; - subimage->width = rect->end_x - rect->start_x; - subimage->height = rect->end_y - rect->start_y; - subimage->planes = image->planes; - subimage->constant = image->constant; - - vxGetValidRegionImage(image, &image_rect); - - /* set valid rectangle */ - if(rect->start_x > image_rect.end_x || - rect->end_x < image_rect.start_x || - rect->start_y > image_rect.end_y || - rect->end_y < image_rect.start_y) - { - /* no intersection */ - subimage->region.start_x = 0; - subimage->region.start_y = 0; - subimage->region.end_x = 0; - subimage->region.end_y = 0; - } - else - { - subimage->region.start_x = VX_MAX(image_rect.start_x, rect->start_x) - rect->start_x; - subimage->region.start_y = VX_MAX(image_rect.start_y, rect->start_y) - rect->start_y; - subimage->region.end_x = VX_MIN(image_rect.end_x, rect->end_x) - rect->start_x; - subimage->region.end_y = VX_MIN(image_rect.end_y, rect->end_y) - rect->start_y; - } - - memcpy(&subimage->scale, &image->scale, sizeof(image->scale)); - memcpy(&subimage->memory, &image->memory, sizeof(image->memory)); - - /* modify the dimensions */ - for (p = 0; p < subimage->planes; p++) - { - vx_uint32 offset = Image::computePlaneOffset(image, rect->start_x, rect->start_y, p); - VX_PRINT(VX_ZONE_IMAGE, "Offsetting SubImage plane[%u] by %u bytes!\n", p, offset); - - subimage->memory.dims[p][VX_DIM_X] = subimage->width; - subimage->memory.dims[p][VX_DIM_Y] = subimage->height; - subimage->memory.ptrs[p] = &image->memory.ptrs[p][offset]; - - /* keep offset to allow vxSwapImageHandle update ROI pointers */ - subimage->memory.offset[p] = offset; - } + /* data type does not have integer byte size, e.g. VX_DF_IMAGE_U1 image */ + pixelSize = memory.stride_x_bits[plane_index]; // bits + if (start_x * pixelSize % 8 != + 0) // Handle case where imagepatch doesn't start at byte boundary + start_x -= (start_x * pixelSize % 8) / pixelSize; - Image::printImage(subimage); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Child image failed to allocate!\n"); - } + vx_size lineSize = + ((end_x - start_x) / scale[plane_index][VX_DIM_X] * pixelSize + 7ul) / 8ul; + VX_PRINT(VX_ZONE_IMAGE, + "numPixels = " VX_FMT_SIZE " pixelSize = " VX_FMT_SIZE " bits\n", + numPixels, pixelSize); + size = lineSize * ((end_y - start_y) / scale[plane_index][VX_DIM_Y]); } else { - VX_PRINT(VX_ZONE_ERROR, "Parent image failed to allocate!\n"); - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); + pixelSize = memory.strides[plane_index][VX_DIM_X]; + VX_PRINT(VX_ZONE_IMAGE, "numPixels = " VX_FMT_SIZE " pixelSize = " VX_FMT_SIZE "\n", + numPixels, pixelSize); + size = numPixels * pixelSize; } } + else + { + vxAddLogEntry((vx_reference)this, VX_ERROR_INVALID_PARAMETERS, + "Plane index %u is out of bounds!", plane_index); + } + + VX_PRINT(VX_ZONE_IMAGE, + "image %p for patch {%u,%u to %u,%u} has a byte size of " VX_FMT_SIZE "\n", this, + start_x, start_y, end_x, end_y, size); } else { - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + VX_PRINT(VX_ZONE_ERROR, "Rect reference is invalid!\n"); } - return (vx_image)subimage; + return size; } -VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromChannel(vx_image image, vx_enum channel) +vx_status Image::accessPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + vx_imagepatch_addressing_t *addr, void **ptr, vx_enum usage) { - vx_image subimage = nullptr; + vx_uint8 *p = nullptr; + vx_status status = VX_FAILURE; + vx_bool mapped = vx_false_e; + vx_uint32 start_x = rect ? rect->start_x : 0u; + vx_uint32 start_y = rect ? rect->start_y : 0u; + vx_uint32 end_x = rect ? rect->end_x : 0u; + vx_uint32 end_y = rect ? rect->end_y : 0u; + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); - if (Image::isValidImage(image) == vx_true_e) + /* bad parameters */ + if ((usage < VX_READ_ONLY) || (VX_READ_AND_WRITE < usage) || (addr == nullptr) || + (ptr == nullptr)) { - /* perhaps the parent hasn't been allocated yet? */ - if (image->allocateImage() == vx_true_e) - { - /* check for valid parameters */ - switch (channel) - { - case VX_CHANNEL_Y: - { - if (VX_DF_IMAGE_YUV4 != image->format && - VX_DF_IMAGE_IYUV != image->format && - VX_DF_IMAGE_NV12 != image->format && - VX_DF_IMAGE_NV21 != image->format) - { - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - return subimage; - } - break; - } + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters for AccessImagePatch!\n"); + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; + } - case VX_CHANNEL_U: - case VX_CHANNEL_V: - { - if (VX_DF_IMAGE_YUV4 != image->format && - VX_DF_IMAGE_IYUV != image->format) - { - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - return subimage; - } - break; - } - - default: - { - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - return subimage; - } - } - - subimage = (vx_image)Reference::createReference(image->context, VX_TYPE_IMAGE, VX_EXTERNAL, image->context); - if (vxGetStatus((vx_reference)subimage) == VX_SUCCESS) - { - vx_uint32 p = 0; - - /* remember that the scope of the subimage is the parent image */ - subimage->scope = (vx_reference)image; - - /* refer to our parent image and internally refcount it */ - subimage->parent = image; - - for (p = 0; p < VX_INT_MAX_REF; p++) - { - if (image->subimages[p] == nullptr) - { - image->subimages[p] = subimage; - break; - } - } - - image->incrementReference(VX_INTERNAL); - - VX_PRINT(VX_ZONE_IMAGE, "Creating SubImage from channel {%u}\n", channel); - - /* plane index */ - p = (VX_CHANNEL_Y == channel) ? 0 : ((VX_CHANNEL_U == channel) ? 1 : 2); - - switch (image->format) - { - case VX_DF_IMAGE_YUV4: - { - /* setup the metadata */ - subimage->format = VX_DF_IMAGE_U8; - subimage->memory_type = image->memory_type; - subimage->range = image->range; - subimage->space = image->space; - subimage->width = image->memory.dims[p][VX_DIM_X]; - subimage->height = image->memory.dims[p][VX_DIM_Y]; - subimage->planes = 1; - subimage->constant = image->constant; - - memset(&subimage->scale, 0, sizeof(image->scale)); - memset(&subimage->memory, 0, sizeof(image->memory)); - - subimage->scale[0][VX_DIM_C] = 1; - subimage->scale[0][VX_DIM_X] = 1; - subimage->scale[0][VX_DIM_Y] = 1; - - subimage->bounds[0][VX_DIM_C][VX_BOUND_START] = 0; - subimage->bounds[0][VX_DIM_C][VX_BOUND_END] = 1; - subimage->bounds[0][VX_DIM_X][VX_BOUND_START] = image->bounds[p][VX_DIM_X][VX_BOUND_START]; - subimage->bounds[0][VX_DIM_X][VX_BOUND_END] = image->bounds[p][VX_DIM_X][VX_BOUND_END]; - subimage->bounds[0][VX_DIM_Y][VX_BOUND_START] = image->bounds[p][VX_DIM_Y][VX_BOUND_START]; - subimage->bounds[0][VX_DIM_Y][VX_BOUND_END] = image->bounds[p][VX_DIM_Y][VX_BOUND_END]; - - subimage->memory.dims[0][VX_DIM_C] = image->memory.dims[p][VX_DIM_C]; - subimage->memory.dims[0][VX_DIM_X] = image->memory.dims[p][VX_DIM_X]; - subimage->memory.dims[0][VX_DIM_Y] = image->memory.dims[p][VX_DIM_Y]; - - subimage->memory.strides[0][VX_DIM_C] = image->memory.strides[p][VX_DIM_C]; - subimage->memory.strides[0][VX_DIM_X] = image->memory.strides[p][VX_DIM_X]; - subimage->memory.strides[0][VX_DIM_Y] = image->memory.strides[p][VX_DIM_Y]; - subimage->memory.stride_x_bits[0] = image->memory.stride_x_bits[p]; - - subimage->memory.ptrs[0] = image->memory.ptrs[p]; - subimage->memory.nptrs = 1; - - Osal::createSem(&subimage->memory.locks[0], 1); - - break; - } - - case VX_DF_IMAGE_IYUV: - case VX_DF_IMAGE_NV12: - case VX_DF_IMAGE_NV21: - { - /* setup the metadata */ - subimage->format = VX_DF_IMAGE_U8; - subimage->memory_type = image->memory_type; - subimage->range = image->range; - subimage->space = image->space; - subimage->width = image->memory.dims[p][VX_DIM_X]; - subimage->height = image->memory.dims[p][VX_DIM_Y]; - subimage->planes = 1; - subimage->constant = image->constant; - - memset(&subimage->scale, 0, sizeof(image->scale)); - memset(&subimage->memory, 0, sizeof(image->memory)); - - subimage->scale[0][VX_DIM_C] = 1; - subimage->scale[0][VX_DIM_X] = 1; - subimage->scale[0][VX_DIM_Y] = 1; - - subimage->bounds[0][VX_DIM_C][VX_BOUND_START] = 0; - subimage->bounds[0][VX_DIM_C][VX_BOUND_END] = 1; - subimage->bounds[0][VX_DIM_X][VX_BOUND_START] = image->bounds[p][VX_DIM_X][VX_BOUND_START]; - subimage->bounds[0][VX_DIM_X][VX_BOUND_END] = image->bounds[p][VX_DIM_X][VX_BOUND_END]; - subimage->bounds[0][VX_DIM_Y][VX_BOUND_START] = image->bounds[p][VX_DIM_Y][VX_BOUND_START]; - subimage->bounds[0][VX_DIM_Y][VX_BOUND_END] = image->bounds[p][VX_DIM_Y][VX_BOUND_END]; - - subimage->memory.dims[0][VX_DIM_C] = image->memory.dims[p][VX_DIM_C]; - subimage->memory.dims[0][VX_DIM_X] = image->memory.dims[p][VX_DIM_X]; - subimage->memory.dims[0][VX_DIM_Y] = image->memory.dims[p][VX_DIM_Y]; - - subimage->memory.strides[0][VX_DIM_C] = image->memory.strides[p][VX_DIM_C]; - subimage->memory.strides[0][VX_DIM_X] = image->memory.strides[p][VX_DIM_X]; - subimage->memory.strides[0][VX_DIM_Y] = image->memory.strides[p][VX_DIM_Y]; - subimage->memory.stride_x_bits[0] = image->memory.stride_x_bits[p]; - - subimage->memory.ptrs[0] = image->memory.ptrs[p]; - subimage->memory.nptrs = 1; - - Osal::createSem(&subimage->memory.locks[0], 1); - - break; - } - } - - /* set inverted region untill the first write to image */ - subimage->region.start_x = subimage->width; - subimage->region.start_y = subimage->height; - subimage->region.end_x = 0; - subimage->region.end_y = 0; - - Image::printImage(subimage); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Child image failed to allocate!\n"); - } - } - else + /* determine if virtual before checking for memory */ + if (is_virtual == vx_true_e) + { + if (is_accessible == vx_false_e) { - VX_PRINT(VX_ZONE_ERROR, "Parent image failed to allocate!\n"); - vx_context context = vxGetContext((vx_reference)image); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); + /* User tried to access a "virtual" image. */ + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + goto exit; } + /* framework trying to access a virtual image, this is ok. */ } - else + + /* more bad parameters */ + if (zero_area == vx_false_e && + ((plane_index >= memory.nptrs) || (plane_index >= planes) || + (rect->start_x >= rect->end_x) || (rect->start_y >= rect->end_y))) { - vx_context context = vxGetContext((vx_reference)subimage); - subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; } - return (vx_image)subimage; -} - -VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromHandle(vx_context context, vx_df_image color, const vx_imagepatch_addressing_t addrs[], void *const ptrs[], vx_enum memory_type) -{ - vx_image image = 0; - - if (Context::isValidImport(memory_type) == vx_false_e) + /* The image needs to be allocated */ + if ((memory.ptrs[0] == nullptr) && (allocateImage() == vx_false_e)) { - return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + VX_PRINT(VX_ZONE_ERROR, "No memory!\n"); + status = VX_ERROR_NO_MEMORY; + goto exit; } - image = vxCreateImage(context, addrs[0].dim_x, addrs[0].dim_y, color); - - if (vxGetStatus((vx_reference)image) == VX_SUCCESS && image->type == VX_TYPE_IMAGE) + /* can't write to constant */ + if ((constant == vx_true_e) && ((usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE))) { - vx_uint32 p = 0; - image->memory_type = memory_type; - image->memory.allocated = vx_true_e; /* don't let the system realloc this memory */ - - /* now assign the plane pointers, assume linearity */ - for (p = 0; p < image->planes; p++) - { - /* ensure row-major memory layout */ - if (addrs[p].stride_x != 0 ? - (addrs[p].stride_x < 0 || addrs[p].stride_y < (vx_int32)(addrs[p].stride_x * addrs[p].dim_x)) : - (addrs[p].stride_x_bits <= 0 || addrs[p].stride_y < (vx_int32)((addrs[p].stride_x_bits * addrs[p].dim_x + 7) / 8))) - { - vxReleaseImage(&image); - return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - } -#ifdef OPENVX_USE_OPENCL_INTEROP - if (context->opencl_context && memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER && ptrs[p]) - { - vx_rectangle_t rect = { 0, 0, image->width, image->height }; - vx_size size = vxComputeImagePatchSize(image, &rect, p); - cl_int cerr; - image->memory.opencl_buf[p] = (cl_mem)ptrs[p]; - image->memory.ptrs[p] = (vx_uint8*)clEnqueueMapBuffer(context->opencl_command_queue, - image->memory.opencl_buf[p], CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCreateImageFromHandle: clEnqueueMapBuffer(%p) => %p (%d)\n", - image->memory.opencl_buf[p], image->memory.ptrs[p], cerr); - if (cerr != CL_SUCCESS) - { - vxReleaseImage(&image); - return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - } - } - else -#endif - { - image->memory.ptrs[p] = reinterpret_cast(ptrs[p]); - image->memory.strides[p][VX_DIM_C] = (vx_uint32)Image::sizeOfChannel(color); - image->memory.strides[p][VX_DIM_X] = addrs[p].stride_x; - image->memory.strides[p][VX_DIM_Y] = addrs[p].stride_y; - image->memory.stride_x_bits[p] = addrs[p].stride_x_bits; - - Osal::createSem(&image->memory.locks[p], 1); - } - } + status = VX_ERROR_NOT_SUPPORTED; + VX_PRINT(VX_ZONE_ERROR, "Can't write to constant data, only read!\n"); + vxAddLogEntry(reinterpret_cast(this), status, + "Can't write to constant data, only read!\n"); + goto exit; } - return image; -} + /*************************************************************************/ + VX_PRINT(VX_ZONE_IMAGE, + "AccessImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", + this, *ptr, rect->start_x, rect->start_y, rect->end_x, rect->end_y, plane_index); -VX_API_ENTRY vx_status VX_API_CALL vxSwapImageHandle(vx_image image, void* const new_ptrs[], - void* prev_ptrs[], vx_size num_planes) -{ - vx_status status = VX_SUCCESS; - (void)num_planes; + /* POSSIBILITIES: + * 1.) !*ptr && RO == MAP + * 2.) !*ptr && WO == MAP + * 3.) !*ptr && RW == MAP + * 4.) *ptr && RO||RW == COPY (UNLESS MAP) + */ - if (Image::isValidImage(image) == vx_true_e) + if ((*ptr == nullptr) && + ((usage == VX_READ_ONLY) || (usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE))) { - if (image->memory_type != VX_MEMORY_TYPE_NONE) - { - vx_uint32 i; - vx_uint32 p; - - if (new_ptrs != nullptr) - { - for (p = 0; p < image->planes; p++) - { - if (new_ptrs[p] == nullptr) - return VX_ERROR_INVALID_PARAMETERS; - } - } - - if (prev_ptrs != nullptr && image->parent != nullptr) - { - /* do not return prev pointers for subimages */ - return VX_ERROR_INVALID_PARAMETERS; - } - - if (prev_ptrs != nullptr && image->parent == nullptr) - { - /* return previous image handles */ - for (p = 0; p < image->planes; p++) - { -#ifdef OPENVX_USE_OPENCL_INTEROP - if (image->memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(image->context->opencl_command_queue, - image->memory.opencl_buf[p], image->memory.ptrs[p], 0, nullptr, nullptr); - clFinish(image->context->opencl_command_queue); - prev_ptrs[p] = image->memory.opencl_buf[p]; - image->memory.opencl_buf[p] = nullptr; - image->memory.ptrs[p] = nullptr; - } - else -#endif - prev_ptrs[p] = image->memory.ptrs[p]; - } - } - - /* visit each subimage of this image and reclaim its pointers */ - for (i = 0; i < VX_INT_MAX_REF; i++) - { - if (image->subimages[i] != nullptr) - { - if (new_ptrs == nullptr) - status = vxSwapImageHandle(image->subimages[i], nullptr, nullptr, image->planes); - else - { - vx_uint8* ptrs[4]; - - for (p = 0; p < image->subimages[i]->planes; p++) - { - vx_uint32 offset = image->subimages[i]->memory.offset[p]; - ptrs[p] = (vx_uint8*)new_ptrs[p] + offset; - } - - status = vxSwapImageHandle(image->subimages[i], (void**)ptrs, nullptr, image->planes); - } + mapped = vx_true_e; + } - break; - } - } + /* MAP mode */ + if (mapped == vx_true_e) + { + vx_uint32 index = 0u; - /* reclaim previous and set new handles for this image */ - for (p = 0; p < image->planes; p++) + /* lock the memory plane for multiple writers*/ + if (usage != VX_READ_ONLY) + { + if (Osal::semWait(&memory.locks[plane_index]) == vx_false_e) { - if (new_ptrs == nullptr) - image->memory.ptrs[p] = 0; - else - { - /* set new pointers for subimage */ -#ifdef OPENVX_USE_OPENCL_INTEROP - if (image->memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - image->memory.opencl_buf[p] = (cl_mem)new_ptrs[p]; - size_t size = 0; - cl_int cerr = clGetMemObjectInfo(image->memory.opencl_buf[p], - CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxSwapImageHandle: clGetMemObjectInfo(%p) => (%d)\n", - image->memory.opencl_buf[p], cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - image->memory.ptrs[p] = (vx_uint8*)clEnqueueMapBuffer(image->context->opencl_command_queue, - image->memory.opencl_buf[p], CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxSwapImageHandle: clEnqueueMapBuffer(%p) => %p (%d)\n", - image->memory.opencl_buf[p], image->memory.ptrs[p], cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - } - else -#endif - image->memory.ptrs[p] = reinterpret_cast(new_ptrs[p]); - } + status = VX_ERROR_NO_RESOURCES; + goto exit; } + } + Memory::printMemory(&memory); + p = (vx_uint8 *)memory.ptrs[plane_index]; - /* clear flag if pointers were reclaimed */ - image->memory.allocated = (new_ptrs == nullptr) ? vx_false_e : vx_true_e; + /* use the addressing of the internal format */ + if (format == VX_DF_IMAGE_U1) + { + addr->dim_x = rect->end_x - rect->start_x + + rect->start_x % 8; // Round start down to byte boundary } else { - status = VX_ERROR_INVALID_PARAMETERS; + addr->dim_x = rect->end_x - rect->start_x; } - } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } + addr->dim_y = rect->end_y - rect->start_y; + addr->stride_x = memory.strides[plane_index][VX_DIM_X]; + addr->stride_y = memory.strides[plane_index][VX_DIM_Y]; + addr->stride_x_bits = memory.stride_x_bits[plane_index]; + addr->step_x = scale[plane_index][VX_DIM_X]; + addr->step_y = scale[plane_index][VX_DIM_Y]; + addr->scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr->scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; - return status; -} + index = Image::computePatchOffset(rect->start_x, rect->start_y, addr); + *ptr = &p[index]; + VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p which is offset by %lu\n", *ptr, + index); -VX_API_ENTRY vx_status VX_API_CALL vxQueryImage(vx_image image, vx_enum attribute, void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; - if (Image::isValidImage(image) == vx_true_e) + // ownReadFromReference(&base); + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; + } + + /* COPY mode */ + else { - switch (attribute) + /* Inconsistent strides for non-integer byte size data? */ + if ((addr->stride_x == 0 || memory.strides[plane_index][VX_DIM_X] == 0) && + addr->stride_x_bits != memory.stride_x_bits[plane_index]) { - case VX_IMAGE_FORMAT: - if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) - { - *(vx_df_image *)ptr = image->format; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_WIDTH: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = image->width; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_HEIGHT: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = image->height; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_PLANES: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) - { - *(vx_size *)ptr = image->planes; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_SPACE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_enum *)ptr = image->space; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_RANGE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_enum *)ptr = image->range; - } - else + VX_PRINT(VX_ZONE_ERROR, + "Copying of non-integer byte size data without preserving stride in " + "x-dimension is not supported! Attempted to copy with strides {stride_x, " + "stride_x_bits}:" + " {%d, %u} <- {%d, %u}\n", + addr->stride_x, addr->stride_x_bits, memory.strides[plane_index][VX_DIM_X], + memory.stride_x_bits[plane_index]); + status = VX_ERROR_NOT_SUPPORTED; + goto exit; + } + + vx_size size = vxComputeImagePatchSize(this, rect, plane_index); + vx_uint32 a = 0u; + + vx_imagepatch_addressing_t *addr_save = new vx_imagepatch_addressing_t(); + /* Strides given by the application */ + addr_save->stride_x = addr->stride_x; + addr_save->stride_y = addr->stride_y; + addr_save->stride_x_bits = addr->stride_x_bits; + /* Computed by the application */ + if (format == VX_DF_IMAGE_U1) + { + addr->dim_x = addr_save->dim_x = + rect->end_x - rect->start_x + rect->start_x % 8; // Round start to byte boundary + } + else + { + addr->dim_x = addr_save->dim_x = rect->end_x - rect->start_x; + } + addr->dim_y = addr_save->dim_y = rect->end_y - rect->start_y; + addr->step_x = addr_save->step_x = scale[plane_index][VX_DIM_X]; + addr->step_y = addr_save->step_y = scale[plane_index][VX_DIM_Y]; + addr->scale_x = addr_save->scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr->scale_y = addr_save->scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; + + if (context->addAccessor(size, usage, *ptr, this, &a, addr_save) == vx_false_e) + { + status = VX_ERROR_NO_MEMORY; + vxAddLogEntry(reinterpret_cast(this), status, + "Failed to allocate memory for COPY! Size=" VX_FMT_SIZE "\n", size); + goto exit; + } + + { + vx_uint32 x, y; + vx_uint8 *tmp = (vx_uint8 *)*ptr; + + /*! \todo implement overlapping multi-writers lock, not just single writer lock */ + if ((usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE)) + { + if (Osal::semWait(&memory.locks[plane_index]) == vx_false_e) { - status = VX_ERROR_INVALID_PARAMETERS; + status = VX_ERROR_NO_RESOURCES; + goto exit; } - break; - case VX_IMAGE_SIZE: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + } + + if ((usage == VX_READ_ONLY) || (usage == VX_READ_AND_WRITE)) + { + /* Copy the patch _from_ the image + * (For non-integer byte size images line-by-line copying only works if the patch + * starts and ends at byte boundaries) */ + if (addr_save->stride_x == memory.strides[plane_index][VX_DIM_X] && + (addr_save->stride_x != 0 + ? 1 + : (addr_save->stride_x_bits == memory.stride_x_bits[plane_index] && + rect->start_x * addr_save->stride_x_bits % 8 == 0 && + rect->end_x * addr_save->stride_x_bits % 8 == 0))) { - vx_size size = 0ul; - vx_uint32 p; - for (p = 0; p < image->planes; p++) + /* Both have compact lines */ + for (y = rect->start_y; y < rect->end_y; y += addr_save->step_y) { - size += (abs(image->memory.strides[p][VX_DIM_Y]) * image->memory.dims[p][VX_DIM_Y]); + vx_uint32 i = + Image::computePlaneOffset(this, rect->start_x, y, plane_index); + vx_uint32 j = Image::computePatchOffset(0, (y - rect->start_y), addr_save); + vx_uint32 len = + Image::computePlaneRangeSize(this, addr_save->dim_x, plane_index); + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", tmp, j, + memory.ptrs[plane_index], i, len); + memcpy(&tmp[j], &memory.ptrs[plane_index][i], len); } - *(vx_size *)ptr = size; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_IMAGE_MEMORY_TYPE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_enum *)ptr = image->memory_type; } + else { - status = VX_ERROR_INVALID_PARAMETERS; + /* The destination is not compact, we need to copy per element */ + vx_uint8 *pDestLine = &tmp[0]; + for (y = rect->start_y; y < rect->end_y; y += addr_save->step_y) + { + vx_uint8 *pDest = pDestLine; + + vx_uint32 offset = + Image::computePlaneOffset(this, rect->start_x, y, plane_index); + vx_uint8 *pSrc = &memory.ptrs[plane_index][offset]; + + for (x = rect->start_x; x < rect->end_x; x += addr_save->step_x) + { + if (format == VX_DF_IMAGE_U1) + { + /* U1 patch not starting and ending at byte boundary in image, + * do pixel-by-pixel copy from the image */ + offset = Image::computePlaneOffset(this, x, y, plane_index); + pSrc = &memory.ptrs[plane_index][offset]; + pDest = &pDestLine[Image::computePatchOffset( + x - rect->start_x + rect->start_x % 8, 0, addr_save)]; + + vx_uint8 mask = 1 << (x % 8); + *pDest = (*pDest & ~mask) | (*pSrc & mask); + } + else + { + /* One element */ + memcpy(pDest, pSrc, memory.strides[plane_index][VX_DIM_X]); + + pSrc += memory.strides[plane_index][VX_DIM_X]; + pDest += addr_save->stride_x; + } + } + VX_PRINT(VX_ZONE_IMAGE, + "Copied %u pixels from row %u in image starting at %p to patch " + "starting at %p\n", + end_x - start_x, y, memory.ptrs[plane_index], tmp); + + pDestLine += addr_save->stride_y; + } } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + + VX_PRINT(VX_ZONE_IMAGE, "Copied image into %p\n", *ptr); + // ownReadFromReference(&base); + } + + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; } } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } - VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); +exit: + VX_PRINT(VX_ZONE_API, "returned %d\n", status); + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxSetImageAttribute(vx_image image, vx_enum attribute, const void *ptr, vx_size size) +vx_status Image::commitPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + const vx_imagepatch_addressing_t *addr, const void *ptr) { - vx_status status = VX_SUCCESS; - if (Image::isValidImage(image) == vx_true_e) + vx_status status = VX_FAILURE; + vx_int32 i = 0; + vx_bool external = vx_true_e; // assume that it was an allocated buffer + vx_uint32 start_x = rect ? rect->start_x : 0u; + vx_uint32 start_y = rect ? rect->start_y : 0u; + vx_uint32 end_x = rect ? rect->end_x : 0u; + vx_uint32 end_y = rect ? rect->end_y : 0u; + vx_uint8 *tmp = (vx_uint8 *)ptr; + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_uint32 index = UINT32_MAX; // out of bounds, if given to remove, won't do anything + + VX_PRINT(VX_ZONE_IMAGE, + "CommitImagePatch to " VX_FMT_REF " from ptr %p plane %u to {%u,%u},{%u,%u}\n", this, + ptr, plane_index, start_x, start_y, end_x, end_y); + + Image::printImage(this); + Image::printImageAddressing(addr); + + /* determine if virtual before checking for memory */ + if (is_virtual == vx_true_e && zero_area == vx_false_e) { - switch (attribute) + if (is_accessible == vx_false_e) { - case VX_IMAGE_SPACE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - image->space = *(vx_enum *)ptr; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + /* User tried to access a "virtual" image. */ + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + goto exit; } + /* framework trying to access a virtual image, this is ok. */ } - else + + if (zero_area == vx_false_e && ((plane_index >= planes) || (plane_index >= memory.nptrs) || + (ptr == nullptr) || (addr == nullptr))) { - status = VX_ERROR_INVALID_REFERENCE; + return VX_ERROR_INVALID_PARAMETERS; } - VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); - return status; -} -VX_API_ENTRY vx_status VX_API_CALL vxSetImagePixelValues(vx_image image, const vx_pixel_value_t *pixel_value) -{ - vx_status status = VX_SUCCESS; - if (Image::isValidImage(image) == vx_true_e) + /* check the rectangle, it has to be in actual plane space */ + if (zero_area == vx_false_e && ((start_x >= end_x) || ((end_x - start_x) > addr->dim_x) || + (start_y >= end_y) || ((end_y - start_y) > addr->dim_y) || + (end_x > (vx_uint32)memory.dims[plane_index][VX_DIM_X] * + (vx_uint32)scale[plane_index][VX_DIM_X]) || + (end_y > (vx_uint32)memory.dims[plane_index][VX_DIM_Y] * + (vx_uint32)scale[plane_index][VX_DIM_X]))) { - vx_uint32 x, y, p, width, height; - vx_size planes = 0; - vx_rectangle_t rect = {0,0,0,0}; - vxGetValidRegionImage(image, &rect); - vx_df_image format = 0; - vxQueryImage(image, VX_IMAGE_FORMAT, &format, sizeof(format)); - vxQueryImage(image, VX_IMAGE_PLANES, &planes, sizeof(planes)); + VX_PRINT(VX_ZONE_ERROR, "Invalid start,end coordinates! plane %u {%u,%u},{%u,%u}\n", + plane_index, start_x, start_y, end_x, end_y); + Image::printImage(this); + DEBUG_BREAK(); + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; + } - for (p = 0; p < planes; p++) + /* Inconsistent strides for non-integer byte size data? */ + if ((addr->stride_x == 0 || memory.strides[plane_index][VX_DIM_X] == 0) && + addr->stride_x_bits != memory.stride_x_bits[plane_index]) + { + VX_PRINT(VX_ZONE_ERROR, + "Copying of non-integer byte size data without preserving stride in " + "x-dimension is not supported! Attempted to copy with strides {stride_x, " + "stride_x_bits}:" + " {%u, %u} -> {%u, %u}\n", + addr->stride_x, addr->stride_x_bits, memory.strides[plane_index][VX_DIM_X], + memory.stride_x_bits[plane_index]); + status = VX_ERROR_NOT_SUPPORTED; + goto exit; + } + + { + /* VARIABLES: + * 1.) ZERO_AREA + * 2.) CONSTANT - independant + * 3.) INTERNAL - independant of area + * 4.) EXTERNAL - dependant on area (do nothing on zero, determine on non-zero) + * 5.) !INTERNAL && !EXTERNAL == MAPPED + */ + vx_bool internal = context->findAccessor(ptr, &index); + + if ((zero_area == vx_false_e) && (constant == vx_true_e)) { - vx_imagepatch_addressing_t addr; - void *base = nullptr; - if (vxAccessImagePatch(image, &rect, p, &addr, &base, VX_WRITE_ONLY) == VX_SUCCESS) + /* we tried to modify constant data! */ + VX_PRINT(VX_ZONE_ERROR, "Can't set constant image data!\n"); + status = VX_ERROR_NOT_SUPPORTED; + /* don't modify the accessor here, it's an error case */ + goto exit; + } + else if (zero_area == vx_false_e && constant == vx_false_e) + { + /* this could be a write-back */ + if (internal == vx_true_e && context->accessors[index].usage == VX_READ_ONLY) { - Image::printImageAddressing(&addr); - width = (format == VX_DF_IMAGE_U1) ? addr.dim_x - rect.start_x % 8 : addr.dim_x; - height = addr.dim_y; - for (y = 0; y < height; y+=addr.step_y) + /* this is a buffer that we allocated on behalf of the user and now they are done. + * Do nothing else*/ + context->removeAccessor(index); + } + else + { + /* determine if this grows the valid region */ + if (region.start_x > start_x) region.start_x = start_x; + if (region.start_y > start_y) region.start_y = start_y; + if (region.end_x < end_x) region.end_x = end_x; + if (region.end_y < end_y) region.end_y = end_y; + + /* index of 1 pixel line past last. */ + i = (memory.dims[plane_index][VX_DIM_Y] * memory.strides[plane_index][VX_DIM_Y]); + + VX_PRINT(VX_ZONE_IMAGE, "base:%p tmp:%p end:%p\n", memory.ptrs[plane_index], ptr, + &memory.ptrs[plane_index][i]); + + if ((memory.ptrs[plane_index] <= (vx_uint8 *)ptr) && + ((vx_uint8 *)ptr < &memory.ptrs[plane_index][i])) { - for (x = 0; x < width; x+=addr.step_x) + /* corner case for 2d memory */ + if (memory.strides[plane_index][VX_DIM_X] != 0 + ? /* Integer byte size data format */ + memory.strides[plane_index][VX_DIM_Y] != + (int)memory.dims[plane_index][VX_DIM_X] * + memory.strides[plane_index][VX_DIM_X] + : /* Non-integer byte size data format */ + memory.strides[plane_index][VX_DIM_Y] != + ((int)memory.dims[plane_index][VX_DIM_X] * + memory.stride_x_bits[plane_index] + + 7) / + 8) { - if (format == VX_DF_IMAGE_U1) - { - vx_uint32 xShftd = x + rect.start_x % 8; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, xShftd, y, &addr)); - vx_uint8 offset = xShftd % 8; - vx_uint8 mask = 1 << offset; - *ptr = (*ptr & ~mask) | ((pixel_value->U1 ? 1 : 0) << offset); - } - if (format == VX_DF_IMAGE_U8) - { - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel_value->U8; - } - else if (format == VX_DF_IMAGE_U16) - { - vx_uint16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel_value->U16; - } - else if (format == VX_DF_IMAGE_U32) - { - vx_uint32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel_value->U32; - } - else if (format == VX_DF_IMAGE_S16) - { - vx_int16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel_value->S16; - } - else if (format == VX_DF_IMAGE_S32) - { - vx_int32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel_value->S32; - } - else if ((format == VX_DF_IMAGE_RGB) || - (format == VX_DF_IMAGE_RGBX)) - { - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = pixel_value->RGBX[0]; - ptr[1] = pixel_value->RGBX[1]; - ptr[2] = pixel_value->RGBX[2]; - if (format == VX_DF_IMAGE_RGBX) - ptr[3] = pixel_value->RGBX[3]; - } - else if ((format == VX_DF_IMAGE_YUV4) || - (format == VX_DF_IMAGE_IYUV)) - { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel[p]; - } - else if ((p == 0) && - ((format == VX_DF_IMAGE_NV12) || - (format == VX_DF_IMAGE_NV21))) - { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - *ptr = pixel[0]; - } - else if ((p == 1) && (format == VX_DF_IMAGE_NV12)) - { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = pixel[1]; - ptr[1] = pixel[2]; - } - else if ((p == 1) && (format == VX_DF_IMAGE_NV21)) + /* determine if the pointer is within the image boundary. */ + vx_uint8 *base = memory.ptrs[plane_index]; + vx_size offset = + ((vx_size)(tmp - base)) % memory.strides[plane_index][VX_DIM_Y]; + if (memory.strides[plane_index][VX_DIM_X] != 0 + ? /* Integer byte size data format */ + offset < (vx_size)(memory.dims[plane_index][VX_DIM_X] * + memory.strides[plane_index][VX_DIM_X]) + : /* Non-integer byte size data format */ + offset < (vx_size)(memory.dims[plane_index][VX_DIM_X] * + memory.stride_x_bits[plane_index] + + 7) / + 8ul) { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - ptr[0] = pixel[2]; - ptr[1] = pixel[1]; + VX_PRINT(VX_ZONE_IMAGE, "Pointer is within 2D image\n"); + external = vx_false_e; } - else if (format == VX_DF_IMAGE_UYVY) + } + else + { + /* the pointer in contained in the image, so it was mapped, thus + * there's nothing else to do. */ + external = vx_false_e; + VX_PRINT(VX_ZONE_IMAGE, "Mapped pointer detected!\n"); + } + } + if (external == vx_true_e || internal == vx_true_e) + { + if (internal == vx_true_e) + { + /* Copy the patch back _to_ the image + * (For non-integer byte size images line-by-line copying only works if the + * patch starts and ends at byte boundaries or at the left/right edges of + * the image's valid region) */ + if (addr->stride_x == memory.strides[plane_index][VX_DIM_X] && + (addr->stride_x != 0 + ? 1 + : (addr->stride_x_bits == memory.stride_x_bits[plane_index] && + (start_x * addr->stride_x_bits % 8 == 0 || + start_x == region.start_x) && + (end_x * addr->stride_x_bits % 8 == 0 || + end_x == region.end_x)))) { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - if (x % 2 == 0) + /* Both source and destination have compact lines */ + vx_uint32 y; + for (y = start_y; y < end_y; y += addr->step_y) { - ptr[0] = pixel[1]; - ptr[1] = pixel[0]; + vx_uint32 i = + Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint32 j = Image::computePatchOffset(0, (y - start_y), addr); + vx_uint32 len = + Image::computePatchRangeSize((end_x - start_x), addr); + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", + memory.ptrs[plane_index], i, tmp, j, len); + memcpy(&memory.ptrs[plane_index][i], &tmp[j], len); } - else + } + + else + { + /* The source is not compact, we need to copy per element */ + vx_uint32 x, y; + vx_uint8 *pDestLine = &tmp[0]; + for (y = start_y; y < end_y; y += addr->step_y) { - ptr[0] = pixel[2]; - ptr[1] = pixel[0]; + vx_uint8 *pSrc = pDestLine; + + vx_uint32 offset = + Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pDest = &memory.ptrs[plane_index][offset]; + + for (x = start_x; x < end_x; x += addr->step_x) + { + if (format == VX_DF_IMAGE_U1) + { + /* U1 patch not starting and ending at byte boundary or + * left/right edges of valid region in image, do + * pixel-by-pixel copy to the image */ + offset = Image::computePlaneOffset(this, x, y, plane_index); + pDest = &memory.ptrs[plane_index][offset]; + pSrc = &pDestLine[Image::computePatchOffset( + x - start_x + start_x % 8, 0, addr)]; + + vx_uint8 mask = 1 << (x % 8); + *pDest = (*pDest & ~mask) | (*pSrc & mask); + } + else + { + /* One element */ + memcpy(pDest, pSrc, memory.strides[plane_index][VX_DIM_X]); + + pDest += memory.strides[plane_index][VX_DIM_X]; + pSrc += addr->stride_x; + } + } + VX_PRINT(VX_ZONE_IMAGE, + "Copied %u pixels from row %u in imagepatch starting at " + "%p to image starting " + "at %p\n", + end_x - start_x, y - start_y, tmp, + memory.ptrs[plane_index]); + + pDestLine += addr->stride_y; } } - else if (format == VX_DF_IMAGE_YUYV) + + /* a write only or read/write copy */ + context->removeAccessor(index); + } + else + { + /* copy the patch back to the image. */ + vx_uint32 x, y, i, j, len; + for (y = start_y; y < end_y; y += addr->step_y) { - vx_uint8 *pixel = (vx_uint8 *)&pixel_value->YUV; - vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); - if (x % 2 == 0) + if (format == VX_DF_IMAGE_U1) { - ptr[0] = pixel[0]; - ptr[1] = pixel[1]; + /* U1: Do pixel-by-pixel copy to the image in case patch doesn't + * start or end at a byte boundary or at the left/right edges of the + * valid region */ + for (x = start_x; x < end_x; x += addr->step_x) + { + i = Image::computePlaneOffset(this, x, y, plane_index); + j = Image::computePatchOffset((x - start_x + start_x % 8), + (y - start_y), addr); + + vx_uint8 mask = 1 << (x % 8); + memory.ptrs[plane_index][i] = + (memory.ptrs[plane_index][i] & ~mask) | (tmp[j] & mask); + } + VX_PRINT(VX_ZONE_IMAGE, + "Copied %u pixels from row %u in external patch starting " + "at %p to image starting " + "at %p\n", + end_x - start_x, y - start_y, tmp, + memory.ptrs[plane_index]); } else { - ptr[0] = pixel[0]; - ptr[1] = pixel[2]; + i = Image::computePlaneOffset(this, start_x, y, plane_index); + j = Image::computePatchOffset(0, (y - start_y), addr); + len = Image::computePatchRangeSize((end_x - start_x), addr); + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", + memory.ptrs[plane_index], i, tmp, j, len); + memcpy(&memory.ptrs[plane_index][i], &tmp[j], len); } } } } - if (vxCommitImagePatch(image, &rect, p, &addr, base) != VX_SUCCESS) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to set initial image patch on plane %u on const image!\n", p); - status = VX_FAILURE; - break; - } + // ownWroteToReference(&base); } - else + status = VX_SUCCESS; + Osal::semPost(&memory.locks[plane_index]); + } + else if (zero_area == vx_true_e) + { + /* could be RO|WO|RW where they decided not to commit anything. */ + if (internal == vx_true_e) // RO { - VX_PRINT(VX_ZONE_ERROR, "Failed to get image patch on plane %u in const image!\n",p); - status = VX_FAILURE; - break; + context->removeAccessor(index); } - } /* for loop */ - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; + else // RW|WO + { + /*! \bug (possible bug, but maybe not) anyone can decrement an + * image access, should we limit to incrementor? that would be + * a lot to track */ + Osal::semPost(&memory.locks[plane_index]); + } + status = VX_SUCCESS; + } + VX_PRINT(VX_ZONE_IMAGE, "Decrementing Image Reference\n"); + decrementReference(VX_EXTERNAL); } +exit: + VX_PRINT(VX_ZONE_API, "return %d\n", status); return status; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseImage(vx_image* image) +vx_status Image::copyPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, + const vx_imagepatch_addressing_t *addr, void *ptr, vx_enum usage, + vx_enum mem_type) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; - if (image != nullptr) + vx_uint32 start_x = rect ? rect->start_x : 0u; + vx_uint32 start_y = rect ? rect->start_y : 0u; + vx_uint32 end_x = rect ? rect->end_x : 0u; + vx_uint32 end_y = rect ? rect->end_y : 0u; + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + + /* bad parameters */ + if (((VX_READ_ONLY != usage) && (VX_WRITE_ONLY != usage)) || (rect == nullptr) || + (addr == nullptr) || (ptr == nullptr)) { - vx_image this_image = *image; - if (Reference::isValidReference((vx_reference)this_image, VX_TYPE_IMAGE) == vx_true_e) + status = VX_ERROR_INVALID_PARAMETERS; + } + + /* determine if virtual before checking for memory */ + if (VX_SUCCESS == status && is_virtual == vx_true_e) + { + if (is_accessible == vx_false_e) { - vx_image parent = this_image->parent; + /* User tried to access a "virtual" image. */ + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + } + /* framework trying to access a virtual image, this is ok. */ + } - /* clear this image from its parent' subimages list */ - if (parent && Reference::isValidReference((vx_reference)parent, VX_TYPE_IMAGE) == vx_true_e) + /* more bad parameters */ + if (VX_SUCCESS == status) + { + if (zero_area == vx_true_e || ((plane_index >= memory.nptrs) || (plane_index >= planes) || + (start_x >= end_x) || (start_y >= end_y))) + { + status = VX_ERROR_INVALID_PARAMETERS; + } + } + + /* The image needs to be allocated */ + if ((VX_SUCCESS == status) && (memory.ptrs[0] == nullptr) && (allocateImage() == vx_false_e)) + { + VX_PRINT(VX_ZONE_ERROR, "No memory!\n"); + status = VX_ERROR_NO_MEMORY; + } + + /* can't write to constant */ + if ((VX_SUCCESS == status) && (constant == vx_true_e) && (usage == VX_WRITE_ONLY)) + { + status = VX_ERROR_NOT_SUPPORTED; + VX_PRINT(VX_ZONE_ERROR, "Can't write to constant data, only read!\n"); + vxAddLogEntry(reinterpret_cast(this), status, + "Can't write to constant data, only read!\n"); + } + + /* Inconsistent strides for non-integer byte size data? */ + if ((VX_SUCCESS == status) && + (addr->stride_x == 0 || memory.strides[plane_index][VX_DIM_X] == 0) && + (addr->stride_x_bits != memory.stride_x_bits[plane_index])) + { + VX_PRINT(VX_ZONE_ERROR, + "Copying of non-integer byte size data without preserving stride in " + "x-dimension is not supported! Attempted to copy with strides {stride_x, " + "stride_x_bits}:" + " {%d, %u} %s {%d, %u}\n", + addr->stride_x, addr->stride_x_bits, usage == VX_READ_ONLY ? "<-" : "->", + memory.strides[plane_index][VX_DIM_X], memory.stride_x_bits[plane_index]); + status = VX_ERROR_NOT_SUPPORTED; + } + + /*************************************************************************/ + if (VX_SUCCESS == status) + { + VX_PRINT(VX_ZONE_IMAGE, + "CopyImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", + this, ptr, start_x, start_y, end_x, end_y, plane_index); + +#ifdef OPENVX_USE_OPENCL_INTEROP + void *ptr_given = ptr; + vx_enum mem_type_given = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + size_t size = 0; + cl_mem opencl_buf = (cl_mem)ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyImagePatch: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) { - vx_uint32 n; - for (n = 0; n < VX_INT_MAX_REF; n++) + return VX_ERROR_INVALID_PARAMETERS; + } + ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyImagePatch: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", opencl_buf, + (int)size, ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + + if (usage == VX_READ_ONLY) + { + /* Copy from image (READ) mode */ + + vx_uint32 x; + vx_uint32 y; + vx_uint8 *pSrc = memory.ptrs[plane_index]; + vx_uint8 *pDst = (vx_uint8 *)ptr; + + vx_imagepatch_addressing_t addr_save = VX_IMAGEPATCH_ADDR_INIT; + + /* Strides given by the application */ + addr_save.dim_x = addr->dim_x; + addr_save.dim_y = addr->dim_y; + addr_save.stride_x = addr->stride_x; + addr_save.stride_y = addr->stride_y; + addr_save.stride_x_bits = addr->stride_x_bits; + + addr_save.step_x = scale[plane_index][VX_DIM_X]; + addr_save.step_y = scale[plane_index][VX_DIM_Y]; + addr_save.scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr_save.scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; + + /* Copy the patch _from_ the image + * (For non-integer byte size images line-by-line copying only works if the patch starts + * and ends at byte boundaries) */ + if (addr_save.stride_x == memory.strides[plane_index][VX_DIM_X] && + (addr_save.stride_x != 0 + ? 1 + : (addr_save.stride_x_bits == memory.stride_x_bits[plane_index] && + start_x * addr_save.stride_x_bits % 8 == 0 && + end_x * addr_save.stride_x_bits % 8 == 0))) + { + /* Both have compact lines */ + for (y = start_y; y < end_y; y += addr_save.step_y) { - if (parent->subimages[n] == this_image) + vx_uint32 srcOffset = Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; + + vx_uint32 dstOffset = Image::computePatchOffset(0, (y - start_y), &addr_save); + vx_uint8 *pDstLine = &pDst[dstOffset]; + + vx_uint32 len = + Image::computePlaneRangeSize(this, end_x - start_x /*width*/, plane_index); + + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, + srcOffset, len); + + memcpy(pDstLine, pSrcLine, len); + } + } + else + { + /* The destination is not compact, we need to copy per element */ + for (y = start_y; y < end_y; y += addr_save.step_y) + { + vx_uint32 srcOffset = Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; + + vx_uint8 *pDstLine = pDst; + + vx_uint32 bitShiftU1 = start_x % 8; // U1 start_x pixel bit-shift + vx_uint32 len = memory.strides[plane_index][VX_DIM_X]; + + for (x = start_x; x < end_x; x += addr_save.step_x) { - parent->subimages[n] = nullptr; - break; + if (format == VX_DF_IMAGE_U1) + { + /* U1 patch not starting and ending at byte boundary in image, + * do pixel-by-pixel copy from the image */ + vx_uint8 mask = 1 << (x % 8); + pDstLine[(x - start_x + bitShiftU1) / 8] = + (pDstLine[(x - start_x + bitShiftU1) / 8] & ~mask) | + (pSrcLine[(x - start_x + bitShiftU1) / 8] & mask); + } + else + { + /* One element */ + memcpy(pDstLine, pSrcLine, len); + + pSrcLine += len; + pDstLine += addr_save.stride_x; + } } + VX_PRINT(VX_ZONE_IMAGE, + "Copied %u pixels from row %u in image starting at %p to patch " + "starting at %p\n", + end_x - start_x, y, memory.ptrs[plane_index], ptr); + + pDst += addr_save.stride_y; } } - status = Reference::releaseReference((vx_reference*)image, VX_TYPE_IMAGE, VX_EXTERNAL, nullptr); + VX_PRINT(VX_ZONE_IMAGE, "Copied image into %p\n", ptr); + + // ownReadFromReference(&base); } - } + else + { + /* Copy to image (WRITE) mode */ + vx_uint32 x; + vx_uint32 y; + vx_uint8 *pSrc = (vx_uint8 *)ptr; + vx_uint8 *pDst = memory.ptrs[plane_index]; - VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); - return status; -} + vx_imagepatch_addressing_t addr_save = VX_IMAGEPATCH_ADDR_INIT; -VX_API_ENTRY vx_size VX_API_CALL vxComputeImagePatchSize(vx_image image, - const vx_rectangle_t *rect, - vx_uint32 plane_index) -{ - vx_size size = 0ul; - vx_uint32 start_x = 0u, start_y = 0u, end_x = 0u, end_y = 0u; + /* Strides given by the application */ + addr_save.dim_x = addr->dim_x; + addr_save.dim_y = addr->dim_y; + addr_save.stride_x = addr->stride_x; + addr_save.stride_y = addr->stride_y; + addr_save.stride_x_bits = addr->stride_x_bits; - if ((Image::isValidImage(image) == vx_true_e) && (rect)) - { - start_x = rect->start_x; - start_y = rect->start_y; - end_x = rect->end_x; - end_y = rect->end_y; + addr_save.step_x = scale[plane_index][VX_DIM_X]; + addr_save.step_y = scale[plane_index][VX_DIM_Y]; + addr_save.scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr_save.scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; - if (image->memory.ptrs[0] == nullptr) - { - if (image->allocateImage() == vx_false_e) + /* lock image plane from multiple writers */ + if (Osal::semWait(&memory.locks[plane_index]) == vx_false_e) { - vxAddLogEntry((vx_reference)image, VX_ERROR_NO_MEMORY, "Failed to allocate image!\n"); - return 0; + status = VX_ERROR_NO_RESOURCES; } - } - if (plane_index < image->planes) - { - vx_size pixelSize; - vx_size numPixels = ((end_x-start_x)/image->scale[plane_index][VX_DIM_X]) * - ((end_y-start_y)/image->scale[plane_index][VX_DIM_Y]); - Image::printImage(image); - if (image->memory.strides[plane_index][VX_DIM_X] == 0 && image->memory.stride_x_bits[plane_index] != 0) + + /* Copy the patch _to_ the image + * (For non-integer byte size images line-by-line copying only works if the patch starts + * and ends at byte boundaries or at the left/right edges of the image's valid region) + */ + if (VX_SUCCESS == status && + addr_save.stride_x == memory.strides[plane_index][VX_DIM_X] && + (addr_save.stride_x != 0 + ? 1 + : (addr_save.stride_x_bits == memory.stride_x_bits[plane_index] && + (start_x * addr_save.stride_x_bits % 8 == 0 || start_x == region.start_x) && + (end_x * addr_save.stride_x_bits % 8 == 0 || end_x == region.end_x)))) { - /* data type does not have integer byte size, e.g. VX_DF_IMAGE_U1 image */ - pixelSize = image->memory.stride_x_bits[plane_index]; // bits - if (start_x * pixelSize % 8 != 0) // Handle case where imagepatch doesn't start at byte boundary - start_x -= (start_x * pixelSize % 8) / pixelSize; + /* Both source and destination have compact lines */ + for (y = start_y; y < end_y; y += addr_save.step_y) + { + vx_uint32 srcOffset = Image::computePatchOffset(0, (y - start_y), &addr_save); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; + + vx_uint32 dstOffset = Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pDstLine = &pDst[dstOffset]; + + vx_uint32 len = Image::computePatchRangeSize((end_x - start_x), &addr_save); + + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, + srcOffset, len); - vx_size lineSize = ( (end_x-start_x) / image->scale[plane_index][VX_DIM_X] * pixelSize + 7ul ) / 8ul; - VX_PRINT(VX_ZONE_IMAGE, "numPixels = " VX_FMT_SIZE " pixelSize = " VX_FMT_SIZE " bits\n", numPixels, pixelSize); - size = lineSize * ( (end_y-start_y) / image->scale[plane_index][VX_DIM_Y] ); + memcpy(pDstLine, pSrcLine, len); + } } else { - pixelSize = image->memory.strides[plane_index][VX_DIM_X]; - VX_PRINT(VX_ZONE_IMAGE, "numPixels = " VX_FMT_SIZE " pixelSize = " VX_FMT_SIZE "\n", numPixels, pixelSize); - size = numPixels * pixelSize; + /* The destination is not compact, we need to copy per element */ + for (y = start_y; y < end_y; y += addr_save.step_y) + { + vx_uint8 *pSrcLine = pSrc; + + vx_uint32 dstOffset = Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pDstLine = &pDst[dstOffset]; + + vx_uint32 bitShiftU1 = start_x % 8; // U1 start_x pixel bit-shift + vx_uint32 len = memory.strides[plane_index][VX_DIM_X]; + + for (x = start_x; x < end_x; x += addr_save.step_x) + { + if (format == VX_DF_IMAGE_U1) + { + /* U1 patch not starting and ending at byte boundary or left/right edges + * of valid region in image, do pixel-by-pixel copy from the patch */ + vx_uint32 xAdjusted = x - start_x + bitShiftU1; + vx_uint8 mask = 1 << (xAdjusted % 8); + pDstLine[xAdjusted / 8] = (pDstLine[xAdjusted / 8] & ~mask) | + (pSrcLine[xAdjusted / 8] & mask); + } + else + { + /* One element */ + memcpy(pDstLine, pSrcLine, len); + + pSrcLine += addr_save.stride_x; + pDstLine += len; + } + } + VX_PRINT(VX_ZONE_IMAGE, + "Copied %u pixels from row %u in %spatch starting at %p to image " + "starting at %p\n", + end_x - start_x, y - start_x, + (mem_type == VX_MEMORY_TYPE_NONE) ? "image" : "external ", ptr, + memory.ptrs[plane_index]); + + pSrc += addr_save.stride_y; + } } + + VX_PRINT(VX_ZONE_IMAGE, "Copied to image from %p\n", ptr); + + // ownWroteToReference(&base); + /* unlock image plane */ + Osal::semPost(&memory.locks[plane_index]); } - else + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (VX_SUCCESS == status && mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) { - vxAddLogEntry((vx_reference)image, VX_ERROR_INVALID_PARAMETERS, "Plane index %u is out of bounds!", plane_index); + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)ptr_given, ptr, 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); } - - VX_PRINT(VX_ZONE_IMAGE, "image %p for patch {%u,%u to %u,%u} has a byte size of " VX_FMT_SIZE "\n", - image, start_x, start_y, end_x, end_y, size); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Image Reference is invalid!\n"); +#endif } - return size; + + VX_PRINT(VX_ZONE_API, "returned %d\n", status); + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxAccessImagePatch(vx_image image, - const vx_rectangle_t *rect, - vx_uint32 plane_index, - vx_imagepatch_addressing_t *addr, - void **ptr, - vx_enum usage) +vx_status Image::mapPatch(const vx_rectangle_t *rect, vx_uint32 plane_index, vx_map_id *map_id, + vx_imagepatch_addressing_t *addr, void **ptr, vx_enum usage, + vx_enum mem_type, vx_uint32 flags) { - vx_uint8 *p = nullptr; - vx_status status = VX_FAILURE; - vx_bool mapped = vx_false_e; +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_enum mem_type_requested = mem_type; + if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + vx_size size = 0; vx_uint32 start_x = rect ? rect->start_x : 0u; vx_uint32 start_y = rect ? rect->start_y : 0u; vx_uint32 end_x = rect ? rect->end_x : 0u; vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_status status = VX_FAILURE; /* bad parameters */ - if ((usage < VX_READ_ONLY) || (VX_READ_AND_WRITE < usage) || - (addr == nullptr) || (ptr == nullptr)) + if ((rect == nullptr) || (map_id == nullptr) || (addr == nullptr) || (ptr == nullptr)) { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to MapImagePatch!\n"); status = VX_ERROR_INVALID_PARAMETERS; goto exit; } - /* bad references */ - if ((!rect) || - (Image::isValidImage(image) == vx_false_e)) - { - status = VX_ERROR_INVALID_REFERENCE; - goto exit; - } - /* determine if virtual before checking for memory */ - if (image->is_virtual == vx_true_e) + if (is_virtual == vx_true_e) { - if (image->is_accessible == vx_false_e) + if (is_accessible == vx_false_e) { /* User tried to access a "virtual" image. */ VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); @@ -1609,18 +1825,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxAccessImagePatch(vx_image image, } /* more bad parameters */ - if (zero_area == vx_false_e && - ((plane_index >= image->memory.nptrs) || - (plane_index >= image->planes) || - (rect->start_x >= rect->end_x) || - (rect->start_y >= rect->end_y))) + if (zero_area == vx_true_e || ((plane_index >= memory.nptrs) || (plane_index >= planes) || + (start_x >= end_x) || (start_y >= end_y))) { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to MapImagePatch!\n"); status = VX_ERROR_INVALID_PARAMETERS; goto exit; } /* The image needs to be allocated */ - if ((image->memory.ptrs[0] == nullptr) && (image->allocateImage() == vx_false_e)) + if ((memory.ptrs[0] == nullptr) && (allocateImage() == vx_false_e)) { VX_PRINT(VX_ZONE_ERROR, "No memory!\n"); status = VX_ERROR_NO_MEMORY; @@ -1628,1208 +1842,1228 @@ VX_API_ENTRY vx_status VX_API_CALL vxAccessImagePatch(vx_image image, } /* can't write to constant */ - if ((image->constant == vx_true_e) && ((usage == VX_WRITE_ONLY) || - (usage == VX_READ_AND_WRITE))) + if ((constant == vx_true_e) && ((usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE))) { status = VX_ERROR_NOT_SUPPORTED; VX_PRINT(VX_ZONE_ERROR, "Can't write to constant data, only read!\n"); - vxAddLogEntry(reinterpret_cast(image), status, "Can't write to constant data, only read!\n"); + vxAddLogEntry(reinterpret_cast(this), status, + "Can't write to constant data, only read!\n"); goto exit; } /*************************************************************************/ - VX_PRINT(VX_ZONE_IMAGE, "AccessImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", - image, *ptr, rect->start_x, rect->start_y, rect->end_x, rect->end_y, plane_index); - - /* POSSIBILITIES: - * 1.) !*ptr && RO == MAP - * 2.) !*ptr && WO == MAP - * 3.) !*ptr && RW == MAP - * 4.) *ptr && RO||RW == COPY (UNLESS MAP) - */ - - if ((*ptr == nullptr) && ((usage == VX_READ_ONLY) || - (usage == VX_WRITE_ONLY) || - (usage == VX_READ_AND_WRITE))) - { - mapped = vx_true_e; - } + VX_PRINT(VX_ZONE_IMAGE, + "MapImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", this, + *ptr, start_x, start_y, end_x, end_y, plane_index); /* MAP mode */ - if (mapped == vx_true_e) { - vx_uint32 index = 0u; + vx_memory_map_extra extra; + vx_uint8 *buf = 0; - /* lock the memory plane for multiple writers*/ - if (usage != VX_READ_ONLY) { - if (Osal::semWait(&image->memory.locks[plane_index]) == vx_false_e) - { - status = VX_ERROR_NO_RESOURCES; - goto exit; - } - } - Memory::printMemory(&image->memory); - p = (vx_uint8 *)image->memory.ptrs[plane_index]; + size = vxComputeImagePatchSize(this, rect, plane_index); - /* use the addressing of the internal format */ - if (image->format == VX_DF_IMAGE_U1) { - addr->dim_x = rect->end_x - rect->start_x + rect->start_x % 8; // Round start down to byte boundary - } - else { - addr->dim_x = rect->end_x - rect->start_x; + extra.image_data.plane_index = plane_index; + extra.image_data.rect = *rect; + + if (VX_MEMORY_TYPE_NONE != memory_type && + vx_true_e == context->memoryMap((vx_reference)this, 0, usage, mem_type, flags, &extra, + (void **)&buf, map_id)) + { + /* use the addressing of the internal format */ + if (format == VX_DF_IMAGE_U1 && start_x % 8 != 0) + addr->dim_x = end_x - start_x + start_x % 8; + else + addr->dim_x = end_x - start_x; + addr->dim_y = end_y - start_y; + addr->stride_x = memory.strides[plane_index][VX_DIM_X]; + addr->stride_y = memory.strides[plane_index][VX_DIM_Y]; + addr->stride_x_bits = memory.stride_x_bits[plane_index]; + addr->step_x = scale[plane_index][VX_DIM_X]; + addr->step_y = scale[plane_index][VX_DIM_Y]; + addr->scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr->scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; + + buf = memory.ptrs[plane_index]; + + vx_uint32 index = Image::computePatchOffset(rect->start_x, rect->start_y, addr); + *ptr = &buf[index]; + VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p\n", *ptr); + + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; } - addr->dim_y = rect->end_y - rect->start_y; - addr->stride_x = image->memory.strides[plane_index][VX_DIM_X]; - addr->stride_y = image->memory.strides[plane_index][VX_DIM_Y]; - addr->stride_x_bits = image->memory.stride_x_bits[plane_index]; - addr->step_x = image->scale[plane_index][VX_DIM_X]; - addr->step_y = image->scale[plane_index][VX_DIM_Y]; - addr->scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr->scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; + else + /* get mapping buffer of sufficient size and map_id */ + if (vx_true_e == context->memoryMap((vx_reference)this, size, usage, mem_type, flags, + &extra, (void **)&buf, map_id)) + { + /* use the addressing of the internal format */ + if (format == VX_DF_IMAGE_U1 && start_x % 8 != 0) + addr->dim_x = end_x - start_x + start_x % 8; + else + addr->dim_x = end_x - start_x; + addr->dim_y = end_y - start_y; + addr->stride_x = memory.strides[plane_index][VX_DIM_X]; + addr->stride_x_bits = memory.stride_x_bits[plane_index]; + addr->stride_y = + addr->stride_x != 0 + ? addr->stride_x * addr->dim_x / scale[plane_index][VX_DIM_Y] + : (addr->stride_x_bits * addr->dim_x / scale[plane_index][VX_DIM_Y] + 7) / + 8; + addr->step_x = scale[plane_index][VX_DIM_X]; + addr->step_y = scale[plane_index][VX_DIM_Y]; + addr->scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr->scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; + + /* initialize mapping buffer with image patch data for read/read-modify-write access + */ + if (VX_READ_ONLY == usage || VX_READ_AND_WRITE == usage) + { + /* lock image plane even for read access to avoid mix of simultaneous read/write + */ + if (vx_true_e == Osal::semWait(&memory.locks[plane_index])) + { + vx_uint32 y; + vx_uint8 *pSrc = memory.ptrs[plane_index]; + vx_uint8 *pDst = buf; - index = Image::computePatchOffset(rect->start_x, rect->start_y, addr); - *ptr = &p[index]; - VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p which is offset by %lu\n", *ptr, index); + Memory::printMemory(&memory); + + /* Both have compact lines */ + for (y = start_y; y < end_y; y += addr->step_y) + { + vx_uint32 srcOffset = + Image::computePlaneOffset(this, start_x, y, plane_index); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; - // ownReadFromReference(&image->base); - image->incrementReference(VX_EXTERNAL); + vx_uint32 dstOffset = Image::computePatchOffset(0, (y - start_y), addr); + vx_uint8 *pDstLine = &pDst[dstOffset]; - status = VX_SUCCESS; + vx_uint32 len = + Image::computePlaneRangeSize(this, addr->dim_x, plane_index); + + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, + pSrc, srcOffset, len); + + memcpy(pDstLine, pSrcLine, len); + } + + // ownReadFromReference(&base); + + /* we're done, unlock the image plane */ + Osal::semPost(&memory.locks[plane_index]); + } + else + { + status = VX_FAILURE; + VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for mapping\n"); + goto exit; + } + } /* if VX_READ_ONLY or VX_READ_AND_WRITE */ + + *ptr = buf; + VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p\n", *ptr); + + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; + } + else + { + status = VX_FAILURE; + } } - /* COPY mode */ - else +exit: + +#ifdef OPENVX_USE_OPENCL_INTEROP + if ((status == VX_SUCCESS) && context->opencl_context && + (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && (size > 0) && ptr && *ptr) { - /* Inconsistent strides for non-integer byte size data? */ - if ( (addr->stride_x == 0 || image->memory.strides[plane_index][VX_DIM_X] == 0) && - addr->stride_x_bits != image->memory.stride_x_bits[plane_index] ) + /* create OpenCL buffer using the host allocated pointer */ + cl_int cerr = 0; + cl_mem opencl_buf = clCreateBuffer( + context->opencl_context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, size, *ptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapImagePatch: clCreateBuffer(%u) => %p (%d)\n", + (vx_uint32)size, opencl_buf, cerr); + if (cerr == CL_SUCCESS) + { + context->memory_maps[*map_id].opencl_buf = opencl_buf; + *ptr = opencl_buf; + } + else { - VX_PRINT(VX_ZONE_ERROR, "Copying of non-integer byte size data without preserving stride in " - "x-dimension is not supported! Attempted to copy with strides {stride_x, stride_x_bits}:" - " {%d, %u} <- {%d, %u}\n", addr->stride_x, addr->stride_x_bits, - image->memory.strides[plane_index][VX_DIM_X], image->memory.stride_x_bits[plane_index]); - status = VX_ERROR_NOT_SUPPORTED; - goto exit; + status = VX_FAILURE; } + } +#endif - vx_size size = vxComputeImagePatchSize(image, rect, plane_index); - vx_uint32 a = 0u; + VX_PRINT(VX_ZONE_API, "return %d\n", status); + return status; +} - vx_imagepatch_addressing_t *addr_save = new vx_imagepatch_addressing_t(); - /* Strides given by the application */ - addr_save->stride_x = addr->stride_x; - addr_save->stride_y = addr->stride_y; - addr_save->stride_x_bits = addr->stride_x_bits; - /* Computed by the application */ - if (image->format == VX_DF_IMAGE_U1) { - addr->dim_x = addr_save->dim_x = rect->end_x - rect->start_x + rect->start_x % 8; // Round start to byte boundary - } - else { - addr->dim_x = addr_save->dim_x = rect->end_x - rect->start_x; - } - addr->dim_y = addr_save->dim_y = rect->end_y - rect->start_y; - addr->step_x = addr_save->step_x = image->scale[plane_index][VX_DIM_X]; - addr->step_y = addr_save->step_y = image->scale[plane_index][VX_DIM_Y]; - addr->scale_x = addr_save->scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr->scale_y = addr_save->scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; +vx_status Image::unmapPatch(vx_map_id map_id) +{ + vx_status status = VX_SUCCESS; - if (image->context->addAccessor(size, usage, *ptr, image, &a, addr_save) == vx_false_e) - { - status = VX_ERROR_NO_MEMORY; - vxAddLogEntry(reinterpret_cast(image), status, "Failed to allocate memory for COPY! Size=" VX_FMT_SIZE "\n", size); - goto exit; - } + /* bad parameters */ + if (context->findMemoryMap((vx_reference)this, map_id) != vx_true_e) + { + status = VX_ERROR_INVALID_PARAMETERS; + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to unmap image patch\n"); + return status; + } - { - vx_uint32 x, y; - vx_uint8 *tmp = (vx_uint8*)*ptr; +#ifdef OPENVX_USE_OPENCL_INTEROP + if (context->opencl_context && context->memory_maps[map_id].opencl_buf && + context->memory_maps[map_id].ptr) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, + context->memory_maps[map_id].opencl_buf, + context->memory_maps[map_id].ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + cl_int cerr = clReleaseMemObject(context->memory_maps[map_id].opencl_buf); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapImagePatch: clReleaseMemObject(%p) => (%d)\n", + context->memory_maps[map_id].opencl_buf, cerr); + context->memory_maps[map_id].opencl_buf = nullptr; + } +#endif - /*! \todo implement overlapping multi-writers lock, not just single writer lock */ - if ((usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE)) - { - if (Osal::semWait(&image->memory.locks[plane_index]) == vx_false_e) - { - status = VX_ERROR_NO_RESOURCES; - goto exit; - } - } + { + vx_memory_map_t *map = &context->memory_maps[map_id]; - if ((usage == VX_READ_ONLY) || (usage == VX_READ_AND_WRITE)) + if (map->used && map->ref == (vx_reference)this) + { + /* commit changes for write access */ + if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && + nullptr != map->ptr) { - /* Copy the patch _from_ the image - * (For non-integer byte size images line-by-line copying only works if the patch starts and ends - * at byte boundaries) */ - if ( addr_save->stride_x == image->memory.strides[plane_index][VX_DIM_X] && - (addr_save->stride_x != 0 ? 1 : - (addr_save->stride_x_bits == image->memory.stride_x_bits[plane_index] && - rect->start_x * addr_save->stride_x_bits % 8 == 0 && - rect->end_x * addr_save->stride_x_bits % 8 == 0)) ) - { - /* Both have compact lines */ - for (y = rect->start_y; y < rect->end_y; y+=addr_save->step_y) - { - vx_uint32 i = Image::computePlaneOffset(image, rect->start_x, y, plane_index); - vx_uint32 j = Image::computePatchOffset(0, (y - rect->start_y), addr_save); - vx_uint32 len = Image::computePlaneRangeSize(image, addr_save->dim_x, plane_index); - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", tmp, j, image->memory.ptrs[plane_index], i, len); - memcpy(&tmp[j], &image->memory.ptrs[plane_index][i], len); - } - } + vx_uint32 plane_index = map->extra.image_data.plane_index; + vx_rectangle_t rect = map->extra.image_data.rect; - else + /* lock image plane for simultaneous write */ + if (vx_true_e == Osal::semWait(&memory.locks[plane_index])) { - /* The destination is not compact, we need to copy per element */ - vx_uint8 *pDestLine = &tmp[0]; - for (y = rect->start_y; y < rect->end_y; y+=addr_save->step_y) - { - vx_uint8 *pDest = pDestLine; + vx_uint32 x, y; + vx_uint8 *pSrc = (vx_uint8 *)map->ptr; + vx_uint8 *pDst = memory.ptrs[plane_index]; + vx_imagepatch_addressing_t addr = VX_IMAGEPATCH_ADDR_INIT; - vx_uint32 offset = Image::computePlaneOffset(image, rect->start_x, y, plane_index); - vx_uint8 *pSrc = &image->memory.ptrs[plane_index][offset]; + /* use the addressing of the internal format */ + if (format == VX_DF_IMAGE_U1 && rect.start_x % 8 != 0) + addr.dim_x = rect.end_x - rect.start_x + rect.start_x % 8; + else + addr.dim_x = rect.end_x - rect.start_x; + addr.dim_y = rect.end_y - rect.start_y; + addr.stride_x = memory.strides[plane_index][VX_DIM_X]; + addr.stride_x_bits = memory.stride_x_bits[plane_index]; + addr.stride_y = + addr.stride_x != 0 + ? addr.stride_x * addr.dim_x / scale[plane_index][VX_DIM_Y] + : (addr.stride_x_bits * addr.dim_x / scale[plane_index][VX_DIM_Y] + 7) / + 8; + addr.step_x = scale[plane_index][VX_DIM_X]; + addr.step_y = scale[plane_index][VX_DIM_Y]; + addr.scale_x = VX_SCALE_UNITY / scale[plane_index][VX_DIM_X]; + addr.scale_y = VX_SCALE_UNITY / scale[plane_index][VX_DIM_Y]; - for (x = rect->start_x; x < rect->end_x; x+=addr_save->step_x) + /* Both source and destination have compact lines, begin write-back to image + * (For non-integer byte size images line-by-line write-back only works if the + * patch starts and ends at byte boundaries or at the left/right edges of the + * image's valid region) */ + if ((addr.stride_x == 0 && addr.stride_x_bits != 0) && + !((rect.start_x * addr.stride_x_bits % 8 == 0 || + rect.start_x == region.start_x) && + (rect.end_x * addr.stride_x_bits % 8 == 0 || rect.end_x == region.end_x))) + { + /* Pixel-by-pixel write-back */ + for (y = rect.start_y; y < rect.end_y; y += addr.step_y) { - if (image->format == VX_DF_IMAGE_U1) - { - /* U1 patch not starting and ending at byte boundary in image, - * do pixel-by-pixel copy from the image */ - offset = Image::computePlaneOffset(image, x, y, plane_index); - pSrc = &image->memory.ptrs[plane_index][offset]; - pDest = &pDestLine[Image::computePatchOffset(x - rect->start_x + rect->start_x % 8, 0, addr_save)]; + vx_uint32 srcOffset = + Image::computePatchOffset(0, (y - rect.start_y), &addr); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; - vx_uint8 mask = 1 << (x % 8); - *pDest = (*pDest & ~mask) | (*pSrc & mask); - } - else - { - /* One element */ - memcpy(pDest, pSrc, image->memory.strides[plane_index][VX_DIM_X]); + vx_uint32 dstOffset = + Image::computePlaneOffset(this, rect.start_x, y, plane_index); + vx_uint8 *pDstLine = &pDst[dstOffset]; - pSrc += image->memory.strides[plane_index][VX_DIM_X]; - pDest += addr_save->stride_x; + vx_uint32 bitOffset = + rect.start_x % + 8; // Respect pixel bit-offsets (cf. vxMapImagePatch) + + for (x = rect.start_x; x < rect.end_x; x += addr.step_x) + { + vx_uint32 xAdjusted = x - rect.start_x + bitOffset; + vx_uint8 mask = 1 << (xAdjusted % 8); + pDstLine[xAdjusted / 8] = (pDstLine[xAdjusted / 8] & ~mask) | + (pSrcLine[xAdjusted / 8] & mask); } + VX_PRINT(VX_ZONE_IMAGE, + "Wrote back %u pixels from row %u in mapped imagepatch: " + "%p[%u] <= %p[%u]\n", + rect.end_x - rect.start_x, y, pDst, dstOffset, pSrc, + srcOffset); } - VX_PRINT(VX_ZONE_IMAGE, - "Copied %u pixels from row %u in image starting at %p to patch starting at %p\n", - end_x - start_x, y, image->memory.ptrs[plane_index], tmp); + } + else + { + /* Line-by-line write-back */ + for (y = rect.start_y; y < rect.end_y; y += addr.step_y) + { + vx_uint32 srcOffset = + Image::computePatchOffset(0, (y - rect.start_y), &addr); + vx_uint8 *pSrcLine = &pSrc[srcOffset]; + + vx_uint32 dstOffset = + Image::computePlaneOffset(this, rect.start_x, y, plane_index); + vx_uint8 *pDstLine = &pDst[dstOffset]; + + vx_uint32 len = + Image::computePatchRangeSize((rect.end_x - rect.start_x), &addr); - pDestLine += addr_save->stride_y; + VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, + pSrc, srcOffset, len); + + memcpy(pDstLine, pSrcLine, len); + } } - } - VX_PRINT(VX_ZONE_IMAGE, "Copied image into %p\n", *ptr); - // ownReadFromReference(&image->base); + /* we're done, unlock the image plane */ + Osal::semPost(&memory.locks[plane_index]); + } + else + { + status = VX_FAILURE; + VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); + goto exit; + } } - image->incrementReference(VX_EXTERNAL); + /* freeing mapping buffer */ + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); status = VX_SUCCESS; } + else + { + status = VX_FAILURE; + } } + exit: - VX_PRINT(VX_ZONE_API, "returned %d\n", status); + VX_PRINT(VX_ZONE_API, "return %d\n", status); return status; } -VX_API_ENTRY vx_status VX_API_CALL vxCommitImagePatch(vx_image image, - const vx_rectangle_t *rect, - vx_uint32 plane_index, - const vx_imagepatch_addressing_t *addr, - const void *ptr) +void Image::printImage(vx_image image) { - vx_status status = VX_ERROR_INVALID_REFERENCE; - vx_int32 i = 0; - vx_bool external = vx_true_e; // assume that it was an allocated buffer - vx_uint32 start_x = rect ? rect->start_x : 0u; - vx_uint32 start_y = rect ? rect->start_y : 0u; - vx_uint32 end_x = rect ? rect->end_x : 0u; - vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_uint8 *tmp = (vx_uint8 *)ptr; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); - vx_uint32 index = UINT32_MAX; // out of bounds, if given to remove, won't do anything - - if (Image::isValidImage(image) == vx_false_e) - return VX_ERROR_INVALID_REFERENCE; - - VX_PRINT(VX_ZONE_IMAGE, "CommitImagePatch to " VX_FMT_REF " from ptr %p plane %u to {%u,%u},{%u,%u}\n", - image, ptr, plane_index, start_x, start_y, end_x, end_y); + vx_uint32 p = 0; + vx_char df_image[5]; + strncpy(df_image, (char *)&image->format, 4); + df_image[4] = '\0'; + Reference::printReference(image); + VX_PRINT(VX_ZONE_IMAGE, "vx_image:%p %s %ux%u (%s)\n", image, df_image, image->width, image->height, (image->constant?"CONSTANT":"MUTABLE")); + for (p = 0; p < image->planes; p++) + { + VX_PRINT(VX_ZONE_IMAGE, "\tplane[%u] ptr:%p dim={%u,%u,%u} stride={%d,%d,%d} stride_x_bits={%u} scale={%u,%u,%u} bounds={%u,%ux%u,%u}\n", + p, + image->memory.ptrs[p], + image->memory.dims[p][VX_DIM_C], + image->memory.dims[p][VX_DIM_X], + image->memory.dims[p][VX_DIM_Y], + image->memory.strides[p][VX_DIM_C], + image->memory.strides[p][VX_DIM_X], + image->memory.strides[p][VX_DIM_Y], + image->memory.stride_x_bits[p], + image->scale[p][VX_DIM_C], + image->scale[p][VX_DIM_X], + image->scale[p][VX_DIM_Y], + image->bounds[p][VX_DIM_X][VX_BOUND_START], + image->bounds[p][VX_DIM_X][VX_BOUND_END], + image->bounds[p][VX_DIM_Y][VX_BOUND_START], + image->bounds[p][VX_DIM_Y][VX_BOUND_END]); + } +} - Image::printImage(image); - Image::printImageAddressing(addr); +void Image::printImageAddressing(const vx_imagepatch_addressing_t *addr) +{ + if (addr) + { + VX_PRINT(VX_ZONE_IMAGE, "addr:%p dim={%u,%u} stride={%d,%d} stride_x_bits={%u} scale={%u,%u} step={%u,%u}\n", + addr, + addr->dim_x, addr->dim_y, + addr->stride_x, addr->stride_y, + addr->stride_x_bits, + addr->scale_x, addr->scale_y, + addr->step_x, addr->step_y); + } +} - /* determine if virtual before checking for memory */ - if (image->is_virtual == vx_true_e && zero_area == vx_false_e) +void Image::destruct() +{ + /* if it's not imported and does not have a parent, free it */ + if ((memory_type == VX_MEMORY_TYPE_NONE) && (parent == nullptr)) + { + freeImage(); + } + else if (parent) + { + Reference::releaseReference((vx_reference*)&parent, VX_TYPE_IMAGE, VX_INTERNAL, nullptr); + } + else if (memory_type != VX_MEMORY_TYPE_NONE) { - if (image->is_accessible == vx_false_e) + vx_uint32 p = 0u; + for (p = 0; p < planes; p++) { - /* User tried to access a "virtual" image. */ - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - goto exit; + Osal::destroySem(&memory.locks[p]); + memory.ptrs[p] = nullptr; + memory.strides[p][VX_DIM_C] = 0; + memory.strides[p][VX_DIM_X] = 0; + memory.strides[p][VX_DIM_Y] = 0; + memory.stride_x_bits[p] = 0; } - /* framework trying to access a virtual image, this is ok. */ + memory.allocated = vx_false_e; } +} - if (zero_area == vx_false_e && - ((plane_index >= image->planes) || - (plane_index >= image->memory.nptrs) || - (ptr == nullptr) || - (addr == nullptr))) - { - return VX_ERROR_INVALID_PARAMETERS; - } +/******************************************************************************/ +/* PUBLIC API */ +/******************************************************************************/ - /* check the rectangle, it has to be in actual plane space */ - if (zero_area == vx_false_e && - ((start_x >= end_x) || ((end_x - start_x) > addr->dim_x) || - (start_y >= end_y) || ((end_y - start_y) > addr->dim_y) || - (end_x > (vx_uint32)image->memory.dims[plane_index][VX_DIM_X] * (vx_uint32)image->scale[plane_index][VX_DIM_X]) || - (end_y > (vx_uint32)image->memory.dims[plane_index][VX_DIM_Y] * (vx_uint32)image->scale[plane_index][VX_DIM_X]))) +VX_API_ENTRY vx_image VX_API_CALL vxCreateImage(vx_context context, vx_uint32 width, vx_uint32 height, vx_df_image format) +{ + if ((width == 0) || (height == 0) || + (Image::isSupportedFourcc(format) == vx_false_e) || (format == VX_DF_IMAGE_VIRT)) { - VX_PRINT(VX_ZONE_ERROR, "Invalid start,end coordinates! plane %u {%u,%u},{%u,%u}\n", - plane_index, start_x, start_y, end_x, end_y); - Image::printImage(image); - DEBUG_BREAK(); - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; + return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } + return (vx_image)Image::createImage(context, width, height, format, vx_false_e); +} - /* Inconsistent strides for non-integer byte size data? */ - if ( (addr->stride_x == 0 || image->memory.strides[plane_index][VX_DIM_X] == 0) && - addr->stride_x_bits != image->memory.stride_x_bits[plane_index] ) +VX_API_ENTRY vx_image VX_API_CALL vxCreateUniformImage(vx_context context, vx_uint32 width, vx_uint32 height, vx_df_image format, const vx_pixel_value_t *value) +{ + vx_image image = 0; + + if (value == nullptr) { - VX_PRINT(VX_ZONE_ERROR, "Copying of non-integer byte size data without preserving stride in " - "x-dimension is not supported! Attempted to copy with strides {stride_x, stride_x_bits}:" - " {%u, %u} -> {%u, %u}\n", addr->stride_x, addr->stride_x_bits, - image->memory.strides[plane_index][VX_DIM_X], image->memory.stride_x_bits[plane_index]); - status = VX_ERROR_NOT_SUPPORTED; - goto exit; + return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } + image = vxCreateImage(context, width, height, format); + if (vxGetStatus((vx_reference)image) == VX_SUCCESS) { - /* VARIABLES: - * 1.) ZERO_AREA - * 2.) CONSTANT - independant - * 3.) INTERNAL - independant of area - * 4.) EXTERNAL - dependant on area (do nothing on zero, determine on non-zero) - * 5.) !INTERNAL && !EXTERNAL == MAPPED - */ - vx_bool internal = image->context->findAccessor(ptr, &index); - - if ((zero_area == vx_false_e) && (image->constant == vx_true_e)) - { - /* we tried to modify constant data! */ - VX_PRINT(VX_ZONE_ERROR, "Can't set constant image data!\n"); - status = VX_ERROR_NOT_SUPPORTED; - /* don't modify the accessor here, it's an error case */ - goto exit; - } - else if (zero_area == vx_false_e && image->constant == vx_false_e) + vx_uint32 x, y, p; + vx_size planes = 0; + vx_rectangle_t rect = {0, 0, width, height}; + vxQueryImage(image, VX_IMAGE_PLANES, &planes, sizeof(planes)); + for (p = 0; p < planes; p++) { - /* this could be a write-back */ - if (internal == vx_true_e && image->context->accessors[index].usage == VX_READ_ONLY) - { - /* this is a buffer that we allocated on behalf of the user and now they are done. Do nothing else*/ - image->context->removeAccessor(index); - } - else + vx_imagepatch_addressing_t addr; + void *base = nullptr; + if (vxAccessImagePatch(image, &rect, p, &addr, &base, VX_WRITE_ONLY) == VX_SUCCESS) { - /* determine if this grows the valid region */ - if (image->region.start_x > start_x) - image->region.start_x = start_x; - if (image->region.start_y > start_y) - image->region.start_y = start_y; - if (image->region.end_x < end_x) - image->region.end_x = end_x; - if (image->region.end_y < end_y) - image->region.end_y = end_y; - - /* index of 1 pixel line past last. */ - i = (image->memory.dims[plane_index][VX_DIM_Y] * image->memory.strides[plane_index][VX_DIM_Y]); - - VX_PRINT(VX_ZONE_IMAGE, "base:%p tmp:%p end:%p\n", - image->memory.ptrs[plane_index], ptr, &image->memory.ptrs[plane_index][i]); - - if ((image->memory.ptrs[plane_index] <= (vx_uint8 *)ptr) && - ((vx_uint8 *)ptr < &image->memory.ptrs[plane_index][i])) + Image::printImageAddressing(&addr); + for (y = 0; y < addr.dim_y; y+=addr.step_y) { - /* corner case for 2d memory */ - if (image->memory.strides[plane_index][VX_DIM_X] != 0 - ? /* Integer byte size data format */ - image->memory.strides[plane_index][VX_DIM_Y] != - (int)image->memory.dims[plane_index][VX_DIM_X] * image->memory.strides[plane_index][VX_DIM_X] - : /* Non-integer byte size data format */ - image->memory.strides[plane_index][VX_DIM_Y] != - ((int)image->memory.dims[plane_index][VX_DIM_X] * image->memory.stride_x_bits[plane_index] + 7) / 8) + for (x = 0; x < addr.dim_x; x+=addr.step_x) { - /* determine if the pointer is within the image boundary. */ - vx_uint8 *base = image->memory.ptrs[plane_index]; - vx_size offset = ((vx_size)(tmp - base)) % image->memory.strides[plane_index][VX_DIM_Y]; - if (image->memory.strides[plane_index][VX_DIM_X] != 0 - ? /* Integer byte size data format */ - offset < (vx_size)(image->memory.dims[plane_index][VX_DIM_X] * - image->memory.strides[plane_index][VX_DIM_X]) - : /* Non-integer byte size data format */ - offset < (vx_size)(image->memory.dims[plane_index][VX_DIM_X] * - image->memory.stride_x_bits[plane_index] + 7) / 8ul) + if (format == VX_DF_IMAGE_U1) { - VX_PRINT(VX_ZONE_IMAGE, "Pointer is within 2D image\n"); - external = vx_false_e; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + vx_uint8 offset = x % 8; + vx_uint8 mask = 1 << offset; + *ptr = (*ptr & ~mask) | ((value->U1 ? 1 : 0) << offset); } - } - else - { - /* the pointer in contained in the image, so it was mapped, thus - * there's nothing else to do. */ - external = vx_false_e; - VX_PRINT(VX_ZONE_IMAGE, "Mapped pointer detected!\n"); - } - } - if (external == vx_true_e || internal == vx_true_e) - { - if (internal == vx_true_e) - { - /* Copy the patch back _to_ the image - * (For non-integer byte size images line-by-line copying only works if the patch starts - * and ends at byte boundaries or at the left/right edges of the image's valid region) */ - if ( addr->stride_x == image->memory.strides[plane_index][VX_DIM_X] && - (addr->stride_x != 0 ? 1 : - (addr->stride_x_bits == image->memory.stride_x_bits[plane_index] && - (start_x * addr->stride_x_bits % 8 == 0 || start_x == image->region.start_x) && - (end_x * addr->stride_x_bits % 8 == 0 || end_x == image->region.end_x ))) ) + if (format == VX_DF_IMAGE_U8) + { + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = value->U8; + } + else if (format == VX_DF_IMAGE_U16) + { + vx_uint16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = value->U16; + } + else if (format == VX_DF_IMAGE_U32) + { + vx_uint32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = value->U32; + } + else if (format == VX_DF_IMAGE_S16) + { + vx_int16 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = value->S16; + } + else if (format == VX_DF_IMAGE_S32) + { + vx_int32 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = value->S32; + } + else if ((format == VX_DF_IMAGE_RGB) || + (format == VX_DF_IMAGE_RGBX)) + { + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = value->RGBX[0]; + ptr[1] = value->RGBX[1]; + ptr[2] = value->RGBX[2]; + if (format == VX_DF_IMAGE_RGBX) + ptr[3] = value->RGBX[3]; + } + else if ((format == VX_DF_IMAGE_YUV4) || + (format == VX_DF_IMAGE_IYUV)) + { + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel[p]; + } + else if ((p == 0) && + ((format == VX_DF_IMAGE_NV12) || + (format == VX_DF_IMAGE_NV21))) + { + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + *ptr = pixel[0]; + } + else if ((p == 1) && (format == VX_DF_IMAGE_NV12)) + { + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = pixel[1]; + ptr[1] = pixel[2]; + } + else if ((p == 1) && (format == VX_DF_IMAGE_NV21)) { - /* Both source and destination have compact lines */ - vx_uint32 y; - for (y = start_y; y < end_y; y+=addr->step_y) - { - vx_uint32 i = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint32 j = Image::computePatchOffset(0, (y - start_y), addr); - vx_uint32 len = Image::computePatchRangeSize((end_x - start_x), addr); - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", - image->memory.ptrs[plane_index], i, tmp, j, len); - memcpy(&image->memory.ptrs[plane_index][i], &tmp[j], len); - } + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + ptr[0] = pixel[2]; + ptr[1] = pixel[1]; } - - else + else if (format == VX_DF_IMAGE_UYVY) { - /* The source is not compact, we need to copy per element */ - vx_uint32 x, y; - vx_uint8 *pDestLine = &tmp[0]; - for (y = start_y; y < end_y; y+=addr->step_y) + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + if (x % 2 == 0) { - vx_uint8 *pSrc = pDestLine; - - vx_uint32 offset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8 *pDest = &image->memory.ptrs[plane_index][offset]; - - for (x = start_x; x < end_x; x+=addr->step_x) - { - if (image->format == VX_DF_IMAGE_U1) - { - /* U1 patch not starting and ending at byte boundary or left/right edges - * of valid region in image, do pixel-by-pixel copy to the image */ - offset = Image::computePlaneOffset(image, x, y, plane_index); - pDest = &image->memory.ptrs[plane_index][offset]; - pSrc = &pDestLine[Image::computePatchOffset(x - start_x + start_x % 8, 0, addr)]; - - vx_uint8 mask = 1 << (x % 8); - *pDest = (*pDest & ~mask) | (*pSrc & mask); - } - else - { - /* One element */ - memcpy(pDest, pSrc, image->memory.strides[plane_index][VX_DIM_X]); - - pDest += image->memory.strides[plane_index][VX_DIM_X]; - pSrc += addr->stride_x; - } - } - VX_PRINT(VX_ZONE_IMAGE, - "Copied %u pixels from row %u in imagepatch starting at %p to image starting " - "at %p\n", end_x - start_x, y - start_y, tmp, image->memory.ptrs[plane_index]); - - pDestLine += addr->stride_y; + ptr[0] = pixel[1]; + ptr[1] = pixel[0]; + } + else + { + ptr[0] = pixel[2]; + ptr[1] = pixel[0]; } } - - /* a write only or read/write copy */ - image->context->removeAccessor(index); - } - else - { - /* copy the patch back to the image. */ - vx_uint32 x, y, i, j, len; - for (y = start_y; y < end_y; y+=addr->step_y) + else if (format == VX_DF_IMAGE_YUYV) { - if (image->format == VX_DF_IMAGE_U1) + vx_uint8 *pixel = (vx_uint8 *)&value->YUV; + vx_uint8 *ptr = reinterpret_cast(vxFormatImagePatchAddress2d(base, x, y, &addr)); + if (x % 2 == 0) { - /* U1: Do pixel-by-pixel copy to the image in case patch doesn't start or - * end at a byte boundary or at the left/right edges of the valid region */ - for (x = start_x; x < end_x; x+=addr->step_x) - { - i = Image::computePlaneOffset(image, x, y, plane_index); - j = Image::computePatchOffset((x - start_x + start_x % 8), (y - start_y), addr); - - vx_uint8 mask = 1 << (x % 8); - image->memory.ptrs[plane_index][i] = - (image->memory.ptrs[plane_index][i] & ~mask) | (tmp[j] & mask); - } - VX_PRINT(VX_ZONE_IMAGE, - "Copied %u pixels from row %u in external patch starting at %p to image starting " - "at %p\n", end_x - start_x, y - start_y, tmp, image->memory.ptrs[plane_index]); + ptr[0] = pixel[0]; + ptr[1] = pixel[1]; } else { - i = Image::computePlaneOffset(image, start_x, y, plane_index); - j = Image::computePatchOffset(0, (y - start_y), addr); - len = Image::computePatchRangeSize((end_x - start_x), addr); - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", - image->memory.ptrs[plane_index], i, tmp, j, len); - memcpy(&image->memory.ptrs[plane_index][i], &tmp[j], len); + ptr[0] = pixel[0]; + ptr[1] = pixel[2]; } } - } } - // ownWroteToReference(&image->base); - } - status = VX_SUCCESS; - Osal::semPost(&image->memory.locks[plane_index]); - } - else if (zero_area == vx_true_e) - { - /* could be RO|WO|RW where they decided not to commit anything. */ - if (internal == vx_true_e) // RO - { - image->context->removeAccessor(index); + if (vxCommitImagePatch(image, &rect, p, &addr, base) != VX_SUCCESS) + { + VX_PRINT(VX_ZONE_ERROR, "Failed to set initial image patch on plane %u on const image!\n", p); + vxReleaseImage(&image); + image = (vx_image)vxGetErrorObject(context, VX_FAILURE); + break; + } } - else // RW|WO + else { - /*! \bug (possible bug, but maybe not) anyone can decrement an - * image access, should we limit to incrementor? that would be - * a lot to track */ - Osal::semPost(&image->memory.locks[plane_index]); + VX_PRINT(VX_ZONE_ERROR, "Failed to get image patch on plane %u in const image!\n",p); + vxReleaseImage(&image); + image = (vx_image)vxGetErrorObject(context, VX_FAILURE); + break; } - status = VX_SUCCESS; + } /* for loop */ + if (vxGetStatus((vx_reference)image) == VX_SUCCESS) + { + /* lock the image from being modified again! */ + ((vx_image)image)->constant = vx_true_e; } - VX_PRINT(VX_ZONE_IMAGE, "Decrementing Image Reference\n"); - image->decrementReference(VX_EXTERNAL); } -exit: - VX_PRINT(VX_ZONE_API, "return %d\n", status); - return status; + + return image; } -VX_API_ENTRY vx_status VX_API_CALL vxCopyImagePatch( - vx_image image, - const vx_rectangle_t* rect, - vx_uint32 plane_index, - const vx_imagepatch_addressing_t* addr, - void* ptr, - vx_enum usage, - vx_enum mem_type) +VX_API_ENTRY vx_image VX_API_CALL vxCreateVirtualImage(vx_graph graph, vx_uint32 width, vx_uint32 height, vx_df_image format) { - vx_status status = VX_SUCCESS; - - vx_uint32 start_x = rect ? rect->start_x : 0u; - vx_uint32 start_y = rect ? rect->start_y : 0u; - vx_uint32 end_x = rect ? rect->end_x : 0u; - vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_image image = nullptr; - /* bad parameters */ - if ( ((VX_READ_ONLY != usage) && (VX_WRITE_ONLY != usage)) || - (rect == nullptr) || (addr == nullptr) || (ptr == nullptr) ) + if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) { - status = VX_ERROR_INVALID_PARAMETERS; + image = Image::createImage(graph->context, width, height, format, vx_true_e); + if (vxGetStatus((vx_reference)image) == VX_SUCCESS && image->type == VX_TYPE_IMAGE) + { + image->scope = (vx_reference)graph; + } } - /* bad references */ - if (VX_SUCCESS == status && - Image::isValidImage(image) == vx_false_e ) - { - status = VX_ERROR_INVALID_REFERENCE; - } + return image; +} - /* determine if virtual before checking for memory */ - if (VX_SUCCESS == status && - image->is_virtual == vx_true_e) +VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromROI(vx_image image, const vx_rectangle_t* rect) +{ + vx_image subimage = nullptr; + + if (Image::isValidImage(image) == vx_true_e) { - if (image->is_accessible == vx_false_e) + if (!rect || + rect->start_x >= rect->end_x || + rect->start_y >= rect->end_y || + rect->end_x > image->width || + rect->end_y > image->height) { - /* User tried to access a "virtual" image. */ - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); - status = VX_ERROR_OPTIMIZED_AWAY; + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - /* framework trying to access a virtual image, this is ok. */ - } - - /* more bad parameters */ - if (VX_SUCCESS == status) - { - if (zero_area == vx_true_e || - ((plane_index >= image->memory.nptrs) || - (plane_index >= image->planes) || - (start_x >= end_x) || - (start_y >= end_y))) + else if (image->format == VX_DF_IMAGE_U1 && (rect->start_x % 8) != 0) { - status = VX_ERROR_INVALID_PARAMETERS; + VX_PRINT(VX_ZONE_ERROR, "Attempted to create U1 image from ROI not starting at a byte boundary in the" + "parent image. U1 subimages must start on byte boundaries in the parent image.\n"); + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - } + else + { + /* perhaps the parent hasn't been allocated yet? */ + if (image->allocateImage() == vx_true_e) + { + subimage = (vx_image)Reference::createReference(image->context, VX_TYPE_IMAGE, VX_EXTERNAL, image->context); + if (vxGetStatus((vx_reference)subimage) == VX_SUCCESS) + { + vx_uint32 p = 0; + vx_rectangle_t image_rect; - /* The image needs to be allocated */ - if ((VX_SUCCESS == status) && - (image->memory.ptrs[0] == nullptr) && - (image->allocateImage() == vx_false_e)) - { - VX_PRINT(VX_ZONE_ERROR, "No memory!\n"); - status = VX_ERROR_NO_MEMORY; + /* remember that the scope of the image is the parent image */ + subimage->scope = (vx_reference)image; + + /* refer to our parent image and internally refcount it */ + subimage->parent = image; + + for (p = 0; p < VX_INT_MAX_REF; p++) + { + if (image->subimages[p] == nullptr) + { + image->subimages[p] = subimage; + break; + } + } + + image->incrementReference(VX_INTERNAL); + + VX_PRINT(VX_ZONE_IMAGE, "Creating SubImage at {%u,%u},{%u,%u}\n", + rect->start_x, rect->start_y, rect->end_x, rect->end_y); + + /* duplicate the metadata */ + subimage->format = image->format; + subimage->memory_type = image->memory_type; + subimage->range = image->range; + subimage->space = image->space; + subimage->width = rect->end_x - rect->start_x; + subimage->height = rect->end_y - rect->start_y; + subimage->planes = image->planes; + subimage->constant = image->constant; + + vxGetValidRegionImage(image, &image_rect); + + /* set valid rectangle */ + if(rect->start_x > image_rect.end_x || + rect->end_x < image_rect.start_x || + rect->start_y > image_rect.end_y || + rect->end_y < image_rect.start_y) + { + /* no intersection */ + subimage->region.start_x = 0; + subimage->region.start_y = 0; + subimage->region.end_x = 0; + subimage->region.end_y = 0; + } + else + { + subimage->region.start_x = VX_MAX(image_rect.start_x, rect->start_x) - rect->start_x; + subimage->region.start_y = VX_MAX(image_rect.start_y, rect->start_y) - rect->start_y; + subimage->region.end_x = VX_MIN(image_rect.end_x, rect->end_x) - rect->start_x; + subimage->region.end_y = VX_MIN(image_rect.end_y, rect->end_y) - rect->start_y; + } + + memcpy(&subimage->scale, &image->scale, sizeof(image->scale)); + memcpy(&subimage->memory, &image->memory, sizeof(image->memory)); + + /* modify the dimensions */ + for (p = 0; p < subimage->planes; p++) + { + vx_uint32 offset = Image::computePlaneOffset(image, rect->start_x, rect->start_y, p); + VX_PRINT(VX_ZONE_IMAGE, "Offsetting SubImage plane[%u] by %u bytes!\n", p, offset); + + subimage->memory.dims[p][VX_DIM_X] = subimage->width; + subimage->memory.dims[p][VX_DIM_Y] = subimage->height; + subimage->memory.ptrs[p] = &image->memory.ptrs[p][offset]; + + /* keep offset to allow vxSwapImageHandle update ROI pointers */ + subimage->memory.offset[p] = offset; + } + + Image::printImage(subimage); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Child image failed to allocate!\n"); + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Parent image failed to allocate!\n"); + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); + } + } } - - /* can't write to constant */ - if ((VX_SUCCESS == status) && - (image->constant == vx_true_e) && - (usage == VX_WRITE_ONLY)) + else { - status = VX_ERROR_NOT_SUPPORTED; - VX_PRINT(VX_ZONE_ERROR, "Can't write to constant data, only read!\n"); - vxAddLogEntry(reinterpret_cast(image), status, "Can't write to constant data, only read!\n"); + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - /* Inconsistent strides for non-integer byte size data? */ - if ( (VX_SUCCESS == status) && - (addr->stride_x == 0 || image->memory.strides[plane_index][VX_DIM_X] == 0) && - (addr->stride_x_bits != image->memory.stride_x_bits[plane_index]) ) - { - VX_PRINT(VX_ZONE_ERROR, "Copying of non-integer byte size data without preserving stride in " - "x-dimension is not supported! Attempted to copy with strides {stride_x, stride_x_bits}:" - " {%d, %u} %s {%d, %u}\n", addr->stride_x, addr->stride_x_bits, - usage == VX_READ_ONLY ? "<-" : "->", - image->memory.strides[plane_index][VX_DIM_X], image->memory.stride_x_bits[plane_index]); - status = VX_ERROR_NOT_SUPPORTED; - } + return (vx_image)subimage; +} - /*************************************************************************/ - if (VX_SUCCESS == status) - { - VX_PRINT(VX_ZONE_IMAGE, "CopyImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", - image, ptr, start_x, start_y, end_x, end_y, plane_index); +VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromChannel(vx_image image, vx_enum channel) +{ + vx_image subimage = nullptr; -#ifdef OPENVX_USE_OPENCL_INTEROP - void * ptr_given = ptr; - vx_enum mem_type_given = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + if (Image::isValidImage(image) == vx_true_e) + { + /* perhaps the parent hasn't been allocated yet? */ + if (image->allocateImage() == vx_true_e) { - // get ptr from OpenCL buffer for HOST - size_t size = 0; - cl_mem opencl_buf = (cl_mem)ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyImagePatch: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - ptr = clEnqueueMapBuffer(image->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyImagePatch: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, ptr, cerr); - if (cerr != CL_SUCCESS) + /* check for valid parameters */ + switch (channel) { - return VX_ERROR_INVALID_PARAMETERS; - } - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif + case VX_CHANNEL_Y: + { + if (VX_DF_IMAGE_YUV4 != image->format && + VX_DF_IMAGE_IYUV != image->format && + VX_DF_IMAGE_NV12 != image->format && + VX_DF_IMAGE_NV21 != image->format) + { + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + return subimage; + } + break; + } - if (usage == VX_READ_ONLY) - { - /* Copy from image (READ) mode */ + case VX_CHANNEL_U: + case VX_CHANNEL_V: + { + if (VX_DF_IMAGE_YUV4 != image->format && + VX_DF_IMAGE_IYUV != image->format) + { + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + return subimage; + } + break; + } - vx_uint32 x; - vx_uint32 y; - vx_uint8* pSrc = image->memory.ptrs[plane_index]; - vx_uint8* pDst = (vx_uint8*)ptr; + default: + { + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + return subimage; + } + } - vx_imagepatch_addressing_t addr_save = VX_IMAGEPATCH_ADDR_INIT; + subimage = (vx_image)Reference::createReference(image->context, VX_TYPE_IMAGE, VX_EXTERNAL, image->context); + if (vxGetStatus((vx_reference)subimage) == VX_SUCCESS) + { + vx_uint32 p = 0; - /* Strides given by the application */ - addr_save.dim_x = addr->dim_x; - addr_save.dim_y = addr->dim_y; - addr_save.stride_x = addr->stride_x; - addr_save.stride_y = addr->stride_y; - addr_save.stride_x_bits = addr->stride_x_bits; + /* remember that the scope of the subimage is the parent image */ + subimage->scope = (vx_reference)image; - addr_save.step_x = image->scale[plane_index][VX_DIM_X]; - addr_save.step_y = image->scale[plane_index][VX_DIM_Y]; - addr_save.scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr_save.scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; + /* refer to our parent image and internally refcount it */ + subimage->parent = image; - /* Copy the patch _from_ the image - * (For non-integer byte size images line-by-line copying only works if the patch starts and ends - * at byte boundaries) */ - if ( addr_save.stride_x == image->memory.strides[plane_index][VX_DIM_X] && - (addr_save.stride_x != 0 ? 1 : - (addr_save.stride_x_bits == image->memory.stride_x_bits[plane_index] && - start_x * addr_save.stride_x_bits % 8 == 0 && - end_x * addr_save.stride_x_bits % 8 == 0)) ) - { - /* Both have compact lines */ - for (y = start_y; y < end_y; y += addr_save.step_y) + for (p = 0; p < VX_INT_MAX_REF; p++) { - vx_uint32 srcOffset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8* pSrcLine = &pSrc[srcOffset]; + if (image->subimages[p] == nullptr) + { + image->subimages[p] = subimage; + break; + } + } - vx_uint32 dstOffset = Image::computePatchOffset(0, (y - start_y), &addr_save); - vx_uint8* pDstLine = &pDst[dstOffset]; + image->incrementReference(VX_INTERNAL); - vx_uint32 len = Image::computePlaneRangeSize(image, end_x - start_x/*image->width*/, plane_index); + VX_PRINT(VX_ZONE_IMAGE, "Creating SubImage from channel {%u}\n", channel); - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, srcOffset, len); + /* plane index */ + p = (VX_CHANNEL_Y == channel) ? 0 : ((VX_CHANNEL_U == channel) ? 1 : 2); - memcpy(pDstLine, pSrcLine, len); - } - } - else - { - /* The destination is not compact, we need to copy per element */ - for (y = start_y; y < end_y; y += addr_save.step_y) + switch (image->format) { - vx_uint32 srcOffset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8* pSrcLine = &pSrc[srcOffset]; - - vx_uint8* pDstLine = pDst; - - vx_uint32 bitShiftU1 = start_x % 8; // U1 start_x pixel bit-shift - vx_uint32 len = image->memory.strides[plane_index][VX_DIM_X]; - - for (x = start_x; x < end_x; x += addr_save.step_x) + case VX_DF_IMAGE_YUV4: { - if (image->format == VX_DF_IMAGE_U1) - { - /* U1 patch not starting and ending at byte boundary in image, - * do pixel-by-pixel copy from the image */ - vx_uint8 mask = 1 << (x % 8); - pDstLine[(x - start_x + bitShiftU1) / 8] = - (pDstLine[(x - start_x + bitShiftU1) / 8] & ~mask) | - (pSrcLine[(x - start_x + bitShiftU1) / 8] & mask); - } - else - { - /* One element */ - memcpy(pDstLine, pSrcLine, len); - - pSrcLine += len; - pDstLine += addr_save.stride_x; - } - } - VX_PRINT(VX_ZONE_IMAGE, - "Copied %u pixels from row %u in image starting at %p to patch starting at %p\n", - end_x - start_x, y, image->memory.ptrs[plane_index], ptr); + /* setup the metadata */ + subimage->format = VX_DF_IMAGE_U8; + subimage->memory_type = image->memory_type; + subimage->range = image->range; + subimage->space = image->space; + subimage->width = image->memory.dims[p][VX_DIM_X]; + subimage->height = image->memory.dims[p][VX_DIM_Y]; + subimage->planes = 1; + subimage->constant = image->constant; - pDst += addr_save.stride_y; - } - } + memset(&subimage->scale, 0, sizeof(image->scale)); + memset(&subimage->memory, 0, sizeof(image->memory)); - VX_PRINT(VX_ZONE_IMAGE, "Copied image into %p\n", ptr); + subimage->scale[0][VX_DIM_C] = 1; + subimage->scale[0][VX_DIM_X] = 1; + subimage->scale[0][VX_DIM_Y] = 1; - // ownReadFromReference(&image->base); - } - else - { - /* Copy to image (WRITE) mode */ - vx_uint32 x; - vx_uint32 y; - vx_uint8* pSrc = (vx_uint8*)ptr; - vx_uint8* pDst = image->memory.ptrs[plane_index]; + subimage->bounds[0][VX_DIM_C][VX_BOUND_START] = 0; + subimage->bounds[0][VX_DIM_C][VX_BOUND_END] = 1; + subimage->bounds[0][VX_DIM_X][VX_BOUND_START] = image->bounds[p][VX_DIM_X][VX_BOUND_START]; + subimage->bounds[0][VX_DIM_X][VX_BOUND_END] = image->bounds[p][VX_DIM_X][VX_BOUND_END]; + subimage->bounds[0][VX_DIM_Y][VX_BOUND_START] = image->bounds[p][VX_DIM_Y][VX_BOUND_START]; + subimage->bounds[0][VX_DIM_Y][VX_BOUND_END] = image->bounds[p][VX_DIM_Y][VX_BOUND_END]; - vx_imagepatch_addressing_t addr_save = VX_IMAGEPATCH_ADDR_INIT; + subimage->memory.dims[0][VX_DIM_C] = image->memory.dims[p][VX_DIM_C]; + subimage->memory.dims[0][VX_DIM_X] = image->memory.dims[p][VX_DIM_X]; + subimage->memory.dims[0][VX_DIM_Y] = image->memory.dims[p][VX_DIM_Y]; - /* Strides given by the application */ - addr_save.dim_x = addr->dim_x; - addr_save.dim_y = addr->dim_y; - addr_save.stride_x = addr->stride_x; - addr_save.stride_y = addr->stride_y; - addr_save.stride_x_bits = addr->stride_x_bits; + subimage->memory.strides[0][VX_DIM_C] = image->memory.strides[p][VX_DIM_C]; + subimage->memory.strides[0][VX_DIM_X] = image->memory.strides[p][VX_DIM_X]; + subimage->memory.strides[0][VX_DIM_Y] = image->memory.strides[p][VX_DIM_Y]; + subimage->memory.stride_x_bits[0] = image->memory.stride_x_bits[p]; - addr_save.step_x = image->scale[plane_index][VX_DIM_X]; - addr_save.step_y = image->scale[plane_index][VX_DIM_Y]; - addr_save.scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr_save.scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; + subimage->memory.ptrs[0] = image->memory.ptrs[p]; + subimage->memory.nptrs = 1; - /* lock image plane from multiple writers */ - if (Osal::semWait(&image->memory.locks[plane_index]) == vx_false_e) - { - status = VX_ERROR_NO_RESOURCES; - } + Osal::createSem(&subimage->memory.locks[0], 1); - /* Copy the patch _to_ the image - * (For non-integer byte size images line-by-line copying only works if the patch starts and ends - * at byte boundaries or at the left/right edges of the image's valid region) */ - if (VX_SUCCESS == status && - addr_save.stride_x == image->memory.strides[plane_index][VX_DIM_X] && - (addr_save.stride_x != 0 ? 1 : - (addr_save.stride_x_bits == image->memory.stride_x_bits[plane_index] && - (start_x * addr_save.stride_x_bits % 8 == 0 || start_x == image->region.start_x) && - (end_x * addr_save.stride_x_bits % 8 == 0 || end_x == image->region.end_x ))) ) - { - /* Both source and destination have compact lines */ - for (y = start_y; y < end_y; y += addr_save.step_y) - { - vx_uint32 srcOffset = Image::computePatchOffset(0, (y - start_y), &addr_save); - vx_uint8* pSrcLine = &pSrc[srcOffset]; + break; + } - vx_uint32 dstOffset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8* pDstLine = &pDst[dstOffset]; + case VX_DF_IMAGE_IYUV: + case VX_DF_IMAGE_NV12: + case VX_DF_IMAGE_NV21: + { + /* setup the metadata */ + subimage->format = VX_DF_IMAGE_U8; + subimage->memory_type = image->memory_type; + subimage->range = image->range; + subimage->space = image->space; + subimage->width = image->memory.dims[p][VX_DIM_X]; + subimage->height = image->memory.dims[p][VX_DIM_Y]; + subimage->planes = 1; + subimage->constant = image->constant; - vx_uint32 len = Image::computePatchRangeSize((end_x - start_x), &addr_save); + memset(&subimage->scale, 0, sizeof(image->scale)); + memset(&subimage->memory, 0, sizeof(image->memory)); - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, srcOffset, len); + subimage->scale[0][VX_DIM_C] = 1; + subimage->scale[0][VX_DIM_X] = 1; + subimage->scale[0][VX_DIM_Y] = 1; - memcpy(pDstLine, pSrcLine, len); - } - } - else - { - /* The destination is not compact, we need to copy per element */ - for (y = start_y; y < end_y; y += addr_save.step_y) - { - vx_uint8* pSrcLine = pSrc; + subimage->bounds[0][VX_DIM_C][VX_BOUND_START] = 0; + subimage->bounds[0][VX_DIM_C][VX_BOUND_END] = 1; + subimage->bounds[0][VX_DIM_X][VX_BOUND_START] = image->bounds[p][VX_DIM_X][VX_BOUND_START]; + subimage->bounds[0][VX_DIM_X][VX_BOUND_END] = image->bounds[p][VX_DIM_X][VX_BOUND_END]; + subimage->bounds[0][VX_DIM_Y][VX_BOUND_START] = image->bounds[p][VX_DIM_Y][VX_BOUND_START]; + subimage->bounds[0][VX_DIM_Y][VX_BOUND_END] = image->bounds[p][VX_DIM_Y][VX_BOUND_END]; - vx_uint32 dstOffset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8* pDstLine = &pDst[dstOffset]; + subimage->memory.dims[0][VX_DIM_C] = image->memory.dims[p][VX_DIM_C]; + subimage->memory.dims[0][VX_DIM_X] = image->memory.dims[p][VX_DIM_X]; + subimage->memory.dims[0][VX_DIM_Y] = image->memory.dims[p][VX_DIM_Y]; - vx_uint32 bitShiftU1 = start_x % 8; // U1 start_x pixel bit-shift - vx_uint32 len = image->memory.strides[plane_index][VX_DIM_X]; + subimage->memory.strides[0][VX_DIM_C] = image->memory.strides[p][VX_DIM_C]; + subimage->memory.strides[0][VX_DIM_X] = image->memory.strides[p][VX_DIM_X]; + subimage->memory.strides[0][VX_DIM_Y] = image->memory.strides[p][VX_DIM_Y]; + subimage->memory.stride_x_bits[0] = image->memory.stride_x_bits[p]; - for (x = start_x; x < end_x; x += addr_save.step_x) - { - if (image->format == VX_DF_IMAGE_U1) - { - /* U1 patch not starting and ending at byte boundary or left/right edges of - * valid region in image, do pixel-by-pixel copy from the patch */ - vx_uint32 xAdjusted = x - start_x + bitShiftU1; - vx_uint8 mask = 1 << (xAdjusted % 8); - pDstLine[xAdjusted / 8] = (pDstLine[xAdjusted / 8] & ~mask) | - (pSrcLine[xAdjusted / 8] & mask); - } - else - { - /* One element */ - memcpy(pDstLine, pSrcLine, len); + subimage->memory.ptrs[0] = image->memory.ptrs[p]; + subimage->memory.nptrs = 1; - pSrcLine += addr_save.stride_x; - pDstLine += len; - } - } - VX_PRINT(VX_ZONE_IMAGE, - "Copied %u pixels from row %u in %spatch starting at %p to image starting at %p\n", - end_x - start_x, y - start_x, (mem_type == VX_MEMORY_TYPE_NONE) ? "image" : "external ", ptr, image->memory.ptrs[plane_index]); + Osal::createSem(&subimage->memory.locks[0], 1); - pSrc += addr_save.stride_y; + break; + } } - } - VX_PRINT(VX_ZONE_IMAGE, "Copied to image from %p\n", ptr); + /* set inverted region untill the first write to image */ + subimage->region.start_x = subimage->width; + subimage->region.start_y = subimage->height; + subimage->region.end_x = 0; + subimage->region.end_y = 0; - // ownWroteToReference(&image->base); - /* unlock image plane */ - Osal::semPost(&image->memory.locks[plane_index]); + Image::printImage(subimage); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Child image failed to allocate!\n"); + } } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (VX_SUCCESS == status && - mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + else { - clEnqueueUnmapMemObject(image->context->opencl_command_queue, - (cl_mem)ptr_given, ptr, 0, nullptr, nullptr); - clFinish(image->context->opencl_command_queue); + VX_PRINT(VX_ZONE_ERROR, "Parent image failed to allocate!\n"); + vx_context context = vxGetContext((vx_reference)image); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_NO_MEMORY); } -#endif + } + else + { + vx_context context = vxGetContext((vx_reference)subimage); + subimage = (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - VX_PRINT(VX_ZONE_API, "returned %d\n", status); - return status; -} /* vxCopyImagePatch() */ - + return (vx_image)subimage; +} -VX_API_ENTRY vx_status VX_API_CALL vxMapImagePatch( - vx_image image, - const vx_rectangle_t* rect, - vx_uint32 plane_index, - vx_map_id* map_id, - vx_imagepatch_addressing_t* addr, - void** ptr, - vx_enum usage, - vx_enum mem_type, - vx_uint32 flags) +VX_API_ENTRY vx_image VX_API_CALL vxCreateImageFromHandle(vx_context context, vx_df_image color, const vx_imagepatch_addressing_t addrs[], void *const ptrs[], vx_enum memory_type) { -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_enum mem_type_requested = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - vx_size size = 0; - vx_uint32 start_x = rect ? rect->start_x : 0u; - vx_uint32 start_y = rect ? rect->start_y : 0u; - vx_uint32 end_x = rect ? rect->end_x : 0u; - vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); - vx_status status = VX_FAILURE; + vx_image image = 0; - /* bad parameters */ - if ( (rect == nullptr) || (map_id == nullptr) || (addr == nullptr) || (ptr == nullptr) ) + if (Context::isValidImport(memory_type) == vx_false_e) { - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; + return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - /* bad references */ - if (Image::isValidImage(image) == vx_false_e) - { - status = VX_ERROR_INVALID_REFERENCE; - goto exit; - } + image = vxCreateImage(context, addrs[0].dim_x, addrs[0].dim_y, color); - /* determine if virtual before checking for memory */ - if (image->is_virtual == vx_true_e) + if (vxGetStatus((vx_reference)image) == VX_SUCCESS && image->type == VX_TYPE_IMAGE) { - if (image->is_accessible == vx_false_e) + vx_uint32 p = 0; + image->memory_type = memory_type; + image->memory.allocated = vx_true_e; /* don't let the system realloc this memory */ + + /* now assign the plane pointers, assume linearity */ + for (p = 0; p < image->planes; p++) { - /* User tried to access a "virtual" image. */ - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual image\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - goto exit; + /* ensure row-major memory layout */ + if (addrs[p].stride_x != 0 ? + (addrs[p].stride_x < 0 || addrs[p].stride_y < (vx_int32)(addrs[p].stride_x * addrs[p].dim_x)) : + (addrs[p].stride_x_bits <= 0 || addrs[p].stride_y < (vx_int32)((addrs[p].stride_x_bits * addrs[p].dim_x + 7) / 8))) + { + vxReleaseImage(&image); + return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } +#ifdef OPENVX_USE_OPENCL_INTEROP + if (context->opencl_context && memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER && ptrs[p]) + { + vx_rectangle_t rect = { 0, 0, image->width, image->height }; + vx_size size = vxComputeImagePatchSize(image, &rect, p); + cl_int cerr; + image->memory.opencl_buf[p] = (cl_mem)ptrs[p]; + image->memory.ptrs[p] = (vx_uint8*)clEnqueueMapBuffer(context->opencl_command_queue, + image->memory.opencl_buf[p], CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, + 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCreateImageFromHandle: clEnqueueMapBuffer(%p) => %p (%d)\n", + image->memory.opencl_buf[p], image->memory.ptrs[p], cerr); + if (cerr != CL_SUCCESS) + { + vxReleaseImage(&image); + return (vx_image)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } + } + else +#endif + { + image->memory.ptrs[p] = reinterpret_cast(ptrs[p]); + image->memory.strides[p][VX_DIM_C] = (vx_uint32)Image::sizeOfChannel(color); + image->memory.strides[p][VX_DIM_X] = addrs[p].stride_x; + image->memory.strides[p][VX_DIM_Y] = addrs[p].stride_y; + image->memory.stride_x_bits[p] = addrs[p].stride_x_bits; + + Osal::createSem(&image->memory.locks[p], 1); + } } - /* framework trying to access a virtual image, this is ok. */ } - /* more bad parameters */ - if (zero_area == vx_true_e || - ((plane_index >= image->memory.nptrs) || - (plane_index >= image->planes) || - (start_x >= end_x) || - (start_y >= end_y))) - { - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; - } + return image; +} - /* The image needs to be allocated */ - if ((image->memory.ptrs[0] == nullptr) && (image->allocateImage() == vx_false_e)) +VX_API_ENTRY vx_status VX_API_CALL vxSwapImageHandle(vx_image image, void* const new_ptrs[], + void* prev_ptrs[], vx_size num_planes) +{ + vx_status status = VX_SUCCESS; + + if (Image::isValidImage(image) == vx_true_e) { - VX_PRINT(VX_ZONE_ERROR, "No memory!\n"); - status = VX_ERROR_NO_MEMORY; - goto exit; + status = image->swapHandle(new_ptrs, prev_ptrs, num_planes); } - - /* can't write to constant */ - if ((image->constant == vx_true_e) && - ((usage == VX_WRITE_ONLY) || (usage == VX_READ_AND_WRITE))) + else { - status = VX_ERROR_NOT_SUPPORTED; - VX_PRINT(VX_ZONE_ERROR, "Can't write to constant data, only read!\n"); - vxAddLogEntry(reinterpret_cast(image), status, "Can't write to constant data, only read!\n"); - goto exit; + status = VX_ERROR_INVALID_REFERENCE; } - /*************************************************************************/ - VX_PRINT(VX_ZONE_IMAGE, "MapImagePatch from " VX_FMT_REF " to ptr %p from {%u,%u} to {%u,%u} plane %u\n", - image, *ptr, start_x, start_y, end_x, end_y, plane_index); + return status; +} - /* MAP mode */ +VX_API_ENTRY vx_status VX_API_CALL vxQueryImage(vx_image image, vx_enum attribute, void *ptr, vx_size size) +{ + vx_status status = VX_SUCCESS; + if (Image::isValidImage(image) == vx_true_e) { - vx_memory_map_extra extra; - vx_uint8* buf = 0; - - size = vxComputeImagePatchSize(image, rect, plane_index); - - extra.image_data.plane_index = plane_index; - extra.image_data.rect = *rect; - - if (VX_MEMORY_TYPE_NONE != image->memory_type && - vx_true_e == image->context->memoryMap((vx_reference)image, 0, usage, mem_type, flags, &extra, (void**)&buf, map_id)) + switch (attribute) { - /* use the addressing of the internal format */ - if (image->format == VX_DF_IMAGE_U1 && start_x % 8 != 0) - addr->dim_x = end_x - start_x + start_x % 8; - else - addr->dim_x = end_x - start_x; - addr->dim_y = end_y - start_y; - addr->stride_x = image->memory.strides[plane_index][VX_DIM_X]; - addr->stride_y = image->memory.strides[plane_index][VX_DIM_Y]; - addr->stride_x_bits = image->memory.stride_x_bits[plane_index]; - addr->step_x = image->scale[plane_index][VX_DIM_X]; - addr->step_y = image->scale[plane_index][VX_DIM_Y]; - addr->scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr->scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; - - buf = image->memory.ptrs[plane_index]; - - vx_uint32 index = Image::computePatchOffset(rect->start_x, rect->start_y, addr); - *ptr = &buf[index]; - VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p\n", *ptr); - - image->incrementReference(VX_EXTERNAL); - - status = VX_SUCCESS; + case VX_IMAGE_FORMAT: + if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) + { + *(vx_df_image *)ptr = image->fmt(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_WIDTH: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = image->wdth(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_HEIGHT: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = image->hght(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_PLANES: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + { + *(vx_size *)ptr = image->numPlanes(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_SPACE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_enum *)ptr = image->colorSpace(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_RANGE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_enum *)ptr = image->colorRange(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_SIZE: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + { + *(vx_size *)ptr = image->size(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_IMAGE_MEMORY_TYPE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_enum *)ptr = image->memoryType(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } - else - /* get mapping buffer of sufficient size and map_id */ - if (vx_true_e == image->context->memoryMap((vx_reference)image, size, usage, mem_type, flags, &extra, (void**)&buf, map_id)) + } + else + { + status = VX_ERROR_INVALID_REFERENCE; + } + VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxSetImageAttribute(vx_image image, vx_enum attribute, const void *ptr, vx_size size) +{ + vx_status status = VX_SUCCESS; + if (Image::isValidImage(image) == vx_true_e) + { + switch (attribute) { - /* use the addressing of the internal format */ - if (image->format == VX_DF_IMAGE_U1 && start_x % 8 != 0) - addr->dim_x = end_x - start_x + start_x % 8; - else - addr->dim_x = end_x - start_x; - addr->dim_y = end_y - start_y; - addr->stride_x = image->memory.strides[plane_index][VX_DIM_X]; - addr->stride_x_bits = image->memory.stride_x_bits[plane_index]; - addr->stride_y = addr->stride_x != 0 ? - addr->stride_x * addr->dim_x / image->scale[plane_index][VX_DIM_Y] : - (addr->stride_x_bits * addr->dim_x / image->scale[plane_index][VX_DIM_Y] + 7) / 8; - addr->step_x = image->scale[plane_index][VX_DIM_X]; - addr->step_y = image->scale[plane_index][VX_DIM_Y]; - addr->scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr->scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; - - /* initialize mapping buffer with image patch data for read/read-modify-write access */ - if (VX_READ_ONLY == usage || VX_READ_AND_WRITE == usage) - { - /* lock image plane even for read access to avoid mix of simultaneous read/write */ - if (vx_true_e == Osal::semWait(&image->memory.locks[plane_index])) + case VX_IMAGE_SPACE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - vx_uint32 y; - vx_uint8* pSrc = image->memory.ptrs[plane_index]; - vx_uint8* pDst = buf; - - Memory::printMemory(&image->memory); - - /* Both have compact lines */ - for (y = start_y; y < end_y; y += addr->step_y) - { - vx_uint32 srcOffset = Image::computePlaneOffset(image, start_x, y, plane_index); - vx_uint8* pSrcLine = &pSrc[srcOffset]; - - vx_uint32 dstOffset = Image::computePatchOffset(0, (y - start_y), addr); - vx_uint8* pDstLine = &pDst[dstOffset]; - - vx_uint32 len = Image::computePlaneRangeSize(image, addr->dim_x, plane_index); - - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, srcOffset, len); - - memcpy(pDstLine, pSrcLine, len); - } - - // ownReadFromReference(&image->base); - - /* we're done, unlock the image plane */ - Osal::semPost(&image->memory.locks[plane_index]); + image->setSpace(*(vx_enum *)ptr); } else { - status = VX_FAILURE; - VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for mapping\n"); - goto exit; + status = VX_ERROR_INVALID_PARAMETERS; } - } /* if VX_READ_ONLY or VX_READ_AND_WRITE */ - - *ptr = buf; - VX_PRINT(VX_ZONE_IMAGE, "Returning mapped pointer %p\n", *ptr); - - image->incrementReference(VX_EXTERNAL); + break; - status = VX_SUCCESS; - } - else - { - status = VX_FAILURE; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } } - -exit: - -#ifdef OPENVX_USE_OPENCL_INTEROP - if ((status == VX_SUCCESS) && image->context->opencl_context && - (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && - (size > 0) && ptr && *ptr) + else { - /* create OpenCL buffer using the host allocated pointer */ - cl_int cerr = 0; - cl_mem opencl_buf = clCreateBuffer(image->context->opencl_context, - CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, - size, *ptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapImagePatch: clCreateBuffer(%u) => %p (%d)\n", - (vx_uint32)size, opencl_buf, cerr); - if (cerr == CL_SUCCESS) - { - image->context->memory_maps[*map_id].opencl_buf = opencl_buf; - *ptr = opencl_buf; - } - else - { - status = VX_FAILURE; - } + status = VX_ERROR_INVALID_REFERENCE; } -#endif - - VX_PRINT(VX_ZONE_API, "return %d\n", status); - + VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); return status; -} /* vxMapImagePatch() */ +} -VX_API_ENTRY vx_status VX_API_CALL vxUnmapImagePatch(vx_image image, vx_map_id map_id) +VX_API_ENTRY vx_status VX_API_CALL vxSetImagePixelValues(vx_image image, const vx_pixel_value_t *pixel_value) { vx_status status = VX_SUCCESS; - /* bad references */ - if (Image::isValidImage(image) == vx_false_e) + if (Image::isValidImage(image) == vx_true_e) { - status = VX_ERROR_INVALID_REFERENCE; - goto exit; + status = image->setPixelValues(pixel_value); } - - /* bad parameters */ - if (image->context->findMemoryMap((vx_reference)image, map_id) != vx_true_e) + else { status = VX_ERROR_INVALID_PARAMETERS; - VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to unmap image patch\n"); - return status; } -#ifdef OPENVX_USE_OPENCL_INTEROP - if (image->context->opencl_context && - image->context->memory_maps[map_id].opencl_buf && - image->context->memory_maps[map_id].ptr) - { - clEnqueueUnmapMemObject(image->context->opencl_command_queue, - image->context->memory_maps[map_id].opencl_buf, - image->context->memory_maps[map_id].ptr, 0, nullptr, nullptr); - clFinish(image->context->opencl_command_queue); - cl_int cerr = clReleaseMemObject(image->context->memory_maps[map_id].opencl_buf); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapImagePatch: clReleaseMemObject(%p) => (%d)\n", - image->context->memory_maps[map_id].opencl_buf, cerr); - image->context->memory_maps[map_id].opencl_buf = nullptr; - } -#endif + return status; +} +VX_API_ENTRY vx_size VX_API_CALL vxComputeImagePatchSize(vx_image image, + const vx_rectangle_t *rect, + vx_uint32 plane_index) +{ + vx_size size = 0; + + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) { - vx_context context = image->context; - vx_memory_map_t* map = &context->memory_maps[map_id]; + size = image->computePatchSize(rect, plane_index); + } - if (map->used && - map->ref == (vx_reference)image) - { - /* commit changes for write access */ - if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && nullptr != map->ptr) - { - vx_uint32 plane_index = map->extra.image_data.plane_index; - vx_rectangle_t rect = map->extra.image_data.rect; + return size; +} - /* lock image plane for simultaneous write */ - if (vx_true_e == Osal::semWait(&image->memory.locks[plane_index])) - { - vx_uint32 x, y; - vx_uint8* pSrc = (vx_uint8*)map->ptr; - vx_uint8* pDst = image->memory.ptrs[plane_index]; - vx_imagepatch_addressing_t addr = VX_IMAGEPATCH_ADDR_INIT; +VX_API_ENTRY vx_status VX_API_CALL vxAccessImagePatch(vx_image image, + const vx_rectangle_t *rect, + vx_uint32 plane_index, + vx_imagepatch_addressing_t *addr, + void **ptr, + vx_enum usage) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - /* use the addressing of the internal format */ - if (image->format == VX_DF_IMAGE_U1 && rect.start_x % 8 != 0) - addr.dim_x = rect.end_x - rect.start_x + rect.start_x % 8; - else - addr.dim_x = rect.end_x - rect.start_x; - addr.dim_y = rect.end_y - rect.start_y; - addr.stride_x = image->memory.strides[plane_index][VX_DIM_X]; - addr.stride_x_bits = image->memory.stride_x_bits[plane_index]; - addr.stride_y = addr.stride_x != 0 ? - addr.stride_x * addr.dim_x / image->scale[plane_index][VX_DIM_Y] : - (addr.stride_x_bits * addr.dim_x / image->scale[plane_index][VX_DIM_Y] + 7) / 8; - addr.step_x = image->scale[plane_index][VX_DIM_X]; - addr.step_y = image->scale[plane_index][VX_DIM_Y]; - addr.scale_x = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_X]; - addr.scale_y = VX_SCALE_UNITY / image->scale[plane_index][VX_DIM_Y]; + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) + { + status = image->accessPatch(rect, plane_index, addr, ptr, usage); + } - /* Both source and destination have compact lines, begin write-back to image - * (For non-integer byte size images line-by-line write-back only works if the patch starts and - * ends at byte boundaries or at the left/right edges of the image's valid region) */ - if ( (addr.stride_x == 0 && addr.stride_x_bits != 0) && - !((rect.start_x * addr.stride_x_bits % 8 == 0 || rect.start_x == image->region.start_x) && - (rect.end_x * addr.stride_x_bits % 8 == 0 || rect.end_x == image->region.end_x )) ) - { - /* Pixel-by-pixel write-back */ - for (y = rect.start_y; y < rect.end_y; y += addr.step_y) - { - vx_uint32 srcOffset = Image::computePatchOffset(0, (y - rect.start_y), &addr); - vx_uint8* pSrcLine = &pSrc[srcOffset]; + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxCommitImagePatch(vx_image image, + const vx_rectangle_t *rect, + vx_uint32 plane_index, + const vx_imagepatch_addressing_t *addr, + const void *ptr) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - vx_uint32 dstOffset = Image::computePlaneOffset(image, rect.start_x, y, plane_index); - vx_uint8* pDstLine = &pDst[dstOffset]; + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) + { + status = image->commitPatch(rect, plane_index, addr, ptr); + } - vx_uint32 bitOffset = rect.start_x % 8; // Respect pixel bit-offsets (cf. vxMapImagePatch) + return status; +} - for (x = rect.start_x; x < rect.end_x; x += addr.step_x) - { - vx_uint32 xAdjusted = x - rect.start_x + bitOffset; - vx_uint8 mask = 1 << (xAdjusted % 8); - pDstLine[xAdjusted / 8] = (pDstLine[xAdjusted / 8] & ~mask) | - (pSrcLine[xAdjusted / 8] & mask); - } - VX_PRINT(VX_ZONE_IMAGE, - "Wrote back %u pixels from row %u in mapped imagepatch: %p[%u] <= %p[%u]\n", - rect.end_x - rect.start_x, y, pDst, dstOffset, pSrc, srcOffset); - } - } - else - { - /* Line-by-line write-back */ - for (y = rect.start_y; y < rect.end_y; y += addr.step_y) - { - vx_uint32 srcOffset = Image::computePatchOffset(0, (y - rect.start_y), &addr); - vx_uint8* pSrcLine = &pSrc[srcOffset]; +VX_API_ENTRY vx_status VX_API_CALL vxCopyImagePatch( + vx_image image, + const vx_rectangle_t* rect, + vx_uint32 plane_index, + const vx_imagepatch_addressing_t* addr, + void* ptr, + vx_enum usage, + vx_enum mem_type) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - vx_uint32 dstOffset = Image::computePlaneOffset(image, rect.start_x, y, plane_index); - vx_uint8* pDstLine = &pDst[dstOffset]; + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) + { + status = image->copyPatch(rect, plane_index, addr, ptr, usage, mem_type); + } - vx_uint32 len = Image::computePatchRangeSize((rect.end_x - rect.start_x), &addr); + return status; +} /* vxCopyImagePatch() */ - VX_PRINT(VX_ZONE_IMAGE, "%p[%u] <= %p[%u] for %u\n", pDst, dstOffset, pSrc, srcOffset, len); +VX_API_ENTRY vx_status VX_API_CALL vxMapImagePatch( + vx_image image, + const vx_rectangle_t* rect, + vx_uint32 plane_index, + vx_map_id* map_id, + vx_imagepatch_addressing_t* addr, + void** ptr, + vx_enum usage, + vx_enum mem_type, + vx_uint32 flags) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - memcpy(pDstLine, pSrcLine, len); - } - } + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) + { + status = image->mapPatch(rect, plane_index, map_id, addr, ptr, usage, mem_type, flags); + } - /* we're done, unlock the image plane */ - Osal::semPost(&image->memory.locks[plane_index]); - } - else - { - status = VX_FAILURE; - VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); - goto exit; - } - } + return status; +} /* vxMapImagePatch() */ - /* freeing mapping buffer */ - image->context->memoryUnmap((vx_uint32)map_id); +VX_API_ENTRY vx_status VX_API_CALL vxUnmapImagePatch(vx_image image, vx_map_id map_id) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - image->decrementReference(VX_EXTERNAL); - status = VX_SUCCESS; - } - else - { - status = VX_FAILURE; - } + /* bad references */ + if (Image::isValidImage(image) == vx_true_e) + { + status = image->unmapPatch(map_id); } -exit: - VX_PRINT(VX_ZONE_API, "return %d\n", status); - return status; } /* vxUnmapImagePatch() */ @@ -2862,28 +3096,12 @@ VX_API_ENTRY void* VX_API_CALL vxFormatImagePatchAddress2d(void *ptr, vx_uint32 VX_API_ENTRY vx_status VX_API_CALL vxGetValidRegionImage(vx_image image, vx_rectangle_t *rect) { vx_status status = VX_ERROR_INVALID_REFERENCE; + if (Image::isValidImage(image) == vx_true_e) { - status = VX_ERROR_INVALID_PARAMETERS; - if (rect) - { - if ((image->region.start_x <= image->region.end_x) && (image->region.start_y <= image->region.end_y)) - { - rect->start_x = image->region.start_x; - rect->start_y = image->region.start_y; - rect->end_x = image->region.end_x; - rect->end_y = image->region.end_y; - } - else - { - rect->start_x = 0; - rect->start_y = 0; - rect->end_x = image->width; - rect->end_y = image->height; - } - status = VX_SUCCESS; - } + status = image->getValidRegion(rect); } + return status; } @@ -2893,31 +3111,43 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetImageValidRectangle(vx_image image, cons if (Image::isValidImage(image) == vx_true_e) { - if (rect) + status = image->setValidRect(rect); + } + + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseImage(vx_image *image) +{ + vx_status status = VX_FAILURE; + + if (image != nullptr) + { + vx_image this_image = *image; + if (Reference::isValidReference((vx_reference)this_image, VX_TYPE_IMAGE) == vx_true_e) { - if ((rect->start_x <= rect->end_x) && (rect->start_y <= rect->end_y) && - (rect->end_x <= image->width) && (rect->end_y <= image->height)) - { - image->region.start_x = rect->start_x; - image->region.start_y = rect->start_y; - image->region.end_x = rect->end_x; - image->region.end_y = rect->end_y; - status = VX_SUCCESS; - } - else + vx_image parent = this_image->parent; + + /* clear this image from its parent' subimages list */ + if (parent && + Reference::isValidReference((vx_reference)parent, VX_TYPE_IMAGE) == vx_true_e) { - status = VX_ERROR_INVALID_PARAMETERS; + vx_uint32 n; + for (n = 0; n < VX_INT_MAX_REF; n++) + { + if (parent->subimages[n] == this_image) + { + parent->subimages[n] = nullptr; + break; + } + } } - } - else - { - image->region.start_x = 0; - image->region.start_y = 0; - image->region.end_x = image->width; - image->region.end_y = image->height; - status = VX_SUCCESS; + + status = Reference::releaseReference((vx_reference *)image, VX_TYPE_IMAGE, VX_EXTERNAL, + nullptr); } } + VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); return status; -} +} \ No newline at end of file From 4998d63918f843cfb27e46c10b6f4022b0188f5a Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sat, 26 Jul 2025 20:19:26 -0700 Subject: [PATCH 08/34] Reworked lut --- framework/include/vx_array.h | 18 ++++- framework/src/vx_array.cpp | 10 +++ framework/src/vx_lut.cpp | 131 ++++++----------------------------- 3 files changed, 50 insertions(+), 109 deletions(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index f134d37b..09a0986d 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -183,11 +183,27 @@ class Array : public Reference /** * @brief Get item size in array * - * @return vx_size + * @return vx_size Item size in bytes * @ingroup group_int_array */ vx_size itemSize() const; + /** + * @brief Get total size of array + * + * @return vx_size Total size in bytes + * @ingroup group_int_array + */ + vx_size totalSize() const; + + /** + * @brief Get offset value + * + * @return vx_uint32 Offset value + * @ingroup group_int_array + */ + vx_uint32 offsetVal() const; + /** * @brief Access array range in object * diff --git a/framework/src/vx_array.cpp b/framework/src/vx_array.cpp index 186a425e..5cb2c147 100644 --- a/framework/src/vx_array.cpp +++ b/framework/src/vx_array.cpp @@ -818,6 +818,16 @@ vx_size Array::itemSize() const return item_size; } +vx_size Array::totalSize() const +{ + return itemSize() * numItems(); +} + +vx_uint32 Array::offsetVal() const +{ + return offset; +} + vx_status Array::addItems(vx_size count, const void *ptr, vx_size stride) { vx_status status = VX_ERROR_NO_MEMORY; diff --git a/framework/src/vx_lut.cpp b/framework/src/vx_lut.cpp index a44f7b54..72f40005 100644 --- a/framework/src/vx_lut.cpp +++ b/framework/src/vx_lut.cpp @@ -104,22 +104,6 @@ VX_API_ENTRY vx_lut VX_API_CALL vxCreateVirtualLUT(vx_graph graph, vx_enum data_ return (vx_lut)lut; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseLUT(vx_lut* l) -{ - vx_status status = VX_FAILURE; - - if (nullptr != l) - { - vx_lut lut = *l; - if (vx_true_e == Reference::isValidReference(lut, VX_TYPE_LUT)) - { - status = Reference::releaseReference((vx_reference*)l, VX_TYPE_LUT, VX_EXTERNAL, nullptr); - } - } - - return status; -} - VX_API_ENTRY vx_status VX_API_CALL vxQueryLUT(vx_lut lut, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -132,7 +116,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryLUT(vx_lut lut, vx_enum attribute, voi case VX_LUT_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = lut->item_type; + *(vx_enum *)ptr = lut->itemType(); } else { @@ -142,7 +126,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryLUT(vx_lut lut, vx_enum attribute, voi case VX_LUT_COUNT: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = lut->num_items; + *(vx_size *)ptr = lut->numItems(); } else { @@ -152,7 +136,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryLUT(vx_lut lut, vx_enum attribute, voi case VX_LUT_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = lut->num_items * lut->item_size; + *(vx_size *)ptr = lut->totalSize(); } else { @@ -162,7 +146,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryLUT(vx_lut lut, vx_enum attribute, voi case VX_LUT_OFFSET: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = lut->offset; + *(vx_uint32 *)ptr = lut->offsetVal(); } else { @@ -211,45 +195,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyLUT(vx_lut lut, void *user_ptr, vx_enum if (Reference::isValidReference(reinterpret_cast(lut), VX_TYPE_LUT) == vx_true_e) { vx_size stride = lut->item_size; -#ifdef OPENVX_USE_OPENCL_INTEROP - void * user_ptr_given = user_ptr; - vx_enum user_mem_type_given = user_mem_type; - if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - /* get ptr from OpenCL buffer for HOST */ - size_t size = 0; - cl_mem opencl_buf = (cl_mem)user_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyLUT: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_ptr = clEnqueueMapBuffer(lut->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyLUT: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, user_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - status = lut->copyArrayRange(0, lut->num_items, stride, user_ptr, usage, user_mem_type); - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(lut->context->opencl_command_queue, - (cl_mem)user_ptr_given, user_ptr, 0, nullptr, nullptr); - clFinish(lut->context->opencl_command_queue); - } -#endif - } else { @@ -264,41 +210,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapLUT(vx_lut lut, vx_map_id *map_id, void if (Reference::isValidReference(reinterpret_cast(lut), VX_TYPE_LUT) == vx_true_e) { -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_enum mem_type_requested = mem_type; - if (mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - vx_size stride = lut->item_size; - status = lut->mapArrayRange(0, lut->num_items, map_id, &stride, ptr, usage, mem_type, flags); - -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_size size = lut->num_items * stride; - if ((status == VX_SUCCESS) && lut->context->opencl_context && - (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && - (size > 0) && ptr && *ptr) - { - /* create OpenCL buffer using the host allocated pointer */ - cl_int cerr = 0; - cl_mem opencl_buf = clCreateBuffer(lut->context->opencl_context, - CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, - size, *ptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapLUT: clCreateBuffer(%u) => %p (%d)\n", - (vx_uint32)size, opencl_buf, cerr); - if (cerr == CL_SUCCESS) - { - lut->context->memory_maps[*map_id].opencl_buf = opencl_buf; - *ptr = opencl_buf; - } - else - { - status = VX_FAILURE; - } - } -#endif + status = + lut->mapArrayRange(0, lut->num_items, map_id, &stride, ptr, usage, mem_type, flags); } else { @@ -313,22 +227,6 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapLUT(vx_lut lut, vx_map_id map_id) if (Reference::isValidReference(reinterpret_cast(lut), VX_TYPE_LUT) == vx_true_e) { -#ifdef OPENVX_USE_OPENCL_INTEROP - if (lut->context->opencl_context && - lut->context->memory_maps[map_id].opencl_buf && - lut->context->memory_maps[map_id].ptr) - { - clEnqueueUnmapMemObject(lut->context->opencl_command_queue, - lut->context->memory_maps[map_id].opencl_buf, - lut->context->memory_maps[map_id].ptr, 0, nullptr, nullptr); - clFinish(lut->context->opencl_command_queue); - cl_int cerr = clReleaseMemObject(lut->context->memory_maps[map_id].opencl_buf); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapLUT: clReleaseMemObject(%p) => (%d)\n", - lut->context->memory_maps[map_id].opencl_buf, cerr); - lut->context->memory_maps[map_id].opencl_buf = nullptr; - } -#endif - status = lut->unmapArrayRange(map_id); } else @@ -337,3 +235,20 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapLUT(vx_lut lut, vx_map_id map_id) } return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseLUT(vx_lut *l) +{ + vx_status status = VX_FAILURE; + + if (nullptr != l) + { + vx_lut lut = *l; + if (vx_true_e == Reference::isValidReference(lut, VX_TYPE_LUT)) + { + status = + Reference::releaseReference((vx_reference *)l, VX_TYPE_LUT, VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From 16247f26864d9672b8e4d517c09a8d908bfa7239 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 15:20:21 -0700 Subject: [PATCH 09/34] Reworked remap --- framework/include/vx_remap.h | 94 ++++++ framework/src/vx_remap.cpp | 633 +++++++++++++++++++---------------- 2 files changed, 433 insertions(+), 294 deletions(-) diff --git a/framework/include/vx_remap.h b/framework/include/vx_remap.h index 3ae9fb51..5ff3ce28 100644 --- a/framework/include/vx_remap.h +++ b/framework/include/vx_remap.h @@ -81,6 +81,100 @@ class Remap : public Reference */ vx_status getCoordValue(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 *src_x, vx_float32 *src_y); + /** + * @brief Get the source width + * + * @return vx_uint32 The source width + * @ingroup group_int_remap + */ + vx_uint32 srcWidth() const; + + /** + * @brief Get the source height + * + * @return vx_uint32 The source height + * @ingroup group_int_remap + */ + vx_uint32 srcHeight() const; + + /** + * @brief Get the destination width + * + * @return vx_uint32 The destination width + * @ingroup group_int_remap + */ + vx_uint32 dstWidth() const; + + /** + * @brief Get the destination height + * + * @return vx_uint32 The destination height + * @ingroup group_int_remap + */ + vx_uint32 dstHeight() const; + + /** + * @brief Set the Remap Point + * + * @param dst_x destination x coord + * @param dst_y destination y coord + * @param src_x source x coord + * @param src_y source y coord + * @return vx_status + * @ingroup group_int_remap + */ + vx_status setRemapPoint(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 src_x, vx_float32 src_y); + + /** + * @brief Get the Remap Point + * + * @param dst_x destination x coord + * @param dst_y destination y coord + * @param src_x source x coord + * @param src_y source y coord + * @return vx_status + * @ingroup group_int_remap + */ + vx_status getRemapPoint(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 *src_x, vx_float32 *src_y); + + /** + * @brief Copy a patch of remap data to/from user memory + * + * @param rect The rectangle to copy + * @param user_stride_y The stride in bytes for the user memory + * @param user_ptr The pointer to the user memory + * @param user_coordinate_type The type of coordinates in the user memory + * @param usage The usage of the memory (read/write) + * @param user_mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_remap + */ + vx_status copyPatch(const vx_rectangle_t *rect, vx_size user_stride_y, void *user_ptr, + vx_enum user_coordinate_type, vx_enum usage, vx_enum user_mem_type); + + /** + * @brief Map a patch of remap data for reading or writing + * @param rect The rectangle to map + * @param map_id The ID of the map + * @param stride_y The stride in bytes for the mapped memory + * @param ptr The pointer to the mapped memory + * @param coordinate_type The type of coordinates in the mapped memory + * @param usage The usage of the memory (read/write) + * @param mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_remap + */ + vx_status mapPatch(const vx_rectangle_t *rect, vx_map_id *map_id, vx_size *stride_y, + void **ptr, vx_enum coordinate_type, vx_enum usage, vx_enum mem_type); + + /** + * @brief Unmap a previously mapped patch of remap data + * @param map_id The ID of the map to unmap + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_remap + */ + vx_status unmapPatch(vx_uint32 map_id); + /** * @brief Function to destroy a remap object * @ingroup group_int_remap diff --git a/framework/src/vx_remap.cpp b/framework/src/vx_remap.cpp index 0d0b449c..ee9aff9d 100644 --- a/framework/src/vx_remap.cpp +++ b/framework/src/vx_remap.cpp @@ -112,262 +112,124 @@ vx_status Remap::getCoordValue(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 *src return status; } -void Remap::destruct() +vx_uint32 Remap::srcWidth() const { - Memory::freeMemory(context, &memory); + return src_width; } -/*****************************************************************************/ -/* PUBLIC INTERFACE */ -/*****************************************************************************/ - -VX_API_ENTRY vx_remap VX_API_CALL vxCreateRemap(vx_context context, - vx_uint32 src_width, vx_uint32 src_height, - vx_uint32 dst_width, vx_uint32 dst_height) +vx_uint32 Remap::srcHeight() const { - vx_remap remap = nullptr; - - if (Context::isValidContext(context) == vx_true_e) - { - if (src_width != 0 && src_height != 0 && dst_width != 0 && dst_height != 0) - { - remap = (vx_remap)Reference::createReference(context, VX_TYPE_REMAP, VX_EXTERNAL, context); - if (vxGetStatus((vx_reference)remap) == VX_SUCCESS && remap->type == VX_TYPE_REMAP) - { - remap->src_width = src_width; - remap->src_height = src_height; - remap->dst_width = dst_width; - remap->dst_height = dst_height; - remap->memory.ndims = 3; - remap->memory.nptrs = 1; - remap->memory.dims[0][VX_DIM_C] = 2; // 2 "channels" of f32 - remap->memory.dims[0][VX_DIM_X] = dst_width; - remap->memory.dims[0][VX_DIM_Y] = dst_height; - remap->memory.strides[0][VX_DIM_C] = sizeof(vx_float32); - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to remap\n"); - vxAddLogEntry(context, VX_ERROR_INVALID_PARAMETERS, "Invalid parameters to remap\n"); - remap = (vx_remap)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); - } - } - - return remap; + return src_height; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseRemap(vx_remap* r) +vx_uint32 Remap::dstWidth() const { - vx_status status = VX_ERROR_INVALID_REFERENCE; - - if (nullptr != r) - { - vx_reference ref = *r; - if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_REMAP)) - { - status = Reference::releaseReference((vx_reference*)r, VX_TYPE_REMAP, VX_EXTERNAL, nullptr); - } - } + return dst_width; +} - return status; +vx_uint32 Remap::dstHeight() const +{ + return dst_height; } -VX_API_ENTRY vx_status VX_API_CALL vxQueryRemap(vx_remap remap, vx_enum attribute, void *ptr, vx_size size) +vx_status Remap::setRemapPoint(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 src_x, vx_float32 src_y) { vx_status status = VX_SUCCESS; - if (Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_false_e) - return VX_ERROR_INVALID_REFERENCE; - switch (attribute) + if (Memory::allocateMemory(context, &memory) == vx_false_e) { - case VX_REMAP_SOURCE_WIDTH: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = remap->src_width; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_REMAP_SOURCE_HEIGHT: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = remap->src_height; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_REMAP_DESTINATION_WIDTH: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = remap->dst_width; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_REMAP_DESTINATION_HEIGHT: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = remap->dst_height; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate memory for remap object!\n"); + status = VX_ERROR_NO_MEMORY; } - return status; -} -VX_API_ENTRY vx_status VX_API_CALL vxSetRemapPoint(vx_remap remap, vx_uint32 dst_x, vx_uint32 dst_y, - vx_float32 src_x, vx_float32 src_y) -{ - vx_status status = VX_FAILURE; - if ((Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_true_e) && - (Memory::allocateMemory(remap->context, &remap->memory) == vx_true_e)) + if ((dst_x >= dst_width) || (dst_y >= dst_height)) { - if ((dst_x < remap->dst_width) && - (dst_y < remap->dst_height)) - { - vx_float32 *coords[] = { - (vx_float32*)Memory::formatMemoryPtr(&remap->memory, 0, dst_x, dst_y, 0), - (vx_float32*)Memory::formatMemoryPtr(&remap->memory, 1, dst_x, dst_y, 0), - }; - *coords[0] = src_x; - *coords[1] = src_y; - // ownWroteToReference(remap); - status = VX_SUCCESS; - VX_PRINT(VX_ZONE_INFO, "SetRemapPoint %ux%u to %f,%f\n", dst_x, dst_y, src_x, src_y); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid source or destintation values!\n"); - status = VX_ERROR_INVALID_VALUE; - } + VX_PRINT(VX_ZONE_ERROR, "Invalid source or destintation values!\n"); + status = VX_ERROR_INVALID_VALUE; } - else + + if (VX_SUCCESS == status) { - VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); - status = VX_ERROR_INVALID_REFERENCE; + vx_float32 *coords[] = { + (vx_float32 *)Memory::formatMemoryPtr(&memory, 0, dst_x, dst_y, 0), + (vx_float32 *)Memory::formatMemoryPtr(&memory, 1, dst_x, dst_y, 0), + }; + *coords[0] = src_x; + *coords[1] = src_y; + // ownWroteToReference(remap); + status = VX_SUCCESS; + VX_PRINT(VX_ZONE_INFO, "SetRemapPoint %ux%u to %f,%f\n", dst_x, dst_y, src_x, src_y); } + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxGetRemapPoint(vx_remap remap, vx_uint32 dst_x, vx_uint32 dst_y, - vx_float32 *src_x, vx_float32 *src_y) +vx_status Remap::getRemapPoint(vx_uint32 dst_x, vx_uint32 dst_y, vx_float32 *src_x, + vx_float32 *src_y) { - vx_status status = VX_FAILURE; - if (Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_true_e) + vx_status status = VX_SUCCESS; + + if ((dst_x < dst_width) && (dst_y < dst_height)) { - if ((dst_x < remap->dst_width) && - (dst_y < remap->dst_height)) - { - vx_float32 *coords[] = { - (vx_float32*)Memory::formatMemoryPtr(&remap->memory, 0, dst_x, dst_y, 0), - (vx_float32*)Memory::formatMemoryPtr(&remap->memory, 1, dst_x, dst_y, 0), - }; - *src_x = *coords[0]; - *src_y = *coords[1]; - remap->read_count++; - status = VX_SUCCESS; + vx_float32 *coords[] = { + (vx_float32 *)Memory::formatMemoryPtr(&memory, 0, dst_x, dst_y, 0), + (vx_float32 *)Memory::formatMemoryPtr(&memory, 1, dst_x, dst_y, 0), + }; + *src_x = *coords[0]; + *src_y = *coords[1]; + read_count++; + status = VX_SUCCESS; - VX_PRINT(VX_ZONE_INFO, "GetRemapPoint dst[%u,%u] to src[%f,%f]\n", dst_x, dst_y, src_x, src_y); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid source or destintation values!\n"); - status = VX_ERROR_INVALID_VALUE; - } + VX_PRINT(VX_ZONE_INFO, "GetRemapPoint dst[%u,%u] to src[%f,%f]\n", dst_x, dst_y, src_x, + src_y); } else { - VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); - status = VX_ERROR_INVALID_REFERENCE; + VX_PRINT(VX_ZONE_ERROR, "Invalid source or destintation values!\n"); + status = VX_ERROR_INVALID_VALUE; } - return status; -} - -VX_API_ENTRY vx_remap VX_API_CALL vxCreateVirtualRemap(vx_graph graph, - vx_uint32 src_width, - vx_uint32 src_height, - vx_uint32 dst_width, - vx_uint32 dst_height) -{ - vx_remap remap = nullptr; - vx_reference gref = (vx_reference)graph; - if (Reference::isValidReference(gref, VX_TYPE_GRAPH) == vx_true_e) - { - remap = vxCreateRemap(gref->context, src_width, src_height, dst_width, dst_height); - if (vxGetStatus((vx_reference)remap) == VX_SUCCESS && remap->type == VX_TYPE_REMAP) - { - remap->scope = (vx_reference)graph; - remap->is_virtual = vx_true_e; - } - } - /* else, the graph is invalid, we can't get any context and then error object */ - return remap; + return status; } -VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, - const vx_rectangle_t *rect, - vx_size user_stride_y, - void * user_ptr, - vx_enum user_coordinate_type, - vx_enum usage, - vx_enum user_mem_type) +vx_status Remap::copyPatch(const vx_rectangle_t *rect, vx_size user_stride_y, void *user_ptr, + vx_enum user_coordinate_type, vx_enum usage, vx_enum user_mem_type) { vx_status status = VX_SUCCESS; vx_uint32 start_x = rect ? rect->start_x : 0u; vx_uint32 start_y = rect ? rect->start_y : 0u; vx_uint32 end_x = rect ? rect->end_x : 0u; vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); vx_size stride = user_stride_y / sizeof(vx_coordinates2df_t); /* bad parameters */ - if ( ((VX_READ_ONLY != usage) && (VX_WRITE_ONLY != usage)) || - (rect == nullptr) || (remap == nullptr) || (user_ptr == nullptr) ) + if (((VX_READ_ONLY != usage) && (VX_WRITE_ONLY != usage)) || (rect == nullptr) || + (user_ptr == nullptr)) { status = VX_ERROR_INVALID_PARAMETERS; } /* more bad parameters */ - if ( VX_SUCCESS == status && - ((user_stride_y < sizeof(vx_coordinates2df_t)*(rect->end_x - rect->start_x)) || - (user_coordinate_type != VX_TYPE_COORDINATES2DF))) + if (VX_SUCCESS == status && + ((user_stride_y < sizeof(vx_coordinates2df_t) * (rect->end_x - rect->start_x)) || + (user_coordinate_type != VX_TYPE_COORDINATES2DF))) { status = VX_ERROR_INVALID_PARAMETERS; } /* more bad parameters */ - if (VX_SUCCESS == status && - user_mem_type != VX_MEMORY_TYPE_HOST && user_mem_type != VX_MEMORY_TYPE_NONE) + if (VX_SUCCESS == status && user_mem_type != VX_MEMORY_TYPE_HOST && + user_mem_type != VX_MEMORY_TYPE_NONE) { status = VX_ERROR_INVALID_PARAMETERS; } - /* bad references */ - if (VX_SUCCESS == status && - Remap::isValidRemap(remap) == vx_false_e ) - { - status = VX_ERROR_INVALID_REFERENCE; - } - /* determine if virtual before checking for memory */ - if (VX_SUCCESS == status && - remap->is_virtual == vx_true_e) + if (VX_SUCCESS == status && is_virtual == vx_true_e) { - if (remap->is_accessible == vx_false_e) + if (is_accessible == vx_false_e) { /* User tried to access a "virtual" remap. */ VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual remap\n"); @@ -377,11 +239,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, } /* more bad parameters */ - if (VX_SUCCESS == status && - zero_area == vx_false_e && - ((0 >= remap->memory.nptrs) || - (start_x >= end_x) || - (start_y >= end_y))) + if (VX_SUCCESS == status && zero_area == vx_false_e && + ((0 >= memory.nptrs) || (start_x >= end_x) || (start_y >= end_y))) { status = VX_ERROR_INVALID_PARAMETERS; } @@ -389,25 +248,26 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, if (VX_SUCCESS == status) { #ifdef OPENVX_USE_OPENCL_INTEROP - void * user_ptr_given = user_ptr; + void *user_ptr_given = user_ptr; vx_enum user_mem_type_given = user_mem_type; if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) { // get ptr from OpenCL buffer for HOST size_t size = 0; cl_mem opencl_buf = (cl_mem)user_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyRemap: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); + opencl_buf, cerr); if (cerr != CL_SUCCESS) { return VX_ERROR_INVALID_PARAMETERS; } - user_ptr = clEnqueueMapBuffer(remap->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); + user_ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyRemap: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, user_ptr, cerr); + opencl_buf, (int)size, user_ptr, cerr); if (cerr != CL_SUCCESS) { return VX_ERROR_INVALID_PARAMETERS; @@ -419,7 +279,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, if (usage == VX_READ_ONLY) { /* Copy from remap (READ) mode */ - vx_coordinates2df_t *ptr = (vx_coordinates2df_t*)user_ptr; + vx_coordinates2df_t *ptr = (vx_coordinates2df_t *)user_ptr; vx_uint32 i; vx_uint32 j; for (i = start_y; i < end_y; i++) @@ -427,14 +287,14 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, for (j = start_x; j < end_x; j++) { vx_coordinates2df_t *coord_ptr = &(ptr[i * stride + j]); - status = remap->getCoordValue(j, i, &coord_ptr->x, &coord_ptr->y); + status = getCoordValue(j, i, &coord_ptr->x, &coord_ptr->y); } } } else { /* Copy to remap (WRITE) mode */ - vx_coordinates2df_t *ptr = (vx_coordinates2df_t*)user_ptr; + vx_coordinates2df_t *ptr = (vx_coordinates2df_t *)user_ptr; vx_uint32 i; vx_uint32 j; for (i = start_y; i < end_y; i++) @@ -442,18 +302,17 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, for (j = start_x; j < end_x; j++) { vx_coordinates2df_t *coord_ptr = &(ptr[i * stride + j]); - status = remap->setCoordValue(j, i, coord_ptr->x, coord_ptr->y); + status = setCoordValue(j, i, coord_ptr->x, coord_ptr->y); } } } #ifdef OPENVX_USE_OPENCL_INTEROP - if (VX_SUCCESS == status && - user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + if (VX_SUCCESS == status && user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) { - clEnqueueUnmapMemObject(remap->context->opencl_command_queue, - (cl_mem)user_ptr_given, user_ptr, 0, nullptr, nullptr); - clFinish(remap->context->opencl_command_queue); + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)user_ptr_given, user_ptr, + 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); } #endif } @@ -462,48 +321,33 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, return status; } - -VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, - const vx_rectangle_t *rect, - vx_map_id *map_id, - vx_size *stride_y, - void **ptr, - vx_enum coordinate_type, - vx_enum usage, - vx_enum mem_type) +vx_status Remap::mapPatch(const vx_rectangle_t *rect, vx_map_id *map_id, vx_size *stride_y, + void **ptr, vx_enum coordinate_type, vx_enum usage, vx_enum mem_type) { vx_uint32 start_x = rect ? rect->start_x : 0u; vx_uint32 start_y = rect ? rect->start_y : 0u; - vx_uint32 end_x = rect ? rect->end_x : 0u; - vx_uint32 end_y = rect ? rect->end_y : 0u; - vx_bool zero_area = ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); + vx_uint32 end_x = rect ? rect->end_x : 0u; + vx_uint32 end_y = rect ? rect->end_y : 0u; + vx_bool zero_area = + ((((end_x - start_x) == 0) || ((end_y - start_y) == 0)) ? vx_true_e : vx_false_e); vx_status status = VX_SUCCESS; /* bad parameters */ - if ( (rect == nullptr) || (map_id == nullptr) || (remap == nullptr) || (ptr == nullptr) ) + if ((rect == nullptr) || (map_id == nullptr) || (ptr == nullptr)) { status = VX_ERROR_INVALID_PARAMETERS; } /* more bad parameters */ - if (VX_SUCCESS == status && - coordinate_type != VX_TYPE_COORDINATES2DF) + if (VX_SUCCESS == status && coordinate_type != VX_TYPE_COORDINATES2DF) { status = VX_ERROR_INVALID_PARAMETERS; } - /* bad references */ - if (VX_SUCCESS == status && - Remap::isValidRemap(remap) == vx_false_e) - { - status = VX_ERROR_INVALID_REFERENCE; - } - /* determine if virtual before checking for memory */ - if (VX_SUCCESS == status && - remap->is_virtual == vx_true_e) + if (VX_SUCCESS == status && is_virtual == vx_true_e) { - if (remap->is_accessible == vx_false_e) + if (is_accessible == vx_false_e) { /* User tried to access a "virtual" remap. */ VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual remap\n"); @@ -513,11 +357,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, } /* more bad parameters */ - if (VX_SUCCESS == status && - zero_area == vx_false_e && - ((0 >= remap->memory.nptrs) || - (start_x >= end_x) || - (start_y >= end_y))) + if (VX_SUCCESS == status && zero_area == vx_false_e && + ((0 >= memory.nptrs) || (start_x >= end_x) || (start_y >= end_y))) { status = VX_ERROR_INVALID_PARAMETERS; } @@ -543,12 +384,12 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, vx_size size = (stride * (end_y - start_y)) * sizeof(vx_coordinates2df_t); vx_size user_stride_y = stride * sizeof(vx_coordinates2df_t); - if (remap->context->memoryMap((vx_reference)remap, size, usage, mem_type, flags, &extra, (void **)&buf, map_id) == vx_true_e) + if (context->memoryMap((vx_reference)this, size, usage, mem_type, flags, &extra, + (void **)&buf, map_id) == vx_true_e) { if (VX_READ_ONLY == usage || VX_READ_AND_WRITE == usage) { - - if (Osal::semWait(&remap->memory.locks[0]) == vx_true_e) + if (Osal::semWait(&memory.locks[0]) == vx_true_e) { *stride_y = user_stride_y; @@ -560,16 +401,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, for (j = start_x; j < end_x; j++) { vx_coordinates2df_t *coord_ptr = &(buf_ptr[i * stride + j]); - status = remap->getCoordValue(j, i, &coord_ptr->x, &coord_ptr->y); + status = getCoordValue(j, i, &coord_ptr->x, &coord_ptr->y); } } if (VX_SUCCESS == status) { *ptr = buf; - remap->incrementReference(VX_EXTERNAL); + incrementReference(VX_EXTERNAL); } - Osal::semPost(&remap->memory.locks[0]); + Osal::semPost(&memory.locks[0]); } else { @@ -581,7 +422,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, /* write only mode */ *stride_y = user_stride_y; *ptr = buf; - remap->incrementReference(VX_EXTERNAL); + incrementReference(VX_EXTERNAL); } } else @@ -590,21 +431,19 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, } #ifdef OPENVX_USE_OPENCL_INTEROP - if ((status == VX_SUCCESS) && - remap->context->opencl_context && - (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && - (size > 0) && ptr && *ptr) + if ((status == VX_SUCCESS) && context->opencl_context && + (mem_type_requested == VX_MEMORY_TYPE_OPENCL_BUFFER) && (size > 0) && ptr && *ptr) { /* create OpenCL buffer using the host allocated pointer */ cl_int cerr = 0; - cl_mem opencl_buf = clCreateBuffer(remap->context->opencl_context, - CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, - size, *ptr, &cerr); + cl_mem opencl_buf = + clCreateBuffer(context->opencl_context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, + size, *ptr, &cerr); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxMapRemap: clCreateBuffer(%u) => %p (%d)\n", - (vx_uint32)size, opencl_buf, cerr); + (vx_uint32)size, opencl_buf, cerr); if (cerr == CL_SUCCESS) { - remap->context->memory_maps[*map_id].opencl_buf = opencl_buf; + context->memory_maps[*map_id].opencl_buf = opencl_buf; *ptr = opencl_buf; } else @@ -619,46 +458,36 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, return status; } - -VX_API_ENTRY vx_status VX_API_CALL vxUnmapRemapPatch(vx_remap remap, vx_map_id map_id) +vx_status Remap::unmapPatch(vx_uint32 map_id) { vx_status status = VX_SUCCESS; - /* bad references */ - if (Remap::isValidRemap(remap) == vx_false_e) - { - status = VX_ERROR_INVALID_REFERENCE; - goto exit; - } - /* bad parameters */ - if (remap->context->findMemoryMap((vx_reference)remap, map_id) != vx_true_e) + if (context->findMemoryMap((vx_reference)this, map_id) != vx_true_e) { status = VX_ERROR_INVALID_PARAMETERS; goto exit; } #ifdef OPENVX_USE_OPENCL_INTEROP - if (remap->context->opencl_context && - remap->context->memory_maps[map_id].opencl_buf && - remap->context->memory_maps[map_id].ptr) - { - clEnqueueUnmapMemObject(remap->context->opencl_command_queue, - remap->context->memory_maps[map_id].opencl_buf, - remap->context->memory_maps[map_id].ptr, 0, nullptr, nullptr); - clFinish(remap->context->opencl_command_queue); - cl_int cerr = clReleaseMemObject(remap->context->memory_maps[map_id].opencl_buf); + if (context->opencl_context && context->memory_maps[map_id].opencl_buf && + context->memory_maps[map_id].ptr) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, + context->memory_maps[map_id].opencl_buf, + context->memory_maps[map_id].ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + cl_int cerr = clReleaseMemObject(context->memory_maps[map_id].opencl_buf); VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxUnmapRemap: clReleaseMemObject(%p) => (%d)\n", - remap->context->memory_maps[map_id].opencl_buf, cerr); - remap->context->memory_maps[map_id].opencl_buf = nullptr; + context->memory_maps[map_id].opencl_buf, cerr); + context->memory_maps[map_id].opencl_buf = nullptr; } #endif if (VX_SUCCESS == status) { - vx_context context = remap->context; - vx_memory_map_t* map = &context->memory_maps[map_id]; - if (map->used && map->ref == (vx_reference)remap) + vx_memory_map_t *map = &context->memory_maps[map_id]; + if (map->used && map->ref == (vx_reference)this) { vx_rectangle_t rect = map->extra.image_data.rect; if (VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) @@ -672,8 +501,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapRemapPatch(vx_remap remap, vx_map_id m for (j = rect.start_x; j < rect.end_x; j++) { vx_coordinates2df_t *coord_ptr = &(ptr[i * stride + j]); - status = remap->setCoordValue(j, i, coord_ptr->x, coord_ptr->y); - if(status != VX_SUCCESS) + status = setCoordValue(j, i, coord_ptr->x, coord_ptr->y); + if (status != VX_SUCCESS) { goto exit; } @@ -681,14 +510,14 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapRemapPatch(vx_remap remap, vx_map_id m } context->memoryUnmap((vx_uint32)map_id); - remap->decrementReference(VX_EXTERNAL); + decrementReference(VX_EXTERNAL); status = VX_SUCCESS; } else { /* rean only mode */ - remap->context->memoryUnmap((vx_uint32)map_id); - remap->decrementReference(VX_EXTERNAL); + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); status = VX_SUCCESS; } } @@ -702,3 +531,219 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapRemapPatch(vx_remap remap, vx_map_id m VX_PRINT(VX_ZONE_API, "return %d\n", status); return status; } + +void Remap::destruct() +{ + Memory::freeMemory(context, &memory); +} + +/*****************************************************************************/ +/* PUBLIC INTERFACE */ +/*****************************************************************************/ + +VX_API_ENTRY vx_remap VX_API_CALL vxCreateRemap(vx_context context, vx_uint32 src_width, + vx_uint32 src_height, vx_uint32 dst_width, + vx_uint32 dst_height) +{ + vx_remap remap = nullptr; + + if (Context::isValidContext(context) == vx_true_e) + { + if (src_width != 0 && src_height != 0 && dst_width != 0 && dst_height != 0) + { + remap = + (vx_remap)Reference::createReference(context, VX_TYPE_REMAP, VX_EXTERNAL, context); + if (vxGetStatus((vx_reference)remap) == VX_SUCCESS && remap->type == VX_TYPE_REMAP) + { + remap->src_width = src_width; + remap->src_height = src_height; + remap->dst_width = dst_width; + remap->dst_height = dst_height; + remap->memory.ndims = 3; + remap->memory.nptrs = 1; + remap->memory.dims[0][VX_DIM_C] = 2; // 2 "channels" of f32 + remap->memory.dims[0][VX_DIM_X] = dst_width; + remap->memory.dims[0][VX_DIM_Y] = dst_height; + remap->memory.strides[0][VX_DIM_C] = sizeof(vx_float32); + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to remap\n"); + vxAddLogEntry(context, VX_ERROR_INVALID_PARAMETERS, "Invalid parameters to remap\n"); + remap = (vx_remap)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } + } + + return remap; +} + +VX_API_ENTRY vx_remap VX_API_CALL vxCreateVirtualRemap(vx_graph graph, vx_uint32 src_width, + vx_uint32 src_height, vx_uint32 dst_width, + vx_uint32 dst_height) +{ + vx_remap remap = nullptr; + vx_reference gref = (vx_reference)graph; + + if (Reference::isValidReference(gref, VX_TYPE_GRAPH) == vx_true_e) + { + remap = vxCreateRemap(gref->context, src_width, src_height, dst_width, dst_height); + if (vxGetStatus((vx_reference)remap) == VX_SUCCESS && remap->type == VX_TYPE_REMAP) + { + remap->scope = (vx_reference)graph; + remap->is_virtual = vx_true_e; + } + } + /* else, the graph is invalid, we can't get any context and then error object */ + return remap; +} + +VX_API_ENTRY vx_status VX_API_CALL vxQueryRemap(vx_remap remap, vx_enum attribute, void *ptr, + vx_size size) +{ + vx_status status = VX_SUCCESS; + if (Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_false_e) + return VX_ERROR_INVALID_REFERENCE; + + switch (attribute) + { + case VX_REMAP_SOURCE_WIDTH: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = remap->srcWidth(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_REMAP_SOURCE_HEIGHT: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = remap->srcHeight(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_REMAP_DESTINATION_WIDTH: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = remap->dstWidth(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_REMAP_DESTINATION_HEIGHT: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32 *)ptr = remap->dstHeight(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; + } + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxSetRemapPoint(vx_remap remap, vx_uint32 dst_x, vx_uint32 dst_y, + vx_float32 src_x, vx_float32 src_y) +{ + vx_status status = VX_FAILURE; + if (Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_true_e) + { + status = remap->setRemapPoint(dst_x, dst_y, src_x, src_y); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); + status = VX_ERROR_INVALID_REFERENCE; + } + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxGetRemapPoint(vx_remap remap, vx_uint32 dst_x, vx_uint32 dst_y, + vx_float32 *src_x, vx_float32 *src_y) +{ + vx_status status = VX_FAILURE; + if (Reference::isValidReference(remap, VX_TYPE_REMAP) == vx_true_e) + { + status = remap->getRemapPoint(dst_x, dst_y, src_x, src_y); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Not a valid object!\n"); + status = VX_ERROR_INVALID_REFERENCE; + } + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxCopyRemapPatch(vx_remap remap, const vx_rectangle_t *rect, + vx_size user_stride_y, void *user_ptr, + vx_enum user_coordinate_type, vx_enum usage, + vx_enum user_mem_type) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + /* bad references */ + if (Remap::isValidRemap(remap) == vx_true_e) + { + status = remap->copyPatch(rect, user_stride_y, user_ptr, user_coordinate_type, usage, + user_mem_type); + } + + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxMapRemapPatch(vx_remap remap, const vx_rectangle_t *rect, + vx_map_id *map_id, vx_size *stride_y, void **ptr, + vx_enum coordinate_type, vx_enum usage, + vx_enum mem_type) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + /* bad references */ + if (Remap::isValidRemap(remap) == vx_true_e) + { + status = remap->mapPatch(rect, map_id, stride_y, ptr, coordinate_type, usage, mem_type); + } + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxUnmapRemapPatch(vx_remap remap, vx_map_id map_id) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + /* bad references */ + if (Remap::isValidRemap(remap) == vx_true_e) + { + status = remap->unmapPatch(map_id); + } + + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseRemap(vx_remap *r) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != r) + { + vx_reference ref = *r; + if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_REMAP)) + { + status = + Reference::releaseReference((vx_reference *)r, VX_TYPE_REMAP, VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From aa147c4031f65279eee62b23080bbc67c19c9f18 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 16:35:37 -0700 Subject: [PATCH 10/34] Reworked threshold --- framework/include/vx_threshold.h | 236 +++++ framework/src/vx_threshold.cpp | 1480 ++++++++++++++++-------------- 2 files changed, 1044 insertions(+), 672 deletions(-) diff --git a/framework/include/vx_threshold.h b/framework/include/vx_threshold.h index fa7a6d08..5b3701a1 100644 --- a/framework/include/vx_threshold.h +++ b/framework/include/vx_threshold.h @@ -53,6 +53,198 @@ class Threshold : public Reference */ ~Threshold(); + /** + * @brief Set the binary threshold value + * + * @param value The binary threshold value + * @ingroup group_int_threshold + */ + void setBinaryValue(vx_int32 value); + + /** + * @brief Set the binary threshold value as a pixel value union + * + * @param value The binary threshold value as a pixel value union + * @ingroup group_int_threshold + */ + void setBinaryValueUnion(vx_pixel_value_t value); + + /** + * @brief Set the lower bound for range threshold + * + * @param lower The lower bound value + * @ingroup group_int_threshold + */ + void setLowerBound(vx_int32 lower); + + /** + * @brief Set the lower bound for range threshold as a pixel value union + * + * @param lower The lower bound value as a pixel value union + * @ingroup group_int_threshold + */ + void setLowerBoundUnion(vx_pixel_value_t lower); + + /** + * @brief Set the upper bound for range threshold + * + * @param upper The upper bound value + * @ingroup group_int_threshold + */ + void setUpperBound(vx_int32 upper); + + /** + * @brief Set the upper bound for range threshold as a pixel value union + * + * @param upper The upper bound value as a pixel value union + * @ingroup group_int_threshold + */ + void setUpperBoundUnion(vx_pixel_value_t upper); + + /** + * @brief Set the true value for output + * + * @param true_value The true value + * @ingroup group_int_threshold + */ + void setTrueValue(vx_int32 true_value); + + /** + * @brief Set the true value for output as a pixel value union + * + * @param true_value The true value as a pixel value union + * @ingroup group_int_threshold + */ + void setTrueValueUnion(vx_pixel_value_t true_value); + + /** + * @brief Set the false value for output + * + * @param false_value The false value + * @ingroup group_int_threshold + */ + void setFalseValue(vx_int32 false_value); + + /** + * @brief Set the false value for output as a pixel value union + * + * @param false_value The false value as a pixel value union + * @ingroup group_int_threshold + */ + void setFalseValueUnion(vx_pixel_value_t false_value); + + /** + * @brief Get the binary threshold value + * + * @return vx_int32 The binary threshold value + * @ingroup group_int_threshold + */ + vx_int32 binaryValue() const; + + /** + * @brief Get the binary threshold value as a pixel value union + * + * @return vx_pixel_value_t + * @ingroup group_int_threshold + */ + vx_pixel_value_t binaryValueUnion() const; + + /** + * @brief Get the lower bound for range threshold + * + * @return vx_int32 The lower bound value + * @ingroup group_int_threshold + */ + vx_int32 lowerBound() const; + + /** + * @brief Get the lower bound for range threshold as a pixel value union + * + * @return vx_pixel_value_t + * @ingroup group_int_threshold + */ + vx_pixel_value_t lowerBoundUnion() const; + + /** + * @brief Get the upper bound for range threshold + * + * @return vx_int32 The upper bound value + * @ingroup group_int_threshold + */ + vx_int32 upperBound() const; + + /** + * @brief Get the upper bound for range threshold as a pixel value union + * + * @return vx_pixel_value_t + * @ingroup group_int_threshold + */ + vx_pixel_value_t upperBoundUnion() const; + + /** + * @brief Get the true value for output + * + * @return vx_int32 The true value + * @ingroup group_int_threshold + */ + vx_int32 trueValue() const; + + /** + * @brief Get the true value for output as a pixel value union + * + * @return vx_pixel_value_t + * @ingroup group_int_threshold + */ + vx_pixel_value_t trueValueUnion() const; + + /** + * @brief Get the false value for output + * + * @return vx_int32 The false value + * @ingroup group_int_threshold + */ + vx_int32 falseValue() const; + + /** + * @brief Get the false value for output as a pixel value union + * + * @return vx_pixel_value_t + * @ingroup group_int_threshold + */ + vx_pixel_value_t falseValueUnion() const; + + /** + * @brief Get the data type of the threshold + * + * @return vx_enum The data type + * @ingroup group_int_threshold + */ + vx_enum dataType() const; + + /** + * @brief Get the threshold type + * + * @return vx_enum The threshold type + * @ingroup group_int_threshold + */ + vx_enum threshType() const; + + /** + * @brief Get the input image format + * + * @return vx_df_image The input image format + * @ingroup group_int_threshold + */ + vx_df_image inputFormat() const; + + /** + * @brief Get the output image format + * + * @return vx_df_image The output image format + * @ingroup group_int_threshold + */ + vx_df_image outputFormat() const; + /** * @brief Validate threshold type * @@ -71,6 +263,50 @@ class Threshold : public Reference */ static vx_bool isValidThresholdDataType(vx_enum data_type); + /** + * @brief Validate threshold format + * + * @param format Threshold format to validate + * @return vx_bool true if valid, false otherwise + * @ingroup group_int_threshold + */ + static vx_bool isValidThresholdFormat(vx_df_image format); + + /** + * @brief Copy the threshold output to/from user memory + * + * @param true_value_ptr Pointer to the true value + * @param false_value_ptr Pointer to the false value + * @param usage Memory usage type (read/write) + * @param user_mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_threshold + */ + vx_status copyOutput(vx_pixel_value_t *true_value_ptr, vx_pixel_value_t *false_value_ptr, + vx_enum usage, vx_enum user_mem_type); + + /** + * @brief Copy the threshold range to/from user memory + * @param lower_value_ptr Pointer to the lower value + * @param upper_value_ptr Pointer to the upper value + * @param usage Memory usage type (read/write) + * @param user_mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_threshold + */ + vx_status copyRange(vx_pixel_value_t *lower_value_ptr, vx_pixel_value_t *upper_value_ptr, + vx_enum usage, vx_enum user_mem_type); + + /** + * @brief Copy the threshold value to/from user memory + * @param value_ptr Pointer to the value + * @param usage Memory usage type (read/write) + * @param user_mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_threshold + */ + vx_status copyValue(vx_pixel_value_t *value_ptr, vx_enum usage, vx_enum user_mem_type); + /*! \brief From \ref vx_threshold_type_e */ vx_enum thresh_type; /*! \brief From \ref vx_type_e */ diff --git a/framework/src/vx_threshold.cpp b/framework/src/vx_threshold.cpp index 3cb76050..564a421e 100644 --- a/framework/src/vx_threshold.cpp +++ b/framework/src/vx_threshold.cpp @@ -39,6 +39,126 @@ Threshold::~Threshold() } +void Threshold::setBinaryValue(vx_int32 value) +{ + this->value.S32 = value; +} + +void Threshold::setBinaryValueUnion(vx_pixel_value_t value) +{ + this->value = value; +} + +void Threshold::setLowerBound(vx_int32 lower) +{ + this->lower.S32 = lower; +} + +void Threshold::setLowerBoundUnion(vx_pixel_value_t lower) +{ + this->lower = lower; +} + +void Threshold::setUpperBound(vx_int32 upper) +{ + this->upper.S32 = upper; +} + +void Threshold::setUpperBoundUnion(vx_pixel_value_t upper) +{ + this->upper = upper; +} + +void Threshold::setTrueValue(vx_int32 true_value) +{ + this->true_value.S32 = true_value; +} + +void Threshold::setTrueValueUnion(vx_pixel_value_t true_value) +{ + this->true_value = true_value; +} + +void Threshold::setFalseValue(vx_int32 false_value) +{ + this->false_value.S32 = false_value; +} + +void Threshold::setFalseValueUnion(vx_pixel_value_t false_value) +{ + this->false_value = false_value; +} + +vx_int32 Threshold::binaryValue() const +{ + return value.S32; +} + +vx_pixel_value_t Threshold::binaryValueUnion() const +{ + return value; +} + +vx_int32 Threshold::lowerBound() const +{ + return lower.S32; +} + +vx_pixel_value_t Threshold::lowerBoundUnion() const +{ + return lower; +} + +vx_int32 Threshold::upperBound() const +{ + return upper.S32; +} + +vx_pixel_value_t Threshold::upperBoundUnion() const +{ + return upper; +} + +vx_int32 Threshold::trueValue() const +{ + return true_value.S32; +} + +vx_pixel_value_t Threshold::trueValueUnion() const +{ + return true_value; +} + +vx_int32 Threshold::falseValue() const +{ + return true_value.S32; +} + +vx_pixel_value_t Threshold::falseValueUnion() const +{ + return true_value; +} + +vx_enum Threshold::dataType() const +{ + return data_type; +} + +vx_enum Threshold::threshType() const +{ + return thresh_type; +} + +vx_df_image Threshold::inputFormat() const +{ + return input_format; +} + +vx_df_image Threshold::outputFormat() const +{ + return output_format; +} + vx_bool Threshold::isValidThresholdType(vx_enum thresh_type) { vx_bool ret = vx_false_e; @@ -66,377 +186,468 @@ vx_bool Threshold::isValidThresholdDataType(vx_enum data_type) return ret; } -/*****************************************************************************/ -/* PUBLIC INTERFACE */ -/*****************************************************************************/ +vx_bool Threshold::isValidThresholdFormat(vx_df_image format) +{ + vx_bool ret = vx_false_e; + if (format == VX_DF_IMAGE_U1 || format == VX_DF_IMAGE_U8 || format == VX_DF_IMAGE_S16 || + format == VX_DF_IMAGE_U16 || format == VX_DF_IMAGE_S32 || format == VX_DF_IMAGE_U32 || + format == VX_DF_IMAGE_RGB || format == VX_DF_IMAGE_RGBX || format == VX_DF_IMAGE_NV12 || + format == VX_DF_IMAGE_NV21 || format == VX_DF_IMAGE_UYVY || format == VX_DF_IMAGE_YUYV || + format == VX_DF_IMAGE_IYUV || format == VX_DF_IMAGE_YUV4) + { + ret = vx_true_e; + } + return ret; +} -VX_API_ENTRY vx_status VX_API_CALL vxReleaseThreshold(vx_threshold* t) +vx_status Threshold::copyOutput(vx_pixel_value_t *true_value_ptr, vx_pixel_value_t *false_value_ptr, + vx_enum usage, vx_enum user_mem_type) { - vx_status status = VX_ERROR_INVALID_REFERENCE; + vx_status status = VX_SUCCESS; - if (nullptr != t) + if (is_virtual == vx_true_e) { - vx_threshold ref = *t; - if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_THRESHOLD)) + if (is_accessible == vx_false_e) { - status = Reference::releaseReference((vx_reference*)t, VX_TYPE_THRESHOLD, VX_EXTERNAL, nullptr); + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + return status; } } - return status; -} - -VX_API_ENTRY vx_threshold VX_API_CALL vxCreateThreshold(vx_context context, vx_enum thresh_type, vx_enum data_type) -{ - vx_threshold threshold = nullptr; - - if (Context::isValidContext(context) == vx_true_e) +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_pixel_value_t *true_value_ptr_given = true_value_ptr; + vx_pixel_value_t *false_value_ptr_given = false_value_ptr; + vx_enum user_mem_type_given = user_mem_type; + if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) { - if (Threshold::isValidThresholdDataType(data_type) == vx_true_e) + // get ptr from OpenCL buffer for HOST + if (true_value_ptr) { - if (Threshold::isValidThresholdType(thresh_type) == vx_true_e) + size_t size = 0; + cl_mem opencl_buf = (cl_mem)true_value_ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdOutput: clGetMemObjectInfo(%p) => (%d)\n", opencl_buf, + cerr); + if (cerr != CL_SUCCESS) { - threshold = (vx_threshold)Reference::createReference(context, VX_TYPE_THRESHOLD, VX_EXTERNAL, context); - if (vxGetStatus((vx_reference)threshold) == VX_SUCCESS && threshold->type == VX_TYPE_THRESHOLD) - { - threshold->thresh_type = thresh_type; - threshold->data_type = data_type; - switch(data_type) - { - case VX_TYPE_BOOL: - threshold->true_value.U1 = VX_U1_THRESHOLD_TRUE_VALUE; - threshold->false_value.U1 = VX_U1_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_INT8: - threshold->true_value.U8 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.U8 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_UINT8: - threshold->true_value.U8 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.U8 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_UINT16: - threshold->true_value.U16 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.U16 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_INT16: - threshold->true_value.S16 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.S16 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_INT32: - threshold->true_value.S32 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.S32 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - case VX_TYPE_UINT32: - threshold->true_value.U32 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; - threshold->false_value.U32 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; - break; - default: - break; - } - } + return VX_ERROR_INVALID_PARAMETERS; } - else + true_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer( + context->opencl_command_queue, opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, + size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdOutput: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, true_value_ptr, cerr); + if (cerr != CL_SUCCESS) { - VX_PRINT(VX_ZONE_ERROR, "Invalid threshold type\n"); - vxAddLogEntry(context, VX_ERROR_INVALID_TYPE, "Invalid threshold type\n"); - threshold = (vx_threshold)vxGetErrorObject(context, VX_ERROR_INVALID_TYPE); + return VX_ERROR_INVALID_PARAMETERS; } } - else + if (false_value_ptr) { - VX_PRINT(VX_ZONE_ERROR, "Invalid data type\n"); - vxAddLogEntry(context, VX_ERROR_INVALID_TYPE, "Invalid data type\n"); - threshold = (vx_threshold)vxGetErrorObject(context, VX_ERROR_INVALID_TYPE); + size_t size = 0; + cl_mem opencl_buf = (cl_mem)false_value_ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdOutput: clGetMemObjectInfo(%p) => (%d)\n", opencl_buf, + cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + false_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer( + context->opencl_command_queue, opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, + size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdOutput: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, false_value_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } } + user_mem_type = VX_MEMORY_TYPE_HOST; } +#endif - return threshold; -} - -VX_API_ENTRY vx_status VX_API_CALL vxSetThresholdAttribute(vx_threshold threshold, vx_enum attribute, const void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_true_e) + if (VX_MEMORY_TYPE_HOST == user_mem_type) { - switch (attribute) + if (usage == VX_READ_ONLY) { - case VX_THRESHOLD_THRESHOLD_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) - { - threshold->value.S32 = *(vx_int32 *)ptr; - // ownWroteToReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) - { - threshold->value = *(vx_pixel_value_t *)ptr; - // ownWroteToReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_THRESHOLD_LOWER: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - threshold->lower.S32 = *(vx_int32 *)ptr; - // ownWroteToReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - threshold->lower = *(vx_pixel_value_t *)ptr; - // ownWroteToReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_THRESHOLD_UPPER: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - threshold->upper.S32 = *(vx_int32 *)ptr; - // ownWroteToReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - threshold->upper = *(vx_pixel_value_t *)ptr; - // ownWroteToReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_TRUE_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) - { - threshold->true_value.S32 = *(vx_int32 *)ptr; - // ownWroteToReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) - { - threshold->true_value = *(vx_pixel_value_t *)ptr; - // ownWroteToReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_FALSE_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) - { - threshold->false_value.S32 = *(vx_int32 *)ptr; - // ownWroteToReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) - { - threshold->false_value = *(vx_pixel_value_t *)ptr; - // ownWroteToReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (true_value_ptr) + { + memcpy(true_value_ptr, &true_value, size); + } + if (false_value_ptr) + { + memcpy(false_value_ptr, &false_value, size); + } + Osal::semPost(&lock); + // ownReadFromReference(&threshold); + status = VX_SUCCESS; + } + else if (usage == VX_WRITE_ONLY) + { + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (true_value_ptr) + { + memcpy(&true_value, true_value_ptr, size); + } + if (false_value_ptr) + { + memcpy(&false_value, false_value_ptr, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&threshold); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); + status = VX_ERROR_INVALID_PARAMETERS; } } else { - status = VX_ERROR_INVALID_REFERENCE; + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); + status = VX_ERROR_NO_MEMORY; } - VX_PRINT(VX_ZONE_API, "return %d\n", status); - return status; -} -VX_API_ENTRY vx_status VX_API_CALL vxQueryThreshold(vx_threshold threshold, vx_enum attribute, void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_true_e) +#ifdef OPENVX_USE_OPENCL_INTEROP + if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) { - switch (attribute) + if (true_value_ptr_given) { - case VX_THRESHOLD_THRESHOLD_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) - { - *(vx_int32 *)ptr = threshold->value.S32; - // ownReadFromReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) - { - *(vx_pixel_value_t *)ptr = threshold->value; - // ownReadFromReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_THRESHOLD_LOWER: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - *(vx_int32 *)ptr = threshold->lower.S32; - // ownReadFromReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - *(vx_pixel_value_t *)ptr = threshold->lower; - // ownReadFromReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_THRESHOLD_UPPER: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - *(vx_int32 *)ptr = threshold->upper.S32; - // ownReadFromReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && - (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) - { - *(vx_pixel_value_t *)ptr = threshold->upper; - // ownReadFromReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_TRUE_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) - { - *(vx_int32 *)ptr = threshold->true_value.S32; - // ownReadFromReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) - { - *(vx_pixel_value_t *)ptr = threshold->true_value; - // ownReadFromReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_FALSE_VALUE: - if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) - { - *(vx_int32 *)ptr = threshold->false_value.S32; - // ownReadFromReference(&threshold); - } - else if(VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) - { - *(vx_pixel_value_t *)ptr = threshold->false_value; - // ownReadFromReference(&threshold); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_DATA_TYPE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_enum *)ptr = threshold->data_type; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_TYPE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_enum *)ptr = threshold->thresh_type; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_INPUT_FORMAT: - if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) - { - *(vx_df_image *)ptr = threshold->input_format; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_THRESHOLD_OUTPUT_FORMAT: - if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) - { - *(vx_df_image *)ptr = threshold->output_format; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)true_value_ptr_given, + true_value_ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + } + if (false_value_ptr_given) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)false_value_ptr_given, + false_value_ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + } + } +#endif + + return status; +} + +vx_status Threshold::copyRange(vx_pixel_value_t *lower_value_ptr, vx_pixel_value_t *upper_value_ptr, + vx_enum usage, vx_enum user_mem_type) +{ + vx_status status = VX_SUCCESS; + + if (is_virtual == vx_true_e) + { + if (is_accessible == vx_false_e) + { + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + return status; + } + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_pixel_value_t *lower_value_ptr_given = lower_value_ptr; + vx_pixel_value_t *upper_value_ptr_given = upper_value_ptr; + vx_enum user_mem_type_given = user_mem_type; + if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + if (lower_value_ptr) + { + size_t size = 0; + cl_mem opencl_buf = (cl_mem)lower_value_ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdRange: clGetMemObjectInfo(%p) => (%d)\n", opencl_buf, + cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + lower_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer( + context->opencl_command_queue, opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, + size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, lower_value_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + } + if (upper_value_ptr) + { + size_t size = 0; + cl_mem opencl_buf = (cl_mem)upper_value_ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdRange: clGetMemObjectInfo(%p) => (%d)\n", opencl_buf, + cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + upper_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer( + context->opencl_command_queue, opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, + size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, upper_value_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + } + user_mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + + if (VX_MEMORY_TYPE_HOST == user_mem_type) + { + if (usage == VX_READ_ONLY) + { + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (lower_value_ptr) + { + memcpy(lower_value_ptr, &lower, size); + } + if (upper_value_ptr) + { + memcpy(upper_value_ptr, &upper, size); + } + Osal::semPost(&lock); + // ownReadFromReference(&threshold); + status = VX_SUCCESS; + } + else if (usage == VX_WRITE_ONLY) + { + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (lower_value_ptr) + { + memcpy(&lower, lower_value_ptr, size); + } + if (upper_value_ptr) + { + memcpy(&upper, upper_value_ptr, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&threshold); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); + status = VX_ERROR_NO_MEMORY; + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + if (lower_value_ptr_given) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)lower_value_ptr_given, + lower_value_ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + } + if (upper_value_ptr_given) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)upper_value_ptr_given, + upper_value_ptr, 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + } + } +#endif + + return status; +} + +vx_status Threshold::copyValue(vx_pixel_value_t *value_ptr, vx_enum usage, vx_enum user_mem_type) +{ + vx_status status = VX_SUCCESS; + + if (is_virtual == vx_true_e) + { + if (is_accessible == vx_false_e) + { + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + return status; + } + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + vx_pixel_value_t *value_ptr_given = value_ptr; + vx_enum user_mem_type_given = user_mem_type; + if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + size_t size = 0; + cl_mem opencl_buf = (cl_mem)value_ptr; + cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdValue: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer( + context->opencl_command_queue, opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, + 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyThresholdValue: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", opencl_buf, + (int)size, value_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + user_mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + + if (VX_MEMORY_TYPE_HOST == user_mem_type) + { + if (usage == VX_READ_ONLY) + { + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (value_ptr) + { + memcpy(value_ptr, &value, size); + } + Osal::semPost(&lock); + // ownReadFromReference(&threshold); + status = VX_SUCCESS; + } + else if (usage == VX_WRITE_ONLY) + { + Osal::semWait(&lock); + vx_size size = sizeof(vx_pixel_value_t); + if (value_ptr) + { + memcpy(&value, value_ptr, size); + } + Osal::semPost(&lock); + // ownWroteToReference(&threshold); + status = VX_SUCCESS; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); + status = VX_ERROR_INVALID_PARAMETERS; } } else { - status = VX_ERROR_INVALID_REFERENCE; + VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); + status = VX_ERROR_NO_MEMORY; } - VX_PRINT(VX_ZONE_API, "return %d\n", status); - return status; -} - -static vx_bool vxIsValidThresholdFormat(vx_df_image format) -{ - vx_bool ret = vx_false_e; - if (format == VX_DF_IMAGE_U1 || - format == VX_DF_IMAGE_U8 || - format == VX_DF_IMAGE_S16 || - format == VX_DF_IMAGE_U16 || - format == VX_DF_IMAGE_S32 || - format == VX_DF_IMAGE_U32 ) +#ifdef OPENVX_USE_OPENCL_INTEROP + if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) { - ret = vx_true_e; + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)value_ptr_given, value_ptr, + 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); } - return ret; +#endif + + return status; } -static vx_bool vxIsValidThresholdFormatEx(vx_df_image format) +/*****************************************************************************/ +/* PUBLIC INTERFACE */ +/*****************************************************************************/ + +VX_API_ENTRY vx_threshold VX_API_CALL vxCreateThreshold(vx_context context, vx_enum thresh_type, + vx_enum data_type) { - vx_bool ret = vx_false_e; - if (format == VX_DF_IMAGE_RGB || - format == VX_DF_IMAGE_RGBX || - format == VX_DF_IMAGE_NV12 || - format == VX_DF_IMAGE_NV21 || - format == VX_DF_IMAGE_UYVY || - format == VX_DF_IMAGE_YUYV || - format == VX_DF_IMAGE_IYUV || - format == VX_DF_IMAGE_YUV4 ) + vx_threshold threshold = nullptr; + + if (Context::isValidContext(context) == vx_true_e) { - ret = vx_true_e; + if (Threshold::isValidThresholdDataType(data_type) == vx_true_e) + { + if (Threshold::isValidThresholdType(thresh_type) == vx_true_e) + { + threshold = (vx_threshold)Reference::createReference(context, VX_TYPE_THRESHOLD, + VX_EXTERNAL, context); + if (vxGetStatus((vx_reference)threshold) == VX_SUCCESS && + threshold->type == VX_TYPE_THRESHOLD) + { + threshold->thresh_type = thresh_type; + threshold->data_type = data_type; + switch (data_type) + { + case VX_TYPE_BOOL: + threshold->true_value.U1 = VX_U1_THRESHOLD_TRUE_VALUE; + threshold->false_value.U1 = VX_U1_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_INT8: + threshold->true_value.U8 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.U8 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_UINT8: + threshold->true_value.U8 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.U8 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_UINT16: + threshold->true_value.U16 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.U16 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_INT16: + threshold->true_value.S16 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.S16 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_INT32: + threshold->true_value.S32 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.S32 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + case VX_TYPE_UINT32: + threshold->true_value.U32 = VX_DEFAULT_THRESHOLD_TRUE_VALUE; + threshold->false_value.U32 = VX_DEFAULT_THRESHOLD_FALSE_VALUE; + break; + default: + break; + } + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid threshold type\n"); + vxAddLogEntry(context, VX_ERROR_INVALID_TYPE, "Invalid threshold type\n"); + threshold = (vx_threshold)vxGetErrorObject(context, VX_ERROR_INVALID_TYPE); + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid data type\n"); + vxAddLogEntry(context, VX_ERROR_INVALID_TYPE, "Invalid data type\n"); + threshold = (vx_threshold)vxGetErrorObject(context, VX_ERROR_INVALID_TYPE); + } } - return ret; + + return threshold; } VX_API_ENTRY vx_threshold VX_API_CALL vxCreateThresholdForImage(vx_context context, @@ -459,10 +670,8 @@ VX_API_ENTRY vx_threshold VX_API_CALL vxCreateThresholdForImage(vx_context conte threshold = (vx_threshold)vxGetErrorObject(context, VX_ERROR_INVALID_TYPE); } - if ( ((vxIsValidThresholdFormat (input_format) == vx_false_e) && - (vxIsValidThresholdFormatEx(input_format) == vx_false_e)) || - ((vxIsValidThresholdFormat (output_format) == vx_false_e) && - (vxIsValidThresholdFormatEx(output_format) == vx_false_e)) ) + if ((Threshold::isValidThresholdFormat(input_format) == vx_false_e) || + (Threshold::isValidThresholdFormat(output_format) == vx_false_e)) { VX_PRINT(VX_ZONE_ERROR, "Invalid input or output format\n"); vxAddLogEntry(context, VX_ERROR_INVALID_TYPE, "Invalid input or output format\n"); @@ -593,157 +802,265 @@ VX_API_ENTRY vx_threshold VX_API_CALL vxCreateVirtualThresholdForImage(vx_graph return threshold; } -VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdOutput(vx_threshold threshold, - vx_pixel_value_t * true_value_ptr, - vx_pixel_value_t * false_value_ptr, - vx_enum usage, - vx_enum user_mem_type) +VX_API_ENTRY vx_status VX_API_CALL vxSetThresholdAttribute(vx_threshold threshold, + vx_enum attribute, const void *ptr, + vx_size size) { - vx_status status = VX_ERROR_INVALID_REFERENCE; - - if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_false_e) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid reference for threshold\n"); - status = VX_ERROR_INVALID_REFERENCE; - return status; - } - - if (threshold->is_virtual == vx_true_e) + vx_status status = VX_SUCCESS; + if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_true_e) { - if (threshold->is_accessible == vx_false_e) + switch (attribute) { - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - return status; + case VX_THRESHOLD_THRESHOLD_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) + { + threshold->setBinaryValue(*(vx_int32 *)ptr); + // ownWroteToReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) + { + threshold->setBinaryValueUnion(*(vx_pixel_value_t *)ptr); + // ownWroteToReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_THRESHOLD_LOWER: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + threshold->setLowerBound(*(vx_int32 *)ptr); + // ownWroteToReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + threshold->setLowerBoundUnion(*(vx_pixel_value_t *)ptr); + // ownWroteToReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_THRESHOLD_UPPER: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + threshold->setUpperBound(*(vx_int32 *)ptr); + // ownWroteToReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + threshold->setUpperBoundUnion(*(vx_pixel_value_t *)ptr); + // ownWroteToReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_TRUE_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) + { + threshold->setTrueValue(*(vx_int32 *)ptr); + // ownWroteToReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) + { + threshold->setTrueValueUnion(*(vx_pixel_value_t *)ptr); + // ownWroteToReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_FALSE_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) + { + threshold->setFalseValue(*(vx_int32 *)ptr); + // ownWroteToReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) + { + threshold->setFalseValueUnion(*(vx_pixel_value_t *)ptr); + // ownWroteToReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } } - -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_pixel_value_t * true_value_ptr_given = true_value_ptr; - vx_pixel_value_t * false_value_ptr_given = false_value_ptr; - vx_enum user_mem_type_given = user_mem_type; - if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + else { - // get ptr from OpenCL buffer for HOST - if (true_value_ptr) - { - size_t size = 0; - cl_mem opencl_buf = (cl_mem)true_value_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdOutput: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - true_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer(threshold->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdOutput: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, true_value_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - } - if (false_value_ptr) - { - size_t size = 0; - cl_mem opencl_buf = (cl_mem)false_value_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdOutput: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - false_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer(threshold->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdOutput: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, false_value_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - } - user_mem_type = VX_MEMORY_TYPE_HOST; + status = VX_ERROR_INVALID_REFERENCE; } -#endif + VX_PRINT(VX_ZONE_API, "return %d\n", status); + return status; +} - if (VX_MEMORY_TYPE_HOST == user_mem_type) +VX_API_ENTRY vx_status VX_API_CALL vxQueryThreshold(vx_threshold threshold, vx_enum attribute, + void *ptr, vx_size size) +{ + vx_status status = VX_SUCCESS; + if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_true_e) { - if (usage == VX_READ_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (true_value_ptr) - { - memcpy(true_value_ptr, &threshold->true_value, size); - } - if (false_value_ptr) - { - memcpy(false_value_ptr, &threshold->false_value, size); - } - Osal::semPost(&threshold->lock); - // ownReadFromReference(&threshold); - status = VX_SUCCESS; - } - else if (usage == VX_WRITE_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (true_value_ptr) - { - memcpy(&threshold->true_value, true_value_ptr, size); - } - if (false_value_ptr) - { - memcpy(&threshold->false_value, false_value_ptr, size); - } - Osal::semPost(&threshold->lock); - // ownWroteToReference(&threshold); - status = VX_SUCCESS; - } - else + switch (attribute) { - VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); - status = VX_ERROR_INVALID_PARAMETERS; + case VX_THRESHOLD_THRESHOLD_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) + { + *(vx_int32 *)ptr = threshold->binaryValue(); + // ownReadFromReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_BINARY)) + { + *(vx_pixel_value_t *)ptr = threshold->binaryValueUnion(); + // ownReadFromReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_THRESHOLD_LOWER: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + *(vx_int32 *)ptr = threshold->lowerBound(); + // ownReadFromReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + *(vx_pixel_value_t *)ptr = threshold->lowerBoundUnion(); + // ownReadFromReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_THRESHOLD_UPPER: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + *(vx_int32 *)ptr = threshold->upperBound(); + // ownReadFromReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3) && + (threshold->thresh_type == VX_THRESHOLD_TYPE_RANGE)) + { + *(vx_pixel_value_t *)ptr = threshold->upperBoundUnion(); + // ownReadFromReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_TRUE_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) + { + *(vx_int32 *)ptr = threshold->trueValue(); + // ownReadFromReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) + { + *(vx_pixel_value_t *)ptr = threshold->trueValueUnion(); + // ownReadFromReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_FALSE_VALUE: + if (VX_CHECK_PARAM(ptr, size, vx_int32, 0x3)) + { + *(vx_int32 *)ptr = threshold->falseValue(); + // ownReadFromReference(&threshold); + } + else if (VX_CHECK_PARAM(ptr, size, vx_pixel_value_t, 0x3)) + { + *(vx_pixel_value_t *)ptr = threshold->falseValueUnion(); + // ownReadFromReference(&threshold); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_DATA_TYPE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_enum *)ptr = threshold->dataType(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_TYPE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_enum *)ptr = threshold->threshType(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_INPUT_FORMAT: + if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) + { + *(vx_df_image *)ptr = threshold->inputFormat(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_THRESHOLD_OUTPUT_FORMAT: + if (VX_CHECK_PARAM(ptr, size, vx_df_image, 0x3)) + { + *(vx_df_image *)ptr = threshold->outputFormat(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } } else { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); - status = VX_ERROR_NO_MEMORY; - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - if (true_value_ptr_given) - { - clEnqueueUnmapMemObject(threshold->context->opencl_command_queue, - (cl_mem)true_value_ptr_given, true_value_ptr, 0, nullptr, nullptr); - clFinish(threshold->context->opencl_command_queue); - } - if (false_value_ptr_given) - { - clEnqueueUnmapMemObject(threshold->context->opencl_command_queue, - (cl_mem)false_value_ptr_given, false_value_ptr, 0, nullptr, nullptr); - clFinish(threshold->context->opencl_command_queue); - } + status = VX_ERROR_INVALID_REFERENCE; } -#endif - + VX_PRINT(VX_ZONE_API, "return %d\n", status); return status; } - -VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdRange(vx_threshold threshold, - vx_pixel_value_t * lower_value_ptr, - vx_pixel_value_t * upper_value_ptr, - vx_enum usage, - vx_enum user_mem_type) +VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdOutput(vx_threshold threshold, + vx_pixel_value_t *true_value_ptr, + vx_pixel_value_t *false_value_ptr, + vx_enum usage, vx_enum user_mem_type) { vx_status status = VX_ERROR_INVALID_REFERENCE; @@ -754,142 +1071,29 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdRange(vx_threshold threshold, return status; } - if (threshold->is_virtual == vx_true_e) - { - if (threshold->is_accessible == vx_false_e) - { - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - return status; - } - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_pixel_value_t * lower_value_ptr_given = lower_value_ptr; - vx_pixel_value_t * upper_value_ptr_given = upper_value_ptr; - vx_enum user_mem_type_given = user_mem_type; - if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - // get ptr from OpenCL buffer for HOST - if (lower_value_ptr) - { - size_t size = 0; - cl_mem opencl_buf = (cl_mem)lower_value_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdRange: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - lower_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer(threshold->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, lower_value_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - } - if (upper_value_ptr) - { - size_t size = 0; - cl_mem opencl_buf = (cl_mem)upper_value_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdRange: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - upper_value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer(threshold->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdRange: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, upper_value_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - } - user_mem_type = VX_MEMORY_TYPE_HOST; - } -#endif + return threshold->copyOutput(true_value_ptr, false_value_ptr, usage, user_mem_type); +} - if (VX_MEMORY_TYPE_HOST == user_mem_type) - { - if (usage == VX_READ_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (lower_value_ptr) - { - memcpy(lower_value_ptr, &threshold->lower, size); - } - if (upper_value_ptr) - { - memcpy(upper_value_ptr, &threshold->upper, size); - } - Osal::semPost(&threshold->lock); - // ownReadFromReference(&threshold); - status = VX_SUCCESS; - } - else if (usage == VX_WRITE_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (lower_value_ptr) - { - memcpy(&threshold->lower, lower_value_ptr, size); - } - if (upper_value_ptr) - { - memcpy(&threshold->upper, upper_value_ptr, size); - } - Osal::semPost(&threshold->lock); - // ownWroteToReference(&threshold); - status = VX_SUCCESS; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); - status = VX_ERROR_NO_MEMORY; - } +VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdRange(vx_threshold threshold, + vx_pixel_value_t *lower_value_ptr, + vx_pixel_value_t *upper_value_ptr, + vx_enum usage, vx_enum user_mem_type) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + if (Reference::isValidReference(threshold, VX_TYPE_THRESHOLD) == vx_false_e) { - if (lower_value_ptr_given) - { - clEnqueueUnmapMemObject(threshold->context->opencl_command_queue, - (cl_mem)lower_value_ptr_given, lower_value_ptr, 0, nullptr, nullptr); - clFinish(threshold->context->opencl_command_queue); - } - if (upper_value_ptr_given) - { - clEnqueueUnmapMemObject(threshold->context->opencl_command_queue, - (cl_mem)upper_value_ptr_given, upper_value_ptr, 0, nullptr, nullptr); - clFinish(threshold->context->opencl_command_queue); - } + VX_PRINT(VX_ZONE_ERROR, "Invalid reference for threshold\n"); + status = VX_ERROR_INVALID_REFERENCE; + return status; } -#endif - return status; + return threshold->copyRange(lower_value_ptr, upper_value_ptr, usage, user_mem_type); } - VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdValue(vx_threshold threshold, - vx_pixel_value_t * value_ptr, - vx_enum usage, - vx_enum user_mem_type - ) + vx_pixel_value_t *value_ptr, vx_enum usage, + vx_enum user_mem_type) { vx_status status = VX_ERROR_INVALID_REFERENCE; @@ -900,90 +1104,22 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyThresholdValue(vx_threshold threshold, return status; } - if (threshold->is_virtual == vx_true_e) - { - if (threshold->is_accessible == vx_false_e) - { - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual threshold\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - return status; - } - } + return threshold->copyValue(value_ptr, usage, user_mem_type); +} -#ifdef OPENVX_USE_OPENCL_INTEROP - vx_pixel_value_t * value_ptr_given = value_ptr; - vx_enum user_mem_type_given = user_mem_type; - if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - // get ptr from OpenCL buffer for HOST - size_t size = 0; - cl_mem opencl_buf = (cl_mem)value_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdValue: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - value_ptr = (vx_pixel_value_t *)clEnqueueMapBuffer(threshold->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyThresholdValue: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, value_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_mem_type = VX_MEMORY_TYPE_HOST; - } -#endif +VX_API_ENTRY vx_status VX_API_CALL vxReleaseThreshold(vx_threshold *t) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; - if (VX_MEMORY_TYPE_HOST == user_mem_type) + if (nullptr != t) { - if (usage == VX_READ_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (value_ptr) - { - memcpy(value_ptr, &threshold->value, size); - } - Osal::semPost(&threshold->lock); - // ownReadFromReference(&threshold); - status = VX_SUCCESS; - } - else if (usage == VX_WRITE_ONLY) - { - Osal::semWait(&threshold->lock); - vx_size size = sizeof(vx_pixel_value_t); - if (value_ptr) - { - memcpy(&threshold->value, value_ptr, size); - } - Osal::semPost(&threshold->lock); - // ownWroteToReference(&threshold); - status = VX_SUCCESS; - } - else + vx_threshold ref = *t; + if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_THRESHOLD)) { - VX_PRINT(VX_ZONE_ERROR, "Wrong parameters for threshold\n"); - status = VX_ERROR_INVALID_PARAMETERS; + status = Reference::releaseReference((vx_reference *)t, VX_TYPE_THRESHOLD, VX_EXTERNAL, + nullptr); } } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to allocate threshold\n"); - status = VX_ERROR_NO_MEMORY; - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(threshold->context->opencl_command_queue, - (cl_mem)value_ptr_given, value_ptr, 0, nullptr, nullptr); - clFinish(threshold->context->opencl_command_queue); - } -#endif return status; } From 5b0dd4db738600327a3e834157cd1514100a3242 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 16:44:14 -0700 Subject: [PATCH 11/34] Reworked type pairs --- framework/src/vx_type_pairs.cpp | 36 +++++++++++++++++++-------------- include/VX/vx_types.h | 5 +++-- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/framework/src/vx_type_pairs.cpp b/framework/src/vx_type_pairs.cpp index 6e65d1f4..2df13ee0 100644 --- a/framework/src/vx_type_pairs.cpp +++ b/framework/src/vx_type_pairs.cpp @@ -16,8 +16,6 @@ #include "vx_internal.h" #include "vx_type_pairs.h" -#include "vx_type_pairs.h" - const vx_enum_string_t type_pairs[] = { {VX_STRINGERIZE(VX_TYPE_INVALID), 0}, /* scalar objects */ @@ -42,21 +40,29 @@ const vx_enum_string_t type_pairs[] = { {VX_STRINGERIZE(VX_TYPE_RECTANGLE), sizeof(vx_rectangle_t) * 2}, {VX_STRINGERIZE(VX_TYPE_KEYPOINT), sizeof(vx_keypoint_t) * 2}, /* data objects */ - {VX_STRINGERIZE(VX_TYPE_ARRAY), 0}, - {VX_STRINGERIZE(VX_TYPE_DISTRIBUTION), 0}, - {VX_STRINGERIZE(VX_TYPE_LUT), 0}, - {VX_STRINGERIZE(VX_TYPE_IMAGE), 0}, - {VX_STRINGERIZE(VX_TYPE_CONVOLUTION), 0}, - {VX_STRINGERIZE(VX_TYPE_THRESHOLD), 0}, - {VX_STRINGERIZE(VX_TYPE_TENSOR), 0}, - {VX_STRINGERIZE(VX_TYPE_MATRIX), 0}, - {VX_STRINGERIZE(VX_TYPE_OBJECT_ARRAY), 0}, - {VX_STRINGERIZE(VX_TYPE_SCALAR), 0}, - {VX_STRINGERIZE(VX_TYPE_PYRAMID), 0}, - {VX_STRINGERIZE(VX_TYPE_REMAP), 0}, + {VX_STRINGERIZE(VX_TYPE_ARRAY), sizeof(Array)}, + {VX_STRINGERIZE(VX_TYPE_DISTRIBUTION), sizeof(Distribution)}, + {VX_STRINGERIZE(VX_TYPE_LUT), sizeof(Lut)}, + {VX_STRINGERIZE(VX_TYPE_IMAGE), sizeof(Image)}, + {VX_STRINGERIZE(VX_TYPE_CONVOLUTION), sizeof(Convolution)}, + {VX_STRINGERIZE(VX_TYPE_THRESHOLD), sizeof(Threshold)}, + {VX_STRINGERIZE(VX_TYPE_TENSOR), sizeof(Tensor)}, + {VX_STRINGERIZE(VX_TYPE_MATRIX), sizeof(Matrix)}, + {VX_STRINGERIZE(VX_TYPE_OBJECT_ARRAY), sizeof(ObjectArray)}, + {VX_STRINGERIZE(VX_TYPE_SCALAR), sizeof(Scalar)}, + {VX_STRINGERIZE(VX_TYPE_PYRAMID), sizeof(Pyramid)}, + {VX_STRINGERIZE(VX_TYPE_REMAP), sizeof(Remap)}, #ifdef OPENVX_KHR_XML - {VX_STRINGERIZE(VX_TYPE_IMPORT), 0}, + {VX_STRINGERIZE(VX_TYPE_IMPORT), sizeof(Import)}, #endif + /* framework objects */ + {VX_STRINGERIZE(VX_TYPE_CONTEXT), sizeof(Context)}, + {VX_STRINGERIZE(VX_TYPE_GRAPH), sizeof(Graph)}, + {VX_STRINGERIZE(VX_TYPE_NODE), sizeof(Node)}, + {VX_STRINGERIZE(VX_TYPE_KERNEL), sizeof(Kernel)}, + {VX_STRINGERIZE(VX_TYPE_TARGET), sizeof(Target)}, + {VX_STRINGERIZE(VX_TYPE_REFERENCE), sizeof(Reference)}, + {VX_STRINGERIZE(VX_TYPE_PARAMETER), sizeof(Parameter)}, }; #if defined(EXPERIMENTAL_USE_DOT) || defined(OPENVX_USE_XML) diff --git a/include/VX/vx_types.h b/include/VX/vx_types.h index 5b6d8904..d7e1460d 100644 --- a/include/VX/vx_types.h +++ b/include/VX/vx_types.h @@ -279,9 +279,10 @@ typedef struct Delay* vx_delay; */ #ifdef __cplusplus class Array; -using vx_lut = Array*; +using Lut = Array; +using vx_lut = Lut *; #else -typedef struct Array* vx_lut; +typedef struct Lut* vx_lut; #endif /*! \brief The Distribution object. This has a user-defined number of bins over From 77876c4398af41cbc991f457be2b009a980e4193 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 17:19:43 -0700 Subject: [PATCH 12/34] Reworked user data object --- framework/include/vx_user_data_object.h | 55 ++++ framework/src/vx_user_data_object.cpp | 396 +++++++++++++----------- 2 files changed, 275 insertions(+), 176 deletions(-) diff --git a/framework/include/vx_user_data_object.h b/framework/include/vx_user_data_object.h index a08e27ef..d11ef68d 100644 --- a/framework/include/vx_user_data_object.h +++ b/framework/include/vx_user_data_object.h @@ -43,6 +43,22 @@ class UserDataObject : public Reference */ ~UserDataObject(); + /** + * @brief Get the type name of the user data object + * + * @return vx_char* The type name + * @ingroup group_int_user_data_object + */ + const vx_char *typeName() const; + + /** + * @brief Get the size of the user data object + * + * @return vx_size The size in bytes + * @ingroup group_int_user_data_object + */ + vx_size objSize() const; + /** * @brief Allocate user data object * @@ -51,6 +67,45 @@ class UserDataObject : public Reference */ vx_bool allocateUserDataObject(); + /** + * @brief Copy data to/from user memory + * + * @param offset The offset in bytes + * @param size The size in bytes + * @param user_ptr The pointer to the user memory + * @param usage The usage of the memory (read/write) + * @param user_mem_type The type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_user_data_object + */ + vx_status copy(vx_size offset, vx_size size, void *user_ptr, vx_enum usage, + vx_enum user_mem_type); + + /** + * @brief Map the user data object for access + * + * @param offset The offset in bytes + * @param size The size in bytes + * @param map_id The map ID to be used + * @param ptr Pointer to the mapped memory + * @param usage Memory usage type (read/write) + * @param mem_type Memory type (host, opencl, etc.) + * @param flags Additional flags for mapping + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_user_data_object + */ + vx_status map(vx_size offset, vx_size size, vx_map_id *map_id, void **ptr, vx_enum usage, + vx_enum mem_type, vx_uint32 flags); + + /** + * @brief Unmap the user data object from access + * + * @param map_id The map ID to be used + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_user_data_object + */ + vx_status unmap(vx_map_id map_id); + /*! \brief Memory layout */ vx_memory_t memory; /*! \brief size of buffer in bytes */ diff --git a/framework/src/vx_user_data_object.cpp b/framework/src/vx_user_data_object.cpp index c2c9702f..8b34e4d0 100644 --- a/framework/src/vx_user_data_object.cpp +++ b/framework/src/vx_user_data_object.cpp @@ -40,6 +40,16 @@ UserDataObject::~UserDataObject() Memory::freeMemory(context, &memory); } +const vx_char *UserDataObject::typeName() const +{ + return type_name; +} + +vx_size UserDataObject::objSize() const +{ + return size; +} + vx_bool UserDataObject::allocateUserDataObject() { vx_bool res = vx_false_e; @@ -50,6 +60,193 @@ vx_bool UserDataObject::allocateUserDataObject() return res; } +vx_status UserDataObject::copy(vx_size offset, vx_size size, void *user_ptr, vx_enum usage, + vx_enum user_mem_type) +{ + vx_status status = (vx_status)VX_SUCCESS; + vx_uint8 *start_ptr; + + if ((vx_enum)VX_MEMORY_TYPE_HOST != user_mem_type) + { + VX_PRINT(VX_ZONE_ERROR, "User mem type is not equal to VX_MEMORY_TYPE_HOST\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + + /* Memory still not allocated */ + if (((vx_enum)VX_READ_ONLY == usage) && + ((uint64_t)(uintptr_t)nullptr == (uintptr_t)memory.ptrs[0])) + { + VX_PRINT(VX_ZONE_ERROR, "Memory is not allocated\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + + if (nullptr == user_ptr) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid nullptr pointer\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + + if ((size < 1U) || ((offset + size) > this->size)) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid offset or size parameter\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + + if ((vx_status)VX_SUCCESS == status) + { + if (allocateUserDataObject() == vx_false_e) + { + return VX_ERROR_NO_MEMORY; + } + } + + if (status == (vx_status)VX_SUCCESS) + { + /* Get the offset to the free memory */ + start_ptr = (vx_uint8 *)&memory.ptrs[0][offset]; + + /* Copy from internal object to user memory */ + if ((vx_enum)VX_READ_ONLY == usage) + { + memcpy(user_ptr, start_ptr, size); + } + else /* Copy from user memory to internal object */ + { + memcpy(start_ptr, user_ptr, size); + } + } + + return status; +} + +vx_status UserDataObject::map(vx_size offset, vx_size size, vx_map_id *map_id, void **ptr, + vx_enum usage, vx_enum mem_type, vx_uint32 flags) +{ + vx_status status = (vx_status)VX_SUCCESS; + vx_memory_map_extra extra; + extra.array_data.start = offset; + extra.array_data.end = offset + size; + vx_uint8 *buf = nullptr; + + if (status == (vx_status)VX_SUCCESS) + { + if (ptr == nullptr) + { + VX_PRINT(VX_ZONE_ERROR, "User pointer is nullptr\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + if (map_id == nullptr) + { + VX_PRINT(VX_ZONE_ERROR, "Map ID is nullptr\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + } + + if (status == (vx_status)VX_SUCCESS) + { + if (((offset + size) > this->size)) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid offset or size parameter\n"); + status = (vx_status)VX_ERROR_INVALID_PARAMETERS; + } + } + + if ((vx_status)VX_SUCCESS == status) + { + if (allocateUserDataObject() == vx_false_e) + { + status = VX_ERROR_NO_MEMORY; + } + } + + if ((vx_status)VX_SUCCESS == status) + { + if (context->memoryMap((vx_reference)this, size, usage, mem_type, flags, &extra, + (void **)&buf, map_id) == vx_true_e) + { + if (VX_READ_ONLY == usage || VX_READ_AND_WRITE == usage) + { + if (Osal::semWait(&memory.locks[0]) == vx_true_e) + { + vx_uint8 *pSrc = (vx_uint8 *)&memory.ptrs[0][offset]; + vx_uint8 *pDst = (vx_uint8 *)buf; + memcpy(pDst, pSrc, size); + + *ptr = buf; + incrementReference(VX_EXTERNAL); + Osal::semPost(&memory.locks[0]); + + status = VX_SUCCESS; + } + else + { + status = VX_ERROR_NO_RESOURCES; + } + } + else + { + /* write only mode */ + *ptr = buf; + incrementReference(VX_EXTERNAL); + status = VX_SUCCESS; + } + } + else + { + status = VX_FAILURE; + } + } + + return status; +} + +vx_status UserDataObject::unmap(vx_map_id map_id) +{ + vx_status status = (vx_status)VX_SUCCESS; + + vx_memory_map_t *map = &context->memory_maps[map_id]; + if (map->used && map->ref == (vx_reference)this) + { + vx_size start = map->extra.array_data.start; + vx_size end = map->extra.array_data.end; + if (VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) + { + if (Osal::semWait(&memory.locks[0]) == vx_true_e) + { + vx_uint32 offset = (vx_uint32)start; + vx_uint8 *pSrc = (vx_uint8 *)map->ptr; + vx_uint8 *pDst = (vx_uint8 *)&memory.ptrs[0][offset]; + vx_size size = (end - start); + memcpy(pDst, pSrc, size); + + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); + Osal::semPost(&memory.locks[0]); + status = VX_SUCCESS; + } + else + { + // Log the error if semaphore wait fails + VX_PRINT(VX_ZONE_ERROR, "Failed to acquire semaphore lock\n"); + status = VX_ERROR_NO_RESOURCES; + } + } + else + { + /* read only mode */ + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); + status = VX_SUCCESS; + } + } + else + { + status = VX_FAILURE; + } + + return status; +} + /*****************************************************************************/ /* PUBLIC INTERFACE */ /*****************************************************************************/ @@ -120,24 +317,8 @@ VX_API_ENTRY vx_user_data_object VX_API_CALL vxCreateUserDataObject( return (user_data_object); } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseUserDataObject(vx_user_data_object *user_data_object) -{ - vx_status status = VX_ERROR_INVALID_REFERENCE; - - if (nullptr != user_data_object) - { - vx_user_data_object obj = *user_data_object; - if (vx_true_e == Reference::isValidReference(obj, VX_TYPE_USER_DATA_OBJECT)) - { - status = Reference::releaseReference((vx_reference*)user_data_object, VX_TYPE_USER_DATA_OBJECT, VX_EXTERNAL, nullptr); - } - } - - return status; -} - -VX_API_ENTRY vx_status VX_API_CALL vxQueryUserDataObject ( - vx_user_data_object user_data_object, vx_enum attribute, void *ptr, vx_size size) +VX_API_ENTRY vx_status VX_API_CALL vxQueryUserDataObject(vx_user_data_object user_data_object, + vx_enum attribute, void *ptr, vx_size size) { vx_status status = (vx_status)VX_SUCCESS; @@ -154,7 +335,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryUserDataObject ( case (vx_enum)VX_USER_DATA_OBJECT_NAME: if ((ptr != nullptr) && ((vx_enum)size >= VX_MAX_REFERENCE_NAME)) { - strncpy(reinterpret_cast(ptr), user_data_object->type_name, VX_MAX_REFERENCE_NAME); + strncpy(reinterpret_cast(ptr), user_data_object->typeName(), + VX_MAX_REFERENCE_NAME); } else { @@ -165,7 +347,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryUserDataObject ( case (vx_enum)VX_USER_DATA_OBJECT_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3U)) { - *(vx_size *)ptr = user_data_object->size; + *(vx_size *)ptr = user_data_object->objSize(); } else { @@ -187,64 +369,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxCopyUserDataObject(vx_user_data_object user vx_size offset, vx_size size, void *user_ptr, vx_enum usage, vx_enum user_mem_type) { vx_status status = (vx_status)VX_SUCCESS; - vx_uint8 *start_ptr; if ((Reference::isValidReference(reinterpret_cast(user_data_object), VX_TYPE_USER_DATA_OBJECT) == (vx_bool)vx_false_e)) { VX_PRINT(VX_ZONE_ERROR, "Invalid user data object reference\n"); status = (vx_status)VX_ERROR_INVALID_REFERENCE; } - else - { - if ((vx_enum)VX_MEMORY_TYPE_HOST != user_mem_type) - { - VX_PRINT(VX_ZONE_ERROR, "User mem type is not equal to VX_MEMORY_TYPE_HOST\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - /* Memory still not allocated */ - if (((vx_enum)VX_READ_ONLY == usage) && - ((uint64_t)(uintptr_t)nullptr == (uintptr_t)user_data_object->memory.ptrs[0])) - { - VX_PRINT(VX_ZONE_ERROR, "Memory is not allocated\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - - if (nullptr == user_ptr) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid nullptr pointer\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - - if ((size < 1U) || ((offset + size) > user_data_object->size)) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid offset or size parameter\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - } - - if ((vx_status)VX_SUCCESS == status) + if (VX_SUCCESS == status) { - if (user_data_object->allocateUserDataObject() == vx_false_e) - { - return VX_ERROR_NO_MEMORY; - } - } - - if (status == (vx_status)VX_SUCCESS) - { - /* Get the offset to the free memory */ - start_ptr = (vx_uint8 *)&user_data_object->memory.ptrs[0][offset]; - - /* Copy from internal object to user memory */ - if ((vx_enum)VX_READ_ONLY == usage) - { - memcpy(user_ptr, start_ptr, size); - } - else /* Copy from user memory to internal object */ - { - memcpy(start_ptr, user_ptr, size); - } + status = user_data_object->copy(offset, size, user_ptr, usage, user_mem_type); } return (status); @@ -267,77 +401,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapUserDataObject( status = (vx_status)VX_ERROR_INVALID_REFERENCE; } - if(status == (vx_status)VX_SUCCESS) - { - if (ptr == nullptr) - { - VX_PRINT(VX_ZONE_ERROR, "User pointer is nullptr\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - if (map_id == nullptr) - { - VX_PRINT(VX_ZONE_ERROR, "Map ID is nullptr\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - } - - if(status == (vx_status)VX_SUCCESS) - { - - if (((offset + size) > user_data_object->size)) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid offset or size parameter\n"); - status = (vx_status)VX_ERROR_INVALID_PARAMETERS; - } - } - if ((vx_status)VX_SUCCESS == status) { - if (user_data_object->allocateUserDataObject() == vx_false_e) - { - status = VX_ERROR_NO_MEMORY; - } - } - - if ((vx_status)VX_SUCCESS == status) - { - vx_memory_map_extra extra; - extra.array_data.start = offset; - extra.array_data.end = offset + size; - vx_uint8 *buf = nullptr; - if (user_data_object->context->memoryMap((vx_reference)user_data_object, size, usage, mem_type, flags, &extra, (void **)&buf, map_id) == vx_true_e) - { - if (VX_READ_ONLY == usage || VX_READ_AND_WRITE == usage) - { - if (Osal::semWait(&user_data_object->memory.locks[0]) == vx_true_e) - { - vx_uint8 *pSrc = (vx_uint8 *)&user_data_object->memory.ptrs[0][offset]; - vx_uint8 *pDst = (vx_uint8 *)buf; - memcpy(pDst, pSrc, size); - - *ptr = buf; - user_data_object->incrementReference(VX_EXTERNAL); - Osal::semPost(&user_data_object->memory.locks[0]); - - status = VX_SUCCESS; - } - else - { - status = VX_ERROR_NO_RESOURCES; - } - } - else - { - /* write only mode */ - *ptr = buf; - user_data_object->incrementReference(VX_EXTERNAL); - status = VX_SUCCESS; - } - } - else - { - status = VX_FAILURE; - } + status = user_data_object->map(offset, size, map_id, ptr, usage, mem_type, flags); } return (status); @@ -355,45 +421,23 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnmapUserDataObject(vx_user_data_object use if(status == (vx_status)VX_SUCCESS) { - vx_context context = user_data_object->context; - vx_memory_map_t* map = &context->memory_maps[map_id]; - if (map->used && map->ref == (vx_reference)user_data_object) - { - vx_size start = map->extra.array_data.start; - vx_size end = map->extra.array_data.end; - if (VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) - { - if (Osal::semWait(&user_data_object->memory.locks[0]) == vx_true_e) - { - vx_uint32 offset = (vx_uint32)start; - vx_uint8 *pSrc = (vx_uint8 *)map->ptr; - vx_uint8 *pDst = (vx_uint8 *)&user_data_object->memory.ptrs[0][offset]; - vx_size size = (end - start); - memcpy(pDst, pSrc, size); + status = user_data_object->unmap(map_id); + } - context->memoryUnmap((vx_uint32)map_id); - user_data_object->decrementReference(VX_EXTERNAL); - Osal::semPost(&user_data_object->memory.locks[0]); - status = VX_SUCCESS; - } - else - { - // Log the error if semaphore wait fails - VX_PRINT(VX_ZONE_ERROR, "Failed to acquire semaphore lock\n"); - status = VX_ERROR_NO_RESOURCES; - } - } - else - { - /* read only mode */ - user_data_object->context->memoryUnmap((vx_uint32)map_id); - user_data_object->decrementReference(VX_EXTERNAL); - status = VX_SUCCESS; - } - } - else + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseUserDataObject(vx_user_data_object *user_data_object) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != user_data_object) + { + vx_user_data_object obj = *user_data_object; + if (vx_true_e == Reference::isValidReference(obj, VX_TYPE_USER_DATA_OBJECT)) { - status = VX_FAILURE; + status = Reference::releaseReference((vx_reference *)user_data_object, + VX_TYPE_USER_DATA_OBJECT, VX_EXTERNAL, nullptr); } } From aee6e99e2f85d5123762fd3e7ca8e1d98204318b Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 17:48:08 -0700 Subject: [PATCH 13/34] Reworked tensor --- framework/include/vx_tensor.h | 84 +++++ framework/src/vx_tensor.cpp | 628 +++++++++++++++++++--------------- 2 files changed, 436 insertions(+), 276 deletions(-) diff --git a/framework/include/vx_tensor.h b/framework/include/vx_tensor.h index e3b32aa6..0863d128 100644 --- a/framework/include/vx_tensor.h +++ b/framework/include/vx_tensor.h @@ -111,6 +111,90 @@ class Tensor : public Reference const vx_size * tensor_stride, const vx_size * patch_stride, vx_size number_of_dimensions, vx_size * tensor_pos, vx_size * patch_pos); + /** + * @brief Get the dimensions of the tensor + * @return const vx_size* The dimensions of the tensor + * @ingroup group_int_tensor + */ + const vx_size *dims() const; + + /** + * @brief Get the number of dimensions in the tensor + * @return vx_size The number of dimensions + * @ingroup group_int_tensor + */ + vx_size numDims() const; + + /** + * @brief Get the data type of the tensor + * @return vx_enum The data type of the tensor + * @ingroup group_int_tensor + */ + vx_enum dataType() const; + + /** + * @brief Get the fixed point position of the tensor + * @return vx_int8 The fixed point position of the tensor + * @ingroup group_int_tensor + */ + vx_int8 fixedPointPosition() const; + + /** + * @brief Get the strides of the tensor + * @return const vx_size* The strides of the tensor + * @ingroup group_int_tensor + */ + const vx_size *strides() const; + + /** + * @brief Get the size of the tensor in bytes + * @return vx_size The size of the tensor in bytes + * @ingroup group_int_tensor + */ + vx_size size() const; + + /** + * @brief Copy a patch of the tensor to/from user memory + * + * @param number_of_dimensions The number of dimensions in the patch + * @param view_start The start indices of the patch + * @param view_end The end indices of the patch + * @param user_stride The stride in user memory + * @param user_ptr The pointer to user memory + * @param usage The usage of the memory (read/write) + * @param user_memory_type The type of user memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_tensor + */ + vx_status copyPatch(vx_size number_of_dimensions, const vx_size *view_start, + const vx_size *view_end, const vx_size *user_stride, void *user_ptr, + vx_enum usage, vx_enum user_memory_type); + + /** + * @brief Map a patch of the tensor to user memory + * @param number_of_dimensions The number of dimensions in the patch + * @param view_start The start indices of the patch + * @param view_end The end indices of the patch + * @param map_id The map ID for the patch + * @param stride The stride in the patch + * @param ptr The pointer to the mapped memory + * @param usage The usage of the memory (read/write) + * @param mem_type The type of memory (host, device, etc.) + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_tensor + */ + vx_status mapPatch(vx_size number_of_dimensions, const vx_size *view_start, + const vx_size *view_end, vx_map_id *map_id, vx_size *stride, void **ptr, + vx_enum usage, vx_enum mem_type); + + /** + * @brief Unmap a patch of the tensor + * @param map_id The map ID for the patch + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_tensor + */ + vx_status unmapPatch(vx_map_id map_id); + /** * @brief Function to destroy tensor obj * @ingroup group_int_tensor diff --git a/framework/src/vx_tensor.cpp b/framework/src/vx_tensor.cpp index e5ecf64d..fd5c4bd6 100644 --- a/framework/src/vx_tensor.cpp +++ b/framework/src/vx_tensor.cpp @@ -130,6 +130,317 @@ void Tensor::computePositionsFromIndex(vx_size index, const vx_size * start, con } } +const vx_size *Tensor::dims() const +{ + return dimensions; +} + +vx_size Tensor::numDims() const +{ + return number_of_dimensions; +} + +vx_enum Tensor::dataType() const +{ + return data_type; +} + +vx_int8 Tensor::fixedPointPosition() const +{ + return fixed_point_position; +} + +const vx_size *Tensor::strides() const +{ + return stride; +} + +vx_size Tensor::size() const +{ + vx_size total_size = Reference::sizeOfType(data_type); + for (vx_uint32 i = 0; i < number_of_dimensions; i++) + { + total_size *= dimensions[i]; + } + return total_size; +} + +vx_status Tensor::copyPatch(vx_size number_of_dimensions, const vx_size *view_start, + const vx_size *view_end, const vx_size *user_stride, void *user_ptr, + vx_enum usage, vx_enum user_memory_type) +{ + vx_status status = VX_SUCCESS; + (void)user_memory_type; + + /* bad parameters */ + if ((view_start == nullptr) || (view_end == nullptr) || (user_stride == nullptr) || + (user_ptr == nullptr)) + { + status = VX_ERROR_INVALID_PARAMETERS; + } + + /* determine if virtual before checking for memory */ + if (VX_SUCCESS == status && is_virtual == vx_true_e && is_accessible == vx_false_e) + { + /* User tried to access a "virtual" tensor. */ + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual tensor\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + } + + if (VX_SUCCESS == status && addr == nullptr) + { + if ( // usage != VX_WRITE_ONLY || + allocateTensorMemory() == nullptr) + { + VX_PRINT(VX_ZONE_ERROR, "Tensor memory was not allocated!\n"); + status = VX_ERROR_NOT_ALLOCATED; + } + } + + if ((VX_SUCCESS == status) && + ((this->number_of_dimensions < number_of_dimensions) || (number_of_dimensions == 0))) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid number of patch dimensions\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + if (VX_SUCCESS == status && + Tensor::checkSizes(dimensions, view_start, view_end, number_of_dimensions) != 0) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid view\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + + if (VX_SUCCESS == status) + { +#ifdef OPENVX_USE_OPENCL_INTEROP + void *user_ptr_given = user_ptr; + vx_enum user_memory_type_given = user_memory_type; + if (user_memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + /* get user_ptr from OpenCL buffer for HOST */ + size_t size = 0; + cl_mem opencl_buf = (cl_mem)user_ptr; + cl_int cerr = + clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyTensorPatch: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + user_ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, + "OPENCL: vxCopyTensorPatch: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, user_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + user_memory_type = VX_MEMORY_TYPE_HOST; + } +#endif + + // element_size = Reference::sizeOfType(data_type); + vx_uint8 *user_curr_ptr = (vx_uint8 *)user_ptr; + vx_uint8 *tensor_ptr = (vx_uint8 *)addr; + vx_size patch_size = Tensor::computePatchSize(view_start, view_end, number_of_dimensions); + for (vx_size i = 0; i < patch_size; i++) + { + vx_size patch_pos = 0; + vx_size tensor_pos = 0; + Tensor::computePositionsFromIndex(i, view_start, view_end, stride, user_stride, + number_of_dimensions, &tensor_pos, &patch_pos); + if (usage == VX_READ_ONLY) + memcpy(user_curr_ptr + patch_pos, tensor_ptr + tensor_pos, stride[0]); + else + memcpy(tensor_ptr + tensor_pos, user_curr_ptr + patch_pos, stride[0]); + } + status = VX_SUCCESS; + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (user_memory_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)user_ptr_given, user_ptr, + 0, nullptr, nullptr); + clFinish(context->opencl_command_queue); + } +#endif + } + + VX_PRINT(VX_ZONE_API, "returned %d\n", status); + return status; +} + +vx_status Tensor::mapPatch(vx_size number_of_dims, const vx_size *view_start, + const vx_size *view_end, vx_map_id *map_id, vx_size *stride, void **ptr, + vx_enum usage, vx_enum mem_type) +{ + vx_status status = VX_SUCCESS; + vx_uint8 *buf = nullptr; + vx_size size; + vx_memory_map_extra extra; + + /* bad parameters */ + if ((view_start == nullptr) || (view_end == nullptr) || (map_id == nullptr) || + (ptr == nullptr) || (stride == nullptr)) + { + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; + } + + /* determine if virtual before checking for memory */ + if (is_virtual == vx_true_e) + { + if (is_accessible == vx_false_e) + { + /* User tried to access a "virtual" tensor. */ + VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual tensor\n"); + status = VX_ERROR_OPTIMIZED_AWAY; + goto exit; + } + } + if (addr == nullptr) + { + if ( // usage != VX_WRITE_ONLY || + allocateTensorMemory() == nullptr) + { + VX_PRINT(VX_ZONE_ERROR, "Tensor memory was allocated failed!\n"); + status = VX_ERROR_NO_MEMORY; + goto exit; + } + } + + if (number_of_dimensions < number_of_dims || number_of_dims == 0) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid number of patch dimensions\n"); + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; + } + if (Tensor::checkSizes(dimensions, view_start, view_end, number_of_dims) != 0) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid view\n"); + status = VX_ERROR_INVALID_PARAMETERS; + goto exit; + } + + stride[0] = Reference::sizeOfType(data_type); + for (vx_uint32 i = 1; i < number_of_dims; i++) + { + stride[i] = stride[i - 1] * (view_end[i] - view_start[i]); + } + // vx_map_id * map_id, vx_size * stride, void ** ptr + size = Tensor::computePatchSize(view_start, view_end, number_of_dims); + + memcpy(extra.tensor_data.start, view_start, sizeof(vx_size) * number_of_dims); + memcpy(extra.tensor_data.end, view_end, sizeof(vx_size) * number_of_dims); + memcpy(extra.tensor_data.stride, stride, sizeof(vx_size) * number_of_dims); + extra.tensor_data.number_of_dims = number_of_dims; + + if (VX_MEMORY_TYPE_HOST == mem_type && + vx_true_e == context->memoryMap((vx_reference)this, 0, usage, mem_type, 0, (void *)&extra, + (void **)&buf, map_id)) + { + *ptr = addr; + + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; + } + else if (vx_true_e == context->memoryMap((vx_reference)this, size, usage, mem_type, 0, + (void *)&extra, (void **)&buf, map_id)) + { + vx_uint8 *user_curr_ptr = buf; + vx_uint8 *tensor_ptr = (vx_uint8 *)addr; + if (usage == VX_READ_ONLY || usage == VX_READ_AND_WRITE) + { + for (vx_size i = 0; i < size; i++) + { + vx_size patch_pos = 0; + vx_size tensor_pos = 0; + Tensor::computePositionsFromIndex(i, view_start, view_end, this->stride, stride, + number_of_dims, &tensor_pos, &patch_pos); + memcpy(user_curr_ptr + patch_pos, tensor_ptr + tensor_pos, this->stride[0]); + } + + // ownReadFromReference(&base); + } + *ptr = buf; + incrementReference(VX_EXTERNAL); + + status = VX_SUCCESS; + } + +exit: + VX_PRINT(VX_ZONE_API, "returned %d\n", status); + return status; +} + +vx_status Tensor::unmapPatch(vx_map_id map_id) +{ + vx_status status = VX_SUCCESS; + + /* bad parameters */ + if (context->findMemoryMap((vx_reference)this, map_id) != vx_true_e) + { + status = VX_ERROR_INVALID_PARAMETERS; + VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to unmap tensor patch\n"); + return status; + } + + { + vx_memory_map_t *map = &context->memory_maps[map_id]; + + if (map->used && map->ref == (vx_reference)this) + { + /* commit changes for write access */ + if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && + nullptr != map->ptr) + { + if (vx_true_e == Osal::semWait(&lock)) + { + vx_uint32 size = Tensor::computePatchSize( + map->extra.tensor_data.start, map->extra.tensor_data.end, + map->extra.tensor_data.number_of_dims); + vx_uint8 *pSrc = (vx_uint8 *)map->ptr; + vx_uint8 *pDst = (vx_uint8 *)addr; + + for (vx_size i = 0; i < size; i++) + { + vx_size patch_pos = 0; + vx_size tensor_pos = 0; + Tensor::computePositionsFromIndex( + i, map->extra.tensor_data.start, map->extra.tensor_data.end, stride, + map->extra.tensor_data.stride, map->extra.tensor_data.number_of_dims, + &tensor_pos, &patch_pos); + memcpy(pDst + patch_pos, pSrc + tensor_pos, stride[0]); + } + + Osal::semPost(&lock); + } + else + { + status = VX_FAILURE; + VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); + goto exit; + } + } + + /* freeing mapping buffer */ + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); + status = VX_SUCCESS; + } + else + status = VX_FAILURE; + } + +exit: + VX_PRINT(VX_ZONE_API, "return %d\n", status); + return status; +} + void Tensor::destruct() { /* if it's not imported and does not have a parent, free it */ @@ -514,22 +825,6 @@ VX_API_ENTRY vx_tensor VX_API_CALL vxCreateVirtualTensor( return tensor; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseTensor(vx_tensor* tensor) -{ - vx_status status = VX_FAILURE; - - if (nullptr != tensor) - { - vx_tensor this_tensor = *tensor; - if (vx_true_e == Reference::isValidReference(this_tensor, VX_TYPE_TENSOR)) - { - status = Reference::releaseReference((vx_reference*)tensor, VX_TYPE_TENSOR, VX_EXTERNAL, nullptr); - } - } - - return status; -} - VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -540,7 +835,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attri case VX_TENSOR_NUMBER_OF_DIMS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = tensor->number_of_dimensions; + *(vx_size *)ptr = tensor->numDims(); } else { @@ -550,7 +845,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attri case VX_TENSOR_DIMS: if (size >= (sizeof(vx_size)*tensor->number_of_dimensions) && ((vx_size)ptr & 0x3) == 0) { - memcpy(ptr, tensor->dimensions, sizeof(vx_size)*tensor->number_of_dimensions); + memcpy(ptr, tensor->dims(), sizeof(vx_size) * tensor->numDims()); } else { @@ -560,19 +855,19 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attri case VX_TENSOR_DATA_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = tensor->data_type; + *(vx_enum *)ptr = tensor->dataType(); } break; case VX_TENSOR_FIXED_POINT_POSITION: if (VX_CHECK_PARAM(ptr, size, vx_int8, 0x0)) //?? { - *(vx_int8 *)ptr = tensor->fixed_point_position; + *(vx_int8 *)ptr = tensor->fixedPointPosition(); } break; case VX_TENSOR_STRIDE: if (size >= (sizeof(vx_size)*tensor->number_of_dimensions) && ((vx_size)ptr & 0x3) == 0) { - memcpy(ptr, tensor->stride, sizeof(vx_size)*tensor->number_of_dimensions); + memcpy(ptr, tensor->strides(), sizeof(vx_size) * tensor->numDims()); } else { @@ -582,12 +877,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attri case VX_TENSOR_TOTAL_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - vx_size total_size = Reference::sizeOfType(tensor->data_type); - for (vx_uint32 i = 0; i < tensor->number_of_dimensions; i++) - { - total_size *= tensor->dimensions[i]; - } - *(vx_size *)ptr = total_size; + *(vx_size *)ptr = tensor->size(); } else { @@ -607,298 +897,84 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryTensor(vx_tensor tensor, vx_enum attri return status; } -VX_API_ENTRY vx_status VX_API_CALL vxMapTensorPatch(vx_tensor tensor, vx_size number_of_dims, - const vx_size * view_start, const vx_size * view_end, - vx_map_id * map_id, vx_size * stride, void ** ptr, vx_enum usage, vx_enum mem_type) +VX_API_ENTRY vx_status VX_API_CALL vxCopyTensorPatch(vx_tensor tensor, vx_size number_of_dimensions, + const vx_size *view_start, + const vx_size *view_end, + const vx_size *user_stride, void *user_ptr, + vx_enum usage, vx_enum user_memory_type) { - vx_status status = VX_FAILURE; - vx_uint8 *buf = nullptr; - vx_size size; - vx_memory_map_extra extra; - - /* bad parameters */ - if ((view_start == nullptr) || (view_end == nullptr) || (map_id == nullptr) || (ptr == nullptr) || - (stride == nullptr)) - { - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; - } + vx_status status = VX_SUCCESS; /* bad references */ if (Tensor::isValidTensor(tensor) == vx_false_e) { status = VX_ERROR_INVALID_REFERENCE; - goto exit; - } - - /* determine if virtual before checking for memory */ - if (tensor->is_virtual == vx_true_e) - { - if (tensor->is_accessible == vx_false_e) - { - /* User tried to access a "virtual" tensor. */ - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual tensor\n"); - status = VX_ERROR_OPTIMIZED_AWAY; - goto exit; - } - } - if (tensor->addr == nullptr) - { - if ( // usage != VX_WRITE_ONLY || - tensor->allocateTensorMemory() == nullptr) - { - VX_PRINT(VX_ZONE_ERROR, "Tensor memory was allocated failed!\n"); - status = VX_ERROR_NO_MEMORY; - goto exit; - } } - if (tensor->number_of_dimensions < number_of_dims || number_of_dims == 0) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid number of patch dimensions\n"); - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; - - } - if (Tensor::checkSizes(tensor->dimensions, view_start, view_end, number_of_dims) != 0) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid view\n"); - status = VX_ERROR_INVALID_PARAMETERS; - goto exit; - - } - - stride[0] = Reference::sizeOfType(tensor->data_type); - for (vx_uint32 i = 1; i < number_of_dims; i++) - { - stride[i] = stride[i - 1] * (view_end[i] - view_start[i]); - } - //vx_map_id * map_id, vx_size * stride, void ** ptr - size = Tensor::computePatchSize(view_start, view_end, number_of_dims); - - memcpy(extra.tensor_data.start, view_start, sizeof(vx_size) * number_of_dims); - memcpy(extra.tensor_data.end, view_end, sizeof(vx_size) * number_of_dims); - memcpy(extra.tensor_data.stride, stride, sizeof(vx_size) * number_of_dims); - extra.tensor_data.number_of_dims = number_of_dims; - - if (VX_MEMORY_TYPE_HOST == mem_type && - vx_true_e == tensor->context->memoryMap((vx_reference)tensor, 0, usage, mem_type, 0, (void *)&extra, (void **)&buf, map_id)) - { - *ptr = tensor->addr; - - tensor->incrementReference(VX_EXTERNAL); - - status = VX_SUCCESS; - } - else if (vx_true_e == tensor->context->memoryMap((vx_reference)tensor, size, usage, mem_type, 0, (void *)&extra, (void **)&buf, map_id)) + if (VX_SUCCESS == status) { - vx_uint8* user_curr_ptr = buf; - vx_uint8* tensor_ptr = (vx_uint8*)tensor->addr; - if (usage == VX_READ_ONLY || usage == VX_READ_AND_WRITE) - { - for (vx_size i = 0; i < size; i++) - { - vx_size patch_pos = 0; - vx_size tensor_pos = 0; - Tensor::computePositionsFromIndex(i,view_start, view_end, tensor->stride, stride, number_of_dims, &tensor_pos, &patch_pos); - memcpy (user_curr_ptr + patch_pos, tensor_ptr + tensor_pos, tensor->stride[0]); - } - - // ownReadFromReference(&tensor->base); - } - *ptr = buf; - tensor->incrementReference(VX_EXTERNAL); - - status = VX_SUCCESS; + status = tensor->copyPatch(number_of_dimensions, view_start, view_end, user_stride, + user_ptr, usage, user_memory_type); } -exit: - VX_PRINT(VX_ZONE_API, "returned %d\n", status); return status; } -VX_API_ENTRY vx_status VX_API_CALL vxUnmapTensorPatch(vx_tensor tensor, vx_map_id map_id) +VX_API_ENTRY vx_status VX_API_CALL vxMapTensorPatch(vx_tensor tensor, vx_size number_of_dims, + const vx_size *view_start, + const vx_size *view_end, vx_map_id *map_id, + vx_size *stride, void **ptr, vx_enum usage, + vx_enum mem_type) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; /* bad references */ if (Tensor::isValidTensor(tensor) == vx_false_e) { status = VX_ERROR_INVALID_REFERENCE; - goto exit; } - /* bad parameters */ - if (tensor->context->findMemoryMap((vx_reference)tensor, map_id) != vx_true_e) + if (VX_SUCCESS == status) { - status = VX_ERROR_INVALID_PARAMETERS; - VX_PRINT(VX_ZONE_ERROR, "Invalid parameters to unmap tensor patch\n"); - return status; + status = tensor->mapPatch(number_of_dims, view_start, view_end, map_id, stride, ptr, usage, + mem_type); } - { - vx_context context = tensor->context; - vx_memory_map_t* map = &context->memory_maps[map_id]; - - if (map->used && map->ref == (vx_reference)tensor) - { - /* commit changes for write access */ - if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && nullptr != map->ptr) - { - if (vx_true_e == Osal::semWait(&tensor->lock)) - { - vx_uint32 size = Tensor::computePatchSize(map->extra.tensor_data.start, - map->extra.tensor_data.end, - map->extra.tensor_data.number_of_dims); - vx_uint8* pSrc = (vx_uint8*)map->ptr; - vx_uint8* pDst = (vx_uint8*)tensor->addr; - - for (vx_size i = 0; i < size; i++) - { - vx_size patch_pos = 0; - vx_size tensor_pos = 0; - Tensor::computePositionsFromIndex(i,map->extra.tensor_data.start, - map->extra.tensor_data.end, - tensor->stride, - map->extra.tensor_data.stride, - map->extra.tensor_data.number_of_dims, - &tensor_pos, - &patch_pos); - memcpy (pDst + patch_pos, pSrc + tensor_pos, tensor->stride[0]); - } - - Osal::semPost(&tensor->lock); - } - else - { - status = VX_FAILURE; - VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); - goto exit; - } - } - - /* freeing mapping buffer */ - context->memoryUnmap((vx_uint32)map_id); - - tensor->decrementReference(VX_EXTERNAL); - - status = VX_SUCCESS; - } - else - status = VX_FAILURE; - } - -exit: - VX_PRINT(VX_ZONE_API, "return %d\n", status); - return status; } -VX_API_ENTRY vx_status VX_API_CALL vxCopyTensorPatch(vx_tensor tensor, vx_size number_of_dimensions, const vx_size * view_start, const vx_size * view_end, - const vx_size * user_stride, void * user_ptr, vx_enum usage, vx_enum user_memory_type) +VX_API_ENTRY vx_status VX_API_CALL vxUnmapTensorPatch(vx_tensor tensor, vx_map_id map_id) { - vx_status status = VX_SUCCESS; - (void)user_memory_type; - - /* bad parameters */ - if ((view_start == nullptr) || (view_end == nullptr) || (user_stride == nullptr) || (user_ptr == nullptr)) - { - status = VX_ERROR_INVALID_PARAMETERS; - } + vx_status status = VX_FAILURE; /* bad references */ - if (VX_SUCCESS == status && Tensor::isValidTensor(tensor) == vx_false_e) + if (Tensor::isValidTensor(tensor) == vx_false_e) { + VX_PRINT(VX_ZONE_ERROR, "Invalid tensor reference!\n"); status = VX_ERROR_INVALID_REFERENCE; } - /* determine if virtual before checking for memory */ - if (VX_SUCCESS == status && tensor->is_virtual == vx_true_e && tensor->is_accessible == vx_false_e) + if (VX_SUCCESS == status) { - /* User tried to access a "virtual" tensor. */ - VX_PRINT(VX_ZONE_ERROR, "Can not access a virtual tensor\n"); - status = VX_ERROR_OPTIMIZED_AWAY; + status = tensor->unmapPatch(map_id); } - if (VX_SUCCESS == status && tensor->addr == nullptr) - { - if ( // usage != VX_WRITE_ONLY || - tensor->allocateTensorMemory() == nullptr) - { - VX_PRINT(VX_ZONE_ERROR, "Tensor memory was not allocated!\n"); - status = VX_ERROR_NOT_ALLOCATED; - } - } - - if ((VX_SUCCESS == status) && - ((tensor->number_of_dimensions < number_of_dimensions) || (number_of_dimensions == 0))) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid number of patch dimensions\n"); - status = VX_ERROR_INVALID_PARAMETERS; + return status; +} - } - if (VX_SUCCESS == status && Tensor::checkSizes(tensor->dimensions, view_start, view_end, number_of_dimensions) != 0) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid view\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } +VX_API_ENTRY vx_status VX_API_CALL vxReleaseTensor(vx_tensor *tensor) +{ + vx_status status = VX_FAILURE; - if (VX_SUCCESS == status) + if (nullptr != tensor) { -#ifdef OPENVX_USE_OPENCL_INTEROP - void * user_ptr_given = user_ptr; - vx_enum user_memory_type_given = user_memory_type; - if (user_memory_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - /* get user_ptr from OpenCL buffer for HOST */ - size_t size = 0; - cl_mem opencl_buf = (cl_mem)user_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyTensorPatch: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_ptr = clEnqueueMapBuffer(tensor->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyTensorPatch: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, user_ptr, cerr); - if (cerr != CL_SUCCESS) + vx_tensor this_tensor = *tensor; + if (vx_true_e == Reference::isValidReference(this_tensor, VX_TYPE_TENSOR)) { - return VX_ERROR_INVALID_PARAMETERS; + status = Reference::releaseReference((vx_reference *)tensor, VX_TYPE_TENSOR, + VX_EXTERNAL, nullptr); } - user_memory_type = VX_MEMORY_TYPE_HOST; - } -#endif - - //element_size = Reference::sizeOfType(tensor->data_type); - vx_uint8* user_curr_ptr = (vx_uint8*)user_ptr; - vx_uint8* tensor_ptr = (vx_uint8*)tensor->addr; - vx_size patch_size = Tensor::computePatchSize (view_start, view_end, number_of_dimensions); - for (vx_size i = 0; i < patch_size; i++) - { - vx_size patch_pos = 0; - vx_size tensor_pos = 0; - Tensor::computePositionsFromIndex(i,view_start, view_end, tensor->stride, user_stride, number_of_dimensions, &tensor_pos, &patch_pos); - if (usage == VX_READ_ONLY) - memcpy (user_curr_ptr + patch_pos, tensor_ptr + tensor_pos, tensor->stride[0]); - else - memcpy (tensor_ptr + tensor_pos, user_curr_ptr + patch_pos, tensor->stride[0]); - } - status = VX_SUCCESS; - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_memory_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(tensor->context->opencl_command_queue, - (cl_mem)user_ptr_given, user_ptr, 0, nullptr, nullptr); - clFinish(tensor->context->opencl_command_queue); - } -#endif } - VX_PRINT(VX_ZONE_API, "returned %d\n", status); return status; -} +} \ No newline at end of file From 23f352c04f8866370a8df641a612f59f4e53737b Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 17:52:38 -0700 Subject: [PATCH 14/34] More minor cleanup to type pairs --- framework/include/vx_type_pairs.h | 54 ++++++++++++++++++++++++++++++- framework/src/vx_type_pairs.cpp | 50 ---------------------------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/framework/include/vx_type_pairs.h b/framework/include/vx_type_pairs.h index d9ce7da2..9cd8151d 100644 --- a/framework/include/vx_type_pairs.h +++ b/framework/include/vx_type_pairs.h @@ -18,6 +18,8 @@ #include +#include "vx_internal.h" + /*! * \file * \brief The internal type pairs implementation @@ -40,7 +42,57 @@ struct vx_enum_string_t uintmax_t nibbles; }; -extern const vx_enum_string_t type_pairs[]; +/*! \brief The type pairs array + * \ingroup group_int_type_pairs + */ +const vx_enum_string_t type_pairs[] = { + {VX_STRINGERIZE(VX_TYPE_INVALID), 0}, + /* scalar objects */ + {VX_STRINGERIZE(VX_TYPE_CHAR), sizeof(vx_char) * 2}, + {VX_STRINGERIZE(VX_TYPE_UINT8), sizeof(vx_uint8) * 2}, + {VX_STRINGERIZE(VX_TYPE_UINT16), sizeof(vx_uint16) * 2}, + {VX_STRINGERIZE(VX_TYPE_UINT32), sizeof(vx_uint32) * 2}, + {VX_STRINGERIZE(VX_TYPE_UINT64), sizeof(vx_uint64) * 2}, + {VX_STRINGERIZE(VX_TYPE_INT8), sizeof(vx_int8) * 2}, + {VX_STRINGERIZE(VX_TYPE_INT16), sizeof(vx_int16) * 2}, + {VX_STRINGERIZE(VX_TYPE_INT32), sizeof(vx_int32) * 2}, + {VX_STRINGERIZE(VX_TYPE_INT64), sizeof(vx_int64) * 2}, + {VX_STRINGERIZE(VX_TYPE_FLOAT32), sizeof(vx_float32) * 2}, + {VX_STRINGERIZE(VX_TYPE_FLOAT64), sizeof(vx_float64) * 2}, + {VX_STRINGERIZE(VX_TYPE_SIZE), sizeof(vx_size) * 2}, + {VX_STRINGERIZE(VX_TYPE_DF_IMAGE), sizeof(vx_df_image) * 2}, + {VX_STRINGERIZE(VX_TYPE_BOOL), sizeof(vx_bool) * 2}, + {VX_STRINGERIZE(VX_TYPE_ENUM), sizeof(vx_enum) * 2}, + /* struct objects */ + {VX_STRINGERIZE(VX_TYPE_COORDINATES2D), sizeof(vx_coordinates2d_t) * 2}, + {VX_STRINGERIZE(VX_TYPE_COORDINATES3D), sizeof(vx_coordinates3d_t) * 2}, + {VX_STRINGERIZE(VX_TYPE_RECTANGLE), sizeof(vx_rectangle_t) * 2}, + {VX_STRINGERIZE(VX_TYPE_KEYPOINT), sizeof(vx_keypoint_t) * 2}, + /* data objects */ + {VX_STRINGERIZE(VX_TYPE_ARRAY), sizeof(Array)}, + {VX_STRINGERIZE(VX_TYPE_DISTRIBUTION), sizeof(Distribution)}, + {VX_STRINGERIZE(VX_TYPE_LUT), sizeof(Lut)}, + {VX_STRINGERIZE(VX_TYPE_IMAGE), sizeof(Image)}, + {VX_STRINGERIZE(VX_TYPE_CONVOLUTION), sizeof(Convolution)}, + {VX_STRINGERIZE(VX_TYPE_THRESHOLD), sizeof(Threshold)}, + {VX_STRINGERIZE(VX_TYPE_TENSOR), sizeof(Tensor)}, + {VX_STRINGERIZE(VX_TYPE_MATRIX), sizeof(Matrix)}, + {VX_STRINGERIZE(VX_TYPE_OBJECT_ARRAY), sizeof(ObjectArray)}, + {VX_STRINGERIZE(VX_TYPE_SCALAR), sizeof(Scalar)}, + {VX_STRINGERIZE(VX_TYPE_PYRAMID), sizeof(Pyramid)}, + {VX_STRINGERIZE(VX_TYPE_REMAP), sizeof(Remap)}, +#ifdef OPENVX_KHR_XML + {VX_STRINGERIZE(VX_TYPE_IMPORT), sizeof(Import)}, +#endif + /* framework objects */ + {VX_STRINGERIZE(VX_TYPE_CONTEXT), sizeof(Context)}, + {VX_STRINGERIZE(VX_TYPE_GRAPH), sizeof(Graph)}, + {VX_STRINGERIZE(VX_TYPE_NODE), sizeof(Node)}, + {VX_STRINGERIZE(VX_TYPE_KERNEL), sizeof(Kernel)}, + {VX_STRINGERIZE(VX_TYPE_TARGET), sizeof(Target)}, + {VX_STRINGERIZE(VX_TYPE_REFERENCE), sizeof(Reference)}, + {VX_STRINGERIZE(VX_TYPE_PARAMETER), sizeof(Parameter)}, +}; class TypePairs { diff --git a/framework/src/vx_type_pairs.cpp b/framework/src/vx_type_pairs.cpp index 2df13ee0..18f71958 100644 --- a/framework/src/vx_type_pairs.cpp +++ b/framework/src/vx_type_pairs.cpp @@ -13,58 +13,8 @@ * limitations under the License. */ -#include "vx_internal.h" #include "vx_type_pairs.h" -const vx_enum_string_t type_pairs[] = { - {VX_STRINGERIZE(VX_TYPE_INVALID), 0}, - /* scalar objects */ - {VX_STRINGERIZE(VX_TYPE_CHAR), sizeof(vx_char) * 2}, - {VX_STRINGERIZE(VX_TYPE_UINT8), sizeof(vx_uint8) * 2}, - {VX_STRINGERIZE(VX_TYPE_UINT16), sizeof(vx_uint16) * 2}, - {VX_STRINGERIZE(VX_TYPE_UINT32), sizeof(vx_uint32) * 2}, - {VX_STRINGERIZE(VX_TYPE_UINT64), sizeof(vx_uint64) * 2}, - {VX_STRINGERIZE(VX_TYPE_INT8), sizeof(vx_int8) * 2}, - {VX_STRINGERIZE(VX_TYPE_INT16), sizeof(vx_int16) * 2}, - {VX_STRINGERIZE(VX_TYPE_INT32), sizeof(vx_int32) * 2}, - {VX_STRINGERIZE(VX_TYPE_INT64), sizeof(vx_int64) * 2}, - {VX_STRINGERIZE(VX_TYPE_FLOAT32), sizeof(vx_float32) * 2}, - {VX_STRINGERIZE(VX_TYPE_FLOAT64), sizeof(vx_float64) * 2}, - {VX_STRINGERIZE(VX_TYPE_SIZE), sizeof(vx_size) * 2}, - {VX_STRINGERIZE(VX_TYPE_DF_IMAGE), sizeof(vx_df_image) * 2}, - {VX_STRINGERIZE(VX_TYPE_BOOL), sizeof(vx_bool) * 2}, - {VX_STRINGERIZE(VX_TYPE_ENUM), sizeof(vx_enum) * 2}, - /* struct objects */ - {VX_STRINGERIZE(VX_TYPE_COORDINATES2D), sizeof(vx_coordinates2d_t) * 2}, - {VX_STRINGERIZE(VX_TYPE_COORDINATES3D), sizeof(vx_coordinates3d_t) * 2}, - {VX_STRINGERIZE(VX_TYPE_RECTANGLE), sizeof(vx_rectangle_t) * 2}, - {VX_STRINGERIZE(VX_TYPE_KEYPOINT), sizeof(vx_keypoint_t) * 2}, - /* data objects */ - {VX_STRINGERIZE(VX_TYPE_ARRAY), sizeof(Array)}, - {VX_STRINGERIZE(VX_TYPE_DISTRIBUTION), sizeof(Distribution)}, - {VX_STRINGERIZE(VX_TYPE_LUT), sizeof(Lut)}, - {VX_STRINGERIZE(VX_TYPE_IMAGE), sizeof(Image)}, - {VX_STRINGERIZE(VX_TYPE_CONVOLUTION), sizeof(Convolution)}, - {VX_STRINGERIZE(VX_TYPE_THRESHOLD), sizeof(Threshold)}, - {VX_STRINGERIZE(VX_TYPE_TENSOR), sizeof(Tensor)}, - {VX_STRINGERIZE(VX_TYPE_MATRIX), sizeof(Matrix)}, - {VX_STRINGERIZE(VX_TYPE_OBJECT_ARRAY), sizeof(ObjectArray)}, - {VX_STRINGERIZE(VX_TYPE_SCALAR), sizeof(Scalar)}, - {VX_STRINGERIZE(VX_TYPE_PYRAMID), sizeof(Pyramid)}, - {VX_STRINGERIZE(VX_TYPE_REMAP), sizeof(Remap)}, -#ifdef OPENVX_KHR_XML - {VX_STRINGERIZE(VX_TYPE_IMPORT), sizeof(Import)}, -#endif - /* framework objects */ - {VX_STRINGERIZE(VX_TYPE_CONTEXT), sizeof(Context)}, - {VX_STRINGERIZE(VX_TYPE_GRAPH), sizeof(Graph)}, - {VX_STRINGERIZE(VX_TYPE_NODE), sizeof(Node)}, - {VX_STRINGERIZE(VX_TYPE_KERNEL), sizeof(Kernel)}, - {VX_STRINGERIZE(VX_TYPE_TARGET), sizeof(Target)}, - {VX_STRINGERIZE(VX_TYPE_REFERENCE), sizeof(Reference)}, - {VX_STRINGERIZE(VX_TYPE_PARAMETER), sizeof(Parameter)}, -}; - #if defined(EXPERIMENTAL_USE_DOT) || defined(OPENVX_USE_XML) vx_int32 TypePairs::stringFromType(vx_enum type) From 7923a5d41371afac8ea30effddf66f6ab7dcd061 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Sun, 27 Jul 2025 18:05:54 -0700 Subject: [PATCH 15/34] Reworked reference --- framework/include/vx_reference.h | 33 ++++++- framework/src/vx_reference.cpp | 150 ++++++++++++++++++++++--------- 2 files changed, 139 insertions(+), 44 deletions(-) diff --git a/framework/include/vx_reference.h b/framework/include/vx_reference.h index ffc9cb8f..cbda82ad 100644 --- a/framework/include/vx_reference.h +++ b/framework/include/vx_reference.h @@ -53,6 +53,37 @@ class Reference { */ virtual ~Reference(); + /** + * @brief Returns the reference count of the object + * @return vx_uint32 The reference count + * @ingroup group_int_reference + */ + vx_uint32 refCount() const; + + /** + * @brief Returns the type of the reference + * + * @return vx_enum The type of the reference + * @ingroup group_int_reference + */ + vx_enum dataType() const; + + /** + * @brief Returns the name of the reference + * + * @return const vx_char* The name of the reference + * @ingroup group_int_reference + */ + const vx_char* refName() const; + + /** + * @brief Sets the name of the reference + * + * @param name The name to set + * @ingroup group_int_reference + */ + void setName(const vx_char* name); + /*! \brief Used to create a reference. * \note This does not add the reference to the system context yet. * \param [in] context The system context. @@ -181,7 +212,7 @@ class Reference { cl_event event; #endif /*! \brief The reference name */ - char name[VX_MAX_REFERENCE_NAME]; + vx_char name[VX_MAX_REFERENCE_NAME]; }; #endif /* VX_REFERENCE_H */ diff --git a/framework/src/vx_reference.cpp b/framework/src/vx_reference.cpp index 06dae9e3..320c50b5 100644 --- a/framework/src/vx_reference.cpp +++ b/framework/src/vx_reference.cpp @@ -60,6 +60,30 @@ Reference::~Reference() // VX_PRINT(VX_ZONE_REFERENCE, ">>>> Reference count was zero, destructed object " VX_FMT_REF "\n", this); } +vx_uint32 Reference::refCount() const +{ + return external_count; +} + +vx_enum Reference::dataType() const +{ + return type; +} + +const vx_char* Reference::refName() const +{ + return name; +} + +void Reference::setName(const char* name) +{ + if (name != nullptr) + { + strncpy(this->name, name, strnlen(name, VX_MAX_REFERENCE_NAME)); + this->name[VX_MAX_REFERENCE_NAME - 1] = '\0'; // Ensure null termination + } +} + vx_bool Reference::isValidReference(vx_reference ref) { vx_bool ret = vx_false_e; @@ -433,7 +457,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryReference(vx_reference ref, vx_enum at case VX_REFERENCE_COUNT: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = ref->external_count; + *(vx_uint32*)ptr = ref->refCount(); } else { @@ -443,7 +467,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryReference(vx_reference ref, vx_enum at case VX_REFERENCE_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = ref->type; + *(vx_enum*)ptr = ref->dataType(); } else { @@ -453,7 +477,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryReference(vx_reference ref, vx_enum at case VX_REFERENCE_NAME: if (VX_CHECK_PARAM(ptr, size, vx_char*, 0x3)) { - *(vx_char**)ptr = &ref->name[0]; + *(vx_char**)ptr = const_cast(ref->refName()); } else { @@ -473,13 +497,29 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetReferenceName(vx_reference ref, const vx if (Reference::isValidReference(ref)) { - strncpy(ref->name, name, strnlen(name, VX_MAX_REFERENCE_NAME)); + ref->setName(name); status = VX_SUCCESS; } return status; } +VX_API_ENTRY vx_status VX_API_CALL vxRetainReference(vx_reference ref) +{ + vx_status status = VX_SUCCESS; + + if (Reference::isValidReference(ref) == vx_true_e) + { + ref->incrementReference(VX_EXTERNAL); + } + else + { + status = VX_ERROR_INVALID_REFERENCE; + } + + return status; +} + VX_API_ENTRY vx_status VX_API_CALL vxReleaseReference(vx_reference* ref_ptr) { vx_status status = VX_ERROR_INVALID_REFERENCE; @@ -489,50 +529,74 @@ VX_API_ENTRY vx_status VX_API_CALL vxReleaseReference(vx_reference* ref_ptr) { switch (ref->type) { - case VX_TYPE_CONTEXT: status = vxReleaseContext((vx_context*)ref_ptr); break; - case VX_TYPE_GRAPH: status = vxReleaseGraph((vx_graph*)ref_ptr); break; - case VX_TYPE_NODE: status = vxReleaseNode((vx_node*)ref_ptr); break; - case VX_TYPE_ARRAY: status = vxReleaseArray((vx_array*)ref_ptr); break; - case VX_TYPE_OBJECT_ARRAY: status = vxReleaseObjectArray((vx_object_array*)ref_ptr); break; - case VX_TYPE_CONVOLUTION: status = vxReleaseConvolution((vx_convolution*)ref_ptr); break; - case VX_TYPE_DISTRIBUTION: status = vxReleaseDistribution((vx_distribution*)ref_ptr); break; - case VX_TYPE_IMAGE: status = vxReleaseImage((vx_image*)ref_ptr); break; - case VX_TYPE_LUT: status = vxReleaseLUT((vx_lut*)ref_ptr); break; - case VX_TYPE_MATRIX: status = vxReleaseMatrix((vx_matrix*)ref_ptr); break; - case VX_TYPE_PYRAMID: status = vxReleasePyramid((vx_pyramid*)ref_ptr); break; - case VX_TYPE_REMAP: status = vxReleaseRemap((vx_remap*)ref_ptr); break; - case VX_TYPE_SCALAR: status = vxReleaseScalar((vx_scalar*)ref_ptr); break; - case VX_TYPE_THRESHOLD: status = vxReleaseThreshold((vx_threshold*)ref_ptr); break; - case VX_TYPE_DELAY: status = vxReleaseDelay((vx_delay*)ref_ptr); break; - case VX_TYPE_KERNEL: status = vxReleaseKernel((vx_kernel*)ref_ptr); break; - case VX_TYPE_PARAMETER: status = vxReleaseParameter((vx_parameter*)ref_ptr); break; - case VX_TYPE_TENSOR: status = vxReleaseTensor((vx_tensor*)ref_ptr); break; + case VX_TYPE_CONTEXT: + status = vxReleaseContext((vx_context*)ref_ptr); + break; + case VX_TYPE_GRAPH: + status = vxReleaseGraph((vx_graph*)ref_ptr); + break; + case VX_TYPE_NODE: + status = vxReleaseNode((vx_node*)ref_ptr); + break; + case VX_TYPE_ARRAY: + status = vxReleaseArray((vx_array*)ref_ptr); + break; + case VX_TYPE_OBJECT_ARRAY: + status = vxReleaseObjectArray((vx_object_array*)ref_ptr); + break; + case VX_TYPE_CONVOLUTION: + status = vxReleaseConvolution((vx_convolution*)ref_ptr); + break; + case VX_TYPE_DISTRIBUTION: + status = vxReleaseDistribution((vx_distribution*)ref_ptr); + break; + case VX_TYPE_IMAGE: + status = vxReleaseImage((vx_image*)ref_ptr); + break; + case VX_TYPE_LUT: + status = vxReleaseLUT((vx_lut*)ref_ptr); + break; + case VX_TYPE_MATRIX: + status = vxReleaseMatrix((vx_matrix*)ref_ptr); + break; + case VX_TYPE_PYRAMID: + status = vxReleasePyramid((vx_pyramid*)ref_ptr); + break; + case VX_TYPE_REMAP: + status = vxReleaseRemap((vx_remap*)ref_ptr); + break; + case VX_TYPE_SCALAR: + status = vxReleaseScalar((vx_scalar*)ref_ptr); + break; + case VX_TYPE_THRESHOLD: + status = vxReleaseThreshold((vx_threshold*)ref_ptr); + break; + case VX_TYPE_DELAY: + status = vxReleaseDelay((vx_delay*)ref_ptr); + break; + case VX_TYPE_KERNEL: + status = vxReleaseKernel((vx_kernel*)ref_ptr); + break; + case VX_TYPE_PARAMETER: + status = vxReleaseParameter((vx_parameter*)ref_ptr); + break; + case VX_TYPE_TENSOR: + status = vxReleaseTensor((vx_tensor*)ref_ptr); + break; #if defined(OPENVX_USE_USER_DATA_OBJECT) - case VX_TYPE_USER_DATA_OBJECT: status = vxReleaseUserDataObject((vx_user_data_object*)ref_ptr); break; + case VX_TYPE_USER_DATA_OBJECT: + status = vxReleaseUserDataObject((vx_user_data_object*)ref_ptr); + break; #endif /* defined(OPENVX_USE_USER_DATA_OBJECT) */ #if defined(OPENVX_USE_IX) || defined(OPENVX_USE_XML) - case VX_TYPE_IMPORT: status = vxReleaseImport((vx_import*)ref_ptr); break; + case VX_TYPE_IMPORT: + status = vxReleaseImport((vx_import*)ref_ptr); + break; #endif - default: - break; + default: + break; } } return status; -} - -VX_API_ENTRY vx_status VX_API_CALL vxRetainReference(vx_reference ref) -{ - vx_status status = VX_SUCCESS; - - if (Reference::isValidReference(ref) == vx_true_e) - { - ref->incrementReference(VX_EXTERNAL); - } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } - - return status; -} +} \ No newline at end of file From a67427de3451dc30019b4879f62d12bfe0cb0cba Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Mon, 28 Jul 2025 17:02:09 -0700 Subject: [PATCH 16/34] Reworked object array --- framework/include/vx_object_array.h | 35 +++++++++++ framework/src/vx_object_array.cpp | 95 ++++++++++++++++++----------- 2 files changed, 96 insertions(+), 34 deletions(-) diff --git a/framework/include/vx_object_array.h b/framework/include/vx_object_array.h index 16b02dc3..3d217d27 100644 --- a/framework/include/vx_object_array.h +++ b/framework/include/vx_object_array.h @@ -91,6 +91,41 @@ class ObjectArray : public Reference */ static vx_bool isValidObjectArray(vx_object_array objarr, vx_enum item_type, vx_size num_items); + /** + * @brief Get the item at the specified index + * + * @param index The index of the item to get + * @return vx_reference The reference to the item + * @ingroup group_int_object_array + */ + vx_reference getItem(vx_size index) const; + + /** + * @brief Set the item at the specified index + * + * @param index The index of the item to set + * @param ref The reference to set at the index + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_object_array + */ + vx_status setItem(vx_size index, vx_reference ref); + + /** + * @brief Get the item type of the object array + * + * @return vx_enum The item type of the object array + * @ingroup group_int_object_array + */ + vx_enum itemType() const; + + /** + * @brief Get the number of items in the object array + * + * @return vx_size The number of items in the object array + * @ingroup group_int_object_array + */ + vx_size numItems() const; + /** * @brief Function to destroy the object array * @ingroup group_int_object_array diff --git a/framework/src/vx_object_array.cpp b/framework/src/vx_object_array.cpp index 7809ffda..01a418b8 100644 --- a/framework/src/vx_object_array.cpp +++ b/framework/src/vx_object_array.cpp @@ -306,9 +306,46 @@ vx_status ObjectArray::initObjectArray(vx_reference exemplar, vx_size num_items) return VX_SUCCESS; } -/*============================================================================== - INTERNAL INTERFACE - =============================================================================*/ +vx_reference ObjectArray::getItem(vx_size index) const +{ + vx_reference item = nullptr; + + if (index < num_items) + { + item = items[index]; + item->incrementReference(VX_EXTERNAL); + } + else + { + item = (vx_reference)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); + } + + return item; +} + +vx_status ObjectArray::setItem(vx_size index, vx_reference ref) +{ + if (index >= VX_INT_MAX_REF) + { + VX_PRINT(VX_ZONE_ERROR, "Index out of bounds: %zu >= %zu\n", index, VX_INT_MAX_REF); + return VX_ERROR_INVALID_PARAMETERS; + } + + items[index] = ref; + num_items++; + + return VX_SUCCESS; +} + +vx_enum ObjectArray::itemType() const +{ + return item_type; +} + +vx_size ObjectArray::numItems() const +{ + return num_items; +} vx_object_array ObjectArray::createObjectArray(vx_reference scope, vx_reference exemplar, vx_size count, vx_bool is_virtual) { @@ -450,21 +487,6 @@ VX_API_ENTRY vx_object_array VX_API_CALL vxCreateVirtualObjectArray(vx_graph gra return arr; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseObjectArray(vx_object_array* arr) -{ - vx_status status = VX_FAILURE; - - if (nullptr != arr) - { - vx_object_array object_array = *arr; - if (vx_true_e == Reference::isValidReference(object_array, VX_TYPE_OBJECT_ARRAY)) - { - status = Reference::releaseReference((vx_reference*)arr, VX_TYPE_OBJECT_ARRAY, VX_EXTERNAL, nullptr); - } - } - return status; -} - VX_API_ENTRY vx_status VX_API_CALL vxQueryObjectArray(vx_object_array arr, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_ERROR_INVALID_REFERENCE; @@ -477,7 +499,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryObjectArray(vx_object_array arr, vx_en case VX_OBJECT_ARRAY_ITEMTYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = arr->item_type; + *(vx_enum *)ptr = arr->itemType(); } else { @@ -488,7 +510,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryObjectArray(vx_object_array arr, vx_en case VX_OBJECT_ARRAY_NUMITEMS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = arr->num_items; + *(vx_size *)ptr = arr->numItems(); } else { @@ -511,15 +533,7 @@ VX_API_ENTRY vx_reference VX_API_CALL vxGetObjectArrayItem(vx_object_array arr, if (ObjectArray::isValidObjectArray(arr) == vx_true_e) { - if (index < arr->num_items) - { - item = arr->items[index]; - item->incrementReference(VX_EXTERNAL); - } - else - { - item = (vx_reference)vxGetErrorObject(arr->context, VX_ERROR_INVALID_PARAMETERS); - } + item = arr->getItem(index); } return item; @@ -529,18 +543,31 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetObjectArrayItem(vx_object_array arr, vx_ { vx_status status = VX_SUCCESS; - if (ObjectArray::isValidObjectArray(arr) != vx_true_e || - Reference::isValidReference(ref) != vx_true_e || - index >= VX_INT_MAX_REF) + if (ObjectArray::isValidObjectArray(arr) != vx_true_e) { status = VX_ERROR_INVALID_PARAMETERS; } if (VX_SUCCESS == status) { - arr->items[index] = ref; - arr->num_items++; + status = arr->setItem(index, ref); } return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseObjectArray(vx_object_array *arr) +{ + vx_status status = VX_FAILURE; + + if (nullptr != arr) + { + vx_object_array object_array = *arr; + if (vx_true_e == Reference::isValidReference(object_array, VX_TYPE_OBJECT_ARRAY)) + { + status = Reference::releaseReference((vx_reference *)arr, VX_TYPE_OBJECT_ARRAY, + VX_EXTERNAL, nullptr); + } + } + return status; +} \ No newline at end of file From 2ebea207deb1960092ae6db75eb518f900150178 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Mon, 28 Jul 2025 17:23:53 -0700 Subject: [PATCH 17/34] Reworked scalar --- framework/include/vx_scalar.h | 49 +++ framework/src/vx_scalar.cpp | 560 ++++++++++++++++++---------------- 2 files changed, 343 insertions(+), 266 deletions(-) diff --git a/framework/include/vx_scalar.h b/framework/include/vx_scalar.h index 14c69a10..f04114c1 100644 --- a/framework/include/vx_scalar.h +++ b/framework/include/vx_scalar.h @@ -77,6 +77,55 @@ class Scalar : public Reference */ static vx_status hostMemToScalar(vx_scalar scalar, void* user_ptr); + /** + * @brief Copy scalar value to/from user memory + * + * @param user_ptr pointer to user memory + * @param usage usage of the memory (read/write) + * @param user_mem_type type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success + * @ingroup group_int_scalar + */ + vx_status copy(void* user_ptr, vx_enum usage, vx_enum user_mem_type); + + /** + * @brief Copy scalar value, given size, to/from user memory + * + * @param size size of the scalar data + * @param user_ptr pointer to user memory + * @param usage usage of the memory (read/write) + * @param user_mem_type type of memory (host, opencl, etc.) + * @return vx_status VX_SUCCESS on success + * @ingroup group_int_scalar + */ + vx_status copy(vx_size size, void* user_ptr, vx_enum usage, vx_enum user_mem_type); + + /** + * @brief Read the scalar value + * + * @param ptr Pointer to the memory location to read the value into + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_scalar + */ + vx_status readValue(void* ptr); + + /** + * @brief Write the scalar value + * + * @param ptr Pointer to the memory location containing the value to write + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_scalar + */ + vx_status writeValue(const void* ptr); + + /** + * @brief Get the data type of the scalar + * + * @return vx_enum The data type of the scalar + * @ingroup group_int_scalar + */ + vx_enum dataType() const; + /** * @brief Print scalar object * diff --git a/framework/src/vx_scalar.cpp b/framework/src/vx_scalar.cpp index 27557871..dc5ab859 100644 --- a/framework/src/vx_scalar.cpp +++ b/framework/src/vx_scalar.cpp @@ -131,6 +131,281 @@ vx_status Scalar::hostMemToScalar(vx_scalar scalar, void* user_ptr) return status; } +vx_status Scalar::copy(void *user_ptr, vx_enum usage, vx_enum user_mem_type) +{ + vx_status status = VX_SUCCESS; + + if (nullptr == user_ptr || VX_MEMORY_TYPE_HOST != user_mem_type) + return VX_ERROR_INVALID_PARAMETERS; + +#ifdef OPENVX_USE_OPENCL_INTEROP + void *user_ptr_given = user_ptr; + vx_enum user_mem_type_given = user_mem_type; + if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + // get ptr from OpenCL buffer for HOST + size_t size = 0; + cl_mem opencl_buf = (cl_mem)user_ptr; + cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyScalar: clGetMemObjectInfo(%p) => (%d)\n", + opencl_buf, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + user_ptr = + clEnqueueMapBuffer(context->opencl_command_queue, opencl_buf, CL_TRUE, + CL_MAP_READ | CL_MAP_WRITE, 0, size, 0, nullptr, nullptr, &cerr); + VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyScalar: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", + opencl_buf, (int)size, user_ptr, cerr); + if (cerr != CL_SUCCESS) + { + return VX_ERROR_INVALID_PARAMETERS; + } + user_mem_type = VX_MEMORY_TYPE_HOST; + } +#endif + + switch (usage) + { + case VX_READ_ONLY: + status = Scalar::scalarToHostMem(this, user_ptr); + break; + case VX_WRITE_ONLY: + status = Scalar::hostMemToScalar(this, user_ptr); + break; + + default: + status = VX_ERROR_INVALID_PARAMETERS; + break; + } + +#ifdef OPENVX_USE_OPENCL_INTEROP + if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) + { + clEnqueueUnmapMemObject(context->opencl_command_queue, (cl_mem)user_ptr_given, user_ptr, 0, + nullptr, nullptr); + clFinish(context->opencl_command_queue); + } +#endif + + return status; +} + +vx_status Scalar::copy(vx_size size, void *user_ptr, vx_enum usage, vx_enum user_mem_type) +{ + vx_status status = VX_SUCCESS; + vx_size min_size = 0; + + if (nullptr == user_ptr || VX_MEMORY_TYPE_HOST != user_mem_type) + return VX_ERROR_INVALID_PARAMETERS; + + switch (usage) + { + case VX_READ_ONLY: + if (data_addr != nullptr && data_len != 0) + { + min_size = data_len > size ? size : data_len; + memcpy(user_ptr, data_addr, min_size); + } + else + { + status = VX_ERROR_NO_RESOURCES; + } + break; + case VX_WRITE_ONLY: + if (data_addr == nullptr) + { + if (nullptr == allocateScalarMemory(size)) + { + status = VX_ERROR_NO_MEMORY; + } + else + { + data_len = size; + memcpy(data_addr, user_ptr, size); + } + } + else + { + if (data_len < size) + { + void *tmp_addr = data_addr; + data_addr = nullptr; + if (nullptr == allocateScalarMemory(size)) + { + data_addr = tmp_addr; + status = VX_ERROR_NO_MEMORY; + } + else + { + free(tmp_addr); + data_len = size; + memcpy(data_addr, user_ptr, size); + } + } + else + { + data_len = size; + memcpy(data_addr, user_ptr, size); + } + } + break; + + default: + status = VX_ERROR_INVALID_PARAMETERS; + break; + } + + return status; +} + +vx_status Scalar::readValue(void* ptr) +{ + vx_status status = VX_SUCCESS; + + if (ptr == nullptr) return VX_ERROR_INVALID_PARAMETERS; + + Osal::semWait(&lock); + Scalar::printScalarValue(this); + switch (data_type) + { + case VX_TYPE_CHAR: + *(vx_char *)ptr = data.chr; + break; + case VX_TYPE_INT8: + *(vx_int8 *)ptr = data.s08; + break; + case VX_TYPE_UINT8: + *(vx_uint8 *)ptr = data.u08; + break; + case VX_TYPE_INT16: + *(vx_int16 *)ptr = data.s16; + break; + case VX_TYPE_UINT16: + *(vx_uint16 *)ptr = data.u16; + break; + case VX_TYPE_INT32: + *(vx_int32 *)ptr = data.s32; + break; + case VX_TYPE_UINT32: + *(vx_uint32 *)ptr = data.u32; + break; + case VX_TYPE_INT64: + *(vx_int64 *)ptr = data.s64; + break; + case VX_TYPE_UINT64: + *(vx_uint64 *)ptr = data.u64; + break; +#ifdef EXPERIMENTAL_PLATFORM_SUPPORTS_16_FLOAT + case VX_TYPE_FLOAT16: + *(vx_float16 *)ptr = data.f16; + break; +#endif + case VX_TYPE_FLOAT32: + *(vx_float32 *)ptr = data.f32; + break; + case VX_TYPE_FLOAT64: + *(vx_float64 *)ptr = data.f64; + break; + case VX_TYPE_DF_IMAGE: + *(vx_df_image *)ptr = data.fcc; + break; + case VX_TYPE_ENUM: + *(vx_enum *)ptr = data.enm; + break; + case VX_TYPE_SIZE: + *(vx_size *)ptr = data.size; + break; + case VX_TYPE_BOOL: + *(vx_bool *)ptr = data.boolean; + break; + default: + VX_PRINT(VX_ZONE_ERROR, "some case is not covered in %s\n", __FUNCTION__); + status = VX_ERROR_NOT_SUPPORTED; + break; + } + Osal::semPost(&lock); + // ownReadFromReference(&base); + + return status; +} + +vx_status Scalar::writeValue(const void *ptr) +{ + vx_status status = VX_SUCCESS; + if (ptr == nullptr) return VX_ERROR_INVALID_PARAMETERS; + + Osal::semWait(&lock); + switch (data_type) + { + case VX_TYPE_CHAR: + data.chr = *(vx_char *)ptr; + break; + case VX_TYPE_INT8: + data.s08 = *(vx_int8 *)ptr; + break; + case VX_TYPE_UINT8: + data.u08 = *(vx_uint8 *)ptr; + break; + case VX_TYPE_INT16: + data.s16 = *(vx_int16 *)ptr; + break; + case VX_TYPE_UINT16: + data.u16 = *(vx_uint16 *)ptr; + break; + case VX_TYPE_INT32: + data.s32 = *(vx_int32 *)ptr; + break; + case VX_TYPE_UINT32: + data.u32 = *(vx_uint32 *)ptr; + break; + case VX_TYPE_INT64: + data.s64 = *(vx_int64 *)ptr; + break; + case VX_TYPE_UINT64: + data.u64 = *(vx_uint64 *)ptr; + break; +#ifdef EXPERIMENTAL_PLATFORM_SUPPORTS_16_FLOAT + case VX_TYPE_FLOAT16: + data.f16 = *(vx_float16 *)ptr; + break; +#endif + case VX_TYPE_FLOAT32: + data.f32 = *(vx_float32 *)ptr; + break; + case VX_TYPE_FLOAT64: + data.f64 = *(vx_float64 *)ptr; + break; + case VX_TYPE_DF_IMAGE: + data.fcc = *(vx_df_image *)ptr; + break; + case VX_TYPE_ENUM: + data.enm = *(vx_enum *)ptr; + break; + case VX_TYPE_SIZE: + data.size = *(vx_size *)ptr; + break; + case VX_TYPE_BOOL: + data.boolean = *(vx_bool *)ptr; + break; + default: + VX_PRINT(VX_ZONE_ERROR, "some case is not covered in %s\n", __FUNCTION__); + status = VX_ERROR_NOT_SUPPORTED; + break; + } + Scalar::printScalarValue(this); + Osal::semPost(&lock); + // ownWroteToReference(&base); + + return status; +} + +vx_enum Scalar::dataType() const +{ + return data_type; +} + void Scalar::printScalarValue(vx_scalar scalar) { switch (scalar->data_type) @@ -288,22 +563,6 @@ VX_API_ENTRY vx_scalar VX_API_CALL vxCreateVirtualScalar(vx_graph graph, vx_enum return (vx_scalar)scalar; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseScalar(vx_scalar* s) -{ - vx_status status = VX_FAILURE; - - if (nullptr != s) - { - vx_scalar scalar = *s; - if (vx_true_e == Reference::isValidReference(scalar, VX_TYPE_SCALAR)) - { - status = Reference::releaseReference((vx_reference*)s, VX_TYPE_SCALAR, VX_EXTERNAL, nullptr); - } - } - - return status; -} /* vxReleaseScalar() */ - VX_API_ENTRY vx_status VX_API_CALL vxQueryScalar(vx_scalar scalar, vx_enum attribute, void* ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -316,7 +575,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryScalar(vx_scalar scalar, vx_enum attri case VX_SCALAR_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum*)ptr = scalar->data_type; + *(vx_enum*)ptr = scalar->dataType(); } else { @@ -334,280 +593,49 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryScalar(vx_scalar scalar, vx_enum attri VX_API_ENTRY vx_status VX_API_CALL vxCopyScalar(vx_scalar scalar, void* user_ptr, vx_enum usage, vx_enum user_mem_type) { - vx_status status = VX_SUCCESS; - if (vx_false_e == Reference::isValidReference(reinterpret_cast(scalar), VX_TYPE_SCALAR)) return VX_ERROR_INVALID_REFERENCE; - if (nullptr == user_ptr || VX_MEMORY_TYPE_HOST != user_mem_type) - return VX_ERROR_INVALID_PARAMETERS; - -#ifdef OPENVX_USE_OPENCL_INTEROP - void * user_ptr_given = user_ptr; - vx_enum user_mem_type_given = user_mem_type; - if (user_mem_type == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - // get ptr from OpenCL buffer for HOST - size_t size = 0; - cl_mem opencl_buf = (cl_mem)user_ptr; - cl_int cerr = clGetMemObjectInfo(opencl_buf, CL_MEM_SIZE, sizeof(size_t), &size, nullptr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyScalar: clGetMemObjectInfo(%p) => (%d)\n", - opencl_buf, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_ptr = clEnqueueMapBuffer(scalar->context->opencl_command_queue, - opencl_buf, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, size, - 0, nullptr, nullptr, &cerr); - VX_PRINT(VX_ZONE_CONTEXT, "OPENCL: vxCopyScalar: clEnqueueMapBuffer(%p,%d) => %p (%d)\n", - opencl_buf, (int)size, user_ptr, cerr); - if (cerr != CL_SUCCESS) - { - return VX_ERROR_INVALID_PARAMETERS; - } - user_mem_type = VX_MEMORY_TYPE_HOST; - } -#endif - - switch (usage) - { - case VX_READ_ONLY: status = Scalar::scalarToHostMem(scalar, user_ptr); break; - case VX_WRITE_ONLY: status = Scalar::hostMemToScalar(scalar, user_ptr); break; - - default: - status = VX_ERROR_INVALID_PARAMETERS; - break; - } - -#ifdef OPENVX_USE_OPENCL_INTEROP - if (user_mem_type_given == VX_MEMORY_TYPE_OPENCL_BUFFER) - { - clEnqueueUnmapMemObject(scalar->context->opencl_command_queue, - (cl_mem)user_ptr_given, user_ptr, 0, nullptr, nullptr); - clFinish(scalar->context->opencl_command_queue); - } -#endif - - return status; + return scalar->copy(user_ptr, usage, user_mem_type);; } /* vxCopyScalar() */ VX_API_ENTRY vx_status VX_API_CALL vxCopyScalarWithSize(vx_scalar scalar, vx_size size, void *user_ptr, vx_enum usage, vx_enum user_mem_type) { - vx_status status = VX_SUCCESS; - vx_size min_size; - if (vx_false_e == Reference::isValidReference(reinterpret_cast(scalar), VX_TYPE_SCALAR)) return VX_ERROR_INVALID_REFERENCE; - if (nullptr == user_ptr || VX_MEMORY_TYPE_HOST != user_mem_type) - return VX_ERROR_INVALID_PARAMETERS; - - - switch (usage) - { - case VX_READ_ONLY: - if (scalar->data_addr != nullptr && scalar->data_len != 0) - { - min_size = scalar->data_len > size ? size : scalar->data_len; - memcpy(user_ptr, scalar->data_addr, min_size); - } - else - { - status = VX_ERROR_NO_RESOURCES; - } - break; - case VX_WRITE_ONLY: - if (scalar->data_addr == nullptr) - { - if(nullptr == scalar->allocateScalarMemory(size)) - { - status = VX_ERROR_NO_MEMORY; - } - else - { - scalar->data_len = size; - memcpy(scalar->data_addr, user_ptr, size); - } - } - else - { - if (scalar->data_len < size) - { - void *tmp_addr = scalar->data_addr; - scalar->data_addr = nullptr; - if(nullptr == scalar->allocateScalarMemory(size)) - { - scalar->data_addr = tmp_addr; - status = VX_ERROR_NO_MEMORY; - } - else - { - free(tmp_addr); - scalar->data_len = size; - memcpy(scalar->data_addr, user_ptr, size); - } - } - else - { - scalar->data_len = size; - memcpy(scalar->data_addr, user_ptr, size); - } - } - break; - - default: - status = VX_ERROR_INVALID_PARAMETERS; - break; - } - - return status; + return scalar->copy(size, user_ptr, usage, user_mem_type); } VX_API_ENTRY vx_status VX_API_CALL vxReadScalarValue(vx_scalar scalar, void *ptr) { - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(reinterpret_cast(scalar), VX_TYPE_SCALAR) == vx_false_e) return VX_ERROR_INVALID_REFERENCE; - if (ptr == nullptr) - return VX_ERROR_INVALID_PARAMETERS; - - Osal::semWait(&scalar->lock); - Scalar::printScalarValue(scalar); - switch (scalar->data_type) - { - case VX_TYPE_CHAR: - *(vx_char *)ptr = scalar->data.chr; - break; - case VX_TYPE_INT8: - *(vx_int8 *)ptr = scalar->data.s08; - break; - case VX_TYPE_UINT8: - *(vx_uint8 *)ptr = scalar->data.u08; - break; - case VX_TYPE_INT16: - *(vx_int16 *)ptr = scalar->data.s16; - break; - case VX_TYPE_UINT16: - *(vx_uint16 *)ptr = scalar->data.u16; - break; - case VX_TYPE_INT32: - *(vx_int32 *)ptr = scalar->data.s32; - break; - case VX_TYPE_UINT32: - *(vx_uint32 *)ptr = scalar->data.u32; - break; - case VX_TYPE_INT64: - *(vx_int64 *)ptr = scalar->data.s64; - break; - case VX_TYPE_UINT64: - *(vx_uint64 *)ptr = scalar->data.u64; - break; -#ifdef EXPERIMENTAL_PLATFORM_SUPPORTS_16_FLOAT - case VX_TYPE_FLOAT16: - *(vx_float16 *)ptr = scalar->data.f16; - break; -#endif - case VX_TYPE_FLOAT32: - *(vx_float32 *)ptr = scalar->data.f32; - break; - case VX_TYPE_FLOAT64: - *(vx_float64 *)ptr = scalar->data.f64; - break; - case VX_TYPE_DF_IMAGE: - *(vx_df_image *)ptr = scalar->data.fcc; - break; - case VX_TYPE_ENUM: - *(vx_enum *)ptr = scalar->data.enm; - break; - case VX_TYPE_SIZE: - *(vx_size *)ptr = scalar->data.size; - break; - case VX_TYPE_BOOL: - *(vx_bool *)ptr = scalar->data.boolean; - break; - default: - VX_PRINT(VX_ZONE_ERROR, "some case is not covered in %s\n", __FUNCTION__); - status = VX_ERROR_NOT_SUPPORTED; - break; - } - Osal::semPost(&scalar->lock); - // ownReadFromReference(&scalar->base); - return status; + return scalar->readValue(ptr);; } VX_API_ENTRY vx_status VX_API_CALL vxWriteScalarValue(vx_scalar scalar, const void *ptr) { - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(reinterpret_cast(scalar), VX_TYPE_SCALAR) == vx_false_e) return VX_ERROR_INVALID_REFERENCE; - if (ptr == nullptr) - return VX_ERROR_INVALID_PARAMETERS; + return scalar->writeValue(ptr);; +} - Osal::semWait(&scalar->lock); - switch (scalar->data_type) +VX_API_ENTRY vx_status VX_API_CALL vxReleaseScalar(vx_scalar *s) +{ + vx_status status = VX_FAILURE; + + if (nullptr != s) { - case VX_TYPE_CHAR: - scalar->data.chr = *(vx_char *)ptr; - break; - case VX_TYPE_INT8: - scalar->data.s08 = *(vx_int8 *)ptr; - break; - case VX_TYPE_UINT8: - scalar->data.u08 = *(vx_uint8 *)ptr; - break; - case VX_TYPE_INT16: - scalar->data.s16 = *(vx_int16 *)ptr; - break; - case VX_TYPE_UINT16: - scalar->data.u16 = *(vx_uint16 *)ptr; - break; - case VX_TYPE_INT32: - scalar->data.s32 = *(vx_int32 *)ptr; - break; - case VX_TYPE_UINT32: - scalar->data.u32 = *(vx_uint32 *)ptr; - break; - case VX_TYPE_INT64: - scalar->data.s64 = *(vx_int64 *)ptr; - break; - case VX_TYPE_UINT64: - scalar->data.u64 = *(vx_uint64 *)ptr; - break; -#ifdef EXPERIMENTAL_PLATFORM_SUPPORTS_16_FLOAT - case VX_TYPE_FLOAT16: - scalar->data.f16 = *(vx_float16 *)ptr; - break; -#endif - case VX_TYPE_FLOAT32: - scalar->data.f32 = *(vx_float32 *)ptr; - break; - case VX_TYPE_FLOAT64: - scalar->data.f64 = *(vx_float64 *)ptr; - break; - case VX_TYPE_DF_IMAGE: - scalar->data.fcc = *(vx_df_image *)ptr; - break; - case VX_TYPE_ENUM: - scalar->data.enm = *(vx_enum *)ptr; - break; - case VX_TYPE_SIZE: - scalar->data.size = *(vx_size *)ptr; - break; - case VX_TYPE_BOOL: - scalar->data.boolean = *(vx_bool *)ptr; - break; - default: - VX_PRINT(VX_ZONE_ERROR, "some case is not covered in %s\n", __FUNCTION__); - status = VX_ERROR_NOT_SUPPORTED; - break; + vx_scalar scalar = *s; + if (vx_true_e == Reference::isValidReference(scalar, VX_TYPE_SCALAR)) + { + status = Reference::releaseReference((vx_reference *)s, VX_TYPE_SCALAR, VX_EXTERNAL, + nullptr); + } } - Scalar::printScalarValue(scalar); - Osal::semPost(&scalar->lock); - // ownWroteToReference(&scalar->base); + return status; -} +} /* vxReleaseScalar() */ \ No newline at end of file From dcf2e4d4ac7d948f4e6848b4874661a1a8653ca0 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Mon, 28 Jul 2025 18:14:20 -0700 Subject: [PATCH 18/34] Reworked parameter --- framework/include/vx_parameter.h | 90 +++++++++++ framework/src/vx_parameter.cpp | 269 ++++++++++++++++++++----------- 2 files changed, 269 insertions(+), 90 deletions(-) diff --git a/framework/include/vx_parameter.h b/framework/include/vx_parameter.h index d8f6d015..3d5c87dc 100644 --- a/framework/include/vx_parameter.h +++ b/framework/include/vx_parameter.h @@ -71,6 +71,96 @@ class Parameter : public Reference */ static vx_bool isValidState(vx_enum state); + /** + * @brief Returns the direction of the parameter + * + * @return vx_enum The direction of the parameter: VX_INPUT, VX_OUTPUT, or VX_BIDIRECTIONAL + * @ingroup group_int_parameter + */ + vx_enum direction() const; + + /** + * @brief Returns the index of the parameter + * + * @return vx_uint32 The index of the parameter + * @ingroup group_int_parameter + */ + vx_uint32 idx() const; + + /** + * @brief Returns the data type of the parameter + * + * @return vx_enum The type of the parameter + * @ingroup group_int_parameter + */ + vx_enum dataType() const; + + /** + * @brief Returns the state of the parameter + * + * @return vx_enum The state of the parameter: VX_PARAMETER_STATE_REQUIRED or + * VX_PARAMETER_STATE_OPTIONAL + * @ingroup group_int_parameter + */ + vx_enum state() const; + + /** + * @brief Returns the reference referred to by the parameter + * + * @return vx_reference The reference contained in the parameter + * @ingroup group_int_parameter + */ + vx_reference ref() const; + + /** + * @brief Returns the meta format contained in the parameter + * + * @return vx_meta_format The meta format contained in the parameter + * @ingroup group_int_parameter + */ + vx_meta_format metaFormat() const; + + /** + * @brief Get a parameter by index from a kernel + * + * @param kernel The kernel to get the parameter from + * @param index The index of the parameter + * @return vx_parameter The parameter object, or nullptr if not found + * @ingroup group_int_parameter + */ + static vx_parameter getKernelParameterByIndex(vx_kernel kernel, vx_uint32 index); + + /** + * @brief Get a parameter by index from a node + * + * @param node The node to get the parameter from + * @param index The index of the parameter + * @return vx_parameter The parameter object, or nullptr if not found + * @ingroup group_int_parameter + */ + static vx_parameter getParameterByIndex(vx_node node, vx_uint32 index); + + /** + * @brief Set a parameter by index on a node + * + * @param node The node to set the parameter on + * @param index The index of the parameter + * @param value The reference to set as the parameter value + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_parameter + */ + static vx_status setParameterByIndex(vx_node node, vx_uint32 index, vx_reference value); + + /** + * @brief Get a parameter by index from a node + * + * @param node The node to get the parameter from + * @param index The index of the parameter + * @return vx_parameter The parameter object, or nullptr if not found + * @ingroup group_int_parameter + */ + vx_status setParameterByReference(vx_reference value); + /*! \brief Index at which this parameter is tracked in both the node references and kernel signatures */ vx_uint32 index; /*! \brief Pointer to the node which this parameter is associated with */ diff --git a/framework/src/vx_parameter.cpp b/framework/src/vx_parameter.cpp index 85d0913d..291a7f8a 100644 --- a/framework/src/vx_parameter.cpp +++ b/framework/src/vx_parameter.cpp @@ -71,38 +71,83 @@ vx_bool Parameter::isValidState(vx_enum state) } } -void Parameter::destruct() +vx_enum Parameter::direction() const { - if (node) + if (kernel) { - if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_true_e) - { - Reference::releaseReference((vx_reference*)&node, VX_TYPE_NODE, VX_INTERNAL, nullptr); - } + return kernel->signature.directions[index]; } - if (kernel) + return VX_FAILURE; +} + +vx_uint32 Parameter::idx() const +{ + return index; +} + +vx_enum Parameter::dataType() const +{ + if (kernel && index < VX_INT_MAX_PARAMS) + { + return kernel->signature.types[index]; + } + return VX_FAILURE; +} + +vx_enum Parameter::state() const +{ + if (kernel && index < VX_INT_MAX_PARAMS) { - if (Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == vx_true_e) + return kernel->signature.states[index]; + } + return VX_FAILURE; +} + +vx_reference Parameter::ref() const +{ + if (node && index < VX_INT_MAX_PARAMS) + { + vx_reference ref = node->parameters[index]; + /* does this object have USER access? */ + if (ref) { - Reference::releaseReference((vx_reference*)&kernel, VX_TYPE_KERNEL, VX_INTERNAL, nullptr); + /*! \internal this could potentially allow the user to break + * a currently chosen optimization! We need to alert the + * system that if a write occurs to this data, put the graph + * into an unverified state. + */ + if (ref->external_count == 0) ref->extracted = vx_true_e; + ref->incrementReference(VX_EXTERNAL); } + return ref; } + + return nullptr; } -/******************************************************************************/ -/* PUBLIC API */ -/******************************************************************************/ +vx_meta_format Parameter::metaFormat() const +{ + if (kernel && index < VX_INT_MAX_PARAMS && kernel->signature.meta_formats[index]) + { + return kernel->signature.meta_formats[index]; + } -VX_API_ENTRY vx_parameter VX_API_CALL vxGetKernelParameterByIndex(vx_kernel kernel, vx_uint32 index) + return nullptr; +} + +vx_parameter Parameter::getKernelParameterByIndex(vx_kernel kernel, vx_uint32 index) { vx_parameter parameter = nullptr; - if (Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == vx_true_e) + if (Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == + vx_true_e) { if (index < VX_INT_MAX_PARAMS && index < kernel->signature.num_parameters) { - parameter = (vx_parameter)Reference::createReference(kernel->context, VX_TYPE_PARAMETER, VX_EXTERNAL, kernel->context); - if (vxGetStatus((vx_reference)parameter) == VX_SUCCESS && parameter->type == VX_TYPE_PARAMETER) + parameter = (vx_parameter)Reference::createReference(kernel->context, VX_TYPE_PARAMETER, + VX_EXTERNAL, kernel->context); + if (vxGetStatus((vx_reference)parameter) == VX_SUCCESS && + parameter->type == VX_TYPE_PARAMETER) { parameter->index = index; parameter->node = nullptr; @@ -118,20 +163,23 @@ VX_API_ENTRY vx_parameter VX_API_CALL vxGetKernelParameterByIndex(vx_kernel kern } else { - vxAddLogEntry(reinterpret_cast(kernel), VX_ERROR_INVALID_PARAMETERS, "Index %u out of range for node %s (numparams = %u)!\n", - index, kernel->name, kernel->signature.num_parameters); - parameter = (vx_parameter)vxGetErrorObject(kernel->context, VX_ERROR_INVALID_PARAMETERS); + vxAddLogEntry(reinterpret_cast(kernel), VX_ERROR_INVALID_PARAMETERS, + "Index %u out of range for node %s (numparams = %u)!\n", index, + kernel->name, kernel->signature.num_parameters); + parameter = + (vx_parameter)vxGetErrorObject(kernel->context, VX_ERROR_INVALID_PARAMETERS); } } return parameter; } -VX_API_ENTRY vx_parameter VX_API_CALL vxGetParameterByIndex(vx_node node, vx_uint32 index) +vx_parameter Parameter::getParameterByIndex(vx_node node, vx_uint32 index) { vx_parameter param = nullptr; - if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_false_e) + if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == + vx_false_e) { return param; } @@ -139,14 +187,17 @@ VX_API_ENTRY vx_parameter VX_API_CALL vxGetParameterByIndex(vx_node node, vx_uin if (node->kernel == nullptr) { /* this can probably never happen */ - vxAddLogEntry(reinterpret_cast(node), VX_ERROR_INVALID_NODE, "Node was created without a kernel! Fatal Error!\n"); + vxAddLogEntry(reinterpret_cast(node), VX_ERROR_INVALID_NODE, + "Node was created without a kernel! Fatal Error!\n"); param = (vx_parameter)vxGetErrorObject(node->context, VX_ERROR_INVALID_NODE); } else { - if (/*0 <= index &&*/ index < VX_INT_MAX_PARAMS && index < node->kernel->signature.num_parameters) + if (/*0 <= index &&*/ index < VX_INT_MAX_PARAMS && + index < node->kernel->signature.num_parameters) { - param = (vx_parameter)Reference::createReference(node->context, VX_TYPE_PARAMETER, VX_EXTERNAL, node); + param = (vx_parameter)Reference::createReference(node->context, VX_TYPE_PARAMETER, + VX_EXTERNAL, node); if (vxGetStatus((vx_reference)param) == VX_SUCCESS && param->type == VX_TYPE_PARAMETER) { param->index = index; @@ -155,13 +206,14 @@ VX_API_ENTRY vx_parameter VX_API_CALL vxGetParameterByIndex(vx_node node, vx_uin param->kernel = node->kernel; param->kernel->incrementReference(VX_INTERNAL); // if (node->parameters[index]) - // node->parameters[index]->incrementReference(VX_INTERNAL); + // node->parameters[index]->incrementReference(VX_INTERNAL); } } else { - vxAddLogEntry(reinterpret_cast(node), VX_ERROR_INVALID_PARAMETERS, "Index %u out of range for node %s (numparams = %u)!\n", - index, node->kernel->name, node->kernel->signature.num_parameters); + vxAddLogEntry(reinterpret_cast(node), VX_ERROR_INVALID_PARAMETERS, + "Index %u out of range for node %s (numparams = %u)!\n", index, + node->kernel->name, node->kernel->signature.num_parameters); param = (vx_parameter)vxGetErrorObject(node->context, VX_ERROR_INVALID_PARAMETERS); } } @@ -169,41 +221,23 @@ VX_API_ENTRY vx_parameter VX_API_CALL vxGetParameterByIndex(vx_node node, vx_uin return param; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseParameter(vx_parameter* param) -{ - vx_status status = VX_FAILURE; - - if (param != nullptr) - { - vx_parameter this_param = *param; - if (Reference::isValidReference((vx_reference)this_param, VX_TYPE_PARAMETER) == vx_true_e) - { - status = Reference::releaseReference((vx_reference*)param, VX_TYPE_PARAMETER, VX_EXTERNAL, nullptr); - } - } - - return status; -} - - -VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 index, vx_reference value) +vx_status Parameter::setParameterByIndex(vx_node node, vx_uint32 index, vx_reference value) { vx_status status = VX_SUCCESS; vx_enum type = 0; vx_enum data_type = 0; - if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_false_e) + if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == + vx_false_e) { VX_PRINT(VX_ZONE_ERROR, "Supplied node was not actually a node\n"); status = VX_ERROR_INVALID_REFERENCE; goto exit; } - VX_PRINT(VX_ZONE_PARAMETER, "Attempting to set parameter[%u] on %s (enum:%d) to " VX_FMT_REF "\n", - index, - node->kernel->name, - node->kernel->enumeration, - value); + VX_PRINT(VX_ZONE_PARAMETER, + "Attempting to set parameter[%u] on %s (enum:%d) to " VX_FMT_REF "\n", index, + node->kernel->name, node->kernel->enumeration, value); /* is the index out of bounds? */ if ((index >= node->kernel->signature.num_parameters) || (index >= VX_INT_MAX_PARAMS)) @@ -223,7 +257,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 /* if it's required, it's got to exist */ if (value == nullptr) { - value = Reference::createReference(node->context, node->kernel->signature.types[index], VX_INTERNAL, node->context); + value = Reference::createReference(node->context, node->kernel->signature.types[index], + VX_INTERNAL, node->context); } /* validate reference */ @@ -255,8 +290,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 goto exit; } } - else if ( (type == VX_TYPE_SCALAR) && - (vxQueryScalar((vx_scalar)value, VX_SCALAR_TYPE, &data_type, sizeof(data_type)) == VX_SUCCESS)) + else if ((type == VX_TYPE_SCALAR) && + (vxQueryScalar((vx_scalar)value, VX_SCALAR_TYPE, &data_type, sizeof(data_type)) == + VX_SUCCESS)) { if (data_type != node->kernel->signature.types[index]) { @@ -277,8 +313,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 } } - if (node->parameters[index] && - node->parameters[index]->delay != nullptr) + if (node->parameters[index] && node->parameters[index]->delay != nullptr) { // we already have a delay element here */ vx_bool res = Delay::removeAssociationToDelay(node->parameters[index], node, index); @@ -290,7 +325,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 } } - if (value->delay!=nullptr) { + if (value->delay != nullptr) + { /* the new parameter is a delay element */ vx_bool res = Delay::addAssociationToDelay(value, node, index); if (res == vx_false_e) @@ -309,17 +345,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 exit: if (status == VX_SUCCESS) { - VX_PRINT(VX_ZONE_PARAMETER, "Assigned Node[%u] %p type:%08x ref=" VX_FMT_REF "\n", - index, node, type, value); + VX_PRINT(VX_ZONE_PARAMETER, "Assigned Node[%u] %p type:%08x ref=" VX_FMT_REF "\n", index, + node, type, value); } - else if (vx_true_e == Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE)) + else if (vx_true_e == + Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE)) { - VX_PRINT(VX_ZONE_ERROR, "Specified: parameter[%u] type:%08x => " VX_FMT_REF "\n", - index, type, value); - VX_PRINT(VX_ZONE_ERROR, "Required: parameter[%u] dir:%d type:%08x\n", - index, - node->kernel->signature.directions[index], - node->kernel->signature.types[index]); + VX_PRINT(VX_ZONE_ERROR, "Specified: parameter[%u] type:%08x => " VX_FMT_REF "\n", index, + type, value); + VX_PRINT(VX_ZONE_ERROR, "Required: parameter[%u] dir:%d type:%08x\n", index, + node->kernel->signature.directions[index], node->kernel->signature.types[index]); } else { @@ -329,16 +364,66 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 return status; } -VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByReference(vx_parameter parameter, vx_reference value) +vx_status Parameter::setParameterByReference(vx_reference value) { vx_status status = VX_ERROR_INVALID_PARAMETERS; - if (Reference::isValidReference(reinterpret_cast(parameter), VX_TYPE_PARAMETER) == vx_true_e) + + if (node) + { + status = Parameter::setParameterByIndex(node, index, value); + } + + return status; +} + +void Parameter::destruct() +{ + if (node) + { + if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == + vx_true_e) + { + Reference::releaseReference((vx_reference *)&node, VX_TYPE_NODE, VX_INTERNAL, nullptr); + } + } + if (kernel) { - if (parameter->node) + if (Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == + vx_true_e) { - status = vxSetParameterByIndex(parameter->node, parameter->index, value); + Reference::releaseReference((vx_reference *)&kernel, VX_TYPE_KERNEL, VX_INTERNAL, + nullptr); } } +} + +/******************************************************************************/ +/* PUBLIC API */ +/******************************************************************************/ + +VX_API_ENTRY vx_parameter VX_API_CALL vxGetKernelParameterByIndex(vx_kernel kernel, vx_uint32 index) +{ + return Parameter::getKernelParameterByIndex(kernel, index); +} + +VX_API_ENTRY vx_parameter VX_API_CALL vxGetParameterByIndex(vx_node node, vx_uint32 index) +{ + return Parameter::getParameterByIndex(node, index); +} + +VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByIndex(vx_node node, vx_uint32 index, + vx_reference value) +{ + return Parameter::setParameterByIndex(node, index, value); +} + +VX_API_ENTRY vx_status VX_API_CALL vxSetParameterByReference(vx_parameter parameter, vx_reference value) +{ + vx_status status = VX_ERROR_INVALID_PARAMETERS; + if (Reference::isValidReference(reinterpret_cast(parameter), VX_TYPE_PARAMETER) == vx_true_e) + { + status = parameter->setParameterByReference(value); + } return status; } @@ -351,25 +436,25 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryParameter(vx_parameter parameter, vx_e { case VX_PARAMETER_DIRECTION: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - *(vx_enum *)ptr = parameter->kernel->signature.directions[parameter->index]; + *(vx_enum *)ptr = parameter->direction(); else status = VX_ERROR_INVALID_PARAMETERS; break; case VX_PARAMETER_INDEX: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - *(vx_uint32 *)ptr = parameter->index; + *(vx_uint32 *)ptr = parameter->idx(); else status = VX_ERROR_INVALID_PARAMETERS; break; case VX_PARAMETER_TYPE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - *(vx_enum *)ptr = parameter->kernel->signature.types[parameter->index]; + *(vx_enum *)ptr = parameter->dataType(); else status = VX_ERROR_INVALID_PARAMETERS; break; case VX_PARAMETER_STATE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - *(vx_enum *)ptr = (vx_enum)parameter->kernel->signature.states[parameter->index]; + *(vx_enum *)ptr = parameter->state(); else status = VX_ERROR_INVALID_PARAMETERS; break; @@ -378,20 +463,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryParameter(vx_parameter parameter, vx_e { if (parameter->node) { - vx_reference ref = parameter->node->parameters[parameter->index]; - /* does this object have USER access? */ - if (ref) - { - /*! \internal this could potentially allow the user to break - * a currently chosen optimization! We need to alert the - * system that if a write occurs to this data, put the graph - * into an unverified state. - */ - if (ref->external_count == 0) - ref->extracted = vx_true_e; - ref->incrementReference(VX_EXTERNAL); - } - *(vx_reference *)ptr = (vx_reference)ref; + *(vx_reference *)ptr = parameter->ref(); } else status = VX_ERROR_NOT_SUPPORTED; @@ -402,9 +474,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryParameter(vx_parameter parameter, vx_e case VX_PARAMETER_META_FORMAT: if (VX_CHECK_PARAM(ptr, size, vx_meta_format, 0x3)) { - if(nullptr != parameter->kernel->signature.meta_formats[parameter->index]) + if (nullptr != parameter->kernel->signature.meta_formats[parameter->index]) { - *(vx_meta_format *)ptr = parameter->kernel->signature.meta_formats[parameter->index]; + *(vx_meta_format *)ptr = parameter->metaFormat(); } else { @@ -425,3 +497,20 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryParameter(vx_parameter parameter, vx_e } return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseParameter(vx_parameter *param) +{ + vx_status status = VX_FAILURE; + + if (param != nullptr) + { + vx_parameter this_param = *param; + if (Reference::isValidReference((vx_reference)this_param, VX_TYPE_PARAMETER) == vx_true_e) + { + status = Reference::releaseReference((vx_reference *)param, VX_TYPE_PARAMETER, + VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From b638a48d2a30c0393f495dffc220900705c6c289 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Mon, 28 Jul 2025 19:06:05 -0700 Subject: [PATCH 19/34] Reworked node --- framework/include/vx_node.h | 144 ++++++++++ framework/src/vx_node.cpp | 551 +++++++++++++++++++++--------------- 2 files changed, 472 insertions(+), 223 deletions(-) diff --git a/framework/include/vx_node.h b/framework/include/vx_node.h index 2850fa72..aee347f9 100644 --- a/framework/include/vx_node.h +++ b/framework/include/vx_node.h @@ -78,6 +78,150 @@ class Node : public Reference */ void setParameter(vx_uint32 index, vx_reference value); + /** + * @brief Set the target for the node + * + * @param target_enum The target enum to set + * @param target_string The target string to set + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_node + */ + vx_status setTarget(vx_enum target_enum, const char *target_string); + + /** + * @brief Get the local data size of the node + * + * @return vx_size The local data size + * @ingroup group_int_node + */ + vx_size localDataSize() const; + + /** + * @brief Get the local data pointer of the node + * + * @return vx_ptr_t The local data pointer + * @ingroup group_int_node + */ + vx_ptr_t localDataPtr() const; + + /** + * @brief Get the global data size of the node + * + * @return vx_size The global data size + * @ingroup group_int_node + */ + vx_size globalDataSize() const; + + /** + * @brief Get the global data pointer of the node + * + * @return vx_ptr_t The global data pointer + * @ingroup group_int_node + */ + vx_ptr_t globalDataPtr() const; + + /** + * @brief Get the border mode of the node + * + * @return vx_border_t The border mode + * @ingroup group_int_node + */ + vx_border_t border() const; + + /** + * @brief Get the number of parameters of the node + * + * @return vx_uint32 The number of parameters + * @ingroup group_int_node + */ + vx_uint32 numParams() const; + + /** + * @brief Get the performance of the node + * + * @return vx_perf_t The performance metrics + * @ingroup group_int_node + */ + vx_perf_t performance() const; + + /** + * @brief Get the status of the node + * + * @return vx_status The status of the node + * @ingroup group_int_node + */ + vx_status getStatus() const; + + /** + * @brief Set the Node Callback Fn object + * + * @param callback The callback function to set + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_node + */ + vx_status setCallbackFn(vx_nodecomplete_f callback); + + /** + * @brief Is the node replicated? + * + * @return vx_bool True if the node is replicated, false otherwise + * @ingroup group_int_node + */ + vx_bool isReplicated() const; + + /** + * @brief Get the replicated parameters flags + * + * @return const vx_bool* The array of flags indicating which parameters are replicated + * @ingroup group_int_node + */ + const vx_bool *replicatedFlags() const; + + /** + * @brief Get the state of the node + * + * @return vx_enum The state of the node + * @ingroup group_int_node + */ + vx_enum getState() const; + + /** + * @brief Get the valid rectangle reset flag + * + * @return vx_bool The valid rectangle reset flag + * @ingroup group_int_node + */ + vx_bool validRectReset() const; + + /** + * @brief Get the OpenCL command queue for the node + * + * @return cl_command_queue The OpenCL command queue + * @ingroup group_int_node + */ + cl_command_queue clCommandQueue() const; + + /** + * @brief Get the callback function for the node + * + * @return vx_nodecomplete_f The callback function + * @ingroup group_int_node + */ + vx_nodecomplete_f callbackFn() const; + + /** + * @brief Replicate the node in the graph + * + * @param graph The graph to replicate the node in + * @param first_node The first node to replicate + * @param replicate The array of flags indicating which parameters to replicate + * @param number_of_parameters The number of parameters to replicate + * @return vx_status VX_SUCCESS on success, error code otherwise + * @ingroup group_int_node + */ + static vx_status replicateNode(vx_graph graph, vx_node first_node, vx_bool *replicate, + vx_uint32 number_of_parameters); + /*! \brief Used to completely destroy a node. * \ingroup group_int_node */ diff --git a/framework/src/vx_node.cpp b/framework/src/vx_node.cpp index 83278598..33c6ccb4 100644 --- a/framework/src/vx_node.cpp +++ b/framework/src/vx_node.cpp @@ -58,6 +58,301 @@ void Node::setParameter(vx_uint32 index, vx_reference value) parameters[index] = (vx_reference)value; } +vx_status Node::setTarget(vx_enum target_enum, const char *target_string) +{ + vx_status status = VX_FAILURE; + vx_kernel kernel = nullptr; + vx_uint32 rt = 0; + vx_uint32 t = 0; + + switch (target_enum) + { + case VX_TARGET_ANY: + { + for (t = 0; (t < context->num_targets) && (kernel == nullptr); t++) + { + rt = context->priority_targets[t]; + kernel = context->targets[rt]->findKernelByEnum(this->kernel->enumeration); + if (nullptr != kernel) break; + } + break; + } + case VX_TARGET_STRING: + { + size_t len = strlen(target_string); + std::string target_lower_string(len + 1, '\0'); + if (target_lower_string.size() > 0) + { + unsigned int i; + /* to lower case */ + for (i = 0; target_string[i] != 0; i++) + { + target_lower_string[i] = std::tolower(target_string[i]); + } + + for (t = 0; (t < context->num_targets) && (kernel == nullptr); t++) + { + rt = context->priority_targets[t]; + if (Target::matchTargetNameWithString(context->targets[rt]->name, + target_lower_string.c_str()) == vx_true_e) + { + kernel = context->targets[rt]->findKernelByEnum(this->kernel->enumeration); + } + } + } + break; + } + default: + status = VX_ERROR_NOT_SUPPORTED; + break; + } + + if (kernel != nullptr) /* target/kernel were found */ + { + kernel->decrementReference(VX_INTERNAL); + this->kernel = kernel; + kernel->incrementReference(VX_INTERNAL); + + affinity = rt; + graph->reverify = graph->verified; + graph->verified = vx_false_e; + graph->state = VX_GRAPH_STATE_UNVERIFIED; + status = VX_SUCCESS; + } + else /* target/kernel were not found */ + { + status = VX_ERROR_NOT_SUPPORTED; + } + + return status; +} + +vx_status Node::setCallbackFn(vx_nodecomplete_f callback) +{ + if ((callback) && (this->callback)) + { + VX_PRINT(VX_ZONE_ERROR, "Attempting to overriding existing callback %p on Node %s!\n", + this->callback, kernel->name); + status = VX_ERROR_NOT_SUPPORTED; + } + else + { + this->callback = callback; + status = VX_SUCCESS; + } + + return status; +} + +vx_perf_t Node::performance() const +{ + VX_PRINT(VX_ZONE_NODE, "Node performance: tmp=%llu, beg=%llu, end=%llu, sum=%llu, avg=%llu, min=%llu, num=%llu, max=%llu\n", + perf.tmp, perf.beg, perf.end, perf.sum, perf.avg, perf.min, perf.num, perf.max); + + return perf; +} + +vx_status Node::getStatus() const +{ + return status; +} + +vx_size Node::localDataSize() const +{ + VX_PRINT(VX_ZONE_NODE, "Local data size %d set!\n", attributes.localDataSize); + return attributes.localDataSize; +} + +vx_ptr_t Node::localDataPtr() const +{ + VX_PRINT(VX_ZONE_NODE, "Local data pointer %p set!\n", attributes.localDataPtr); + return attributes.localDataPtr; +} + +vx_size Node::globalDataSize() const +{ + VX_PRINT(VX_ZONE_NODE, "Global data size %d set!\n", attributes.globalDataSize); + return attributes.globalDataSize; +} + +vx_ptr_t Node::globalDataPtr() const +{ + VX_PRINT(VX_ZONE_NODE, "Global data pointer %p set!\n", attributes.globalDataPtr); + return attributes.globalDataPtr; +} + +vx_border_t Node::border() const +{ + VX_PRINT(VX_ZONE_NODE, "Border mode %x set!\n", attributes.borders.mode); + return attributes.borders; +} + +vx_uint32 Node::numParams() const +{ + vx_uint32 numParams = kernel->signature.num_parameters; + VX_PRINT(VX_ZONE_NODE, "Number of node parameters is %d\n", numParams); + return numParams; +} + +vx_bool Node::isReplicated() const +{ + vx_bool is_replicated = this->is_replicated; + if (vx_true_e == is_replicated) + VX_PRINT(VX_ZONE_NODE, "Node is replicated\n"); + else + VX_PRINT(VX_ZONE_NODE, "Number is not replicated\n"); + return is_replicated; +} + +const vx_bool* Node::replicatedFlags() const +{ + return replicated_flags; +} + +vx_bool Node::validRectReset() const +{ + vx_bool valid_rect_reset = this->attributes.valid_rect_reset; + if (vx_true_e == valid_rect_reset) + VX_PRINT(VX_ZONE_NODE, "Valid rect to be reset to full image\n"); + else + VX_PRINT(VX_ZONE_NODE, "Valid rect to be calculated\n"); + return valid_rect_reset; +} + +cl_command_queue Node::clCommandQueue() const +{ + return context->opencl_command_queue; +} + +vx_enum Node::getState() const +{ + return state; +} + +vx_nodecomplete_f Node::callbackFn() const +{ + return callback; +} + +vx_status Node::replicateNode(vx_graph graph, vx_node first_node, vx_bool *replicate, + vx_uint32 number_of_parameters) +{ + vx_uint32 n; + vx_uint32 p; + vx_uint32 numParams = 0; + vx_size num_of_replicas = 0; + vx_status status = VX_SUCCESS; + + if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) != + vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Graph %p was invalid!\n", graph); + vxAddLogEntry((vx_reference)graph, VX_ERROR_INVALID_REFERENCE, "Graph %p as invalid!\n", + graph); + status = VX_ERROR_INVALID_REFERENCE; + } + else if (Reference::isValidReference(reinterpret_cast(first_node), + VX_TYPE_NODE) != vx_true_e) + { + VX_PRINT(VX_ZONE_ERROR, "Node %p was invalid!\n", first_node); + vxAddLogEntry((vx_reference)first_node, VX_ERROR_INVALID_REFERENCE, "Node %p as invalid!\n", + first_node); + status = VX_ERROR_INVALID_REFERENCE; + } + else if (first_node->graph != graph) + { + status = VX_FAILURE; + } + else if (replicate == nullptr) + { + status = VX_ERROR_INVALID_PARAMETERS; + } + else + { + /* validate replicated params */ + status = vxQueryNode(first_node, VX_NODE_PARAMETERS, &numParams, sizeof(numParams)); + if (VX_SUCCESS == status) + { + if (numParams != number_of_parameters) status = VX_ERROR_INVALID_PARAMETERS; + } + + for (p = 0; (VX_SUCCESS == status) && p < number_of_parameters; p++) + { + vx_parameter param = 0; + vx_reference ref = 0; + vx_enum type = 0; + vx_enum state = 0; + vx_enum dir = 0; + + param = vxGetParameterByIndex(first_node, p); + + vxQueryParameter(param, VX_PARAMETER_TYPE, &type, sizeof(vx_enum)); + vxQueryParameter(param, VX_PARAMETER_REF, &ref, sizeof(vx_reference)); + vxQueryParameter(param, VX_PARAMETER_STATE, &state, sizeof(vx_enum)); + vxQueryParameter(param, VX_PARAMETER_DIRECTION, &dir, sizeof(vx_enum)); + + if (replicate[p] == vx_false_e && (dir == VX_OUTPUT || dir == VX_BIDIRECTIONAL)) + status = VX_FAILURE; + + if (replicate[p] == vx_true_e) + { + if (Reference::isValidReference(ref, type) == vx_true_e) + { + vx_size items = 0; + if (ref->scope->type == VX_TYPE_PYRAMID && + Reference::isValidReference(ref->scope, VX_TYPE_PYRAMID) == vx_true_e) + { + vx_pyramid pyramid = (vx_pyramid)ref->scope; + vxQueryPyramid(pyramid, VX_PYRAMID_LEVELS, &items, sizeof(vx_size)); + } + else if (ref->scope->type == VX_TYPE_OBJECT_ARRAY && + Reference::isValidReference(ref->scope, VX_TYPE_OBJECT_ARRAY) == + vx_true_e) + { + vx_object_array object_array = (vx_object_array)ref->scope; + vxQueryObjectArray(object_array, VX_OBJECT_ARRAY_NUMITEMS, &items, + sizeof(vx_size)); + } + else + { + status = VX_FAILURE; + } + + if (num_of_replicas == 0) + { + num_of_replicas = items; + } + + if (num_of_replicas != 0 && items != num_of_replicas) + { + status = VX_FAILURE; + } + } + else + { + status = VX_FAILURE; + } + } + + vxReleaseReference(&ref); + vxReleaseParameter(¶m); + } + } + + if (VX_SUCCESS == status) + { + /* set replicate flag for node */ + first_node->is_replicated = vx_true_e; + + for (n = 0; n < number_of_parameters; n++) + { + first_node->replicated_flags[n] = replicate[n]; + } + } + + return status; +} + void Node::destruct() { vx_uint32 p = 0; @@ -326,7 +621,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_PERFORMANCE: if (VX_CHECK_PARAM(ptr, size, vx_perf_t, 0x3)) { - memcpy(ptr, &node->perf, size); + vx_perf_t perf = node->performance(); + memcpy(ptr, &perf, size); } else { @@ -336,7 +632,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_STATUS: if (VX_CHECK_PARAM(ptr, size, vx_status, 0x3)) { - *(vx_status *)ptr = node->status; + *(vx_status *)ptr = node->getStatus(); } else { @@ -346,7 +642,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_LOCAL_DATA_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = node->attributes.localDataSize; + *(vx_size *)ptr = node->localDataSize(); } else { @@ -356,7 +652,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_LOCAL_DATA_PTR: if (VX_CHECK_PARAM(ptr, size, vx_ptr_t, 0x3)) { - *(vx_ptr_t *)ptr = node->attributes.localDataPtr; + *(vx_ptr_t *)ptr = node->localDataPtr(); } else { @@ -367,7 +663,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_GLOBAL_DATA_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = node->attributes.globalDataSize; + *(vx_size *)ptr = node->globalDataSize(); } else { @@ -377,7 +673,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_GLOBAL_DATA_PTR: if (VX_CHECK_PARAM(ptr, size, vx_ptr_t, 0x3)) { - *(vx_ptr_t *)ptr = node->attributes.globalDataPtr; + *(vx_ptr_t *)ptr = node->globalDataPtr(); } else { @@ -388,8 +684,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_BORDER: if (VX_CHECK_PARAM(ptr, size, vx_border_t, 0x3)) { - VX_PRINT(VX_ZONE_NODE, "Border mode %x set!\n", node->attributes.borders.mode); - memcpy((vx_border_t *)ptr, &node->attributes.borders, sizeof(vx_border_t)); + *(vx_border_t *)ptr = node->border(); } else { @@ -399,9 +694,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_PARAMETERS: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - vx_uint32 numParams = node->kernel->signature.num_parameters; - VX_PRINT(VX_ZONE_NODE, "Number of node parameters is %d\n", numParams); - memcpy((vx_uint32*)ptr, &numParams, sizeof(numParams)); + *(vx_uint32*)ptr = node->numParams(); } else { @@ -411,12 +704,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_IS_REPLICATED: if (VX_CHECK_PARAM(ptr, size, vx_bool, 0x3)) { - vx_bool is_replicated = node->is_replicated; - if (vx_true_e == is_replicated) - VX_PRINT(VX_ZONE_NODE, "Node is replicated\n"); - else - VX_PRINT(VX_ZONE_NODE, "Number is not replicated\n"); - memcpy((vx_bool*)ptr, &is_replicated, sizeof(is_replicated)); + *(vx_bool *)ptr = node->isReplicated(); } else { @@ -428,10 +716,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, vx_size sz = sizeof(vx_bool)*node->kernel->signature.num_parameters; if (size == sz && ((vx_size)ptr & 0x3) == 0) { - vx_uint32 i = 0; - vx_uint32 numParams = node->kernel->signature.num_parameters; - for (i = 0; i < numParams; i++) - ((vx_bool*)ptr)[i] = node->replicated_flags[i]; + memcpy((vx_bool *)ptr, node->replicatedFlags(), + node->kernel->signature.num_parameters * sizeof(vx_bool)); } else { @@ -442,12 +728,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_VALID_RECT_RESET: if (VX_CHECK_PARAM(ptr, size, vx_bool, 0x3)) { - vx_bool valid_rect_reset = node->attributes.valid_rect_reset; - if (vx_true_e == valid_rect_reset) - VX_PRINT(VX_ZONE_NODE, "Valid rect to be reset to full image\n"); - else - VX_PRINT(VX_ZONE_NODE, "Valid rect to be calculated\n"); - memcpy((vx_bool*)ptr, &valid_rect_reset, sizeof(valid_rect_reset)); + *(vx_bool *)ptr = node->validRectReset(); } else { @@ -458,7 +739,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_CL_COMMAND_QUEUE: if (VX_CHECK_PARAM(ptr, size, cl_command_queue, 0x3)) { - *(cl_command_queue *)ptr = node->context->opencl_command_queue; + *(cl_command_queue *)ptr = node->clCommandQueue(); } else { @@ -469,7 +750,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryNode(vx_node node, vx_enum attribute, case VX_NODE_STATE: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = node->state; + *(vx_enum *)ptr = node->getState(); } else { @@ -560,20 +841,6 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetNodeAttribute(vx_node node, vx_enum attr return status; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseNode(vx_node* node) -{ - vx_status status = VX_ERROR_INVALID_REFERENCE; - if (nullptr != node) - { - vx_node n = *node; - if (vx_true_e == Reference::isValidReference(reinterpret_cast(n), VX_TYPE_NODE)) - { - status = Reference::releaseReference((vx_reference*)node, VX_TYPE_NODE, VX_EXTERNAL, nullptr); - } - } - return status; -} - VX_API_ENTRY vx_status VX_API_CALL vxRemoveNode(vx_node* node) { vx_status status = VX_ERROR_INVALID_REFERENCE; @@ -602,16 +869,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAssignNodeCallback(vx_node node, vx_nodecom if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_true_e) { - if ((callback) && (node->callback)) - { - VX_PRINT(VX_ZONE_ERROR, "Attempting to overriding existing callback %p on Node %s!\n", node->callback, node->kernel->name); - status = VX_ERROR_NOT_SUPPORTED; - } - else - { - node->callback = callback; - status = VX_SUCCESS; - } + status = node->setCallbackFn(callback); } return status; } @@ -622,122 +880,14 @@ VX_API_ENTRY vx_nodecomplete_f VX_API_CALL vxRetrieveNodeCallback(vx_node node) if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_true_e) { - cb = node->callback; + cb = node->callbackFn(); } return cb; } VX_API_ENTRY vx_status VX_API_CALL vxReplicateNode(vx_graph graph, vx_node first_node, vx_bool replicate[], vx_uint32 number_of_parameters) { - vx_uint32 n; - vx_uint32 p; - vx_uint32 numParams = 0; - vx_size num_of_replicas = 0; - vx_status status = VX_SUCCESS; - - if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) != vx_true_e) - { - VX_PRINT(VX_ZONE_ERROR, "Graph %p was invalid!\n", graph); - vxAddLogEntry((vx_reference)graph, VX_ERROR_INVALID_REFERENCE, "Graph %p as invalid!\n", graph); - status = VX_ERROR_INVALID_REFERENCE; - } - else if (Reference::isValidReference(reinterpret_cast(first_node), VX_TYPE_NODE) != vx_true_e) - { - VX_PRINT(VX_ZONE_ERROR, "Node %p was invalid!\n", first_node); - vxAddLogEntry((vx_reference)first_node, VX_ERROR_INVALID_REFERENCE, "Node %p as invalid!\n", first_node); - status = VX_ERROR_INVALID_REFERENCE; - } - else if (first_node->graph != graph) - { - status = VX_FAILURE; - } - else if (replicate == nullptr) - { - status = VX_ERROR_INVALID_PARAMETERS; - } - else - { - /* validate replicated params */ - status = vxQueryNode(first_node, VX_NODE_PARAMETERS, &numParams, sizeof(numParams)); - if (VX_SUCCESS == status) - { - if (numParams != number_of_parameters) - status = VX_ERROR_INVALID_PARAMETERS; - } - - for (p = 0; (VX_SUCCESS == status) && p < number_of_parameters; p++) - { - vx_parameter param = 0; - vx_reference ref = 0; - vx_enum type = 0; - vx_enum state = 0; - vx_enum dir = 0; - - param = vxGetParameterByIndex(first_node, p); - - vxQueryParameter(param, VX_PARAMETER_TYPE, &type, sizeof(vx_enum)); - vxQueryParameter(param, VX_PARAMETER_REF, &ref, sizeof(vx_reference)); - vxQueryParameter(param, VX_PARAMETER_STATE, &state, sizeof(vx_enum)); - vxQueryParameter(param, VX_PARAMETER_DIRECTION, &dir, sizeof(vx_enum)); - - if (replicate[p] == vx_false_e && (dir == VX_OUTPUT || dir == VX_BIDIRECTIONAL)) - status = VX_FAILURE; - - if (replicate[p] == vx_true_e) - { - if (Reference::isValidReference(ref, type) == vx_true_e) - { - vx_size items = 0; - if (ref->scope->type == VX_TYPE_PYRAMID && - Reference::isValidReference(ref->scope, VX_TYPE_PYRAMID) == vx_true_e) - { - vx_pyramid pyramid = (vx_pyramid)ref->scope; - vxQueryPyramid(pyramid, VX_PYRAMID_LEVELS, &items, sizeof(vx_size)); - } - else if (ref->scope->type == VX_TYPE_OBJECT_ARRAY && - Reference::isValidReference(ref->scope, VX_TYPE_OBJECT_ARRAY) == vx_true_e) - { - vx_object_array object_array = (vx_object_array)ref->scope; - vxQueryObjectArray(object_array, VX_OBJECT_ARRAY_NUMITEMS, &items, sizeof(vx_size)); - } - else - { - status = VX_FAILURE; - } - - if (num_of_replicas == 0) - { - num_of_replicas = items; - } - - if (num_of_replicas != 0 && items != num_of_replicas) - { - status = VX_FAILURE; - } - } - else - { - status = VX_FAILURE; - } - } - - vxReleaseReference(&ref); - vxReleaseParameter(¶m); - } - } - - if (VX_SUCCESS == status) - { - /* set replicate flag for node */ - first_node->is_replicated = vx_true_e; - - for (n = 0; n < number_of_parameters; n++) - { - first_node->replicated_flags[n] = replicate[n]; - } - } - - return status; + return Node::replicateNode(graph, first_node, replicate, number_of_parameters); } VX_API_ENTRY vx_status VX_API_CALL vxSetNodeTarget(vx_node node, vx_enum target_enum, const char* target_string) @@ -745,68 +895,23 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetNodeTarget(vx_node node, vx_enum target_ vx_status status = VX_ERROR_INVALID_REFERENCE; if (Reference::isValidReference(reinterpret_cast(node), VX_TYPE_NODE) == vx_true_e) { - vx_context context = node->context; - vx_kernel kernel = nullptr; - vx_uint32 rt = 0; - vx_uint32 t = 0; - - switch (target_enum) - { - case VX_TARGET_ANY: - for (t = 0; (t < context->num_targets) && (kernel == nullptr); t++) - { - rt = context->priority_targets[t]; - kernel = context->targets[rt]->findKernelByEnum(node->kernel->enumeration); - if (nullptr != kernel) - break; - } - break; - - case VX_TARGET_STRING: - { - size_t len = strlen(target_string); - std::string target_lower_string(len + 1, '\0'); - if (target_lower_string.size() > 0) - { - unsigned int i; - /* to lower case */ - for (i = 0; target_string[i] != 0; i++) - { - target_lower_string[i] = std::tolower(target_string[i]); - } - - for (t = 0; (t < context->num_targets) && (kernel == nullptr); t++) - { - rt = context->priority_targets[t]; - if (Target::matchTargetNameWithString(context->targets[rt]->name, target_lower_string.c_str()) == vx_true_e) - { - kernel = context->targets[rt]->findKernelByEnum(node->kernel->enumeration); - } - } - } - } - break; + status = node->setTarget(target_enum, target_string); + } + return status; +} - default: - status = VX_ERROR_NOT_SUPPORTED; - break; - } - if (kernel != nullptr) /* target/kernel were found */ - { - kernel->decrementReference(VX_INTERNAL); - node->kernel = kernel; - kernel->incrementReference(VX_INTERNAL); - - node->affinity = rt; - node->graph->reverify = node->graph->verified; - node->graph->verified = vx_false_e; - node->graph->state = VX_GRAPH_STATE_UNVERIFIED; - status = VX_SUCCESS; - } - else /* target/kernel were not found */ +VX_API_ENTRY vx_status VX_API_CALL vxReleaseNode(vx_node *node) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + if (nullptr != node) + { + vx_node n = *node; + if (vx_true_e == + Reference::isValidReference(reinterpret_cast(n), VX_TYPE_NODE)) { - status = VX_ERROR_NOT_SUPPORTED; + status = Reference::releaseReference((vx_reference *)node, VX_TYPE_NODE, VX_EXTERNAL, + nullptr); } } return status; -} +} \ No newline at end of file From b53f297f57ab318b0bae128b243526116f4acf23 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Mon, 28 Jul 2025 19:19:54 -0700 Subject: [PATCH 20/34] More node cleanup --- framework/include/vx_distribution.h | 2 +- framework/include/vx_node.h | 20 ++++++++++++++++++-- framework/src/vx_node.cpp | 14 ++++++++++++-- targets/c_model/vx_canny.cpp | 10 +++++----- targets/c_model/vx_harris.cpp | 10 +++++----- targets/c_model/vx_pyramid.cpp | 10 +++++----- targets/c_model/vx_scale.cpp | 12 ++++++------ targets/tiling/vx_scale.cpp | 12 ++++++------ targets/venum/vx_harris.cpp | 10 +++++----- targets/venum/vx_pyramid.cpp | 4 ++-- 10 files changed, 65 insertions(+), 39 deletions(-) diff --git a/framework/include/vx_distribution.h b/framework/include/vx_distribution.h index e73b176c..0221e955 100644 --- a/framework/include/vx_distribution.h +++ b/framework/include/vx_distribution.h @@ -50,7 +50,7 @@ class Distribution : public Reference * @ingroup group_int_distribution */ vx_size dims() const; - + /** * @brief Get the range of the distribution * diff --git a/framework/include/vx_node.h b/framework/include/vx_node.h index aee347f9..45caeb2e 100644 --- a/framework/include/vx_node.h +++ b/framework/include/vx_node.h @@ -43,14 +43,14 @@ enum vx_node_attribute_internal_e { * parameters. * \ingroup group_int_node */ -vx_status ownSetChildGraphOfNode(vx_node node, vx_graph graph); +vx_status vxSetChildGraphOfNode(vx_node node, vx_graph graph); /*! \brief Retrieves the handle of the child graph, if it exists. * \param [in] node The node. * \return Returns the handle of the child graph or zero if it doesn't have one. * \ingroup group_int_node */ -vx_graph ownGetChildGraphOfNode(vx_node node); +vx_graph vxGetChildGraphOfNode(vx_node node); /*! \brief The internal representation of a node. * \ingroup group_int_node @@ -222,6 +222,22 @@ class Node : public Reference static vx_status replicateNode(vx_graph graph, vx_node first_node, vx_bool *replicate, vx_uint32 number_of_parameters); + /*! \brief Used to set the graph as a child of the node within another graph. + * \param [in] node The node. + * \param [in] graph The child graph. + * \retval VX_ERROR_INVALID_GRAPH The Graph's parameters do not match the Node's + * parameters. + * \ingroup group_int_node + */ + static vx_status setChildGraphOfNode(vx_node node, vx_graph graph); + + /*! \brief Retrieves the handle of the child graph, if it exists. + * \param [in] node The node. + * \return Returns the handle of the child graph or zero if it doesn't have one. + * \ingroup group_int_node + */ + static vx_graph getChildGraphOfNode(vx_node node); + /*! \brief Used to completely destroy a node. * \ingroup group_int_node */ diff --git a/framework/src/vx_node.cpp b/framework/src/vx_node.cpp index 33c6ccb4..e049e5a7 100644 --- a/framework/src/vx_node.cpp +++ b/framework/src/vx_node.cpp @@ -458,7 +458,7 @@ void Node::printNode(vx_node node) } /* ![FROM SAMPLE EXTENSION] */ -vx_status ownSetChildGraphOfNode(vx_node node, vx_graph graph) +vx_status Node::setChildGraphOfNode(vx_node node, vx_graph graph) { vx_status status = VX_ERROR_INVALID_GRAPH; @@ -527,7 +527,7 @@ vx_status ownSetChildGraphOfNode(vx_node node, vx_graph graph) return status; } -vx_graph ownGetChildGraphOfNode(vx_node node) +vx_graph Node::getChildGraphOfNode(vx_node node) { vx_graph graph = nullptr; @@ -900,6 +900,16 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetNodeTarget(vx_node node, vx_enum target_ return status; } +VX_API_ENTRY vx_status VX_API_CALL vxSetChildGraphOfNode(vx_node node, vx_graph graph) +{ + return Node::setChildGraphOfNode(node, graph); +} + +VX_API_ENTRY vx_graph VX_API_CALL vxGetChildGraphOfNode(vx_node node) +{ + return Node::getChildGraphOfNode(node); +} + VX_API_ENTRY vx_status VX_API_CALL vxReleaseNode(vx_node *node) { vx_status status = VX_ERROR_INVALID_REFERENCE; diff --git a/targets/c_model/vx_canny.cpp b/targets/c_model/vx_canny.cpp index 5bcbb37f..f92dcb09 100644 --- a/targets/c_model/vx_canny.cpp +++ b/targets/c_model/vx_canny.cpp @@ -47,7 +47,7 @@ static vx_status VX_CALLBACK vxCannyEdgeKernel(vx_node node, const vx_reference if (num == dimof(canny_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -218,7 +218,7 @@ static vx_status VX_CALLBACK vxCannyEdgeInitializer(vx_node node, const vx_refer if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; @@ -322,7 +322,7 @@ static vx_status VX_CALLBACK vxCannyEdgeInitializer(vx_node node, const vx_refer status |= vxReleaseScalar(&sshift); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } @@ -337,7 +337,7 @@ static vx_status VX_CALLBACK vxCannyEdgeDeinitializer(vx_node node, const vx_ref if (num == dimof(canny_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); vx_context context = vxGetContext((vx_reference)node); status = VX_SUCCESS; @@ -345,7 +345,7 @@ static vx_status VX_CALLBACK vxCannyEdgeDeinitializer(vx_node node, const vx_ref status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); status |= vxUnloadKernels(context, "openvx-extras"); } diff --git a/targets/c_model/vx_harris.cpp b/targets/c_model/vx_harris.cpp index cde9c326..863c07c3 100644 --- a/targets/c_model/vx_harris.cpp +++ b/targets/c_model/vx_harris.cpp @@ -46,7 +46,7 @@ static vx_status VX_CALLBACK vxHarrisCornersKernel(vx_node node, const vx_refere if (num == dimof(harris_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -240,7 +240,7 @@ static vx_status VX_CALLBACK vxHarrisInitializer(vx_node node, const vx_referenc if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; @@ -338,7 +338,7 @@ static vx_status VX_CALLBACK vxHarrisInitializer(vx_node node, const vx_referenc status |= vxVerifyGraph(subgraph); VX_PRINT(VX_ZONE_INFO, "Status from Child Graph = %d\n", status); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } @@ -353,7 +353,7 @@ static vx_status VX_CALLBACK vxHarrisDeinitializer(vx_node node, const vx_refere if (num == dimof(harris_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); vx_context context = vxGetContext((vx_reference)node); status = VX_SUCCESS; @@ -361,7 +361,7 @@ static vx_status VX_CALLBACK vxHarrisDeinitializer(vx_node node, const vx_refere status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); status |= vxUnloadKernels(context, "openvx-extras"); status |= vxUnloadKernels(context, "openvx-debug"); diff --git a/targets/c_model/vx_pyramid.cpp b/targets/c_model/vx_pyramid.cpp index 1dd701c4..36091df5 100644 --- a/targets/c_model/vx_pyramid.cpp +++ b/targets/c_model/vx_pyramid.cpp @@ -466,7 +466,7 @@ static vx_status VX_CALLBACK vxGaussianPyramidKernel(vx_node node, const vx_refe if (num == dimof(gaussian_pyramid_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -562,7 +562,7 @@ static vx_status VX_CALLBACK vxGaussianPyramidInitializer(vx_node node, const vx if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; @@ -630,7 +630,7 @@ static vx_status VX_CALLBACK vxGaussianPyramidInitializer(vx_node node, const vx status |= vxReleaseConvolution(&conv); status |= vxVerifyGraph(subgraph); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } @@ -645,7 +645,7 @@ static vx_status VX_CALLBACK vxGaussianPyramidDeinitializer(vx_node node, const if (num == dimof(gaussian_pyramid_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); vx_context context = vxGetContext((vx_reference)node); status = VX_SUCCESS; @@ -653,7 +653,7 @@ static vx_status VX_CALLBACK vxGaussianPyramidDeinitializer(vx_node node, const status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); status |= vxUnloadKernels(context, "openvx-debug"); } diff --git a/targets/c_model/vx_scale.cpp b/targets/c_model/vx_scale.cpp index dde01250..73478357 100644 --- a/targets/c_model/vx_scale.cpp +++ b/targets/c_model/vx_scale.cpp @@ -269,7 +269,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianKernel(vx_node node, const vx_re if (num == dimof(scale_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -417,7 +417,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; } @@ -465,7 +465,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const status |= vxReleaseNode(&nodes[i]); } - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } else if (kernel_size == 3 || kernel_size == 5) { @@ -506,7 +506,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const status |= vxReleaseImage(&virt); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } } @@ -522,14 +522,14 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianDeinitializer(vx_node node, cons if (num == dimof(scale_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = VX_SUCCESS; status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); } return status; diff --git a/targets/tiling/vx_scale.cpp b/targets/tiling/vx_scale.cpp index 24da42c3..4bb846e6 100644 --- a/targets/tiling/vx_scale.cpp +++ b/targets/tiling/vx_scale.cpp @@ -239,7 +239,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianKernel(vx_node node, const vx_re if (num == dimof(scale_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -388,7 +388,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; } @@ -436,7 +436,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const status |= vxReleaseNode(&nodes[i]); } - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } else if (kernel_size == 3 || kernel_size == 5) { @@ -477,7 +477,7 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianInitializer(vx_node node, const status |= vxReleaseImage(&virt); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } } @@ -492,14 +492,14 @@ static vx_status VX_CALLBACK vxHalfscaleGaussianDeinitializer(vx_node node, cons if (num == dimof(scale_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = VX_SUCCESS; status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); } return status; diff --git a/targets/venum/vx_harris.cpp b/targets/venum/vx_harris.cpp index 868a34c0..813473a0 100644 --- a/targets/venum/vx_harris.cpp +++ b/targets/venum/vx_harris.cpp @@ -44,7 +44,7 @@ static vx_status VX_CALLBACK vxHarrisCornersKernel(vx_node node, const vx_refere if (num == dimof(harris_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); status = vxProcessGraph(subgraph); } @@ -236,7 +236,7 @@ static vx_status VX_CALLBACK vxHarrisInitializer(vx_node node, const vx_referenc if (VX_SUCCESS != status) return status; - status = ownSetChildGraphOfNode(node, 0); + status = vxSetChildGraphOfNode(node, 0); if (VX_SUCCESS != status) return status; @@ -334,7 +334,7 @@ static vx_status VX_CALLBACK vxHarrisInitializer(vx_node node, const vx_referenc status |= vxVerifyGraph(subgraph); VX_PRINT(VX_ZONE_INFO, "Status from Child Graph = %d\n", status); - status |= ownSetChildGraphOfNode(node, subgraph); + status |= vxSetChildGraphOfNode(node, subgraph); } } return status; @@ -346,7 +346,7 @@ static vx_status VX_CALLBACK vxHarrisDeinitializer(vx_node node, const vx_refere if (num == dimof(harris_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); vx_context context = vxGetContext((vx_reference)node); status = VX_SUCCESS; @@ -354,7 +354,7 @@ static vx_status VX_CALLBACK vxHarrisDeinitializer(vx_node node, const vx_refere status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); /*status |= */vxUnloadKernels(context, "openvx-extras"); /*status |= */vxUnloadKernels(context, "openvx-debug"); } diff --git a/targets/venum/vx_pyramid.cpp b/targets/venum/vx_pyramid.cpp index 0dd02fcc..e9936450 100644 --- a/targets/venum/vx_pyramid.cpp +++ b/targets/venum/vx_pyramid.cpp @@ -1051,12 +1051,12 @@ static vx_status VX_CALLBACK vxLaplacianReconstructDeinitializer(vx_node node, c vx_status status = VX_ERROR_INVALID_PARAMETERS; if (num == dimof(laplacian_reconstruct_kernel_params)) { - vx_graph subgraph = ownGetChildGraphOfNode(node); + vx_graph subgraph = vxGetChildGraphOfNode(node); vx_context context = vxGetContext((vx_reference)node); status = VX_SUCCESS; status |= vxReleaseGraph(&subgraph); /* set subgraph to "null" */ - status |= ownSetChildGraphOfNode(node, 0); + status |= vxSetChildGraphOfNode(node, 0); status |= vxUnloadKernels(context, "openvx-debug"); } return status; From 6ecfe52d5bd8a5491c4bd4588b35f155e47f23b0 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Tue, 29 Jul 2025 15:28:44 -0700 Subject: [PATCH 21/34] Reworked graph --- framework/include/vx_graph.h | 160 ++ framework/src/vx_graph.cpp | 4904 +++++++++++++++++----------------- 2 files changed, 2677 insertions(+), 2387 deletions(-) diff --git a/framework/include/vx_graph.h b/framework/include/vx_graph.h index 807225bc..74a1b775 100644 --- a/framework/include/vx_graph.h +++ b/framework/include/vx_graph.h @@ -36,6 +36,57 @@ */ class Graph : public Reference { +private: + + /** + * @brief Get the next node index given current node index + * + * @param index The current node index . + * @return vx_uint32 The next node index + * @ingroup group_int_graph + */ + vx_uint32 nextNode(vx_uint32 index); + + /** + * @brief Locate reference given base location + * + * @param ref Start reference. + * @param start Start location. + * @param end End location. + * @return vx_reference vx_reference if found, otherwise nullptr + * @ingroup group_int_graph + */ + static vx_reference locateBaseLocation(vx_reference ref, vx_size* start, vx_size* end); + + /** + * @brief Locate tensor within view + * + * @param mddata Tensor metadata. + * @param start Start view. + * @param end End view. + * @return vx_tensor vx_tensor if found, othewise nullptr + * @ingroup group_int_graph + */ + static vx_tensor locateView(vx_tensor mddata, vx_size* start, vx_size* end); + + /** + * @brief Check write dependency between two references + * + * @param ref1 First reference to compare. + * @param ref2 Second reference to compare. + * @return vx_bool vx_true_e if write dependency exists, otherwise vx_false_e + * @ingroup group_int_graph + */ + static vx_bool checkWriteDependency(vx_reference ref1, vx_reference ref2); + + /** + * @brief Scan the entire context for graphs which may contain + * this reference and mark them as unverified. + * + * @param ref The reference to scan for. + * @ingroup group_int_graph + */ + static void contaminateGraphs(vx_reference ref); public: /** * @brief Construct a new Graph object @@ -161,6 +212,115 @@ class Graph : public Reference vx_status traverseGraph(vx_uint32 parentIndex, vx_uint32 childIndex); + /** + * @brief Get the graph performance + * + * @return vx_perf_t The performance structure + * @ingroup group_int_graph + */ + vx_perf_t performance() const; + + /** + * @brief Get the Graph state + * + * @return vx_enum The graph state + * @ingroup group_int_graph + */ + vx_enum getState() const; + + /** + * @brief Get the number of nodes in the graph + * + * @return vx_uint32 The number of nodes in the graph + * @ingroup group_int_graph + */ + vx_uint32 getNumNodes() const; + + /** + * @brief Get the number of parameters of the graph + * + * @return vx_uint32 The number of graph parameters + * @ingroup group_int_graph + */ + vx_uint32 getNumParams() const; + + /** + * @brief Is graph verified + * + * @return vx_bool true if verified, false otherwise + * @ingroup group_int_graph + */ + vx_bool isVerified(); + + /** + * @brief Verify the graph + * + * @return vx_status VX_SUCCESS if successful, otherwise an return status with error code. + * @ingroup group_int_graph + */ + vx_status verify(); + + /** + * @brief Execute the graph + * + * @param depth Optional count of executions + * @return vx_status VX_SUCCESS if successful, otherwise return status with error code. + * @ingroup group_int_graph + */ + vx_status executeGraph(vx_uint32 depth); + + /** + * @brief Schedule the graph + * + * @return vx_status VX_SUCCESS if successful, otherwise return status with error code. + * @ingroup group_int_graph + */ + vx_status schedule(); + + /** + * @brief Wait on the graph to complete + * + * @return vx_status VX_SUCCESS if successful, otherwise return status with error code. + * @ingroup group_int_graph + */ + vx_status wait(); + + /** + * @brief Process the graph + * + * @return vx_status VX_SUCCESS if successful, otherwise return status with error code. + * @ingroup group_int_graph + */ + vx_status processGraph(); + + /** + * @brief Add a graph paramter + * + * @param param The parameter to add to the graph. + * @return vx_status VX_SUCCESS if successful, otherwise a status with error code. + * @ingroup group_int_graph + */ + vx_status addParameter(vx_parameter param); + + /** + * @brief Set the graph parameter by index + * + * @param index The graph parameter index + * @param value The reference to set + * @return vx_status VX_SUCCESS on success, otherwise an error + * @ingroup group_int_graph + */ + vx_status setParameterByIndex(vx_uint32 index, vx_reference value); + + /** + * @brief Get the parameter object by index + * + * @param index The graph parameter index + * @return vx_parameter A valid parameter object on success + * @ingroup group_int_graph + */ + vx_parameter getParameterByIndex(vx_uint32 index); + /** * @brief Validate the graph parameters queue references list * diff --git a/framework/src/vx_graph.cpp b/framework/src/vx_graph.cpp index 11326079..4947aea4 100644 --- a/framework/src/vx_graph.cpp +++ b/framework/src/vx_graph.cpp @@ -21,14 +21,46 @@ #include "vx_internal.h" /******************************************************************************/ -/* STATIC FUNCTIONS */ +/* INTERNAL FUNCTIONS */ /******************************************************************************/ -static vx_uint32 vxNextNode(vx_graph graph, vx_uint32 index) +Graph::Graph(vx_context context, vx_reference scope) + : Reference(context, VX_TYPE_GRAPH, scope), + nodes(), + perf(), + numNodes(0), + heads(), + numHeads(0), + state(VX_FAILURE), + verified(vx_false_e), + reverify(vx_false_e), + lock(), + parameters(), + numParams(0), + shouldSerialize(vx_false_e), + parentGraph(nullptr), + delays(), +#ifdef OPENVX_USE_PIPELINING + numEnqueableParams(0), + scheduleCount(0), +#endif /* OPENVX_USE_PIPELINING */ +#ifdef OPENVX_USE_STREAMING + isStreamingEnabled(vx_false_e), + isStreaming(vx_false_e), + triggerNodeIndex(UINT32_MAX), + streamingThread(), +#endif /* OPENVX_USE_STREAMING */ + scheduleMode(VX_GRAPH_SCHEDULE_MODE_NORMAL) +{ +} + +Graph::~Graph() {} + +vx_uint32 Graph::nextNode(vx_uint32 index) { - return ((index + 1) % graph->numNodes); + return ((index + 1) % numNodes); } -static vx_reference vxLocateBaseLocation(vx_reference ref, vx_size* start, vx_size* end) +vx_reference Graph::locateBaseLocation(vx_reference ref, vx_size* start, vx_size* end) { if (ref->type == VX_TYPE_IMAGE) { @@ -44,17 +76,20 @@ static vx_reference vxLocateBaseLocation(vx_reference ref, vx_size* start, vx_si end[i] = ((vx_tensor)ref)->dimensions[i]; } } - while ((ref->type == VX_TYPE_IMAGE && ((vx_image)ref)->parent && ((vx_image)ref)->parent != ((vx_image)ref)) - || - (ref->type == VX_TYPE_TENSOR && ((vx_tensor)ref)->parent && ((vx_tensor)ref)->parent != ((vx_tensor)ref)) - ) + while ((ref->type == VX_TYPE_IMAGE && ((vx_image)ref)->parent && + ((vx_image)ref)->parent != ((vx_image)ref)) || + (ref->type == VX_TYPE_TENSOR && ((vx_tensor)ref)->parent && + ((vx_tensor)ref)->parent != ((vx_tensor)ref))) { if (ref->type == VX_TYPE_IMAGE) { vx_image img = (vx_image)ref; vx_size plane_offset = img->memory.ptrs[0] - img->parent->memory.ptrs[0]; - vx_uint32 dy = (vx_uint32)(plane_offset * img->scale[0][VX_DIM_Y] / img->memory.strides[0][VX_DIM_Y]); - vx_uint32 dx = (vx_uint32)((plane_offset - (dy * img->memory.strides[0][VX_DIM_Y] / img->scale[0][VX_DIM_Y])) * img->scale[0][VX_DIM_X] / img->memory.strides[0][VX_DIM_X]); + vx_uint32 dy = (vx_uint32)(plane_offset * img->scale[0][VX_DIM_Y] / + img->memory.strides[0][VX_DIM_Y]); + vx_uint32 dx = (vx_uint32)((plane_offset - (dy * img->memory.strides[0][VX_DIM_Y] / + img->scale[0][VX_DIM_Y])) * + img->scale[0][VX_DIM_X] / img->memory.strides[0][VX_DIM_X]); start[0] += dx; end[0] += dx; start[1] += dy; @@ -67,7 +102,8 @@ static vx_reference vxLocateBaseLocation(vx_reference ref, vx_size* start, vx_si vx_uint32 offset = 0; for (vx_int32 i = tensor->number_of_dimensions - 1; i >= 0; i--) { - start[i] = ((vx_uint8*)tensor->addr - (vx_uint8*)tensor->parent->addr - offset) / tensor->stride[i]; + start[i] = ((vx_uint8*)tensor->addr - (vx_uint8*)tensor->parent->addr - offset) / + tensor->stride[i]; end[i] = start[i] + tensor->dimensions[i]; offset += (vx_uint32)(start[i] * tensor->stride[i]); } @@ -77,7 +113,7 @@ static vx_reference vxLocateBaseLocation(vx_reference ref, vx_size* start, vx_si return ref; } -static vx_tensor vxLocateView(vx_tensor mddata, vx_size* start, vx_size* end) +vx_tensor Graph::locateView(vx_tensor mddata, vx_size* start, vx_size* end) { for (vx_uint32 i = 0; i < VX_MAX_TENSOR_DIMENSIONS; i++) { @@ -87,9 +123,10 @@ static vx_tensor vxLocateView(vx_tensor mddata, vx_size* start, vx_size* end) while (mddata->parent && mddata->parent != mddata) { size_t offset = 0; - for (vx_int32 i = mddata->number_of_dimensions-1; i >= 0; i--) + for (vx_int32 i = mddata->number_of_dimensions - 1; i >= 0; i--) { - start[i] = ((vx_uint8*)mddata->addr - (vx_uint8*)mddata->parent->addr - offset) / mddata->stride[i]; + start[i] = ((vx_uint8*)mddata->addr - (vx_uint8*)mddata->parent->addr - offset) / + mddata->stride[i]; end[i] = start[i] + mddata->dimensions[i]; offset += start[i] * mddata->stride[i]; } @@ -98,7 +135,7 @@ static vx_tensor vxLocateView(vx_tensor mddata, vx_size* start, vx_size* end) return mddata; } -static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) +vx_bool Graph::checkWriteDependency(vx_reference ref1, vx_reference ref2) { if (!ref1 || !ref2) /* garbage input */ return vx_false_e; @@ -114,8 +151,7 @@ static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) { vx_image img = (vx_image)ref2; while (img->parent && img->parent != img) img = img->parent; - if (img->scope == ref1) - return vx_true_e; + if (img->scope == ref1) return vx_true_e; } /* write to pyramid then read a layer */ @@ -123,22 +159,23 @@ static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) { vx_image img = (vx_image)ref1; while (img->parent && img->parent != img) img = img->parent; - if (img->scope == ref2) - return vx_true_e; + if (img->scope == ref2) return vx_true_e; } /* two images or ROIs */ if (ref1->type == VX_TYPE_IMAGE && ref2->type == VX_TYPE_IMAGE) { - vx_size rr_start[VX_MAX_TENSOR_DIMENSIONS], rw_start[VX_MAX_TENSOR_DIMENSIONS], rr_end[VX_MAX_TENSOR_DIMENSIONS], rw_end[VX_MAX_TENSOR_DIMENSIONS]; - vx_reference refr = vxLocateBaseLocation(ref1, rr_start, rr_end); - vx_reference refw = vxLocateBaseLocation(ref2, rw_start, rw_end); + vx_size rr_start[VX_MAX_TENSOR_DIMENSIONS], rw_start[VX_MAX_TENSOR_DIMENSIONS], + rr_end[VX_MAX_TENSOR_DIMENSIONS], rw_end[VX_MAX_TENSOR_DIMENSIONS]; + vx_reference refr = Graph::locateBaseLocation(ref1, rr_start, rr_end); + vx_reference refw = Graph::locateBaseLocation(ref2, rw_start, rw_end); if (refr == refw) { if (refr->type == VX_TYPE_IMAGE) { /* check for ROI intersection */ - if (rr_start[0] < rw_end[0] && rr_end[0] > rw_start[0] && rr_start[1] < rw_end[1] && rr_end[1] > rw_start[1]) + if (rr_start[0] < rw_end[0] && rr_end[0] > rw_start[0] && rr_start[1] < rw_end[1] && + rr_end[1] > rw_start[1]) { return vx_true_e; } @@ -149,8 +186,7 @@ static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) { for (vx_uint32 i = 0; i < ((vx_tensor)refr)->number_of_dimensions; i++) { - if ((rr_start[i] >= rw_end[i]) || - (rw_start[i] >= rr_end[i])) + if ((rr_start[i] >= rw_end[i]) || (rw_start[i] >= rr_end[i])) { return vx_false_e; } @@ -162,15 +198,15 @@ static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) } if (ref1->type == VX_TYPE_TENSOR && ref2->type == VX_TYPE_TENSOR) { - vx_size rr_start[VX_MAX_TENSOR_DIMENSIONS], rw_start[VX_MAX_TENSOR_DIMENSIONS], rr_end[VX_MAX_TENSOR_DIMENSIONS], rw_end[VX_MAX_TENSOR_DIMENSIONS]; - vx_tensor datar = vxLocateView((vx_tensor)ref1, rr_start, rr_end); - vx_tensor dataw = vxLocateView((vx_tensor)ref2, rw_start, rw_end); + vx_size rr_start[VX_MAX_TENSOR_DIMENSIONS], rw_start[VX_MAX_TENSOR_DIMENSIONS], + rr_end[VX_MAX_TENSOR_DIMENSIONS], rw_end[VX_MAX_TENSOR_DIMENSIONS]; + vx_tensor datar = Graph::locateView((vx_tensor)ref1, rr_start, rr_end); + vx_tensor dataw = Graph::locateView((vx_tensor)ref2, rw_start, rw_end); if (datar == dataw) { for (vx_uint32 i = 0; i < datar->number_of_dimensions; i++) { - if ((rr_start[i] >= rw_end[i]) || - (rw_start[i] >= rr_end[i])) + if ((rr_start[i] >= rw_end[i]) || (rw_start[i] >= rr_end[i])) { return vx_false_e; } @@ -182,7 +218,7 @@ static vx_bool vxCheckWriteDependency(vx_reference ref1, vx_reference ref2) return vx_false_e; } -void vxContaminateGraphs(vx_reference ref) +void Graph::contaminateGraphs(vx_reference ref) { if (Reference::isValidReference(ref) == vx_true_e) { @@ -194,8 +230,7 @@ void vxContaminateGraphs(vx_reference ref) Osal::semWait(&context->lock); for (r = 0u; r < context->num_references; r++) { - if (context->reftable[r] == nullptr) - continue; + if (context->reftable[r] == nullptr) continue; if (context->reftable[r]->type == VX_TYPE_GRAPH) { vx_uint32 n; @@ -226,1338 +261,1872 @@ void vxContaminateGraphs(vx_reference ref) } } -/******************************************************************************/ -/* INTERNAL FUNCTIONS */ -/******************************************************************************/ +vx_perf_t Graph::performance() const +{ + return perf; +} -Graph::Graph(vx_context context, vx_reference scope) - : Reference(context, VX_TYPE_GRAPH, scope), - nodes(), - perf(), - numNodes(0), - heads(), - numHeads(0), - state(VX_FAILURE), - verified(vx_false_e), - reverify(vx_false_e), - lock(), - parameters(), - numParams(0), - shouldSerialize(vx_false_e), - parentGraph(nullptr), - delays(), -#ifdef OPENVX_USE_PIPELINING - numEnqueableParams(0), - scheduleCount(0), -#endif /* OPENVX_USE_PIPELINING */ -#ifdef OPENVX_USE_STREAMING - isStreamingEnabled(vx_false_e), - isStreaming(vx_false_e), - triggerNodeIndex(UINT32_MAX), - streamingThread(), -#endif /* OPENVX_USE_STREAMING */ - scheduleMode(VX_GRAPH_SCHEDULE_MODE_NORMAL) +vx_enum Graph::getState() const { + return state; } -Graph::~Graph() +vx_uint32 Graph::getNumNodes() const { + return numNodes; } -void Graph::clearVisitation() +vx_uint32 Graph::getNumParams() const { - vx_uint32 n = 0; - for (n = 0; n < numNodes; n++) - nodes[n]->visited = vx_false_e; + return numParams; } -void Graph::clearExecution() +vx_bool Graph::isVerified() { - vx_uint32 n = 0; - for (n = 0; n < numNodes; n++) - nodes[n]->executed = vx_false_e; + VX_PRINT(VX_ZONE_GRAPH, "Graph is %sverified\n", (verified == vx_true_e ? "" : "NOT ")); + return verified; } -vx_status Graph::findNodesWithReference( - vx_reference ref, - vx_uint32 refnodes[], - vx_uint32 *count, - vx_enum reftype) +vx_status Graph::verify() { - vx_uint32 n, p, nc = 0, max; - vx_status status = VX_ERROR_INVALID_LINK; + vx_status status = VX_SUCCESS; + vx_uint32 num_errors = 0u; + vx_bool first_time_verify = + ((this->verified == vx_false_e) && (this->reverify == vx_false_e)) ? vx_true_e : vx_false_e; - /* save the maximum number of nodes to find */ - max = *count; + this->verified = vx_false_e; - /* reset the current count to zero */ - *count = 0; + vx_uint32 h, n, p; + vx_bool hasACycle = vx_false_e; - VX_PRINT(VX_ZONE_GRAPH,"Find nodes with reference " VX_FMT_REF " type %d over %u nodes upto %u finds\n", ref, reftype, numNodes, max); - for (n = 0; n < numNodes; n++) + /* lock the graph */ + Osal::semWait(&this->lock); + + /* To properly deal with parameter dependence in the graph, the + nodes have to be in topological order when their parameters + are inspected and their dependent attributes -such as geometry + and type- are propagated. */ + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Topological Sort Phase\n"); + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); + this->topologicalSort(this->nodes, this->numNodes); + + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); + VX_PRINT(VX_ZONE_GRAPH, "User Kernel Preprocess Phase! (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); + + for (n = 0; n < this->numNodes; n++) { - for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) + vx_node node = this->nodes[n]; + if (node->kernel->user_kernel) { - vx_enum dir = nodes[n]->kernel->signature.directions[p]; - vx_reference thisref = nodes[n]->parameters[p]; - - VX_PRINT(VX_ZONE_GRAPH,"\tchecking node[%u].parameter[%u] dir = %d ref = " VX_FMT_REF " (=?%d:" VX_FMT_REF ")\n", n, p, dir, thisref, reftype, ref); - if ((dir == reftype) && vxCheckWriteDependency(thisref, ref)) + if (!first_time_verify) // re-verify { - if (nc < max) + if (node->kernel->deinitialize) { - VX_PRINT(VX_ZONE_GRAPH, "match at node[%u].parameter[%u]\n", n, p); - if (refnodes) - refnodes[nc] = n; - nc++; - status = VX_SUCCESS; + vx_status status; + if (node->local_data_set_by_implementation == vx_false_e) + node->local_data_change_is_enabled = vx_true_e; + status = + node->kernel->deinitialize((vx_node)node, (vx_reference*)node->parameters, + node->kernel->signature.num_parameters); + node->local_data_change_is_enabled = vx_false_e; + if (status != VX_SUCCESS) + { + VX_PRINT(VX_ZONE_ERROR, "Failed to de-initialize kernel %s!\n", + node->kernel->name); + goto exit; + } } - else + + if (node->kernel->attributes.localDataSize == 0) { - VX_PRINT(VX_ZONE_ERROR, "ERROR: Overflow in refnodes[]\n"); + if (node->attributes.localDataPtr) + { + if (!first_time_verify && node->attributes.localDataPtr) + { + ::operator delete(node->attributes.localDataPtr); + } + node->attributes.localDataSize = 0; + node->attributes.localDataPtr = nullptr; + } } + node->local_data_set_by_implementation = vx_false_e; } } } - *count = nc; - VX_PRINT(VX_ZONE_GRAPH, "Found %u nodes with reference " VX_FMT_REF " status = %d\n", nc, ref, status); - return status; -} - -void Graph::findNextNodes( - vx_uint32 last_nodes[VX_INT_MAX_REF], vx_uint32 numLast, - vx_uint32 next_nodes[VX_INT_MAX_REF], vx_uint32 *numNext, - vx_uint32 left_nodes[VX_INT_MAX_REF], vx_uint32 *numLeft) -{ - vx_uint32 poss_next[VX_INT_MAX_REF]; - vx_uint32 i,n,p,n1,numPoss = 0; - - VX_PRINT(VX_ZONE_GRAPH, "Entering with %u left nodes\n", *numLeft); - for (n = 0; n < *numLeft; n++) - { - VX_PRINT(VX_ZONE_GRAPH, "leftover: node[%u] = %s\n", left_nodes[n], nodes[left_nodes[n]]->kernel->name); - } - numPoss = 0; - *numNext = 0; + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Parameter Validation Phase! (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "###########################\n"); - /* for each last node, add all output to input nodes to the list of possible. */ - for (i = 0; i < numLast; i++) + for (n = 0; n < this->numNodes; n++) { - n = last_nodes[i]; - for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) + /* check to make sure that a node has all required parameters */ + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) { - vx_enum dir = nodes[n]->kernel->signature.directions[p]; - vx_reference ref = nodes[n]->parameters[p]; - if (((dir == VX_OUTPUT) || (dir == VX_BIDIRECTIONAL)) && (ref != nullptr)) + if (this->nodes[n]->kernel->signature.states[p] == VX_PARAMETER_STATE_REQUIRED) { - /* send the max possible nodes */ - n1 = dimof(poss_next) - numPoss; - if (findNodesWithReference(ref, &poss_next[numPoss], &n1, VX_INPUT) == VX_SUCCESS) + if (this->nodes[n]->parameters[p] == nullptr) { - VX_PRINT(VX_ZONE_GRAPH, "Adding %u nodes to possible list\n", n1); - numPoss += n1; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_PARAMETERS, + "Node %s: Some parameters were not supplied!\n", + this->nodes[n]->kernel->name); + VX_PRINT(VX_ZONE_ERROR, + "Node " VX_FMT_REF + " (%s) Parameter[%u] was required and not supplied!\n", + this->nodes[n], this->nodes[n]->kernel->name, p); + status = VX_ERROR_INVALID_PARAMETERS; + num_errors++; + } + else if (this->nodes[n]->parameters[p]->internal_count == 0) + { + VX_PRINT(VX_ZONE_ERROR, "Internal reference counts are wrong!\n"); + DEBUG_BREAK(); + num_errors++; } } } - } - - VX_PRINT(VX_ZONE_GRAPH, "There are %u possible nodes\n", numPoss); + if (status != VX_SUCCESS) + { + goto exit; + } - /* add back all the left over nodes (making sure to not include duplicates) */ - for (i = 0; i < *numLeft; i++) - { - vx_uint32 j; - vx_bool match = vx_false_e; - for (j = 0; j < numPoss; j++) + /* debugging, show that we can detect "constant" data or "unreferenced data" */ + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) { - if (left_nodes[i] == poss_next[j]) + vx_reference ref = (vx_reference)this->nodes[n]->parameters[p]; + if (ref) { - match = vx_true_e; + if (ref->external_count == 0) + { + VX_PRINT(VX_ZONE_INFO, "%s[%u] = " VX_FMT_REF " (CONSTANT) type:%08x\n", + this->nodes[n]->kernel->name, p, ref, ref->type); + } + else + { + VX_PRINT(VX_ZONE_INFO, "%s[%u] = " VX_FMT_REF " (MUTABLE) type:%08x count:%d\n", + this->nodes[n]->kernel->name, p, ref, ref->type, ref->external_count); + } } } - if (match == vx_false_e) + + /* check if new style validators are provided (see bug14654) */ + if (this->nodes[n]->kernel->validate != nullptr) { - VX_PRINT(VX_ZONE_GRAPH, "Adding back left over node[%u] %s\n", left_nodes[i], nodes[left_nodes[i]]->kernel->name); - poss_next[numPoss++] = left_nodes[i]; - } - } - *numLeft = 0; + VX_PRINT(VX_ZONE_GRAPH, "Using new style validators\n"); - /* now check all possible next nodes to see if the parent nodes are visited. */ - for (i = 0; i < numPoss; i++) - { - vx_uint32 poss_params[VX_INT_MAX_PARAMS]; - vx_uint32 pi, numPossParam = 0; - vx_bool ready = vx_true_e; + vx_status validation_status = VX_SUCCESS; + vx_reference vref[VX_INT_MAX_PARAMS]; + vx_meta_format metas[VX_INT_MAX_PARAMS]; - n = poss_next[i]; - VX_PRINT(VX_ZONE_GRAPH, "possible: node[%u] = %s\n", n, nodes[n]->kernel->name); - for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) - { - if (nodes[n]->kernel->signature.directions[p] == VX_INPUT) + for (p = 0; p < dimof(metas); p++) { - VX_PRINT(VX_ZONE_GRAPH,"nodes[%u].parameter[%u] predicate needs to be checked\n", n, p); - poss_params[numPossParam] = p; - numPossParam++; + metas[p] = nullptr; + vref[p] = nullptr; } - } - /* now check to make sure all possible input parameters have their */ - /* parent nodes executed. */ - for (pi = 0; pi < numPossParam; pi++) - { - vx_uint32 predicate_nodes[VX_INT_MAX_REF]; - vx_uint32 predicate_count = 0; - vx_uint32 predicate_index = 0; - vx_uint32 refIdx = 0; - vx_reference ref = 0; - vx_enum reftype[2] = {VX_OUTPUT, VX_BIDIRECTIONAL}; + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) + { + if ((this->nodes[n]->parameters[p] != nullptr) && + (this->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT)) + { + if (this->setupOutput(n, p, &vref[p], &metas[p], &status, &num_errors) == + vx_false_e) + { + break; + } + } + } - p = poss_params[pi]; - ref = nodes[n]->parameters[p]; - VX_PRINT(VX_ZONE_GRAPH, "checking node[%u].parameter[%u] = " VX_FMT_REF "\n", n, p, ref); + if (status == VX_SUCCESS) + { + validation_status = this->nodes[n]->kernel->validate( + (vx_node)this->nodes[n], this->nodes[n]->parameters, + this->nodes[n]->kernel->signature.num_parameters, metas); + if (validation_status != VX_SUCCESS) + { + status = validation_status; + vxAddLogEntry(reinterpret_cast(this), status, + "Node[%u] %s: parameter(s) failed validation!\n", n, + this->nodes[n]->kernel->name); + VX_PRINT(VX_ZONE_GRAPH, + "Failed on validation of parameter(s) of kernel %s in node #%d " + "(status=%d)\n", + this->nodes[n]->kernel->name, n, status); + num_errors++; + } + } - for(refIdx = 0; refIdx < dimof(reftype); refIdx++) + if (status == VX_SUCCESS) { - /* set the size of predicate nodes going in */ - predicate_count = dimof(predicate_nodes); - if (findNodesWithReference(ref, predicate_nodes, &predicate_count, reftype[refIdx]) == VX_SUCCESS) + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) { - /* check to see of all of the predicate nodes are executed */ - for (predicate_index = 0; - predicate_index < predicate_count; - predicate_index++) + if ((this->nodes[n]->parameters[p] != nullptr) && + (this->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT)) { - n1 = predicate_nodes[predicate_index]; - if (nodes[n1]->executed == vx_false_e) + if (this->postprocessOutput(n, p, &vref[p], metas[p], &status, + &num_errors) == vx_false_e) { - VX_PRINT(VX_ZONE_GRAPH, "predicated: node[%u] = %s\n", n1, nodes[n1]->kernel->name); - ready = vx_false_e; break; } } } - if(ready == vx_false_e) + } + + for (p = 0; p < dimof(metas); p++) + { + if (metas[p]) { - break; + vxReleaseMetaFormat(&metas[p]); } } } - if (ready == vx_true_e) + else /* old style validators */ { - /* make sure we don't schedule this node twice */ - if (nodes[n]->visited == vx_false_e) + VX_PRINT(VX_ZONE_GRAPH, "Using old style validators\n"); + vx_meta_format metas[VX_INT_MAX_PARAMS] = {nullptr}; + + /* first pass for inputs */ + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) { - next_nodes[(*numNext)++] = n; - nodes[n]->visited = vx_true_e; + if (((this->nodes[n]->kernel->signature.directions[p] == VX_BIDIRECTIONAL) || + (this->nodes[n]->kernel->signature.directions[p] == VX_INPUT)) && + (this->nodes[n]->parameters[p] != nullptr) && + (this->nodes[n]->kernel->validate_input != nullptr)) + { + vx_status input_validation_status = + this->nodes[n]->kernel->validate_input((vx_node)this->nodes[n], p); + if (input_validation_status != VX_SUCCESS) + { + status = input_validation_status; + vxAddLogEntry(reinterpret_cast(this), status, + "Node[%u] %s: parameter[%u] failed input/bi validation!\n", n, + this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_GRAPH, + "Failed on validation of parameter %u of kernel %s in node #%d " + "(status=%d)\n", + p, this->nodes[n]->kernel->name, n, status); + num_errors++; + } + } } - } - else - { - /* put the node back into the possible list for next time */ - left_nodes[(*numLeft)++] = n; - VX_PRINT(VX_ZONE_GRAPH, "notready: node[%u] = %s\n", n, nodes[n]->kernel->name); - } - } + /* second pass for bi/output (we may encounter "virtual" objects here, + * then we must reparse graph to replace with new objects) + */ + /*! \bug Bidirectional parameters currently break parsing. */ + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) + { + vx_reference vref = nullptr; + if (this->nodes[n]->parameters[p] == nullptr) continue; - VX_PRINT(VX_ZONE_GRAPH, "%u Next Nodes\n", *numNext); - for (i = 0; i < *numNext; i++) - { - n = next_nodes[i]; - VX_PRINT(VX_ZONE_GRAPH, "next: node[%u] = %s\n", n, nodes[n]->kernel->name); - } - VX_PRINT(VX_ZONE_GRAPH, "%u Left Nodes\n", *numLeft); - for (i = 0; i < *numLeft; i++) - { - n = left_nodes[i]; - VX_PRINT(VX_ZONE_GRAPH, "left: node[%u] = %s\n", n, nodes[n]->kernel->name); - } -} - -vx_status Graph::traverseGraph(vx_uint32 parentIndex, - vx_uint32 childIndex) -{ - /* this is expensive, but needed in order to know who references a parameter */ - static vx_uint32 refNodes[VX_INT_MAX_REF]; - /* this keeps track of the available starting point in the static buffer */ - static vx_uint32 refStart = 0; - /* this makes sure we don't have any odd conditions about infinite depth */ - static vx_uint32 depth = 0; + VX_PRINT(VX_ZONE_GRAPH, "Checking Node[%u].Parameter[%u]\n", n, p); + if (this->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT) + { + vx_status output_validation_status = VX_SUCCESS; + if (this->setupOutput(n, p, &vref, &metas[p], &status, &num_errors) == + vx_false_e) + break; + if (this->nodes[n]->kernel->validate_output != nullptr) + { + output_validation_status = this->nodes[n]->kernel->validate_output( + (vx_node)this->nodes[n], p, metas[p]); + if (output_validation_status == VX_SUCCESS) + { + if (this->postprocessOutput(n, p, &vref, metas[p], &status, + &num_errors) == vx_false_e) + { + break; + } + } + else + { + status = output_validation_status; + vxAddLogEntry(reinterpret_cast(this), status, + "Node %s: parameter[%u] failed output validation! " + "(status = %d)\n", + this->nodes[n]->kernel->name, p, status); + VX_PRINT(VX_ZONE_ERROR, + "Failed on validation of output parameter[%u] on kernel " + "%s, status=%d\n", + p, this->nodes[n]->kernel->name, status); + } + } + } + } - vx_uint32 refCount = 0; - vx_uint32 refIndex = 0; - vx_uint32 thisIndex = 0; - vx_status status = VX_SUCCESS; - vx_uint32 p = 0; + for (p = 0; p < dimof(metas); p++) + { + if (metas[p]) + { + vxReleaseMetaFormat(&metas[p]); + } + } + } + } - VX_PRINT(VX_ZONE_GRAPH, "refStart = %u\n", refStart); + VX_PRINT(VX_ZONE_GRAPH, "####################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Single Writer Phase! (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "####################\n"); - if (parentIndex == childIndex && parentIndex != VX_INT_MAX_NODES) - { - VX_PRINT(VX_ZONE_ERROR, "################################\n"); - VX_PRINT(VX_ZONE_ERROR, "ERROR: CYCLE DETECTED! node[%u]\n", parentIndex); - VX_PRINT(VX_ZONE_ERROR, "################################\n"); - /* there's a cycle in the graph */ - status = VX_ERROR_INVALID_GRAPH; - } - else if (depth > numNodes) /* should be impossible under normal circumstances */ - { - /* there's a cycle in the graph */ - status = VX_ERROR_INVALID_GRAPH; - } - else + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) { - /* if the parent is an invalid index, then we assume we're processing a - * head of a graph which has no parent index. - */ - if (parentIndex == VX_INT_MAX_NODES) + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) { - parentIndex = childIndex; - thisIndex = parentIndex; - VX_PRINT(VX_ZONE_GRAPH, "Starting head-first traverse of graph from node[%u]\n", thisIndex); - } - else - { - thisIndex = childIndex; - VX_PRINT(VX_ZONE_GRAPH, "continuing traverse of graph from node[%u] on node[%u] start=%u\n", parentIndex, thisIndex, refStart); + if (this->nodes[n]->parameters[p] && + ((this->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT) || + (this->nodes[n]->kernel->signature.directions[p] == VX_BIDIRECTIONAL))) + { + vx_uint32 n1, p1; + /* check for other output references to this parameter in the graph. */ + for (n1 = this->nextNode(n); n1 != n; n1 = this->nextNode(n1)) + { + for (p1 = 0; p1 < this->nodes[n]->kernel->signature.num_parameters; p1++) + { + if ((this->nodes[n1]->kernel->signature.directions[p1] == VX_OUTPUT) || + (this->nodes[n1]->kernel->signature.directions[p1] == VX_BIDIRECTIONAL)) + { + if (vx_true_e == + Graph::checkWriteDependency(this->nodes[n]->parameters[p], + this->nodes[n1]->parameters[p1])) + { + status = VX_ERROR_MULTIPLE_WRITERS; + VX_PRINT(VX_ZONE_GRAPH, + "Multiple Writer to a reference found, check log!\n"); + vxAddLogEntry(reinterpret_cast(this), status, + "Node %s and Node %s are trying to output to the " + "same reference " VX_FMT_REF "\n", + this->nodes[n]->kernel->name, + this->nodes[n1]->kernel->name, + this->nodes[n]->parameters[p]); + } + } + } + } + } } + } - for (p = 0; p < nodes[thisIndex]->kernel->signature.num_parameters; p++) - { - vx_enum dir = nodes[thisIndex]->kernel->signature.directions[p]; - vx_reference ref = nodes[thisIndex]->parameters[p]; + VX_PRINT(VX_ZONE_GRAPH, "########################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Memory Allocation Phase! (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "########################\n"); - if (dir != VX_INPUT && ref != nullptr) + /* now make sure each parameter is backed by memory. */ + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) + { + VX_PRINT(VX_ZONE_GRAPH, "Checking node %u\n", n); + + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) + { + if (this->nodes[n]->parameters[p]) { - VX_PRINT(VX_ZONE_GRAPH, "[traverse] node[%u].parameter[%u] = " VX_FMT_REF "\n", thisIndex, p, ref); - /* send the maximum number of possible nodes to find */ - refCount = dimof(refNodes) - refStart; - status = findNodesWithReference(ref, &refNodes[refStart], &refCount, VX_INPUT); - VX_PRINT(VX_ZONE_GRAPH, "status = %d at node[%u] start=%u count=%u\n", status, thisIndex, refStart, refCount); - if (status == VX_SUCCESS) + VX_PRINT(VX_ZONE_GRAPH, "\tparameter[%u]=%p type %d sig type %d\n", p, + this->nodes[n]->parameters[p], this->nodes[n]->parameters[p]->type, + this->nodes[n]->kernel->signature.types[p]); + + if (this->nodes[n]->parameters[p]->type == VX_TYPE_IMAGE) { - vx_uint32 refStop = refStart + refCount; - VX_PRINT(VX_ZONE_GRAPH, "Looping from %u to %u\n", refStart, refStop); - for (refIndex = refStart; refIndex < refStop; refIndex++) + if (static_cast(this->nodes[n]->parameters[p])->allocateImage() == + vx_false_e) { - vx_status child_status = VX_SUCCESS; - VX_PRINT(VX_ZONE_GRAPH, "node[%u] => node[%u]\n", thisIndex, refNodes[refIndex]); - refStart += refCount; - depth++; /* go one more level in */ - child_status = traverseGraph(thisIndex, refNodes[refIndex]); - if (child_status != VX_SUCCESS) - status = child_status; - depth--; /* pull out one level */ - refStart -= refCount; - VX_PRINT(VX_ZONE_GRAPH, "status = %d at node[%u]\n", status, thisIndex); + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate image at node[%u] %s parameter[%u]\n", n, + this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); } } - if (status == VX_ERROR_INVALID_LINK) /* no links at all */ + else if ((VX_TYPE_IS_SCALAR(this->nodes[n]->parameters[p]->type)) || + (this->nodes[n]->parameters[p]->type == VX_TYPE_RECTANGLE) || + (this->nodes[n]->parameters[p]->type == VX_TYPE_THRESHOLD)) { - VX_PRINT(VX_ZONE_GRAPH, "[Ok] No link found for node[%u].parameter[%u]\n", thisIndex, p); - status = VX_SUCCESS; + /* these objects don't need to be allocated */ + } + else if (this->nodes[n]->parameters[p]->type == VX_TYPE_LUT) + { + vx_lut_t lut = (vx_lut_t)this->nodes[n]->parameters[p]; + if (Memory::allocateMemory(this->context, &lut->memory) == vx_false_e) + { + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate lut at node[%u] %s parameter[%u]\n", n, + this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); + } + } + else if (this->nodes[n]->parameters[p]->type == VX_TYPE_DISTRIBUTION) + { + vx_distribution dist = (vx_distribution)this->nodes[n]->parameters[p]; + if (Memory::allocateMemory(this->context, &dist->memory) == vx_false_e) + { + vxAddLogEntry( + reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate distribution at node[%u] %s parameter[%u]\n", n, + this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); + } + } + else if (this->nodes[n]->parameters[p]->type == VX_TYPE_PYRAMID) + { + vx_pyramid pyr = (vx_pyramid)this->nodes[n]->parameters[p]; + vx_uint32 i = 0; + for (i = 0; i < pyr->numLevels; i++) + { + if ((pyr->levels[i]->allocateImage()) == vx_false_e) + { + vxAddLogEntry( + reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate pyramid image at node[%u] %s parameter[%u]\n", + n, this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); + } + } + } + else if ((this->nodes[n]->parameters[p]->type == VX_TYPE_MATRIX) || + (this->nodes[n]->parameters[p]->type == VX_TYPE_CONVOLUTION)) + { + vx_matrix mat = (vx_matrix)this->nodes[n]->parameters[p]; + if (Memory::allocateMemory(this->context, &mat->memory) == vx_false_e) + { + vxAddLogEntry( + reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate matrix (or subtype) at node[%u] %s parameter[%u]\n", + n, this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); + } + } + else if (this->nodes[n]->kernel->signature.types[p] == VX_TYPE_ARRAY) + { + if (static_cast(this->nodes[n]->parameters[p])->allocateArray() == + vx_false_e) + { + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_NO_MEMORY, + "Failed to allocate array at node[%u] %s parameter[%u]\n", n, + this->nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "See log\n"); + } } + /*! \todo add other memory objects to graph auto-allocator as needed! */ } - else + } + } + + VX_PRINT(VX_ZONE_GRAPH, "###############################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Head Nodes Determination Phase! (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "###############################\n"); + + memset(this->heads, 0, sizeof(this->heads)); + this->numHeads = 0; + + /* now traverse the graph and put nodes with no predecessor in the head list */ + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) + { + uint32_t n1, p1; + vx_bool isAHead = vx_true_e; /* assume every node is a head until proven otherwise */ + + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters && isAHead == vx_true_e; + p++) + { + if ((this->nodes[n]->kernel->signature.directions[p] == VX_INPUT) && + (this->nodes[n]->parameters[p] != nullptr)) { - VX_PRINT(VX_ZONE_GRAPH, "[ ignore ] node[%u].parameter[%u] = " VX_FMT_REF " type %d\n", childIndex, p, ref, dir); + /* ring loop over the node array, checking every node but this nth node. */ + for (n1 = this->nextNode(n); (n1 != n) && (isAHead == vx_true_e); + n1 = this->nextNode(n1)) + { + for (p1 = 0; p1 < this->nodes[n1]->kernel->signature.num_parameters && + isAHead == vx_true_e; + p1++) + { + if (this->nodes[n1]->kernel->signature.directions[p1] != VX_INPUT) + { + VX_PRINT(VX_ZONE_GRAPH, + "Checking input nodes[%u].parameter[%u] to " + "nodes[%u].parameters[%u]\n", + n, p, n1, p1); + /* if the parameter is referenced elsewhere */ + if (Graph::checkWriteDependency(this->nodes[n]->parameters[p], + this->nodes[n1]->parameters[p1])) + { + /* @TODO: this was added by AI; deep dive this logic */ + vx_reference refA = this->nodes[n]->parameters[p]; + vx_reference refB = this->nodes[n1]->parameters[p1]; + if (refA->type == refB->type && refA->delay && refB->delay && + refA->delay == refB->delay) + { + /* skip delay slot dependency for head node detection */ + continue; + } + VX_PRINT(VX_ZONE_GRAPH, + "\tnodes[%u].parameter[%u] referenced in " + "nodes[%u].parameter[%u]\n", + n, p, n1, p1); + isAHead = + vx_false_e; /* this will cause all the loops to break too. */ + } + } + } + } } - if (status == VX_ERROR_INVALID_GRAPH) - break; } - if (status == VX_SUCCESS) + if (isAHead == vx_true_e) { - /* mark it visited for the next check to pass */ - nodes[thisIndex]->visited = vx_true_e; + VX_PRINT(VX_ZONE_GRAPH, "Found a head in node[%u] => %s\n", n, + this->nodes[n]->kernel->name); + this->heads[this->numHeads++] = n; } } - VX_PRINT(VX_ZONE_GRAPH, "returning status %d\n", status); - return status; -} -void Graph::topologicalSort(vx_node *list, vx_uint32 nnodes) -{ - /* Knuth TAoCP algorithm 2.2.3 T. - Nodes and their parameters are the "objects" which have partial-order - relations (with "<" noting the similar-looking general symbol for - relational order, not the specific less-than relation), and it's - always pair-wise: node < parameter for outputs, - parameter < node for inputs. */ - vx_uint32 nobjects; /* Number of objects; "n" in TAoCP. */ - vx_uint32 nremain; /* Number of remaining objects to be "output"; "N" in TAoCP. */ - vx_uint32 objectno; /* Running count, 1-based. */ - vx_uint32 j, k, n, r, f; - vx_uint32 outputnr; /* Running count of nodes as they're "output". */ + /* graph has a cycle as there are no starting points! */ + if ((this->numHeads == 0) && (status == VX_SUCCESS)) + { + status = VX_ERROR_INVALID_GRAPH; + VX_PRINT(VX_ZONE_ERROR, "Graph has no heads!\n"); + vxAddLogEntry(reinterpret_cast(this), status, + "Cycle: Graph has no head nodes!\n"); + } - struct direct_successor { - vx_uint32 suc; - struct direct_successor *next; - }; + VX_PRINT(VX_ZONE_GRAPH, "##############\n"); + VX_PRINT(VX_ZONE_GRAPH, "Cycle Checking (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "##############\n"); - struct object_relations { - union { - vx_uint32 count; - vx_uint32 qlink; - } u; - struct direct_successor *top; - vx_reference ref; - }; + this->clearVisitation(); - std::unique_ptr x; - std::unique_ptr suc_next_table; - struct direct_successor *avail; + /* cycle checking by traversal of the graph from heads to tails */ + for (h = 0; h < this->numHeads; h++) + { + vx_status cycle_status = VX_SUCCESS; + status = this->traverseGraph(VX_INT_MAX_NODES, this->heads[h]); + if (cycle_status != VX_SUCCESS) + { + status = cycle_status; + VX_PRINT(VX_ZONE_ERROR, "Cycle found in graph!"); + vxAddLogEntry(reinterpret_cast(this), status, + "Cycle: Graph has a cycle!\n"); + goto exit; + } + } - /* Visit each node in the list and its in- and out-parameters, - clearing all indices. Find upper bound for nobjects, for use when - allocating x (X in the algorithm). This number is also the exact - number of relations, for use with suc_next_table (the unnamed - "suc, next" table in the algorithm). */ - vx_uint32 max_n_objects_relations = nnodes; + VX_PRINT(VX_ZONE_GRAPH, "############################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Checking for Unvisited Nodes (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "############################\n"); - for (n = 0; n < nnodes; n++) + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) { - vx_uint32 parmno; + if (this->nodes[n]->visited == vx_false_e) + { + VX_PRINT(VX_ZONE_ERROR, "UNVISITED: %s node[%u]\n", this->nodes[n]->kernel->name, n); + status = VX_ERROR_INVALID_GRAPH; + vxAddLogEntry(reinterpret_cast(this), status, "Node %s: unvisited!\n", + this->nodes[n]->kernel->name); + } + } - max_n_objects_relations += list[n]->kernel->signature.num_parameters; + this->clearVisitation(); - for (parmno = 0; parmno < list[n]->kernel->signature.num_parameters; parmno++) + if (hasACycle == vx_true_e) + { + status = VX_ERROR_INVALID_GRAPH; + vxAddLogEntry(reinterpret_cast(this), status, "Cycle: Graph has a cycle!\n"); + goto exit; + } + + VX_PRINT(VX_ZONE_GRAPH, "#########################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Target Verification Phase (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "#########################\n"); + + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) + { + vx_uint32 index = this->nodes[n]->affinity; + vx_target target = this->context->targets[index]; + if (target) { - /* Pick the parent object in case of su-objects (e.g., ROI) */ - vx_reference ref = list[n]->parameters[parmno]; - while ( (ref != nullptr) && - (ref->scope != nullptr) && - (ref->scope != (vx_reference)this) && - (ref->scope != (vx_reference)ref->context) - ) + vx_status target_verify_status = target->funcs.verify(target, this->nodes[n]); + if (target_verify_status != VX_SUCCESS) { - ref = ref->scope; + status = target_verify_status; + vxAddLogEntry(reinterpret_cast(this), status, + "Target: %s Failed to Verify Node %s\n", target->name, + this->nodes[n]->kernel->name); } + } + } - if (ref != nullptr) + VX_PRINT(VX_ZONE_GRAPH, "#######################\n"); + VX_PRINT(VX_ZONE_GRAPH, "Kernel Initialize Phase (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "#######################\n"); + + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) + { + vx_node node = this->nodes[n]; + if (node->kernel->initialize) + { + vx_status kernel_init_status = VX_FAILURE; + + /* call the kernel initialization routine */ + if ((node->kernel->user_kernel == vx_true_e) && + (node->kernel->attributes.localDataSize == 0)) + node->local_data_change_is_enabled = vx_true_e; + + kernel_init_status = + node->kernel->initialize((vx_node)node, (vx_reference*)node->parameters, + node->kernel->signature.num_parameters); + node->local_data_change_is_enabled = vx_false_e; + if (kernel_init_status != VX_SUCCESS) { - ref->index = 0; + status = kernel_init_status; + vxAddLogEntry(reinterpret_cast(this), status, + "Kernel: %s failed to initialize!\n", node->kernel->name); } - else + } + + /* once the kernel has been initialized, create any local data for it */ + if ((node->attributes.localDataSize > 0) && (node->attributes.localDataPtr == nullptr)) + { + node->attributes.localDataPtr = new vx_char(node->attributes.localDataSize); + if (node->kernel->user_kernel == vx_true_e) { - /* Ignore nullptr (optional) parameters. */ - max_n_objects_relations--; + node->local_data_set_by_implementation = vx_true_e; } + VX_PRINT(VX_ZONE_GRAPH, + "Local Data Allocated " VX_FMT_SIZE " bytes for node into %p\n!", + node->attributes.localDataSize, node->attributes.localDataPtr); } } - /* Visit each node and its parameters, setting all indices. Allocate - and initialize the node + parameters-list. The x table is - 1-based; index 0 is a sentinel. - (This is step T1.) */ - x = std::make_unique(max_n_objects_relations + 1); - suc_next_table = std::make_unique(max_n_objects_relations); - - avail = suc_next_table.get(); - - for (objectno = 1; objectno <= nnodes; objectno++) + VX_PRINT(VX_ZONE_GRAPH, "#######################\n"); + VX_PRINT(VX_ZONE_GRAPH, "COST CALCULATIONS (%d)\n", status); + VX_PRINT(VX_ZONE_GRAPH, "#######################\n"); + for (n = 0; (n < this->numNodes) && (status == VX_SUCCESS); n++) { - vx_node node = list[objectno - 1]; - node->index = objectno; - x[objectno].ref = (vx_reference)node; + this->nodes[n]->costs.bandwidth = 0ul; + for (p = 0; p < this->nodes[n]->kernel->signature.num_parameters; p++) + { + vx_reference ref = this->nodes[n]->parameters[p]; + if (ref) + { + vx_uint32 i; + switch (ref->type) + { + case VX_TYPE_IMAGE: + { + vx_image image = (vx_image)ref; + for (i = 0; i < image->memory.nptrs; i++) + this->nodes[n]->costs.bandwidth += + Memory::computeMemorySize(&image->memory, i); + break; + } + case VX_TYPE_ARRAY: + { + vx_array array = (vx_array)ref; + this->nodes[n]->costs.bandwidth += + Memory::computeMemorySize(&array->memory, 0); + break; + } + case VX_TYPE_PYRAMID: + { + vx_pyramid pyr = (vx_pyramid)ref; + vx_uint32 j; + for (j = 0; j < pyr->numLevels; j++) + { + vx_image image = pyr->levels[j]; + for (i = 0; i < image->memory.nptrs; i++) + { + this->nodes[n]->costs.bandwidth += + Memory::computeMemorySize(&image->memory, i); + } + } + break; + } + default: + VX_PRINT(VX_ZONE_WARNING, + "Node[%u].parameter[%u] Unknown bandwidth cost!\n", n, p); + break; + } + } + } + VX_PRINT(VX_ZONE_GRAPH, "Node[%u] has bandwidth cost of " VX_FMT_SIZE " bytes\n", n, + this->nodes[n]->costs.bandwidth); } - /* While we visit the parameters (setting their index if 0), we - "input" the relation. We don't have to iterate separately after - all parameters are "indexed", as all nodes are already in place - (and "indexed") and a parameter doesn't have a direct relation - with another parameter. - (Steps T2 and T3). */ - for (n = 0; n < nnodes; n++) +exit: + this->reverify = vx_false_e; + if (status == VX_SUCCESS) { - vx_uint32 parmno; + this->verified = vx_true_e; + this->state = VX_GRAPH_STATE_VERIFIED; + } + else + { + this->verified = vx_false_e; + this->state = VX_GRAPH_STATE_UNVERIFIED; + } - for (parmno = 0; parmno < list[n]->kernel->signature.num_parameters; parmno++) - { - vx_reference ref = list[n]->parameters[parmno]; - struct direct_successor *p; + /* unlock the graph */ + Osal::semPost(&this->lock); - /* Pick the parent object in case of su-objects (e.g., ROI) */ - while ( (ref != nullptr) && - (ref->scope != nullptr) && - (ref->scope != (vx_reference)this) && - (ref->scope != (vx_reference)ref->context) - ) - { - ref = ref->scope; - } + VX_PRINT(VX_ZONE_GRAPH, "Returning status %d\n", status); + return status; +} - if (ref == nullptr) - { - continue; - } +vx_status Graph::executeGraph(vx_uint32 depth) +{ + vx_status status = VX_SUCCESS; + vx_action action = VX_ACTION_CONTINUE; + vx_uint32 n, p, numLast, numNext, numLeft = 0; + vx_uint32 last_nodes[VX_INT_MAX_REF]; + vx_uint32 next_nodes[VX_INT_MAX_REF]; + vx_uint32 left_nodes[VX_INT_MAX_REF]; + vx_uint32 max_pipeup_depth = 1; + (void)depth; - if (ref->index == 0) - { - x[objectno].ref = ref; - ref->index = objectno++; - } +#if defined(OPENVX_USE_SMP) + vx_value_set_t workitems[VX_INT_MAX_REF]; +#endif - /* Step T2. */ - if (list[n]->kernel->signature.directions[parmno] == VX_INPUT) +#ifdef OPENVX_USE_PIPELINING + // Dequeue graph parameters if pipelining is enabled + if (this->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO || + this->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) + { + for (vx_uint32 i = 0; i < this->numEnqueableParams; i++) + { + auto& paramQueue = this->parameters[i].queue; + vx_reference ref; + + // Dequeue a reference from the "ready" queue + if (paramQueue.peekReady(ref)) { - /* parameter < node */ - j = ref->index; - k = n + 1; + vx_node node = this->parameters[i].node; + vx_uint32 param_index = this->parameters[i].index; + // Save the old reference for this graph parameter + vx_reference old_ref = node->parameters[param_index]; + + // Update ALL node parameters that point to this old reference + if (node->parameters[param_index] != ref) + { + for (vx_uint32 n = 0; n < this->numNodes; n++) + { + for (vx_uint32 p = 0; p < this->nodes[n]->kernel->signature.num_parameters; + p++) + { + // Assign the dequeued reference to the corresponding node parameter + if (this->nodes[n]->parameters[p] == old_ref) + { + this->context->removeReference(this->nodes[n]->parameters[p]); + ref->incrementReference(VX_INTERNAL); + this->nodes[n]->parameters[p] = ref; + } + } + } + } + + VX_PRINT(VX_ZONE_GRAPH, + "Dequeued reference for graph parameter %u and \ + assigned to node parameter %u\n", + i, param_index); } else { - /* node < parameter */ - k = ref->index; - j = n + 1; + VX_PRINT(VX_ZONE_ERROR, "Failed to dequeue reference for graph parameter %u\n", i); + std::cerr << "Failed to dequeue reference for graph parameter " << i << std::endl; + return VX_ERROR_NO_RESOURCES; } - - /* Step T3. */ - x[k].u.count++; - p = avail++; - p->suc = k; - p->next = x[j].top; - x[j].top = p; } } +#endif - /* With a 1-based index, we need to back-off one to get the number of objects. */ - nobjects = objectno - 1; - nremain = nobjects; - - /* At this point, we could visit all the nodes in - x[1..graph->numNodes] (all the first graph->numNodes in x are - nodes) and put those with - count <= node->kernel->signature.num_parameters in graph->heads - (as a node is always dependent on its input parameters and all - nodes have inputs, but some may be nullptr), avoiding the - O(numNodes**2) loop later in our caller. */ - - /* Step T4. Note that we're not zero-based but 1-based; 0 and x[0] - are sentinels. */ - r = 0; - x[0].u.qlink = 0; - for (k = 1; k <= nobjects; k++) + if (this->verified == vx_false_e) { - if (x[k].u.count == 0) + status = vxVerifyGraph((vx_graph)this); + if (status != VX_SUCCESS) { - x[r].u.qlink = k; - r = k; + return status; } } + VX_PRINT(VX_ZONE_GRAPH, "************************\n"); + VX_PRINT(VX_ZONE_GRAPH, "*** PROCESSING GRAPH ***\n"); + VX_PRINT(VX_ZONE_GRAPH, "************************\n"); - f = x[0].u.qlink; - outputnr = 0; - - /* Step T5. (We don't output a final 0 as present in the algorithm.) */ - while (f != 0) + this->state = VX_GRAPH_STATE_RUNNING; + this->clearVisitation(); + this->clearExecution(); + if (context->perf_enabled) { - struct direct_successor *p; - - /* This is our "output". Nodes only; we don't otherwise make - use the order in which parameters are being processed. */ - if (x[f].ref->type == VX_TYPE_NODE) - list[outputnr++] = (vx_node)x[f].ref; - nremain--; - p = x[f].top; - - /* Step T6. */ - while (p != nullptr) - { - if (--x[p->suc].u.count == 0) - { - x[r].u.qlink = p->suc; - r = p->suc; - } - p = p->next; - } - - /* Step T7 */ - f = x[f].u.qlink; + Osal::startCapture(&this->perf); } - /* Step T8. - At this point, we could inspect nremain and if non-zero, we have - a cycle. To wit, we can avoid the O(numNodes**2) loop later in - our caller. We have to do check for cycles anyway, because if - there was a cycle we need to restore *all* the nodes into list[], - or else they can't be disposed of properly. We use the original - order, both for simplicity and because the caller might be making - invalid assumptions; having passed an incorrect graph is cause - for concern about integrity. */ - if (nremain != 0) - for (n = 0; n < nnodes; n++) - list[n] = (vx_node)x[n+1].ref; -} - -vx_bool Graph::setupOutput(vx_uint32 n, vx_uint32 p, vx_reference* vref, vx_meta_format* meta, - vx_status* status, vx_uint32* num_errors) -{ - *vref = nodes[n]->parameters[p]; - *meta = vxCreateMetaFormat(context); + /* initialize the next_nodes as the graph heads */ + memcpy(next_nodes, this->heads, this->numHeads * sizeof(vx_uint32)); + numNext = this->numHeads; - /* check to see if the reference is virtual */ - if ((*vref)->is_virtual == vx_false_e) + do { - *vref = nullptr; - } - else - { - VX_PRINT(VX_ZONE_GRAPH, "Virtual Reference detected at kernel %s parameter %u\n", - nodes[n]->kernel->name, - p); - if ((*vref)->scope->type == VX_TYPE_GRAPH && - (*vref)->scope != (vx_reference)this && - /* We check only one level up; we make use of the - knowledge that this implementation has no more - than one level of child-graphs. (Nodes are only - one level; no child-graph-using node is composed - from other child-graph-using nodes.) We need - this check (for example) for a virtual image - being an output parameter to a node for which - this graph is the child-graph implementation, - like in vx_bug13517.c. */ - (*vref)->scope != (vx_reference)parentGraph) + for (n = 0; n < numNext; n++) { - /* major fault! */ - *status = VX_ERROR_INVALID_SCOPE; - vxAddLogEntry((vx_reference)(*vref), *status, "Virtual Reference is in the wrong scope, created from another graph!\n"); - (*num_errors)++; - return vx_false_e; /* break; */ + Node::printNode(this->nodes[next_nodes[n]]); } - /* ok if context, pyramid or this graph */ - } - - /* the type of the parameter is known by the system, so let the system set it by default. */ - (*meta)->type = nodes[n]->kernel->signature.types[p]; - - return vx_true_e; -} - -/* - * Parameters: - * n - index of node - * p - index of parameter - * vref - reference of the parameter - * meta - parameter meta info - */ -vx_bool Graph::postprocessOutputDataType(vx_uint32 n, vx_uint32 p, vx_reference* item, vx_reference* vref, vx_meta_format meta, - vx_status* status, vx_uint32* num_errors) -{ - if (Context::isValidType(meta->type) == vx_false_e) - { - *status = VX_ERROR_INVALID_TYPE; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] is not a valid type %d!\n", - nodes[n]->kernel->name, p, meta->type); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } - if (meta->type == VX_TYPE_IMAGE) - { - vx_image img = (vx_image)*item; - VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, %ux%u\n", meta->type, meta->dim.image.width, meta->dim.image.height); - if (*vref == (vx_reference)img) + /* execute the next nodes */ + for (n = 0; n < numNext; n++) { - VX_PRINT(VX_ZONE_GRAPH, "Creating Image From Meta Data!\n"); - /*! \todo need to worry about images that have a format, but no dimensions too */ - if (img->format == VX_DF_IMAGE_VIRT || img->format == meta->dim.image.format) + if (this->nodes[next_nodes[n]]->executed == vx_false_e) { - img->format = meta->dim.image.format; - img->width = meta->dim.image.width; - img->height = meta->dim.image.height; - /* we have to go set all the other dimensional information up. */ - img->initImage(img->width, img->height, img->format); - Image::printImage(img); /* show that it's been created. */ - } - else - { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has invalid format %08x!\n", - nodes[n]->kernel->name, p, img->format); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid format %08x!\n", - nodes[n]->kernel->name, p, img->format); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } - } - else - { - /* check the data that came back from the output validator against the object */ - if ((img->width != meta->dim.image.width) || - (img->height != meta->dim.image.height)) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] is an invalid dimension %ux%u!\n", - nodes[n]->kernel->name, p, img->width, img->height); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] is an invalid dimension %ux%u!\n", - nodes[n]->kernel->name, p, img->width, img->height); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: expected dimension %ux%u with format %08x!\n", - nodes[n]->kernel->name, meta->dim.image.width, meta->dim.image.height, meta->dim.image.format); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } - if (img->format != meta->dim.image.format) - { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] is an invalid format %08x!\n", - nodes[n]->kernel->name, p, img->format); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid format %08x!\n", - nodes[n]->kernel->name, p, img->format); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } - } + vx_uint32 t = this->nodes[next_nodes[n]]->affinity; +#if defined(OPENVX_USE_SMP) + if (depth == 1 && this->shouldSerialize == vx_false_e) + { + vx_value_set_t* work = &workitems[n]; + vx_target target = this->context->targets[t]; + vx_node node = this->nodes[next_nodes[n]]; + work->v1 = (vx_value_t)target; + work->v2 = (vx_value_t)node; + work->v3 = (vx_value_t)VX_ACTION_CONTINUE; + VX_PRINT(VX_ZONE_GRAPH, "Scheduling work on %s for %s\n", target->name, + node->kernel->name); + } + else +#endif + { + vx_target target = this->context->targets[t]; + vx_node node = this->nodes[next_nodes[n]]; - if (nullptr != meta->set_valid_rectangle_callback) - nodes[n]->attributes.valid_rect_reset = vx_false_e; + /* turn on access to virtual memory */ + for (p = 0u; p < node->kernel->signature.num_parameters; p++) + { + if (node->parameters[p] == nullptr) continue; + if (node->parameters[p]->is_virtual == vx_true_e) + { + node->parameters[p]->is_accessible = vx_true_e; + } + } - if (vx_false_e == nodes[n]->attributes.valid_rect_reset && - nullptr != meta->set_valid_rectangle_callback) - { - /* calculate image valid rectangle through callback */ + VX_PRINT(VX_ZONE_GRAPH, "Calling Node[%u] %s:%s\n", next_nodes[n], target->name, + node->kernel->name); - vx_uint32 i; - vx_uint32 nparams = 0; - vx_uint32 num_in_images = 0; - vx_rectangle_t** in_rect = nullptr; - vx_rectangle_t* out_rect[1] = { nullptr }; - vx_node node = nodes[n]; + /* Check for pipeup phase: + * If this is the first time we are executing the graph, we need to pipeup + * all nodes with kernels in the graph that need pipeup of refs. + */ + max_pipeup_depth = std::max( + {max_pipeup_depth, node->kernel->input_depth, node->kernel->output_depth}); + if (node->kernel->pipeUpCounter < max_pipeup_depth - 1) + { + node->state = VX_NODE_STATE_PIPEUP; + std::cout << "max_pipeup_depth: " << max_pipeup_depth << std::endl; + node->kernel->pipeUpCounter++; + // Retain input buffers during PIPEUP + for (vx_uint32 i = 0; i < node->kernel->output_depth - 1; i++) + { + action = target->funcs.process(target, &node, 0, 1); + node->kernel->pipeUpCounter++; + } + // For source nodes, provide new output buffers during PIPEUP + for (vx_uint32 i = 0; i < node->kernel->input_depth - 1; i++) + { + action = target->funcs.process(target, &node, 0, 1); + node->kernel->pipeUpCounter++; + } + } - /* assume no errors */ - vx_bool res = vx_true_e; + /* If this node was in pipeup, update its state */ + node->state = VX_NODE_STATE_STEADY; - if (VX_SUCCESS != vxQueryNode(node, VX_NODE_PARAMETERS, &nparams, sizeof(nparams))) - { - *status = VX_FAILURE; - return vx_false_e; - } + action = target->funcs.process(target, &node, 0, 1); - /* compute num of input images */ - for (i = 0; i < nparams; i++) - { - if (VX_INPUT == node->kernel->signature.directions[i] && - VX_TYPE_IMAGE == node->parameters[i]->type) - { - num_in_images++; - } - } + VX_PRINT(VX_ZONE_GRAPH, "Returned Node[%u] %s:%s Action %d\n", next_nodes[n], + target->name, node->kernel->name, action); - /* allocate array of pointers to input images valid rectangles */ - in_rect = new vx_rectangle_t*[num_in_images](); - if (nullptr == in_rect) - { - *status = VX_FAILURE; - return vx_false_e; - } + /* turn off access to virtual memory */ + for (p = 0u; p < node->kernel->signature.num_parameters; p++) + { + if (node->parameters[p] == nullptr) + { + continue; + } + if (node->parameters[p]->is_virtual == vx_true_e) + { + node->parameters[p]->is_accessible = vx_false_e; + } + } - for (i = 0; i < nparams; i++) - { - if (VX_INPUT == node->kernel->signature.directions[i] && - VX_TYPE_IMAGE == node->parameters[i]->type) - { - in_rect[i] = new vx_rectangle_t(); - if (nullptr == in_rect[i]) +#ifdef OPENVX_USE_PIPELINING + /* Raise a node completed event. */ + vx_event_info_t event_info; + event_info.node_completed.graph = this; + event_info.node_completed.node = node; + if (this->context->event_queue.isEnabled() && + VX_SUCCESS != this->context->event_queue.push(VX_EVENT_NODE_COMPLETED, 0, + &event_info, + (vx_reference)node)) { - *status = VX_FAILURE; - res = vx_false_e; - break; + VX_PRINT(VX_ZONE_ERROR, "Failed to push node completed event for node %s\n", + node->kernel->name); } - /* collect input images valid rectagles in array */ - if (VX_SUCCESS != vxGetValidRegionImage((vx_image)node->parameters[i], in_rect[i])) + /* Raise a graph parameter consumed event */ + for (vx_uint32 gp = 0; gp < this->numEnqueableParams; gp++) { - *status = VX_FAILURE; - res = vx_false_e; + vx_node param_node = this->parameters[gp].node; + vx_uint32 param_index = this->parameters[gp].index; + + /* If this node just executed and consumed a graph parameter */ + if (param_node == node) + { + vx_event_info_t event_info = {}; + event_info.graph_parameter_consumed.graph = this; + event_info.graph_parameter_consumed.graph_parameter_index = param_index; + + (void)this->parameters[gp].queue.moveReadyToDone(); + + if (this->context->event_queue.isEnabled() && + param_node->kernel->signature.directions[param_index] == VX_INPUT && + VX_SUCCESS != this->context->event_queue.push( + VX_EVENT_GRAPH_PARAMETER_CONSUMED, 0, &event_info, + (vx_reference)this)) + { + VX_PRINT(VX_ZONE_ERROR, + "Failed to push graph parameter consumed event for " + "graph %p, param %u\n", + this, gp); + } + } + } +#endif + + if (action == VX_ACTION_ABANDON) + { +#ifdef OPENVX_USE_PIPELINING + /* Raise a node error event. */ + vx_event_info_t event_info; + event_info.node_error.graph = this; + event_info.node_error.node = node; + event_info.node_error.status = node->status; + if (this->context->event_queue.isEnabled() && + VX_SUCCESS != this->context->event_queue.push(VX_EVENT_NODE_ERROR, 0, + &event_info, + (vx_reference)node)) + { + VX_PRINT(VX_ZONE_ERROR, "Failed to push node error event for node %s\n", + node->kernel->name); + } +#endif break; } } } + else + { + VX_PRINT(VX_ZONE_ERROR, "Multiple executions attempted!\n"); + break; + } + } - if (vx_false_e != res) +#if defined(OPENVX_USE_SMP) + if (depth == 1 && this->shouldSerialize == vx_false_e) + { + if (Osal::issueThreadpool(this->context->workers, workitems, numNext) == vx_true_e) { - out_rect[0] = new vx_rectangle_t(); - if (nullptr == out_rect[0]) + /* do a blocking complete */ + VX_PRINT(VX_ZONE_GRAPH, "Issued %u work items!\n", numNext); + if (Osal::completeThreadpool(this->context->workers, vx_true_e) == vx_true_e) { - *status = VX_FAILURE; - res = vx_false_e; + VX_PRINT(VX_ZONE_GRAPH, "Processed %u items in threadpool!\n", numNext); } - - /* calculate output image valid rectangle */ - if (VX_SUCCESS == meta->set_valid_rectangle_callback(nodes[n], p, (const vx_rectangle_t* const*)in_rect, - (vx_rectangle_t* const*)out_rect)) + action = VX_ACTION_CONTINUE; + for (n = 0; n < numNext; n++) { - /* set output image valid rectangle */ - if (VX_SUCCESS != vxSetImageValidRectangle(img, (const vx_rectangle_t*)out_rect[0])) + vx_action a = workitems[n].v3; + if (a != VX_ACTION_CONTINUE) { - *status = VX_FAILURE; - res = vx_false_e; + action = a; + VX_PRINT(VX_ZONE_WARNING, "Workitem[%u] returned action code %d\n", n, a); + break; } } - else - { - *status = VX_FAILURE; - res = vx_false_e; - } } + } +#endif - /* deallocate arrays memory */ - for (i = 0; i < num_in_images; i++) - { - if (nullptr != in_rect[i]) - { - delete(in_rect[i]); - } - } + if (action == VX_ACTION_ABANDON) + { + break; + } - if (nullptr != in_rect) - delete[](in_rect); - if (nullptr != out_rect[0]) - delete(out_rect[0]); + /* copy next_nodes to last_nodes */ + memcpy(last_nodes, next_nodes, numNext * sizeof(vx_uint32)); + numLast = numNext; + /* determine the next nodes */ + this->findNextNodes(last_nodes, numLast, next_nodes, &numNext, left_nodes, &numLeft); - return res; - } + } while (numNext > 0); - if (vx_true_e == nodes[n]->attributes.valid_rect_reset) - { - /* reset image valid rectangle */ - vx_rectangle_t out_rect; - out_rect.start_x = 0; - out_rect.start_y = 0; - out_rect.end_x = img->width; - out_rect.end_y = img->height; + if (action == VX_ACTION_ABANDON) + { + status = VX_ERROR_GRAPH_ABANDONED; + } + if (context->perf_enabled) + { + Osal::stopCapture(&this->perf); + } + this->clearVisitation(); - if (VX_SUCCESS != vxSetImageValidRectangle(img, &out_rect)) - { - *status = VX_FAILURE; - return vx_false_e; - } - } - } /* VX_TYPE_IMAGE */ - else if (meta->type == VX_TYPE_ARRAY) + for (n = 0; n < VX_INT_MAX_REF; n++) { - vx_array arr = (vx_array)*item; - VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, 0x%08x " VX_FMT_SIZE "\n", meta->type, meta->dim.array.item_type, meta->dim.array.capacity); - if (*vref == (vx_reference)arr) - { - VX_PRINT(VX_ZONE_GRAPH, "Creating Array From Meta Data %x and " VX_FMT_SIZE "!\n", meta->dim.array.item_type, meta->dim.array.capacity); - if (arr->initVirtualArray(meta->dim.array.item_type, meta->dim.array.capacity) != vx_true_e) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: meta[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, meta->dim.array.item_type, meta->dim.array.capacity); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, meta->dim.array.item_type, meta->dim.array.capacity); - (*num_errors)++; - return vx_false_e; //break; - } - } - else + if (this->delays[n] && + Reference::isValidReference(reinterpret_cast(this->delays[n]), + VX_TYPE_DELAY) == vx_true_e) { - if (arr->validateArray(meta->dim.array.item_type, meta->dim.array.capacity) != vx_true_e) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, arr->item_type, arr->capacity); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, arr->item_type, arr->capacity); - (*num_errors)++; - return vx_false_e; //break; - } + vxAgeDelay(this->delays[n]); } } - else if (meta->type == VX_TYPE_PYRAMID) - { - vx_pyramid pyramid = (vx_pyramid)*item; - vx_uint32 i; - vx_bool res = vx_true_e; + VX_PRINT(VX_ZONE_GRAPH, "Process returned status %d\n", status); - VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, %ux%u:%u:%lf\n", - meta->type, - meta->dim.pyramid.width, - meta->dim.pyramid.height, - meta->dim.pyramid.levels, - meta->dim.pyramid.scale); - VX_PRINT(VX_ZONE_GRAPH, "Nodes[%u] %s parameters[%u]\n", n, nodes[n]->kernel->name, p); +#ifdef OPENVX_USE_PIPELINING + /* Raise a graph completed event. */ + vx_event_info_t event_info; + event_info.graph_completed.graph = this; + if (this->context->event_queue.isEnabled() && + VX_SUCCESS != this->context->event_queue.push(VX_EVENT_GRAPH_COMPLETED, 0, &event_info, + (vx_reference)this)) + { + VX_PRINT(VX_ZONE_ERROR, "Failed to push graph completed event for graph %p\n", this); + } +#endif - if ((pyramid->numLevels != meta->dim.pyramid.levels) || - (pyramid->scale != meta->dim.pyramid.scale)) + // Report the performance of the graph execution. + if (context->perf_enabled) + { + for (n = 0; n < this->numNodes; n++) { - *status = VX_ERROR_INVALID_VALUE; - vxAddLogEntry(reinterpret_cast(this), *status, "Either levels (%u?=%u) or scale (%lf?=%lf) are invalid\n", - pyramid->numLevels, meta->dim.pyramid.levels, - pyramid->scale, meta->dim.pyramid.scale); - (*num_errors)++; - return vx_false_e; //break; + VX_PRINT( + VX_ZONE_PERF, + "nodes[%u] %s[%d] last:" VX_FMT_TIME "ms avg:" VX_FMT_TIME "ms min:" VX_FMT_TIME + "ms max:" VX_FMT_TIME "\n", + n, this->nodes[n]->kernel->name, this->nodes[n]->kernel->enumeration, + Osal::timeToMS(this->nodes[n]->perf.tmp), Osal::timeToMS(this->nodes[n]->perf.avg), + Osal::timeToMS(this->nodes[n]->perf.min), Osal::timeToMS(this->nodes[n]->perf.max)); } + } - if ((pyramid->format != VX_DF_IMAGE_VIRT) && - (pyramid->format != meta->dim.pyramid.format)) + if (status == VX_SUCCESS) + { + this->state = VX_GRAPH_STATE_COMPLETED; + } + else + { + this->state = VX_GRAPH_STATE_ABANDONED; + } + + return status; +} + +vx_status Graph::schedule() +{ + vx_status status = VX_SUCCESS; + + if (verified == vx_false_e) + { + status = verify(); + if (status != VX_SUCCESS) { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, "Invalid pyramid format %x, needs %x\n", - pyramid->format, - meta->dim.pyramid.format); - (*num_errors)++; - return vx_false_e; //break; + return status; } + } - if (((pyramid->width != 0) && - (pyramid->width != meta->dim.pyramid.width)) || - ((pyramid->height != 0) && - (pyramid->height != meta->dim.pyramid.height))) +#ifdef OPENVX_USE_PIPELINING + vx_uint32 numParams = std::min(this->numParams, numEnqueableParams); + vx_size batch_depth = 1u; + if (scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) + { + batch_depth = UINT32_MAX; // Use UINT32_MAX to indicate no limit on batch depth + for (vx_uint32 i = 0; i < numParams; ++i) { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, "Invalid pyramid dimensions %ux%u, needs %ux%u\n", - pyramid->width, pyramid->height, - meta->dim.pyramid.width, meta->dim.pyramid.height); - (*num_errors)++; - return vx_false_e; //break; + batch_depth = std::min(batch_depth, parameters[i].queue.readyQueueSize()); } - /* check to see if the pyramid is virtual */ - if (*vref == (vx_reference)pyramid) + if (batch_depth == 0 || batch_depth == UINT32_MAX) { - pyramid->initPyramid( - meta->dim.pyramid.levels, - meta->dim.pyramid.scale, - meta->dim.pyramid.width, - meta->dim.pyramid.height, - meta->dim.pyramid.format); + // Not enough data to schedule a batch + return VX_ERROR_NOT_SUFFICIENT; } + } - if (nullptr != meta->set_valid_rectangle_callback) - nodes[n]->attributes.valid_rect_reset = vx_false_e; + for (vx_uint32 i = 0; i < batch_depth; i++) +#endif + // if (Osal::semTryWait(&lock) == vx_true_e) + { + Osal::semTryWait(&lock); + vx_sem_t* p_graph_queue_lock = context->p_global_lock; + vx_uint32 q = 0u; + vx_value_set_t* pq = nullptr; - if (vx_false_e == nodes[n]->attributes.valid_rect_reset && - nullptr != meta->set_valid_rectangle_callback) + Osal::semWait(p_graph_queue_lock); + /* acquire a position in the graph queue */ + for (q = 0; q < dimof(context->graph_queue); q++) { - /* calculate pyramid levels valid rectangles */ - - vx_uint32 nparams = 0; - vx_uint32 num_in_images = 0; - vx_rectangle_t** in_rect = nullptr; - vx_rectangle_t** out_rect = nullptr; - - vx_node node = nodes[n]; - - if (VX_SUCCESS != vxQueryNode(node, VX_NODE_PARAMETERS, &nparams, sizeof(nparams))) + if (context->graph_queue[q].v1 == 0) { - *status = VX_FAILURE; - return vx_false_e; + pq = &context->graph_queue[q]; + context->numGraphsQueued++; + break; } + } + Osal::semPost(p_graph_queue_lock); + if (pq) + { + memset(pq, 0, sizeof(vx_value_set_t)); + pq->v1 = (vx_value_t)this; - /* compute num of input images */ - for (i = 0; i < nparams; i++) +#ifdef OPENVX_USE_PIPELINING + /* Increment the schedule count */ + scheduleCount++; +#endif + /* now add the graph to the queue */ + VX_PRINT(VX_ZONE_GRAPH, "Writing graph=" VX_FMT_REF ", status=%d\n", this, status); + if (Osal::writeQueue(&context->proc.input, pq) == vx_true_e) { - if (VX_INPUT == node->kernel->signature.directions[i] && - VX_TYPE_IMAGE == node->parameters[i]->type) - { - num_in_images++; - } + status = VX_SUCCESS; } - - in_rect = new vx_rectangle_t* [num_in_images](); - if (nullptr == in_rect) + else { - *status = VX_FAILURE; - return vx_false_e; + Osal::semPost(&lock); + VX_PRINT(VX_ZONE_ERROR, "Failed to write graph to queue"); + status = VX_ERROR_NO_RESOURCES; } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Graph queue is full\n"); + status = VX_ERROR_NO_RESOURCES; + } + } + // else + // { + // /* graph is already scheduled */ + // VX_PRINT(VX_ZONE_WARNING, "Graph is already scheduled!\n"); + // // status = VX_ERROR_GRAPH_SCHEDULED; + // } - for (i = 0; i < num_in_images; i++) - in_rect[i] = nullptr; + return status; +} - for (i = 0; i < nparams; i++) +vx_status Graph::wait() +{ + vx_status status = VX_SUCCESS; + + if (Osal::semTryWait(&lock) == vx_false_e || + scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) /* locked */ + { + vx_sem_t* p_graph_queue_lock = context->p_global_lock; + vx_graph g2; + vx_bool ret = vx_true_e; + vx_value_set_t* data = nullptr; + do + { + ret = Osal::readQueue(&context->proc.output, &data); + if (ret == vx_false_e) { - if (VX_INPUT == node->kernel->signature.directions[i] && - VX_TYPE_IMAGE == node->parameters[i]->type) + /* graph was locked but the queue was empty... */ + VX_PRINT(VX_ZONE_ERROR, "Queue was empty but graph was locked.\n"); + status = VX_FAILURE; + } + else + { + g2 = (vx_graph)data->v1; + status = (vx_status)data->v2; + if (g2 == this) /* great, it's the graph we want. */ { - in_rect[i] = new vx_rectangle_t(); - if (nullptr == in_rect[i]) + vx_uint32 q = 0u; + Osal::semWait(p_graph_queue_lock); + /* find graph in the graph queue */ + for (q = 0; q < dimof(context->graph_queue); q++) { - *status = VX_FAILURE; - res = vx_false_e; - break; + if (context->graph_queue[q].v1 == (vx_value_t)this) + { + context->graph_queue[q].v1 = 0; + context->numGraphsQueued--; + break; + } } + Osal::semPost(p_graph_queue_lock); - if (VX_SUCCESS != vxGetValidRegionImage((vx_image)node->parameters[i], in_rect[i])) +#ifdef OPENVX_USE_PIPELINING + /* Decrement the schedule count */ + scheduleCount--; + /* Unlock the graph only if all scheduled executions are completed */ + if (scheduleCount == 0) { - *status = VX_FAILURE; - res = vx_false_e; + Osal::semPost(&lock); break; } +#else + break; +#endif } - } - - if (vx_false_e != res) - { - out_rect = new vx_rectangle_t*[meta->dim.pyramid.levels](); - if (nullptr != out_rect) + else { - vx_uint32 k; - for (k = 0; k < meta->dim.pyramid.levels; k++) - out_rect[k] = nullptr; + /* not the right graph, put it back. */ + Osal::writeQueue(&context->proc.output, data); + } + } + } while (ret == vx_true_e); + Osal::semPost(&lock); /* unlock the graph. */ + } + else + { + // status = VX_FAILURE; + Osal::semPost(&lock); /* was free, release */ + } - for (i = 0; i < meta->dim.pyramid.levels; i++) - { - out_rect[i] = new vx_rectangle_t(); - if (nullptr == out_rect[i]) - { - *status = VX_FAILURE; - res = vx_false_e; - break; - } - } - } - else - { - *status = VX_FAILURE; - res = vx_false_e; - } - } + return status; +} - if (vx_false_e != res) - { - /* calculate pyramid levels valid rectangles */ - if (VX_SUCCESS == meta->set_valid_rectangle_callback(nodes[n], p, (const vx_rectangle_t* const*)in_rect, out_rect)) - { - for (i = 0; i < meta->dim.pyramid.levels; i++) - { - vx_image img = vxGetPyramidLevel(pyramid, i); +vx_status Graph::processGraph() +{ + vx_status status = VX_SUCCESS; - if (vx_false_e == Reference::isValidReference((vx_reference)img, VX_TYPE_IMAGE)) - { - *status = VX_FAILURE; - res = vx_false_e; - vxReleaseImage(&img); /* already on error path, ignore additional errors */ - break; - } + /* create a counter for re-entrancy checking */ + static vx_uint32 count = 0; + vx_sem_t* p_sem = context->p_global_lock; - if (VX_SUCCESS != vxSetImageValidRectangle(img, out_rect[i])) - { - *status = VX_FAILURE; - res = vx_false_e; - vxReleaseImage(&img); /* already on error path, ignore additional errors */ - break; - } + Osal::semWait(p_sem); + count++; + Osal::semPost(p_sem); + status = executeGraph(count); + Osal::semWait(p_sem); + count--; + Osal::semPost(p_sem); - if (VX_SUCCESS != vxReleaseImage(&img)) - { - *status = VX_FAILURE; - res = vx_false_e; - break; - } - } /* for pyramid levels */ - } - else - { - *status = VX_FAILURE; - res = vx_false_e; - } - } /* if successful memory allocation */ + return status; +} - /* deallocate rectangle arrays */ - for (i = 0; i < num_in_images; i++) - { - if (nullptr != in_rect && nullptr != in_rect[i]) - { - delete(in_rect[i]); - } - } +vx_status Graph::addParameter(vx_parameter param) +{ + vx_status status = VX_ERROR_INVALID_PARAMETERS; - if (nullptr != in_rect) - delete[](in_rect); + if (Reference::isValidReference(reinterpret_cast(param), VX_TYPE_PARAMETER) == + vx_true_e) + { + parameters[numParams].node = param->node; + parameters[numParams].index = param->index; + numParams++; + status = VX_SUCCESS; + } + else if (Reference::isValidReference(reinterpret_cast(param), + VX_TYPE_PARAMETER) == vx_false_e) + { + /* insert an empty parameter */ + parameters[numParams].node = nullptr; + parameters[numParams].index = 0; + numParams++; + status = VX_SUCCESS; + } - for (i = 0; i < meta->dim.pyramid.levels; i++) - { - if (nullptr != out_rect && nullptr != out_rect[i]) - delete(out_rect[i]); - } + return status; +} - if (nullptr != out_rect) - delete[](out_rect); +vx_status Graph::setParameterByIndex(vx_uint32 index, vx_reference value) +{ + vx_status status = VX_SUCCESS; - return res; - } + if (index < VX_INT_MAX_PARAMS) + { + status = + Parameter::setParameterByIndex(parameters[index].node, parameters[index].index, value); + } + else + { + status = VX_ERROR_INVALID_VALUE; + } - if (vx_true_e == nodes[n]->attributes.valid_rect_reset) - { - /* reset output pyramid levels valid rectangles */ + return status; +} - vx_bool res = vx_true_e; +vx_parameter Graph::getParameterByIndex(vx_uint32 index) +{ + vx_parameter parameter = nullptr; - for (i = 0; i < meta->dim.pyramid.levels; i++) - { - vx_uint32 width = 0; - vx_uint32 height = 0; - vx_rectangle_t out_rect; + if ((index < VX_INT_MAX_PARAMS) && (index < numParams)) + { + vx_uint32 node_index = parameters[index].index; + parameter = Parameter::getParameterByIndex(parameters[index].node, node_index); + } - vx_image img = vxGetPyramidLevel(pyramid, i); + return parameter; +} - if (vx_false_e == Reference::isValidReference((vx_reference)img, VX_TYPE_IMAGE)) - { - *status = VX_FAILURE; - return vx_false_e; - } +void Graph::clearVisitation() +{ + vx_uint32 n = 0; + for (n = 0; n < numNodes; n++) + nodes[n]->visited = vx_false_e; +} - if (VX_SUCCESS != vxQueryImage(img, VX_IMAGE_WIDTH, &width, sizeof(width))) +void Graph::clearExecution() +{ + vx_uint32 n = 0; + for (n = 0; n < numNodes; n++) + nodes[n]->executed = vx_false_e; +} + +vx_status Graph::findNodesWithReference( + vx_reference ref, + vx_uint32 refnodes[], + vx_uint32 *count, + vx_enum reftype) +{ + vx_uint32 n, p, nc = 0, max; + vx_status status = VX_ERROR_INVALID_LINK; + + /* save the maximum number of nodes to find */ + max = *count; + + /* reset the current count to zero */ + *count = 0; + + VX_PRINT(VX_ZONE_GRAPH,"Find nodes with reference " VX_FMT_REF " type %d over %u nodes upto %u finds\n", ref, reftype, numNodes, max); + for (n = 0; n < numNodes; n++) + { + for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) + { + vx_enum dir = nodes[n]->kernel->signature.directions[p]; + vx_reference thisref = nodes[n]->parameters[p]; + + VX_PRINT(VX_ZONE_GRAPH,"\tchecking node[%u].parameter[%u] dir = %d ref = " VX_FMT_REF " (=?%d:" VX_FMT_REF ")\n", n, p, dir, thisref, reftype, ref); + if ((dir == reftype) && Graph::checkWriteDependency(thisref, ref)) + { + if (nc < max) { - *status = VX_FAILURE; - res = vx_false_e; - vxReleaseImage(&img); /* already on error path, ignore additional errors */ - break; + VX_PRINT(VX_ZONE_GRAPH, "match at node[%u].parameter[%u]\n", n, p); + if (refnodes) + refnodes[nc] = n; + nc++; + status = VX_SUCCESS; } - - if (VX_SUCCESS != vxQueryImage(img, VX_IMAGE_HEIGHT, &height, sizeof(height))) + else { - *status = VX_FAILURE; - res = vx_false_e; - vxReleaseImage(&img); /* already on error path, ignore additional errors */ - break; + VX_PRINT(VX_ZONE_ERROR, "ERROR: Overflow in refnodes[]\n"); } + } + } + } + *count = nc; + VX_PRINT(VX_ZONE_GRAPH, "Found %u nodes with reference " VX_FMT_REF " status = %d\n", nc, ref, status); + return status; +} - if (vx_false_e != res) - { - out_rect.start_x = 0; - out_rect.start_y = 0; - out_rect.end_x = width; - out_rect.end_y = height; +void Graph::findNextNodes( + vx_uint32 last_nodes[VX_INT_MAX_REF], vx_uint32 numLast, + vx_uint32 next_nodes[VX_INT_MAX_REF], vx_uint32 *numNext, + vx_uint32 left_nodes[VX_INT_MAX_REF], vx_uint32 *numLeft) +{ + vx_uint32 poss_next[VX_INT_MAX_REF]; + vx_uint32 i,n,p,n1,numPoss = 0; - /* pyramid level valid rectangle is a whole image */ - if (VX_SUCCESS != vxSetImageValidRectangle(img, &out_rect)) - { - *status = VX_FAILURE; - res = vx_false_e; - } - } + VX_PRINT(VX_ZONE_GRAPH, "Entering with %u left nodes\n", *numLeft); + for (n = 0; n < *numLeft; n++) + { + VX_PRINT(VX_ZONE_GRAPH, "leftover: node[%u] = %s\n", left_nodes[n], nodes[left_nodes[n]]->kernel->name); + } - if (VX_SUCCESS != vxReleaseImage(&img)) - { - *status = VX_FAILURE; - res = vx_false_e; - } - } /* for pyramid levels */ + numPoss = 0; + *numNext = 0; - return res; - } - } /* VX_TYPE_PYRAMID */ - else if (meta->type == VX_TYPE_SCALAR) + /* for each last node, add all output to input nodes to the list of possible. */ + for (i = 0; i < numLast; i++) { - vx_scalar scalar = (vx_scalar)*item; - if (scalar->data_type != meta->dim.scalar.type) + n = last_nodes[i]; + for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) { - *status = VX_ERROR_INVALID_TYPE; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, - "Scalar contains invalid typed objects for node %s\n", nodes[n]->kernel->name); - (*num_errors)++; - return vx_false_e; //break; + vx_enum dir = nodes[n]->kernel->signature.directions[p]; + vx_reference ref = nodes[n]->parameters[p]; + if (((dir == VX_OUTPUT) || (dir == VX_BIDIRECTIONAL)) && (ref != nullptr)) + { + /* send the max possible nodes */ + n1 = dimof(poss_next) - numPoss; + if (findNodesWithReference(ref, &poss_next[numPoss], &n1, VX_INPUT) == VX_SUCCESS) + { + VX_PRINT(VX_ZONE_GRAPH, "Adding %u nodes to possible list\n", n1); + numPoss += n1; + } + } } - } /* VX_TYPE_SCALAR */ - else if (meta->type == VX_TYPE_MATRIX) + } + + VX_PRINT(VX_ZONE_GRAPH, "There are %u possible nodes\n", numPoss); + + /* add back all the left over nodes (making sure to not include duplicates) */ + for (i = 0; i < *numLeft; i++) { - vx_matrix matrix = (vx_matrix)*item; - if (matrix->data_type != meta->dim.matrix.type) + vx_uint32 j; + vx_bool match = vx_false_e; + for (j = 0; j < numPoss; j++) { - *status = VX_ERROR_INVALID_TYPE; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, - "Node: %s: parameter[%u] has an invalid data type 0x%08x\n", - nodes[n]->kernel->name, p, matrix->data_type); - (*num_errors)++; - return vx_false_e; //break; + if (left_nodes[i] == poss_next[j]) + { + match = vx_true_e; + } } - - if (matrix->columns != meta->dim.matrix.cols || matrix->rows != meta->dim.matrix.rows) + if (match == vx_false_e) { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid matrix dimention %ux%u\n", - nodes[n]->kernel->name, p, matrix->data_type, matrix->rows, matrix->columns); - (*num_errors)++; - return vx_false_e; //break; + VX_PRINT(VX_ZONE_GRAPH, "Adding back left over node[%u] %s\n", left_nodes[i], nodes[left_nodes[i]]->kernel->name); + poss_next[numPoss++] = left_nodes[i]; } - } /* VX_TYPE_MATRIX */ - else if (meta->type == VX_TYPE_DISTRIBUTION) + } + *numLeft = 0; + + /* now check all possible next nodes to see if the parent nodes are visited. */ + for (i = 0; i < numPoss; i++) { - vx_distribution distribution = (vx_distribution)*item; - //fix - if (distribution->offset_x != meta->dim.distribution.offset || - distribution->range_x != meta->dim.distribution.range || - distribution->memory.dims[0][VX_DIM_X] != meta->dim.distribution.bins) + vx_uint32 poss_params[VX_INT_MAX_PARAMS]; + vx_uint32 pi, numPossParam = 0; + vx_bool ready = vx_true_e; + + n = poss_next[i]; + VX_PRINT(VX_ZONE_GRAPH, "possible: node[%u] = %s\n", n, nodes[n]->kernel->name); + for (p = 0; p < nodes[n]->kernel->signature.num_parameters; p++) { - *status = VX_ERROR_INVALID_VALUE; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_VALUE, - "Node: %s: parameter[%u] has an invalid offset %u, number of bins %u or range %u\n", - nodes[n]->kernel->name, p, distribution->offset_x, - distribution->memory.dims[0][VX_DIM_X], distribution->range_x); - (*num_errors)++; - return vx_false_e; //break; + if (nodes[n]->kernel->signature.directions[p] == VX_INPUT) + { + VX_PRINT(VX_ZONE_GRAPH,"nodes[%u].parameter[%u] predicate needs to be checked\n", n, p); + poss_params[numPossParam] = p; + numPossParam++; + } } - } /* VX_TYPE_DISTRIBUTION */ - else if (meta->type == VX_TYPE_REMAP) - { - vx_remap remap = (vx_remap)*item; - if (remap->src_width != meta->dim.remap.src_width || remap->src_height != meta->dim.remap.src_height) + + /* now check to make sure all possible input parameters have their */ + /* parent nodes executed. */ + for (pi = 0; pi < numPossParam; pi++) { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid source dimention %ux%u\n", - nodes[n]->kernel->name, p); - (*num_errors)++; - return vx_false_e; //break; - } + vx_uint32 predicate_nodes[VX_INT_MAX_REF]; + vx_uint32 predicate_count = 0; + vx_uint32 predicate_index = 0; + vx_uint32 refIdx = 0; + vx_reference ref = 0; + vx_enum reftype[2] = {VX_OUTPUT, VX_BIDIRECTIONAL}; - if (remap->dst_width != meta->dim.remap.dst_width || remap->dst_height != meta->dim.remap.dst_height) + p = poss_params[pi]; + ref = nodes[n]->parameters[p]; + VX_PRINT(VX_ZONE_GRAPH, "checking node[%u].parameter[%u] = " VX_FMT_REF "\n", n, p, ref); + + for(refIdx = 0; refIdx < dimof(reftype); refIdx++) + { + /* set the size of predicate nodes going in */ + predicate_count = dimof(predicate_nodes); + if (findNodesWithReference(ref, predicate_nodes, &predicate_count, reftype[refIdx]) == VX_SUCCESS) + { + /* check to see of all of the predicate nodes are executed */ + for (predicate_index = 0; + predicate_index < predicate_count; + predicate_index++) + { + n1 = predicate_nodes[predicate_index]; + if (nodes[n1]->executed == vx_false_e) + { + VX_PRINT(VX_ZONE_GRAPH, "predicated: node[%u] = %s\n", n1, nodes[n1]->kernel->name); + ready = vx_false_e; + break; + } + } + } + if(ready == vx_false_e) + { + break; + } + } + } + if (ready == vx_true_e) { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid destination dimention %ux%u", - nodes[n]->kernel->name, p); - (*num_errors)++; - return vx_false_e; //break; + /* make sure we don't schedule this node twice */ + if (nodes[n]->visited == vx_false_e) + { + next_nodes[(*numNext)++] = n; + nodes[n]->visited = vx_true_e; + } } - } /* VX_TYPE_REMAP */ - else if (meta->type == VX_TYPE_LUT) - { - vx_lut_t lut = (vx_lut_t)*item; - if (lut->item_type != meta->dim.lut.type || lut->num_items != meta->dim.lut.count) + else { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid item type 0x%08x or count " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, lut->item_type, lut->num_items); - (*num_errors)++; - return vx_false_e; //break; + /* put the node back into the possible list for next time */ + left_nodes[(*numLeft)++] = n; + VX_PRINT(VX_ZONE_GRAPH, "notready: node[%u] = %s\n", n, nodes[n]->kernel->name); } - } /* VX_TYPE_LUT */ - else if (meta->type == VX_TYPE_THRESHOLD) + } + + VX_PRINT(VX_ZONE_GRAPH, "%u Next Nodes\n", *numNext); + for (i = 0; i < *numNext; i++) { - vx_threshold threshold = (vx_threshold)*item; - if (threshold->thresh_type != meta->dim.threshold.type) + n = next_nodes[i]; + VX_PRINT(VX_ZONE_GRAPH, "next: node[%u] = %s\n", n, nodes[n]->kernel->name); + } + VX_PRINT(VX_ZONE_GRAPH, "%u Left Nodes\n", *numLeft); + for (i = 0; i < *numLeft; i++) + { + n = left_nodes[i]; + VX_PRINT(VX_ZONE_GRAPH, "left: node[%u] = %s\n", n, nodes[n]->kernel->name); + } +} + +vx_status Graph::traverseGraph(vx_uint32 parentIndex, + vx_uint32 childIndex) +{ + /* this is expensive, but needed in order to know who references a parameter */ + static vx_uint32 refNodes[VX_INT_MAX_REF]; + /* this keeps track of the available starting point in the static buffer */ + static vx_uint32 refStart = 0; + /* this makes sure we don't have any odd conditions about infinite depth */ + static vx_uint32 depth = 0; + + vx_uint32 refCount = 0; + vx_uint32 refIndex = 0; + vx_uint32 thisIndex = 0; + vx_status status = VX_SUCCESS; + vx_uint32 p = 0; + + VX_PRINT(VX_ZONE_GRAPH, "refStart = %u\n", refStart); + + if (parentIndex == childIndex && parentIndex != VX_INT_MAX_NODES) + { + VX_PRINT(VX_ZONE_ERROR, "################################\n"); + VX_PRINT(VX_ZONE_ERROR, "ERROR: CYCLE DETECTED! node[%u]\n", parentIndex); + VX_PRINT(VX_ZONE_ERROR, "################################\n"); + /* there's a cycle in the graph */ + status = VX_ERROR_INVALID_GRAPH; + } + else if (depth > numNodes) /* should be impossible under normal circumstances */ + { + /* there's a cycle in the graph */ + status = VX_ERROR_INVALID_GRAPH; + } + else + { + /* if the parent is an invalid index, then we assume we're processing a + * head of a graph which has no parent index. + */ + if (parentIndex == VX_INT_MAX_NODES) { - *status = VX_ERROR_INVALID_TYPE; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, - "Threshold contains invalid typed objects for node %s\n", nodes[n]->kernel->name); - (*num_errors)++; - return vx_false_e; //break; + parentIndex = childIndex; + thisIndex = parentIndex; + VX_PRINT(VX_ZONE_GRAPH, "Starting head-first traverse of graph from node[%u]\n", thisIndex); } - } /* VX_TYPE_THRESHOLD */ - else if (meta->type == VX_TYPE_TENSOR) + else + { + thisIndex = childIndex; + VX_PRINT(VX_ZONE_GRAPH, "continuing traverse of graph from node[%u] on node[%u] start=%u\n", parentIndex, thisIndex, refStart); + } + + for (p = 0; p < nodes[thisIndex]->kernel->signature.num_parameters; p++) + { + vx_enum dir = nodes[thisIndex]->kernel->signature.directions[p]; + vx_reference ref = nodes[thisIndex]->parameters[p]; + + if (dir != VX_INPUT && ref != nullptr) + { + VX_PRINT(VX_ZONE_GRAPH, "[traverse] node[%u].parameter[%u] = " VX_FMT_REF "\n", thisIndex, p, ref); + /* send the maximum number of possible nodes to find */ + refCount = dimof(refNodes) - refStart; + status = findNodesWithReference(ref, &refNodes[refStart], &refCount, VX_INPUT); + VX_PRINT(VX_ZONE_GRAPH, "status = %d at node[%u] start=%u count=%u\n", status, thisIndex, refStart, refCount); + if (status == VX_SUCCESS) + { + vx_uint32 refStop = refStart + refCount; + VX_PRINT(VX_ZONE_GRAPH, "Looping from %u to %u\n", refStart, refStop); + for (refIndex = refStart; refIndex < refStop; refIndex++) + { + vx_status child_status = VX_SUCCESS; + VX_PRINT(VX_ZONE_GRAPH, "node[%u] => node[%u]\n", thisIndex, refNodes[refIndex]); + refStart += refCount; + depth++; /* go one more level in */ + child_status = traverseGraph(thisIndex, refNodes[refIndex]); + if (child_status != VX_SUCCESS) + status = child_status; + depth--; /* pull out one level */ + refStart -= refCount; + VX_PRINT(VX_ZONE_GRAPH, "status = %d at node[%u]\n", status, thisIndex); + } + } + if (status == VX_ERROR_INVALID_LINK) /* no links at all */ + { + VX_PRINT(VX_ZONE_GRAPH, "[Ok] No link found for node[%u].parameter[%u]\n", thisIndex, p); + status = VX_SUCCESS; + } + } + else + { + VX_PRINT(VX_ZONE_GRAPH, "[ ignore ] node[%u].parameter[%u] = " VX_FMT_REF " type %d\n", childIndex, p, ref, dir); + } + if (status == VX_ERROR_INVALID_GRAPH) + break; + } + + if (status == VX_SUCCESS) + { + /* mark it visited for the next check to pass */ + nodes[thisIndex]->visited = vx_true_e; + } + } + VX_PRINT(VX_ZONE_GRAPH, "returning status %d\n", status); + return status; +} + +void Graph::topologicalSort(vx_node *list, vx_uint32 nnodes) +{ + /* Knuth TAoCP algorithm 2.2.3 T. + Nodes and their parameters are the "objects" which have partial-order + relations (with "<" noting the similar-looking general symbol for + relational order, not the specific less-than relation), and it's + always pair-wise: node < parameter for outputs, + parameter < node for inputs. */ + vx_uint32 nobjects; /* Number of objects; "n" in TAoCP. */ + vx_uint32 nremain; /* Number of remaining objects to be "output"; "N" in TAoCP. */ + vx_uint32 objectno; /* Running count, 1-based. */ + vx_uint32 j, k, n, r, f; + vx_uint32 outputnr; /* Running count of nodes as they're "output". */ + + struct direct_successor { + vx_uint32 suc; + struct direct_successor *next; + }; + + struct object_relations { + union { + vx_uint32 count; + vx_uint32 qlink; + } u; + struct direct_successor *top; + vx_reference ref; + }; + + std::unique_ptr x; + std::unique_ptr suc_next_table; + struct direct_successor *avail; + + /* Visit each node in the list and its in- and out-parameters, + clearing all indices. Find upper bound for nobjects, for use when + allocating x (X in the algorithm). This number is also the exact + number of relations, for use with suc_next_table (the unnamed + "suc, next" table in the algorithm). */ + vx_uint32 max_n_objects_relations = nnodes; + + for (n = 0; n < nnodes; n++) { - vx_tensor tensor = (vx_tensor)*item; - if (*vref == (vx_reference)tensor) + vx_uint32 parmno; + + max_n_objects_relations += list[n]->kernel->signature.num_parameters; + + for (parmno = 0; parmno < list[n]->kernel->signature.num_parameters; parmno++) { - VX_PRINT(VX_ZONE_GRAPH, "Creating Tensor From Meta Data!\n"); - if ((tensor->data_type != VX_TYPE_INVALID) && - (tensor->data_type != meta->dim.tensor.data_type || tensor->fixed_point_position != meta->dim.tensor.fixed_point_position)) + /* Pick the parent object in case of su-objects (e.g., ROI) */ + vx_reference ref = list[n]->parameters[parmno]; + while ( (ref != nullptr) && + (ref->scope != nullptr) && + (ref->scope != (vx_reference)this) && + (ref->scope != (vx_reference)ref->context) + ) { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has invalid data type %08x or fixed point position %d!\n", - nodes[n]->kernel->name, p, tensor->data_type, tensor->fixed_point_position); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid data type %08x or fixed point position %d!\n", - nodes[n]->kernel->name, p, tensor->data_type, tensor->fixed_point_position); - (*num_errors)++; - return vx_false_e; /* exit on error */ + ref = ref->scope; } - if (tensor->number_of_dimensions != 0) + + if (ref != nullptr) { - for (unsigned i = 0; i < tensor->number_of_dimensions; i++) - { - if (tensor->dimensions[i] != 0 && tensor->dimensions[i] != meta->dim.tensor.dimensions[i]) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has invalid dimension size %d in dimension %d!\n", - nodes[n]->kernel->name, p, tensor->dimensions[i], i); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid dimension size %d in dimension %d!\n", - nodes[n]->kernel->name, p, tensor->dimensions[i], i); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } - } + ref->index = 0; } - else if (tensor->number_of_dimensions != meta->dim.tensor.number_of_dimensions) + else { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has invalid dimension %d!\n", - nodes[n]->kernel->name, p, tensor->number_of_dimensions); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid dimension %d!\n", - nodes[n]->kernel->name, p, tensor->number_of_dimensions); - (*num_errors)++; - return vx_false_e; /* exit on error */ + /* Ignore nullptr (optional) parameters. */ + max_n_objects_relations--; } - tensor->initTensor(meta->dim.tensor.dimensions, meta->dim.tensor.number_of_dimensions, meta->dim.tensor.data_type, meta->dim.tensor.fixed_point_position); - tensor->allocateTensorMemory(); } - else + } + + /* Visit each node and its parameters, setting all indices. Allocate + and initialize the node + parameters-list. The x table is + 1-based; index 0 is a sentinel. + (This is step T1.) */ + x = std::make_unique(max_n_objects_relations + 1); + suc_next_table = std::make_unique(max_n_objects_relations); + + avail = suc_next_table.get(); + + for (objectno = 1; objectno <= nnodes; objectno++) + { + vx_node node = list[objectno - 1]; + node->index = objectno; + x[objectno].ref = (vx_reference)node; + } + + /* While we visit the parameters (setting their index if 0), we + "input" the relation. We don't have to iterate separately after + all parameters are "indexed", as all nodes are already in place + (and "indexed") and a parameter doesn't have a direct relation + with another parameter. + (Steps T2 and T3). */ + for (n = 0; n < nnodes; n++) + { + vx_uint32 parmno; + + for (parmno = 0; parmno < list[n]->kernel->signature.num_parameters; parmno++) { - if (tensor->number_of_dimensions != meta->dim.tensor.number_of_dimensions) + vx_reference ref = list[n]->parameters[parmno]; + struct direct_successor *p; + + /* Pick the parent object in case of su-objects (e.g., ROI) */ + while ( (ref != nullptr) && + (ref->scope != nullptr) && + (ref->scope != (vx_reference)this) && + (ref->scope != (vx_reference)ref->context) + ) { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] is an invalid number of dimensions %u!\n", - nodes[n]->kernel->name, p, tensor->number_of_dimensions); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] is an invalid number of dimensions %u!\n", - nodes[n]->kernel->name, p, tensor->number_of_dimensions); - (*num_errors)++; - return vx_false_e; /* exit on error */ + ref = ref->scope; } - for (unsigned i = 0; i < tensor->number_of_dimensions; i++) + + if (ref == nullptr) { - if (tensor->dimensions[i] != meta->dim.tensor.dimensions[i]) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has an invalid dimension %u!\n", - nodes[n]->kernel->name, p, tensor->dimensions[i]); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid dimension %u!\n", - nodes[n]->kernel->name, p, tensor->dimensions[i]); - (*num_errors)++; - return vx_false_e; /* exit on error */ - } + continue; + } + + if (ref->index == 0) + { + x[objectno].ref = ref; + ref->index = objectno++; } - if (tensor->data_type != meta->dim.tensor.data_type) + + /* Step T2. */ + if (list[n]->kernel->signature.directions[parmno] == VX_INPUT) { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] is an invalid data type %08x!\n", - nodes[n]->kernel->name, p, tensor->data_type); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid data type %08x!\n", - nodes[n]->kernel->name, p, tensor->data_type); - (*num_errors)++; - return vx_false_e; /* exit on error */ + /* parameter < node */ + j = ref->index; + k = n + 1; } - if (tensor->fixed_point_position != meta->dim.tensor.fixed_point_position) + else { - *status = VX_ERROR_INVALID_FORMAT; - vxAddLogEntry(reinterpret_cast(this), *status, - "Node: %s: parameter[%u] has an invalid fixed point position %08x!\n", - nodes[n]->kernel->name, p, tensor->fixed_point_position); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid fixed point position %08x!\n", - nodes[n]->kernel->name, p, tensor->fixed_point_position); - (*num_errors)++; - return vx_false_e; /* exit on error */ + /* node < parameter */ + k = ref->index; + j = n + 1; } + + /* Step T3. */ + x[k].u.count++; + p = avail++; + p->suc = k; + p->next = x[j].top; + x[j].top = p; } - } /* VX_TYPE_TENSOR */ - /*! \todo support other output types for safety checks in graph verification parameters phase */ + } + + /* With a 1-based index, we need to back-off one to get the number of objects. */ + nobjects = objectno - 1; + nremain = nobjects; + + /* At this point, we could visit all the nodes in + x[1..graph->numNodes] (all the first graph->numNodes in x are + nodes) and put those with + count <= node->kernel->signature.num_parameters in graph->heads + (as a node is always dependent on its input parameters and all + nodes have inputs, but some may be nullptr), avoiding the + O(numNodes**2) loop later in our caller. */ + + /* Step T4. Note that we're not zero-based but 1-based; 0 and x[0] + are sentinels. */ + r = 0; + x[0].u.qlink = 0; + for (k = 1; k <= nobjects; k++) + { + if (x[k].u.count == 0) + { + x[r].u.qlink = k; + r = k; + } + } + + f = x[0].u.qlink; + outputnr = 0; + + /* Step T5. (We don't output a final 0 as present in the algorithm.) */ + while (f != 0) + { + struct direct_successor *p; + + /* This is our "output". Nodes only; we don't otherwise make + use the order in which parameters are being processed. */ + if (x[f].ref->type == VX_TYPE_NODE) + list[outputnr++] = (vx_node)x[f].ref; + nremain--; + p = x[f].top; + + /* Step T6. */ + while (p != nullptr) + { + if (--x[p->suc].u.count == 0) + { + x[r].u.qlink = p->suc; + r = p->suc; + } + p = p->next; + } + + /* Step T7 */ + f = x[f].u.qlink; + } + + /* Step T8. + At this point, we could inspect nremain and if non-zero, we have + a cycle. To wit, we can avoid the O(numNodes**2) loop later in + our caller. We have to do check for cycles anyway, because if + there was a cycle we need to restore *all* the nodes into list[], + or else they can't be disposed of properly. We use the original + order, both for simplicity and because the caller might be making + invalid assumptions; having passed an incorrect graph is cause + for concern about integrity. */ + if (nremain != 0) + for (n = 0; n < nnodes; n++) + list[n] = (vx_node)x[n+1].ref; +} + +vx_bool Graph::setupOutput(vx_uint32 n, vx_uint32 p, vx_reference* vref, vx_meta_format* meta, + vx_status* status, vx_uint32* num_errors) +{ + *vref = nodes[n]->parameters[p]; + *meta = vxCreateMetaFormat(context); + + /* check to see if the reference is virtual */ + if ((*vref)->is_virtual == vx_false_e) + { + *vref = nullptr; + } else { - VX_PRINT(VX_ZONE_GRAPH, "Returned Meta type %x\n", meta->type); + VX_PRINT(VX_ZONE_GRAPH, "Virtual Reference detected at kernel %s parameter %u\n", + nodes[n]->kernel->name, + p); + if ((*vref)->scope->type == VX_TYPE_GRAPH && + (*vref)->scope != (vx_reference)this && + /* We check only one level up; we make use of the + knowledge that this implementation has no more + than one level of child-graphs. (Nodes are only + one level; no child-graph-using node is composed + from other child-graph-using nodes.) We need + this check (for example) for a virtual image + being an output parameter to a node for which + this graph is the child-graph implementation, + like in vx_bug13517.c. */ + (*vref)->scope != (vx_reference)parentGraph) + { + /* major fault! */ + *status = VX_ERROR_INVALID_SCOPE; + vxAddLogEntry((vx_reference)(*vref), *status, "Virtual Reference is in the wrong scope, created from another graph!\n"); + (*num_errors)++; + return vx_false_e; /* break; */ + } + /* ok if context, pyramid or this graph */ } + /* the type of the parameter is known by the system, so let the system set it by default. */ + (*meta)->type = nodes[n]->kernel->signature.types[p]; + return vx_true_e; -} /* postprocessOutputDataType() */ +} /* * Parameters: @@ -1566,7 +2135,7 @@ vx_bool Graph::postprocessOutputDataType(vx_uint32 n, vx_uint32 p, vx_reference* * vref - reference of the parameter * meta - parameter meta info */ -vx_bool Graph::postprocessOutput(vx_uint32 n, vx_uint32 p, vx_reference* vref, vx_meta_format meta, +vx_bool Graph::postprocessOutputDataType(vx_uint32 n, vx_uint32 p, vx_reference* item, vx_reference* vref, vx_meta_format meta, vx_status* status, vx_uint32* num_errors) { if (Context::isValidType(meta->type) == vx_false_e) @@ -1579,1505 +2148,1085 @@ vx_bool Graph::postprocessOutput(vx_uint32 n, vx_uint32 p, vx_reference* vref, v return vx_false_e; /* exit on error */ } - if (meta->type == VX_TYPE_OBJECT_ARRAY) + if (meta->type == VX_TYPE_IMAGE) { - vx_object_array objarr = (vx_object_array)nodes[n]->parameters[p]; - VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, 0x%08x " VX_FMT_SIZE "\n", meta->type, meta->dim.object_array.item_type, meta->dim.object_array.num_items); - - if (ObjectArray::isValidObjectArray(objarr, meta->dim.object_array.item_type, meta->dim.object_array.num_items) != vx_true_e) - { - *status = VX_ERROR_INVALID_DIMENSION; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, - "Node: %s: parameter[%u] has an invalid item type 0x%08x or num_items " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, objarr->item_type, objarr->num_items); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid item type 0x%08x or num_items " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, p, objarr->item_type, objarr->num_items); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: Expected item type 0x%08x or num_items " VX_FMT_SIZE "\n", - nodes[n]->kernel->name, meta->dim.object_array.item_type, meta->dim.object_array.num_items); - (*num_errors)++; - return vx_false_e; //break; - } - - if (vref == (vx_reference*)&objarr) + vx_image img = (vx_image)*item; + VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, %ux%u\n", meta->type, meta->dim.image.width, meta->dim.image.height); + if (*vref == (vx_reference)img) { - VX_PRINT(VX_ZONE_GRAPH, "Creating Object Array From Meta Data %x and " VX_FMT_SIZE "!\n", meta->dim.object_array.item_type, meta->dim.object_array.num_items); - for (vx_uint32 i = 0; i < meta->dim.object_array.num_items; i++) + VX_PRINT(VX_ZONE_GRAPH, "Creating Image From Meta Data!\n"); + /*! \todo need to worry about images that have a format, but no dimensions too */ + if (img->format == VX_DF_IMAGE_VIRT || img->format == meta->dim.image.format) { - vx_reference item = vxGetObjectArrayItem(objarr, i); - - if (!postprocessOutputDataType(n, p, &item, vref, meta, status, num_errors)) - { - vxReleaseReference(&item); - *status = VX_ERROR_INVALID_PARAMETERS; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_PARAMETERS, - "Node: %s: meta[%u] has an invalid meta of exemplar\n", - nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid meta of exemplar\n", - nodes[n]->kernel->name, p); - (*num_errors)++; - - return vx_false_e; //break; - } - - vxReleaseReference(&item); + img->format = meta->dim.image.format; + img->width = meta->dim.image.width; + img->height = meta->dim.image.height; + /* we have to go set all the other dimensional information up. */ + img->initImage(img->width, img->height, img->format); + Image::printImage(img); /* show that it's been created. */ + } + else + { + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has invalid format %08x!\n", + nodes[n]->kernel->name, p, img->format); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid format %08x!\n", + nodes[n]->kernel->name, p, img->format); + (*num_errors)++; + return vx_false_e; /* exit on error */ } } else { /* check the data that came back from the output validator against the object */ - for (vx_uint32 i = 0; i < meta->dim.object_array.num_items; i++) + if ((img->width != meta->dim.image.width) || + (img->height != meta->dim.image.height)) { - vx_reference item = vxGetObjectArrayItem(objarr, i); - vx_reference itemref = vxGetObjectArrayItem((vx_object_array)*vref, i); - - if (!postprocessOutputDataType(n, p, &item, &itemref, meta, status, num_errors)) - { - vxReleaseReference(&item); - *status = VX_ERROR_INVALID_PARAMETERS; - vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_PARAMETERS, - "Node: %s: meta[%u] has an invalid meta of exemplar\n", - nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid meta of exemplar\n", - nodes[n]->kernel->name, p); - (*num_errors)++; - - return vx_false_e; //break; - } - - vxReleaseReference(&item); + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] is an invalid dimension %ux%u!\n", + nodes[n]->kernel->name, p, img->width, img->height); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] is an invalid dimension %ux%u!\n", + nodes[n]->kernel->name, p, img->width, img->height); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: expected dimension %ux%u with format %08x!\n", + nodes[n]->kernel->name, meta->dim.image.width, meta->dim.image.height, meta->dim.image.format); + (*num_errors)++; + return vx_false_e; /* exit on error */ + } + if (img->format != meta->dim.image.format) + { + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] is an invalid format %08x!\n", + nodes[n]->kernel->name, p, img->format); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid format %08x!\n", + nodes[n]->kernel->name, p, img->format); + (*num_errors)++; + return vx_false_e; /* exit on error */ } } - } - else - { - return postprocessOutputDataType(n, p, &nodes[n]->parameters[p], vref, meta, status, num_errors); - } - return vx_true_e; -} /* postprocessOutput() */ + if (nullptr != meta->set_valid_rectangle_callback) + nodes[n]->attributes.valid_rect_reset = vx_false_e; -vx_status Graph::pipelineValidateRefsList( - const vx_graph_parameter_queue_params_t graph_parameters_queue_param) -{ - vx_status status = VX_SUCCESS; - vx_meta_format meta_base = nullptr, meta = nullptr; - vx_uint32 i; + if (vx_false_e == nodes[n]->attributes.valid_rect_reset && + nullptr != meta->set_valid_rectangle_callback) + { + /* calculate image valid rectangle through callback */ - if (nullptr != graph_parameters_queue_param.refs_list[0]) - { - meta_base = vxCreateMetaFormat(graph_parameters_queue_param.refs_list[0]->context); - status = vxSetMetaFormatFromReference(meta_base, graph_parameters_queue_param.refs_list[0]); - } + vx_uint32 i; + vx_uint32 nparams = 0; + vx_uint32 num_in_images = 0; + vx_rectangle_t** in_rect = nullptr; + vx_rectangle_t* out_rect[1] = { nullptr }; + vx_node node = nodes[n]; - if ( (VX_SUCCESS == status) - && (nullptr != meta_base) ) - { - for (i = 1; i < graph_parameters_queue_param.refs_list_size; i++) - { - if (nullptr != graph_parameters_queue_param.refs_list[i]) + /* assume no errors */ + vx_bool res = vx_true_e; + + if (VX_SUCCESS != vxQueryNode(node, VX_NODE_PARAMETERS, &nparams, sizeof(nparams))) { - meta = vxCreateMetaFormat(graph_parameters_queue_param.refs_list[i]->context); + *status = VX_FAILURE; + return vx_false_e; + } - if (nullptr != meta) - { - status = vxSetMetaFormatFromReference(meta, graph_parameters_queue_param.refs_list[i]); - } - else + /* compute num of input images */ + for (i = 0; i < nparams; i++) + { + if (VX_INPUT == node->kernel->signature.directions[i] && + VX_TYPE_IMAGE == node->parameters[i]->type) { - status = VX_FAILURE; - VX_PRINT(VX_ZONE_ERROR, "Meta Format is NULL\n"); + num_in_images++; } + } - if (VX_SUCCESS == status) + /* allocate array of pointers to input images valid rectangles */ + in_rect = new vx_rectangle_t*[num_in_images](); + if (nullptr == in_rect) + { + *status = VX_FAILURE; + return vx_false_e; + } + + for (i = 0; i < nparams; i++) + { + if (VX_INPUT == node->kernel->signature.directions[i] && + VX_TYPE_IMAGE == node->parameters[i]->type) { - if (graph_parameters_queue_param.refs_list[0]->type == - graph_parameters_queue_param.refs_list[i]->type) + in_rect[i] = new vx_rectangle_t(); + if (nullptr == in_rect[i]) { - if (vx_true_e != MetaFormat::isMetaFormatEqual(meta_base, meta, graph_parameters_queue_param.refs_list[0]->type)) - { - status = VX_ERROR_INVALID_PARAMETERS; - VX_PRINT(VX_ZONE_ERROR, "Invalid meta data of reference list!\n"); - } + *status = VX_FAILURE; + res = vx_false_e; + break; + } + + /* collect input images valid rectagles in array */ + if (VX_SUCCESS != vxGetValidRegionImage((vx_image)node->parameters[i], in_rect[i])) + { + *status = VX_FAILURE; + res = vx_false_e; + break; } } + } - if (Reference::isValidReference(meta, VX_TYPE_META_FORMAT) == vx_true_e) + if (vx_false_e != res) + { + out_rect[0] = new vx_rectangle_t(); + if (nullptr == out_rect[0]) { - status |= vxReleaseMetaFormat(&meta); - if (VX_SUCCESS != status) + *status = VX_FAILURE; + res = vx_false_e; + } + + /* calculate output image valid rectangle */ + if (VX_SUCCESS == meta->set_valid_rectangle_callback(nodes[n], p, (const vx_rectangle_t* const*)in_rect, + (vx_rectangle_t* const*)out_rect)) + { + /* set output image valid rectangle */ + if (VX_SUCCESS != vxSetImageValidRectangle(img, (const vx_rectangle_t*)out_rect[0])) { - VX_PRINT(VX_ZONE_ERROR, "Failed to release meta format object \n"); + *status = VX_FAILURE; + res = vx_false_e; } } - - if (VX_SUCCESS != status) + else { - break; + *status = VX_FAILURE; + res = vx_false_e; } } - else + + /* deallocate arrays memory */ + for (i = 0; i < num_in_images; i++) { - status = VX_ERROR_INVALID_PARAMETERS; - VX_PRINT(VX_ZONE_ERROR, "Invalid graph parameter ref list!\n"); + if (nullptr != in_rect[i]) + { + delete(in_rect[i]); + } } - } - } - - if (Reference::isValidReference(meta_base, VX_TYPE_META_FORMAT) == vx_true_e) - { - status |= vxReleaseMetaFormat(&meta_base); - if (VX_SUCCESS != status) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to release meta format object \n"); - } - } - return status; -} + if (nullptr != in_rect) + delete[](in_rect); + if (nullptr != out_rect[0]) + delete(out_rect[0]); -void Graph::streamingLoop() -{ -#ifdef OPENVX_USE_STREAMING - while (isStreaming) - { - /* Wait for trigger node event if set */ - // if (triggerNodeIndex != UINT32_MAX) - // { - // VX_PRINT(VX_ZONE_INFO, "Trigger node defined -- waiting on it to trigger\n"); - // /* Wait for the trigger node to complete */ - // while (!nodes[triggerNodeIndex]->executed) - // { - // std::cout << "Waiting for trigger node to complete" << std::endl; - // std::this_thread::sleep_for(std::chrono::milliseconds(10)); - // /* Allow clean exit */ - // if (!isStreaming) return; - // } - // /* Reset the event for the next iteration */ - // nodes[triggerNodeIndex]->executed = vx_false_e; - // } - /* Schedule and wait for the graph */ - vx_status status = vxScheduleGraph(this); - if (status != VX_SUCCESS) break; - status = vxWaitGraph(this); - if (status != VX_SUCCESS) break; - } -#endif /* OPENVX_USE_STREAMING */ -} + return res; + } -void Graph::destruct() -{ - while (numNodes) - { - vx_node node = nodes[0]; - /* Interpretation of spec is to release all external references of Nodes when vxReleaseGraph() - is called AND all graph references count == 0 (garbage collection). - However, it may be possible that the user would have already released its external reference - so we need to check. */ - if (nullptr != node) + if (vx_true_e == nodes[n]->attributes.valid_rect_reset) { - if (node->external_count) - { - Reference::releaseReference((vx_reference*)&node, VX_TYPE_NODE, VX_EXTERNAL, nullptr); - } + /* reset image valid rectangle */ + vx_rectangle_t out_rect; + out_rect.start_x = 0; + out_rect.start_y = 0; + out_rect.end_x = img->width; + out_rect.end_y = img->height; - if (node) + if (VX_SUCCESS != vxSetImageValidRectangle(img, &out_rect)) { - node->removeNode(); + *status = VX_FAILURE; + return vx_false_e; } } - } -} - -/******************************************************************************/ -/* PUBLIC FUNCTIONS */ -/******************************************************************************/ - -VX_API_ENTRY vx_graph VX_API_CALL vxCreateGraph(vx_context context) -{ - vx_graph graph = nullptr; - - if (Context::isValidContext(context) == vx_true_e) + } /* VX_TYPE_IMAGE */ + else if (meta->type == VX_TYPE_ARRAY) { - graph = (vx_graph)Reference::createReference(context, VX_TYPE_GRAPH, VX_EXTERNAL, context); - if (vxGetStatus((vx_reference)graph) == VX_SUCCESS && graph->type == VX_TYPE_GRAPH) + vx_array arr = (vx_array)*item; + VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, 0x%08x " VX_FMT_SIZE "\n", meta->type, meta->dim.array.item_type, meta->dim.array.capacity); + if (*vref == (vx_reference)arr) { - Osal::initPerf(&graph->perf); - Osal::createSem(&graph->lock, 1); - VX_PRINT(VX_ZONE_GRAPH,"Created Graph %p\n", graph); - Reference::printReference((vx_reference)graph); - graph->reverify = graph->verified; - graph->verified = vx_false_e; - graph->state = VX_GRAPH_STATE_UNVERIFIED; + VX_PRINT(VX_ZONE_GRAPH, "Creating Array From Meta Data %x and " VX_FMT_SIZE "!\n", meta->dim.array.item_type, meta->dim.array.capacity); + if (arr->initVirtualArray(meta->dim.array.item_type, meta->dim.array.capacity) != vx_true_e) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: meta[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, meta->dim.array.item_type, meta->dim.array.capacity); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, meta->dim.array.item_type, meta->dim.array.capacity); + (*num_errors)++; + return vx_false_e; //break; + } + } + else + { + if (arr->validateArray(meta->dim.array.item_type, meta->dim.array.capacity) != vx_true_e) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, arr->item_type, arr->capacity); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid item type 0x%08x or capacity " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, arr->item_type, arr->capacity); + (*num_errors)++; + return vx_false_e; //break; + } } } - - return (vx_graph)graph; -} - -VX_API_ENTRY vx_status VX_API_CALL vxSetGraphAttribute(vx_graph graph, vx_enum attribute, const void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; - (void)attribute; - (void)ptr; - (void)size; - - if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) - { - /*! @todo there are no settable attributes in this implementation yet... */ - status = VX_ERROR_NOT_SUPPORTED; - } - else + else if (meta->type == VX_TYPE_PYRAMID) { - status = VX_ERROR_INVALID_REFERENCE; - } - - return status; -} + vx_pyramid pyramid = (vx_pyramid)*item; -VX_API_ENTRY vx_status VX_API_CALL vxQueryGraph(vx_graph graph, vx_enum attribute, void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; + vx_uint32 i; + vx_bool res = vx_true_e; - if (Reference::isValidReference(reinterpret_cast(graph)) == vx_true_e) - { - VX_PRINT(VX_ZONE_GRAPH,"INFO: Query:0x%x:%d\n", attribute, (attribute & VX_ATTRIBUTE_ID_MASK)); + VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, %ux%u:%u:%lf\n", + meta->type, + meta->dim.pyramid.width, + meta->dim.pyramid.height, + meta->dim.pyramid.levels, + meta->dim.pyramid.scale); + VX_PRINT(VX_ZONE_GRAPH, "Nodes[%u] %s parameters[%u]\n", n, nodes[n]->kernel->name, p); - switch (attribute) + if ((pyramid->numLevels != meta->dim.pyramid.levels) || + (pyramid->scale != meta->dim.pyramid.scale)) { - case VX_GRAPH_PERFORMANCE: - if (VX_CHECK_PARAM(ptr, size, vx_perf_t, 0x3)) - { - memcpy(ptr, &graph->perf, size); - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_GRAPH_STATE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - { - *(vx_status *)ptr = graph->state; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_GRAPH_NUMNODES: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = graph->numNodes; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - case VX_GRAPH_NUMPARAMETERS: - if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) - { - *(vx_uint32 *)ptr = graph->numParams; - } - else - { - status = VX_ERROR_INVALID_PARAMETERS; - } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; + *status = VX_ERROR_INVALID_VALUE; + vxAddLogEntry(reinterpret_cast(this), *status, "Either levels (%u?=%u) or scale (%lf?=%lf) are invalid\n", + pyramid->numLevels, meta->dim.pyramid.levels, + pyramid->scale, meta->dim.pyramid.scale); + (*num_errors)++; + return vx_false_e; //break; } - } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } - return status; -} + if ((pyramid->format != VX_DF_IMAGE_VIRT) && + (pyramid->format != meta->dim.pyramid.format)) + { + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, "Invalid pyramid format %x, needs %x\n", + pyramid->format, + meta->dim.pyramid.format); + (*num_errors)++; + return vx_false_e; //break; + } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseGraph(vx_graph *g) -{ - vx_status status = VX_ERROR_INVALID_REFERENCE; + if (((pyramid->width != 0) && + (pyramid->width != meta->dim.pyramid.width)) || + ((pyramid->height != 0) && + (pyramid->height != meta->dim.pyramid.height))) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, "Invalid pyramid dimensions %ux%u, needs %ux%u\n", + pyramid->width, pyramid->height, + meta->dim.pyramid.width, meta->dim.pyramid.height); + (*num_errors)++; + return vx_false_e; //break; + } - if (nullptr != g) - { - vx_graph graph = *(g); - if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) + /* check to see if the pyramid is virtual */ + if (*vref == (vx_reference)pyramid) { - status = Reference::releaseReference((vx_reference*)g, VX_TYPE_GRAPH, VX_EXTERNAL, nullptr); + pyramid->initPyramid( + meta->dim.pyramid.levels, + meta->dim.pyramid.scale, + meta->dim.pyramid.width, + meta->dim.pyramid.height, + meta->dim.pyramid.format); } - } - return status; -} + if (nullptr != meta->set_valid_rectangle_callback) + nodes[n]->attributes.valid_rect_reset = vx_false_e; -VX_API_ENTRY vx_status VX_API_CALL vxVerifyGraph(vx_graph graph) -{ - vx_status status = VX_SUCCESS; - vx_uint32 num_errors = 0u; - vx_bool first_time_verify = ((graph->verified == vx_false_e) && (graph->reverify == vx_false_e)) ? vx_true_e : vx_false_e; + if (vx_false_e == nodes[n]->attributes.valid_rect_reset && + nullptr != meta->set_valid_rectangle_callback) + { + /* calculate pyramid levels valid rectangles */ + + vx_uint32 nparams = 0; + vx_uint32 num_in_images = 0; + vx_rectangle_t** in_rect = nullptr; + vx_rectangle_t** out_rect = nullptr; - graph->verified = vx_false_e; + vx_node node = nodes[n]; - if (Reference::isValidReference(reinterpret_cast(graph)) == vx_true_e) - { - vx_uint32 h,n,p; - vx_bool hasACycle = vx_false_e; + if (VX_SUCCESS != vxQueryNode(node, VX_NODE_PARAMETERS, &nparams, sizeof(nparams))) + { + *status = VX_FAILURE; + return vx_false_e; + } - /* lock the graph */ - Osal::semWait(&graph->lock); + /* compute num of input images */ + for (i = 0; i < nparams; i++) + { + if (VX_INPUT == node->kernel->signature.directions[i] && + VX_TYPE_IMAGE == node->parameters[i]->type) + { + num_in_images++; + } + } - /* To properly deal with parameter dependence in the graph, the - nodes have to be in topological order when their parameters - are inspected and their dependent attributes -such as geometry - and type- are propagated. */ - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Topological Sort Phase\n"); - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); - graph->topologicalSort(graph->nodes, graph->numNodes); + in_rect = new vx_rectangle_t* [num_in_images](); + if (nullptr == in_rect) + { + *status = VX_FAILURE; + return vx_false_e; + } - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); - VX_PRINT(VX_ZONE_GRAPH,"User Kernel Preprocess Phase! (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); + for (i = 0; i < num_in_images; i++) + in_rect[i] = nullptr; - for (n = 0; n < graph->numNodes; n++) - { - vx_node node = graph->nodes[n]; - if (node->kernel->user_kernel) + for (i = 0; i < nparams; i++) { - if (!first_time_verify) // re-verify + if (VX_INPUT == node->kernel->signature.directions[i] && + VX_TYPE_IMAGE == node->parameters[i]->type) { - if (node->kernel->deinitialize) + in_rect[i] = new vx_rectangle_t(); + if (nullptr == in_rect[i]) { - vx_status status; - if (node->local_data_set_by_implementation == vx_false_e) - node->local_data_change_is_enabled = vx_true_e; - status = node->kernel->deinitialize((vx_node)node, - (vx_reference *)node->parameters, - node->kernel->signature.num_parameters); - node->local_data_change_is_enabled = vx_false_e; - if (status != VX_SUCCESS) - { - VX_PRINT(VX_ZONE_ERROR,"Failed to de-initialize kernel %s!\n", node->kernel->name); - goto exit; - } + *status = VX_FAILURE; + res = vx_false_e; + break; } - if (node->kernel->attributes.localDataSize == 0) + if (VX_SUCCESS != vxGetValidRegionImage((vx_image)node->parameters[i], in_rect[i])) { - if (node->attributes.localDataPtr) - { - if (!first_time_verify && node->attributes.localDataPtr) - { - ::operator delete(node->attributes.localDataPtr); - } - node->attributes.localDataSize = 0; - node->attributes.localDataPtr = nullptr; - } + *status = VX_FAILURE; + res = vx_false_e; + break; } - node->local_data_set_by_implementation = vx_false_e; } } - } - - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Parameter Validation Phase! (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"###########################\n"); - for (n = 0; n numNodes; n++) - { - /* check to make sure that a node has all required parameters */ - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) + if (vx_false_e != res) { - if (graph->nodes[n]->kernel->signature.states[p] == VX_PARAMETER_STATE_REQUIRED) + out_rect = new vx_rectangle_t*[meta->dim.pyramid.levels](); + if (nullptr != out_rect) { - if (graph->nodes[n]->parameters[p] == nullptr) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_INVALID_PARAMETERS, "Node %s: Some parameters were not supplied!\n", graph->nodes[n]->kernel->name); - VX_PRINT(VX_ZONE_ERROR, "Node " VX_FMT_REF " (%s) Parameter[%u] was required and not supplied!\n", - graph->nodes[n], - graph->nodes[n]->kernel->name,p); - status = VX_ERROR_INVALID_PARAMETERS; - num_errors++; - } - else if (graph->nodes[n]->parameters[p]->internal_count == 0) + vx_uint32 k; + for (k = 0; k < meta->dim.pyramid.levels; k++) + out_rect[k] = nullptr; + + for (i = 0; i < meta->dim.pyramid.levels; i++) { - VX_PRINT(VX_ZONE_ERROR, "Internal reference counts are wrong!\n"); - DEBUG_BREAK(); - num_errors++; + out_rect[i] = new vx_rectangle_t(); + if (nullptr == out_rect[i]) + { + *status = VX_FAILURE; + res = vx_false_e; + break; + } } } + else + { + *status = VX_FAILURE; + res = vx_false_e; + } } - if (status != VX_SUCCESS) + + if (vx_false_e != res) { - goto exit; - } + /* calculate pyramid levels valid rectangles */ + if (VX_SUCCESS == meta->set_valid_rectangle_callback(nodes[n], p, (const vx_rectangle_t* const*)in_rect, out_rect)) + { + for (i = 0; i < meta->dim.pyramid.levels; i++) + { + vx_image img = vxGetPyramidLevel(pyramid, i); + + if (vx_false_e == Reference::isValidReference((vx_reference)img, VX_TYPE_IMAGE)) + { + *status = VX_FAILURE; + res = vx_false_e; + vxReleaseImage(&img); /* already on error path, ignore additional errors */ + break; + } + + if (VX_SUCCESS != vxSetImageValidRectangle(img, out_rect[i])) + { + *status = VX_FAILURE; + res = vx_false_e; + vxReleaseImage(&img); /* already on error path, ignore additional errors */ + break; + } + + if (VX_SUCCESS != vxReleaseImage(&img)) + { + *status = VX_FAILURE; + res = vx_false_e; + break; + } + } /* for pyramid levels */ + } + else + { + *status = VX_FAILURE; + res = vx_false_e; + } + } /* if successful memory allocation */ - /* debugging, show that we can detect "constant" data or "unreferenced data" */ - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) + /* deallocate rectangle arrays */ + for (i = 0; i < num_in_images; i++) { - vx_reference ref = (vx_reference)graph->nodes[n]->parameters[p]; - if (ref) + if (nullptr != in_rect && nullptr != in_rect[i]) { - if (ref->external_count == 0) - { - VX_PRINT(VX_ZONE_INFO, "%s[%u] = " VX_FMT_REF " (CONSTANT) type:%08x\n", graph->nodes[n]->kernel->name, p, ref, ref->type); - } - else - { - VX_PRINT(VX_ZONE_INFO, "%s[%u] = " VX_FMT_REF " (MUTABLE) type:%08x count:%d\n", graph->nodes[n]->kernel->name, p, ref, ref->type, ref->external_count); - } + delete(in_rect[i]); } } - /* check if new style validators are provided (see bug14654) */ - if (graph->nodes[n]->kernel->validate != nullptr) + if (nullptr != in_rect) + delete[](in_rect); + + for (i = 0; i < meta->dim.pyramid.levels; i++) { - VX_PRINT(VX_ZONE_GRAPH, "Using new style validators\n"); + if (nullptr != out_rect && nullptr != out_rect[i]) + delete(out_rect[i]); + } - vx_status validation_status = VX_SUCCESS; - vx_reference vref[VX_INT_MAX_PARAMS]; - vx_meta_format metas[VX_INT_MAX_PARAMS]; + if (nullptr != out_rect) + delete[](out_rect); - for (p = 0; p < dimof(metas); p++) - { - metas[p] = nullptr; - vref[p] = nullptr; - } + return res; + } - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) - { - if ((graph->nodes[n]->parameters[p] != nullptr) && - (graph->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT)) - { - if (graph->setupOutput(n, p, &vref[p], &metas[p], &status, &num_errors) == vx_false_e) - { - break; - } - } - } + if (vx_true_e == nodes[n]->attributes.valid_rect_reset) + { + /* reset output pyramid levels valid rectangles */ - if (status == VX_SUCCESS) - { - validation_status = graph->nodes[n]->kernel->validate((vx_node)graph->nodes[n], - graph->nodes[n]->parameters, - graph->nodes[n]->kernel->signature.num_parameters, - metas); - if (validation_status != VX_SUCCESS) - { - status = validation_status; - vxAddLogEntry(reinterpret_cast(graph), status, "Node[%u] %s: parameter(s) failed validation!\n", - n, graph->nodes[n]->kernel->name); - VX_PRINT(VX_ZONE_GRAPH,"Failed on validation of parameter(s) of kernel %s in node #%d (status=%d)\n", - graph->nodes[n]->kernel->name, n, status); - num_errors++; - } - } + vx_bool res = vx_true_e; - if (status == VX_SUCCESS) + for (i = 0; i < meta->dim.pyramid.levels; i++) + { + vx_uint32 width = 0; + vx_uint32 height = 0; + vx_rectangle_t out_rect; + + vx_image img = vxGetPyramidLevel(pyramid, i); + + if (vx_false_e == Reference::isValidReference((vx_reference)img, VX_TYPE_IMAGE)) { - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) - { - if ((graph->nodes[n]->parameters[p] != nullptr) && - (graph->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT)) - { - if (graph->postprocessOutput(n, p, &vref[p], metas[p], &status, &num_errors) == vx_false_e) - { - break; - } - } - } + *status = VX_FAILURE; + return vx_false_e; } - for (p = 0; p < dimof(metas); p++) + if (VX_SUCCESS != vxQueryImage(img, VX_IMAGE_WIDTH, &width, sizeof(width))) { - if (metas[p]) - { - vxReleaseMetaFormat(&metas[p]); - } + *status = VX_FAILURE; + res = vx_false_e; + vxReleaseImage(&img); /* already on error path, ignore additional errors */ + break; } - } - else /* old style validators */ - { - VX_PRINT(VX_ZONE_GRAPH, "Using old style validators\n"); - vx_meta_format metas[VX_INT_MAX_PARAMS] = {nullptr}; - /* first pass for inputs */ - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) + if (VX_SUCCESS != vxQueryImage(img, VX_IMAGE_HEIGHT, &height, sizeof(height))) { - if (((graph->nodes[n]->kernel->signature.directions[p] == VX_BIDIRECTIONAL) || - (graph->nodes[n]->kernel->signature.directions[p] == VX_INPUT)) && - (graph->nodes[n]->parameters[p] != nullptr) && - (graph->nodes[n]->kernel->validate_input != nullptr)) - { - vx_status input_validation_status = graph->nodes[n]->kernel->validate_input((vx_node)graph->nodes[n], p); - if (input_validation_status != VX_SUCCESS) - { - status = input_validation_status; - vxAddLogEntry(reinterpret_cast(graph), status, "Node[%u] %s: parameter[%u] failed input/bi validation!\n", - n, graph->nodes[n]->kernel->name, - p); - VX_PRINT(VX_ZONE_GRAPH,"Failed on validation of parameter %u of kernel %s in node #%d (status=%d)\n", - p, graph->nodes[n]->kernel->name, n, status); - num_errors++; - } - } + *status = VX_FAILURE; + res = vx_false_e; + vxReleaseImage(&img); /* already on error path, ignore additional errors */ + break; } - /* second pass for bi/output (we may encounter "virtual" objects here, - * then we must reparse graph to replace with new objects) - */ - /*! \bug Bidirectional parameters currently break parsing. */ - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) + + if (vx_false_e != res) { - vx_reference vref = nullptr; - if (graph->nodes[n]->parameters[p] == nullptr) - continue; + out_rect.start_x = 0; + out_rect.start_y = 0; + out_rect.end_x = width; + out_rect.end_y = height; - VX_PRINT(VX_ZONE_GRAPH,"Checking Node[%u].Parameter[%u]\n", n, p); - if (graph->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT) + /* pyramid level valid rectangle is a whole image */ + if (VX_SUCCESS != vxSetImageValidRectangle(img, &out_rect)) { - vx_status output_validation_status = VX_SUCCESS; - if (graph->setupOutput(n, p, &vref, &metas[p], &status, &num_errors) == - vx_false_e) - break; - if (graph->nodes[n]->kernel->validate_output != nullptr) - { - output_validation_status = graph->nodes[n]->kernel->validate_output( - (vx_node)graph->nodes[n], p, metas[p]); - if (output_validation_status == VX_SUCCESS) - { - if (graph->postprocessOutput(n, p, &vref, metas[p], &status, - &num_errors) == vx_false_e) - { - break; - } - } - else - { - status = output_validation_status; - vxAddLogEntry(reinterpret_cast(graph), status, - "Node %s: parameter[%u] failed output validation! " - "(status = %d)\n", - graph->nodes[n]->kernel->name, p, status); - VX_PRINT(VX_ZONE_ERROR, - "Failed on validation of output parameter[%u] on kernel " - "%s, status=%d\n", - p, graph->nodes[n]->kernel->name, status); - } - } + *status = VX_FAILURE; + res = vx_false_e; } } - for (p = 0; p < dimof(metas); p++) + if (VX_SUCCESS != vxReleaseImage(&img)) { - if (metas[p]) - { - vxReleaseMetaFormat(&metas[p]); - } + *status = VX_FAILURE; + res = vx_false_e; } - } - } - - VX_PRINT(VX_ZONE_GRAPH,"####################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Single Writer Phase! (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"####################\n"); + } /* for pyramid levels */ - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) + return res; + } + } /* VX_TYPE_PYRAMID */ + else if (meta->type == VX_TYPE_SCALAR) + { + vx_scalar scalar = (vx_scalar)*item; + if (scalar->data_type != meta->dim.scalar.type) { - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) - { - if (graph->nodes[n]->parameters[p] && - ((graph->nodes[n]->kernel->signature.directions[p] == VX_OUTPUT) || - (graph->nodes[n]->kernel->signature.directions[p] == VX_BIDIRECTIONAL))) - { - vx_uint32 n1, p1; - /* check for other output references to this parameter in the graph. */ - for (n1 = vxNextNode(graph, n); n1 != n; n1=vxNextNode(graph, n1)) - { - for (p1 = 0; p1 < graph->nodes[n]->kernel->signature.num_parameters; p1++) - { - if ((graph->nodes[n1]->kernel->signature.directions[p1] == VX_OUTPUT) || - (graph->nodes[n1]->kernel->signature.directions[p1] == VX_BIDIRECTIONAL)) - { - if (vx_true_e == vxCheckWriteDependency(graph->nodes[n]->parameters[p], graph->nodes[n1]->parameters[p1])) - { - status = VX_ERROR_MULTIPLE_WRITERS; - VX_PRINT(VX_ZONE_GRAPH, "Multiple Writer to a reference found, check log!\n"); - vxAddLogEntry(reinterpret_cast(graph), status, "Node %s and Node %s are trying to output to the same reference " VX_FMT_REF "\n", graph->nodes[n]->kernel->name, graph->nodes[n1]->kernel->name, graph->nodes[n]->parameters[p]); - } - } - } - } - } - } + *status = VX_ERROR_INVALID_TYPE; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, + "Scalar contains invalid typed objects for node %s\n", nodes[n]->kernel->name); + (*num_errors)++; + return vx_false_e; //break; } - - VX_PRINT(VX_ZONE_GRAPH,"########################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Memory Allocation Phase! (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"########################\n"); - - /* now make sure each parameter is backed by memory. */ - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) + } /* VX_TYPE_SCALAR */ + else if (meta->type == VX_TYPE_MATRIX) + { + vx_matrix matrix = (vx_matrix)*item; + if (matrix->data_type != meta->dim.matrix.type) { - VX_PRINT(VX_ZONE_GRAPH,"Checking node %u\n",n); - - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) - { - if (graph->nodes[n]->parameters[p]) - { - VX_PRINT(VX_ZONE_GRAPH,"\tparameter[%u]=%p type %d sig type %d\n", p, - graph->nodes[n]->parameters[p], - graph->nodes[n]->parameters[p]->type, - graph->nodes[n]->kernel->signature.types[p]); - - if (graph->nodes[n]->parameters[p]->type == VX_TYPE_IMAGE) - { - if (static_cast(graph->nodes[n]->parameters[p])->allocateImage() == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate image at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - else if ((VX_TYPE_IS_SCALAR(graph->nodes[n]->parameters[p]->type)) || - (graph->nodes[n]->parameters[p]->type == VX_TYPE_RECTANGLE) || - (graph->nodes[n]->parameters[p]->type == VX_TYPE_THRESHOLD)) - { - /* these objects don't need to be allocated */ - } - else if (graph->nodes[n]->parameters[p]->type == VX_TYPE_LUT) - { - vx_lut_t lut = (vx_lut_t)graph->nodes[n]->parameters[p]; - if (Memory::allocateMemory(graph->context, &lut->memory) == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate lut at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - else if (graph->nodes[n]->parameters[p]->type == VX_TYPE_DISTRIBUTION) - { - vx_distribution dist = (vx_distribution)graph->nodes[n]->parameters[p]; - if (Memory::allocateMemory(graph->context, &dist->memory) == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate distribution at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - else if (graph->nodes[n]->parameters[p]->type == VX_TYPE_PYRAMID) - { - vx_pyramid pyr = (vx_pyramid)graph->nodes[n]->parameters[p]; - vx_uint32 i = 0; - for (i = 0; i < pyr->numLevels; i++) - { - if ((pyr->levels[i]->allocateImage()) == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate pyramid image at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - } - else if ((graph->nodes[n]->parameters[p]->type == VX_TYPE_MATRIX) || - (graph->nodes[n]->parameters[p]->type == VX_TYPE_CONVOLUTION)) - { - vx_matrix mat = (vx_matrix)graph->nodes[n]->parameters[p]; - if (Memory::allocateMemory(graph->context, &mat->memory) == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate matrix (or subtype) at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - else if (graph->nodes[n]->kernel->signature.types[p] == VX_TYPE_ARRAY) - { - if (static_cast(graph->nodes[n]->parameters[p])->allocateArray() == vx_false_e) - { - vxAddLogEntry(reinterpret_cast(graph), VX_ERROR_NO_MEMORY, "Failed to allocate array at node[%u] %s parameter[%u]\n", - n, graph->nodes[n]->kernel->name, p); - VX_PRINT(VX_ZONE_ERROR, "See log\n"); - } - } - /*! \todo add other memory objects to graph auto-allocator as needed! */ - } - } + *status = VX_ERROR_INVALID_TYPE; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, + "Node: %s: parameter[%u] has an invalid data type 0x%08x\n", + nodes[n]->kernel->name, p, matrix->data_type); + (*num_errors)++; + return vx_false_e; //break; } - VX_PRINT(VX_ZONE_GRAPH,"###############################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Head Nodes Determination Phase! (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"###############################\n"); - - memset(graph->heads, 0, sizeof(graph->heads)); - graph->numHeads = 0; - - /* now traverse the graph and put nodes with no predecessor in the head list */ - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) + if (matrix->columns != meta->dim.matrix.cols || matrix->rows != meta->dim.matrix.rows) { - uint32_t n1,p1; - vx_bool isAHead = vx_true_e; /* assume every node is a head until proven otherwise */ - - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters && isAHead == vx_true_e; p++) - { - if ((graph->nodes[n]->kernel->signature.directions[p] == VX_INPUT) && - (graph->nodes[n]->parameters[p] != nullptr)) - { - /* ring loop over the node array, checking every node but this nth node. */ - for (n1 = vxNextNode(graph, n); - (n1 != n) && (isAHead == vx_true_e); - n1 = vxNextNode(graph, n1)) - { - for (p1 = 0; p1 < graph->nodes[n1]->kernel->signature.num_parameters && isAHead == vx_true_e; p1++) - { - if (graph->nodes[n1]->kernel->signature.directions[p1] != VX_INPUT) - { - VX_PRINT(VX_ZONE_GRAPH,"Checking input nodes[%u].parameter[%u] to nodes[%u].parameters[%u]\n", n, p, n1, p1); - /* if the parameter is referenced elsewhere */ - if (vxCheckWriteDependency(graph->nodes[n]->parameters[p], graph->nodes[n1]->parameters[p1])) - { - /* @TODO: this was added by AI; deep dive this logic */ - vx_reference refA = graph->nodes[n]->parameters[p]; - vx_reference refB = graph->nodes[n1]->parameters[p1]; - if (refA->type == refB->type && refA->delay && refB->delay && - refA->delay == refB->delay) - { - /* skip delay slot dependency for head node detection */ - continue; - } - VX_PRINT(VX_ZONE_GRAPH,"\tnodes[%u].parameter[%u] referenced in nodes[%u].parameter[%u]\n", n,p,n1,p1); - isAHead = vx_false_e; /* this will cause all the loops to break too. */ - } - } - } - } - } - } + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid matrix dimention %ux%u\n", + nodes[n]->kernel->name, p, matrix->data_type, matrix->rows, matrix->columns); + (*num_errors)++; + return vx_false_e; //break; + } + } /* VX_TYPE_MATRIX */ + else if (meta->type == VX_TYPE_DISTRIBUTION) + { + vx_distribution distribution = (vx_distribution)*item; + //fix + if (distribution->offset_x != meta->dim.distribution.offset || + distribution->range_x != meta->dim.distribution.range || + distribution->memory.dims[0][VX_DIM_X] != meta->dim.distribution.bins) + { + *status = VX_ERROR_INVALID_VALUE; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_VALUE, + "Node: %s: parameter[%u] has an invalid offset %u, number of bins %u or range %u\n", + nodes[n]->kernel->name, p, distribution->offset_x, + distribution->memory.dims[0][VX_DIM_X], distribution->range_x); + (*num_errors)++; + return vx_false_e; //break; + } + } /* VX_TYPE_DISTRIBUTION */ + else if (meta->type == VX_TYPE_REMAP) + { + vx_remap remap = (vx_remap)*item; + if (remap->src_width != meta->dim.remap.src_width || remap->src_height != meta->dim.remap.src_height) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid source dimention %ux%u\n", + nodes[n]->kernel->name, p); + (*num_errors)++; + return vx_false_e; //break; + } - if (isAHead == vx_true_e) - { - VX_PRINT(VX_ZONE_GRAPH,"Found a head in node[%u] => %s\n", n, graph->nodes[n]->kernel->name); - graph->heads[graph->numHeads++] = n; - } + if (remap->dst_width != meta->dim.remap.dst_width || remap->dst_height != meta->dim.remap.dst_height) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid destination dimention %ux%u", + nodes[n]->kernel->name, p); + (*num_errors)++; + return vx_false_e; //break; + } + } /* VX_TYPE_REMAP */ + else if (meta->type == VX_TYPE_LUT) + { + vx_lut_t lut = (vx_lut_t)*item; + if (lut->item_type != meta->dim.lut.type || lut->num_items != meta->dim.lut.count) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid item type 0x%08x or count " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, lut->item_type, lut->num_items); + (*num_errors)++; + return vx_false_e; //break; } - - /* graph has a cycle as there are no starting points! */ - if ((graph->numHeads == 0) && (status == VX_SUCCESS)) + } /* VX_TYPE_LUT */ + else if (meta->type == VX_TYPE_THRESHOLD) + { + vx_threshold threshold = (vx_threshold)*item; + if (threshold->thresh_type != meta->dim.threshold.type) { - status = VX_ERROR_INVALID_GRAPH; - VX_PRINT(VX_ZONE_ERROR,"Graph has no heads!\n"); - vxAddLogEntry(reinterpret_cast(graph), status, "Cycle: Graph has no head nodes!\n"); + *status = VX_ERROR_INVALID_TYPE; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_TYPE, + "Threshold contains invalid typed objects for node %s\n", nodes[n]->kernel->name); + (*num_errors)++; + return vx_false_e; //break; } - - VX_PRINT(VX_ZONE_GRAPH,"##############\n"); - VX_PRINT(VX_ZONE_GRAPH,"Cycle Checking (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"##############\n"); - - graph->clearVisitation(); - - /* cycle checking by traversal of the graph from heads to tails */ - for (h = 0; h < graph->numHeads; h++) + } /* VX_TYPE_THRESHOLD */ + else if (meta->type == VX_TYPE_TENSOR) + { + vx_tensor tensor = (vx_tensor)*item; + if (*vref == (vx_reference)tensor) { - vx_status cycle_status = VX_SUCCESS; - status = graph->traverseGraph(VX_INT_MAX_NODES, graph->heads[h]); - if (cycle_status != VX_SUCCESS) + VX_PRINT(VX_ZONE_GRAPH, "Creating Tensor From Meta Data!\n"); + if ((tensor->data_type != VX_TYPE_INVALID) && + (tensor->data_type != meta->dim.tensor.data_type || tensor->fixed_point_position != meta->dim.tensor.fixed_point_position)) { - status = cycle_status; - VX_PRINT(VX_ZONE_ERROR,"Cycle found in graph!"); - vxAddLogEntry(reinterpret_cast(graph), status, "Cycle: Graph has a cycle!\n"); - goto exit; + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has invalid data type %08x or fixed point position %d!\n", + nodes[n]->kernel->name, p, tensor->data_type, tensor->fixed_point_position); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid data type %08x or fixed point position %d!\n", + nodes[n]->kernel->name, p, tensor->data_type, tensor->fixed_point_position); + (*num_errors)++; + return vx_false_e; /* exit on error */ } - } - - VX_PRINT(VX_ZONE_GRAPH,"############################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Checking for Unvisited Nodes (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"############################\n"); - - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) - { - if (graph->nodes[n]->visited == vx_false_e) + if (tensor->number_of_dimensions != 0) { - VX_PRINT(VX_ZONE_ERROR, "UNVISITED: %s node[%u]\n", graph->nodes[n]->kernel->name, n); - status = VX_ERROR_INVALID_GRAPH; - vxAddLogEntry(reinterpret_cast(graph), status, "Node %s: unvisited!\n", graph->nodes[n]->kernel->name); + for (unsigned i = 0; i < tensor->number_of_dimensions; i++) + { + if (tensor->dimensions[i] != 0 && tensor->dimensions[i] != meta->dim.tensor.dimensions[i]) + { + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has invalid dimension size %d in dimension %d!\n", + nodes[n]->kernel->name, p, tensor->dimensions[i], i); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid dimension size %d in dimension %d!\n", + nodes[n]->kernel->name, p, tensor->dimensions[i], i); + (*num_errors)++; + return vx_false_e; /* exit on error */ + } + } } - } - - graph->clearVisitation(); - - if (hasACycle == vx_true_e) - { - status = VX_ERROR_INVALID_GRAPH; - vxAddLogEntry(reinterpret_cast(graph), status, "Cycle: Graph has a cycle!\n"); - goto exit; - } - - VX_PRINT(VX_ZONE_GRAPH,"#########################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Target Verification Phase (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"#########################\n"); - - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) - { - vx_uint32 index = graph->nodes[n]->affinity; - vx_target target = graph->context->targets[index]; - if (target) + else if (tensor->number_of_dimensions != meta->dim.tensor.number_of_dimensions) { - vx_status target_verify_status = target->funcs.verify(target, graph->nodes[n]); - if (target_verify_status != VX_SUCCESS) - { - status = target_verify_status; - vxAddLogEntry(reinterpret_cast(graph), status, "Target: %s Failed to Verify Node %s\n", target->name, graph->nodes[n]->kernel->name); - } + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has invalid dimension %d!\n", + nodes[n]->kernel->name, p, tensor->number_of_dimensions); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid dimension %d!\n", + nodes[n]->kernel->name, p, tensor->number_of_dimensions); + (*num_errors)++; + return vx_false_e; /* exit on error */ } + tensor->initTensor(meta->dim.tensor.dimensions, meta->dim.tensor.number_of_dimensions, meta->dim.tensor.data_type, meta->dim.tensor.fixed_point_position); + tensor->allocateTensorMemory(); } - - VX_PRINT(VX_ZONE_GRAPH,"#######################\n"); - VX_PRINT(VX_ZONE_GRAPH,"Kernel Initialize Phase (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"#######################\n"); - - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) + else { - vx_node node = graph->nodes[n]; - if (node->kernel->initialize) + if (tensor->number_of_dimensions != meta->dim.tensor.number_of_dimensions) { - vx_status kernel_init_status = VX_FAILURE; - - /* call the kernel initialization routine */ - if ((node->kernel->user_kernel == vx_true_e) && - (node->kernel->attributes.localDataSize == 0)) - node->local_data_change_is_enabled = vx_true_e; - - kernel_init_status = node->kernel->initialize((vx_node)node, - (vx_reference *)node->parameters, - node->kernel->signature.num_parameters); - node->local_data_change_is_enabled = vx_false_e; - if (kernel_init_status != VX_SUCCESS) - { - status = kernel_init_status; - vxAddLogEntry(reinterpret_cast(graph), status, "Kernel: %s failed to initialize!\n", node->kernel->name); - } + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] is an invalid number of dimensions %u!\n", + nodes[n]->kernel->name, p, tensor->number_of_dimensions); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] is an invalid number of dimensions %u!\n", + nodes[n]->kernel->name, p, tensor->number_of_dimensions); + (*num_errors)++; + return vx_false_e; /* exit on error */ } - - /* once the kernel has been initialized, create any local data for it */ - if ((node->attributes.localDataSize > 0) && - (node->attributes.localDataPtr == nullptr)) + for (unsigned i = 0; i < tensor->number_of_dimensions; i++) { - node->attributes.localDataPtr = new vx_char(node->attributes.localDataSize); - if (node->kernel->user_kernel == vx_true_e) + if (tensor->dimensions[i] != meta->dim.tensor.dimensions[i]) { - node->local_data_set_by_implementation = vx_true_e; + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has an invalid dimension %u!\n", + nodes[n]->kernel->name, p, tensor->dimensions[i]); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid dimension %u!\n", + nodes[n]->kernel->name, p, tensor->dimensions[i]); + (*num_errors)++; + return vx_false_e; /* exit on error */ } - VX_PRINT(VX_ZONE_GRAPH, "Local Data Allocated " VX_FMT_SIZE " bytes for node into %p\n!", - node->attributes.localDataSize, - node->attributes.localDataPtr); } - } - - VX_PRINT(VX_ZONE_GRAPH,"#######################\n"); - VX_PRINT(VX_ZONE_GRAPH,"COST CALCULATIONS (%d)\n", status); - VX_PRINT(VX_ZONE_GRAPH,"#######################\n"); - for (n = 0; (n < graph->numNodes) && (status == VX_SUCCESS); n++) - { - graph->nodes[n]->costs.bandwidth = 0ul; - for (p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; p++) + if (tensor->data_type != meta->dim.tensor.data_type) { - vx_reference ref = graph->nodes[n]->parameters[p]; - if (ref) - { - vx_uint32 i; - switch (ref->type) - { - case VX_TYPE_IMAGE: - { - vx_image image = (vx_image)ref; - for (i = 0; i < image->memory.nptrs; i++) - graph->nodes[n]->costs.bandwidth += Memory::computeMemorySize(&image->memory, i); - break; - } - case VX_TYPE_ARRAY: - { - vx_array array = (vx_array)ref; - graph->nodes[n]->costs.bandwidth += Memory::computeMemorySize(&array->memory, 0); - break; - } - case VX_TYPE_PYRAMID: - { - vx_pyramid pyr = (vx_pyramid)ref; - vx_uint32 j; - for (j = 0; j < pyr->numLevels; j++) - { - vx_image image = pyr->levels[j]; - for (i = 0; i < image->memory.nptrs; i++) - { - graph->nodes[n]->costs.bandwidth += Memory::computeMemorySize(&image->memory, i); - } - } - break; - } - default: - VX_PRINT(VX_ZONE_WARNING, "Node[%u].parameter[%u] Unknown bandwidth cost!\n", n, p); - break; - } - } + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] is an invalid data type %08x!\n", + nodes[n]->kernel->name, p, tensor->data_type); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid data type %08x!\n", + nodes[n]->kernel->name, p, tensor->data_type); + (*num_errors)++; + return vx_false_e; /* exit on error */ + } + if (tensor->fixed_point_position != meta->dim.tensor.fixed_point_position) + { + *status = VX_ERROR_INVALID_FORMAT; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] has an invalid fixed point position %08x!\n", + nodes[n]->kernel->name, p, tensor->fixed_point_position); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has invalid fixed point position %08x!\n", + nodes[n]->kernel->name, p, tensor->fixed_point_position); + (*num_errors)++; + return vx_false_e; /* exit on error */ } - VX_PRINT(VX_ZONE_GRAPH, "Node[%u] has bandwidth cost of " VX_FMT_SIZE " bytes\n", n, graph->nodes[n]->costs.bandwidth); - } - -exit: - graph->reverify = vx_false_e; - if (status == VX_SUCCESS) - { - graph->verified = vx_true_e; - graph->state = VX_GRAPH_STATE_VERIFIED; - } - else - { - graph->verified = vx_false_e; - graph->state = VX_GRAPH_STATE_UNVERIFIED; } - - /* unlock the graph */ - Osal::semPost(&graph->lock); - } + } /* VX_TYPE_TENSOR */ + /*! \todo support other output types for safety checks in graph verification parameters phase */ else { - status = VX_ERROR_INVALID_REFERENCE; + VX_PRINT(VX_ZONE_GRAPH, "Returned Meta type %x\n", meta->type); } - VX_PRINT(VX_ZONE_GRAPH,"Returning status %d\n", status); - return status; -} + return vx_true_e; +} /* postprocessOutputDataType() */ -static vx_status vxExecuteGraph(vx_graph graph, vx_uint32 depth) +/* + * Parameters: + * n - index of node + * p - index of parameter + * vref - reference of the parameter + * meta - parameter meta info + */ +vx_bool Graph::postprocessOutput(vx_uint32 n, vx_uint32 p, vx_reference* vref, vx_meta_format meta, + vx_status* status, vx_uint32* num_errors) { - vx_status status = VX_SUCCESS; - vx_action action = VX_ACTION_CONTINUE; - vx_uint32 n, p, numLast, numNext, numLeft = 0; - vx_uint32 last_nodes[VX_INT_MAX_REF]; - vx_uint32 next_nodes[VX_INT_MAX_REF]; - vx_uint32 left_nodes[VX_INT_MAX_REF]; - vx_context context = vxGetContext((vx_reference)graph); - vx_uint32 max_pipeup_depth = 1; - (void)depth; - -#if defined(OPENVX_USE_SMP) - vx_value_set_t workitems[VX_INT_MAX_REF]; -#endif - if (Reference::isValidReference(reinterpret_cast(graph)) == vx_false_e) + if (Context::isValidType(meta->type) == vx_false_e) { - return VX_ERROR_INVALID_REFERENCE; + *status = VX_ERROR_INVALID_TYPE; + vxAddLogEntry(reinterpret_cast(this), *status, + "Node: %s: parameter[%u] is not a valid type %d!\n", + nodes[n]->kernel->name, p, meta->type); + (*num_errors)++; + return vx_false_e; /* exit on error */ } -#ifdef OPENVX_USE_PIPELINING - // Dequeue graph parameters if pipelining is enabled - if (graph->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO || - graph->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) + if (meta->type == VX_TYPE_OBJECT_ARRAY) { - for (vx_uint32 i = 0; i < graph->numEnqueableParams; i++) + vx_object_array objarr = (vx_object_array)nodes[n]->parameters[p]; + VX_PRINT(VX_ZONE_GRAPH, "meta: type 0x%08x, 0x%08x " VX_FMT_SIZE "\n", meta->type, meta->dim.object_array.item_type, meta->dim.object_array.num_items); + + if (ObjectArray::isValidObjectArray(objarr, meta->dim.object_array.item_type, meta->dim.object_array.num_items) != vx_true_e) { - auto& paramQueue = graph->parameters[i].queue; - vx_reference ref; + *status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_DIMENSION, + "Node: %s: parameter[%u] has an invalid item type 0x%08x or num_items " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, objarr->item_type, objarr->num_items); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: parameter[%u] has an invalid item type 0x%08x or num_items " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, p, objarr->item_type, objarr->num_items); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: Expected item type 0x%08x or num_items " VX_FMT_SIZE "\n", + nodes[n]->kernel->name, meta->dim.object_array.item_type, meta->dim.object_array.num_items); + (*num_errors)++; + return vx_false_e; //break; + } - // Dequeue a reference from the "ready" queue - if (paramQueue.peekReady(ref)) + if (vref == (vx_reference*)&objarr) + { + VX_PRINT(VX_ZONE_GRAPH, "Creating Object Array From Meta Data %x and " VX_FMT_SIZE "!\n", meta->dim.object_array.item_type, meta->dim.object_array.num_items); + for (vx_uint32 i = 0; i < meta->dim.object_array.num_items; i++) { - vx_node node = graph->parameters[i].node; - vx_uint32 param_index = graph->parameters[i].index; - // Save the old reference for this graph parameter - vx_reference old_ref = node->parameters[param_index]; + vx_reference item = vxGetObjectArrayItem(objarr, i); + + if (!postprocessOutputDataType(n, p, &item, vref, meta, status, num_errors)) + { + vxReleaseReference(&item); + *status = VX_ERROR_INVALID_PARAMETERS; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_PARAMETERS, + "Node: %s: meta[%u] has an invalid meta of exemplar\n", + nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid meta of exemplar\n", + nodes[n]->kernel->name, p); + (*num_errors)++; + + return vx_false_e; //break; + } + + vxReleaseReference(&item); + } + } + else + { + /* check the data that came back from the output validator against the object */ + for (vx_uint32 i = 0; i < meta->dim.object_array.num_items; i++) + { + vx_reference item = vxGetObjectArrayItem(objarr, i); + vx_reference itemref = vxGetObjectArrayItem((vx_object_array)*vref, i); + + if (!postprocessOutputDataType(n, p, &item, &itemref, meta, status, num_errors)) + { + vxReleaseReference(&item); + *status = VX_ERROR_INVALID_PARAMETERS; + vxAddLogEntry(reinterpret_cast(this), VX_ERROR_INVALID_PARAMETERS, + "Node: %s: meta[%u] has an invalid meta of exemplar\n", + nodes[n]->kernel->name, p); + VX_PRINT(VX_ZONE_ERROR, "Node: %s: meta[%u] has an invalid meta of exemplar\n", + nodes[n]->kernel->name, p); + (*num_errors)++; - // Update ALL node parameters that point to this old reference - if (node->parameters[param_index] != ref) - { - for (vx_uint32 n = 0; n < graph->numNodes; n++) - { - for (vx_uint32 p = 0; p < graph->nodes[n]->kernel->signature.num_parameters; - p++) - { - // Assign the dequeued reference to the corresponding node parameter - if (graph->nodes[n]->parameters[p] == old_ref) - { - graph->context->removeReference(graph->nodes[n]->parameters[p]); - ref->incrementReference(VX_INTERNAL); - graph->nodes[n]->parameters[p] = ref; - } - } - } + return vx_false_e; //break; } - VX_PRINT(VX_ZONE_GRAPH, - "Dequeued reference for graph parameter %u and \ - assigned to node parameter %u\n", - i, param_index); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Failed to dequeue reference for graph parameter %u\n", i); - std::cerr << "Failed to dequeue reference for graph parameter " << i << std::endl; - return VX_ERROR_NO_RESOURCES; + vxReleaseReference(&item); } } } -#endif - - if (graph->verified == vx_false_e) + else { - status = vxVerifyGraph((vx_graph)graph); - if (status != VX_SUCCESS) - { - return status; - } + return postprocessOutputDataType(n, p, &nodes[n]->parameters[p], vref, meta, status, num_errors); } - VX_PRINT(VX_ZONE_GRAPH,"************************\n"); - VX_PRINT(VX_ZONE_GRAPH,"*** PROCESSING GRAPH ***\n"); - VX_PRINT(VX_ZONE_GRAPH,"************************\n"); - graph->state = VX_GRAPH_STATE_RUNNING; - graph->clearVisitation(); - graph->clearExecution(); - if (context->perf_enabled) - { - Osal::startCapture(&graph->perf); - } + return vx_true_e; +} /* postprocessOutput() */ - /* initialize the next_nodes as the graph heads */ - memcpy(next_nodes, graph->heads, graph->numHeads * sizeof(vx_uint32)); - numNext = graph->numHeads; +vx_status Graph::pipelineValidateRefsList( + const vx_graph_parameter_queue_params_t graph_parameters_queue_param) +{ + vx_status status = VX_SUCCESS; + vx_meta_format meta_base = nullptr, meta = nullptr; + vx_uint32 i; - do { - for (n = 0; n < numNext; n++) - { - Node::printNode(graph->nodes[next_nodes[n]]); - } + if (nullptr != graph_parameters_queue_param.refs_list[0]) + { + meta_base = vxCreateMetaFormat(graph_parameters_queue_param.refs_list[0]->context); + status = vxSetMetaFormatFromReference(meta_base, graph_parameters_queue_param.refs_list[0]); + } - /* execute the next nodes */ - for (n = 0; n < numNext; n++) + if ( (VX_SUCCESS == status) + && (nullptr != meta_base) ) + { + for (i = 1; i < graph_parameters_queue_param.refs_list_size; i++) { - if (graph->nodes[next_nodes[n]]->executed == vx_false_e) + if (nullptr != graph_parameters_queue_param.refs_list[i]) { - vx_uint32 t = graph->nodes[next_nodes[n]]->affinity; -#if defined(OPENVX_USE_SMP) - if (depth == 1 && graph->shouldSerialize == vx_false_e) + meta = vxCreateMetaFormat(graph_parameters_queue_param.refs_list[i]->context); + + if (nullptr != meta) { - vx_value_set_t *work = &workitems[n]; - vx_target target = graph->context->targets[t]; - vx_node node = graph->nodes[next_nodes[n]]; - work->v1 = (vx_value_t)target; - work->v2 = (vx_value_t)node; - work->v3 = (vx_value_t)VX_ACTION_CONTINUE; - VX_PRINT(VX_ZONE_GRAPH, "Scheduling work on %s for %s\n", target->name, node->kernel->name); + status = vxSetMetaFormatFromReference(meta, graph_parameters_queue_param.refs_list[i]); } else -#endif { - vx_target target = graph->context->targets[t]; - vx_node node = graph->nodes[next_nodes[n]]; - - /* turn on access to virtual memory */ - for (p = 0u; p < node->kernel->signature.num_parameters; p++) - { - if (node->parameters[p] == nullptr) continue; - if (node->parameters[p]->is_virtual == vx_true_e) - { - node->parameters[p]->is_accessible = vx_true_e; - } - } - - VX_PRINT(VX_ZONE_GRAPH, "Calling Node[%u] %s:%s\n", - next_nodes[n], - target->name, node->kernel->name); - - /* Check for pipeup phase: - * If this is the first time we are executing the graph, we need to pipeup - * all nodes with kernels in the graph that need pipeup of refs. - */ - max_pipeup_depth = std::max( - {max_pipeup_depth, node->kernel->input_depth, node->kernel->output_depth}); - if (node->kernel->pipeUpCounter < max_pipeup_depth - 1) - { - node->state = VX_NODE_STATE_PIPEUP; - std::cout << "max_pipeup_depth: " << max_pipeup_depth << std::endl; - node->kernel->pipeUpCounter++; - // Retain input buffers during PIPEUP - for (vx_uint32 i = 0; i < node->kernel->output_depth - 1; i++) - { - action = target->funcs.process(target, &node, 0, 1); - node->kernel->pipeUpCounter++; - } - // For source nodes, provide new output buffers during PIPEUP - for (vx_uint32 i = 0; i < node->kernel->input_depth - 1; i++) - { - action = target->funcs.process(target, &node, 0, 1); - node->kernel->pipeUpCounter++; - } - } - - /* If this node was in pipeup, update its state */ - node->state = VX_NODE_STATE_STEADY; - - action = target->funcs.process(target, &node, 0, 1); - - VX_PRINT(VX_ZONE_GRAPH, "Returned Node[%u] %s:%s Action %d\n", - next_nodes[n], - target->name, node->kernel->name, - action); + status = VX_FAILURE; + VX_PRINT(VX_ZONE_ERROR, "Meta Format is NULL\n"); + } - /* turn off access to virtual memory */ - for (p = 0u; p < node->kernel->signature.num_parameters; p++) + if (VX_SUCCESS == status) + { + if (graph_parameters_queue_param.refs_list[0]->type == + graph_parameters_queue_param.refs_list[i]->type) { - if (node->parameters[p] == nullptr) - { - continue; - } - if (node->parameters[p]->is_virtual == vx_true_e) + if (vx_true_e != MetaFormat::isMetaFormatEqual(meta_base, meta, graph_parameters_queue_param.refs_list[0]->type)) { - node->parameters[p]->is_accessible = vx_false_e; + status = VX_ERROR_INVALID_PARAMETERS; + VX_PRINT(VX_ZONE_ERROR, "Invalid meta data of reference list!\n"); } } + } -#ifdef OPENVX_USE_PIPELINING - /* Raise a node completed event. */ - vx_event_info_t event_info; - event_info.node_completed.graph = graph; - event_info.node_completed.node = node; - if (graph->context->event_queue.isEnabled() && - VX_SUCCESS != graph->context->event_queue.push(VX_EVENT_NODE_COMPLETED, 0, - &event_info, - (vx_reference)node)) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to push node completed event for node %s\n", - node->kernel->name); - } - - /* Raise a graph parameter consumed event */ - for (vx_uint32 gp = 0; gp < graph->numEnqueableParams; gp++) + if (Reference::isValidReference(meta, VX_TYPE_META_FORMAT) == vx_true_e) + { + status |= vxReleaseMetaFormat(&meta); + if (VX_SUCCESS != status) { - vx_node param_node = graph->parameters[gp].node; - vx_uint32 param_index = graph->parameters[gp].index; - - /* If this node just executed and consumed a graph parameter */ - if (param_node == node) - { - vx_event_info_t event_info = {}; - event_info.graph_parameter_consumed.graph = graph; - event_info.graph_parameter_consumed.graph_parameter_index = param_index; - - (void)graph->parameters[gp].queue.moveReadyToDone(); - - if (graph->context->event_queue.isEnabled() && - param_node->kernel->signature.directions[param_index] == VX_INPUT && - VX_SUCCESS != graph->context->event_queue.push( - VX_EVENT_GRAPH_PARAMETER_CONSUMED, 0, &event_info, - (vx_reference)graph)) - { - VX_PRINT(VX_ZONE_ERROR, - "Failed to push graph parameter consumed event for " - "graph %p, param %u\n", - graph, gp); - } - } + VX_PRINT(VX_ZONE_ERROR, "Failed to release meta format object \n"); } -#endif + } - if (action == VX_ACTION_ABANDON) - { -#ifdef OPENVX_USE_PIPELINING - /* Raise a node error event. */ - vx_event_info_t event_info; - event_info.node_error.graph = graph; - event_info.node_error.node = node; - event_info.node_error.status = node->status; - if (graph->context->event_queue.isEnabled() && - VX_SUCCESS != graph->context->event_queue.push(VX_EVENT_NODE_ERROR, 0, - &event_info, - (vx_reference)node)) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to push node error event for node %s\n", - node->kernel->name); - } -#endif - break; - } + if (VX_SUCCESS != status) + { + break; } } else { - VX_PRINT(VX_ZONE_ERROR, "Multiple executions attempted!\n"); - break; - } - } - -#if defined(OPENVX_USE_SMP) - if (depth == 1 && graph->shouldSerialize == vx_false_e) - { - if (Osal::issueThreadpool(graph->context->workers, workitems, numNext) == vx_true_e) - { - /* do a blocking complete */ - VX_PRINT(VX_ZONE_GRAPH, "Issued %u work items!\n", numNext); - if (Osal::completeThreadpool(graph->context->workers, vx_true_e) == vx_true_e) - { - VX_PRINT(VX_ZONE_GRAPH, "Processed %u items in threadpool!\n", numNext); - } - action = VX_ACTION_CONTINUE; - for (n = 0; n < numNext; n++) - { - vx_action a = workitems[n].v3; - if (a != VX_ACTION_CONTINUE) - { - action = a; - VX_PRINT(VX_ZONE_WARNING, "Workitem[%u] returned action code %d\n", n, a); - break; - } - } + status = VX_ERROR_INVALID_PARAMETERS; + VX_PRINT(VX_ZONE_ERROR, "Invalid graph parameter ref list!\n"); } } -#endif + } - if (action == VX_ACTION_ABANDON) + if (Reference::isValidReference(meta_base, VX_TYPE_META_FORMAT) == vx_true_e) + { + status |= vxReleaseMetaFormat(&meta_base); + if (VX_SUCCESS != status) { - break; + VX_PRINT(VX_ZONE_ERROR, "Failed to release meta format object \n"); } + } - /* copy next_nodes to last_nodes */ - memcpy(last_nodes, next_nodes, numNext * sizeof(vx_uint32)); - numLast = numNext; - - /* determine the next nodes */ - graph->findNextNodes(last_nodes, numLast, next_nodes, &numNext, left_nodes, &numLeft); - - } while (numNext > 0); + return status; +} - if (action == VX_ACTION_ABANDON) - { - status = VX_ERROR_GRAPH_ABANDONED; - } - if (context->perf_enabled) +void Graph::streamingLoop() +{ +#ifdef OPENVX_USE_STREAMING + while (isStreaming) { - Osal::stopCapture(&graph->perf); + /* Wait for trigger node event if set */ + // if (triggerNodeIndex != UINT32_MAX) + // { + // VX_PRINT(VX_ZONE_INFO, "Trigger node defined -- waiting on it to trigger\n"); + // /* Wait for the trigger node to complete */ + // while (!nodes[triggerNodeIndex]->executed) + // { + // std::cout << "Waiting for trigger node to complete" << std::endl; + // std::this_thread::sleep_for(std::chrono::milliseconds(10)); + // /* Allow clean exit */ + // if (!isStreaming) return; + // } + // /* Reset the event for the next iteration */ + // nodes[triggerNodeIndex]->executed = vx_false_e; + // } + + /* Schedule and wait for the graph */ + vx_status status = vxScheduleGraph(this); + if (status != VX_SUCCESS) break; + status = vxWaitGraph(this); + if (status != VX_SUCCESS) break; } - graph->clearVisitation(); +#endif /* OPENVX_USE_STREAMING */ +} - for (n = 0; n < VX_INT_MAX_REF; n++) +void Graph::destruct() +{ + while (numNodes) { - if (graph->delays[n] && Reference::isValidReference(reinterpret_cast(graph->delays[n]), VX_TYPE_DELAY) == vx_true_e) + vx_node node = nodes[0]; + /* Interpretation of spec is to release all external references of Nodes when vxReleaseGraph() + is called AND all graph references count == 0 (garbage collection). + However, it may be possible that the user would have already released its external reference + so we need to check. */ + if (nullptr != node) { - vxAgeDelay(graph->delays[n]); + if (node->external_count) + { + Reference::releaseReference((vx_reference*)&node, VX_TYPE_NODE, VX_EXTERNAL, nullptr); + } + + if (node) + { + node->removeNode(); + } } } +} - VX_PRINT(VX_ZONE_GRAPH,"Process returned status %d\n", status); +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ -#ifdef OPENVX_USE_PIPELINING - /* Raise a graph completed event. */ - vx_event_info_t event_info; - event_info.graph_completed.graph = graph; - if (graph->context->event_queue.isEnabled() && - VX_SUCCESS != graph->context->event_queue.push(VX_EVENT_GRAPH_COMPLETED, 0, &event_info, - (vx_reference)graph)) - { - VX_PRINT(VX_ZONE_ERROR, "Failed to push graph completed event for graph %p\n", graph); - } -#endif +VX_API_ENTRY vx_graph VX_API_CALL vxCreateGraph(vx_context context) +{ + vx_graph graph = nullptr; - // Report the performance of the graph execution. - if (context->perf_enabled) + if (Context::isValidContext(context) == vx_true_e) { - for (n = 0; n < graph->numNodes; n++) + graph = (vx_graph)Reference::createReference(context, VX_TYPE_GRAPH, VX_EXTERNAL, context); + if (vxGetStatus((vx_reference)graph) == VX_SUCCESS && graph->type == VX_TYPE_GRAPH) { - VX_PRINT(VX_ZONE_PERF,"nodes[%u] %s[%d] last:" VX_FMT_TIME "ms avg:" VX_FMT_TIME "ms min:" VX_FMT_TIME "ms max:" VX_FMT_TIME "\n", - n, - graph->nodes[n]->kernel->name, - graph->nodes[n]->kernel->enumeration, - Osal::timeToMS(graph->nodes[n]->perf.tmp), - Osal::timeToMS(graph->nodes[n]->perf.avg), - Osal::timeToMS(graph->nodes[n]->perf.min), - Osal::timeToMS(graph->nodes[n]->perf.max) - ); + Osal::initPerf(&graph->perf); + Osal::createSem(&graph->lock, 1); + VX_PRINT(VX_ZONE_GRAPH,"Created Graph %p\n", graph); + Reference::printReference((vx_reference)graph); + graph->reverify = graph->verified; + graph->verified = vx_false_e; + graph->state = VX_GRAPH_STATE_UNVERIFIED; } } - if (status == VX_SUCCESS) + return (vx_graph)graph; +} + +VX_API_ENTRY vx_status VX_API_CALL vxSetGraphAttribute(vx_graph graph, vx_enum attribute, const void *ptr, vx_size size) +{ + vx_status status = VX_SUCCESS; + (void)attribute; + (void)ptr; + (void)size; + + if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) { - graph->state = VX_GRAPH_STATE_COMPLETED; + /*! @todo there are no settable attributes in this implementation yet... */ + status = VX_ERROR_NOT_SUPPORTED; } else { - graph->state = VX_GRAPH_STATE_ABANDONED; + status = VX_ERROR_INVALID_REFERENCE; } return status; } -VX_API_ENTRY vx_status VX_API_CALL vxScheduleGraph(vx_graph graph) +VX_API_ENTRY vx_status VX_API_CALL vxQueryGraph(vx_graph graph, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; - if (Reference::isValidReference(reinterpret_cast(graph)) == vx_false_e) - { - return VX_ERROR_INVALID_REFERENCE; - } - if (graph->verified == vx_false_e) + if (Reference::isValidReference(reinterpret_cast(graph)) == vx_true_e) { - status = vxVerifyGraph((vx_graph)graph); - if (status != VX_SUCCESS) + VX_PRINT(VX_ZONE_GRAPH,"INFO: Query:0x%x:%d\n", attribute, (attribute & VX_ATTRIBUTE_ID_MASK)); + + switch (attribute) { - return status; + case VX_GRAPH_PERFORMANCE: + if (VX_CHECK_PARAM(ptr, size, vx_perf_t, 0x3)) + { + vx_perf_t perf = graph->performance(); + memcpy(ptr, &perf, size); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_GRAPH_STATE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + { + *(vx_status*)ptr = graph->getState(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_GRAPH_NUMNODES: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32*)ptr = graph->getNumNodes(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_GRAPH_NUMPARAMETERS: + if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) + { + *(vx_uint32*)ptr = graph->getNumParams(); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } } - -#ifdef OPENVX_USE_PIPELINING - vx_uint32 numParams = std::min(graph->numParams, graph->numEnqueableParams); - vx_size batch_depth = 1u; - if (graph->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) + else { - batch_depth = UINT32_MAX; // Use UINT32_MAX to indicate no limit on batch depth - for (vx_uint32 i = 0; i < numParams; ++i) - { - batch_depth = std::min(batch_depth, graph->parameters[i].queue.readyQueueSize()); - } - - if (batch_depth == 0 || batch_depth == UINT32_MAX) - { - // Not enough data to schedule a batch - return VX_ERROR_NOT_SUFFICIENT; - } + status = VX_ERROR_INVALID_REFERENCE; } - for (vx_uint32 i = 0; i < batch_depth; i++) -#endif - // if (Osal::semTryWait(&graph->lock) == vx_true_e) - { - Osal::semTryWait(&graph->lock); - vx_sem_t* p_graph_queue_lock = graph->context->p_global_lock; - vx_uint32 q = 0u; - vx_value_set_t *pq = nullptr; + return status; +} - Osal::semWait(p_graph_queue_lock); - /* acquire a position in the graph queue */ - for (q = 0; q < dimof(graph->context->graph_queue); q++) - { - if (graph->context->graph_queue[q].v1 == 0) - { - pq = &graph->context->graph_queue[q]; - graph->context->numGraphsQueued++; - break; - } - } - Osal::semPost(p_graph_queue_lock); - if (pq) - { - memset(pq, 0, sizeof(vx_value_set_t)); - pq->v1 = (vx_value_t)graph; +VX_API_ENTRY vx_status VX_API_CALL vxVerifyGraph(vx_graph graph) +{ + vx_status status = VX_SUCCESS; -#ifdef OPENVX_USE_PIPELINING - /* Increment the schedule count */ - graph->scheduleCount++; -#endif - /* now add the graph to the queue */ - VX_PRINT(VX_ZONE_GRAPH,"Writing graph=" VX_FMT_REF ", status=%d\n",graph, status); - if (Osal::writeQueue(&graph->context->proc.input, pq) == vx_true_e) - { - status = VX_SUCCESS; - } - else - { - Osal::semPost(&graph->lock); - VX_PRINT(VX_ZONE_ERROR, "Failed to write graph to queue"); - status = VX_ERROR_NO_RESOURCES; - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Graph queue is full\n"); - status = VX_ERROR_NO_RESOURCES; - } + if (Reference::isValidReference(reinterpret_cast(graph)) == vx_true_e) + { + status = graph->verify(); + } + else + { + status = VX_ERROR_INVALID_REFERENCE; } - // else - // { - // /* graph is already scheduled */ - // VX_PRINT(VX_ZONE_WARNING, "Graph is already scheduled!\n"); - // // status = VX_ERROR_GRAPH_SCHEDULED; - // } + VX_PRINT(VX_ZONE_GRAPH, "Returning status %d\n", status); return status; } -VX_API_ENTRY vx_status VX_API_CALL vxWaitGraph(vx_graph graph) +VX_API_ENTRY vx_status VX_API_CALL vxScheduleGraph(vx_graph graph) { - vx_status status = VX_SUCCESS; - if (Reference::isValidReference(reinterpret_cast(graph)) == vx_false_e) { return VX_ERROR_INVALID_REFERENCE; } - if (Osal::semTryWait(&graph->lock) == vx_false_e || - graph->scheduleMode == VX_GRAPH_SCHEDULE_MODE_QUEUE_MANUAL) /* locked */ - { - vx_sem_t* p_graph_queue_lock = graph->context->p_global_lock; - vx_graph g2; - vx_bool ret = vx_true_e; - vx_value_set_t *data = nullptr; - do - { - ret = Osal::readQueue(&graph->context->proc.output, &data); - if (ret == vx_false_e) - { - /* graph was locked but the queue was empty... */ - VX_PRINT(VX_ZONE_ERROR, "Queue was empty but graph was locked.\n"); - status = VX_FAILURE; - } - else - { - g2 = (vx_graph)data->v1; - status = (vx_status)data->v2; - if (g2 == graph) /* great, it's the graph we want. */ - { - vx_uint32 q = 0u; - Osal::semWait(p_graph_queue_lock); - /* find graph in the graph queue */ - for (q = 0; q < dimof(graph->context->graph_queue); q++) - { - if (graph->context->graph_queue[q].v1 == (vx_value_t)graph) - { - graph->context->graph_queue[q].v1 = 0; - graph->context->numGraphsQueued--; - break; - } - } - Osal::semPost(p_graph_queue_lock); + return graph->schedule(); +} -#ifdef OPENVX_USE_PIPELINING - /* Decrement the schedule count */ - graph->scheduleCount--; - /* Unlock the graph only if all scheduled executions are completed */ - if (graph->scheduleCount == 0) - { - Osal::semPost(&graph->lock); - break; - } -#else - break; -#endif - } - else - { - /* not the right graph, put it back. */ - Osal::writeQueue(&graph->context->proc.output, data); - } - } - } while (ret == vx_true_e); - Osal::semPost(&graph->lock); /* unlock the graph. */ - } - else +VX_API_ENTRY vx_status VX_API_CALL vxWaitGraph(vx_graph graph) +{ + if (Reference::isValidReference(reinterpret_cast(graph)) == vx_false_e) { - // status = VX_FAILURE; - Osal::semPost(&graph->lock); /* was free, release */ + return VX_ERROR_INVALID_REFERENCE; } - return status; + return graph->wait(); } VX_API_ENTRY vx_status VX_API_CALL vxProcessGraph(vx_graph graph) @@ -3091,17 +3240,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxProcessGraph(vx_graph graph) if (VX_SUCCESS == status) { - /* create a counter for re-entrancy checking */ - static vx_uint32 count = 0; - vx_sem_t* p_sem = graph->context->p_global_lock; - - Osal::semWait(p_sem); - count++; - Osal::semPost(p_sem); - status = vxExecuteGraph(graph, count); - Osal::semWait(p_sem); - count--; - Osal::semPost(p_sem); + status = graph->processGraph(); } VX_PRINT(VX_ZONE_GRAPH, "%s returned %d\n", __func__, status ); @@ -3112,22 +3251,10 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToGraph(vx_graph graph, vx_para { vx_status status = VX_ERROR_INVALID_REFERENCE; - if ((Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) && - (Reference::isValidReference(reinterpret_cast(param), VX_TYPE_PARAMETER) == vx_true_e)) - { - graph->parameters[graph->numParams].node = param->node; - graph->parameters[graph->numParams].index = param->index; - graph->numParams++; - status = VX_SUCCESS; - } - else if ((Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) && - (Reference::isValidReference(reinterpret_cast(param), VX_TYPE_PARAMETER) == vx_false_e)) + if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == + vx_true_e) { - /* insert an empty parameter */ - graph->parameters[graph->numParams].node = nullptr; - graph->parameters[graph->numParams].index = 0; - graph->numParams++; - status = VX_SUCCESS; + status = graph->addParameter(param); } else { @@ -3143,16 +3270,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetGraphParameterByIndex(vx_graph graph, vx if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) { - if (index < VX_INT_MAX_PARAMS) - { - status = vxSetParameterByIndex((vx_node)graph->parameters[index].node, - graph->parameters[index].index, - value); - } - else - { - status = VX_ERROR_INVALID_VALUE; - } + status = graph->setParameterByIndex(index, value); } return status; @@ -3164,11 +3282,7 @@ VX_API_ENTRY vx_parameter VX_API_CALL vxGetGraphParameterByIndex(vx_graph graph, if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) { - if ((index < VX_INT_MAX_PARAMS) && (index < graph->numParams)) - { - vx_uint32 node_index = graph->parameters[index].index; - parameter = vxGetParameterByIndex((vx_node)graph->parameters[index].node, node_index); - } + parameter = graph->getParameterByIndex(index); } else { @@ -3184,9 +3298,25 @@ VX_API_ENTRY vx_bool VX_API_CALL vxIsGraphVerified(vx_graph graph) vx_bool verified = vx_false_e; if (Reference::isValidReference(reinterpret_cast(graph), VX_TYPE_GRAPH) == vx_true_e) { - VX_PRINT(VX_ZONE_GRAPH, "Graph is %sverified\n", (graph->verified == vx_true_e?"":"NOT ")); - verified = graph->verified; + graph->isVerified(); } return verified; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseGraph(vx_graph* g) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != g) + { + vx_graph graph = *(g); + if (Reference::isValidReference(graph, VX_TYPE_GRAPH) == vx_true_e) + { + status = + Reference::releaseReference((vx_reference*)g, VX_TYPE_GRAPH, VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From ef1d2ed7d68b57c3a74000718c21c045669c3bfe Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Tue, 29 Jul 2025 18:04:07 -0700 Subject: [PATCH 22/34] Reworked context --- framework/include/vx_context.h | 251 ++++++++- framework/src/vx_context.cpp | 919 ++++++++++++++++++++------------- 2 files changed, 791 insertions(+), 379 deletions(-) diff --git a/framework/include/vx_context.h b/framework/include/vx_context.h index 23b6e081..9c9b8daf 100644 --- a/framework/include/vx_context.h +++ b/framework/include/vx_context.h @@ -17,6 +17,7 @@ #define VX_CONTEXT_H #include +#include #include "vx_event_queue.hpp" #include "vx_internal.h" @@ -52,6 +53,150 @@ class Context : public Reference */ ~Context(); + /** + * @brief Get vendor id + * + * @return vx_uint16 The vendor id. + * @ingroup group_int_context + */ + vx_uint16 vendorId() const; + + /** + * @brief Get version number + * + * @return vx_uint16 The version number. + * @ingroup group_int_context + */ + vx_uint16 version() const; + + /** + * @brief Get number of loaded modules + * + * @return vx_uint32 The number of loaded modules. + * @ingroup group_int_context + */ + vx_uint32 numModules() const; + + /** + * @brief Get number of references + * + * @return vx_uint32 The number of tracked references. + * @ingroup group_int_context + */ + vx_uint32 numReferences() const; + + /** + * @brief Get the implementation name + * + * @return const vx_char* The implementation name. + * @ingroup group_int_context + */ + const vx_char* implName() const; + + /** + * @brief Get the names of the extensions supported + * + * @return const vx_char* The names of the extensions supported + * @ingroup group_int_context + */ + const vx_char* extensions() const; + + /** + * @brief Get the max dimensions of a convolution supported + * + * @return vx_size The max dimensions of a convolution supported. + * @ingroup group_int_context + */ + vx_size convolutionMaxDim() const; + + /** + * @brief Get the max dimensions of a non linear supported + * + * @return vx_size The max dimensions of a non linear supported. + * @ingroup group_int_context + */ + vx_size nonLinearMaxDim() const; + + /** + * @brief Get the optical flow max window dimension supported + * + * @return vx_size The optical flow max window dimension supported. + * @ingroup group_int_context + */ + vx_size opticalFlowMaxWindowDim() const; + + /** + * @brief Get the immediate border + * + * @return vx_border_t The immediate border. + * @ingroup group_int_context + */ + vx_border_t immediateBorder() const; + + /** + * @brief Get the immediate border policy + * + * @return vx_enum The immediate border policy. + * @ingroup group_int_context + */ + vx_enum immediateBorderPolicy() const; + + /** + * @brief Get the number of unique kernels + * + * @return vx_uint32 The number of unique kernels. + * @ingroup group_int_context + */ + vx_uint32 numUniqueKernels() const; + + /** + * @brief Get the max tensor dimensions supported + * + * @return vx_size The max tensor dimensions supported. + * @ingroup group_int_context + */ + vx_size maxTensorDims() const; + + /** + * @brief Get the unique kernel information + * + * @return std::vector The unique kernel information table. + * @ingroup group_int_context + */ + std::vector uniqueKernelTable(); + + /** + * @brief Get the OpenCL context + * + * @return cl_context The OpenCL context. + * @ingroup group_int_context + */ + cl_context clContext() const; + + /** + * @brief Get the OpenCL command queue + * + * @return cl_command_queue The OpenCL command queue. + * @ingroup group_int_context + */ + cl_command_queue clCommandQueue() const; + + /** + * @brief Set the logging enabled state + * + * @param flag vx_bool indicating whether to enable or disable logging + * @ingroup group_int_context + */ + void setLoggingEnabled(vx_bool flag); + + /** + * @brief Set the perf enabled state + * + * @param flag vx_bool indicating whether to enable or disable performance tracking + * @ingroup group_int_context + */ + void setPerfEnabled(vx_bool flag); + /*! \brief This determines if a context is valid. * \param [in] context The pointer to the context to test. * \retval vx_true_e The context is valid. @@ -105,12 +250,8 @@ class Context : public Reference * will allocate memory if needed. * \ingroup group_int_context */ - vx_bool addAccessor(vx_size size, - vx_enum usage, - void*& ptr, - vx_reference ref, - vx_uint32 *pIndex, - void *extra_data); + vx_bool addAccessor(vx_size size, vx_enum usage, void*& ptr, vx_reference ref, + vx_uint32* pIndex, void* extra_data); /*! \brief Finds and removes an accessor from the list. * \ingroup group_int_context @@ -173,21 +314,101 @@ class Context : public Reference /** * @brief Launch worker graph thread * - * @param arg - * @return vx_value_t + * @param arg Optional argument to pass as parameter. + * @return vx_value_t Thread return value. * @ingroup group_int_context */ static vx_value_t workerGraph(void *arg); /** - * @brief Launch worker node thread + * @brief Launch worker node * - * @param worker - * @return vx_bool + * @param worker The threadpool of the worker. + * @return vx_bool vx_true_e if ran successful, vx_false_e otherwise * @ingroup group_int_context */ static vx_bool workerNode(vx_threadpool_worker_t *worker); + /** + * @brief Register a user struct with a certain number of bytes + * + * @param size The size in bytes of the user struct. + * @return vx_enum The user struct enumeration. + * @ingroup group_int_context + */ + vx_enum registerUserStruct(vx_size size); + + /** + * @brief Get the User Struct By Name object + * + * @param name The user struct name. + * @return vx_enum The user struct enumeration. + * @ingroup group_int_context + */ + vx_enum getUserStructByName(const vx_char* name); + + /** + * @brief Get the User Struct Name By Enum object + * + * @param user_struct_type Enumeration for user struct type. + * @param type_name Name of user struct type. + * @param name_size Size of user struct name. + * @return vx_status VX_SUCCESS if successful, otherwise a return status with an error + * code. + * @ingroup group_int_context + */ + vx_status getUserStructNameByEnum(vx_enum user_struct_type, vx_char* type_name, + vx_size name_size); + + /** + * @brief Get the User Struct Enum By Name object + * + * @param type_name The user struct name. + * @param user_struct_type The user struct type enumeration. + * @return vx_status VX_SUCCESS if successful, otherwise a return status with an error + * code. + * @ingroup group_int_context + */ + vx_status getUserStructEnumByName(const vx_char* type_name, vx_enum* user_struct_type); + + /** + * @brief Register user struct with name + * + * @param size Size of user struct name. + * @param type_name The user struct name. + * @return vx_enum Enumeration of registered user struct + * @ingroup group_int_context + */ + vx_enum registerUserStructWithName(vx_size size, const vx_char* type_name); + + /** + * @brief Allocate a unique kernel id + * + * @param pKernelEnumId Pointer to allocated kernel id by the framework. + * @return vx_status VX_SUCCESS if successful, otherwise a return status with an error code. + * @ingroup group_int_context + */ + vx_status allocateKernelId(vx_enum* pKernelEnumId); + + /** + * @brief Allocate a unique library id + * + * @param pLibraryId Pointer to allocated library id by the framework. + * @return vx_status VX_SUCCESS if successful, otherwise a return status with an error code. + * @ingroup group_int_context + */ + vx_status allocateLibraryId(vx_enum* pLibraryId); + + /** + * @brief Set the Immediate Mode Target + * + * @param target_enum The target enumeration. + * @param target_string The target string. + * @return vx_status VX_SUCCESS if successful, otherwise a return status with an error code. + * @ingroup group_int_context + */ + vx_status setImmediateModeTarget(vx_enum target_enum, const char* target_string); + /*! \brief The pointer to process global lock */ vx_sem_t* p_global_lock; /*! \brief The reference table which contains the handle for later garage collection if needed */ @@ -274,6 +495,14 @@ class Context : public Reference vx_value_set_t graph_queue[VX_INT_MAX_QUEUE_DEPTH]; /*! \brief The number of graphs in the queue */ vx_size numGraphsQueued; + /*! \brief The vendor id */ + const vx_uint16 vendor_id; + /*! \brief The version number this implements */ + const vx_uint16 version_number; + /*! \brief The name of this impleemntation */ + const vx_char implementation[VX_MAX_IMPLEMENTATION_NAME]; + /*! \brief The name of additional extensions in this impleemntation */ + const vx_char* extension; }; #endif /* VX_CONTEXT_H */ diff --git a/framework/src/vx_context.cpp b/framework/src/vx_context.cpp index 92809e91..ef800690 100644 --- a/framework/src/vx_context.cpp +++ b/framework/src/vx_context.cpp @@ -20,8 +20,6 @@ #include "vx_internal.h" #include "vx_context.h" -const vx_char implementation[VX_MAX_IMPLEMENTATION_NAME] = "core.VX"; - vx_char targetModules[][VX_MAX_TARGET_NAME] = { #if defined(EXPERIMENTAL_USE_OPENCL) "openvx-opencl", @@ -35,21 +33,6 @@ vx_char targetModules[][VX_MAX_TARGET_NAME] = { "openvx-c_model", "openvx-onnxRT", "openvx-ai_server", "openvx-liteRT", "openvx-torch", }; -const vx_char extensions[] = -#if defined(OPENVX_USE_TILING) - OPENVX_KHR_TILING" " -#endif -#if defined(OPENVX_USE_XML) - OPENVX_KHR_XML" " -#endif -#if defined(OPENVX_USE_S16) - "vx_khr_s16 " -#endif -#if defined(EXPERIMENTAL_USE_DOT) - OPENVX_KHR_DOT" " -#endif - " "; - static std::shared_ptr single_context = nullptr; static vx_sem_t context_lock; static vx_sem_t global_lock; @@ -102,7 +85,24 @@ Context::Context() event_queue(), #endif graph_queue(), - numGraphsQueued(0ul) + numGraphsQueued(0ul), + vendor_id((vx_uint16)VX_ID_EDGE_AI), + version_number((vx_uint16)VX_VERSION), + implementation("core.VX"), + extension( +#if defined(OPENVX_USE_TILING) + OPENVX_KHR_TILING " " +#endif +#if defined(OPENVX_USE_XML) + OPENVX_KHR_XML " " +#endif +#if defined(OPENVX_USE_S16) + "vx_khr_s16 " +#endif +#if defined(EXPERIMENTAL_USE_DOT) + OPENVX_KHR_DOT " " +#endif + " ") { imm_border.mode = VX_BORDER_UNDEFINED; } @@ -123,6 +123,132 @@ Context::~Context() } } +vx_uint16 Context::vendorId() const +{ + return vendor_id; +} + +vx_uint16 Context::version() const +{ + return version_number; +} + +vx_uint32 Context::numModules() const +{ + return num_modules; +} + +vx_uint32 Context::numReferences() const +{ + return num_references; +} + +const vx_char *Context::implName() const +{ + return implementation; +} + +const vx_char* Context::extensions() const +{ + return extension; +} + +vx_size Context::convolutionMaxDim() const +{ + return VX_INT_MAX_CONVOLUTION_DIM; +} + +vx_size Context::nonLinearMaxDim() const +{ + return VX_INT_MAX_NONLINEAR_DIM; +} + +vx_size Context::opticalFlowMaxWindowDim() const +{ + return VX_OPTICALFLOWPYRLK_MAX_DIM; +} + +vx_border_t Context::immediateBorder() const +{ + return imm_border; +} + +vx_enum Context::immediateBorderPolicy() const +{ + return imm_border_policy; +} + +vx_uint32 Context::numUniqueKernels() const +{ + return num_unique_kernels; +} + +vx_size Context::maxTensorDims() const +{ + return VX_MAX_TENSOR_DIMENSIONS; +} + +std::vector Context::uniqueKernelTable() +{ + vx_uint32 k = 0u; + vx_uint32 t = 0u; + vx_uint32 k2 = 0u; + vx_uint32 numk = 0u; + std::vector table(VX_INT_MAX_KERNELS); + + for (t = 0; t < this->num_targets; t++) + { + for (k = 0u; k < VX_INT_MAX_KERNELS; k++) + { + vx_bool found = vx_false_e; + VX_PRINT(VX_ZONE_INFO, "Checking uniqueness of %s (%d)\n", + this->targets[t]->kernels[k]->name, this->targets[t]->kernels[k]->enumeration); + for (k2 = 0u; k2 < numk; k2++) + { + if (VX_KERNEL_INVALID < this->targets[t]->kernels[k]->enumeration && + VX_KERNEL_MAX_1_0 > this->targets[t]->kernels[k]->enumeration && + table[k2].enumeration == this->targets[t]->kernels[k]->enumeration) + { + found = vx_true_e; + break; + } + } + + if (VX_KERNEL_INVALID < this->targets[t]->kernels[k]->enumeration && + VX_KERNEL_MAX_1_0 > this->targets[t]->kernels[k]->enumeration && + found == vx_false_e) + { + VX_PRINT(VX_ZONE_INFO, "Kernel %s is unique\n", this->targets[t]->kernels[k]->name); + table[numk].enumeration = this->targets[t]->kernels[k]->enumeration; + strncpy(table[numk].name, this->targets[t]->kernels[k]->name, VX_MAX_KERNEL_NAME); + numk++; + } + } + } + + return table; +} + +cl_context Context::clContext() const +{ + return opencl_context; +} + +cl_command_queue Context::clCommandQueue() const +{ + return opencl_command_queue; +} + +void Context::setLoggingEnabled(vx_bool flag) +{ + log_enabled = flag; +} + +void Context::setPerfEnabled(vx_bool flag) +{ + perf_enabled = flag; +} + vx_bool Context::isValidContext(vx_context context) { vx_bool ret = vx_false_e; @@ -715,6 +841,206 @@ vx_target* Context::findTargetByString(const char* target_string) return target; } +vx_enum Context::registerUserStruct(vx_size size) +{ + vx_enum type = VX_TYPE_INVALID; + vx_uint32 i = 0; + + if (size != 0) + { + for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) + { + if (user_structs[i].type == VX_TYPE_INVALID) + { + user_structs[i].type = VX_TYPE_USER_STRUCT_START + i; + user_structs[i].size = size; + user_structs[i].name[0] = 0; + type = user_structs[i].type; + break; + } + } + } + + return type; +} + +vx_enum Context::getUserStructByName(const vx_char *name) +{ + vx_enum type = VX_TYPE_INVALID; + vx_uint32 i = 0; + vx_size len = strlen(name); + + if (VX_MAX_STRUCT_NAME < len) + { + len = VX_MAX_STRUCT_NAME; + } + + if (len != 0) + { + for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) + { + if ((VX_TYPE_INVALID != user_structs[i].type) && + (0 == strncmp(user_structs[i].name, name, len))) + { + type = user_structs[i].type; + break; + } + } + } + + return type; +} + +vx_status Context::getUserStructNameByEnum(vx_enum user_struct_type, vx_char *type_name, + vx_size name_size) +{ + vx_status status = VX_ERROR_INVALID_PARAMETERS; + vx_uint32 i = 0; + + if (user_struct_type != VX_TYPE_INVALID) + { + for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) + { + if (user_struct_type == user_structs[i].type) + { + break; + } + } + + if (i == VX_INT_MAX_USER_STRUCTS) + { + status = VX_FAILURE; + } + else + { + if (name_size < (strlen(user_structs[i].name) + 1)) + { + status = VX_ERROR_NO_MEMORY; + } + else + { + memcpy(type_name, user_structs[i].name, strlen(user_structs[i].name) + 1); + status = VX_SUCCESS; + } + } + } + + return status; +} + +vx_status Context::getUserStructEnumByName(const vx_char *type_name, vx_enum *user_struct_type) +{ + vx_status status = VX_FAILURE; + vx_uint32 i = 0; + vx_size len = 0; + + if (nullptr != type_name) + { + len = strlen(type_name); + if (VX_MAX_REFERENCE_NAME < len) + { + len = VX_MAX_REFERENCE_NAME; + } + } + if (len != 0) + { + for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) + { + if ((VX_TYPE_INVALID != user_structs[i].type) && + (0 == strncmp(user_structs[i].name, type_name, len))) + { + *user_struct_type = user_structs[i].type; + status = VX_SUCCESS; + break; + } + } + } + + return status; +} + +vx_enum Context::registerUserStructWithName(vx_size size, const vx_char *type_name) +{ + vx_enum type = VX_TYPE_INVALID; + vx_uint32 i = 0; + + if ((size != 0) && VX_TYPE_INVALID == getUserStructByName(type_name)) + { + for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) + { + if (user_structs[i].type == VX_TYPE_INVALID) + { + user_structs[i].type = VX_TYPE_USER_STRUCT_START + i; + user_structs[i].size = size; + strncpy(user_structs[i].name, type_name, VX_MAX_REFERENCE_NAME - 1); + type = user_structs[i].type; + break; + } + } + } + + return type; +} + +vx_status Context::allocateKernelId(vx_enum *pKernelEnumId) +{ + vx_status status = VX_ERROR_NO_RESOURCES; + if (next_dynamic_user_kernel_id <= VX_KERNEL_MASK) + { + *pKernelEnumId = VX_KERNEL_BASE(VX_ID_USER, 0) + next_dynamic_user_kernel_id++; + status = VX_SUCCESS; + } + return status; +} + +vx_status Context::allocateLibraryId(vx_enum *pLibraryId) +{ + vx_status status = VX_ERROR_NO_RESOURCES; + if (next_dynamic_user_library_id <= VX_LIBRARY(VX_LIBRARY_MASK)) + { + *pLibraryId = next_dynamic_user_library_id++; + status = VX_SUCCESS; + } + return status; +} + +vx_status Context::setImmediateModeTarget(vx_enum target_enum, const char *target_string) +{ + vx_status status = VX_FAILURE; + vx_target *target = nullptr; + + switch (target_enum) + { + case VX_TARGET_ANY: + context->imm_target_enum = VX_TARGET_ANY; + memset(context->imm_target_string, 0, sizeof(context->imm_target_string)); + status = VX_SUCCESS; + break; + + case VX_TARGET_STRING: + target = context->findTargetByString(target_string); + if (target != nullptr) /* target was found */ + { + context->imm_target_enum = VX_TARGET_STRING; + strncpy(context->imm_target_string, target_string, + sizeof(context->imm_target_string)); + context->imm_target_string[sizeof(context->imm_target_string) - 1] = '\0'; + status = VX_SUCCESS; + } + else /* target was not found */ + { + status = VX_ERROR_NOT_SUPPORTED; + } + break; + + default: + status = VX_ERROR_NOT_SUPPORTED; + break; + } + + return status; +} + /******************************************************************************/ /* PUBLIC API */ /******************************************************************************/ @@ -862,159 +1188,26 @@ VX_API_ENTRY vx_context VX_API_CALL vxCreateContext(void) return context; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseContext(vx_context* c) +#ifdef OPENVX_USE_OPENCL_INTEROP +VX_API_ENTRY vx_context VX_API_CALL vxCreateContextFromCL(cl_context opencl_context, + cl_command_queue opencl_command_queue) { - vx_status status = VX_SUCCESS; - vx_context context = (c?*c:0); - vx_uint32 r,m,a; - vx_uint32 t; - - if (c) *c = 0; - Osal::semWait(&context_lock); - if (Context::isValidContext(context) == vx_true_e) + vx_context context = vxCreateContext(); + if (vxGetStatus((vx_reference)context) == VX_SUCCESS) { - if (context->decrementReference(VX_EXTERNAL) == 0) + cl_int err1 = clRetainContext(opencl_context); + cl_int err2 = clRetainCommandQueue(opencl_command_queue); + if ((err1 != CL_SUCCESS) || (err2 != CL_SUCCESS)) { -#ifdef OPENVX_USE_OPENCL_INTEROP - if(context->opencl_command_queue) - { - clReleaseCommandQueue(context->opencl_command_queue); - context->opencl_command_queue = nullptr; - } - if(context->opencl_context) - { - clReleaseContext(context->opencl_context); - context->opencl_context = nullptr; - } -#endif - Osal::destroyThreadpool(&context->workers); - context->proc.running = vx_false_e; - Osal::popQueue(&context->proc.input); - Osal::joinThread(context->proc.thread, nullptr); - Osal::deinitQueue(&context->proc.output); - Osal::deinitQueue(&context->proc.input); - - /* Deregister any log callbacks if there is any registered */ - vxRegisterLogCallback(context, nullptr, vx_false_e); - - /*! \internal Garbage Collect All References */ - /* Details: - * 1. This loop will warn of references which have not been released by the user. - * 2. It will close all internally opened error references. - * 3. It will close the external references, which in turn will internally - * close any internally dependent references that they reference, assuming the - * reference counting has been done properly in the framework. - * 4. This garbage collection must be done before the targets are released since some of - * these external references may have internal references to target kernels. - */ - for (r = 0; r < VX_INT_MAX_REF; r++) - { - vx_reference ref = context->reftable[r]; - - /* Warnings should only come when users have not released all external references */ - if (ref && ref->external_count > 0) - { - VX_PRINT(VX_ZONE_WARNING,"Stale reference " VX_FMT_REF " of type %s at external count %u, internal count %u\n", - ref, vxGetObjectTypeName(ref->type), ref->external_count, ref->internal_count); - } - - /* These were internally opened during creation, so should internally close ERRORs */ - if (ref && ref->type == VX_TYPE_ERROR) - { - Reference::releaseReference(&ref, ref->type, VX_INTERNAL, nullptr); - } - - /* Warning above so user can fix release external objects, but close here anyway */ - while (ref && ref->external_count > 1) - { - ref->decrementReference(VX_EXTERNAL); - } - if (ref && ref->external_count > 0) - { - Reference::releaseReference(&ref, ref->type, VX_EXTERNAL, nullptr); - } - } - - for (m = 0; m < VX_INT_MAX_MODULES; m++) - { - Osal::semWait(&context->modules[m].lock); - if (context->modules[m].handle) - { - Osal::unloadModule(context->modules[m].handle); - memset(context->modules[m].name, 0, sizeof(context->modules[m].name)); - context->modules[m].handle = VX_MODULE_INIT; - } - Osal::semPost(&context->modules[m].lock); - Osal::destroySem(&context->modules[m].lock); - } - - /* de-initialize and unload each target */ - for (t = 0u; t < context->num_targets; t++) - { - /* if (context->targets[t]->enabled == vx_true_e) */ - { - context->targets[t]->funcs.deinit(context->targets[t]); - context->targets[t]->enabled = vx_false_e; - context->unloadTarget(t, vx_true_e); - } - } - - /* Remove all outstanding accessors. */ - for (a = 0; a < dimof(context->accessors); ++a) - { - if (context->accessors[a].used) - { - context->removeAccessor(a); - } - } - - /* Check for outstanding mappings */ - for (a = 0; a < dimof(context->memory_maps); ++a) - { - if (context->memory_maps[a].used) - { - VX_PRINT(VX_ZONE_ERROR, "Memory map %d not unmapped\n", a); - context->memoryUnmap(a); - } - } - - Osal::destroySem(&context->memory_maps_lock); - - /* By now, all external and internal references should be removed */ - for (r = 0; r < VX_INT_MAX_REF; r++) - { - if (context->reftable[r]) - { - VX_PRINT(VX_ZONE_ERROR, "Reference %p, type %x not removed [%d:%d]\n", - context->reftable[r], context->reftable[r]->type, - context->reftable[r]->internal_count, context->reftable[r]->external_count); - } - } - - /*! \internal wipe away the context memory first */ - /* Normally destroy sem is part of release reference, but can't for context */ - Osal::destroySem(&context->lock); - Osal::destroySem(&global_lock); - Osal::semPost(&context_lock); - Osal::destroySem(&context_lock); - single_context.reset(); - single_context = nullptr; - - return status; - } - else - { - VX_PRINT(VX_ZONE_WARNING, "Context still has %u holders\n", context->totalReferenceCount()); + vxReleaseContext(&context); + return nullptr; } + context->opencl_context = opencl_context; + context->opencl_command_queue = opencl_command_queue; } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } - Osal::semPost(&context_lock); - - return status; + return context; } +#endif /* OPENVX_USE_OPENCL_INTEROP */ VX_API_ENTRY vx_context VX_API_CALL vxGetContext(vx_reference reference) { @@ -1087,7 +1280,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_VENDOR_ID: if (VX_CHECK_PARAM(ptr, size, vx_uint16, 0x1)) { - *(vx_uint16 *)ptr = VX_ID_KHRONOS; + *(vx_uint16 *)ptr = context->vendorId(); } else { @@ -1097,7 +1290,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_VERSION: if (VX_CHECK_PARAM(ptr, size, vx_uint16, 0x1)) { - *(vx_uint16 *)ptr = (vx_uint16)VX_VERSION; + *(vx_uint16 *)ptr = context->version(); } else { @@ -1107,7 +1300,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_MODULES: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = context->num_modules; + *(vx_uint32 *)ptr = context->numModules(); } else { @@ -1117,7 +1310,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_REFERENCES: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = context->num_references; + *(vx_uint32 *)ptr = context->numReferences(); } else { @@ -1127,7 +1320,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_IMPLEMENTATION: if (size <= VX_MAX_IMPLEMENTATION_NAME && ptr) { - strncpy(reinterpret_cast(ptr), implementation, VX_MAX_IMPLEMENTATION_NAME); + strncpy(reinterpret_cast(ptr), context->implName(), + VX_MAX_IMPLEMENTATION_NAME); } else { @@ -1137,7 +1331,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_EXTENSIONS_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = sizeof(extensions); + *(vx_size *)ptr = strlen(context->extensions()); } else { @@ -1145,9 +1339,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at } break; case VX_CONTEXT_EXTENSIONS: - if (size <= sizeof(extensions) && ptr) + if (size <= strlen(context->extensions()) && ptr) { - strncpy(reinterpret_cast(ptr), extensions, size); + strncpy(reinterpret_cast(ptr), context->extensions(), size); } else { @@ -1157,7 +1351,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_CONVOLUTION_MAX_DIMENSION: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = VX_INT_MAX_CONVOLUTION_DIM; + *(vx_size *)ptr = context->convolutionMaxDim(); } else { @@ -1167,7 +1361,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_NONLINEAR_MAX_DIMENSION: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = VX_INT_MAX_NONLINEAR_DIM; + *(vx_size *)ptr = context->nonLinearMaxDim(); } else { @@ -1177,7 +1371,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_OPTICAL_FLOW_MAX_WINDOW_DIMENSION: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = VX_OPTICALFLOWPYRLK_MAX_DIM; + *(vx_size *)ptr = context->opticalFlowMaxWindowDim(); } else { @@ -1187,7 +1381,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_IMMEDIATE_BORDER: if (VX_CHECK_PARAM(ptr, size, vx_border_t, 0x3)) { - *(vx_border_t *)ptr = context->imm_border; + *(vx_border_t *)ptr = context->immediateBorder(); } else { @@ -1197,7 +1391,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_IMMEDIATE_BORDER_POLICY: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = context->imm_border_policy; + *(vx_enum *)ptr = context->immediateBorderPolicy(); } else { @@ -1207,7 +1401,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_UNIQUE_KERNELS: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = context->num_unique_kernels; + *(vx_uint32 *)ptr = context->numUniqueKernels(); } else { @@ -1217,7 +1411,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_MAX_TENSOR_DIMS: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = VX_MAX_TENSOR_DIMENSIONS; + *(vx_size *)ptr = context->maxTensorDims(); } else { @@ -1228,41 +1422,11 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at if ((size == (context->num_unique_kernels * sizeof(vx_kernel_info_t))) && (ptr != nullptr)) { - vx_uint32 k = 0u; - vx_uint32 t = 0u; - vx_uint32 k2 = 0u; - vx_uint32 numk = 0u; - vx_kernel_info_t* table = (vx_kernel_info_t*)ptr; - - for (t = 0; t < context->num_targets; t++) - { - for (k = 0u; k < VX_INT_MAX_KERNELS; k++) - { - vx_bool found = vx_false_e; - VX_PRINT(VX_ZONE_INFO, "Checking uniqueness of %s (%d)\n", context->targets[t]->kernels[k]->name, context->targets[t]->kernels[k]->enumeration); - for (k2 = 0u; k2 < numk; k2++) - { - if (VX_KERNEL_INVALID < context->targets[t]->kernels[k]->enumeration && - VX_KERNEL_MAX_1_0 > context->targets[t]->kernels[k]->enumeration && - table[k2].enumeration == context->targets[t]->kernels[k]->enumeration) - { - found = vx_true_e; - break; - } - } - - if (VX_KERNEL_INVALID < context->targets[t]->kernels[k]->enumeration && - VX_KERNEL_MAX_1_0 > context->targets[t]->kernels[k]->enumeration && - found == vx_false_e) - { - VX_PRINT(VX_ZONE_INFO, "Kernel %s is unique\n", context->targets[t]->kernels[k]->name); - table[numk].enumeration = context->targets[t]->kernels[k]->enumeration; - strncpy(table[numk].name, context->targets[t]->kernels[k]->name, VX_MAX_KERNEL_NAME); - numk++; - } - } - } - } else { + std::vector table = context->uniqueKernelTable(); + memcpy((vx_kernel_info_t *)ptr, table.data(), size); + } + else + { status = VX_ERROR_INVALID_PARAMETERS; } break; @@ -1270,7 +1434,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_CL_CONTEXT: if (VX_CHECK_PARAM(ptr, size, cl_context, 0x3)) { - *(cl_context *)ptr = context->opencl_context; + *(cl_context *)ptr = context->clContext(); } else { @@ -1280,7 +1444,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryContext(vx_context context, vx_enum at case VX_CONTEXT_CL_COMMAND_QUEUE: if (VX_CHECK_PARAM(ptr, size, cl_command_queue, 0x3)) { - *(cl_command_queue *)ptr = context->opencl_command_queue; + *(cl_command_queue *)ptr = context->clCommandQueue(); } else { @@ -1348,15 +1512,15 @@ VX_API_ENTRY vx_status VX_API_CALL vxDirective(vx_reference reference, vx_enum d switch (directive) { case VX_DIRECTIVE_DISABLE_LOGGING: - context->log_enabled = vx_false_e; + context->setLoggingEnabled(vx_false_e); break; case VX_DIRECTIVE_ENABLE_LOGGING: - context->log_enabled = vx_true_e; + context->setLoggingEnabled(vx_true_e); break; case VX_DIRECTIVE_DISABLE_PERFORMANCE: if (ref_type == VX_TYPE_CONTEXT) { - context->perf_enabled = vx_false_e; + context->setPerfEnabled(vx_false_e); } else { @@ -1366,7 +1530,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxDirective(vx_reference reference, vx_enum d case VX_DIRECTIVE_ENABLE_PERFORMANCE: if (ref_type == VX_TYPE_CONTEXT) { - context->perf_enabled = vx_true_e; + context->setPerfEnabled(vx_true_e); } else { @@ -1384,22 +1548,10 @@ VX_API_ENTRY vx_status VX_API_CALL vxDirective(vx_reference reference, vx_enum d VX_API_ENTRY vx_enum VX_API_CALL vxRegisterUserStruct(vx_context context, vx_size size) { vx_enum type = VX_TYPE_INVALID; - vx_uint32 i = 0; - if ((Context::isValidContext(context) == vx_true_e) && - (size != 0)) + if (Context::isValidContext(context) == vx_true_e) { - for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) - { - if (context->user_structs[i].type == VX_TYPE_INVALID) - { - context->user_structs[i].type = VX_TYPE_USER_STRUCT_START + i; - context->user_structs[i].size = size; - context->user_structs[i].name[0] = 0; - type = context->user_structs[i].type; - break; - } - } + type = context->registerUserStruct(size); } return type; @@ -1408,26 +1560,10 @@ VX_API_ENTRY vx_enum VX_API_CALL vxRegisterUserStruct(vx_context context, vx_siz VX_API_ENTRY vx_enum VX_API_CALL vxGetUserStructByName(vx_context context, const vx_char *name) { vx_enum type = VX_TYPE_INVALID; - vx_uint32 i = 0; - vx_size len = strlen(name); - if (VX_MAX_STRUCT_NAME < len) + if (Context::isValidContext(context) == vx_true_e) { - len = VX_MAX_STRUCT_NAME; - } - - if ((Context::isValidContext(context) == vx_true_e) && - (len != 0)) - { - for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) - { - if ((VX_TYPE_INVALID != context->user_structs[i].type) && - (0 == strncmp(context->user_structs[i].name, name, len))) - { - type = context->user_structs[i].type; - break; - } - } + type = context->getUserStructByName(name); } return type; @@ -1436,35 +1572,10 @@ VX_API_ENTRY vx_enum VX_API_CALL vxGetUserStructByName(vx_context context, const VX_API_ENTRY vx_status VX_API_CALL vxGetUserStructNameByEnum(vx_context context, vx_enum user_struct_type, vx_char* type_name, vx_size name_size) { vx_status status = VX_ERROR_INVALID_PARAMETERS; - vx_uint32 i = 0; - if ((Context::isValidContext(context) == vx_true_e) && (user_struct_type != VX_TYPE_INVALID)) + if (Context::isValidContext(context) == vx_true_e) { - for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) - { - if (user_struct_type == context->user_structs[i].type) - { - break; - } - } - - if (i == VX_INT_MAX_USER_STRUCTS) - { - status = VX_FAILURE; - } - else - { - if (name_size < (strlen(context->user_structs[i].name) + 1)) - { - status = VX_ERROR_NO_MEMORY; - } - else - { - memcpy(type_name, context->user_structs[i].name, - strlen(context->user_structs[i].name) + 1); - status = VX_SUCCESS; - } - } + status = context->getUserStructNameByEnum(user_struct_type, type_name, name_size); } return status; @@ -1472,30 +1583,11 @@ VX_API_ENTRY vx_status VX_API_CALL vxGetUserStructNameByEnum(vx_context context, VX_API_ENTRY vx_status VX_API_CALL vxGetUserStructEnumByName(vx_context context, const vx_char* type_name, vx_enum *user_struct_type) { - vx_status status = VX_FAILURE; - vx_uint32 i = 0; - vx_size len = 0; + vx_status status = VX_ERROR_INVALID_REFERENCE; - if (nullptr != type_name) - { - len = strlen(type_name); - if (VX_MAX_REFERENCE_NAME < len) - { - len = VX_MAX_REFERENCE_NAME; - } - } - if ((Context::isValidContext(context) == vx_true_e) && (len != 0)) + if (Context::isValidContext(context) == vx_true_e) { - for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) - { - if ((VX_TYPE_INVALID != context->user_structs[i].type) && - (0 == strncmp(context->user_structs[i].name, type_name, len))) - { - *user_struct_type = context->user_structs[i].type; - status = VX_SUCCESS; - break; - } - } + status = context->getUserStructEnumByName(type_name, user_struct_type); } return status; @@ -1504,23 +1596,10 @@ VX_API_ENTRY vx_status VX_API_CALL vxGetUserStructEnumByName(vx_context context, VX_API_ENTRY vx_enum VX_API_CALL vxRegisterUserStructWithName(vx_context context, vx_size size, const vx_char *type_name) { vx_enum type = VX_TYPE_INVALID; - vx_uint32 i = 0; - if ((Context::isValidContext(context) == vx_true_e) && - (size != 0) && - VX_TYPE_INVALID == vxGetUserStructByName(context, type_name)) + if (Context::isValidContext(context) == vx_true_e) { - for (i = 0; i < VX_INT_MAX_USER_STRUCTS; ++i) - { - if (context->user_structs[i].type == VX_TYPE_INVALID) - { - context->user_structs[i].type = VX_TYPE_USER_STRUCT_START + i; - context->user_structs[i].size = size; - strncpy(context->user_structs[i].name, type_name, VX_MAX_REFERENCE_NAME - 1); - type = context->user_structs[i].type; - break; - } - } + type = context->registerUserStructWithName(size, type_name); } return type; @@ -1531,12 +1610,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAllocateUserKernelId(vx_context context, vx vx_status status = VX_ERROR_INVALID_REFERENCE; if ((Context::isValidContext(context) == vx_true_e) && pKernelEnumId) { - status = VX_ERROR_NO_RESOURCES; - if(context->next_dynamic_user_kernel_id <= VX_KERNEL_MASK) - { - *pKernelEnumId = VX_KERNEL_BASE(VX_ID_USER,0) + context->next_dynamic_user_kernel_id++; - status = VX_SUCCESS; - } + status = context->allocateKernelId(pKernelEnumId); } return status; } @@ -1546,12 +1620,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAllocateUserKernelLibraryId(vx_context cont vx_status status = VX_ERROR_INVALID_REFERENCE; if ((Context::isValidContext(context) == vx_true_e) && pLibraryId) { - status = VX_ERROR_NO_RESOURCES; - if(context->next_dynamic_user_library_id <= VX_LIBRARY(VX_LIBRARY_MASK)) - { - *pLibraryId = context->next_dynamic_user_library_id++; - status = VX_SUCCESS; - } + status = context->allocateLibraryId(pLibraryId); } return status; } @@ -1562,54 +1631,168 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetImmediateModeTarget(vx_context context, if (Context::isValidContext(context) == vx_true_e) { - vx_target* target = nullptr; - switch (target_enum) + status = context->setImmediateModeTarget(target_enum, target_string); + } + + return status; +} + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseContext(vx_context *c) +{ + vx_status status = VX_SUCCESS; + vx_context context = (c ? *c : 0); + vx_uint32 r, m, a; + vx_uint32 t; + + if (c) *c = 0; + Osal::semWait(&context_lock); + if (Context::isValidContext(context) == vx_true_e) + { + if (context->decrementReference(VX_EXTERNAL) == 0) { - case VX_TARGET_ANY: - context->imm_target_enum = VX_TARGET_ANY; - memset(context->imm_target_string, 0, sizeof(context->imm_target_string)); - status = VX_SUCCESS; - break; +#ifdef OPENVX_USE_OPENCL_INTEROP + if (context->opencl_command_queue) + { + clReleaseCommandQueue(context->opencl_command_queue); + context->opencl_command_queue = nullptr; + } + if (context->opencl_context) + { + clReleaseContext(context->opencl_context); + context->opencl_context = nullptr; + } +#endif + Osal::destroyThreadpool(&context->workers); + context->proc.running = vx_false_e; + Osal::popQueue(&context->proc.input); + Osal::joinThread(context->proc.thread, nullptr); + Osal::deinitQueue(&context->proc.output); + Osal::deinitQueue(&context->proc.input); - case VX_TARGET_STRING: - target = context->findTargetByString(target_string); - if (target != nullptr) /* target was found */ + /* Deregister any log callbacks if there is any registered */ + vxRegisterLogCallback(context, nullptr, vx_false_e); + + /*! \internal Garbage Collect All References */ + /* Details: + * 1. This loop will warn of references which have not been released by the user. + * 2. It will close all internally opened error references. + * 3. It will close the external references, which in turn will internally + * close any internally dependent references that they reference, assuming the + * reference counting has been done properly in the framework. + * 4. This garbage collection must be done before the targets are released since some + * of these external references may have internal references to target kernels. + */ + for (r = 0; r < VX_INT_MAX_REF; r++) + { + vx_reference ref = context->reftable[r]; + + /* Warnings should only come when users have not released all external references */ + if (ref && ref->external_count > 0) { - context->imm_target_enum = VX_TARGET_STRING; - strncpy(context->imm_target_string, target_string, sizeof(context->imm_target_string)); - context->imm_target_string[sizeof(context->imm_target_string) - 1] = '\0'; - status = VX_SUCCESS; + VX_PRINT(VX_ZONE_WARNING, + "Stale reference " VX_FMT_REF + " of type %s at external count %u, internal count %u\n", + ref, vxGetObjectTypeName(ref->type), ref->external_count, + ref->internal_count); } - else /* target was not found */ + + /* These were internally opened during creation, so should internally close ERRORs + */ + if (ref && ref->type == VX_TYPE_ERROR) { - status = VX_ERROR_NOT_SUPPORTED; + Reference::releaseReference(&ref, ref->type, VX_INTERNAL, nullptr); } - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; - } - } - return status; -} + /* Warning above so user can fix release external objects, but close here anyway */ + while (ref && ref->external_count > 1) + { + ref->decrementReference(VX_EXTERNAL); + } + if (ref && ref->external_count > 0) + { + Reference::releaseReference(&ref, ref->type, VX_EXTERNAL, nullptr); + } + } -#ifdef OPENVX_USE_OPENCL_INTEROP -VX_API_ENTRY vx_context VX_API_CALL vxCreateContextFromCL(cl_context opencl_context, cl_command_queue opencl_command_queue) -{ - vx_context context = vxCreateContext(); - if(vxGetStatus((vx_reference)context) == VX_SUCCESS) - { - cl_int err1 = clRetainContext(opencl_context); - cl_int err2 = clRetainCommandQueue(opencl_command_queue); - if((err1 != CL_SUCCESS) || (err2 != CL_SUCCESS)) + for (m = 0; m < VX_INT_MAX_MODULES; m++) + { + Osal::semWait(&context->modules[m].lock); + if (context->modules[m].handle) + { + Osal::unloadModule(context->modules[m].handle); + memset(context->modules[m].name, 0, sizeof(context->modules[m].name)); + context->modules[m].handle = VX_MODULE_INIT; + } + Osal::semPost(&context->modules[m].lock); + Osal::destroySem(&context->modules[m].lock); + } + + /* de-initialize and unload each target */ + for (t = 0u; t < context->num_targets; t++) + { + /* if (context->targets[t]->enabled == vx_true_e) */ + { + context->targets[t]->funcs.deinit(context->targets[t]); + context->targets[t]->enabled = vx_false_e; + context->unloadTarget(t, vx_true_e); + } + } + + /* Remove all outstanding accessors. */ + for (a = 0; a < dimof(context->accessors); ++a) + { + if (context->accessors[a].used) + { + context->removeAccessor(a); + } + } + + /* Check for outstanding mappings */ + for (a = 0; a < dimof(context->memory_maps); ++a) + { + if (context->memory_maps[a].used) + { + VX_PRINT(VX_ZONE_ERROR, "Memory map %d not unmapped\n", a); + context->memoryUnmap(a); + } + } + + Osal::destroySem(&context->memory_maps_lock); + + /* By now, all external and internal references should be removed */ + for (r = 0; r < VX_INT_MAX_REF; r++) + { + if (context->reftable[r]) + { + VX_PRINT(VX_ZONE_ERROR, "Reference %p, type %x not removed [%d:%d]\n", + context->reftable[r], context->reftable[r]->type, + context->reftable[r]->internal_count, + context->reftable[r]->external_count); + } + } + + /*! \internal wipe away the context memory first */ + /* Normally destroy sem is part of release reference, but can't for context */ + Osal::destroySem(&context->lock); + Osal::destroySem(&global_lock); + Osal::semPost(&context_lock); + Osal::destroySem(&context_lock); + single_context.reset(); + single_context = nullptr; + + return status; + } + else { - vxReleaseContext(&context); - return nullptr; + VX_PRINT(VX_ZONE_WARNING, "Context still has %u holders\n", + context->totalReferenceCount()); } - context->opencl_context = opencl_context; - context->opencl_command_queue = opencl_command_queue; } - return context; + else + { + status = VX_ERROR_INVALID_REFERENCE; + } + Osal::semPost(&context_lock); + + return status; } -#endif From e1073cfbf75c5887ce2487e1761d38db619566a8 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 30 Jul 2025 11:54:43 -0700 Subject: [PATCH 23/34] Reworked delay --- framework/include/vx_delay.h | 58 +++++++ framework/src/vx_delay.cpp | 289 +++++++++++++++++++---------------- 2 files changed, 219 insertions(+), 128 deletions(-) diff --git a/framework/include/vx_delay.h b/framework/include/vx_delay.h index ba3ad5d7..0a7281d5 100644 --- a/framework/include/vx_delay.h +++ b/framework/include/vx_delay.h @@ -44,6 +44,31 @@ class Delay : public Reference */ ~Delay(); + /** + * @brief Get data type of references associated with this delay object + * + * @return vx_enum The data type of references. + * @ingroup group_int_delay + */ + vx_enum dataType() const; + + /** + * @brief Get the number of objects in this delay object + * + * @return vx_size The number of objects in this delay object + * @ingroup group_int_delay + */ + vx_size numObjects() const; + + /** + * @brief Retrieves a reference to a delay slot object. + * + * @param [in] index The index of the delay slot from which to extract the object reference. + * @return vx_reference The vx_reference at the index specified if found, otherwise an error object + * @ingroup group_int_delay + */ + vx_reference getReference(vx_int32 index); + /*! \brief Removes an association to a node from a delay slot object reference. * \param [in] value The delay slot object reference. * \param [in] n The node reference. @@ -60,6 +85,39 @@ class Delay : public Reference */ static vx_bool addAssociationToDelay(vx_reference value, vx_node n, vx_uint32 i); + /** + * @brief Shifts the internal delay ring by one. + * + * This function performs a shift of the internal delay ring by one. This means that, + * the data originally at index 0 move to index -1 and so forth until index + * \f$ -count+1 \f$. The data originally at index \f$ -count+1 \f$ move to index 0. + * Here \f$ count \f$ is the number of slots in delay ring. + * When a delay is aged, any graph making use of this delay (delay object itself or data + * objects in delay slots) gets its data automatically updated accordingly. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_delay + */ + vx_status age(); + + /** + * @brief Register a delay for auto-aging. + * + * This function registers a delay object to be auto-aged by the graph. + * This delay object will be automatically aged after each successful completion of + * this graph. Aging of a delay object cannot be called during graph execution. + * A graph abandoned due to a node callback will trigger an auto-aging. + * + * If a delay is registered for auto-aging multiple times in a same graph, + * the delay will be only aged a single time at each graph completion. + * If a delay is registered for auto-aging in multiple graphs, this delay will + * aged automatically after each successful completion of any of these graphs. + * + * @param [in] graph The graph to which the delay is registered for auto-aging. + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + */ + vx_status registerAutoAging(vx_graph graph); + /** * @brief Destruct function for delay objects * @ingroup group_int_delay diff --git a/framework/src/vx_delay.cpp b/framework/src/vx_delay.cpp index ea4154f8..9ac6f0d4 100644 --- a/framework/src/vx_delay.cpp +++ b/framework/src/vx_delay.cpp @@ -37,6 +37,37 @@ Delay::~Delay() { } +vx_enum Delay::dataType() const +{ + return type; +} + +vx_size Delay::numObjects() const +{ + return count; +} + +vx_reference Delay::getReference(vx_int32 index) +{ + vx_reference ref = nullptr; + + if ((vx_uint32)abs(index) < this->count) + { + vx_int32 i = (this->index + abs(index)) % (vx_int32)this->count; + ref = this->refs[i]; + VX_PRINT(VX_ZONE_DELAY, "Retrieving relative index %d => " VX_FMT_REF " from Delay (%d)\n", + index, ref, i); + } + else + { + vxAddLogEntry((vx_reference)this, VX_ERROR_INVALID_PARAMETERS, + "Failed to retrieve reference from delay by index %d\n", index); + ref = (vx_reference)vxGetErrorObject(this->context, VX_ERROR_INVALID_PARAMETERS); + } + + return ref; +} + vx_bool Delay::addAssociationToDelay(vx_reference value, vx_node n, vx_uint32 i) { @@ -129,6 +160,82 @@ vx_bool Delay::removeAssociationToDelay(vx_reference value, vx_node n, vx_uint32 return vx_true_e; } +vx_status Delay::age() +{ + vx_status status = VX_SUCCESS; + vx_int32 i, j; + + /* increment the index */ + this->index = (this->index + (vx_uint32)this->count - 1) % (vx_uint32)this->count; + + VX_PRINT(VX_ZONE_DELAY, "Delay has shifted by 1, base index is now %d\n", this->index); + + /* then reassign the parameters */ + for (i = 0; i < (vx_int32)this->count; i++) + { + vx_delay_param_t *param = nullptr; + + j = (this->index + i) % (vx_int32)this->count; + param = &this->set[i]; + do + { + if (param->node != 0) + { + param->node->setParameter(param->index, this->refs[j]); + } + param = param->next; + } while (param != nullptr); + } + + if (this->type == VX_TYPE_PYRAMID && this->pyr != nullptr) + { + /* age pyramid levels */ + vx_int32 numLevels = (vx_int32)(((vx_pyramid)this->refs[0])->numLevels); + for (i = 0; i < numLevels; ++i) status |= this->pyr[i]->age(); + } + + return status; +} + +vx_status Delay::registerAutoAging(vx_graph graph) +{ + vx_uint32 i; + vx_status status = VX_SUCCESS; + vx_bool isAlreadyRegistered = vx_false_e; + vx_bool isRegisteredDelaysListFull = vx_true_e; + + if (vxIsValidGraph(graph) == vx_false_e) return VX_ERROR_INVALID_REFERENCE; + + /* check if this particular delay is already registered in the graph */ + for (i = 0; i < VX_INT_MAX_REF; i++) + { + if (graph->delays[i] && vxIsValidDelay(graph->delays[i]) && graph->delays[i] == this) + { + isAlreadyRegistered = vx_true_e; + break; + } + } + + /* if not regisered yet, find the first empty slot and register delay */ + if (isAlreadyRegistered == vx_false_e) + { + for (i = 0; i < VX_INT_MAX_REF; i++) + { + if (vxIsValidDelay(graph->delays[i]) == vx_false_e) + { + isRegisteredDelaysListFull = vx_false_e; + graph->delays[i] = this; + break; + } + } + + /* report error if there is no empty slots to register delay */ + if (isRegisteredDelaysListFull == vx_true_e) status = VX_ERROR_INVALID_REFERENCE; + } + + return status; +} + void Delay::destruct() { vx_uint32 i = 0; @@ -181,75 +288,6 @@ void Delay::destruct() /* PUBLIC INTERFACE */ /******************************************************************************/ -VX_API_ENTRY vx_reference VX_API_CALL vxGetReferenceFromDelay(vx_delay delay, vx_int32 index) -{ - vx_reference ref = nullptr; - - if (vxIsValidDelay(delay) == vx_true_e) - { - if ((vx_uint32)abs(index) < delay->count) - { - vx_int32 i = (delay->index + abs(index)) % (vx_int32)delay->count; - ref = delay->refs[i]; - VX_PRINT(VX_ZONE_DELAY, "Retrieving relative index %d => " VX_FMT_REF " from Delay (%d)\n", index, ref, i); - } - else - { - vxAddLogEntry((vx_reference)delay, VX_ERROR_INVALID_PARAMETERS, "Failed to retrieve reference from delay by index %d\n", index); - ref = (vx_reference)vxGetErrorObject(delay->context, VX_ERROR_INVALID_PARAMETERS); - } - } - return ref; -} - -VX_API_ENTRY vx_status VX_API_CALL vxQueryDelay(vx_delay delay, vx_enum attribute, void *ptr, vx_size size) -{ - vx_status status = VX_SUCCESS; - if (vxIsValidDelay(delay) == vx_true_e) - { - switch (attribute) - { - case VX_DELAY_TYPE: - if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) - *(vx_enum *)ptr = delay->type; - else - status = VX_ERROR_INVALID_PARAMETERS; - break; - case VX_DELAY_SLOTS: - if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) - *(vx_size *)ptr = (vx_size)delay->count; - else - status = VX_ERROR_INVALID_PARAMETERS; - break; - default: - status = VX_ERROR_NOT_SUPPORTED; - break; - } - } - else - { - status = VX_ERROR_INVALID_REFERENCE; - } - VX_PRINT(VX_ZONE_API, "%s returned %d\n",__FUNCTION__, status); - return status; -} - -VX_API_ENTRY vx_status VX_API_CALL vxReleaseDelay(vx_delay* d) -{ - vx_status status = VX_FAILURE; - - if (nullptr != d) - { - vx_delay delay = *d; - if (vx_true_e == Reference::isValidReference(delay, VX_TYPE_DELAY)) - { - status = Reference::releaseReference((vx_reference*)d, VX_TYPE_DELAY, VX_EXTERNAL, nullptr); - } - } - - return status; -} - VX_API_ENTRY vx_delay VX_API_CALL vxCreateDelay(vx_context context, vx_reference exemplar, vx_size count) @@ -455,89 +493,84 @@ VX_API_ENTRY vx_delay VX_API_CALL vxCreateDelay(vx_context context, return (vx_delay)delay; } -VX_API_ENTRY vx_status VX_API_CALL vxAgeDelay(vx_delay delay) +VX_API_ENTRY vx_reference VX_API_CALL vxGetReferenceFromDelay(vx_delay delay, vx_int32 index) { - vx_status status = VX_SUCCESS; + vx_reference ref = nullptr; + if (vxIsValidDelay(delay) == vx_true_e) { - vx_int32 i,j; - - /* increment the index */ - delay->index = (delay->index + (vx_uint32)delay->count - 1) % (vx_uint32)delay->count; - - VX_PRINT(VX_ZONE_DELAY, "Delay has shifted by 1, base index is now %d\n", delay->index); - - /* then reassign the parameters */ - for (i = 0; i < (vx_int32)delay->count; i++) - { - vx_delay_param_t *param = nullptr; - - j = (delay->index + i) % (vx_int32)delay->count; - param = &delay->set[i]; - do { - if (param->node != 0) - { - param->node->setParameter(param->index, - delay->refs[j]); - } - param = param->next; - } while (param != nullptr); - } + ref = delay->getReference(index); + } + return ref; +} - if (delay->type == VX_TYPE_PYRAMID && delay->pyr != nullptr) +VX_API_ENTRY vx_status VX_API_CALL vxQueryDelay(vx_delay delay, vx_enum attribute, void *ptr, + vx_size size) +{ + vx_status status = VX_SUCCESS; + if (vxIsValidDelay(delay) == vx_true_e) + { + switch (attribute) { - /* age pyramid levels */ - vx_int32 numLevels = (vx_int32)(((vx_pyramid)delay->refs[0])->numLevels); - for (i = 0; i < numLevels; ++i) - vxAgeDelay(delay->pyr[i]); + case VX_DELAY_TYPE: + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) + *(vx_enum *)ptr = delay->dataType(); + else + status = VX_ERROR_INVALID_PARAMETERS; + break; + case VX_DELAY_SLOTS: + if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) + *(vx_size *)ptr = (vx_size)delay->numObjects(); + else + status = VX_ERROR_INVALID_PARAMETERS; + break; + default: + status = VX_ERROR_NOT_SUPPORTED; + break; } } else { status = VX_ERROR_INVALID_REFERENCE; } + VX_PRINT(VX_ZONE_API, "%s returned %d\n", __FUNCTION__, status); return status; } -VX_API_ENTRY vx_status VX_API_CALL vxRegisterAutoAging(vx_graph graph, vx_delay delay) +VX_API_ENTRY vx_status VX_API_CALL vxAgeDelay(vx_delay delay) { - unsigned int i; vx_status status = VX_SUCCESS; - vx_bool isAlreadyRegistered = vx_false_e; - vx_bool isRegisteredDelaysListFull = vx_true_e; - - if (vxIsValidGraph(graph) == vx_false_e) - return VX_ERROR_INVALID_REFERENCE; + if (vxIsValidDelay(delay) == vx_true_e) + { + status = delay->age(); + } + else + { + status = VX_ERROR_INVALID_REFERENCE; + } + return status; +} +VX_API_ENTRY vx_status VX_API_CALL vxRegisterAutoAging(vx_graph graph, vx_delay delay) +{ if (vxIsValidDelay(delay) == vx_false_e) return VX_ERROR_INVALID_REFERENCE; - /* check if this particular delay is already registered in the graph */ - for (i = 0; i < VX_INT_MAX_REF; i++) - { - if (graph->delays[i] && vxIsValidDelay(graph->delays[i]) && graph->delays[i] == delay) - { - isAlreadyRegistered = vx_true_e; - break; - } - } + return delay->registerAutoAging(graph); +} - /* if not regisered yet, find the first empty slot and register delay */ - if (isAlreadyRegistered == vx_false_e) +VX_API_ENTRY vx_status VX_API_CALL vxReleaseDelay(vx_delay *d) +{ + vx_status status = VX_FAILURE; + + if (nullptr != d) { - for (i = 0; i < VX_INT_MAX_REF; i++) + vx_delay delay = *d; + if (vx_true_e == Reference::isValidReference(delay, VX_TYPE_DELAY)) { - if (vxIsValidDelay(graph->delays[i]) == vx_false_e) - { - isRegisteredDelaysListFull = vx_false_e; - graph->delays[i] = delay; - break; - } + status = + Reference::releaseReference((vx_reference *)d, VX_TYPE_DELAY, VX_EXTERNAL, nullptr); } - - /* report error if there is no empty slots to register delay */ - if (isRegisteredDelaysListFull == vx_true_e) - status = VX_ERROR_INVALID_REFERENCE; } return status; From 78a2150106c52b36064d57dbeffa36be089537b2 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 30 Jul 2025 13:59:02 -0700 Subject: [PATCH 24/34] Reworked error --- framework/include/vx_error.h | 19 +++++++++++++++++++ framework/src/vx_error.cpp | 25 +++++++++++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/framework/include/vx_error.h b/framework/include/vx_error.h index e6b0c21e..a3ce5ca3 100644 --- a/framework/include/vx_error.h +++ b/framework/include/vx_error.h @@ -62,6 +62,25 @@ class Error : public Reference */ static void releaseError(vx_error* error); + /*! \brief Matches the status code against all known error objects in the + * context. + * \param [in] context The pointer to the overall context. + * \param [in] status The status code to find. + * \return Returns a matching error object. + * \ingroup group_int_error + */ + static vx_error getError(vx_context context, vx_status status); + + /** + * @brief Provides a generic API to return status values from Object constructors if they + * fail. + * + * @param [in] ref The reference to check for construction errors. + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_error + */ + static vx_status getStatus(vx_reference ref); + /*! \brief The specific error code contained in this object. */ vx_status status; }; diff --git a/framework/src/vx_error.cpp b/framework/src/vx_error.cpp index 31608af9..64451767 100644 --- a/framework/src/vx_error.cpp +++ b/framework/src/vx_error.cpp @@ -61,19 +61,14 @@ vx_bool Error::createConstErrors(vx_context context) return ret; } -/******************************************************************************/ -/* PUBLIC INTERFACE */ -/******************************************************************************/ - -VX_API_ENTRY vx_error vxGetErrorObject(vx_context context, vx_status status) +vx_error Error::getError(vx_context context, vx_status status) { vx_error error = nullptr; vx_size i = 0ul; Osal::semWait(&context->lock); for (i = 0ul; i < context->num_references; i++) { - if (context->reftable[i] == nullptr) - continue; + if (context->reftable[i] == nullptr) continue; if (context->reftable[i]->type == VX_TYPE_ERROR) { @@ -89,7 +84,7 @@ VX_API_ENTRY vx_error vxGetErrorObject(vx_context context, vx_status status) return error; } -VX_API_ENTRY vx_status VX_API_CALL vxGetStatus(vx_reference ref) +vx_status Error::getStatus(vx_reference ref) { if (ref == nullptr) { @@ -120,3 +115,17 @@ VX_API_ENTRY vx_status VX_API_CALL vxGetStatus(vx_reference ref) VX_PRINT(VX_ZONE_ERROR, "returning fail\n"); return VX_FAILURE; } + +/******************************************************************************/ +/* PUBLIC INTERFACE */ +/******************************************************************************/ + +VX_API_ENTRY vx_error vxGetErrorObject(vx_context context, vx_status status) +{ + return Error::getError(context, status); +} + +VX_API_ENTRY vx_status VX_API_CALL vxGetStatus(vx_reference ref) +{ + return Error::getStatus(ref); +} From c9d2b911f903723e6e87715c6580ea8a620aba5b Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 30 Jul 2025 14:25:43 -0700 Subject: [PATCH 25/34] Reworked import --- framework/include/vx_import.h | 56 +++++++++++++++++- framework/src/vx_import.cpp | 108 ++++++++++++++++++++++------------ 2 files changed, 124 insertions(+), 40 deletions(-) diff --git a/framework/include/vx_import.h b/framework/include/vx_import.h index b6c96f7f..ded8f727 100644 --- a/framework/include/vx_import.h +++ b/framework/include/vx_import.h @@ -50,8 +50,34 @@ class Import : public Reference */ ~Import(); -#if defined(OPENVX_USE_IX) || defined(OPENVX_USE_XML) +#if defined(OPENVX_USE_XML) + /** + * @brief Get the number of references in the import + * + * @return vx_uint32 The number of references in the import. + * @ingroup group_int_import + */ + vx_uint32 numRefs() const; + + /** + * @brief Get the type of import + * + * @return vx_enum The type of import. + * @ingroup group_int_import + */ + vx_enum importType() const; + /** + * @brief Get the Reference By Index object + * + * @param index + * @return vx_reference + * @ingroup group_int_import + */ + vx_reference getReferenceByIndex(vx_uint32 index); +#endif /* defined(OPENVX_USE_XML) */ + +#if defined(OPENVX_USE_IX) || defined(OPENVX_USE_XML) /*! \brief Create an import object. * \param [in] context The context. * \param [in] type The type of import. @@ -62,11 +88,37 @@ class Import : public Reference vx_enum type, vx_uint32 count); + /** + * @brief Get a reference from the import object by name.\n + * + * @details All accessible references of the import object created using \ref + * vxImportObjectsFromMemory are in the array *refs*, which is populated partly by the + * application before import, and partly by the framework. However, it may be more convenient to + * access the references in the import object without referring to this array, for example if + * the import object is passed as a parameter to another function. In this case, references may + * be retreived by name, assuming that \ref vxSetReferenceName was called to assign a + * name to the reference. This function searches the given import for the given name and returns + * the associated reference.\n The reference may have been named either before export or + * after import.\n If more than one reference exists in the import with the given name, + * this is an error.\n Only references in the array *refs* after calling \ref + * vxImportObjectsFromMemory may be retrieved using this function.\n A reference to + * a named object may be obtained from a valid import object using this API even if all other + * references to the object have been released. + * + * @param name The name to find, points to a string of at least one and less than + * VX_MAX_REFERENCE_NAME bytes followed by a zero byte; the function will fail if this is not + * valid. + * @return vx_reference A \ref vx_reference[*REQ*].\n + * Calling \ref Error::getStatus with the reference as a parameter will return VX_SUCCESS if + * the function was successful[*REQ*].\n + * @ingroup group_int_import + */ + vx_reference getReferenceByName(const vx_char* name); + /*! \brief Destroys an Import and it's scoped-objects. * \ingroup group_int_import */ void destruct() override final; - #endif /* defined(OPENVX_USE_IX) || defined(OPENVX_USE_XML) */ /*! \brief The internal representation of any import object. diff --git a/framework/src/vx_import.cpp b/framework/src/vx_import.cpp index 45613450..089ad5ce 100644 --- a/framework/src/vx_import.cpp +++ b/framework/src/vx_import.cpp @@ -31,6 +31,39 @@ Import::~Import() } +#if defined(OPENVX_USE_XML) + +vx_uint32 Import::numRefs() const +{ + return count; +} + +vx_enum Import::importType() const +{ + return import_type; +} + +vx_reference Import::getReferenceByIndex(vx_uint32 index) +{ + vx_reference ref = nullptr; + + if (index < this->count) + { + ref = (vx_reference)this->refs[index]; + ref->incrementReference(VX_EXTERNAL); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Incorrect index value\n"); + vxAddLogEntry(this->context, VX_ERROR_INVALID_PARAMETERS, "Incorrect index value\n"); + ref = (vx_reference)vxGetErrorObject(this->context, VX_ERROR_INVALID_PARAMETERS); + } + + return ref; +} + +#endif /* defined(OPENVX_USE_XML) */ + #if defined(OPENVX_USE_XML) || defined(OPENVX_USE_IX) vx_import Import::createImportInt(vx_context context, @@ -53,6 +86,24 @@ vx_import Import::createImportInt(vx_context context, return import; } +vx_reference Import::getReferenceByName(const vx_char *name) +{ + vx_reference ref = nullptr; + vx_uint32 index = 0; + + for (index = 0; index < this->count; index++) + { + if (strncmp(name, this->refs[index]->name, VX_MAX_REFERENCE_NAME) == 0) + { + ref = (vx_reference)this->refs[index]; + ref->incrementReference(VX_EXTERNAL); + break; + } + } + + return ref; +} + void Import::destruct() { vx_uint32 i = 0; @@ -73,33 +124,9 @@ void Import::destruct() #endif /* defined(OPENVX_USE_XML) || defined(OPENVX_USE_IX) */ /******************************************************************************/ -/* PUBLIC API */ +/* PUBLIC API */ /******************************************************************************/ #if defined(OPENVX_USE_XML) -VX_API_ENTRY vx_reference VX_API_CALL vxGetImportReferenceByIndex(vx_import import, vx_uint32 index) -{ - vx_reference ref = nullptr; - if (import && import->type == VX_TYPE_IMPORT) - { - if (index < import->count) - { - ref = (vx_reference)import->refs[index]; - ref->incrementReference(VX_EXTERNAL); - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Incorrect index value\n"); - vxAddLogEntry(import->context, VX_ERROR_INVALID_PARAMETERS, "Incorrect index value\n"); - ref = (vx_reference)vxGetErrorObject(import->context, VX_ERROR_INVALID_PARAMETERS); - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid import reference!\n"); - } - return ref; -} - VX_API_ENTRY vx_status VX_API_CALL vxQueryImport(vx_import import, vx_enum attribute, void *ptr, vx_size size) { vx_status status = VX_SUCCESS; @@ -110,7 +137,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryImport(vx_import import, vx_enum attri case VX_IMPORT_ATTRIBUTE_COUNT: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = import->count; + *(vx_uint32 *)ptr = import->numRefs(); } else { @@ -118,9 +145,9 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryImport(vx_import import, vx_enum attri } break; case VX_IMPORT_ATTRIBUTE_TYPE: - if ((size <= VX_MAX_TARGET_NAME) && (ptr != nullptr)) + if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_uint32 *)ptr = import->import_type; + *(vx_uint32 *)ptr = import->importType(); } else { @@ -136,6 +163,20 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryImport(vx_import import, vx_enum attri status = VX_ERROR_INVALID_REFERENCE; return status; } + +VX_API_ENTRY vx_reference VX_API_CALL vxGetImportReferenceByIndex(vx_import import, vx_uint32 index) +{ + vx_reference ref = nullptr; + if (import && import->type == VX_TYPE_IMPORT) + { + ref = import->getReferenceByIndex(index); + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid import reference!\n"); + } + return ref; +} #endif /* defined(OPENVX_USE_XML) */ #if defined(OPENVX_USE_IX) || defined(OPENVX_USE_XML) @@ -145,16 +186,7 @@ VX_API_ENTRY vx_reference VX_API_CALL vxGetImportReferenceByName(vx_import impor vx_reference ref = nullptr; if (import && import->type == VX_TYPE_IMPORT) { - vx_uint32 index = 0; - for (index = 0; index < import->count; index++) - { - if (strncmp(name, import->refs[index]->name, VX_MAX_REFERENCE_NAME) == 0) - { - ref = (vx_reference)import->refs[index]; - ref->incrementReference(VX_EXTERNAL); - break; - } - } + ref = import->getReferenceByName(name); } return ref; } From 8941c270d5155631c88d290ad90772d70b169023 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 30 Jul 2025 16:24:45 -0700 Subject: [PATCH 26/34] Reworked kernel --- framework/include/vx_kernel.h | 276 +++++++++++++ framework/src/vx_kernel.cpp | 748 +++++++++++++++++++++------------- 2 files changed, 736 insertions(+), 288 deletions(-) diff --git a/framework/include/vx_kernel.h b/framework/include/vx_kernel.h index 3699e1c4..5d601e5f 100644 --- a/framework/include/vx_kernel.h +++ b/framework/include/vx_kernel.h @@ -16,6 +16,10 @@ #ifndef VX_KERNEL_H #define VX_KERNEL_H +#ifdef OPENVX_KHR_TILING +#include +#endif /* OPENVX_KHR_TILING */ + #include "vx_internal.h" #include "vx_reference.h" @@ -69,6 +73,150 @@ class Kernel : public Reference */ ~Kernel() = default; + /** + * @brief Get the number of kernel parameters + * + * @return vx_uint32 The number of kernel parameters. + * @ingroup group_int_kernel + */ + vx_uint32 numParameters() const; + + /** + * @brief Get the kernel name + * + * @return const vx_char* The kernel name. + * @ingroup group_int_kernel + */ + const vx_char *kernelName() const; + + /** + * @brief Get the kernel enuemration + * + * @return vx_enum The kernel enuemration. + * @ingroup group_int_kernel + */ + vx_enum kernelEnum() const; + + /** + * @brief Get the local data size + * + * @return vx_size The local data size. + * @ingroup group_int_kernel + */ + vx_size localDataSize() const; + +#ifdef OPENVX_KHR_TILING + /** + * @brief Get the input neighborhood size + * + * @return vx_neighborhood_size_t The input neighborhood size. + * @ingroup group_int_kernel + */ + vx_neighborhood_size_t inputNeighborhood() const; + + /** + * @brief Get the output tile block size + * + * @return vx_tile_block_size_t The output tile block size. + * @ingroup group_int_kernel + */ + vx_tile_block_size_t outputTileBlockSize() const; + + /** + * @brief Get the kernel border object + * + * @return vx_border_t The kernel border object. + * @ingroup group_int_kernel + */ + vx_border_t border() const; +#endif /* OPENVX_KHR_TILING */ + +#ifdef OPENVX_USE_OPENCL_INTEROP + /** + * @brief Is Opencl in use + * + * @return vx_bool vx_true_e if used, otherwise vx_false_e. + * @ingroup group_int_kernel + */ + vx_bool useOpencl() const; +#endif /* OPENVX_USE_OPENCL_INTEROP */ + + /** + * @brief Get the pipeup input depth + * + * @return vx_uint32 The pipeup input depth. + * @ingroup group_int_kernel + */ + vx_uint32 pipeupInputDepth() const; + + /** + * @brief Get the pipeup output depth + * + * @return vx_uint32 The pipeup output depth. + * @ingroup group_int_kernel + */ + vx_uint32 pipeupOutputDepth() const; + + /** + * @brief Set the local data size + * + * @param size The local data size. + * @ingroup group_int_kernel + */ + void setLocalDataSize(vx_size size); + +#ifdef OPENVX_KHR_TILING + /** + * @brief Set the input neighborhood size + * + * @param input The input neighborhood size. + * @ingroup group_int_kernel + */ + void setInputNeighborhood(vx_neighborhood_size_t input); + + /** + * @brief Set the output tile block size + * + * @param tile_size The output tile block size. + * @ingroup group_int_kernel + */ + void setOutputTileBlockSize(vx_tile_block_size_t tile_size); + + /** + * @brief Set the kernel border object + * + * @param border The kernel border object. + * @ingroup group_int_kernel + */ + void setBorder(vx_border_t border); +#endif /* OPENVX_KHR_TILING */ + +#ifdef OPENVX_USE_OPENCL_INTEROP + /** + * @brief Set Opencl access + * + * @param flag Opencl access flag. + * @ingroup group_int_kernel + */ + void setOpenclAccess(vx_bool flag); +#endif /* OPENVX_USE_OPENCL_INTEROP */ + + /** + * @brief Set the pipeup input depth + * + * @param depth The pipeup input depth. + * @ingroup group_int_kernel + */ + void setInputDepth(vx_uint32 depth); + + /** + * @brief Set the pipeup output depth + * + * @param depth The pipeup output depth. + * @ingroup group_int_kernel + */ + void setOutputDepth(vx_uint32 depth); + /*! \brief Determines if a kernel is unique in the system. * \param kernel The handle to the kernel. * \ingroup group_int_kernel @@ -128,7 +276,135 @@ class Kernel : public Reference vx_kernel_deinitialize_f deinitialize, vx_bool valid_rect_reset); +#ifdef OPENVX_KHR_TILING + /** + * @brief Allows a user to add a tile-able kernel to the framework. + * + * @param [in] context The handle to the implementation context. + * @param [in] name The string to be used to match the kernel. + * @param [in] enumeration The enumerated value of the kernel to be used by clients. + * @param [in] flexible_func_ptr The process-local flexible function pointer to be invoked. + * @param [in] fast_func_ptr The process-local fast function pointer to be invoked. + * @param [in] num_params The number of parameters for this kernel. + * @param [in] input The pointer to a function which will validate the + * input parameters to this kernel. + * @param [in] output The pointer to a function which will validate the + * output parameters to this kernel. + * @note Tiling Kernels do not have access to any of the normal node attributes listed + * in @ref vx_node_attribute_e. + * @post Call \ref addParameter for as many parameters as the function has, + * then call \ref finalize. + * @return vx_kernel Nullptr indicates that an error occurred when adding the kernel. + * Note that the fast or flexible formula, but not both, can be NULL. + * @ingroup group_int_kernel + */ + static vx_kernel addTilingKernel(vx_context context, vx_char name[VX_MAX_KERNEL_NAME], + vx_enum enumeration, vx_tiling_kernel_f flexible_func_ptr, + vx_tiling_kernel_f fast_func_ptr, vx_uint32 num_params, + vx_kernel_input_validate_f input, + vx_kernel_output_validate_f output); +#endif /* OPENVX_KHR_TILING */ + + /** + * @brief This API is called after all parameters have been added to the + * kernel and the kernel is \e ready to be used. Notice that the reference to the kernel created + * by addKernel is still valid after the call to finalize. + * If an error occurs, the kernel is not available for usage by the clients of the framework. + * Typically this is due to a mismatch between the number of parameters requested and given. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_kernel + */ + vx_status finalize(); + + /** + * @brief Allows users to set the signatures of the custom kernel. + * + * @param [in] index The index of the parameter to add. + * @param [in] dir The direction of the parameter. This must be either \ref VX_INPUT or + * \ref VX_OUTPUT. + * @param [in] data_type The type of parameter. This must be a value from \ref + * vx_type_e. + * @param [in] state The state of the parameter (required or not). This must be a value from + * \ref vx_parameter_state_e. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_kernel + */ + vx_status addParameter(vx_uint32 index, vx_enum dir, vx_enum data_type, vx_enum state); + + /** + * @brief Removes a custom kernel from its context and releases it. + * + * @param [in] kernel The reference to the kernel to remove. Returned from \ref + * addKernel. + * @note Any kernel enumerated in the base standard + * cannot be removed; only kernels added through \ref vxAddUserKernel can + * be removed. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_kernel + */ + static vx_status removeKernel(vx_kernel kernel); + + /** + * @brief Loads a library of kernels, called module, into the context. + * + * @note When all references to loaded kernels are released, the module + * may be automatically unloaded. + * @param [in] context The reference to the context the kernels must be added to. + * @param [in] module The short name of the module to load. On systems where + * there are specific naming conventions for modules, the name passed + * should ignore such conventions. For example: \c libxyz.so should be + * passed as just \c xyz and the implementation will do the right thing that + * the platform requires. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_kernel + */ + static vx_status loadKernels(vx_context context, const vx_char *name); + + /** + * @brief Unloads all kernels from the context that had been loaded from + * the module using the \ref loadKernels function. + * + * @param [in] context The reference to the context the kernels must be removed from. + * @param [in] module The short name of the module to unload. On systems where + * there are specific naming conventions for modules, the name passed + * should ignore such conventions. For example: \c libxyz.so should be + * passed as just \c xyz and the implementation will do the right thing + * that the platform requires. + * @note This API uses the system pre-defined paths for modules. + * + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. + * @ingroup group_int_kernel + */ + static vx_status unloadKernels(vx_context context, const vx_char *name); + + /** + * @brief Get the Kernel By Name + * + * @param [in] context The reference to the implementation context. + * @param [in] string The string of the name of the kernel to get. + * @return vx_kernel A \ref vx_kernel reference. Any possible errors preventing a + * successful completion of the function should be checked using \ref Error::getStatus. + * @ingroup group_int_kernel + */ + static vx_kernel getKernelByName(vx_context context, const vx_char string[VX_MAX_KERNEL_NAME]); + + /** + * @brief Get the Kernel By Enum + * + * @param context The reference to the implementation context. + * @param kernelenum A value from a vendor or client-defined value. + * @return vx_kernel A \ref vx_kernel reference. Any possible errors preventing a + * successful completion of the function should be checked using \ref Error::getStatus. + * @ingroup group_int_kernel + */ + static vx_kernel getKernelByEnum(vx_context context, vx_enum kernelenum); + /*! \brief Used to deinitialize a kernel object in a target kernel list. + * \return vx_status VX_SUCCESS if successful, any other value indicates failure. * \ingroup group_int_kernel */ vx_status deinitializeKernel(); diff --git a/framework/src/vx_kernel.cpp b/framework/src/vx_kernel.cpp index a274943a..84d55bf4 100644 --- a/framework/src/vx_kernel.cpp +++ b/framework/src/vx_kernel.cpp @@ -88,6 +88,106 @@ void Kernel::printKernel(vx_kernel kernel) kernel->name); } +vx_uint32 Kernel::numParameters() const +{ + return signature.num_parameters; +} + +const vx_char *Kernel::kernelName() const +{ + vx_char kname[VX_MAX_KERNEL_NAME]; + vx_char *k, *v; + strncpy(kname, this->name, VX_MAX_KERNEL_NAME); + k = strtok(kname, ":"); + v = strtok(nullptr, ":"); + (void)v; /* need this variable in the future for variant searches */ + + return k; +} + +vx_enum Kernel::kernelEnum() const +{ + return enumeration; +} + +vx_size Kernel::localDataSize() const +{ + return attributes.localDataSize; +} + +#ifdef OPENVX_KHR_TILING +vx_neighborhood_size_t Kernel::inputNeighborhood() const +{ + return attributes.nhbdinfo; +} + +vx_tile_block_size_t Kernel::outputTileBlockSize() const +{ + return attributes.blockinfo; +} + +vx_border_t Kernel::border() const +{ + return attributes.borders; +} +#endif /* OPENVX_KHR_TILING */ + +#ifdef OPENVX_USE_OPENCL_INTEROP +vx_bool Kernel::useOpencl() const +{ + return attributes.opencl_access; +} +#endif /* OPENVX_USE_OPENCL_INTEROP */ + +vx_uint32 Kernel::pipeupInputDepth() const +{ + return input_depth; +} + +vx_uint32 Kernel::pipeupOutputDepth() const +{ + return output_depth; +} + +void Kernel::setLocalDataSize(vx_size size) +{ + attributes.localDataSize = size; +} + +#ifdef OPENVX_KHR_TILING +void Kernel::setInputNeighborhood(vx_neighborhood_size_t input) +{ + memcpy(&attributes.nhbdinfo, &input, sizeof(vx_neighborhood_size_t)); +} + +void Kernel::setOutputTileBlockSize(vx_tile_block_size_t tile_size) +{ + memcpy(&attributes.blockinfo, &tile_size, sizeof(vx_tile_block_size_t)); +} + +void Kernel::setBorder(vx_border_t border) +{ + memcpy(&attributes.borders, &border, sizeof(vx_border_t)); +} +#endif /* OPENVX_KHR_TILING */ + +#ifdef OPENVX_USE_OPENCL_INTEROP +void Kernel::setOpenclAccess(vx_bool flag) +{ + attributes.opencl_access = flag; +} +#endif /* OPENVX_USE_OPENCL_INTEROP */ + +void Kernel::setInputDepth(vx_uint32 depth) +{ + input_depth = depth; +} + +void Kernel::setOutputDepth(vx_uint32 depth) +{ + output_depth = depth; +} + vx_bool Kernel::isKernelUnique(vx_kernel kernel) { vx_uint32 t = 0u, k = 0u; @@ -272,32 +372,263 @@ vx_kernel Kernel::addkernel(vx_context context, return kernel; } -vx_status Kernel::deinitializeKernel() +#ifdef OPENVX_KHR_TILING +vx_kernel Kernel::addTilingKernel(vx_context context, vx_char name[VX_MAX_KERNEL_NAME], + vx_enum enumeration, vx_tiling_kernel_f flexible_func_ptr, + vx_tiling_kernel_f fast_func_ptr, vx_uint32 num_params, + vx_kernel_input_validate_f input, + vx_kernel_output_validate_f output) +{ + vx_kernel kernel = 0; + vx_uint32 t = 0; + vx_size index = 0; + vx_target target = nullptr; + vx_char targetName[VX_MAX_TARGET_NAME]; + + if (Context::isValidContext(context) == vx_false_e) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid Context\n"); + return (vx_kernel) nullptr; + } + if ((flexible_func_ptr == nullptr && fast_func_ptr == nullptr) || input == nullptr || + output == nullptr || num_params > VX_INT_MAX_PARAMS || num_params == 0 || name == nullptr || + strncmp(name, "", VX_MAX_KERNEL_NAME) == 0) + /* initialize and de-initialize can be nullptr */ + { + VX_PRINT(VX_ZONE_ERROR, "Invalid Parameters!\n"); + vxAddLogEntry((vx_reference)context, VX_ERROR_INVALID_PARAMETERS, + "Invalid Parameters supplied to vxAddKernel\n"); + return (vx_kernel) nullptr; + } + + /* find target to assign this to */ + index = strnindex(name, ':', VX_MAX_TARGET_NAME); + if (index == VX_MAX_TARGET_NAME) + { + strcpy(targetName, "khronos.tiling"); + } + else + { + strncpy(targetName, name, index); + } + VX_PRINT(VX_ZONE_KERNEL, "Deduced Name as %s\n", targetName); + for (t = 0u; t < context->num_targets; t++) + { + target = context->targets[t]; + if (strncmp(targetName, target->name, VX_MAX_TARGET_NAME) == 0) + { + break; + } + target = nullptr; + } + if (target && target->funcs.addtilingkernel) + { + kernel = target->funcs.addtilingkernel(target, name, enumeration, nullptr, + flexible_func_ptr, fast_func_ptr, num_params, + nullptr, input, output, nullptr, nullptr); + VX_PRINT(VX_ZONE_KERNEL, "Added Kernel %s to Target %s (" VX_FMT_REF ")\n", name, + target->name, kernel); + } + else + { + vxAddLogEntry((vx_reference)context, VX_ERROR_NO_RESOURCES, "No target named %s exists!\n", + targetName); + } + return (vx_kernel)kernel; +} +#endif /* OPENVX_KHR_TILING */ + +vx_status Kernel::finalize() { vx_status status = VX_SUCCESS; - vx_reference ref = (vx_reference)this; + vx_uint32 p = 0; - if (internal_count) + for (p = 0; p < VX_INT_MAX_PARAMS; p++) { - VX_PRINT(VX_ZONE_KERNEL, "Deinit and Releasing kernel " VX_FMT_REF "\n", (void *)ref); - status = Reference::releaseReference(&ref, VX_TYPE_KERNEL, VX_INTERNAL, nullptr); + if (p >= this->signature.num_parameters) + { + break; + } + if ((this->signature.directions[p] < VX_INPUT) || + (this->signature.directions[p] > VX_BIDIRECTIONAL)) + { + status = VX_ERROR_INVALID_PARAMETERS; + break; + } + if (Context::isValidType(this->signature.types[p]) == vx_false_e) + { + status = VX_ERROR_INVALID_PARAMETERS; + break; + } + } + if (p == this->signature.num_parameters) + { + this->context->num_kernels++; + if (Kernel::isKernelUnique(this) == vx_true_e) + { + VX_PRINT(VX_ZONE_KERNEL, "Kernel %s (%x) is unique!\n", this->name, this->enumeration); + this->context->num_unique_kernels++; + } + this->enabled = vx_true_e; } return status; } -/******************************************************************************/ -/* PUBLIC FUNCTIONS */ -/******************************************************************************/ +vx_status Kernel::addParameter(vx_uint32 index, + vx_enum dir, + vx_enum data_type, + vx_enum state) +{ + vx_status status = VX_SUCCESS; -VX_API_ENTRY vx_status VX_API_CALL vxLoadKernels(vx_context context, const vx_char *name) + if (index < this->signature.num_parameters) + { +#ifdef OPENVX_KHR_TILING + if (this->tilingfast_function) + { + if (((data_type != VX_TYPE_IMAGE) && (data_type != VX_TYPE_SCALAR) && + (data_type != VX_TYPE_THRESHOLD) && (data_type != VX_TYPE_REMAP) && + (data_type != VX_TYPE_CONVOLUTION) && (data_type != VX_TYPE_TENSOR) && + (data_type != VX_TYPE_ARRAY) && (data_type != VX_TYPE_LUT) && + (data_type != VX_TYPE_MATRIX)) || + (Parameter::isValidDirection(dir) == vx_false_e) || + (Parameter::isValidState(state) == vx_false_e)) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid data type, param direction, or param state!\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + else + { + this->signature.directions[index] = dir; + this->signature.types[index] = data_type; + this->signature.states[index] = state; + status = VX_SUCCESS; + } + } + else +#endif /* OPENVX_KHR_TILING */ + { + if (((Context::isValidType(data_type) == vx_false_e) || + (Parameter::isValidDirection(dir) == vx_false_e) || + (Parameter::isValidState(state) == vx_false_e)) || + (data_type == VX_TYPE_DELAY && dir != VX_INPUT)) + { + VX_PRINT(VX_ZONE_ERROR, "Invalid data type, param direction, or param state!\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + else + { + this->signature.directions[index] = dir; + this->signature.types[index] = data_type; + this->signature.states[index] = state; + status = VX_SUCCESS; + } + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Invalid number of parameters associated!\n"); + status = VX_ERROR_INVALID_PARAMETERS; + } + + return status; +} + +vx_status Kernel::removeKernel(vx_kernel kernel) +{ + vx_status status = VX_ERROR_INVALID_PARAMETERS; + + if (kernel && + Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == + vx_true_e && + kernel->user_kernel) + { + vx_target target = nullptr; + vx_char targetName[VX_MAX_TARGET_NAME]; + vx_uint32 kernelIdx = 0u; + vx_context context = kernel->context; + + /* Remove the reference from the context */ + vx_reference ref = reinterpret_cast(kernel); + context->removeReference(ref); + + /* find back references to kernel's target and kernel in target->kernels array */ + vx_uint32 index = (vx_uint32)(strnindex(kernel->name, ':', VX_MAX_TARGET_NAME)); + if (index == VX_MAX_TARGET_NAME) + { + strcpy(targetName, "khronos.any"); + } + else + { + strncpy(targetName, kernel->name, index); + } + + for (vx_uint32 t = 0u; t < context->num_targets; t++) + { + target = context->targets[t]; + if (strncmp(targetName, target->name, VX_MAX_TARGET_NAME) == 0) + { + break; + } + target = nullptr; + } + + if (target) + { + for (vx_uint32 k = 0u; k < VX_INT_MAX_KERNELS; k++) + { + if (kernel == target->kernels[k]) + { + kernelIdx = k; + break; + } + } + } + + if (target && kernelIdx < VX_INT_MAX_KERNELS) + { + if (kernel->enabled) + { + kernel->enabled = vx_false_e; + context->num_kernels--; + if (Kernel::isKernelUnique(kernel) == vx_true_e) + { + context->num_unique_kernels--; + } + } + target->num_kernels--; + + status = kernel->deinitializeKernel(); + + if (status == VX_SUCCESS) + { + target->kernels[kernelIdx]->enumeration = VX_KERNEL_INVALID; + target->kernels[kernelIdx]->user_kernel = vx_false_e; + target->kernels[kernelIdx] = nullptr; + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Can't deinitialize kernel properly\n"); + } + } + else + { + VX_PRINT(VX_ZONE_ERROR, "Can't locate kernel in its context\n"); + } + } + + return status; +} + +vx_status Kernel::loadKernels(vx_context context, const vx_char *name) { vx_status status = VX_FAILURE; vx_char module[VX_INT_MAX_PATH]; vx_uint32 m = 0; vx_publish_kernels_f publish = nullptr; - snprintf(module, VX_INT_MAX_PATH, VX_MODULE_NAME("%s"), (name?name:"openvx-ext")); + snprintf(module, VX_INT_MAX_PATH, VX_MODULE_NAME("%s"), (name ? name : "openvx-ext")); VX_PRINT(VX_ZONE_INFO, "Attempting to load module: %s\n", module); if (Context::isValidContext(context) == vx_false_e) @@ -309,7 +640,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxLoadKernels(vx_context context, const vx_ch for (m = 0; m < VX_INT_MAX_MODULES; m++) { Osal::semWait(&context->modules[m].lock); - if (context->modules[m].handle != nullptr && strncmp(name, context->modules[m].name, VX_INT_MAX_PATH) == 0) + if (context->modules[m].handle != nullptr && + strncmp(name, context->modules[m].name, VX_INT_MAX_PATH) == 0) { context->modules[m].ref_count++; Osal::semPost(&context->modules[m].lock); @@ -381,14 +713,14 @@ VX_API_ENTRY vx_status VX_API_CALL vxLoadKernels(vx_context context, const vx_ch return status; } -VX_API_ENTRY vx_status VX_API_CALL vxUnloadKernels(vx_context context, const vx_char *name) +vx_status Kernel::unloadKernels(vx_context context, const vx_char *name) { vx_status status = VX_FAILURE; vx_char module[VX_INT_MAX_PATH]; vx_uint32 m = 0; vx_unpublish_kernels_f unpublish = nullptr; - snprintf(module, VX_INT_MAX_PATH, VX_MODULE_NAME("%s"), (name?name:"openvx-ext")); + snprintf(module, VX_INT_MAX_PATH, VX_MODULE_NAME("%s"), (name ? name : "openvx-ext")); if (Context::isValidContext(context) == vx_false_e) { @@ -399,7 +731,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnloadKernels(vx_context context, const vx_ for (m = 0; m < VX_INT_MAX_MODULES; m++) { Osal::semWait(&context->modules[m].lock); - if (context->modules[m].handle != nullptr && strncmp(name, context->modules[m].name, VX_INT_MAX_PATH) == 0) + if (context->modules[m].handle != nullptr && + strncmp(name, context->modules[m].name, VX_INT_MAX_PATH) == 0) { context->modules[m].ref_count--; if (context->modules[m].ref_count != 0) @@ -441,7 +774,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxUnloadKernels(vx_context context, const vx_ return status; } -VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByName(vx_context context, const vx_char string[VX_MAX_KERNEL_NAME]) +vx_kernel Kernel::getKernelByName(vx_context context, const vx_char string[VX_MAX_KERNEL_NAME]) { vx_kernel kern = nullptr; if (Context::isValidContext(context) == vx_true_e) @@ -464,7 +797,8 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByName(vx_context context, const v { /* There should be no colon */ /* Doing nothing will leave kern = nullptr, causing error condition below */ - VX_PRINT(VX_ZONE_ERROR, "Kernel name should not contain any ':' in this implementation\n"); + VX_PRINT(VX_ZONE_ERROR, + "Kernel name should not contain any ':' in this implementation\n"); } free(nameBuffer); @@ -493,15 +827,14 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByName(vx_context context, const v if (kern == nullptr) { VX_PRINT(VX_ZONE_ERROR, "Failed to find kernel %s\n", string); - vxAddLogEntry(reinterpret_cast(context), VX_ERROR_INVALID_PARAMETERS, "Failed to find kernel %s\n", string); + vxAddLogEntry(reinterpret_cast(context), VX_ERROR_INVALID_PARAMETERS, + "Failed to find kernel %s\n", string); kern = (vx_kernel)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } else { - VX_PRINT(VX_ZONE_KERNEL,"Found Kernel enum %d, name %s on target %s\n", - kern->enumeration, - kern->name, - context->targets[kern->affinity]->name); + VX_PRINT(VX_ZONE_KERNEL, "Found Kernel enum %d, name %s on target %s\n", + kern->enumeration, kern->name, context->targets[kern->affinity]->name); } } else @@ -511,13 +844,14 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByName(vx_context context, const v return (vx_kernel)kern; } -VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByEnum(vx_context context, vx_enum kernelenum) +vx_kernel Kernel::getKernelByEnum(vx_context context, vx_enum kernelenum) { vx_kernel kernel = nullptr; if (Context::isValidContext(context) == vx_true_e) { vx_uint32 k = 0u, t = 0u; - VX_PRINT(VX_ZONE_KERNEL,"Scanning for kernel enum %d out of %d kernels\n", kernelenum, context->num_kernels); + VX_PRINT(VX_ZONE_KERNEL, "Scanning for kernel enum %d out of %d kernels\n", kernelenum, + context->num_kernels); for (t = 0; t < context->num_targets; t++) { vx_target target = context->targets[context->priority_targets[t]]; @@ -526,7 +860,8 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByEnum(vx_context context, vx_enum VX_PRINT(VX_ZONE_KERNEL, "Target[%u] is not valid!\n", t); continue; } - VX_PRINT(VX_ZONE_KERNEL, "Checking Target[%u]=%s for %u kernels\n", context->priority_targets[t], target->name, target->num_kernels); + VX_PRINT(VX_ZONE_KERNEL, "Checking Target[%u]=%s for %u kernels\n", + context->priority_targets[t], target->name, target->num_kernels); for (k = 0; k < VX_INT_MAX_KERNELS; k++) { if (target->kernels[k] && target->kernels[k]->enumeration == kernelenum) @@ -534,22 +869,23 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByEnum(vx_context context, vx_enum kernel = target->kernels[k]; kernel->affinity = context->priority_targets[t]; kernel->incrementReference(VX_EXTERNAL); - VX_PRINT(VX_ZONE_KERNEL,"Found Kernel[%u] enum:%d name:%s in target[%u]=%s\n", k, kernelenum, kernel->name, context->priority_targets[t], target->name); + VX_PRINT(VX_ZONE_KERNEL, "Found Kernel[%u] enum:%d name:%s in target[%u]=%s\n", + k, kernelenum, kernel->name, context->priority_targets[t], + target->name); break; } } /* Acquire the highest priority target */ - if (kernel != nullptr) - break; + if (kernel != nullptr) break; } if (kernel == nullptr) { VX_PRINT(VX_ZONE_ERROR, "Kernel enum %x not found.\n", kernelenum); - vxAddLogEntry(reinterpret_cast(context), VX_ERROR_INVALID_PARAMETERS, "Kernel enum %x not found.\n", kernelenum); + vxAddLogEntry(reinterpret_cast(context), VX_ERROR_INVALID_PARAMETERS, + "Kernel enum %x not found.\n", kernelenum); kernel = (vx_kernel)vxGetErrorObject(context, VX_ERROR_INVALID_PARAMETERS); } - } else { @@ -558,28 +894,45 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByEnum(vx_context context, vx_enum return kernel; } -VX_API_ENTRY vx_status VX_API_CALL vxReleaseKernel(vx_kernel *kernel) +vx_status Kernel::deinitializeKernel() { - vx_status status = VX_ERROR_INVALID_REFERENCE; - if (nullptr != kernel) - { - vx_kernel ref = *kernel; - if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_KERNEL)) - { - VX_PRINT(VX_ZONE_KERNEL, "Releasing kernel " VX_FMT_REF "\n", (void *)ref); - - /* deinitialize kernel object */ - if (ref->kernel_object_deinitialize != nullptr) - { - ref->kernel_object_deinitialize(ref); - } + vx_status status = VX_SUCCESS; + vx_reference ref = (vx_reference)this; - status = Reference::releaseReference((vx_reference*)kernel, VX_TYPE_KERNEL, VX_EXTERNAL, nullptr); - } + if (internal_count) + { + VX_PRINT(VX_ZONE_KERNEL, "Deinit and Releasing kernel " VX_FMT_REF "\n", (void *)ref); + status = Reference::releaseReference(&ref, VX_TYPE_KERNEL, VX_INTERNAL, nullptr); } + return status; } +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ + +VX_API_ENTRY vx_status VX_API_CALL vxLoadKernels(vx_context context, const vx_char *name) +{ + return Kernel::loadKernels(context, name); +} + +VX_API_ENTRY vx_status VX_API_CALL vxUnloadKernels(vx_context context, const vx_char *name) +{ + return Kernel::unloadKernels(context, name); +} + +VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByName(vx_context context, + const vx_char string[VX_MAX_KERNEL_NAME]) +{ + return Kernel::getKernelByName(context, string); +} + +VX_API_ENTRY vx_kernel VX_API_CALL vxGetKernelByEnum(vx_context context, vx_enum kernelenum) +{ + return Kernel::getKernelByEnum(context, kernelenum); +} + /* * add std-extra kernels */ @@ -625,62 +978,8 @@ VX_API_ENTRY vx_kernel VX_API_CALL vxAddTilingKernel(vx_context context, vx_kernel_input_validate_f input, vx_kernel_output_validate_f output) { - vx_kernel kernel = 0; - vx_uint32 t = 0; - vx_size index = 0; - vx_target target = nullptr; - vx_char targetName[VX_MAX_TARGET_NAME]; - - if (Context::isValidContext(context) == vx_false_e) - { - VX_PRINT(VX_ZONE_ERROR, "Invalid Context\n"); - return (vx_kernel)nullptr; - } - if ((flexible_func_ptr == nullptr && fast_func_ptr == nullptr) || - input == nullptr || - output == nullptr || - num_params > VX_INT_MAX_PARAMS || num_params == 0 || - name == nullptr || - strncmp(name, "", VX_MAX_KERNEL_NAME) == 0) - /* initialize and de-initialize can be nullptr */ - { - VX_PRINT(VX_ZONE_ERROR, "Invalid Parameters!\n"); - vxAddLogEntry((vx_reference)context, VX_ERROR_INVALID_PARAMETERS, "Invalid Parameters supplied to vxAddKernel\n"); - return (vx_kernel)nullptr; - } - - /* find target to assign this to */ - index = strnindex(name, ':', VX_MAX_TARGET_NAME); - if (index == VX_MAX_TARGET_NAME) - { - strcpy(targetName,"khronos.tiling"); - } - else - { - strncpy(targetName, name, index); - } - VX_PRINT(VX_ZONE_KERNEL, "Deduced Name as %s\n", targetName); - for (t = 0u; t < context->num_targets; t++) - { - target = context->targets[t]; - if (strncmp(targetName,target->name, VX_MAX_TARGET_NAME) == 0) - { - break; - } - target = nullptr; - } - if (target && target->funcs.addtilingkernel) - { - kernel = target->funcs.addtilingkernel(target, name, enumeration, nullptr, - flexible_func_ptr, fast_func_ptr, num_params, nullptr, - input, output, nullptr, nullptr); - VX_PRINT(VX_ZONE_KERNEL,"Added Kernel %s to Target %s (" VX_FMT_REF ")\n", name, target->name, kernel); - } - else - { - vxAddLogEntry((vx_reference)context, VX_ERROR_NO_RESOURCES, "No target named %s exists!\n", targetName); - } - return (vx_kernel)kernel; + return Kernel::addTilingKernel(context, name, enumeration, flexible_func_ptr, fast_func_ptr, + num_params, input, output); } #endif /* OPENVX_KHR_TILING */ @@ -689,35 +988,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxFinalizeKernel(vx_kernel kernel) vx_status status = VX_SUCCESS; if (kernel && Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == vx_true_e) { - vx_uint32 p = 0; - for (p = 0; p < VX_INT_MAX_PARAMS; p++) - { - if (p >= kernel->signature.num_parameters) - { - break; - } - if ((kernel->signature.directions[p] < VX_INPUT) || - (kernel->signature.directions[p] > VX_BIDIRECTIONAL)) - { - status = VX_ERROR_INVALID_PARAMETERS; - break; - } - if (Context::isValidType(kernel->signature.types[p]) == vx_false_e) - { - status = VX_ERROR_INVALID_PARAMETERS; - break; - } - } - if (p == kernel->signature.num_parameters) - { - kernel->context->num_kernels++; - if (Kernel::isKernelUnique(kernel) == vx_true_e) - { - VX_PRINT(VX_ZONE_KERNEL, "Kernel %s (%x) is unique!\n", kernel->name, kernel->enumeration); - kernel->context->num_unique_kernels++; - } - kernel->enabled = vx_true_e; - } + status = kernel->finalize(); } else { @@ -737,7 +1008,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_PARAMETERS: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - *(vx_uint32 *)ptr = kernel->signature.num_parameters; + *(vx_uint32 *)ptr = kernel->numParameters(); } else { @@ -747,13 +1018,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_NAME: if (ptr != nullptr && size <= VX_MAX_KERNEL_NAME) { - vx_char kname[VX_MAX_KERNEL_NAME]; - vx_char *k, *v; - strncpy(kname, kernel->name, VX_MAX_KERNEL_NAME); - k = strtok(kname, ":"); - v = strtok(nullptr, ":"); - (void)v; /* need this variable in the future for variant searches */ - strncpy(reinterpret_cast(ptr), k, VX_MAX_KERNEL_NAME); + strncpy(reinterpret_cast(ptr), kernel->kernelName(), VX_MAX_KERNEL_NAME); } else { @@ -763,7 +1028,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_ENUM: if (VX_CHECK_PARAM(ptr, size, vx_enum, 0x3)) { - *(vx_enum *)ptr = kernel->enumeration; + *(vx_enum *)ptr = kernel->kernelEnum(); } else { @@ -773,7 +1038,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_LOCAL_DATA_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - *(vx_size *)ptr = kernel->attributes.localDataSize; + *(vx_size *)ptr = kernel->localDataSize(); } else { @@ -784,7 +1049,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_INPUT_NEIGHBORHOOD: if (VX_CHECK_PARAM(ptr, size, vx_neighborhood_size_t, 0x3)) { - memcpy(ptr, &kernel->attributes.nhbdinfo, size); + vx_neighborhood_size_t nhbd = kernel->inputNeighborhood(); + memcpy(ptr, &nhbd, size); } else { @@ -795,7 +1061,19 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_OUTPUT_TILE_BLOCK_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_tile_block_size_t, 0x3)) { - memcpy(ptr, &kernel->attributes.blockinfo, size); + vx_tile_block_size_t blockinfo = kernel->outputTileBlockSize(); + memcpy(ptr, &blockinfo, size); + } + else + { + status = VX_ERROR_INVALID_PARAMETERS; + } + break; + case VX_KERNEL_BORDER: + if (VX_CHECK_PARAM(ptr, size, vx_border_t, 0x3)) + { + vx_border_t border = kernel->border(); + memcpy(ptr, &border, size); } else { @@ -807,7 +1085,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_USE_OPENCL: if (VX_CHECK_PARAM(ptr, size, vx_bool, 0x3)) { - *(vx_bool *)ptr = kernel->attributes.opencl_access; + *(vx_bool *)ptr = kernel->useOpencl(); } else { @@ -818,7 +1096,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_PIPEUP_INPUT_DEPTH: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3) && *(vx_uint32 *)ptr > 0) { - *(vx_uint32 *)ptr = kernel->input_depth; + *(vx_uint32 *)ptr = kernel->pipeupInputDepth(); } else { @@ -828,7 +1106,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxQueryKernel(vx_kernel kernel, vx_enum attri case VX_KERNEL_PIPEUP_OUTPUT_DEPTH: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3) && *(vx_uint32 *)ptr > 0) { - *(vx_uint32 *)ptr = kernel->output_depth; + *(vx_uint32 *)ptr = kernel->pipeupOutputDepth(); } else { @@ -859,61 +1137,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToKernel(vx_kernel kernel, if (kernel && Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == vx_true_e) { - if (index < kernel->signature.num_parameters) - { -#ifdef OPENVX_KHR_TILING - if (kernel->tilingfast_function) - { - if (((data_type != VX_TYPE_IMAGE) && - (data_type != VX_TYPE_SCALAR) && - (data_type != VX_TYPE_THRESHOLD) && - (data_type != VX_TYPE_REMAP) && - (data_type != VX_TYPE_CONVOLUTION) && - (data_type != VX_TYPE_TENSOR) && - (data_type != VX_TYPE_ARRAY) && - (data_type != VX_TYPE_LUT) && - (data_type != VX_TYPE_MATRIX)) || - (Parameter::isValidDirection(dir) == vx_false_e) || - (Parameter::isValidState(state) == vx_false_e)) - { - VX_PRINT(VX_ZONE_ERROR, - "Invalid data type, param direction, or param state!\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } - else - { - kernel->signature.directions[index] = dir; - kernel->signature.types[index] = data_type; - kernel->signature.states[index] = state; - status = VX_SUCCESS; - } - } - else -#endif /* OPENVX_KHR_TILING */ - { - if (((Context::isValidType(data_type) == vx_false_e) || - (Parameter::isValidDirection(dir) == vx_false_e) || - (Parameter::isValidState(state) == vx_false_e)) || - (data_type == VX_TYPE_DELAY && dir != VX_INPUT)) - { - VX_PRINT(VX_ZONE_ERROR, - "Invalid data type, param direction, or param state!\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } - else - { - kernel->signature.directions[index] = dir; - kernel->signature.types[index] = data_type; - kernel->signature.states[index] = state; - status = VX_SUCCESS; - } - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Invalid number of parameters associated!\n"); - status = VX_ERROR_INVALID_PARAMETERS; - } + status = kernel->addParameter(index, dir, data_type, state); } else { @@ -925,87 +1149,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToKernel(vx_kernel kernel, VX_API_ENTRY vx_status VX_API_CALL vxRemoveKernel(vx_kernel kernel) { - vx_status status = VX_ERROR_INVALID_PARAMETERS; - - if (kernel && - Reference::isValidReference(reinterpret_cast(kernel), VX_TYPE_KERNEL) == vx_true_e && - kernel->user_kernel) - { - vx_target target = nullptr; - vx_char targetName[VX_MAX_TARGET_NAME]; - vx_uint32 kernelIdx = 0u; - vx_context context = kernel->context; - - /* Remove the reference from the context */ - vx_reference ref = reinterpret_cast(kernel); - context->removeReference(ref); - - /* find back references to kernel's target and kernel in target->kernels array */ - vx_uint32 index = (vx_uint32)(strnindex(kernel->name, ':', VX_MAX_TARGET_NAME)); - if (index == VX_MAX_TARGET_NAME) - { - strcpy(targetName, "khronos.any"); - } - else - { - strncpy(targetName, kernel->name, index); - } - - for (vx_uint32 t = 0u; t < context->num_targets; t++) - { - target = context->targets[t]; - if (strncmp(targetName,target->name, VX_MAX_TARGET_NAME) == 0) - { - break; - } - target = nullptr; - } - - if (target) - { - for (vx_uint32 k = 0u; k < VX_INT_MAX_KERNELS; k++) - { - if (kernel == target->kernels[k]) - { - kernelIdx = k; - break; - } - } - } - - if (target && kernelIdx < VX_INT_MAX_KERNELS) - { - if (kernel->enabled) - { - kernel->enabled = vx_false_e; - context->num_kernels--; - if (Kernel::isKernelUnique(kernel) == vx_true_e) - { - context->num_unique_kernels--; - } - } - target->num_kernels--; - - status = kernel->deinitializeKernel(); - - if (status == VX_SUCCESS) - { - target->kernels[kernelIdx]->enumeration = VX_KERNEL_INVALID; - target->kernels[kernelIdx]->user_kernel = vx_false_e; - target->kernels[kernelIdx] = nullptr; - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Can't deinitialize kernel properly\n"); - } - } - else - { - VX_PRINT(VX_ZONE_ERROR, "Can't locate kernel in its context\n"); - } - } - - return status; + return Kernel::removeKernel(kernel); } VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enum attribute, const void * ptr, vx_size size) @@ -1016,16 +1160,18 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu { return VX_ERROR_INVALID_REFERENCE; } + if (kernel->enabled == vx_true_e) { return VX_ERROR_NOT_SUPPORTED; } + switch (attribute) { case VX_KERNEL_LOCAL_DATA_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_size, 0x3)) { - kernel->attributes.localDataSize = *(vx_size *)ptr; + kernel->setLocalDataSize(*(vx_size *)ptr); VX_PRINT(VX_ZONE_KERNEL, "Set Local Data Size to " VX_FMT_SIZE " bytes\n", kernel->attributes.localDataSize); } else @@ -1037,7 +1183,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu case VX_KERNEL_INPUT_NEIGHBORHOOD: if (VX_CHECK_PARAM(ptr, size, vx_neighborhood_size_t, 0x3)) { - memcpy(&kernel->attributes.nhbdinfo, ptr, size); + kernel->setInputNeighborhood(*(vx_neighborhood_size_t *)ptr); } else { @@ -1047,7 +1193,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu case VX_KERNEL_OUTPUT_TILE_BLOCK_SIZE: if (VX_CHECK_PARAM(ptr, size, vx_tile_block_size_t, 0x3)) { - memcpy(&kernel->attributes.blockinfo, ptr, size); + kernel->setOutputTileBlockSize(*(vx_tile_block_size_t *)ptr); } else { @@ -1061,7 +1207,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu if ((border->mode == VX_BORDER_MODE_SELF) || (border->mode == VX_BORDER_UNDEFINED)) { - memcpy(&kernel->attributes.borders, border, sizeof(vx_border_t)); + kernel->setBorder(*border); } else { @@ -1078,7 +1224,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu case VX_KERNEL_USE_OPENCL: if (VX_CHECK_PARAM(ptr, size, vx_bool, 0x3)) { - kernel->attributes.opencl_access = *(vx_bool *)ptr; + kernel->setOpenclAccess(*(vx_bool *)ptr); } else { @@ -1089,7 +1235,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu case VX_KERNEL_PIPEUP_INPUT_DEPTH: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - kernel->input_depth = *(vx_uint32 *)ptr; + kernel->setInputDepth(*(vx_uint32 *)ptr); } else { @@ -1099,7 +1245,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu case VX_KERNEL_PIPEUP_OUTPUT_DEPTH: if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) { - kernel->output_depth = *(vx_uint32 *)ptr; + kernel->setOutputDepth(*(vx_uint32 *)ptr); } else { @@ -1110,5 +1256,31 @@ VX_API_ENTRY vx_status VX_API_CALL vxSetKernelAttribute(vx_kernel kernel, vx_enu status = VX_ERROR_NOT_SUPPORTED; break; } + return status; } + +VX_API_ENTRY vx_status VX_API_CALL vxReleaseKernel(vx_kernel *kernel) +{ + vx_status status = VX_ERROR_INVALID_REFERENCE; + + if (nullptr != kernel) + { + vx_kernel ref = *kernel; + if (vx_true_e == Reference::isValidReference(ref, VX_TYPE_KERNEL)) + { + VX_PRINT(VX_ZONE_KERNEL, "Releasing kernel " VX_FMT_REF "\n", (void *)ref); + + /* deinitialize kernel object */ + if (ref->kernel_object_deinitialize != nullptr) + { + ref->kernel_object_deinitialize(ref); + } + + status = Reference::releaseReference((vx_reference *)kernel, VX_TYPE_KERNEL, + VX_EXTERNAL, nullptr); + } + } + + return status; +} \ No newline at end of file From f7daa9d7e23489189b90805b50682173d6c719b5 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Wed, 30 Jul 2025 17:09:32 -0700 Subject: [PATCH 27/34] Reworked log --- framework/include/vx_log.h | 35 ++++++++++++++++++++++++++++++++++- framework/src/vx_log.cpp | 35 ++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/framework/include/vx_log.h b/framework/include/vx_log.h index 3cff8615..bffeefbc 100644 --- a/framework/include/vx_log.h +++ b/framework/include/vx_log.h @@ -23,8 +23,41 @@ * \brief The internal log implementation * * \defgroup group_int_log Internal Log API - * \ingroup group_internal * \brief The Internal Log API + * \ingroup group_internal + */ + +/** + * @brief Logger utility class that wraps spdlog functionality + * @ingroup group_int_log */ +class Logger +{ +public: + /** + * @brief Registers a callback facility to the OpenVX implementation to receive error logs. + * + * @param [in] context The overall context to OpenVX. + * @param [in] callback The callback function. If NULL, the previous callback is removed. + * @param [in] reentrant If reentrancy flag is \ref vx_true_e, then the callback may be + * entered from multiple simultaneous tasks or threads (if the host OS supports this). + * @ingroup group_int_log + */ + static void registerLogCallback(vx_context context, vx_log_callback_f callback, vx_bool reentrant); + /** + * @brief Adds a line to the log. + * + * @param [in] ref The reference to add the log entry against. Some valid value must be + * provided. + * @param [in] status The status code. \ref VX_SUCCESS status entries are ignored and + * not added. + * @param [in] message The human readable message to add to the log. + * @param [in] ap a list of variable arguments to the message. + * @note Messages may not exceed \ref VX_MAX_LOG_MESSAGE_LEN bytes and will be + * truncated in the log if they exceed this limit. + * @ingroup group_int_log + */ + static void addLogEntry(vx_reference ref, vx_status status, const char *message, va_list ap); +}; #endif /* VX_LOG_H */ diff --git a/framework/src/vx_log.cpp b/framework/src/vx_log.cpp index 9c24f3cf..ad50cb6d 100644 --- a/framework/src/vx_log.cpp +++ b/framework/src/vx_log.cpp @@ -17,7 +17,11 @@ #include "vx_internal.h" #include "vx_log.h" -VX_API_ENTRY void VX_API_CALL vxRegisterLogCallback(vx_context context, vx_log_callback_f callback, vx_bool reentrant) +/******************************************************************************/ +/* INTERNAL INTERFACE */ +/******************************************************************************/ + +void Logger::registerLogCallback(vx_context context, vx_log_callback_f callback, vx_bool reentrant) { if (Context::isValidContext(context) == vx_true_e) { @@ -39,7 +43,8 @@ VX_API_ENTRY void VX_API_CALL vxRegisterLogCallback(vx_context context, vx_log_c } context->log_enabled = vx_false_e; } - if ((context->log_callback != nullptr) && (callback != nullptr) && (context->log_callback != callback)) + if ((context->log_callback != nullptr) && (callback != nullptr) && + (context->log_callback != callback)) { if (context->log_reentrant == vx_false_e) { @@ -56,9 +61,8 @@ VX_API_ENTRY void VX_API_CALL vxRegisterLogCallback(vx_context context, vx_log_c } } -VX_API_ENTRY void VX_API_CALL vxAddLogEntry(vx_reference ref, vx_status status, const char *message, ...) +void Logger::addLogEntry(vx_reference ref, vx_status status, const char *message, va_list ap) { - va_list ap; vx_context context = nullptr; vx_char string[VX_MAX_LOG_MESSAGE_LEN]; @@ -92,10 +96,8 @@ VX_API_ENTRY void VX_API_CALL vxAddLogEntry(vx_reference ref, vx_status status, context = ref->context; } - va_start(ap, message); vsnprintf(string, VX_MAX_LOG_MESSAGE_LEN, message, ap); - string[VX_MAX_LOG_MESSAGE_LEN-1] = 0; /* for MSVC which is not C99 compliant */ - va_end(ap); + string[VX_MAX_LOG_MESSAGE_LEN - 1] = 0; /* for MSVC which is not C99 compliant */ if (context->log_callback == nullptr) { @@ -120,3 +122,22 @@ VX_API_ENTRY void VX_API_CALL vxAddLogEntry(vx_reference ref, vx_status status, } return; } + +/******************************************************************************/ +/* PUBLIC FUNCTIONS */ +/******************************************************************************/ + +VX_API_ENTRY void VX_API_CALL vxRegisterLogCallback(vx_context context, vx_log_callback_f callback, + vx_bool reentrant) +{ + Logger::registerLogCallback(context, callback, reentrant); +} + +VX_API_ENTRY void VX_API_CALL vxAddLogEntry(vx_reference ref, vx_status status, const char *message, + ...) +{ + va_list ap; + va_start(ap, message); + Logger::addLogEntry(ref, status, message, ap); + va_end(ap); +} From c35fccebcbed7c751a39978945cbb433e36e4368 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 10:19:47 -0700 Subject: [PATCH 28/34] Fixed broken integration test --- framework/include/vx_debug.h | 3 +- framework/src/vx_array.cpp | 2 + framework/src/vx_debug.cpp | 18 +++++--- framework/src/vx_graph.cpp | 6 ++- framework/src/vx_tensor.cpp | 78 ++++++++++++++++---------------- targets/liteRT/vx_litert_inf.cpp | 10 ++-- tests/integration_test/BUILD | 5 +- tests/unit_test/test_context.cpp | 2 +- 8 files changed, 70 insertions(+), 54 deletions(-) diff --git a/framework/include/vx_debug.h b/framework/include/vx_debug.h index 18b56211..ab55c2ea 100644 --- a/framework/include/vx_debug.h +++ b/framework/include/vx_debug.h @@ -61,7 +61,8 @@ enum vx_debug_zone_e { VX_ZONE_DELAY = 16, /*!< Used to show only delay logs */ VX_ZONE_TARGET = 17, /*!< Used to show only target logs */ - VX_ZONE_LOG = 18, /*!< Used to show only log logs */ + VX_ZONE_TENSOR = 18, /*!< Used to show only tensor logs */ + VX_ZONE_LOG = 19, /*!< Used to show only logs */ VX_ZONE_MAX = 32 /*!< The maximum number of zones */ }; diff --git a/framework/src/vx_array.cpp b/framework/src/vx_array.cpp index 5cb2c147..9327e72a 100644 --- a/framework/src/vx_array.cpp +++ b/framework/src/vx_array.cpp @@ -727,6 +727,7 @@ vx_status Array::unmapArrayRange(vx_map_id map_id) } else { + VX_PRINT(VX_ZONE_ERROR, "Unable to acquire semaphore resource\n"); status = VX_ERROR_NO_RESOURCES; } } @@ -740,6 +741,7 @@ vx_status Array::unmapArrayRange(vx_map_id map_id) } else { + VX_PRINT(VX_ZONE_ERROR, "Internal memory map issue\n"); status = VX_FAILURE; } diff --git a/framework/src/vx_debug.cpp b/framework/src/vx_debug.cpp index 8e1f472c..d82a0b73 100644 --- a/framework/src/vx_debug.cpp +++ b/framework/src/vx_debug.cpp @@ -46,13 +46,17 @@ struct vx_string_and_enum_e { }; struct vx_string_and_enum_e enumnames[] = { - _STR2(VX_ZONE_ERROR), _STR2(VX_ZONE_WARNING), _STR2(VX_ZONE_API), - _STR2(VX_ZONE_INFO), _STR2(VX_ZONE_DEBUG), _STR2(VX_ZONE_PERF), - _STR2(VX_ZONE_CONTEXT), _STR2(VX_ZONE_OSAL), _STR2(VX_ZONE_REFERENCE), - _STR2(VX_ZONE_ARRAY), _STR2(VX_ZONE_IMAGE), _STR2(VX_ZONE_SCALAR), - _STR2(VX_ZONE_KERNEL), _STR2(VX_ZONE_GRAPH), _STR2(VX_ZONE_NODE), - _STR2(VX_ZONE_PARAMETER), _STR2(VX_ZONE_DELAY), _STR2(VX_ZONE_TARGET), - _STR2(VX_ZONE_LOG), {"UNKNOWN", -1}, // if the zone is not found, this will be returned. + _STR2(VX_ZONE_ERROR), _STR2(VX_ZONE_WARNING), + _STR2(VX_ZONE_API), _STR2(VX_ZONE_INFO), + _STR2(VX_ZONE_DEBUG), _STR2(VX_ZONE_PERF), + _STR2(VX_ZONE_CONTEXT), _STR2(VX_ZONE_OSAL), + _STR2(VX_ZONE_REFERENCE), _STR2(VX_ZONE_ARRAY), + _STR2(VX_ZONE_IMAGE), _STR2(VX_ZONE_SCALAR), + _STR2(VX_ZONE_KERNEL), _STR2(VX_ZONE_GRAPH), + _STR2(VX_ZONE_NODE), _STR2(VX_ZONE_PARAMETER), + _STR2(VX_ZONE_DELAY), _STR2(VX_ZONE_TARGET), + _STR2(VX_ZONE_TENSOR), _STR2(VX_ZONE_LOG), + {"UNKNOWN", -1}, // if the zone is not found, this will be returned. }; void vx_set_debug_zone(vx_enum zone) diff --git a/framework/src/vx_graph.cpp b/framework/src/vx_graph.cpp index 4947aea4..ab860e40 100644 --- a/framework/src/vx_graph.cpp +++ b/framework/src/vx_graph.cpp @@ -814,8 +814,8 @@ vx_status Graph::verify() { if (this->nodes[n]->visited == vx_false_e) { - VX_PRINT(VX_ZONE_ERROR, "UNVISITED: %s node[%u]\n", this->nodes[n]->kernel->name, n); status = VX_ERROR_INVALID_GRAPH; + VX_PRINT(VX_ZONE_ERROR, "UNVISITED: %s node[%u]\n", this->nodes[n]->kernel->name, n); vxAddLogEntry(reinterpret_cast(this), status, "Node %s: unvisited!\n", this->nodes[n]->kernel->name); } @@ -826,6 +826,7 @@ vx_status Graph::verify() if (hasACycle == vx_true_e) { status = VX_ERROR_INVALID_GRAPH; + VX_PRINT(VX_ZONE_ERROR, "Cycle: Graph has a cycle!\n"); vxAddLogEntry(reinterpret_cast(this), status, "Cycle: Graph has a cycle!\n"); goto exit; } @@ -844,6 +845,8 @@ vx_status Graph::verify() if (target_verify_status != VX_SUCCESS) { status = target_verify_status; + VX_PRINT(VX_ZONE_ERROR, "Target: %s Failed to Verify Node %s\n", target->name, + this->nodes[n]->kernel->name); vxAddLogEntry(reinterpret_cast(this), status, "Target: %s Failed to Verify Node %s\n", target->name, this->nodes[n]->kernel->name); @@ -874,6 +877,7 @@ vx_status Graph::verify() if (kernel_init_status != VX_SUCCESS) { status = kernel_init_status; + VX_PRINT(VX_ZONE_ERROR, "Kernel: %s failed to initialize!\n", node->kernel->name); vxAddLogEntry(reinterpret_cast(this), status, "Kernel: %s failed to initialize!\n", node->kernel->name); } diff --git a/framework/src/vx_tensor.cpp b/framework/src/vx_tensor.cpp index fd5c4bd6..4bebbf01 100644 --- a/framework/src/vx_tensor.cpp +++ b/framework/src/vx_tensor.cpp @@ -389,55 +389,55 @@ vx_status Tensor::unmapPatch(vx_map_id map_id) return status; } - { - vx_memory_map_t *map = &context->memory_maps[map_id]; + vx_memory_map_t *map = &context->memory_maps[map_id]; - if (map->used && map->ref == (vx_reference)this) + if (map->used && map->ref == (vx_reference)this) + { + /* commit changes for write access */ + if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && nullptr != map->ptr) { - /* commit changes for write access */ - if ((VX_WRITE_ONLY == map->usage || VX_READ_AND_WRITE == map->usage) && - nullptr != map->ptr) + if (vx_true_e == Osal::semWait(&lock)) { - if (vx_true_e == Osal::semWait(&lock)) - { - vx_uint32 size = Tensor::computePatchSize( - map->extra.tensor_data.start, map->extra.tensor_data.end, - map->extra.tensor_data.number_of_dims); - vx_uint8 *pSrc = (vx_uint8 *)map->ptr; - vx_uint8 *pDst = (vx_uint8 *)addr; - - for (vx_size i = 0; i < size; i++) - { - vx_size patch_pos = 0; - vx_size tensor_pos = 0; - Tensor::computePositionsFromIndex( - i, map->extra.tensor_data.start, map->extra.tensor_data.end, stride, - map->extra.tensor_data.stride, map->extra.tensor_data.number_of_dims, - &tensor_pos, &patch_pos); - memcpy(pDst + patch_pos, pSrc + tensor_pos, stride[0]); - } + vx_uint32 size = Tensor::computePatchSize(map->extra.tensor_data.start, + map->extra.tensor_data.end, + map->extra.tensor_data.number_of_dims); + vx_uint8 *pSrc = (vx_uint8 *)map->ptr; + vx_uint8 *pDst = (vx_uint8 *)addr; - Osal::semPost(&lock); - } - else + for (vx_size i = 0; i < size; i++) { - status = VX_FAILURE; - VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); - goto exit; + vx_size patch_pos = 0; + vx_size tensor_pos = 0; + Tensor::computePositionsFromIndex( + i, map->extra.tensor_data.start, map->extra.tensor_data.end, stride, + map->extra.tensor_data.stride, map->extra.tensor_data.number_of_dims, + &tensor_pos, &patch_pos); + memcpy(pDst + patch_pos, pSrc + tensor_pos, stride[0]); } - } - /* freeing mapping buffer */ - context->memoryUnmap((vx_uint32)map_id); - decrementReference(VX_EXTERNAL); - status = VX_SUCCESS; + Osal::semPost(&lock); + } + else + { + status = VX_ERROR_NO_RESOURCES; + VX_PRINT(VX_ZONE_ERROR, "Can't lock memory plane for unmapping\n"); + goto exit; + } } - else - status = VX_FAILURE; + + /* freeing mapping buffer */ + context->memoryUnmap((vx_uint32)map_id); + decrementReference(VX_EXTERNAL); + status = VX_SUCCESS; + } + else + { + status = VX_FAILURE; + VX_PRINT(VX_ZONE_ERROR, "Internal memory mapping failure\n"); } exit: - VX_PRINT(VX_ZONE_API, "return %d\n", status); + VX_PRINT(VX_ZONE_API, "returned %d\n", status); return status; } @@ -945,7 +945,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxMapTensorPatch(vx_tensor tensor, vx_size nu VX_API_ENTRY vx_status VX_API_CALL vxUnmapTensorPatch(vx_tensor tensor, vx_map_id map_id) { - vx_status status = VX_FAILURE; + vx_status status = VX_SUCCESS; /* bad references */ if (Tensor::isValidTensor(tensor) == vx_false_e) diff --git a/targets/liteRT/vx_litert_inf.cpp b/targets/liteRT/vx_litert_inf.cpp index 43168350..e50ebed7 100644 --- a/targets/liteRT/vx_litert_inf.cpp +++ b/targets/liteRT/vx_litert_inf.cpp @@ -45,7 +45,7 @@ class VxLiteRTRunner nullptr == parameters || num != dimof(kernelParams)) { - status = VX_FAILURE; + status = VX_ERROR_INVALID_PARAMETERS; } if (VX_SUCCESS == status) @@ -81,7 +81,7 @@ class VxLiteRTRunner // Get the input tensor dimensions from the tensors status = processTensorDims(reinterpret_cast(parameters[1]), inputDims); // Get the output tensor dimensions from the tensors - status = processTensorDims(reinterpret_cast(parameters[2]), outputDims); + status |= processTensorDims(reinterpret_cast(parameters[2]), outputDims); } if (VX_SUCCESS == status) @@ -232,7 +232,7 @@ class VxLiteRTRunner { vx_status status = VX_SUCCESS; vx_size numItems = 0; - vxQueryObjectArray(objArr, VX_OBJECT_ARRAY_NUMITEMS, &numItems, sizeof(numItems)); + status = vxQueryObjectArray(objArr, VX_OBJECT_ARRAY_NUMITEMS, &numItems, sizeof(numItems)); for (vx_uint32 i = 0; i < numItems && status == VX_SUCCESS; ++i) { @@ -252,13 +252,15 @@ class VxLiteRTRunner if (VX_SUCCESS != status) { - std::cerr << "Error: Unable to prep tensor in " << __func__ << ", status: " << status << std::endl; + std::cerr << "Error: Unable to prep tensor in " << __func__ + << ", status: " << status << std::endl; break; } tensors.emplace_back((float *)ptr, size); status |= vxUnmapTensorPatch(tensor, map_id); } + return status; } }; diff --git a/tests/integration_test/BUILD b/tests/integration_test/BUILD index 870b099f..c21a00cd 100644 --- a/tests/integration_test/BUILD +++ b/tests/integration_test/BUILD @@ -102,11 +102,14 @@ cc_test( deps = [ "//:corevx", "@googletest//:gtest_main", + "//targets/ai_server:imported_openvx_ai_server", "//targets/c_model:imported_openvx_c_model", "//targets/debug:imported_openvx_debug", "//targets/extras:imported_openvx_extras", - "//targets/opencl:imported_openvx_opencl", "//targets/liteRT:imported_openvx_liteRT", + "//targets/opencl:imported_openvx_opencl", + "//targets/onnxRT:imported_openvx_onnxRT", + "//targets/executorch:imported_openvx_torch", ], linkopts = select({ "@platforms//os:linux": ["-Wl,-rpath,$ORIGIN"], diff --git a/tests/unit_test/test_context.cpp b/tests/unit_test/test_context.cpp index 25c37ab6..19bb9c05 100644 --- a/tests/unit_test/test_context.cpp +++ b/tests/unit_test/test_context.cpp @@ -48,7 +48,7 @@ TEST_F(ContextTest, QueryContext) vx_uint16 vendor_id; vx_status status = vxQueryContext(context, VX_CONTEXT_VENDOR_ID, &vendor_id, sizeof(vendor_id)); EXPECT_EQ(status, VX_SUCCESS); - EXPECT_EQ(vendor_id, VX_ID_KHRONOS); + EXPECT_EQ(vendor_id, VX_ID_EDGE_AI); vx_uint16 version; status = vxQueryContext(context, VX_CONTEXT_VERSION, &version, sizeof(version)); From 9878ed12f6fa9a083a0842eeaa279d6fb1c1a617 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:45:36 -0700 Subject: [PATCH 29/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index 09a0986d..03580c2f 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -142,7 +142,7 @@ class Array : public Reference * @param count number of items to add * @param ptr pointer to data * @param stride size of stride - * @return vx_status + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. * @ingroup group_int_array */ vx_status addItems(vx_size count, const void *ptr, vx_size stride); From 51bcfe13f9df1734a03fb5d804060441be53c3eb Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:45:54 -0700 Subject: [PATCH 30/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index 03580c2f..a7867336 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -151,7 +151,7 @@ class Array : public Reference * @brief Truncate array to new number of items * * @param new_num_items new number of items - * @return vx_status + * @return vx_status VX_SUCCESS if successful, any other value indicates failure. * @ingroup group_int_array */ vx_status truncate(vx_size new_num_items); From 7471353cdb9ee0d7996fdceaaaacd04336ae1b26 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:46:07 -0700 Subject: [PATCH 31/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index a7867336..fa37d81a 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -157,7 +157,7 @@ class Array : public Reference vx_status truncate(vx_size new_num_items); /** - * @brief Get item type of array + * @brief Get item type of the array * * @return vx_enum * @ingroup group_int_array From ceb975047c1a8b967dd115ef923bde1c55e759ce Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:46:21 -0700 Subject: [PATCH 32/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index fa37d81a..6aea7909 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -159,7 +159,7 @@ class Array : public Reference /** * @brief Get item type of the array * - * @return vx_enum + * @return vx_enum The item type of the array. * @ingroup group_int_array */ vx_enum itemType() const; From 0fa2b3ef6719db70cd3f2f56b96efc0dca650937 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:46:42 -0700 Subject: [PATCH 33/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index 6aea7909..dd84094b 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -167,7 +167,7 @@ class Array : public Reference /** * @brief Get number of items in array * - * @return vx_size + * @return vx_size The number of items in the array. * @ingroup group_int_array */ vx_size numItems() const; From ccfb148a1dedf0ed87d4c59313a38e4d28087924 Mon Sep 17 00:00:00 2001 From: Andrew Mikhail Date: Thu, 31 Jul 2025 14:46:55 -0700 Subject: [PATCH 34/34] Apply suggestion from @amikhail48 --- framework/include/vx_array.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/vx_array.h b/framework/include/vx_array.h index dd84094b..1fea1652 100644 --- a/framework/include/vx_array.h +++ b/framework/include/vx_array.h @@ -175,7 +175,7 @@ class Array : public Reference /** * @brief Get capacity of array * - * @return vx_size + * @return vx_size The capacity of the array. * @ingroup group_int_array */ vx_size totalCapacity() const;