text: /****************************************************************************
  *
  *    Copyright (c) 2020 Vivante Corporation
  *
  *    Permission is hereby granted, free of charge, to any person obtaining a
  *    copy of this software and associated documentation files (the "Software"),
  *    to deal in the Software without restriction, including without limitation
  *    the rights to use, copy, modify, merge, publish, distribute, sublicense,
  *    and/or sell copies of the Software, and to permit persons to whom the
  *    Software is furnished to do so, subject to the following conditions:
  *
  *    The above copyright notice and this permission notice shall be included in
  *    all copies or substantial portions of the Software.
  *
  *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  *    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  *    DEALINGS IN THE SOFTWARE.
  *
  *****************************************************************************/
  
  
  #include <stdint.h>
  #include <stdlib.h>
  #include <string.h>
  #include "vsi_nn_types.h"
  #include "vsi_nn_tensor.h"
  #include "vsi_nn_graph.h"
  #include "vsi_nn_log.h"
  #include "vsi_nn_error.h"
  #include "vsi_nn_prv.h"
  #include "vsi_nn_tensor_util.h"
  #include "utils/vsi_nn_util.h"
  #include "kernel/vsi_nn_kernel.h"
  #include "libnnext/vx_lib_nnext.h"
  
  __BEGIN_DECLS
  
  /*
   * Define kernel meta.
   */
  #define _INPUT_NUM          (2)
  #define _OUTPUT_NUM         (1)
  #define _KERNEL_NAME        CVIVANTE_NAMESPACE("cpu.extra_ending")
  
  
  /*
   * Kernel params
   */
  static vx_param_description_t _extra_ending_kernel_param_def[] =
  {
      {VX_INPUT,  VX_TYPE_TENSOR, VX_PARAMETER_STATE_REQUIRED},
      {VX_INPUT,  VX_TYPE_TENSOR, VX_PARAMETER_STATE_REQUIRED},
      {VX_OUTPUT, VX_TYPE_TENSOR, VX_PARAMETER_STATE_REQUIRED},
      // Add kererl parameters here
  };
  #define _EXTRA_ENDING_PARAM_NUM  _cnt_of_array( _extra_ending_kernel_param_def )
  
  /*
   * Kernel function
   */
  DEF_KERNEL_EXECUTOR(_compute)
      (
      vsi_nn_kernel_node_t                node,
      const vsi_nn_kernel_node_param_t  * param,
      size_t                              param_size
      )
  {
      vsi_status status = VSI_FAILURE;
      vsi_nn_kernel_tensor_t input[_INPUT_NUM] = {NULL};
      vsi_nn_kernel_tensor_t output[_OUTPUT_NUM] = {NULL};
      uint8_t *u8_in_buffer[_INPUT_NUM] = {NULL};
      uint8_t *u8_out_buffer[_OUTPUT_NUM] = {NULL};
      vsi_nn_kernel_tensor_attr_t *in_attr[_INPUT_NUM] = {NULL};
      vsi_nn_kernel_tensor_attr_t *out_attr[_OUTPUT_NUM] = {NULL};
      vsi_size_t   out_stride_size[_OUTPUT_NUM][VSI_NN_MAX_DIM_NUM] = {{1}};
      vsi_size_t   out_elements[_OUTPUT_NUM] = {0};
      vsi_size_t   out_bytes[_OUTPUT_NUM] = {0};
      int32_t i = 0;
  
      /* prepare data */
      input[1] = (vsi_nn_kernel_tensor_t)param[1];
      in_attr[1] = vsi_nn_kernel_tensor_attr_create( input[1] );
      u8_in_buffer[1] = (uint8_t*)vsi_nn_kernel_tensor_create_buffer( input[1], in_attr[1], FALSE );
      CHECK_PTR_FAIL_GOTO( u8_in_buffer[i], "Create input buffer fail.", final );
  
      for (i = 0; i < _OUTPUT_NUM; i ++)
      {
          output[i] = (vsi_nn_kernel_tensor_t)param[i + _INPUT_NUM];
          out_attr[i] = vsi_nn_kernel_tensor_attr_create( output[i] );
          vsi_nn_kernel_tensor_attr_get_stride( out_attr[i], out_stride_size[i] );
          out_elements[i] = vsi_nn_kernel_tensor_attr_get_size( out_attr[i] );
          out_bytes[i] = out_elements[i] * sizeof(uint8_t);
          u8_out_buffer[i] = (uint8_t *)malloc( out_bytes[i] );
          CHECK_PTR_FAIL_GOTO( u8_out_buffer[i], "Create output buffer fail.", final );
          memset( u8_out_buffer[i], 0, out_bytes[i] );
      }
  
      memcpy(u8_out_buffer[0], u8_in_buffer[1], out_bytes[0]);
  
      for (i = 0; i < _OUTPUT_NUM; i ++)
      {
          status = vsi_nn_kernel_tensor_write( output[i], out_attr[i],
              u8_out_buffer[i], out_bytes[i] );
          CHECK_STATUS_FAIL_GOTO( status, final );
      }
  final:
      for (i = 0; i < _INPUT_NUM; i++)
      {
          vsi_nn_safe_free(u8_in_buffer[i]);
  
          if (in_attr[i])
          {
              vsi_nn_kernel_tensor_attr_release( &in_attr[i] );
          }
      }
      for (i = 0; i < _OUTPUT_NUM; i++)
      {
          vsi_nn_safe_free(u8_out_buffer[i]);
  
          if (out_attr[i])
          {
              vsi_nn_kernel_tensor_attr_release( &out_attr[i] );
          }
      }
  
      return status;
  } /* _compute() */
  
  
  /*
   * Query kernel
   */
  static vsi_status _query_kernel
      (
      vsi_nn_kernel_t * kernel,
      vsi_nn_tensor_t * const * const inputs,
      vsi_nn_tensor_t * const * const outputs
      )
  {
      vsi_status status = VSI_SUCCESS;
      snprintf( kernel->info.name, VX_MAX_KERNEL_NAME, "%s",  _KERNEL_NAME );
      kernel->info.function    = _compute;
      kernel->info.parameters  = _extra_ending_kernel_param_def;
      kernel->info.numParams   = _cnt_of_array( _extra_ending_kernel_param_def );
  
      return status;
  } /* _query_kernel() */
  
  
  static vsi_nn_kernel_node_t _setup
      (
      vsi_nn_graph_t              * graph,
      vsi_nn_tensor_t            ** inputs,
      size_t                        input_num,
      vsi_nn_tensor_t            ** outputs,
      size_t                        output_num,
      const vsi_nn_kernel_param_t * params,
      vsi_nn_kernel_t             * kernel
      )
  {
      vsi_status status = VSI_FAILURE;
      vsi_nn_kernel_node_param_t node_params[_EXTRA_ENDING_PARAM_NUM] = {NULL};
      vsi_nn_kernel_node_t node = NULL;
  
      status = _query_kernel( kernel, inputs, outputs );
      if ( VSI_SUCCESS == status)
      {
          node = vsi_nn_kernel_create_node( graph, kernel );
          if ( node )
          {
              /* Set inputs and outputs */
              vsi_nn_kernel_node_pack_io( node_params, _EXTRA_ENDING_PARAM_NUM,
                      inputs, input_num, outputs, output_num );
              /* Pass parameters to node. */
              status  = vsi_nn_kernel_node_pass_param( node, node_params, _EXTRA_ENDING_PARAM_NUM );
          }
      }
  
      return node;
  } /* _setup() */
  
  __END_DECLS
  
  REGISTER_BACKEND_CPU( extra_ending, _setup )
  