Ticket Name: TDA4VM: if ub960 work in Line-Interleave mode and with 4 camera , how to separate 4 camera image into separate buffers Query Text: Part Number: TDA4VM Other Parts Discussed in Thread: TDA2, EVM board SDK 0804 The ub960 work in line interleave mode with 4 camera , but we find all camera images combine to a single buff. How can we separate the image from the 4 cameras into separate buffers Responses: Hi Jin, You would have to run additional DMA to separate them. There is no reference example in SDK to separate them. Regards, Brijesh hi, can you point out where should we use DMA to separate the image data in sdk Hi, In the SDK, all the demos assume that the DES sends in the data with separate virtual channel. Hence, the SHIM layer stores the buffer in DDR based on the Virtual channel ID. In your case, since the DDR itself has all channels interleaved as one buffer, you would require to do another dma copy to deinterleave from that buffer to another separate buffers in the DDR. However, currently we do not have a out of the box example in the SDK that does the same. Regards, Nikhil Hi Nikhil, Can TDA2 split the interleaved image into 4 buffers without extra DMA copy ? Deinterleaving the bufffer will consume more DDR bandwidth, so ti will low the whole performance, expecially for C7X which needs more throughout. Using another DMA to deinterleave image is not a good solution, do you have other recommendation to relsove the problem? Thank you in advance! BR Yunjie Li Hi Yunjie Li said: Can TDA2 split the interleaved image into 4 buffers without extra DMA copy ? May I know if you are referring to TDA2 or TDA4? I assumed the thread was opened for TDA4VM. In case of csi-rx of TDA4VM, the SHIM layer gives different UDMA PSIL thread based on a VC-DT combination. hongyao.jin said: The ub960 work in line interleave mode with 4 camera , but we find all camera images combine to a single buff. May I know why you require to use UB960 is in this mode? Regards, Nikhil I mean TDA2, the original design adopts TDA2(the solution is provided by other vendor). Now,we want to replace TDA2 with TDA4, so I have to follow the legacy the requirement of peer. I have no idea weather TDA2 can deinterleave the image, do you know the relevant implement of TDA2 ? BR Yunjie Li Hi Li, Do you mean TDA2Px? Because TDA2x doesnot support MIPI input and TDA2Px does support MIPI input via CAL module. CAL module can separate the camera data using virtual channel and data type fields and then can store them in separate buffers. This is same as CSIRX. If it is line interleaved data, CAL and CSIRX both will store them in a same buffer and then you need to separate them using another DMA. I am wondering where this data is processed. Is it going to be processed in the ISP? Regards, Brijesh Brijesh Jadav said: Do you mean TDA2Px? [Yunjie Li]: yes. Brijesh Jadav said: I am wondering where this data is processed. Is it going to be processed in the ISP? [Yunjie Li]: The data is processed by A72, bypass ISP, the format of data is yuv422. We try to use UDMA 2D to deinterleave an interleaved image of 12MB( 4 streams) on MCU2_0, it takes 6ms to get an image (3MB) by triggering UDMA 2D, so 4 images will take 6ms * 4 = 24ms. During this time, other components(C66, C7x)can not access DDR, it comsumes too much resource, the CV algorithm may be not deployed, so the solution does not make sense on TDA4. By the way, the camera is 30 fps. BR Yunjie Li Hi Li, ok, in this case, isn't it better to update CV algorithm to support this line interleaved image? CV algorithm needs to just play with the pitch and start address to get the correct image of each input camera. This will save the DDR BW and also latency.. Regards, Brijesh Brijesh Jadav said: isn't it better to update CV algorithm to support this line interleaved image It is impossible to persuade CV guys to accept it, I will try other method to avoid deinterleaving in SOC. Thank you so much! BR Yunjie Li You can probably use other HW accelerator to separate them. Like DSS M2M path can accept YUV422 and can also output YUV422, so you can use it to separate them. Regards, Brijesh Hi Brijesh, Need you help give more guide about the DSS M2M for customer. do we have some demo code for customer? BR, Biao Hi Brijesh, Customer have done DSS m2m to split this picture. The two source files customer modified and the generated patch file are in the attachment. The log running locally is as follows: Currently, all four tasks are enabled and run together. There is some running latency(around 20ms) issue, it slower than do it via MCU. Need you help to reduce the latency? In addition to the running time problem, it seems that the split image also has some problems and becomes a bit blurry. Can you help review the code? The original large picture, the four small pictures split by python script, and the four small pictures split by DSS M2M are all in below link. https://tidrive.ext.ti.com/u/9lFCH0tRQlfkUUIR/6a1ac96e-36ad-4d8e-be84-750c390b75f3?l 3;rrD8ZY BR, Biao We split the image through the CPU and found that the four images cost a total of 11ms, why does it seem to be faster than DMA and DSSM2M Hongyao, that's great to hear you make this in progress. Did you split/copy and deinterleaved those super-frame by A72 correctly, from the data integrity point of view? BTW, at least for me, it's not surprise at all the empty 2xA72 can do this memcpy better, because the frequency and performance of CPU is very high compared to all the other hardware accelerators. appreciate. yes, the small images split by A72 are normal The figure on the left is separated by memcpy, and the figure on the right is by M2M. It is obvious that the M2M image is superimposed by four images It seems that 4 images are overlayed, or blent. hi Yunjie Li, hongyao jin, Did you take care of cache operations before saving these images into a file? If not, can you check and take care of it? Buffers are typically cached mapped on all cores, so they should not be accessed without cache operation and without cache operation, the content written in the file may not be correct. Also i did not get that small size by A72 is correct?? Do you mean the above performance data is for small size image? and do you only see these one correct? Regards, Brijesh 1. We don't think the cache is causing this problem, because the data in memory is actually modified before and after the M2M operation 2. yes, the two images above are channel 0, one is split by memcpy, the other is split by M2M, but the images of the four channels after splitting by M2M are completely consistent Brijesh, kindly here we need BU urgent support to work out an example, for instance, test_display_m2m.c, in order to fulfill the deinterleaving of super frame by lines of 4x/channels. Technically, as we aligned, the tiovx display node should be extended to support pitching of ovx image object. appreciate. Hi Xu, As discussed over the email, please find attached patch to add support for de-interleaving in DSS M2M node. Please apply this patch on top of ti-processor-sdk-rtos-j721e-evm-08_04_00_06/tiovx folder. In this patch, 1, I have added additional create time parameter “enable_deiniterleave” in DSS M2M tivx_display_m2m_params_t struct. 2, when this flag is set, DSS M2M node expects input as image and output as one of the element of the object array. It expects input frame size to be ‘n’ times the output image size and image format to be same. It also expects the ‘n’ images are line interleaved in the input image exactly at the pitch boundary. 3, the input address is calculated at the pich offset and output image is extracted from the image array. /cfs-file/__key/communityserver-discussions-components-files/791/DSSM2M_5F00_DeInterleave_5F00_Support.patch Regards, Brijesh After patch was applied, it was consistent with the previous phenomenon that split images still failed, and when deinterleave was enabled, the program would be stuck the log when deinterleave is enabled root@p789-adcu1:~# root@p789-adcu1:~# cd /hirain/data/ti_dss_patch/ root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 294 298 312 314 316 DSS_M2M: task id 0 start_time 1699996576 s 261890 us 0.000000 s: VX_ZONE_INFO:[ownNodeKernelValidate:241] Validating kernel com.ti.hwa.displaym2m 0.000000 s: VX_ZONE_INNOTICE: the log when deinterleave is disabled root@p789-adcu1:~# root@p789-adcu1:~# cd /hirain/data/ti_dss_patch/ root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ls -l total 40304 -rw-r--r-- 1 root root 1541 Nov 15 2023 app_multi_cam.cfg -rw-r--r-- 1 root root 13158400 Nov 15 2023 img_raw.yuv -rw-r--r-- 1 root root 28054632 Nov 15 05:17 libtivision_apps.so.8.4.0 -rwxr-xr-x 1 root root 45720 Nov 15 05:16 vx_app_multi_cam.out root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 294 298 312 314 316 DSS_M2M: task id 0 start_time 1699996676 s 346544 us 0.000000 s: VX_ZONE_INFO:[ownNodeKernelValidate:241] Validating kernel com.ti.hwa.displaym2m 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:523] Calling create callback for node node_91 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:529] Create callback for node node_91 completed 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:578] kernel init for node 0, kernel com.ti.hwa.displaym2m ... 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:589] kernel init for node 0, kernel com.ti.hwa.displaym2m ... done !!! 0.000000 s: VX_ZONE_INFO:[ownGraphScheduleGraph:764] Scheduling Graph (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownNodeKernelSchedule:627] Scheduling Node (node=12, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownCheckGraphCompleted:677] Graph Completed (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownCheckGraphCompleted:705] All Graphs Completed 334 DSS_M2M: task id 0 stop_time 1699996676 s 363282 us 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed Received events from Task0 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_nf_generic destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_nf_bilateral destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dmpac_sde destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_ldc destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_msc_multi_scale destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_msc_pyramid destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dmpac_dof destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dof_visualize destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_viss destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.display destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.capture destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.csitx destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.displaym2m destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:Enabled Display M2M Conformance Test Finished... 0.000000 s: VX_ZONE_INIT:[tivxHostDeInitLocal:100] De-Initialization Done for HOST !!! 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:181] Is kernel use failed, index: 0 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:182] kernel name: org.khronos.openvx.absdiff 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:230] Is image use failed, index: 2 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:278] Is error use failed, index: 0 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INIT:[tivxDeInitLocal:193] De-Initialization Done !!! APP: Deinit ... !!! REMOTE_SERVICE: Deinit ... !!! REMOTE_SERVICE: Deinit ... Done !!! IPC: Deinit ... !!! IPC: DeInit ... Done !!! MEM: Deinit ... !!! DDR_SHARED_MEM: Alloc's: 8 alloc's of 52633620 bytes DDR_SHARED_MEM: Free's : 8 free's of 52633620 bytes DDR_SHARED_MEM: Open's : 0 allocs of 0 bytes DDR_SHARED_MEM: Total size: 805306368 bytes MEM: Deinit ... Done !!! APP: Deinit ... Done !!! root@p789-adcu1:/hirain/data/ti_dss_patch# The modified source file is as follows vx_display_m2m_host.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "TI/tivx.h" #include "tivx_hwa_kernels.h" #include "tivx_kernel_display_m2m.h" #include "TI/tivx_target_kernel.h" static vx_kernel vx_display_m2m_kernel = NULL; static vx_status VX_CALLBACK tivxAddKernelDisplayM2MValidate(vx_node node, const vx_reference parameters[ ], vx_uint32 num, vx_meta_format metas[]); static vx_status VX_CALLBACK tivxAddKernelDisplayM2MInitialize(vx_node node, const vx_reference parameters[ ], vx_uint32 num_params); vx_status tivxAddKernelDisplayM2M(vx_context context); vx_status tivxRemoveKernelDisplayM2M(vx_context context); static vx_status VX_CALLBACK tivxAddKernelDisplayM2MValidate(vx_node node, const vx_reference parameters[ ], vx_uint32 num, vx_meta_format metas[]) { vx_status status = (vx_status)VX_SUCCESS; vx_user_data_object configuration = NULL; vx_char configuration_name[VX_MAX_REFERENCE_NAME]; vx_size configuration_size; tivx_display_m2m_params_t params; vx_image input = NULL; vx_uint32 input_w; vx_uint32 input_h; vx_df_image input_fmt; vx_image output = NULL; vx_uint32 output_w; vx_uint32 output_h; vx_df_image output_fmt; if ( (num != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "One or more REQUIRED parameters are set to NULL\n"); } if ((vx_status)VX_SUCCESS == status) { configuration = (vx_user_data_object)parameters[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]; input = (vx_image)parameters[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; output = (vx_image)parameters[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; } /* PARAMETER ATTRIBUTE FETCH */ if ((vx_status)VX_SUCCESS == status) { tivxCheckStatus(&status, vxQueryUserDataObject(configuration, (vx_enum)VX_USER_DATA_OBJECT_NAME, &configuration_name, sizeof(configuration_name))); tivxCheckStatus(&status, vxQueryUserDataObject(configuration, (vx_enum)VX_USER_DATA_OBJECT_SIZE, &configuration_size, sizeof(configuration_size))); tivxCheckStatus(&status, vxQueryImage(input, (vx_enum)VX_IMAGE_WIDTH, &input_w, sizeof(input_w))); tivxCheckStatus(&status, vxQueryImage(input, (vx_enum)VX_IMAGE_HEIGHT, &input_h, sizeof(input_h))); tivxCheckStatus(&status, vxQueryImage(input, (vx_enum)VX_IMAGE_FORMAT, &input_fmt, sizeof(input_fmt))); tivxCheckStatus(&status, vxQueryImage(output, (vx_enum)VX_IMAGE_WIDTH, &output_w, sizeof(output_w))); tivxCheckStatus(&status, vxQueryImage(output, (vx_enum)VX_IMAGE_HEIGHT, &output_h, sizeof(output_h))); tivxCheckStatus(&status, vxQueryImage(output, (vx_enum)VX_IMAGE_FORMAT, &output_fmt, sizeof(output_fmt))); } /* PARAMETER CHECKING */ if ((vx_status)VX_SUCCESS == status) { if ((configuration_size != sizeof(tivx_display_m2m_params_t)) || (strncmp(configuration_name, "tivx_display_m2m_params_t", sizeof(configuration_name)) != 0)) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "'configuration' should be a user_data_object of type:\n tivx_display_m2m_params_t \n"); } else { status = vxCopyUserDataObject(configuration, 0, sizeof(tivx_display_m2m_params_t), ¶ms, (vx_enum)VX_READ_ONLY, (vx_enum)VX_MEMORY_TYPE_HOST); } if ((vx_status)VX_SUCCESS == status) { if(1U != params.numPipe) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "'configuration.numPipe' should be set to 1 as blending is not supported currently \n"); } } if( ((vx_df_image)VX_DF_IMAGE_RGB != input_fmt) && ((vx_df_image)VX_DF_IMAGE_RGBX != input_fmt) && ((vx_df_image)VX_DF_IMAGE_UYVY != input_fmt) && ((vx_df_image)VX_DF_IMAGE_YUYV != input_fmt) && ((vx_df_image)VX_DF_IMAGE_NV12 != input_fmt)) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "'input' should be an image of type:\n VX_DF_IMAGE_RGB or VX_DF_IMAGE_RGBX or VX_DF_IMAGE_UYVY or VX_DF_IMAGE_NV12 \n"); } if( ((vx_df_image)VX_DF_IMAGE_RGB != output_fmt) && ((vx_df_image)VX_DF_IMAGE_RGBX != output_fmt) && ((vx_df_image)VX_DF_IMAGE_UYVY != output_fmt) && ((vx_df_image)VX_DF_IMAGE_YUYV != output_fmt) && ((vx_df_image)VX_DF_IMAGE_NV12 != output_fmt)) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "'output' should be an image of type:\n VX_DF_IMAGE_RGB or VX_DF_IMAGE_RGBX or VX_DF_IMAGE_UYVY or VX_DF_IMAGE_NV12 \n"); } if (params.enable_deiniterleave) { if (input_fmt != output_fmt) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "Input and output formats must be same for de-interleaving\n"); } if (((input_w % output_w) != 0) || ((input_h % output_h) != 0) || ((input_w % output_w) != (input_h % output_h))) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "Incorrect input/output size\n"); } } } return status; } static vx_status VX_CALLBACK tivxAddKernelDisplayM2MInitialize(vx_node node, const vx_reference parameters[ ], vx_uint32 num_params) { vx_status status = (vx_status)VX_SUCCESS; tivxKernelValidRectParams prms; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == parameters[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_ERROR_INVALID_PARAMETERS; VX_PRINT(VX_ZONE_ERROR, "One or more REQUIRED parameters are set to NULL\n"); } if ((vx_status)VX_SUCCESS == status) { tivxKernelValidRectParams_init(&prms); prms.in_img[0U] = (vx_image)parameters[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; prms.out_img[0U] = (vx_image)parameters[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; prms.num_input_images = 1; prms.num_output_images = 1; prms.top_pad = 0; prms.bot_pad = 0; prms.left_pad = 0; prms.right_pad = 0; prms.border_mode = VX_BORDER_UNDEFINED; status = tivxKernelConfigValidRect(&prms); } return status; } vx_status tivxAddKernelDisplayM2M(vx_context context) { vx_kernel kernel; vx_status status; uint32_t index; vx_enum kernel_id; status = vxAllocateUserKernelId(context, &kernel_id); if(status != (vx_status)VX_SUCCESS) { VX_PRINT(VX_ZONE_ERROR, "Unable to allocate user kernel ID\n"); } if (status == (vx_status)VX_SUCCESS) { kernel = vxAddUserKernel( context, TIVX_KERNEL_DISPLAY_M2M_NAME, kernel_id, NULL, TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS, tivxAddKernelDisplayM2MValidate, tivxAddKernelDisplayM2MInitialize, NULL); status = vxGetStatus((vx_reference)kernel); } if (status == (vx_status)VX_SUCCESS) { index = 0; { status = vxAddParameterToKernel(kernel, index, (vx_enum)VX_INPUT, (vx_enum)VX_TYPE_USER_DATA_OBJECT, (vx_enum)VX_PARAMETER_STATE_REQUIRED ); index++; } if (status == (vx_status)VX_SUCCESS) { status = vxAddParameterToKernel(kernel, index, (vx_enum)VX_INPUT, (vx_enum)VX_TYPE_IMAGE, (vx_enum)VX_PARAMETER_STATE_REQUIRED ); index++; } if (status == (vx_status)VX_SUCCESS) { status = vxAddParameterToKernel(kernel, index, (vx_enum)VX_OUTPUT, (vx_enum)VX_TYPE_IMAGE, (vx_enum)VX_PARAMETER_STATE_REQUIRED ); index++; } if (status == (vx_status)VX_SUCCESS) { /* add supported target's */ tivxAddKernelTarget(kernel, TIVX_TARGET_DISPLAY_M2M1); tivxAddKernelTarget(kernel, TIVX_TARGET_DISPLAY_M2M2); tivxAddKernelTarget(kernel, TIVX_TARGET_DISPLAY_M2M3); tivxAddKernelTarget(kernel, TIVX_TARGET_DISPLAY_M2M4); } if (status == (vx_status)VX_SUCCESS) { status = vxFinalizeKernel(kernel); } if (status != (vx_status)VX_SUCCESS) { vxReleaseKernel(&kernel); kernel = NULL; } } else { kernel = NULL; } vx_display_m2m_kernel = kernel; return status; } vx_status tivxRemoveKernelDisplayM2M(vx_context context) { vx_status status; vx_kernel kernel = vx_display_m2m_kernel; status = vxRemoveKernel(kernel); vx_display_m2m_kernel = NULL; return status; } void tivx_display_m2m_params_init(tivx_display_m2m_params_t *prms) { uint32_t loopCnt; prms->instId = 0U; prms->numPipe = 1U; for (loopCnt = 0U ; loopCnt < TIVX_DISPLAY_M2M_MAX_PIPE ; loopCnt++) { prms->pipeId[loopCnt] = 1U; } prms->overlayId = 0U; prms->enable_deiniterleave = 1u; } 3757.vx_display_m2m_target.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include "TI/tivx.h" #include "VX/vx.h" #include "TI/tivx_event.h" #include "tivx_hwa_kernels.h" #include "tivx_kernel_display_m2m.h" #include "TI/tivx_target_kernel.h" #include "tivx_kernels_target_utils.h" #include "tivx_hwa_display_m2m_priv.h" #include #include #include #include #include #define DISPLAY_MAX_VALID_PLANES 2U #define DISPLAY_M2M_MAX_HANDLES (10) typedef struct { /*! IDs=> 0: Write-back pipe-line1 */ uint32_t instId; /*! Number of pipe-lines used, should be set to '1' as blending is not supported currently */ uint32_t numPipe; /*! IDs=> 0:VID1, 1:VIDL1, 2:VID2 and 3:VIDL2 */ uint32_t pipeId[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! IDs=> 0:Overlay1, 1:Overlay2, 2:Overlay3 and 3:Overlay4 */ uint32_t overlayId; /*! FVID2 display driver handle */ Fvid2_Handle drvHandle; /*! WB pipe create parameters */ Dss_WbCreateParams createParams; /*! WB pipe create status */ Dss_WbCreateStatus createStatus; /*! Callback parameters */ Fvid2_CbParams cbParams; /*! WB pipe status */ Dss_WbStatus wbStatus; /*! WB pipe configuration */ Dss_WbPipeCfgParams wbCfg; /*! WB pipe DMA configuration */ CSL_DssWbPipeDmaCfg wbDmaCfg; /*! WB pipe MFlag configuration */ Dss_WbPipeMflagParams wbMflagCfg; /*! WB pipe CSC configuration */ CSL_DssCscCoeff wbCscCfg; /*! Display pipe configuration */ Dss_PipeCfgParams pipeCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe MFlag configuration */ Dss_PipeMflagParams mFlagCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe CSC configuration */ Dss_PipeCscParams cscCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display Overlay configuration */ Dss_DctrlOverlayParams ovrCfg; /*! Display Layer configuration */ Dss_DctrlOverlayLayerParams layerCfg; /*! Display Global configuration */ Dss_DctrlGlobalDssParams globalParams; /*! Mutex used for waiting for process completion */ tivx_event waitForProcessCmpl; /*! Display M2M Driver Input Frame List, used for providing * an array of input frames */ Fvid2_FrameList inFrmList; /*! Display M2M Driver Output Frame List, used for providing * an array of output frames */ Fvid2_FrameList outFrmList; /*! Display M2M Driver Input Frames */ Fvid2_Frame inFrm[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display M2M Driver Output Frames */ Fvid2_Frame outFrm[1U]; } tivxDisplayM2MDrvObj; typedef struct { /*! IDs=> 0: Object free, 1: allocated */ uint32_t isAlloc; /*! Display M2M driver object */ tivxDisplayM2MDrvObj drvObj; /*! Display M2M Node create parameters provided by application */ tivx_display_m2m_params_t createParams; uint32_t numOutImgs; } tivxDisplayM2MParams; typedef struct { tivx_mutex lock; tivxDisplayM2MParams m2mObj[DISPLAY_M2M_MAX_HANDLES]; } tivxDisplayM2MInstObj; static tivx_target_kernel vx_display_m2m_target_kernel1 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel2 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel3 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel4 = NULL; tivxDisplayM2MInstObj gTivxDispM2mInstObj; static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut); static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj); static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj); static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData); static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format); static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj); static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj); static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_obj_desc_image_t *input_desc; tivx_obj_desc_image_t *output_desc; void *input_target_ptr, *input_target_ptr2 = NULL; void *output_target_ptr, *output_target_ptr2 = NULL; Fvid2_Frame *frm; int32_t fvid2_status = FVID2_SOK; uint32_t pipeIdx, iterCnt; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } if((vx_status)VX_SUCCESS == status) { uint32_t size; input_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; output_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "DISPLAY M2M: ERROR: Instance context is NULL!\r\n"); } } if((vx_status)VX_SUCCESS == status) { /* Update 'input_desc' to array from only single image input to support blending i.e. more than 1 number of pipes. */ input_target_ptr = tivxMemShared2TargetPtr(&input_desc->mem_ptr[0]); VX_PRINT(VX_ZONE_INFO, "input_target_ptr = %p\n", input_target_ptr); if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { input_target_ptr2 = tivxMemShared2TargetPtr(&input_desc->mem_ptr[1]); VX_PRINT(VX_ZONE_INFO, "input_target_ptr2 = %p\n", input_target_ptr2); } for (iterCnt = 0u; iterCnt < prms->numOutImgs; iterCnt ++) { output_desc = (tivx_obj_desc_image_t *) tivxGetObjDescElement(obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX],iterCnt); output_target_ptr = tivxMemShared2TargetPtr(&output_desc->mem_ptr[0]); VX_PRINT(VX_ZONE_INFO, "output_target_ptr = %p\n", output_target_ptr); if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { output_target_ptr2 = tivxMemShared2TargetPtr(&output_desc->mem_ptr[1]); VX_PRINT(VX_ZONE_INFO, "output_target_ptr2 = %p\n", output_target_ptr2); } /* call kernel processing function */ drvObj = &prms->drvObj; /* Assign input buffer addresses */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = &drvObj->inFrm[pipeIdx]; frm->addr[0U] = ((uint64_t)input_target_ptr) + iterCnt*input_desc->imagepatch_addr[0].stride_y; if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { frm->addr[1U] = ((uint64_t)input_target_ptr2) + iterCnt*input_desc->imagepatch_addr[1].stride_y; } } /* Assign output buffer addresses */ frm = drvObj->outFrm; frm->addr[0U] = (uint64_t)output_target_ptr; if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { frm->addr[1U] = (uint64_t)output_target_ptr2; } /* Submit the request to the driver */ fvid2_status = Fvid2_processRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, FVID2_TIMEOUT_FOREVER); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Submit Request\n"); status = (vx_status)VX_FAILURE; } else { /* Wait for Frame Completion */ tivxEventWait(drvObj->waitForProcessCmpl, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); fvid2_status = Fvid2_getProcessedRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, 0); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); status = (vx_status)VX_FAILURE; } } } /* kernel processing function complete */ } return status; } static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivx_obj_desc_user_data_object_t *configuration_desc; tivx_obj_desc_image_t *obj_desc_imageIn, *obj_desc_imageOut; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { configuration_desc = (tivx_obj_desc_user_data_object_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]; obj_desc_imageIn = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; obj_desc_imageOut = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; if (configuration_desc->mem_size != sizeof(tivx_display_m2m_params_t)) { VX_PRINT(VX_ZONE_ERROR, "User data object size on target does not match the size on host, possibly due to misalignment in data structure\n"); status = (vx_status)VX_FAILURE; } prms = tivxDispM2mAllocObject(&gTivxDispM2mInstObj); if (NULL == prms) { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } /* Create Node object elements */ if ((vx_status)VX_SUCCESS == status) { status = tivxDisplayM2MSetCreateParams(prms, configuration_desc, obj_desc_imageIn, obj_desc_imageOut); } /* Create sync events */ if (status == (vx_status)VX_SUCCESS) { status = tivxEventCreate(&prms->drvObj.waitForProcessCmpl); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to allocate Event\n"); } } /* DSS M2M Driver create and configuration */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvCfg(&prms->drvObj); } if ((vx_status)VX_SUCCESS == status) { tivxSetTargetKernelInstanceContext(kernel, prms, sizeof(tivxDisplayM2MParams)); } else { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; uint32_t size; int32_t fvid2_status = FVID2_SOK; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: Could not obtain kernel instance context !!!\n"); } if(NULL == prms) { VX_PRINT(VX_ZONE_ERROR, "Kernel instance context is NULL!!!\n"); status = (vx_status)VX_FAILURE; } if ((vx_status)VX_SUCCESS == status) { /* Stop Display M2M Driver */ fvid2_status = Fvid2_stop(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 DSS M2M not stopped !!!\n"); } } if ((vx_status)VX_SUCCESS == status) { /* Dequeue all the request from the driver */ while ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_getProcessedRequest(prms->drvObj.drvHandle, &prms->drvObj.inFrmList, &prms->drvObj.outFrmList, 0); if (FVID2_SOK != fvid2_status) { if (fvid2_status != FVID2_ENO_MORE_BUFFERS) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); } status = (vx_status)VX_FAILURE; } } if (fvid2_status == FVID2_ENO_MORE_BUFFERS) { status = (vx_status)VX_SUCCESS; } } if ((vx_status)VX_SUCCESS == status) { /* print status */ fvid2_status = Fvid2_control(prms->drvObj.drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &prms->drvObj.wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { printf( "==========================================================\r\n"); printf( " Display M2M Status: Instance|%d\r\n", prms->drvObj.instId); printf( "==========================================================\r\n"); printf( " Queue Count: %d\r\n", prms->drvObj.wbStatus.queueCount); printf( " De-queue Count: %d\r\n", prms->drvObj.wbStatus.dequeueCount); printf( " Write-back Frames Count: %d\r\n", prms->drvObj.wbStatus.wbFrmCount); printf( " Underflow Count: %d\r\n", prms->drvObj.wbStatus.underflowCount); } } if ((vx_status)VX_SUCCESS == status) { /* Delete FVID2 handle */ fvid2_status = Fvid2_delete(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 Delete Failed !!!\n"); } else { prms->drvObj.drvHandle = NULL; } } if ((vx_status)VX_SUCCESS == status) { /* Delete event */ tivxEventDelete(&prms->drvObj.waitForProcessCmpl); } if ((NULL != prms) && (sizeof(tivxDisplayM2MParams) == size)) { tivxDispM2mFreeObject(&gTivxDispM2mInstObj, prms); //tivxMemFree(prms, size, (vx_enum)TIVX_MEM_EXTERNAL); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; int32_t fvid2_status = FVID2_SOK; uint32_t size; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_display_m2m_statistics_t *m2m_status_prms = NULL; void *target_ptr; tivx_obj_desc_user_data_object_t *usr_data_obj; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; } if (status == (vx_status)VX_SUCCESS) { switch (node_cmd_id) { case TIVX_DISPLAY_M2M_GET_STATISTICS: { if (NULL != obj_desc[0]) { drvObj = &prms->drvObj; fvid2_status = Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &drvObj->wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { /* Update return status object */ usr_data_obj = (tivx_obj_desc_user_data_object_t *)obj_desc[0U]; target_ptr = tivxMemShared2TargetPtr(&usr_data_obj->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); if (sizeof(tivx_display_m2m_statistics_t) == usr_data_obj->mem_size) { m2m_status_prms = (tivx_display_m2m_statistics_t *)target_ptr; m2m_status_prms->queueCount = drvObj->wbStatus.queueCount; m2m_status_prms->dequeueCount = drvObj->wbStatus.dequeueCount; m2m_status_prms->wbFrmCount = drvObj->wbStatus.wbFrmCount; m2m_status_prms->underflowCount = drvObj->wbStatus.underflowCount; } else { VX_PRINT(VX_ZONE_ERROR, "Invalid Size \n"); status = (vx_status)VX_ERROR_INVALID_PARAMETERS; } tivxCheckStatus(&status, tivxMemBufferUnmap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); } } else { VX_PRINT(VX_ZONE_ERROR, "User data object was NULL\n"); status = (vx_status)VX_FAILURE; } break; } default: { VX_PRINT(VX_ZONE_ERROR, "Invalid Command Id\n"); status = (vx_status)VX_FAILURE; break; } } } return status; } void tivxAddTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_FAILURE; char target_name[TIVX_TARGET_MAX_NAME]; vx_enum self_cpu; self_cpu = tivxGetSelfCpuId(); if ( self_cpu == (vx_enum)TIVX_CPU_ID_MCU2_0 ) { strncpy(target_name, TIVX_TARGET_DISPLAY_M2M1, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel1 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M2, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel2 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M3, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel3 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M4, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel4 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); status = tivxMutexCreate(&gTivxDispM2mInstObj.lock); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to create Mutex\n"); } else { memset(&gTivxDispM2mInstObj.m2mObj, 0x0, sizeof(tivxDisplayM2MParams) * DISPLAY_M2M_MAX_HANDLES); } } } void tivxRemoveTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_SUCCESS; status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel1); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel1 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel2); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel2 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel3); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel3 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel4); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel4 = NULL; } if (NULL != gTivxDispM2mInstObj.lock) { tivxMutexDelete(&gTivxDispM2mInstObj.lock); } } static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut) { vx_status status = (vx_status)VX_SUCCESS; void *cfgPtr; tivx_display_m2m_params_t *createParams; tivxDisplayM2MDrvObj *drvObj; uint32_t pipeIdx, layerIdx, pitchIdx; Dss_DispParams *dispParams; CSL_DssWbPipeCfg *wbPipeCfg; Dss_DctrlOverlayParams *ovrParams; Dss_DctrlOverlayLayerParams *layerParams; Fvid2_Frame *frm; cfgPtr = tivxMemShared2TargetPtr(&obj_desc->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(cfgPtr, obj_desc->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_READ_ONLY)); if (status == (vx_status)VX_SUCCESS) { createParams = (tivx_display_m2m_params_t *)cfgPtr; memcpy(&prms->createParams, createParams, sizeof(tivx_display_m2m_params_t)); drvObj = &prms->drvObj; /* Set Driver object */ drvObj->instId = createParams->instId; drvObj->numPipe = createParams->numPipe; drvObj->overlayId = createParams->overlayId; memcpy(&drvObj->pipeId[0U], &createParams->pipeId[0U], sizeof(createParams->pipeId)); if (createParams->enable_deiniterleave) { tivx_obj_desc_t *obj_desc = (tivx_obj_desc_t *)obj_desc_imageOut; if((vx_enum)obj_desc->type==(vx_enum)TIVX_OBJ_DESC_OBJARRAY) { tivx_obj_desc_object_array_t *obj_desc_obj_array; obj_desc_obj_array = (tivx_obj_desc_object_array_t *)obj_desc; prms->numOutImgs = 4;//obj_desc_obj_array->num_items; } else { if ((vx_enum)TIVX_OBJ_DESC_INVALID != (vx_enum)obj_desc->scope_obj_desc_id) { tivx_obj_desc_object_array_t *parent_obj_desc = NULL; tivxGetObjDescList( &obj_desc->scope_obj_desc_id, (tivx_obj_desc_t**)&parent_obj_desc, 1); if (parent_obj_desc != NULL) { prms->numOutImgs = 4;//parent_obj_desc->num_items; } else { prms->numOutImgs = 4u; } } else { prms->numOutImgs = 4u; } } } else { prms->numOutImgs = 4u; } } /* Initialize driver object */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvStructsInit(drvObj); } /* set driver object parameters */ if (status == (vx_status)VX_SUCCESS) { /* Callback parameters */ drvObj->cbParams.cbFxn = (Fvid2_CbFxn) (&tivxDisplayM2MCallback); drvObj->cbParams.appData = drvObj; drvObj->createParams.numPipe = drvObj->numPipe; drvObj->createParams.overlayId = drvObj->overlayId; /* Set Display pipeline parameters */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { dispParams = &drvObj->pipeCfg[pipeIdx].cfgParams; drvObj->createParams.pipeId[pipeIdx] = drvObj->pipeId[pipeIdx]; drvObj->pipeCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->mFlagCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->cscCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; dispParams->pipeCfg.pipeType = CSL_DSS_VID_PIPE_TYPE_VID; dispParams->layerPos.startX = 0U; dispParams->layerPos.startY = 0U; dispParams->pipeCfg.scEnable = FALSE; dispParams->alphaCfg.globalAlpha = 0xFFU; dispParams->alphaCfg.preMultiplyAlpha = FALSE; status = tivxDisplayExtractFvid2Format( obj_desc_imageIn, &dispParams->pipeCfg.inFmt); if (status == (vx_status)VX_SUCCESS) { /* Set video pipe output frame dimensions same as input as no scaling is done in video pipe-line */ dispParams->pipeCfg.outWidth = dispParams->pipeCfg.inFmt.width; dispParams->pipeCfg.outHeight = dispParams->pipeCfg.inFmt.height; if (createParams->enable_deiniterleave) { for (pitchIdx = 0; pitchIdx < 3; pitchIdx ++) { dispParams->pipeCfg.inFmt.pitch[pitchIdx] = dispParams->pipeCfg.inFmt.pitch[pitchIdx] * prms->numOutImgs; } } } else { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); break; } } /* Set Display WB pipeline parameters */ if (((vx_status)VX_SUCCESS == status) && (pipeIdx > 0)) { wbPipeCfg = &drvObj->wbCfg.pipeCfg; /* Set WB pipe input frame dimensions same as video pipe input/output frame, no scaling is done in video pipe, it will be done in WB pipe-line */ wbPipeCfg->inFmt.width = dispParams->pipeCfg.outWidth; wbPipeCfg->inFmt.height = dispParams->pipeCfg.outHeight; wbPipeCfg->inPos.startX = 0U; wbPipeCfg->inPos.startY = 0U; status = tivxDisplayExtractFvid2Format(obj_desc_imageOut, &wbPipeCfg->outFmt); if (status != (vx_status)VX_SUCCESS) { VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); status = (vx_status)VX_FAILURE; } else { if ((wbPipeCfg->inFmt.width != wbPipeCfg->outFmt.width) || (wbPipeCfg->inFmt.height != wbPipeCfg->outFmt.height)) { wbPipeCfg->scEnable = TRUE; } } } /* Set Display WB pipeline parameters */ if ((vx_status)VX_SUCCESS == status) { ovrParams = &drvObj->ovrCfg; ovrParams->overlayId = drvObj->overlayId; ovrParams->colorbarEnable = FALSE; ovrParams->overlayCfg.colorKeyEnable = FALSE; ovrParams->overlayCfg.colorKeySel = CSL_DSS_OVERLAY_TRANS_COLOR_DEST; ovrParams->overlayCfg.backGroundColor = 0xc8c800U; layerParams = &drvObj->layerCfg; layerParams->overlayId = drvObj->overlayId; /* Set all layer to invalid first and then update only used ones */ for(layerIdx = 0U ; layerIdx < CSL_DSS_VID_PIPE_ID_MAX ; layerIdx++) { layerParams->pipeLayerNum[layerIdx] = CSL_DSS_OVERLAY_LAYER_INVALID; } /* Currently blending is not supported so only one layer is used. This code needs to updated when blending is supported. */ layerParams->pipeLayerNum[drvObj->createParams.pipeId[0U]] = CSL_DSS_OVERLAY_LAYER_NUM_0; } /* Update frame-lists */ if ((vx_status)VX_SUCCESS == status) { drvObj->inFrmList.numFrames = drvObj->numPipe; for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = (Fvid2_Frame *) &drvObj->inFrm[pipeIdx]; frm->chNum = drvObj->createParams.pipeId[pipeIdx]; drvObj->inFrmList.frames[pipeIdx] = frm; } frm = (Fvid2_Frame *) &drvObj->outFrm[0U]; drvObj->outFrmList.frames[0U] = frm; drvObj->outFrmList.numFrames = 1U; } } return status; } static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; /* Initialize driver create parameters */ Dss_m2mCreateParamsInit(&drvObj->createParams); /* Initialize driver call-back parameters */ Fvid2CbParams_init(&drvObj->cbParams); /* Initialize driver pipe configuration parameters */ for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { Dss_dispParamsInit(&drvObj->pipeCfg[loopCnt].cfgParams); Dss_dispPipeMflagParamsInit(&drvObj->mFlagCfg[loopCnt].mFlagCfg); CSL_dssCscCoeffInit(&drvObj->cscCfg[loopCnt].csc); } /* Initialize WB pipeline parameters */ Dss_m2mPipeCfgParamsInit(&drvObj->wbCfg); CSL_dssWbPipeDmaCfgInit(&drvObj->wbDmaCfg); Dss_m2mMFlagParamsInit(&drvObj->wbMflagCfg); CSL_dssCscCoeffInit(&drvObj->wbCscCfg); Dss_m2mStatusInit(&drvObj->wbStatus); /* Initialize Display overlay parameters */ Dss_dctrlOverlayParamsInit(&drvObj->ovrCfg); Dss_dctrlOverlayLayerParamsInit(&drvObj->layerCfg); /* Initialize Display global parameters */ Dss_dctrlGlobalDssParamsInit(&drvObj->globalParams); /* Initialize input and output frame lists */ Fvid2FrameList_init(&drvObj->inFrmList); Fvid2FrameList_init(&drvObj->outFrmList); return status; } static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; int32_t fvid2_status = FVID2_SOK; /* Display M2M Driver create */ drvObj->drvHandle = Fvid2_create(DSS_M2M_DRV_ID, drvObj->instId, &drvObj->createParams, &drvObj->createStatus, &drvObj->cbParams); if((NULL == drvObj->drvHandle) || (drvObj->createStatus.retVal != FVID2_SOK)) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Create Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } /* Display M2M pipe configuration */ if ((vx_status)VX_SUCCESS == status) { for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_PARAMS, &drvObj->pipeCfg[loopCnt], NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_MFLAG_PARAMS, &drvObj->mFlagCfg[loopCnt], NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M DISP IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; break; } } } /* Display M2M overlay configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_OVERLAY_PARAMS, &drvObj->ovrCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_LAYER_PARAMS, &drvObj->layerCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Overlay IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M global configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_GLOBAL_DSS_PARAMS, &drvObj->globalParams, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Global IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M write-back pipe configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_PARAMS, &drvObj->wbCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_MFLAG_PARAMS, &drvObj->wbMflagCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_DMA_CFG, &drvObj->wbDmaCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M WB IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Start Display M2M Driver */ if ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_start(drvObj->drvHandle, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Driver Start Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } return status; } static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData) { tivxDisplayM2MDrvObj *drvObj = (tivxDisplayM2MDrvObj *)(appData); if ((NULL != drvObj) && (drvObj->waitForProcessCmpl != NULL)) { tivxEventPost(drvObj->waitForProcessCmpl); } return (vx_status)VX_SUCCESS; } static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format) { vx_status status = (vx_status)VX_SUCCESS; Fvid2Format_init(format); format->width = obj_desc_img->imagepatch_addr[0].dim_x; format->height = obj_desc_img->imagepatch_addr[0].dim_y; format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->scanFormat = FVID2_SF_PROGRESSIVE; switch (obj_desc_img->format) { case (vx_df_image)TIVX_DF_IMAGE_RGB565: format->dataFormat = FVID2_DF_BGR16_565; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGB: format->dataFormat = FVID2_DF_RGB24_888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGBX: format->dataFormat = FVID2_DF_RGBX24_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)TIVX_DF_IMAGE_BGRX: format->dataFormat = FVID2_DF_BGRX32_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_UYVY: format->dataFormat = FVID2_DF_YUV422I_UYVY; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_YUYV: format->dataFormat = FVID2_DF_YUV422I_YUYV; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_NV12: format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[1].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U16: format->ccsFormat = FVID2_CCSF_BITS12_UNPACKED16; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U8: format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; default: status = (vx_status)VX_FAILURE; break; } return status; } static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj) { uint32_t cnt; tivxDisplayM2MParams *m2mObj = NULL; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (0U == instObj->m2mObj[cnt].isAlloc) { m2mObj = &instObj->m2mObj[cnt]; memset(m2mObj, 0x0, sizeof(tivxDisplayM2MParams)); instObj->m2mObj[cnt].isAlloc = 1U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); return (m2mObj); } static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj) { uint32_t cnt; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (m2mObj == &instObj->m2mObj[cnt]) { m2mObj->isAlloc = 0U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); } main_linux_arm.c /* * * Copyright (c) 2017 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include FILE *fp_src_img = NULL; char file_name[20] = "file_name"; FILE *fp_dst_img[4] = {0}; uint32_t payload = 0; void *virt_addr1 = NULL; void *virt_addr2 = NULL; uint64_t phys_addr1 = 0; uint64_t phys_addr2 = 0; uint8_t *src_buf = NULL, *dest_buf = NULL; uint32_t width = 1280U; uint32_t pitch = 4U*2*1280U; uint32_t height = 1285U; uint32_t size = 0; uint8_t *image_test = NULL; void timer_print_start(int task_id) { struct timeval tv1; gettimeofday(&tv1, NULL); printf("DSS_M2M: task id %d start_time %ld s %ld us\n", task_id, tv1.tv_sec, tv1.tv_usec); } void timer_print_stop(int task_id) { struct timeval tv1; gettimeofday(&tv1, NULL); printf("DSS_M2M: task id %d stop_time %ld s %ld us\n", task_id, tv1.tv_sec, tv1.tv_usec); } int main(int argc, char *argv[]) { int status = 0; width = 1280U; pitch = 4U*2*1280U; height = 1285U; size = pitch*height; status = appInit(); if(status==0) { //int app_multi_cam_main(int argc, char* argv[]); //status = app_multi_cam_main(argc, argv); { extern void main_dss_m2m_test(); virt_addr1 = appMemAlloc(APP_MEM_HEAP_DDR, size, 0); virt_addr2 = appMemAlloc(APP_MEM_HEAP_DDR, size, 0); if (virt_addr1 == NULL || virt_addr2 == NULL) { printf("UDMA: MEM alloc fail !"); } src_buf = (uint8_t*)virt_addr1; dest_buf = (uint8_t*)virt_addr2; fp_src_img = fopen("img_raw.yuv", "r"); fread(src_buf, width*pitch, 1, fp_src_img); //system("sync"); sleep(2); main_dss_m2m_test(); #if 0 timer_print_start(7); for(int j = 0; j < 4; j++) { for(int i = 0; i < height; i++) { memcpy(&dest_buf[j*width*2U*height + i*width*2U], &src_buf[j*width*2U + i*pitch], width*2U); } } timer_print_stop(7); #endif //system("sync"); sleep(2); for(int i = 0; i < 4; i++) { sprintf(file_name, "img_raw_ch%d.yuv", i); fp_dst_img[i] = fopen(file_name, "w"); fwrite(&dest_buf[i*width*height*2U], width*height*2U, 1, fp_dst_img[i]); } } appDeInit(); } return status; } test_display_m2m.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include "test_engine/test.h" #include #include #include #include #include "math.h" #include #include #include "test_tiovx/test_tiovx.h" #include "test_hwa_common.h" #define TIVX_TARGET_DEFAULT_STACK_SIZE (256U * 1024U) #define TIVX_TARGET_DEFAULT_TASK_PRIORITY1 (8u) #define DSS_M2M_NUM_CH (1U) #define DSS_M2M_NUM_CH_MAX (4U) /* Common Configurations across channels */ #define DSS_M2M_WB_PIPE_INST_ID (0U) #define DSS_M2M_PIPE_NUM (1U) #define DSS_M2M_PIPE_INST_ID (3U) /* Currently Only Overlay2 can be used for M2M operations, this can be changed through DSS initialization API available in vision_apps */ #define DSS_M2M_OVERLAY_ID (3U) /* Channel 0 configurations */ #define DSS_M2M_CH0_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH0_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH0_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH0_IN_FRAME_BPP (2U) #define DSS_M2M_CH0_IN_FRAME_PITCH (DSS_M2M_CH0_IN_FRAME_WIDTH * \ DSS_M2M_CH0_IN_FRAME_BPP * 4) #define DSS_M2M_CH0_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH0_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH0_OUT_FRAME_HEIGHT (1285U) /* Channel 1 configurations */ #define DSS_M2M_CH1_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH1_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH1_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH1_IN_FRAME_BPP (2U) #define DSS_M2M_CH1_IN_FRAME_PITCH (DSS_M2M_CH1_IN_FRAME_WIDTH * \ DSS_M2M_CH1_IN_FRAME_BPP * 4) #define DSS_M2M_CH1_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH1_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH1_OUT_FRAME_HEIGHT (1285U) /* Channel 2 configurations */ #define DSS_M2M_CH2_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH2_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH2_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH2_IN_FRAME_BPP (2U) #define DSS_M2M_CH2_IN_FRAME_PITCH (DSS_M2M_CH2_IN_FRAME_WIDTH * \ DSS_M2M_CH2_IN_FRAME_BPP * 4) #define DSS_M2M_CH2_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH2_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH2_OUT_FRAME_HEIGHT (1285U) /* Channel 3 configurations */ #define DSS_M2M_CH3_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH3_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH3_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH3_IN_FRAME_BPP (2U) #define DSS_M2M_CH3_IN_FRAME_PITCH (DSS_M2M_CH3_IN_FRAME_WIDTH * \ DSS_M2M_CH3_IN_FRAME_BPP * 4) #define DSS_M2M_CH3_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH3_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH3_OUT_FRAME_HEIGHT (1285U) #define DSS_M2M_NODE_NAME_LEN_MAX (100U) /* Preloaded image buffers */ /* 1920 x 1080 buffers */ extern uint32_t gTiovxCtDisplayArrayBGR888[1555200]; extern uint32_t gTiovxCtDisplayArrayYUV420NV12[777600]; extern uint32_t gTiovxCtDisplayArrayYUV422[1036800]; TESTCASE(tivxHwaDisplayM2M, CT_VXContext, ct_setup_vx_context, 0) typedef struct { uint32_t taskId; uint32_t instId; uint32_t numPipe; uint32_t pipeId[TIVX_DISPLAY_M2M_MAX_PIPE]; uint32_t overlayId; vx_df_image inFmt; uint32_t inWidth; uint32_t inHeight; uint32_t inBpp; uint32_t inPitch; vx_df_image outFmt; uint32_t outWidth; uint32_t outHeight; uint32_t posX; uint32_t posY; tivx_event eventHandle_TaskFinished; tivx_task taskHandle_m2m; tivx_task_create_params_t taskParams_m2m; char nodeName[DSS_M2M_NODE_NAME_LEN_MAX]; uint32_t iterationCnt; } tivx_display_m2m_test_params_t; typedef struct { const char* name; uint32_t Width; uint32_t Height; uint32_t loopCount; } Arg; #define ADD_WIDTH(testArgName, nextmacro, ...) \ CT_EXPAND(nextmacro(testArgName "/Width=1920", __VA_ARGS__, 1920)) #define ADD_HEIGHT(testArgName, nextmacro, ...) \ CT_EXPAND(nextmacro(testArgName "/Height=1080", __VA_ARGS__, 1080)) #define ADD_LOOP_1000(testArgName, nextmacro, ...) \ CT_EXPAND(nextmacro(testArgName "/loopCount=1000", __VA_ARGS__, 1000)) #define PARAMETERS \ CT_GENERATE_PARAMETERS("DisplayM2M", ADD_WIDTH, ADD_HEIGHT, ADD_LOOP_1000 ,ARG), \ static vx_context context; static uint32_t gLoop_cnt; tivx_display_m2m_test_params_t gTestParams[DSS_M2M_NUM_CH_MAX]; extern uint8_t *src_buf, *dest_buf; static void VX_CALLBACK tivxTask_m2m(void *app_var) { vx_node m2m_node = 0; vx_image in_image = 0; vx_image out_image = 0; vx_user_data_object m2m_config; tivx_display_m2m_params_t local_m2m_config; uint32_t wbFrmCnt = 0U; vx_graph_parameter_queue_params_t m2m_graph_parameters_queue_params_list[1]; vx_map_id map_id; vx_int32 i,j; vx_imagepatch_addressing_t addr; uint16_t *ptr = NULL; vx_imagepatch_addressing_t image_addr; vx_rectangle_t rect; vx_graph m2m_graph = 0; tivx_display_m2m_test_params_t *testParams = (tivx_display_m2m_test_params_t *)app_var; uint32_t status = 0; vx_imagepatch_addressing_t image_addr_from_file, image_addr_from_file2; vx_rectangle_t rect_from_file; vx_map_id map_id1, map_id2; void *data_ptr1, *data_ptr2; ASSERT_VX_OBJECT(m2m_graph = vxCreateGraph(context), VX_TYPE_GRAPH); printf("Graph %d: created...\n", testParams->taskId); /* allocate Input and Output frame refs */ ASSERT_VX_OBJECT(in_image = vxCreateImage(context, testParams->inWidth, testParams->inHeight, testParams->inFmt), VX_TYPE_IMAGE); ASSERT_VX_OBJECT(out_image = vxCreateImage(context, testParams->outWidth, testParams->outHeight, testParams->outFmt), VX_TYPE_IMAGE); vx_object_array out_img_array = vxCreateObjectArray(context, (vx_reference)out_image, 4); vxReleaseImage(&out_image); out_image = (vx_image)vxGetObjectArrayItem(out_img_array, 0); printf("Graph %d: input and output images created...\n", testParams->taskId); image_addr.dim_x = testParams->inWidth; image_addr.dim_y = testParams->inHeight; image_addr.stride_x = testParams->inBpp; image_addr.stride_y = testParams->inPitch; image_addr.scale_x = VX_SCALE_UNITY; image_addr.scale_y = VX_SCALE_UNITY; image_addr.step_x = 1; image_addr.step_y = 1; rect.start_x = 0; rect.start_y = 0; rect.end_x = testParams->inWidth; rect.end_y = testParams->inHeight; printf("Graph %d: input and output images created 2 ...\n", testParams->taskId); printf("%d\n", __LINE__); tivxTaskWaitMsecs(1000); /* Copy reference input image to input buffer */ if (testParams->inFmt == VX_DF_IMAGE_RGB) { vxCopyImagePatch(in_image, &rect, 0, &image_addr, (void *)gTiovxCtDisplayArrayBGR888, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); } else if (testParams->inFmt == VX_DF_IMAGE_YUYV) { vxCopyImagePatch(in_image, &rect, 0, &image_addr, (void *)gTiovxCtDisplayArrayYUV422, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); } else if (testParams->inFmt == VX_DF_IMAGE_UYVY) { rect_from_file.start_x = 0; rect_from_file.start_y = 0; rect_from_file.end_x = testParams->inWidth; rect_from_file.end_y = testParams->inHeight; /* Update input buffer here for other formats */ status = vxMapImagePatch(in_image, &rect_from_file, 0, &map_id1, &image_addr_from_file, &data_ptr1, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X); if(status != 0) { printf("vxMapImagePatch failed. \n"); } printf("%d\n", __LINE__); memcpy(data_ptr1, &src_buf[1280U*2U*testParams->taskId], 1280U*2U*(1285U*4U - testParams->taskId)); } printf("%d\n", __LINE__); /* DSS M2M initialization */ tivx_display_m2m_params_init(&local_m2m_config); local_m2m_config.instId = testParams->instId; /* Only one pipeline is supported */ local_m2m_config.numPipe = testParams->numPipe; local_m2m_config.pipeId[0U] = testParams->pipeId[0U]; local_m2m_config.overlayId = testParams->overlayId; ASSERT_VX_OBJECT(m2m_config = vxCreateUserDataObject(context, "tivx_display_m2m_params_t", sizeof(tivx_display_m2m_params_t), &local_m2m_config), (enum vx_type_e)VX_TYPE_USER_DATA_OBJECT); printf("%d\n", __LINE__); ASSERT_VX_OBJECT(m2m_node = tivxDisplayM2MNode(m2m_graph, m2m_config, in_image, out_image), VX_TYPE_NODE); printf("%d\n", __LINE__); VX_CALL(vxSetNodeTarget(m2m_node, VX_TARGET_STRING, &testParams->nodeName[0U])); printf("%d\n", __LINE__); // printf("Added \'%s\' node in graph %d\n", &testParams->nodeName[0U], testParams->taskId); // printf("Graph %d: verifying...\n", testParams->taskId); // VX_CALL(vxVerifyGraph(m2m_graph)); // printf("Graph %d: verify done...\n", testParams->taskId); { extern void timer_print_start(int task_id); timer_print_start(testParams->taskId); } //for (wbFrmCnt = 0U ; wbFrmCnt < testParams->iterationCnt ; wbFrmCnt++) { VX_CALL(vxProcessGraph(m2m_graph)); } printf("%d\n", __LINE__); { extern void timer_print_stop(int task_id); timer_print_stop(testParams->taskId); } { for(int i = 0; i < 4; i++) { out_image = (vx_image)vxGetObjectArrayItem(out_img_array, i); rect_from_file.start_x = 0; rect_from_file.start_y = 0; rect_from_file.end_x = testParams->outWidth; rect_from_file.end_y = testParams->outHeight; /* Update input buffer here for other formats */ status = vxMapImagePatch(out_image, &rect_from_file, 0, &map_id2, &image_addr_from_file2, &data_ptr2, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X); if(status != 0) { printf("vxMapImagePatch failed 2. \n"); } memcpy(&dest_buf[1280U*1285U*2U*i], data_ptr2, 1280U*1285U*2U); } } VX_CALL(vxReleaseNode(&m2m_node)); VX_CALL(vxReleaseImage(&in_image)); VX_CALL(vxReleaseImage(&out_image)); VX_CALL(vxReleaseUserDataObject(&m2m_config)); VX_CALL(vxReleaseGraph(&m2m_graph)); /*Signal the completion of m2m graph processing*/ tivxEventPost(testParams->eventHandle_TaskFinished); } TEST_WITH_ARG(tivxHwaDisplayM2M, tivxHwaDisplayM2Mtest, Arg, PARAMETERS) { context = context_->vx_context_; uint32_t taskIdx; tivx_display_m2m_test_params_t *testParams; uint32_t createTask = 0U; printf("Starting Display M2M Conformance Test...\n"); /* Initialize global test parameters structure to '0' */ memset(&gTestParams[0U], 0, sizeof(gTestParams)); ASSERT(vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1)); { tivxHwaLoadKernels(context); CT_RegisterForGarbageCollection(context, ct_teardown_hwa_kernels, CT_GC_OBJECT); tivx_set_debug_zone(VX_ZONE_INFO); gLoop_cnt = arg_->loopCount; for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { createTask = 0U; testParams = &gTestParams[taskIdx]; testParams->taskId = taskIdx; ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxEventCreate(&testParams->eventHandle_TaskFinished)); testParams->instId = DSS_M2M_WB_PIPE_INST_ID; testParams->numPipe = DSS_M2M_PIPE_NUM; /* Note: Directly assigning as only one pipe is supported currently */ testParams->pipeId[0U] = DSS_M2M_PIPE_INST_ID; testParams->overlayId = DSS_M2M_OVERLAY_ID; testParams->inFmt = DSS_M2M_CH0_IN_FRAME_FORMAT; testParams->iterationCnt = (gLoop_cnt / (taskIdx + 1U)); switch (taskIdx) { case 0U: /* Initialize test parameters for task 0 */ createTask = 1U; testParams->inWidth = DSS_M2M_CH0_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH0_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH0_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH0_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH0_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH0_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH0_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M1); break; case 1U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH1_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH1_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH1_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH1_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH1_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH1_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH1_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH1_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M2); break; case 2U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH2_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH2_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH2_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH2_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH2_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH2_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH2_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH2_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M3); break; case 3U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH3_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH3_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH3_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH3_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH3_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH3_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH3_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH3_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M4); break; default: break; } if (createTask == 1U) { /* Setting up task params for m2m_task */ tivxTaskSetDefaultCreateParams(&testParams->taskParams_m2m); testParams->taskParams_m2m.task_main = &tivxTask_m2m; testParams->taskParams_m2m.app_var = testParams; testParams->taskParams_m2m.stack_ptr = NULL; testParams->taskParams_m2m.stack_size = TIVX_TARGET_DEFAULT_STACK_SIZE; testParams->taskParams_m2m.core_affinity = TIVX_TASK_AFFINITY_ANY; testParams->taskParams_m2m.priority = TIVX_TARGET_DEFAULT_TASK_PRIORITY1; printf("Creating Task %d...\n", testParams->taskId); /* Create Tasks */ ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxTaskCreate(&testParams->taskHandle_m2m, &testParams->taskParams_m2m)); } } /* wait here for all tasks to finish */ printf("Waiting for graphs to finish execution...\n"); for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; tivxEventWait(testParams->eventHandle_TaskFinished, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); printf("Received events from Task%d\n", testParams->taskId); } /* Delete tasks and sync events */ for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxTaskDelete(&testParams->taskHandle_m2m)); ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxEventDelete(&testParams->eventHandle_TaskFinished)); } tivxHwaUnLoadKernels(context); tivx_set_debug_zone(VX_ZONE_INFO); } printf("Display M2M Conformance Test Finished...\n"); } TESTCASE_TESTS(tivxHwaDisplayM2M, tivxHwaDisplayM2Mtest) void main_dss_m2m_test() { //context = context_->vx_context_; uint32_t taskIdx; tivx_display_m2m_test_params_t *testParams; uint32_t createTask = 0U; uint32_t status = 0; /* Create OpenVx Context */ context = vxCreateContext(); status = vxGetStatus((vx_reference)context); printf("Creating context done status : %d!\n", status); printf("Starting Display M2M Conformance Test...\n"); /* Initialize global test parameters structure to '0' */ memset(&gTestParams[0U], 0, sizeof(gTestParams)); ASSERT(vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1)); { tivxHwaLoadKernels(context); //CT_RegisterForGarbageCollection(context, ct_teardown_hwa_kernels, CT_GC_OBJECT); printf("Starting Display M2M Conformance Test 2...\n"); tivx_set_debug_zone(VX_ZONE_INFO); //gLoop_cnt = arg_->loopCount; gLoop_cnt = 1; for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { createTask = 0U; testParams = &gTestParams[taskIdx]; testParams->taskId = taskIdx; ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxEventCreate(&testParams->eventHandle_TaskFinished)); testParams->instId = DSS_M2M_WB_PIPE_INST_ID; testParams->numPipe = DSS_M2M_PIPE_NUM; /* Note: Directly assigning as only one pipe is supported currently */ testParams->pipeId[0U] = DSS_M2M_PIPE_INST_ID; testParams->overlayId = DSS_M2M_OVERLAY_ID; testParams->inFmt = DSS_M2M_CH0_IN_FRAME_FORMAT; testParams->iterationCnt = gLoop_cnt; switch (taskIdx) { case 0U: /* Initialize test parameters for task 0 */ createTask = 1U; testParams->inWidth = DSS_M2M_CH0_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH0_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH0_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH0_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH0_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH0_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH0_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M1); break; case 1U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH1_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH1_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH1_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH1_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH1_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH1_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH1_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH1_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M2); break; case 2U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH2_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH2_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH2_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH2_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH2_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH2_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH2_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH2_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M3); break; case 3U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH3_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH3_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH3_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH3_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH3_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH3_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH3_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH3_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M4); break; default: break; } if (createTask == 1U) { /* Setting up task params for m2m_task */ tivxTaskSetDefaultCreateParams(&testParams->taskParams_m2m); testParams->taskParams_m2m.task_main = &tivxTask_m2m; testParams->taskParams_m2m.app_var = testParams; testParams->taskParams_m2m.stack_ptr = NULL; testParams->taskParams_m2m.stack_size = TIVX_TARGET_DEFAULT_STACK_SIZE; testParams->taskParams_m2m.core_affinity = TIVX_TASK_AFFINITY_ANY; testParams->taskParams_m2m.priority = TIVX_TARGET_DEFAULT_TASK_PRIORITY1; printf("Creating Task %d...\n", testParams->taskId); /* Create Tasks */ ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxTaskCreate(&testParams->taskHandle_m2m, &testParams->taskParams_m2m)); } } /* wait here for all tasks to finish */ printf("Waiting for graphs to finish execution...\n"); for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; tivxEventWait(testParams->eventHandle_TaskFinished, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); printf("Received events from Task%d\n", testParams->taskId); } /* Delete tasks and sync events */ for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxTaskDelete(&testParams->taskHandle_m2m)); ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxEventDelete(&testParams->eventHandle_TaskFinished)); } tivxHwaUnLoadKernels(context); tivx_set_debug_zone(VX_ZONE_INFO); } printf("Display M2M Conformance Test Finished...\n"); } the log after adding buff address the log when deinterleave is enabled A72: root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 294 MCU20: root@p789-adcu1:/hirain/data# ./vx_app_arm_remote_log.out [MCU2_0] 53.554546 s: dmTimer : timer count is 0. [MCU2_0] 58.298841 s: Output Buffer Luma=0xba5c0000 Chroma=0x0 [MCU2_0] 58. the log when deinterleave is disabled A72: root@p789-adcu1:/hirain/data/ti_dss_patch# ls -l total 40304 -rw-r--r-- 1 root root 13158400 Nov 15 2023 img_raw.yuv -rw-r--r-- 1 root root 28054632 Nov 15 05:17 libtivision_apps.so.8.4.0 -rwxr-xr-x 1 root root 45720 Nov 15 05:17 vx_app_multi_cam.out root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 294 298 312 314 316 DSS_M2M: task id 0 start_time 1699996730 s 938252 us 0.000000 s: VX_ZONE_INFO:[ownNodeKernelValidate:241] Validating kernel com.ti.hwa.displaym2m 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:523] Calling create callback for node node_91 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:529] Create callback for node node_91 completed 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:578] kernel init for node 0, kernel com.ti.hwa.displaym2m ... 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:589] kernel init for node 0, kernel com.ti.hwa.displaym2m ... done !!! 0.000000 s: VX_ZONE_INFO:[ownGraphScheduleGraph:764] Scheduling Graph (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownNodeKernelSchedule:627] Scheduling Node (node=12, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownCheckGraphCompleted:677] Graph Completed (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownCheckGraphCompleted:705] All Graphs Completed 334 DSS_M2M: task id 0 stop_time 1699996730 s 955180 us 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed Received events from Task0 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_nf_generic destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_nf_bilateral destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dmpac_sde destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_ldc destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_msc_multi_scale destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_msc_pyramid destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dmpac_dof destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.dof_visualize destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.vpac_viss destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.display destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.capture destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.csitx destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:[ownDestructKernel:44] Kernel com.ti.hwa.displaym2m destructor called (removed from context) 0.000000 s: VX_ZONE_INFO:Enabled Display M2M Conformance Test Finished... 0.000000 s: VX_ZONE_INIT:[tivxHostDeInitLocal:100] De-Initialization Done for HOST !!! 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:181] Is kernel use failed, index: 0 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:182] kernel name: org.khronos.openvx.absdiff 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:230] Is image use failed, index: 2 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:278] Is error use failed, index: 0 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INFO:[tivxQueueDelete:182] if this hangs, please ensure all application threads have been destroyed 0.000000 s: VX_ZONE_INIT:[tivxDeInitLocal:193] De-Initialization Done !!! APP: Deinit ... !!! REMOTE_SERVICE: Deinit ... !!! REMOTE_SERVICE: Deinit ... Done !!! IPC: Deinit ... !!! IPC: DeInit ... Done !!! MEM: Deinit ... !!! DDR_SHARED_MEM: Alloc's: 8 alloc's of 52633620 bytes DDR_SHARED_MEM: Free's : 8 free's of 52633620 bytes DDR_SHARED_MEM: Open's : 0 allocs of 0 bytes DDR_SHARED_MEM: Total size: 805306368 bytes MEM: Deinit ... Done !!! APP: Deinit ... Done !!! root@p789-adcu1:/hirain/data/ti_dss_patch# MCU20: root@p789-adcu1:/hirain/data# root@p789-adcu1:/hirain/data# root@p789-adcu1:/hirain/data# ./vx_app_arm_remote_log.out [MCU2_0] 153.465506 s: dmTimer : timer count is 0. [MCU2_0] 154.549665 s: Iteration0 Input Buffer Luma=0xb9920000 Chroma=0x0 [MCU2_0] 154.549757 s: Output Buffer Luma=0xba5c0000 Chroma=0x0 [MCU2_0] 154.567895 s: ========================================================== [MCU2_0] 154.567997 s: Display M2M Status: Instance|0 [MCU2_0] 154.568029 s: ========================================================== [MCU2_0] 154.568072 s: Queue Count: 1 [MCU2_0] 154.568135 s: Write-back Frames Count: 1 [MCU2_0] 154.568169 s: Underflow Count: 0 [MCU2_0] 158.465509 s: dmTimer : timer count is 0. Hi, I think somehow numPipe is becoming is 0, because i dont see print in the input buffer. This parameter is set from the input numPipe parameter in the createParams. So can you please check and make sure that numPIpe is set to correct value in the application? Regards, Brijesh hi The value of numPipe is defined by macros in test_display_m2m.c, which we haven't changed, so we shouldn't use the default value, right? So what should it be Hi, Do you have JTAG to connect to the board using CCS? If not, can we please try to figure out where it is becoming 0? Maybe please add some print statement in tivxDisplayM2MCreate API to see where it is becoming 0? Regards, Brijesh hi Can you provide the location of some key code for adding print debugging hi After I reduced the print cycle of remotelog from 10ms to 1ms, we can see the print of input buff, so we didn't see it before because the log cycle was too long, not a program bug the modefi as follow the log when deinterleave is disabled A72: root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 294 MCU20: root@p789-adcu1:/hirain/data# ./vx_app_arm_remote_log_1ms.out [MCU2_0] 33.502204 s: dmTimer : timer count is 0. [MCU2_0] 38.502209 s: dmTimer : timer count is 0. [MCU2_0] 43.502213 s: dmTimer : timer count is 0. [MCU2_0] 43.535382 s: Iteration0 Input Buffer Luma=0xb9920000 Chroma=0x0 [MCU2_0] 43.535472 s: tivxDisplayM2MProcess pipeIdx 1 drvObj->numPipe 1 [MCU2_0] 43.5355 hongyao.jin said: the log when deinterleave is disabled Can you please also share the log with deinterleave is enabled? Because that's what we want to debug. Regards, Brijesh hi We get more logs through CCS and gdb, But when the program crashes, CCS prompts that the connection to the CPU is disconnected and we can't see anything anymore the log when deinterleave is enabled A72: root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# gdb vx_app_multi_cam.out GNU gdb (GDB) 9.1 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "aarch64-linux". Type "show configuration" for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from vx_app_multi_cam.out... (gdb) r Starting program: /hirain/data/ti_dss_patch/vx_app_multi_cam.out warning: File "/lib/libthread_db-1.0.so" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". To enable execution of this file add add-auto-load-safe-path /lib/libthread_db-1.0.so line to your configuration file "/home/root/.gdbinit". To completely disable this security protection add set auto-load safe-path / line to your configuration file "/home/root/.gdbinit". For more information about this security protection see the "Auto-loading safe path" section in the GDB manual. E.g., run from the shell: info "(gdb)Auto-loading safe path" warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available. APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! [New LWP 1073] IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled [New LWP 1074] [New LWP 1075] [New LWP 1076] [New LWP 1077] 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... [New LWP 1078] Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 Waiting for graphs to finish execution... 294 298 312 314 316 DSS_M2M: task id 0 start_time 1699996630 s 261787 us 0.000000 s: VX_ZONE_INFO:[ownNodeKernelValidate:241] Validating kernel com.ti.hwa.displaym2m 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:523] Calling create callback for node node_91 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:529] Create callback for node node_91 completed 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:578] kernel init for node 0, kernel com.ti.hwa.displaym2m ... 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:589] kernel init for node 0, kernel com.ti.hwa.displaym2m ... done !!! 0.000000 s: VX_ZONE_INFO:[ownGraphScheduleGraph:764] Scheduling Graph (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownNodeKernelSchedule:627] Scheduling Node (node=12, pipe=0) MCU20: [MCU2_0] 127.414887 s: Iteration0 Input Buffer Luma=0xb9920000 Chroma=0x0 [MCU2_0] 127.414978 s: tivxDisplayM2MProcess pipeIdx 1 drvObj->numPipe 1 [MCU2_0] 127.415024 s: Output Buffer Luma=0xba5c0000 Chroma=0x0 And we found through debugging, when iterCnt<1 the program runs normally, but when iterCnt<2, the program crashes Hi, Can you please go inside this API tivxGetObjDescElement and see where exactly it crashes on the second iteration? or if it does not crash here, can you please go further in their API to figure out where it crashes? Since second iteration print did not come, i think it crashed either in tivxGetObjDescElement or in tivxMemShared2TargetPtr API call. Can you please share some more information here? Regards, Brijesh hi Currently we are debugging and suspect that the program crashed at Fvid2_processRequest the log when deinterleave is enabled A72: root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... 0.000000 s: VX_ZONE_INFO:Enabled Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 251 304 308 322 324 326 0.000000 s: VX_ZONE_INFO:[ownNodeKernelValidate:241] Validating kernel com.ti.hwa.displaym2m 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:523] Calling create callback for node node_91 0.000000 s: VX_ZONE_INFO:[ownNodeKernelInit:529] Create callback for node node_91 completed 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:578] kernel init for node 0, kernel com.ti.hwa.displaym2m ... 0.000000 s: VX_ZONE_INFO:[ownGraphNodeKernelInit:589] kernel init for node 0, kernel com.ti.hwa.displaym2m ... done !!! DSS_M2M: task id 0 start_time 1699996596 s 44206 us 0.000000 s: VX_ZONE_INFO:[ownGraphScheduleGraph:764] Scheduling Graph (graph=15, pipe=0) 0.000000 s: VX_ZONE_INFO:[ownNodeKernelSchedule:627] Scheduling Node (node=12, pipe=0) MCU20: [MCU2_0] 38.631230 s: dmTimer : timer count is 0. [MCU2_0] 46.219472 s: Iteration0 Input Buffer Luma=0xb9920a00 Chroma=0x0 [MCU2_0] 46.219566 s: tivxDisplayM2MProcess pipeIdx 1 drvObj->numPipe 1 [MCU2_0] 46.219612 s: Output Buffer Luma=0xba5c0000 Chroma=0x0 [MCU2_0] 46.280601 s: Iteration0 Input Buffer Luma=0xb9920a00 Chroma=0x0 [MCU2_0] 46.280695 s: tivxDisplayM2MProcess pipeIdx 1 drvObj->numPipe 1 [MCU2_0] 46.280742 s: Output Buffer Luma=0x0 Chroma=0x0 8865.vx_display_m2m_target.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include "TI/tivx.h" #include "VX/vx.h" #include "TI/tivx_event.h" #include "tivx_hwa_kernels.h" #include "tivx_kernel_display_m2m.h" #include "TI/tivx_target_kernel.h" #include "tivx_kernels_target_utils.h" #include "tivx_hwa_display_m2m_priv.h" #include #include #include #include #include #include #define DISPLAY_MAX_VALID_PLANES 2U #define DISPLAY_M2M_MAX_HANDLES (10) typedef struct { /*! IDs=> 0: Write-back pipe-line1 */ uint32_t instId; /*! Number of pipe-lines used, should be set to '1' as blending is not supported currently */ uint32_t numPipe; /*! IDs=> 0:VID1, 1:VIDL1, 2:VID2 and 3:VIDL2 */ uint32_t pipeId[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! IDs=> 0:Overlay1, 1:Overlay2, 2:Overlay3 and 3:Overlay4 */ uint32_t overlayId; /*! FVID2 display driver handle */ Fvid2_Handle drvHandle; /*! WB pipe create parameters */ Dss_WbCreateParams createParams; /*! WB pipe create status */ Dss_WbCreateStatus createStatus; /*! Callback parameters */ Fvid2_CbParams cbParams; /*! WB pipe status */ Dss_WbStatus wbStatus; /*! WB pipe configuration */ Dss_WbPipeCfgParams wbCfg; /*! WB pipe DMA configuration */ CSL_DssWbPipeDmaCfg wbDmaCfg; /*! WB pipe MFlag configuration */ Dss_WbPipeMflagParams wbMflagCfg; /*! WB pipe CSC configuration */ CSL_DssCscCoeff wbCscCfg; /*! Display pipe configuration */ Dss_PipeCfgParams pipeCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe MFlag configuration */ Dss_PipeMflagParams mFlagCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe CSC configuration */ Dss_PipeCscParams cscCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display Overlay configuration */ Dss_DctrlOverlayParams ovrCfg; /*! Display Layer configuration */ Dss_DctrlOverlayLayerParams layerCfg; /*! Display Global configuration */ Dss_DctrlGlobalDssParams globalParams; /*! Mutex used for waiting for process completion */ tivx_event waitForProcessCmpl; /*! Display M2M Driver Input Frame List, used for providing * an array of input frames */ Fvid2_FrameList inFrmList; /*! Display M2M Driver Output Frame List, used for providing * an array of output frames */ Fvid2_FrameList outFrmList; /*! Display M2M Driver Input Frames */ Fvid2_Frame inFrm[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display M2M Driver Output Frames */ Fvid2_Frame outFrm[1U]; } tivxDisplayM2MDrvObj; typedef struct { /*! IDs=> 0: Object free, 1: allocated */ uint32_t isAlloc; /*! Display M2M driver object */ tivxDisplayM2MDrvObj drvObj; /*! Display M2M Node create parameters provided by application */ tivx_display_m2m_params_t createParams; uint32_t numOutImgs; } tivxDisplayM2MParams; typedef struct { tivx_mutex lock; tivxDisplayM2MParams m2mObj[DISPLAY_M2M_MAX_HANDLES]; } tivxDisplayM2MInstObj; static tivx_target_kernel vx_display_m2m_target_kernel1 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel2 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel3 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel4 = NULL; tivxDisplayM2MInstObj gTivxDispM2mInstObj; static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut); static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj); static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj); static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData); static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format); static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj); static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj); extern void appLogPrintf(const char *format, ...); static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_obj_desc_image_t *input_desc; tivx_obj_desc_image_t *output_desc; void *input_target_ptr, *input_target_ptr2 = NULL; void *output_target_ptr, *output_target_ptr2 = NULL; Fvid2_Frame *frm; int32_t fvid2_status = FVID2_SOK; uint32_t pipeIdx, iterCnt; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } if((vx_status)VX_SUCCESS == status) { uint32_t size; input_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; output_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "DISPLAY M2M: ERROR: Instance context is NULL!\r\n"); } } if((vx_status)VX_SUCCESS == status) { /* Update 'input_desc' to array from only single image input to support blending i.e. more than 1 number of pipes. */ input_target_ptr = tivxMemShared2TargetPtr(&input_desc->mem_ptr[0]); if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { input_target_ptr2 = tivxMemShared2TargetPtr(&input_desc->mem_ptr[1]); } for (iterCnt = 0u; iterCnt < 2; iterCnt ++) { output_desc = (tivx_obj_desc_image_t *) tivxGetObjDescElement(obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX],iterCnt); output_target_ptr = tivxMemShared2TargetPtr(&output_desc->mem_ptr[0]); if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { output_target_ptr2 = tivxMemShared2TargetPtr(&output_desc->mem_ptr[1]); } /* call kernel processing function */ drvObj = &prms->drvObj; /* Assign input buffer addresses */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = &drvObj->inFrm[pipeIdx]; frm->addr[0U] = ((uint64_t)input_target_ptr) + input_desc->imagepatch_addr[0].stride_y; if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { frm->addr[1U] = ((uint64_t)input_target_ptr2) + input_desc->imagepatch_addr[1].stride_y; } appLogPrintf("Iteration%d Input Buffer Luma=0x%x Chroma=0x%x \n", pipeIdx, (void *)frm->addr[0U], (void *)frm->addr[1U]); } appLogPrintf("tivxDisplayM2MProcess pipeIdx %x drvObj->numPipe %x \n", pipeIdx, drvObj->numPipe); /* Assign output buffer addresses */ frm = drvObj->outFrm; frm->addr[0U] = (uint64_t)output_target_ptr; if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { frm->addr[1U] = (uint64_t)output_target_ptr2; } appLogPrintf("Output Buffer Luma=0x%x Chroma=0x%x \n", (void *)frm->addr[0U], (void *)frm->addr[1U]); /* Submit the request to the driver */ tivxTaskWaitMsecs(50); fvid2_status = Fvid2_processRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, FVID2_TIMEOUT_FOREVER); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Submit Request\n"); status = (vx_status)VX_FAILURE; } else { /* Wait for Frame Completion */ tivxEventWait(drvObj->waitForProcessCmpl, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); fvid2_status = Fvid2_getProcessedRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, 0); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); status = (vx_status)VX_FAILURE; } } } /* kernel processing function complete */ } return status; } static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivx_obj_desc_user_data_object_t *configuration_desc; tivx_obj_desc_image_t *obj_desc_imageIn, *obj_desc_imageOut; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { configuration_desc = (tivx_obj_desc_user_data_object_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]; obj_desc_imageIn = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; obj_desc_imageOut = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; if (configuration_desc->mem_size != sizeof(tivx_display_m2m_params_t)) { VX_PRINT(VX_ZONE_ERROR, "User data object size on target does not match the size on host, possibly due to misalignment in data structure\n"); status = (vx_status)VX_FAILURE; } prms = tivxDispM2mAllocObject(&gTivxDispM2mInstObj); if (NULL == prms) { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } /* Create Node object elements */ if ((vx_status)VX_SUCCESS == status) { status = tivxDisplayM2MSetCreateParams(prms, configuration_desc, obj_desc_imageIn, obj_desc_imageOut); } /* Create sync events */ if (status == (vx_status)VX_SUCCESS) { status = tivxEventCreate(&prms->drvObj.waitForProcessCmpl); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to allocate Event\n"); } } /* DSS M2M Driver create and configuration */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvCfg(&prms->drvObj); } if ((vx_status)VX_SUCCESS == status) { tivxSetTargetKernelInstanceContext(kernel, prms, sizeof(tivxDisplayM2MParams)); } else { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; uint32_t size; int32_t fvid2_status = FVID2_SOK; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: Could not obtain kernel instance context !!!\n"); } if(NULL == prms) { VX_PRINT(VX_ZONE_ERROR, "Kernel instance context is NULL!!!\n"); status = (vx_status)VX_FAILURE; } if ((vx_status)VX_SUCCESS == status) { /* Stop Display M2M Driver */ fvid2_status = Fvid2_stop(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 DSS M2M not stopped !!!\n"); } } if ((vx_status)VX_SUCCESS == status) { /* Dequeue all the request from the driver */ while ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_getProcessedRequest(prms->drvObj.drvHandle, &prms->drvObj.inFrmList, &prms->drvObj.outFrmList, 0); if (FVID2_SOK != fvid2_status) { if (fvid2_status != FVID2_ENO_MORE_BUFFERS) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); } status = (vx_status)VX_FAILURE; } } if (fvid2_status == FVID2_ENO_MORE_BUFFERS) { status = (vx_status)VX_SUCCESS; } } if ((vx_status)VX_SUCCESS == status) { /* print status */ fvid2_status = Fvid2_control(prms->drvObj.drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &prms->drvObj.wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { printf( "==========================================================\r\n"); printf( " Display M2M Status: Instance|%d\r\n", prms->drvObj.instId); printf( "==========================================================\r\n"); printf( " Queue Count: %d\r\n", prms->drvObj.wbStatus.queueCount); printf( " De-queue Count: %d\r\n", prms->drvObj.wbStatus.dequeueCount); printf( " Write-back Frames Count: %d\r\n", prms->drvObj.wbStatus.wbFrmCount); printf( " Underflow Count: %d\r\n", prms->drvObj.wbStatus.underflowCount); } } if ((vx_status)VX_SUCCESS == status) { /* Delete FVID2 handle */ fvid2_status = Fvid2_delete(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 Delete Failed !!!\n"); } else { prms->drvObj.drvHandle = NULL; } } if ((vx_status)VX_SUCCESS == status) { /* Delete event */ tivxEventDelete(&prms->drvObj.waitForProcessCmpl); } if ((NULL != prms) && (sizeof(tivxDisplayM2MParams) == size)) { tivxDispM2mFreeObject(&gTivxDispM2mInstObj, prms); //tivxMemFree(prms, size, (vx_enum)TIVX_MEM_EXTERNAL); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; int32_t fvid2_status = FVID2_SOK; uint32_t size; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_display_m2m_statistics_t *m2m_status_prms = NULL; void *target_ptr; tivx_obj_desc_user_data_object_t *usr_data_obj; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; } if (status == (vx_status)VX_SUCCESS) { switch (node_cmd_id) { case TIVX_DISPLAY_M2M_GET_STATISTICS: { if (NULL != obj_desc[0]) { drvObj = &prms->drvObj; fvid2_status = Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &drvObj->wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { /* Update return status object */ usr_data_obj = (tivx_obj_desc_user_data_object_t *)obj_desc[0U]; target_ptr = tivxMemShared2TargetPtr(&usr_data_obj->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); if (sizeof(tivx_display_m2m_statistics_t) == usr_data_obj->mem_size) { m2m_status_prms = (tivx_display_m2m_statistics_t *)target_ptr; m2m_status_prms->queueCount = drvObj->wbStatus.queueCount; m2m_status_prms->dequeueCount = drvObj->wbStatus.dequeueCount; m2m_status_prms->wbFrmCount = drvObj->wbStatus.wbFrmCount; m2m_status_prms->underflowCount = drvObj->wbStatus.underflowCount; } else { VX_PRINT(VX_ZONE_ERROR, "Invalid Size \n"); status = (vx_status)VX_ERROR_INVALID_PARAMETERS; } tivxCheckStatus(&status, tivxMemBufferUnmap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); } } else { VX_PRINT(VX_ZONE_ERROR, "User data object was NULL\n"); status = (vx_status)VX_FAILURE; } break; } default: { VX_PRINT(VX_ZONE_ERROR, "Invalid Command Id\n"); status = (vx_status)VX_FAILURE; break; } } } return status; } void tivxAddTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_FAILURE; char target_name[TIVX_TARGET_MAX_NAME]; vx_enum self_cpu; self_cpu = tivxGetSelfCpuId(); if ( self_cpu == (vx_enum)TIVX_CPU_ID_MCU2_0 ) { strncpy(target_name, TIVX_TARGET_DISPLAY_M2M1, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel1 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M2, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel2 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M3, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel3 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M4, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel4 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); status = tivxMutexCreate(&gTivxDispM2mInstObj.lock); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to create Mutex\n"); } else { memset(&gTivxDispM2mInstObj.m2mObj, 0x0, sizeof(tivxDisplayM2MParams) * DISPLAY_M2M_MAX_HANDLES); } } } void tivxRemoveTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_SUCCESS; status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel1); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel1 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel2); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel2 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel3); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel3 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel4); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel4 = NULL; } if (NULL != gTivxDispM2mInstObj.lock) { tivxMutexDelete(&gTivxDispM2mInstObj.lock); } } static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut) { vx_status status = (vx_status)VX_SUCCESS; void *cfgPtr; tivx_display_m2m_params_t *createParams; tivxDisplayM2MDrvObj *drvObj; uint32_t pipeIdx, layerIdx, pitchIdx; Dss_DispParams *dispParams; CSL_DssWbPipeCfg *wbPipeCfg; Dss_DctrlOverlayParams *ovrParams; Dss_DctrlOverlayLayerParams *layerParams; Fvid2_Frame *frm; cfgPtr = tivxMemShared2TargetPtr(&obj_desc->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(cfgPtr, obj_desc->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_READ_ONLY)); if (status == (vx_status)VX_SUCCESS) { createParams = (tivx_display_m2m_params_t *)cfgPtr; memcpy(&prms->createParams, createParams, sizeof(tivx_display_m2m_params_t)); drvObj = &prms->drvObj; /* Set Driver object */ drvObj->instId = createParams->instId; drvObj->numPipe = createParams->numPipe; drvObj->overlayId = createParams->overlayId; memcpy(&drvObj->pipeId[0U], &createParams->pipeId[0U], sizeof(createParams->pipeId)); if (createParams->enable_deiniterleave) { tivx_obj_desc_t *obj_desc = (tivx_obj_desc_t *)obj_desc_imageOut; if((vx_enum)obj_desc->type==(vx_enum)TIVX_OBJ_DESC_OBJARRAY) { tivx_obj_desc_object_array_t *obj_desc_obj_array; obj_desc_obj_array = (tivx_obj_desc_object_array_t *)obj_desc; prms->numOutImgs = obj_desc_obj_array->num_items; } else { if ((vx_enum)TIVX_OBJ_DESC_INVALID != (vx_enum)obj_desc->scope_obj_desc_id) { tivx_obj_desc_object_array_t *parent_obj_desc = NULL; tivxGetObjDescList( &obj_desc->scope_obj_desc_id, (tivx_obj_desc_t**)&parent_obj_desc, 1); if (parent_obj_desc != NULL) { prms->numOutImgs = parent_obj_desc->num_items; } else { prms->numOutImgs = 1u; } } else { prms->numOutImgs = 1u; } } } else { prms->numOutImgs = 1u; } } /* Initialize driver object */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvStructsInit(drvObj); } /* set driver object parameters */ if (status == (vx_status)VX_SUCCESS) { /* Callback parameters */ drvObj->cbParams.cbFxn = (Fvid2_CbFxn) (&tivxDisplayM2MCallback); drvObj->cbParams.appData = drvObj; drvObj->createParams.numPipe = drvObj->numPipe; drvObj->createParams.overlayId = drvObj->overlayId; /* Set Display pipeline parameters */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { dispParams = &drvObj->pipeCfg[pipeIdx].cfgParams; drvObj->createParams.pipeId[pipeIdx] = drvObj->pipeId[pipeIdx]; drvObj->pipeCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->mFlagCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->cscCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; dispParams->pipeCfg.pipeType = CSL_DSS_VID_PIPE_TYPE_VID; dispParams->layerPos.startX = 0U; dispParams->layerPos.startY = 0U; dispParams->pipeCfg.scEnable = FALSE; dispParams->alphaCfg.globalAlpha = 0xFFU; dispParams->alphaCfg.preMultiplyAlpha = FALSE; status = tivxDisplayExtractFvid2Format( obj_desc_imageIn, &dispParams->pipeCfg.inFmt); if (status == (vx_status)VX_SUCCESS) { /* Set video pipe output frame dimensions same as input as no scaling is done in video pipe-line */ dispParams->pipeCfg.outWidth = dispParams->pipeCfg.inFmt.width; dispParams->pipeCfg.outHeight = dispParams->pipeCfg.inFmt.height; if (createParams->enable_deiniterleave) { for (pitchIdx = 0; pitchIdx < 3; pitchIdx ++) { dispParams->pipeCfg.inFmt.pitch[pitchIdx] = dispParams->pipeCfg.inFmt.pitch[pitchIdx] * prms->numOutImgs; } } } else { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); break; } } /* Set Display WB pipeline parameters */ if (((vx_status)VX_SUCCESS == status) && (pipeIdx > 0)) { wbPipeCfg = &drvObj->wbCfg.pipeCfg; /* Set WB pipe input frame dimensions same as video pipe input/output frame, no scaling is done in video pipe, it will be done in WB pipe-line */ wbPipeCfg->inFmt.width = dispParams->pipeCfg.outWidth; wbPipeCfg->inFmt.height = dispParams->pipeCfg.outHeight; wbPipeCfg->inPos.startX = 0U; wbPipeCfg->inPos.startY = 0U; status = tivxDisplayExtractFvid2Format(obj_desc_imageOut, &wbPipeCfg->outFmt); if (status != (vx_status)VX_SUCCESS) { VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); status = (vx_status)VX_FAILURE; } else { if ((wbPipeCfg->inFmt.width != wbPipeCfg->outFmt.width) || (wbPipeCfg->inFmt.height != wbPipeCfg->outFmt.height)) { wbPipeCfg->scEnable = TRUE; } } } /* Set Display WB pipeline parameters */ if ((vx_status)VX_SUCCESS == status) { ovrParams = &drvObj->ovrCfg; ovrParams->overlayId = drvObj->overlayId; ovrParams->colorbarEnable = FALSE; ovrParams->overlayCfg.colorKeyEnable = FALSE; ovrParams->overlayCfg.colorKeySel = CSL_DSS_OVERLAY_TRANS_COLOR_DEST; ovrParams->overlayCfg.backGroundColor = 0xc8c800U; layerParams = &drvObj->layerCfg; layerParams->overlayId = drvObj->overlayId; /* Set all layer to invalid first and then update only used ones */ for(layerIdx = 0U ; layerIdx < CSL_DSS_VID_PIPE_ID_MAX ; layerIdx++) { layerParams->pipeLayerNum[layerIdx] = CSL_DSS_OVERLAY_LAYER_INVALID; } /* Currently blending is not supported so only one layer is used. This code needs to updated when blending is supported. */ layerParams->pipeLayerNum[drvObj->createParams.pipeId[0U]] = CSL_DSS_OVERLAY_LAYER_NUM_0; } /* Update frame-lists */ if ((vx_status)VX_SUCCESS == status) { drvObj->inFrmList.numFrames = drvObj->numPipe; for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = (Fvid2_Frame *) &drvObj->inFrm[pipeIdx]; frm->chNum = drvObj->createParams.pipeId[pipeIdx]; drvObj->inFrmList.frames[pipeIdx] = frm; } frm = (Fvid2_Frame *) &drvObj->outFrm[0U]; drvObj->outFrmList.frames[0U] = frm; drvObj->outFrmList.numFrames = 1U; } } return status; } static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; /* Initialize driver create parameters */ Dss_m2mCreateParamsInit(&drvObj->createParams); /* Initialize driver call-back parameters */ Fvid2CbParams_init(&drvObj->cbParams); /* Initialize driver pipe configuration parameters */ for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { Dss_dispParamsInit(&drvObj->pipeCfg[loopCnt].cfgParams); Dss_dispPipeMflagParamsInit(&drvObj->mFlagCfg[loopCnt].mFlagCfg); CSL_dssCscCoeffInit(&drvObj->cscCfg[loopCnt].csc); } /* Initialize WB pipeline parameters */ Dss_m2mPipeCfgParamsInit(&drvObj->wbCfg); CSL_dssWbPipeDmaCfgInit(&drvObj->wbDmaCfg); Dss_m2mMFlagParamsInit(&drvObj->wbMflagCfg); CSL_dssCscCoeffInit(&drvObj->wbCscCfg); Dss_m2mStatusInit(&drvObj->wbStatus); /* Initialize Display overlay parameters */ Dss_dctrlOverlayParamsInit(&drvObj->ovrCfg); Dss_dctrlOverlayLayerParamsInit(&drvObj->layerCfg); /* Initialize Display global parameters */ Dss_dctrlGlobalDssParamsInit(&drvObj->globalParams); /* Initialize input and output frame lists */ Fvid2FrameList_init(&drvObj->inFrmList); Fvid2FrameList_init(&drvObj->outFrmList); return status; } static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; int32_t fvid2_status = FVID2_SOK; /* Display M2M Driver create */ drvObj->drvHandle = Fvid2_create(DSS_M2M_DRV_ID, drvObj->instId, &drvObj->createParams, &drvObj->createStatus, &drvObj->cbParams); if((NULL == drvObj->drvHandle) || (drvObj->createStatus.retVal != FVID2_SOK)) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Create Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } /* Display M2M pipe configuration */ if ((vx_status)VX_SUCCESS == status) { for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_PARAMS, &drvObj->pipeCfg[loopCnt], NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_MFLAG_PARAMS, &drvObj->mFlagCfg[loopCnt], NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M DISP IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; break; } } } /* Display M2M overlay configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_OVERLAY_PARAMS, &drvObj->ovrCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_LAYER_PARAMS, &drvObj->layerCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Overlay IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M global configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_GLOBAL_DSS_PARAMS, &drvObj->globalParams, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Global IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M write-back pipe configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_PARAMS, &drvObj->wbCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_MFLAG_PARAMS, &drvObj->wbMflagCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_DMA_CFG, &drvObj->wbDmaCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M WB IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Start Display M2M Driver */ if ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_start(drvObj->drvHandle, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Driver Start Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } return status; } static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData) { tivxDisplayM2MDrvObj *drvObj = (tivxDisplayM2MDrvObj *)(appData); if ((NULL != drvObj) && (drvObj->waitForProcessCmpl != NULL)) { tivxEventPost(drvObj->waitForProcessCmpl); } return (vx_status)VX_SUCCESS; } static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format) { vx_status status = (vx_status)VX_SUCCESS; Fvid2Format_init(format); format->width = obj_desc_img->imagepatch_addr[0].dim_x; format->height = obj_desc_img->imagepatch_addr[0].dim_y; format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->scanFormat = FVID2_SF_PROGRESSIVE; switch (obj_desc_img->format) { case (vx_df_image)TIVX_DF_IMAGE_RGB565: format->dataFormat = FVID2_DF_BGR16_565; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGB: format->dataFormat = FVID2_DF_RGB24_888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGBX: format->dataFormat = FVID2_DF_RGBX24_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)TIVX_DF_IMAGE_BGRX: format->dataFormat = FVID2_DF_BGRX32_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_UYVY: format->dataFormat = FVID2_DF_YUV422I_UYVY; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_YUYV: format->dataFormat = FVID2_DF_YUV422I_YUYV; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_NV12: format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[1].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U16: format->ccsFormat = FVID2_CCSF_BITS12_UNPACKED16; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U8: format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; default: status = (vx_status)VX_FAILURE; break; } return status; } static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj) { uint32_t cnt; tivxDisplayM2MParams *m2mObj = NULL; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (0U == instObj->m2mObj[cnt].isAlloc) { m2mObj = &instObj->m2mObj[cnt]; memset(m2mObj, 0x0, sizeof(tivxDisplayM2MParams)); instObj->m2mObj[cnt].isAlloc = 1U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); return (m2mObj); } static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj) { uint32_t cnt; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (m2mObj == &instObj->m2mObj[cnt]) { m2mObj->isAlloc = 0U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); } hi At present, we have successfully split the image, but it took about 60ms, can you optimize the time consumed the log when deinterleave is enabled root@p789-adcu1:/hirain/data/ti_dss_patch# ./vx_app_multi_cam.out APP: Init ... !!! MEM: Init ... !!! MEM: Initialized DMA HEAP (fd=4) !!! MEM: Init ... Done !!! IPC: Init ... !!! IPC: Init ... Done !!! REMOTE_SERVICE: Init ... !!! REMOTE_SERVICE: Init ... Done !!! 0.000000 s: GTC Frequency = 0 MHz APP: Init ... Done !!! 0.000000 s: VX_ZONE_INIT:Enabled 0.000000 s: VX_ZONE_ERROR:Enabled 0.000000 s: VX_ZONE_WARNING:Enabled 0.000000 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!! 0.000000 s: VX_ZONE_INIT:[tivxHostInitLocal:86] Initialization Done for HOST !!! Creating context done status : 0! Starting Display M2M Conformance Test... Starting Display M2M Conformance Test 2... Creating Task 0... Waiting for graphs to finish execution... Graph 0: created... Graph 0: input and output images created... Graph 0: input and output images created 2 ... 225 268 272 287 289 291 293 Graph 0: verifying... DSS_M2M: task id 0 start_time 1699996983 s 477170 us 313 DSS_M2M: task id 0 stop_time 1699996983 s 539877 us Received events from Task0 Display M2M Conformance Test Finished... 0.000000 s: VX_ZONE_INIT:[tivxHostDeInitLocal:100] De-Initialization Done for HOST !!! 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:181] Is kernel use failed, index: 0 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:182] kernel name: org.khronos.openvx.absdiff 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:230] Is image use failed, index: 2 0.000000 s: VX_ZONE_ERROR:[tivxObjectDeInit:278] Is error use failed, index: 0 0.000000 s: VX_ZONE_INIT:[tivxDeInitLocal:193] De-Initialization Done !!! APP: Deinit ... !!! REMOTE_SERVICE: Deinit ... !!! REMOTE_SERVICE: Deinit ... Done !!! IPC: Deinit ... !!! IPC: DeInit ... Done !!! MEM: Deinit ... !!! DDR_SHARED_MEM: Alloc's: 8 alloc's of 52633620 bytes DDR_SHARED_MEM: Free's : 8 free's of 52633620 bytes DDR_SHARED_MEM: Open's : 0 allocs of 0 bytes DDR_SHARED_MEM: Total size: 805306368 bytes MEM: Deinit ... Done !!! APP: Deinit ... Done !!! root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# sync root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# ls -l total 53160 -rw-r--r-- 1 root root 13158400 Nov 15 2023 img_raw.yuv -rw-r--r-- 1 root root 3289600 Nov 15 05:23 img_raw_ch0.yuv -rw-r--r-- 1 root root 3289600 Nov 15 05:23 img_raw_ch1.yuv -rw-r--r-- 1 root root 3289600 Nov 15 05:23 img_raw_ch2.yuv -rw-r--r-- 1 root root 3289600 Nov 15 05:23 img_raw_ch3.yuv -rw-r--r-- 1 root root 28045840 Nov 15 05:33 libtivision_apps.so.8.4.0 -rwxr-xr-x 1 root root 45720 Nov 15 05:22 vx_app_multi_cam.out root@p789-adcu1:/hirain/data/ti_dss_patch# root@p789-adcu1:/hirain/data/ti_dss_patch# 6746.main_linux_arm.c /* * * Copyright (c) 2017 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include FILE *fp_src_img = NULL; char file_name[20] = "file_name"; FILE *fp_dst_img[4] = {0}; uint32_t payload = 0; void *virt_addr1 = NULL; void *virt_addr2 = NULL; uint64_t phys_addr1 = 0; uint64_t phys_addr2 = 0; uint8_t *src_buf = NULL, *dest_buf = NULL; uint32_t width = 1280U; uint32_t pitch = 4U*2*1280U; uint32_t height = 1285U; uint32_t size = 0; uint8_t *image_test = NULL; void timer_print_start(int task_id) { struct timeval tv1; gettimeofday(&tv1, NULL); printf("DSS_M2M: task id %d start_time %ld s %ld us\n", task_id, tv1.tv_sec, tv1.tv_usec); } void timer_print_stop(int task_id) { struct timeval tv1; gettimeofday(&tv1, NULL); printf("DSS_M2M: task id %d stop_time %ld s %ld us\n", task_id, tv1.tv_sec, tv1.tv_usec); } int main(int argc, char *argv[]) { int status = 0; width = 1280U; pitch = 4U*2*1280U; height = 1285U; size = pitch*height; status = appInit(); if(status==0) { //int app_multi_cam_main(int argc, char* argv[]); //status = app_multi_cam_main(argc, argv); { extern void main_dss_m2m_test(); virt_addr1 = appMemAlloc(APP_MEM_HEAP_DDR, size, 0); virt_addr2 = appMemAlloc(APP_MEM_HEAP_DDR, size, 0); if (virt_addr1 == NULL || virt_addr2 == NULL) { printf("UDMA: MEM alloc fail !"); } src_buf = (uint8_t*)virt_addr1; dest_buf = (uint8_t*)virt_addr2; fp_src_img = fopen("img_raw.yuv", "r"); fread(src_buf, width*pitch, 1, fp_src_img); //system("sync"); sleep(2); main_dss_m2m_test(); #if 0 timer_print_start(7); for(int j = 0; j < 4; j++) { for(int i = 0; i < height; i++) { memcpy(&dest_buf[j*width*2U*height + i*width*2U], &src_buf[j*width*2U + i*pitch], width*2U); } } timer_print_stop(7); #endif //system("sync"); sleep(2); for(int i = 0; i < 4; i++) { sprintf(file_name, "img_raw_ch%d.yuv", i); fp_dst_img[i] = fopen(file_name, "w"); fwrite(&dest_buf[i*width*height*2U], width*height*2U, 1, fp_dst_img[i]); } } appDeInit(); } return status; } 1460.test_display_m2m.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "math.h" #include #include #define TIVX_TARGET_DEFAULT_STACK_SIZE (256U * 1024U) #define TIVX_TARGET_DEFAULT_TASK_PRIORITY1 (8u) #define DSS_M2M_NUM_CH (1U) #define DSS_M2M_NUM_CH_MAX (4U) /* Common Configurations across channels */ #define DSS_M2M_WB_PIPE_INST_ID (0U) #define DSS_M2M_PIPE_NUM (1U) #define DSS_M2M_PIPE_INST_ID (3U) /* Currently Only Overlay2 can be used for M2M operations, this can be changed through DSS initialization API available in vision_apps */ #define DSS_M2M_OVERLAY_ID (3U) /* Channel 0 configurations */ #define DSS_M2M_CH0_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH0_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH0_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH0_IN_FRAME_BPP (2U) #define DSS_M2M_CH0_IN_FRAME_PITCH (DSS_M2M_CH0_IN_FRAME_WIDTH * \ DSS_M2M_CH0_IN_FRAME_BPP * 4) #define DSS_M2M_CH0_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH0_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH0_OUT_FRAME_HEIGHT (1285U) /* Channel 1 configurations */ #define DSS_M2M_CH1_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH1_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH1_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH1_IN_FRAME_BPP (2U) #define DSS_M2M_CH1_IN_FRAME_PITCH (DSS_M2M_CH1_IN_FRAME_WIDTH * \ DSS_M2M_CH1_IN_FRAME_BPP * 4) #define DSS_M2M_CH1_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH1_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH1_OUT_FRAME_HEIGHT (1285U) /* Channel 2 configurations */ #define DSS_M2M_CH2_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH2_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH2_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH2_IN_FRAME_BPP (2U) #define DSS_M2M_CH2_IN_FRAME_PITCH (DSS_M2M_CH2_IN_FRAME_WIDTH * \ DSS_M2M_CH2_IN_FRAME_BPP * 4) #define DSS_M2M_CH2_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH2_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH2_OUT_FRAME_HEIGHT (1285U) /* Channel 3 configurations */ #define DSS_M2M_CH3_IN_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH3_IN_FRAME_WIDTH (1280U) #define DSS_M2M_CH3_IN_FRAME_HEIGHT (1285U*4U) #define DSS_M2M_CH3_IN_FRAME_BPP (2U) #define DSS_M2M_CH3_IN_FRAME_PITCH (DSS_M2M_CH3_IN_FRAME_WIDTH * \ DSS_M2M_CH3_IN_FRAME_BPP * 4) #define DSS_M2M_CH3_OUT_FRAME_FORMAT (VX_DF_IMAGE_UYVY) #define DSS_M2M_CH3_OUT_FRAME_WIDTH (1280U) #define DSS_M2M_CH3_OUT_FRAME_HEIGHT (1285U) #define DSS_M2M_NODE_NAME_LEN_MAX (100U) /* Preloaded image buffers */ /* 1920 x 1080 buffers */ extern uint32_t gTiovxCtDisplayArrayBGR888[1555200]; extern uint32_t gTiovxCtDisplayArrayYUV420NV12[777600]; extern uint32_t gTiovxCtDisplayArrayYUV422[1036800]; typedef struct { uint32_t taskId; uint32_t instId; uint32_t numPipe; uint32_t pipeId[TIVX_DISPLAY_M2M_MAX_PIPE]; uint32_t overlayId; vx_df_image inFmt; uint32_t inWidth; uint32_t inHeight; uint32_t inBpp; uint32_t inPitch; vx_df_image outFmt; uint32_t outWidth; uint32_t outHeight; uint32_t posX; uint32_t posY; tivx_event eventHandle_TaskFinished; tivx_task taskHandle_m2m; tivx_task_create_params_t taskParams_m2m; char nodeName[DSS_M2M_NODE_NAME_LEN_MAX]; uint32_t iterationCnt; } tivx_display_m2m_test_params_t; static vx_context context; static uint32_t gLoop_cnt; tivx_display_m2m_test_params_t gTestParams[DSS_M2M_NUM_CH_MAX]; extern uint8_t *src_buf, *dest_buf; static void tivxTask_m2m(void *app_var) { vx_node m2m_node = 0; vx_image in_image = 0; vx_image out_image = 0; vx_user_data_object m2m_config; tivx_display_m2m_params_t local_m2m_config; vx_imagepatch_addressing_t image_addr; vx_rectangle_t rect; vx_graph m2m_graph = 0; tivx_display_m2m_test_params_t *testParams = (tivx_display_m2m_test_params_t *)app_var; uint32_t status = 0; vx_bool dss_m2m_prms_replicate[] = {vx_false_e, vx_false_e, vx_true_e}; vx_imagepatch_addressing_t image_addr_from_file, image_addr_from_file2; vx_rectangle_t rect_from_file; vx_map_id map_id1, map_id2; void *data_ptr1, *data_ptr2; m2m_graph = vxCreateGraph(context); printf("Graph %d: created...\n", testParams->taskId); /* allocate Input and Output frame refs */ in_image = vxCreateImage(context, testParams->inWidth, testParams->inHeight, testParams->inFmt); out_image = vxCreateImage(context, testParams->outWidth, testParams->outHeight, testParams->outFmt); vx_object_array out_img_array = vxCreateObjectArray(context, (vx_reference)out_image, 4); vxReleaseImage(&out_image); out_image = (vx_image)vxGetObjectArrayItem(out_img_array, 0); printf("Graph %d: input and output images created...\n", testParams->taskId); image_addr.dim_x = testParams->inWidth; image_addr.dim_y = testParams->inHeight; image_addr.stride_x = testParams->inBpp; image_addr.stride_y = testParams->inPitch; image_addr.scale_x = VX_SCALE_UNITY; image_addr.scale_y = VX_SCALE_UNITY; image_addr.step_x = 1; image_addr.step_y = 1; rect.start_x = 0; rect.start_y = 0; rect.end_x = testParams->inWidth; rect.end_y = testParams->inHeight; printf("Graph %d: input and output images created 2 ...\n", testParams->taskId); printf("%d\n", __LINE__); tivxTaskWaitMsecs(1000); /* Copy reference input image to input buffer */ if (testParams->inFmt == VX_DF_IMAGE_RGB) { vxCopyImagePatch(in_image, &rect, 0, &image_addr, (void *)gTiovxCtDisplayArrayBGR888, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); } else if (testParams->inFmt == VX_DF_IMAGE_YUYV) { vxCopyImagePatch(in_image, &rect, 0, &image_addr, (void *)gTiovxCtDisplayArrayYUV422, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); } else if (testParams->inFmt == VX_DF_IMAGE_UYVY) { rect_from_file.start_x = 0; rect_from_file.start_y = 0; rect_from_file.end_x = testParams->inWidth; rect_from_file.end_y = testParams->inHeight; /* Update input buffer here for other formats */ status = vxMapImagePatch(in_image, &rect_from_file, 0, &map_id1, &image_addr_from_file, &data_ptr1, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X); if(status != 0) { printf("vxMapImagePatch failed. \n"); } printf("%d\n", __LINE__); memcpy(data_ptr1, &src_buf[1280U*2U*testParams->taskId], 1280U*2U*(1285U*4U - testParams->taskId)); } printf("%d\n", __LINE__); /* DSS M2M initialization */ tivx_display_m2m_params_init(&local_m2m_config); local_m2m_config.instId = testParams->instId; /* Only one pipeline is supported */ local_m2m_config.numPipe = testParams->numPipe; local_m2m_config.pipeId[0U] = testParams->pipeId[0U]; local_m2m_config.overlayId = testParams->overlayId; local_m2m_config.enable_deiniterleave = 1u; m2m_config = vxCreateUserDataObject(context, "tivx_display_m2m_params_t", sizeof(tivx_display_m2m_params_t), &local_m2m_config); printf("%d\n", __LINE__); m2m_node = tivxDisplayM2MNode(m2m_graph, m2m_config, in_image, out_image); printf("%d\n", __LINE__); vxSetNodeTarget(m2m_node, VX_TARGET_STRING, &testParams->nodeName[0U]); printf("%d\n", __LINE__); vxReplicateNode(m2m_graph, m2m_node, dss_m2m_prms_replicate, 3u); printf("%d\n", __LINE__); // printf("Added \'%s\' node in graph %d\n", &testParams->nodeName[0U], testParams->taskId); printf("Graph %d: verifying...\n", testParams->taskId); vxVerifyGraph(m2m_graph); sleep(10); // printf("Graph %d: verify done...\n", testParams->taskId); { extern void timer_print_start(int task_id); timer_print_start(testParams->taskId); } //for (wbFrmCnt = 0U ; wbFrmCnt < testParams->iterationCnt ; wbFrmCnt++) { vxProcessGraph(m2m_graph); } printf("%d\n", __LINE__); { extern void timer_print_stop(int task_id); timer_print_stop(testParams->taskId); } { for(int i = 0; i < 4; i++) { out_image = (vx_image)vxGetObjectArrayItem(out_img_array, i); rect_from_file.start_x = 0; rect_from_file.start_y = 0; rect_from_file.end_x = testParams->outWidth; rect_from_file.end_y = testParams->outHeight; /* Update input buffer here for other formats */ status = vxMapImagePatch(out_image, &rect_from_file, 0, &map_id2, &image_addr_from_file2, &data_ptr2, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X); if(status != 0) { printf("vxMapImagePatch failed 2. \n"); } memcpy(&dest_buf[1280U*1285U*2U*i], data_ptr2, 1280U*1285U*2U); } } vxReleaseNode(&m2m_node); vxReleaseImage(&in_image); vxReleaseImage(&out_image); vxReleaseUserDataObject(&m2m_config); vxReleaseGraph(&m2m_graph); /*Signal the completion of m2m graph processing*/ tivxEventPost(testParams->eventHandle_TaskFinished); } void main_dss_m2m_test() { //context = context_->vx_context_; uint32_t taskIdx; tivx_display_m2m_test_params_t *testParams; uint32_t createTask = 0U; uint32_t status = 0; /* Create OpenVx Context */ context = vxCreateContext(); status = vxGetStatus((vx_reference)context); printf("Creating context done status : %d!\n", status); printf("Starting Display M2M Conformance Test...\n"); /* Initialize global test parameters structure to '0' */ memset(&gTestParams[0U], 0, sizeof(gTestParams)); { tivxHwaLoadKernels(context); //CT_RegisterForGarbageCollection(context, ct_teardown_hwa_kernels, CT_GC_OBJECT); printf("Starting Display M2M Conformance Test 2...\n"); tivx_set_debug_zone(VX_ZONE_MAX); //gLoop_cnt = arg_->loopCount; gLoop_cnt = 1; for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { createTask = 0U; testParams = &gTestParams[taskIdx]; testParams->taskId = taskIdx; tivxEventCreate(&testParams->eventHandle_TaskFinished); testParams->instId = DSS_M2M_WB_PIPE_INST_ID; testParams->numPipe = DSS_M2M_PIPE_NUM; /* Note: Directly assigning as only one pipe is supported currently */ testParams->pipeId[0U] = DSS_M2M_PIPE_INST_ID; testParams->overlayId = DSS_M2M_OVERLAY_ID; testParams->inFmt = DSS_M2M_CH0_IN_FRAME_FORMAT; testParams->iterationCnt = gLoop_cnt; switch (taskIdx) { case 0U: /* Initialize test parameters for task 0 */ createTask = 1U; testParams->inWidth = DSS_M2M_CH0_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH0_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH0_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH0_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH0_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH0_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH0_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M1); break; case 1U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH1_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH1_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH1_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH1_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH1_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH1_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH1_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH1_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M2); break; case 2U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH2_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH2_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH2_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH2_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH2_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH2_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH2_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH2_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M3); break; case 3U: createTask = 1U; /* Initialize test parameters for task 1 */ testParams->inFmt = DSS_M2M_CH3_IN_FRAME_FORMAT; testParams->inWidth = DSS_M2M_CH3_IN_FRAME_WIDTH; testParams->inHeight = DSS_M2M_CH3_IN_FRAME_HEIGHT; testParams->inBpp = DSS_M2M_CH3_IN_FRAME_BPP; testParams->inPitch = DSS_M2M_CH3_IN_FRAME_PITCH; testParams->outFmt = DSS_M2M_CH3_OUT_FRAME_FORMAT; testParams->outWidth = DSS_M2M_CH3_OUT_FRAME_WIDTH; testParams->outHeight = DSS_M2M_CH3_OUT_FRAME_HEIGHT; strcpy(&testParams->nodeName[0U], TIVX_TARGET_DISPLAY_M2M4); break; default: break; } if (createTask == 1U) { /* Setting up task params for m2m_task */ tivxTaskSetDefaultCreateParams(&testParams->taskParams_m2m); testParams->taskParams_m2m.task_main = &tivxTask_m2m; testParams->taskParams_m2m.app_var = testParams; testParams->taskParams_m2m.stack_ptr = NULL; testParams->taskParams_m2m.stack_size = TIVX_TARGET_DEFAULT_STACK_SIZE; testParams->taskParams_m2m.core_affinity = TIVX_TASK_AFFINITY_ANY; testParams->taskParams_m2m.priority = TIVX_TARGET_DEFAULT_TASK_PRIORITY1; printf("Creating Task %d...\n", testParams->taskId); /* Create Tasks */ tivxTaskCreate(&testParams->taskHandle_m2m, &testParams->taskParams_m2m); } } /* wait here for all tasks to finish */ printf("Waiting for graphs to finish execution...\n"); for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; tivxEventWait(testParams->eventHandle_TaskFinished, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); printf("Received events from Task%d\n", testParams->taskId); } /* Delete tasks and sync events */ for (taskIdx = 0U ; taskIdx < DSS_M2M_NUM_CH ; taskIdx++) { testParams = &gTestParams[taskIdx]; tivxTaskDelete(&testParams->taskHandle_m2m); tivxEventDelete(&testParams->eventHandle_TaskFinished); } tivxHwaUnLoadKernels(context); tivx_set_debug_zone(VX_ZONE_MAX); } printf("Display M2M Conformance Test Finished...\n"); } 1460.vx_display_m2m_target.c /* * * Copyright (c) 2021 Texas Instruments Incorporated * * All rights reserved not granted herein. * * Limited License. * * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive * license under copyrights and patents it now or hereafter owns or controls to make, * have made, use, import, offer to sell and sell ("Utilize") this software subject to the * terms herein. With respect to the foregoing patent license, such license is granted * solely to the extent that any such patent is necessary to Utilize the software alone. * The patent license shall not apply to any combinations which include this software, * other than combinations with devices manufactured by or for TI ("TI Devices"). * No hardware patent is licensed hereunder. * * Redistributions must preserve existing copyright notices and reproduce this license * (including the above copyright notice and the disclaimer and (if applicable) source * code license limitations below) in the documentation and/or other materials provided * with the distribution * * Redistribution and use in binary form, without modification, are permitted provided * that the following conditions are met: * * * No reverse engineering, decompilation, or disassembly of this software is * permitted with respect to any software provided in binary form. * * * any redistribution and use are licensed by TI for use only with TI Devices. * * * Nothing shall obligate TI to provide you with source code for the software * licensed and provided to you in object code. * * If software source code is provided to you, modification and redistribution of the * source code are permitted provided that the following conditions are met: * * * any redistribution and use of the source code, including any resulting derivative * works, are licensed by TI for use only with TI Devices. * * * any redistribution and use of any object code compiled from the source code * and any resulting derivative works, are licensed by TI for use only with TI Devices. * * Neither the name of Texas Instruments Incorporated nor the names of its suppliers * * may be used to endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER. * * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include "TI/tivx.h" #include "VX/vx.h" #include "TI/tivx_event.h" #include "tivx_hwa_kernels.h" #include "tivx_kernel_display_m2m.h" #include "TI/tivx_target_kernel.h" #include "tivx_kernels_target_utils.h" #include "tivx_hwa_display_m2m_priv.h" #include #include #include #include #include #define DISPLAY_MAX_VALID_PLANES 2U #define DISPLAY_M2M_MAX_HANDLES (10) typedef struct { /*! IDs=> 0: Write-back pipe-line1 */ uint32_t instId; /*! Number of pipe-lines used, should be set to '1' as blending is not supported currently */ uint32_t numPipe; /*! IDs=> 0:VID1, 1:VIDL1, 2:VID2 and 3:VIDL2 */ uint32_t pipeId[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! IDs=> 0:Overlay1, 1:Overlay2, 2:Overlay3 and 3:Overlay4 */ uint32_t overlayId; /*! FVID2 display driver handle */ Fvid2_Handle drvHandle; /*! WB pipe create parameters */ Dss_WbCreateParams createParams; /*! WB pipe create status */ Dss_WbCreateStatus createStatus; /*! Callback parameters */ Fvid2_CbParams cbParams; /*! WB pipe status */ Dss_WbStatus wbStatus; /*! WB pipe configuration */ Dss_WbPipeCfgParams wbCfg; /*! WB pipe DMA configuration */ CSL_DssWbPipeDmaCfg wbDmaCfg; /*! WB pipe MFlag configuration */ Dss_WbPipeMflagParams wbMflagCfg; /*! WB pipe CSC configuration */ CSL_DssCscCoeff wbCscCfg; /*! Display pipe configuration */ Dss_PipeCfgParams pipeCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe MFlag configuration */ Dss_PipeMflagParams mFlagCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display pipe CSC configuration */ Dss_PipeCscParams cscCfg[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display Overlay configuration */ Dss_DctrlOverlayParams ovrCfg; /*! Display Layer configuration */ Dss_DctrlOverlayLayerParams layerCfg; /*! Display Global configuration */ Dss_DctrlGlobalDssParams globalParams; /*! Mutex used for waiting for process completion */ tivx_event waitForProcessCmpl; /*! Display M2M Driver Input Frame List, used for providing * an array of input frames */ Fvid2_FrameList inFrmList; /*! Display M2M Driver Output Frame List, used for providing * an array of output frames */ Fvid2_FrameList outFrmList; /*! Display M2M Driver Input Frames */ Fvid2_Frame inFrm[TIVX_DISPLAY_M2M_MAX_PIPE]; /*! Display M2M Driver Output Frames */ Fvid2_Frame outFrm[1U]; } tivxDisplayM2MDrvObj; typedef struct { /*! IDs=> 0: Object free, 1: allocated */ uint32_t isAlloc; /*! Display M2M driver object */ tivxDisplayM2MDrvObj drvObj; /*! Display M2M Node create parameters provided by application */ tivx_display_m2m_params_t createParams; uint32_t numOutImgs; } tivxDisplayM2MParams; typedef struct { tivx_mutex lock; tivxDisplayM2MParams m2mObj[DISPLAY_M2M_MAX_HANDLES]; } tivxDisplayM2MInstObj; static tivx_target_kernel vx_display_m2m_target_kernel1 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel2 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel3 = NULL; static tivx_target_kernel vx_display_m2m_target_kernel4 = NULL; tivxDisplayM2MInstObj gTivxDispM2mInstObj; static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg); static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut); static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj); static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj); static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData); static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format); static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj); static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj); static vx_status VX_CALLBACK tivxDisplayM2MProcess( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_obj_desc_image_t *input_desc; tivx_obj_desc_image_t *output_desc; void *input_target_ptr, *input_target_ptr2 = NULL; void *output_target_ptr, *output_target_ptr2 = NULL; Fvid2_Frame *frm; int32_t fvid2_status = FVID2_SOK; uint32_t pipeIdx, iterCnt; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } if((vx_status)VX_SUCCESS == status) { uint32_t size; input_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; output_desc = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "DISPLAY M2M: ERROR: Instance context is NULL!\r\n"); } } if((vx_status)VX_SUCCESS == status) { /* Update 'input_desc' to array from only single image input to support blending i.e. more than 1 number of pipes. */ input_target_ptr = tivxMemShared2TargetPtr(&input_desc->mem_ptr[0]); VX_PRINT(VX_ZONE_INFO, "input_target_ptr = %p\n", input_target_ptr); if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { input_target_ptr2 = tivxMemShared2TargetPtr(&input_desc->mem_ptr[1]); VX_PRINT(VX_ZONE_INFO, "input_target_ptr2 = %p\n", input_target_ptr2); } for (iterCnt = 0u; iterCnt < prms->numOutImgs; iterCnt ++) { output_desc = (tivx_obj_desc_image_t *) tivxGetObjDescElement(obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX],iterCnt); output_target_ptr = tivxMemShared2TargetPtr(&output_desc->mem_ptr[0]); VX_PRINT(VX_ZONE_INFO, "output_target_ptr = %p\n", output_target_ptr); if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { output_target_ptr2 = tivxMemShared2TargetPtr(&output_desc->mem_ptr[1]); VX_PRINT(VX_ZONE_INFO, "output_target_ptr2 = %p\n", output_target_ptr2); } /* call kernel processing function */ drvObj = &prms->drvObj; /* Assign input buffer addresses */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = &drvObj->inFrm[pipeIdx]; frm->addr[0U] = ((uint64_t)input_target_ptr) + iterCnt*input_desc->imagepatch_addr[0].stride_y; if((vx_df_image)VX_DF_IMAGE_NV12 == input_desc->format) { frm->addr[1U] = ((uint64_t)input_target_ptr2) + iterCnt*input_desc->imagepatch_addr[1].stride_y; } } /* Assign output buffer addresses */ frm = drvObj->outFrm; frm->addr[0U] = (uint64_t)output_target_ptr; if((vx_df_image)VX_DF_IMAGE_NV12 == output_desc->format) { frm->addr[1U] = (uint64_t)output_target_ptr2; } /* Submit the request to the driver */ fvid2_status = Fvid2_processRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, FVID2_TIMEOUT_FOREVER); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Submit Request\n"); status = (vx_status)VX_FAILURE; } else { /* Wait for Frame Completion */ tivxEventWait(drvObj->waitForProcessCmpl, TIVX_EVENT_TIMEOUT_WAIT_FOREVER); fvid2_status = Fvid2_getProcessedRequest(drvObj->drvHandle, &drvObj->inFrmList, &drvObj->outFrmList, 0); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); status = (vx_status)VX_FAILURE; } } } /* kernel processing function complete */ } return status; } static vx_status VX_CALLBACK tivxDisplayM2MCreate( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; tivx_obj_desc_user_data_object_t *configuration_desc; tivx_obj_desc_image_t *obj_desc_imageIn, *obj_desc_imageOut; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { configuration_desc = (tivx_obj_desc_user_data_object_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]; obj_desc_imageIn = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]; obj_desc_imageOut = (tivx_obj_desc_image_t *)obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]; if (configuration_desc->mem_size != sizeof(tivx_display_m2m_params_t)) { VX_PRINT(VX_ZONE_ERROR, "User data object size on target does not match the size on host, possibly due to misalignment in data structure\n"); status = (vx_status)VX_FAILURE; } prms = tivxDispM2mAllocObject(&gTivxDispM2mInstObj); if (NULL == prms) { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } /* Create Node object elements */ if ((vx_status)VX_SUCCESS == status) { status = tivxDisplayM2MSetCreateParams(prms, configuration_desc, obj_desc_imageIn, obj_desc_imageOut); } /* Create sync events */ if (status == (vx_status)VX_SUCCESS) { status = tivxEventCreate(&prms->drvObj.waitForProcessCmpl); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to allocate Event\n"); } } /* DSS M2M Driver create and configuration */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvCfg(&prms->drvObj); } if ((vx_status)VX_SUCCESS == status) { tivxSetTargetKernelInstanceContext(kernel, prms, sizeof(tivxDisplayM2MParams)); } else { status = (vx_status)VX_ERROR_NO_MEMORY; VX_PRINT(VX_ZONE_ERROR, "Unable to allocate local memory\n"); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MDelete( tivx_target_kernel_instance kernel, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; tivxDisplayM2MParams *prms = NULL; uint32_t size; int32_t fvid2_status = FVID2_SOK; if ( (num_params != TIVX_KERNEL_DISPLAY_M2M_MAX_PARAMS) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_CONFIGURATION_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_INPUT_IDX]) || (NULL == obj_desc[TIVX_KERNEL_DISPLAY_M2M_OUTPUT_IDX]) ) { status = (vx_status)VX_FAILURE; } else { status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: Could not obtain kernel instance context !!!\n"); } if(NULL == prms) { VX_PRINT(VX_ZONE_ERROR, "Kernel instance context is NULL!!!\n"); status = (vx_status)VX_FAILURE; } if ((vx_status)VX_SUCCESS == status) { /* Stop Display M2M Driver */ fvid2_status = Fvid2_stop(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 DSS M2M not stopped !!!\n"); } } if ((vx_status)VX_SUCCESS == status) { /* Dequeue all the request from the driver */ while ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_getProcessedRequest(prms->drvObj.drvHandle, &prms->drvObj.inFrmList, &prms->drvObj.outFrmList, 0); if (FVID2_SOK != fvid2_status) { if (fvid2_status != FVID2_ENO_MORE_BUFFERS) { VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n"); } status = (vx_status)VX_FAILURE; } } if (fvid2_status == FVID2_ENO_MORE_BUFFERS) { status = (vx_status)VX_SUCCESS; } } if ((vx_status)VX_SUCCESS == status) { /* print status */ fvid2_status = Fvid2_control(prms->drvObj.drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &prms->drvObj.wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { printf( "==========================================================\r\n"); printf( " Display M2M Status: Instance|%d\r\n", prms->drvObj.instId); printf( "==========================================================\r\n"); printf( " Queue Count: %d\r\n", prms->drvObj.wbStatus.queueCount); printf( " De-queue Count: %d\r\n", prms->drvObj.wbStatus.dequeueCount); printf( " Write-back Frames Count: %d\r\n", prms->drvObj.wbStatus.wbFrmCount); printf( " Underflow Count: %d\r\n", prms->drvObj.wbStatus.underflowCount); } } if ((vx_status)VX_SUCCESS == status) { /* Delete FVID2 handle */ fvid2_status = Fvid2_delete(prms->drvObj.drvHandle, NULL); if (FVID2_SOK != fvid2_status) { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, " DSS M2M: ERROR: FVID2 Delete Failed !!!\n"); } else { prms->drvObj.drvHandle = NULL; } } if ((vx_status)VX_SUCCESS == status) { /* Delete event */ tivxEventDelete(&prms->drvObj.waitForProcessCmpl); } if ((NULL != prms) && (sizeof(tivxDisplayM2MParams) == size)) { tivxDispM2mFreeObject(&gTivxDispM2mInstObj, prms); //tivxMemFree(prms, size, (vx_enum)TIVX_MEM_EXTERNAL); } } return status; } static vx_status VX_CALLBACK tivxDisplayM2MControl( tivx_target_kernel_instance kernel, uint32_t node_cmd_id, tivx_obj_desc_t *obj_desc[], uint16_t num_params, void *priv_arg) { vx_status status = (vx_status)VX_SUCCESS; int32_t fvid2_status = FVID2_SOK; uint32_t size; tivxDisplayM2MParams *prms = NULL; tivxDisplayM2MDrvObj *drvObj; tivx_display_m2m_statistics_t *m2m_status_prms = NULL; void *target_ptr; tivx_obj_desc_user_data_object_t *usr_data_obj; status = tivxGetTargetKernelInstanceContext(kernel, (void **)&prms, &size); if (((vx_status)VX_SUCCESS != status) || (NULL == prms) || (sizeof(tivxDisplayM2MParams) != size)) { status = (vx_status)VX_FAILURE; } if (status == (vx_status)VX_SUCCESS) { switch (node_cmd_id) { case TIVX_DISPLAY_M2M_GET_STATISTICS: { if (NULL != obj_desc[0]) { drvObj = &prms->drvObj; fvid2_status = Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_GET_CURRENT_STATUS, &drvObj->wbStatus, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, "Get status returned failure\n"); status = (vx_status)VX_FAILURE; } else { /* Update return status object */ usr_data_obj = (tivx_obj_desc_user_data_object_t *)obj_desc[0U]; target_ptr = tivxMemShared2TargetPtr(&usr_data_obj->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); if (sizeof(tivx_display_m2m_statistics_t) == usr_data_obj->mem_size) { m2m_status_prms = (tivx_display_m2m_statistics_t *)target_ptr; m2m_status_prms->queueCount = drvObj->wbStatus.queueCount; m2m_status_prms->dequeueCount = drvObj->wbStatus.dequeueCount; m2m_status_prms->wbFrmCount = drvObj->wbStatus.wbFrmCount; m2m_status_prms->underflowCount = drvObj->wbStatus.underflowCount; } else { VX_PRINT(VX_ZONE_ERROR, "Invalid Size \n"); status = (vx_status)VX_ERROR_INVALID_PARAMETERS; } tivxCheckStatus(&status, tivxMemBufferUnmap(target_ptr, usr_data_obj->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_WRITE_ONLY)); } } else { VX_PRINT(VX_ZONE_ERROR, "User data object was NULL\n"); status = (vx_status)VX_FAILURE; } break; } default: { VX_PRINT(VX_ZONE_ERROR, "Invalid Command Id\n"); status = (vx_status)VX_FAILURE; break; } } } return status; } void tivxAddTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_FAILURE; char target_name[TIVX_TARGET_MAX_NAME]; vx_enum self_cpu; self_cpu = tivxGetSelfCpuId(); if ( self_cpu == (vx_enum)TIVX_CPU_ID_MCU2_0 ) { strncpy(target_name, TIVX_TARGET_DISPLAY_M2M1, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel1 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M2, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel2 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M3, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel3 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); strncpy(target_name, TIVX_TARGET_DISPLAY_M2M4, TIVX_TARGET_MAX_NAME); vx_display_m2m_target_kernel4 = tivxAddTargetKernelByName( TIVX_KERNEL_DISPLAY_M2M_NAME, target_name, tivxDisplayM2MProcess, tivxDisplayM2MCreate, tivxDisplayM2MDelete, tivxDisplayM2MControl, NULL); status = tivxMutexCreate(&gTivxDispM2mInstObj.lock); if ((vx_status)VX_SUCCESS != status) { VX_PRINT(VX_ZONE_ERROR, "Failed to create Mutex\n"); } else { memset(&gTivxDispM2mInstObj.m2mObj, 0x0, sizeof(tivxDisplayM2MParams) * DISPLAY_M2M_MAX_HANDLES); } } } void tivxRemoveTargetKernelDisplayM2M(void) { vx_status status = (vx_status)VX_SUCCESS; status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel1); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel1 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel2); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel2 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel3); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel3 = NULL; } status = tivxRemoveTargetKernel(vx_display_m2m_target_kernel4); if (status == (vx_status)VX_SUCCESS) { vx_display_m2m_target_kernel4 = NULL; } if (NULL != gTivxDispM2mInstObj.lock) { tivxMutexDelete(&gTivxDispM2mInstObj.lock); } } static vx_status tivxDisplayM2MSetCreateParams( tivxDisplayM2MParams *prms, const tivx_obj_desc_user_data_object_t *obj_desc, const tivx_obj_desc_image_t *obj_desc_imageIn, const tivx_obj_desc_image_t *obj_desc_imageOut) { vx_status status = (vx_status)VX_SUCCESS; void *cfgPtr; tivx_display_m2m_params_t *createParams; tivxDisplayM2MDrvObj *drvObj; uint32_t pipeIdx, layerIdx, pitchIdx; Dss_DispParams *dispParams; CSL_DssWbPipeCfg *wbPipeCfg; Dss_DctrlOverlayParams *ovrParams; Dss_DctrlOverlayLayerParams *layerParams; Fvid2_Frame *frm; cfgPtr = tivxMemShared2TargetPtr(&obj_desc->mem_ptr); tivxCheckStatus(&status, tivxMemBufferMap(cfgPtr, obj_desc->mem_size, (vx_enum)VX_MEMORY_TYPE_HOST, (vx_enum)VX_READ_ONLY)); if (status == (vx_status)VX_SUCCESS) { createParams = (tivx_display_m2m_params_t *)cfgPtr; memcpy(&prms->createParams, createParams, sizeof(tivx_display_m2m_params_t)); drvObj = &prms->drvObj; /* Set Driver object */ drvObj->instId = createParams->instId; drvObj->numPipe = createParams->numPipe; drvObj->overlayId = createParams->overlayId; memcpy(&drvObj->pipeId[0U], &createParams->pipeId[0U], sizeof(createParams->pipeId)); if (createParams->enable_deiniterleave) { tivx_obj_desc_t *obj_desc = (tivx_obj_desc_t *)obj_desc_imageOut; if((vx_enum)obj_desc->type==(vx_enum)TIVX_OBJ_DESC_OBJARRAY) { tivx_obj_desc_object_array_t *obj_desc_obj_array; obj_desc_obj_array = (tivx_obj_desc_object_array_t *)obj_desc; prms->numOutImgs = 4;//obj_desc_obj_array->num_items; } else { if ((vx_enum)TIVX_OBJ_DESC_INVALID != (vx_enum)obj_desc->scope_obj_desc_id) { tivx_obj_desc_object_array_t *parent_obj_desc = NULL; tivxGetObjDescList( &obj_desc->scope_obj_desc_id, (tivx_obj_desc_t**)&parent_obj_desc, 1); if (parent_obj_desc != NULL) { prms->numOutImgs = 4;//parent_obj_desc->num_items; } else { prms->numOutImgs = 4u; } } else { prms->numOutImgs = 4u; } } } else { prms->numOutImgs = 4u; } } /* Initialize driver object */ if (status == (vx_status)VX_SUCCESS) { status = tivxDisplayM2MDrvStructsInit(drvObj); } /* set driver object parameters */ if (status == (vx_status)VX_SUCCESS) { /* Callback parameters */ drvObj->cbParams.cbFxn = (Fvid2_CbFxn) (&tivxDisplayM2MCallback); drvObj->cbParams.appData = drvObj; drvObj->createParams.numPipe = drvObj->numPipe; drvObj->createParams.overlayId = drvObj->overlayId; /* Set Display pipeline parameters */ for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { dispParams = &drvObj->pipeCfg[pipeIdx].cfgParams; drvObj->createParams.pipeId[pipeIdx] = drvObj->pipeId[pipeIdx]; drvObj->pipeCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->mFlagCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; drvObj->cscCfg[pipeIdx].pipeId = drvObj->pipeId[pipeIdx]; dispParams->pipeCfg.pipeType = CSL_DSS_VID_PIPE_TYPE_VID; dispParams->layerPos.startX = 0U; dispParams->layerPos.startY = 0U; dispParams->pipeCfg.scEnable = FALSE; dispParams->alphaCfg.globalAlpha = 0xFFU; dispParams->alphaCfg.preMultiplyAlpha = FALSE; status = tivxDisplayExtractFvid2Format( obj_desc_imageIn, &dispParams->pipeCfg.inFmt); if (status == (vx_status)VX_SUCCESS) { if (createParams->enable_deiniterleave) { dispParams->pipeCfg.inFmt.height = dispParams->pipeCfg.inFmt.height / prms->numOutImgs; /* Set video pipe output frame dimensions same as input as no scaling is done in video pipe-line */ dispParams->pipeCfg.outWidth = dispParams->pipeCfg.inFmt.width; dispParams->pipeCfg.outHeight = dispParams->pipeCfg.inFmt.height; for (pitchIdx = 0; pitchIdx < 3; pitchIdx ++) { dispParams->pipeCfg.inFmt.pitch[pitchIdx] = dispParams->pipeCfg.inFmt.pitch[pitchIdx] * prms->numOutImgs; } } /* Set video pipe output frame dimensions same as input as no scaling is done in video pipe-line */ dispParams->pipeCfg.outWidth = dispParams->pipeCfg.inFmt.width; dispParams->pipeCfg.outHeight = dispParams->pipeCfg.inFmt.height; } else { status = (vx_status)VX_FAILURE; VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); break; } } /* Set Display WB pipeline parameters */ if (((vx_status)VX_SUCCESS == status) && (pipeIdx > 0)) { wbPipeCfg = &drvObj->wbCfg.pipeCfg; /* Set WB pipe input frame dimensions same as video pipe input/output frame, no scaling is done in video pipe, it will be done in WB pipe-line */ wbPipeCfg->inFmt.width = dispParams->pipeCfg.outWidth; wbPipeCfg->inFmt.height = dispParams->pipeCfg.outHeight; wbPipeCfg->inPos.startX = 0U; wbPipeCfg->inPos.startY = 0U; status = tivxDisplayExtractFvid2Format(obj_desc_imageOut, &wbPipeCfg->outFmt); if (status != (vx_status)VX_SUCCESS) { VX_PRINT(VX_ZONE_ERROR, "Invalid Input Image\n"); status = (vx_status)VX_FAILURE; } else { if ((wbPipeCfg->inFmt.width != wbPipeCfg->outFmt.width) || (wbPipeCfg->inFmt.height != wbPipeCfg->outFmt.height)) { wbPipeCfg->scEnable = TRUE; } } } /* Set Display WB pipeline parameters */ if ((vx_status)VX_SUCCESS == status) { ovrParams = &drvObj->ovrCfg; ovrParams->overlayId = drvObj->overlayId; ovrParams->colorbarEnable = FALSE; ovrParams->overlayCfg.colorKeyEnable = FALSE; ovrParams->overlayCfg.colorKeySel = CSL_DSS_OVERLAY_TRANS_COLOR_DEST; ovrParams->overlayCfg.backGroundColor = 0xc8c800U; layerParams = &drvObj->layerCfg; layerParams->overlayId = drvObj->overlayId; /* Set all layer to invalid first and then update only used ones */ for(layerIdx = 0U ; layerIdx < CSL_DSS_VID_PIPE_ID_MAX ; layerIdx++) { layerParams->pipeLayerNum[layerIdx] = CSL_DSS_OVERLAY_LAYER_INVALID; } /* Currently blending is not supported so only one layer is used. This code needs to updated when blending is supported. */ layerParams->pipeLayerNum[drvObj->createParams.pipeId[0U]] = CSL_DSS_OVERLAY_LAYER_NUM_0; } /* Update frame-lists */ if ((vx_status)VX_SUCCESS == status) { drvObj->inFrmList.numFrames = drvObj->numPipe; for (pipeIdx = 0U ; pipeIdx < drvObj->numPipe ; pipeIdx++) { frm = (Fvid2_Frame *) &drvObj->inFrm[pipeIdx]; frm->chNum = drvObj->createParams.pipeId[pipeIdx]; drvObj->inFrmList.frames[pipeIdx] = frm; } frm = (Fvid2_Frame *) &drvObj->outFrm[0U]; drvObj->outFrmList.frames[0U] = frm; drvObj->outFrmList.numFrames = 1U; } } return status; } static vx_status tivxDisplayM2MDrvStructsInit(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; /* Initialize driver create parameters */ Dss_m2mCreateParamsInit(&drvObj->createParams); /* Initialize driver call-back parameters */ Fvid2CbParams_init(&drvObj->cbParams); /* Initialize driver pipe configuration parameters */ for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { Dss_dispParamsInit(&drvObj->pipeCfg[loopCnt].cfgParams); Dss_dispPipeMflagParamsInit(&drvObj->mFlagCfg[loopCnt].mFlagCfg); CSL_dssCscCoeffInit(&drvObj->cscCfg[loopCnt].csc); } /* Initialize WB pipeline parameters */ Dss_m2mPipeCfgParamsInit(&drvObj->wbCfg); CSL_dssWbPipeDmaCfgInit(&drvObj->wbDmaCfg); Dss_m2mMFlagParamsInit(&drvObj->wbMflagCfg); CSL_dssCscCoeffInit(&drvObj->wbCscCfg); Dss_m2mStatusInit(&drvObj->wbStatus); /* Initialize Display overlay parameters */ Dss_dctrlOverlayParamsInit(&drvObj->ovrCfg); Dss_dctrlOverlayLayerParamsInit(&drvObj->layerCfg); /* Initialize Display global parameters */ Dss_dctrlGlobalDssParamsInit(&drvObj->globalParams); /* Initialize input and output frame lists */ Fvid2FrameList_init(&drvObj->inFrmList); Fvid2FrameList_init(&drvObj->outFrmList); return status; } static vx_status tivxDisplayM2MDrvCfg(tivxDisplayM2MDrvObj *drvObj) { vx_status status = (vx_status)VX_SUCCESS; uint32_t loopCnt; int32_t fvid2_status = FVID2_SOK; /* Display M2M Driver create */ drvObj->drvHandle = Fvid2_create(DSS_M2M_DRV_ID, drvObj->instId, &drvObj->createParams, &drvObj->createStatus, &drvObj->cbParams); if((NULL == drvObj->drvHandle) || (drvObj->createStatus.retVal != FVID2_SOK)) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Create Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } /* Display M2M pipe configuration */ if ((vx_status)VX_SUCCESS == status) { for (loopCnt = 0U ; loopCnt < drvObj->numPipe ; loopCnt++) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_PARAMS, &drvObj->pipeCfg[loopCnt], NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_PIPE_MFLAG_PARAMS, &drvObj->mFlagCfg[loopCnt], NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M DISP IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; break; } } } /* Display M2M overlay configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_OVERLAY_PARAMS, &drvObj->ovrCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_LAYER_PARAMS, &drvObj->layerCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Overlay IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M global configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_DCTRL_SET_GLOBAL_DSS_PARAMS, &drvObj->globalParams, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Global IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Display M2M write-back pipe configuration */ if ((vx_status)VX_SUCCESS == status) { fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_PARAMS, &drvObj->wbCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_MFLAG_PARAMS, &drvObj->wbMflagCfg, NULL); fvid2_status += Fvid2_control(drvObj->drvHandle, IOCTL_DSS_M2M_SET_WB_PIPE_DMA_CFG, &drvObj->wbDmaCfg, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M WB IOCTL Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } /* Start Display M2M Driver */ if ((vx_status)VX_SUCCESS == status) { fvid2_status = Fvid2_start(drvObj->drvHandle, NULL); if (FVID2_SOK != fvid2_status) { VX_PRINT(VX_ZONE_ERROR, ": Display M2M Driver Start Failed!!!\r\n"); status = (vx_status)VX_FAILURE; } } return status; } static int32_t tivxDisplayM2MCallback(Fvid2_Handle handle, void *appData) { tivxDisplayM2MDrvObj *drvObj = (tivxDisplayM2MDrvObj *)(appData); if ((NULL != drvObj) && (drvObj->waitForProcessCmpl != NULL)) { tivxEventPost(drvObj->waitForProcessCmpl); } return (vx_status)VX_SUCCESS; } static vx_status tivxDisplayExtractFvid2Format( const tivx_obj_desc_image_t *obj_desc_img, Fvid2_Format *format) { vx_status status = (vx_status)VX_SUCCESS; Fvid2Format_init(format); format->width = obj_desc_img->imagepatch_addr[0].dim_x; format->height = obj_desc_img->imagepatch_addr[0].dim_y; format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->scanFormat = FVID2_SF_PROGRESSIVE; switch (obj_desc_img->format) { case (vx_df_image)TIVX_DF_IMAGE_RGB565: format->dataFormat = FVID2_DF_BGR16_565; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGB: format->dataFormat = FVID2_DF_RGB24_888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_RGBX: format->dataFormat = FVID2_DF_RGBX24_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)TIVX_DF_IMAGE_BGRX: format->dataFormat = FVID2_DF_BGRX32_8888; format->pitch[FVID2_RGB_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_UYVY: format->dataFormat = FVID2_DF_YUV422I_UYVY; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_YUYV: format->dataFormat = FVID2_DF_YUV422I_YUYV; format->pitch[FVID2_YUV_INT_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_NV12: format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[1].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U16: format->ccsFormat = FVID2_CCSF_BITS12_UNPACKED16; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; case (vx_df_image)VX_DF_IMAGE_U8: format->ccsFormat = FVID2_CCSF_BITS8_PACKED; format->dataFormat = FVID2_DF_YUV420SP_UV; format->pitch[FVID2_YUV_SP_Y_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; format->pitch[FVID2_YUV_SP_CBCR_ADDR_IDX] = (uint32_t)obj_desc_img->imagepatch_addr[0].stride_y; break; default: status = (vx_status)VX_FAILURE; break; } return status; } static tivxDisplayM2MParams *tivxDispM2mAllocObject(tivxDisplayM2MInstObj *instObj) { uint32_t cnt; tivxDisplayM2MParams *m2mObj = NULL; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (0U == instObj->m2mObj[cnt].isAlloc) { m2mObj = &instObj->m2mObj[cnt]; memset(m2mObj, 0x0, sizeof(tivxDisplayM2MParams)); instObj->m2mObj[cnt].isAlloc = 1U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); return (m2mObj); } static void tivxDispM2mFreeObject(tivxDisplayM2MInstObj *instObj, tivxDisplayM2MParams *m2mObj) { uint32_t cnt; /* Lock instance mutex */ tivxMutexLock(instObj->lock); for (cnt = 0U; cnt < DISPLAY_M2M_MAX_HANDLES; cnt ++) { if (m2mObj == &instObj->m2mObj[cnt]) { m2mObj->isAlloc = 0U; break; } } /* Release instance mutex */ tivxMutexUnlock(instObj->lock); } j7_display_m2m.h Hi, No, it should not take such a high time. On which SoC are you trying to run this example? Also how are you measuring the time? It should take less than 15ms to finish all 4 frame processing in the default SDK release. Have you made any changes in the SDK release? or are you using this overlay, which is also used for DSS M2M path? Regards, Brijesh hi The time we measure with the oscilloscope is still around 60ms, by pulling up and down the GPIO also, the data we moved through M2M was 12.5MB Hi Hirain team, I have discussed with Brijesh via Webex, it means nothing as you profile the VxProcessGraph function, because ProcessGRaph does a lot of things. So it is not good idea to check the performance around process graph. so pls move on to next step to integrate to real project, and to see the final effect. In the meanwhile TI can check the performance of DSS M2M node for this sample example and share you the result by tomorrow. BR, Biao Hi Biao, Hirain Team, I profiled the process function in the DSS M2M node for the same configuration and it takes around ~12ms to complete processing for all 4 frames, so DSS M2M path works as expected. Regards, Brijesh Hi Biao, Hirain Team, Essentially, I have added an array in dss m2m node to store the time information. Please find attached updated file. After running it for 1000 frames, we need to connect CCS to get the timestamp values. /cfs-file/__key/communityserver-discussions-components-files/791/3386.vx_5F00_display_5F00_m2m_5F00_target.c Regards, Brijesh Hi Brijesh, according to your suggestion, we has printed the timestamp and found that it took about 12ms for deinterleaving each time, but using the print function provided by multi_cam, this value is about 50ms, which data is credible? Hi Mingda xu, Are you also replicating this node? Because if you replicate this node, framework is going to create multiple replica of this node and then performance here is for addition of all nodes performance. If you are doing 4 times replication, 12 x 4 = 50 + some overhead, this will be around 50ms. So both are credible numbers. Where are going to use this node? Is it in some other replicated node? Lets say can you add LDC node after this node for YUV422 to YUV420 conversion and replicate LDC node, so that it allocates memory for all objects in input object array? Then you dont require to replicate this DSS M2M node. Regards, Brijesh Hello Brijesh, It is not our intention to replicate M2M node. The example you gave include the replication. Our use case is 1 image to 4 images (array). We tried to remove vxReplicateNode in the demo and the App isn't working. Regards, Sijie Zhu Hi Sijie Zhu, Yes, in the above application, if you remove call to vxReplicateNode, it will not work, because framework then does not allocate memory for all images of the object array. In order to allocate the memory, we need to call replicate node for one of the node, where this object array is going to be used. Because of the replicate node, the performance becomes 4 times the actual performance and this in a way proves that DSS M2M is working fine with the good performance. I would suggest to use it in your actual application, where output of DSS M2M node is going to be used in replicated node. Regards, Brijesh Hi Brijesh, according to my understanding, four identical m2m nodes are executed in parallel, so the execution time should be 12 ms instead of 50 ms. Or maybe it's because there is only one DMA channel causing the four m2m nodes to only be executed sequentially? In addition, a practical application scenario contains a number of nodes as follows: capture->m2m->ldc->algorithm provider self defined->display. Could you please leave us improvement with the above graph structure? Thanks a lot. Regards, Mingda Hi Mingda, DSS M2M is a single HW block, so it is not possible to run/execute 4 channels in parallel. It will execute/run serially only and so execution time will be around 50ms. mingda.xu said: In addition, a practical application scenario contains a number of nodes as follows: capture->m2m->ldc->algorithm provider self defined->display. Could you please leave us improvement with the above graph structure? In the above graph, - capture is a single instance node outputting a single vx_image - m2m is a single instance node, taking vx_image as input and an instance of vx_image from object array output image. - ldc node runs on 4 images, it is replicated node and takes an instance of vx_image from object array as input image. - not sure what algorithm is doing here, but if it needs to run on all 4 images, it should also be replicated. - display can be enabled to display one of the output image of the algorithm. Regards, Brijesh Hi Mingda, Can you please try with the attached file? I have added LDC for YUV422 to YUV420 conversion. Can you please try this? /cfs-file/__key/communityserver-discussions-components-files/791/5488.test_5F00_display_5F00_m2m.c Regards, brijesh Hi Brijesh, when I try to apply your patch to multi_cam demo, an error about vxReplicateNode() occurs: I try to compare the code app_ldc_module.c with your test_display_m2m.c patch and find that your patch lose the vxSetNodetarget() part for ldc node. The second image is about app_create_graph_ldc() in multi_cam demo. Any suggestion about failure in vxReplicateNode()? Thanks a lot. Regards, Mingda Xu Hi Mingda xu, Yes, that's one error. Can you please set the target to LDC by calling vxSetTargetNode for LDC node? You can use same as app_create_graph_ldc API. But what i am surprised is, it says the second array has 8 elements, ie output image array of LDC has 8 elements, that should not happen. I see i have created an array of 4 in below statement. Is there any change in below code? vx_object_array ldc_out_img_array = vxCreateObjectArray(context, (vx_reference)out_image, 4); vxReleaseImage(&out_image); Regards, Brijesh