# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# License); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2021, OPEN AI LAB
# Author: lswang@openailab.com
#

# unset for regeneration
UNSET (_TENGINE_DEVICE_SOURCE)
UNSET (_TENGINE_DEVICE_HEADER_PATH)
UNSET (_TENGINE_DEVICE_COMPILER_DEFINES)
UNSET (_TENGINE_DEVICE_COMPILER_OPTIONS)
UNSET (_TENGINE_DEVICE_LINKER_OPTIONS)
UNSET (_TENGINE_DEVICE_LINK_LIBRARIES)
UNSET (_REGISTER_DEVICE_LIST)


# include each device, manually for now
ADD_SUBDIRECTORY (cpu)


# device level source files
FILE (GLOB   _DEVICE_SOURCE                     ${CMAKE_SOURCE_DIR}/source/device/*.c)
LIST (APPEND _TENGINE_DEVICE_SOURCE             ${_DEVICE_SOURCE})
LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_CPU_DEVICE_SOURCE})
LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_CPU_REF_SOURCE})

# add to src group
TENGINE_SOURCE_GROUP ("device" ${_DEVICE_SOURCE})


IF (TENGINE_STANDALONE_HCL)
    # TODO: finish this standalone mode
ELSE()
    LIST (APPEND _TENGINE_DEVICE_SOURCE         ${TENGINE_CPU_HCL_SOURCE})
ENDIF()


# for CPU
LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_CPU_HEADER_PATH})
LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_CPU_COMPILER_DEFINES})
LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_CPU_COMPILER_OPTIONS})
LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_CPU_LINKER_OPTIONS})
LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_CPU_LINK_LIBRARIES})
LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/cpu/cpu_device.c")


# Arm Compute Library
IF (TENGINE_ENABLE_ACL)
    ADD_SUBDIRECTORY (acl)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_ACL_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_ACL_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_ACL_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_ACL_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_ACL_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_ACL_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_ACL_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/acl/acl_device.cc")
ENDIF()


# nVIDIA CUDA
IF (TENGINE_ENABLE_CUDA)
    ADD_SUBDIRECTORY (cuda)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_CUDA_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_CUDA_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_CUDA_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_CUDA_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_CUDA_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_CUDA_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_CUDA_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/cuda/cuda_device.cc")
ENDIF()


# Khronos OpenCL
IF (TENGINE_ENABLE_OPENCL)
    ADD_SUBDIRECTORY (opencl)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_OCL_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_OCL_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_OCL_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_OCL_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_OCL_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_OCL_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_OCL_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/opencl/ocl_device.cc")
ENDIF()


# OPENDLA
IF (TENGINE_ENABLE_OPENDLA)
    ADD_SUBDIRECTORY (opendla)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_ODLA_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_ODLA_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_ODLA_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_ODLA_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_ODLA_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_ODLA_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_ODLA_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/openda/odla_device.cc")
ENDIF()


# nVIDIA TensorRT
IF (TENGINE_ENABLE_TENSORRT)
    ADD_SUBDIRECTORY (tensorrt)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_TENSORRT_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_TENSORRT_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_TENSORRT_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_TENSORRT_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_TENSORRT_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_TENSORRT_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_TENSORRT_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/tensorrt/trt_device.cc")
ENDIF()


# VeriSilicon TIM-VX
IF (TENGINE_ENABLE_TIM_VX)
    ADD_SUBDIRECTORY (tim-vx)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_TIM_VX_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_TIM_VX_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_TIM_VX_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_TIM_VX_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_TIM_VX_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_TIM_VX_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_TIM_VX_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/tim-vx/timvx_device.cc")
ENDIF()

# libTorch
IF (TENGINE_ENABLE_TORCH)
    ADD_SUBDIRECTORY (torch)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_TORCH_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_TORCH_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_TORCH_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_TORCH_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_TORCH_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_TORCH_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_TORCH_DEVICE_SOURCE})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/torch/torch_device.cc")
ENDIF()

# Khronos Vulkan
IF (TENGINE_ENABLE_VULKAN)
    ADD_SUBDIRECTORY (vulkan)

    LIST (APPEND _TENGINE_DEVICE_HEADER_PATH        ${TENGINE_VULKAN_HEADER_PATH})
    LIST (APPEND _TENGINE_DEVICE_LINK_PATH          ${TENGINE_VULKAN_LINK_PATH})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_DEFINES   ${TENGINE_VULKAN_COMPILER_DEFINES})
    LIST (APPEND _TENGINE_DEVICE_COMPILER_OPTIONS   ${TENGINE_VULKAN_COMPILER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINKER_OPTIONS     ${TENGINE_VULKAN_LINKER_OPTIONS})
    LIST (APPEND _TENGINE_DEVICE_LINK_LIBRARIES     ${TENGINE_VULKAN_LINK_LIBRARIES})
    LIST (APPEND _TENGINE_DEVICE_SOURCE             ${TENGINE_VULKAN_DEVICE_SOURCE})
    LIST (APPEND _TENGINE_DEVICE_DEPENDS_FORWARD    ${TENGINE_VULKAN_DEPENDS_FORWARD})
    LIST (APPEND _REGISTER_DEVICE_LIST              "${CMAKE_SOURCE_DIR}/source/device/vulkan/vulkan_device.cc")
ENDIF()


# set var to cache
SET (TENGINE_DEVICE_HEADER_PATH         ${_TENGINE_DEVICE_HEADER_PATH}      CACHE INTERNAL "Tengine device level header files searching path" FORCE)
SET (TENGINE_DEVICE_LINK_PATH           ${_TENGINE_DEVICE_LINK_PATH}        CACHE INTERNAL "Tengine device level link libraries searching path" FORCE)
SET (TENGINE_DEVICE_SOURCE              ${_TENGINE_DEVICE_SOURCE}           CACHE INTERNAL "Tengine device level source files" FORCE)
SET (TENGINE_DEVICE_COMPILER_DEFINES    ${_TENGINE_DEVICE_COMPILER_DEFINES} CACHE INTERNAL "Tengine device about compiler defines" FORCE)
SET (TENGINE_DEVICE_COMPILER_OPTIONS    ${_TENGINE_DEVICE_COMPILER_OPTIONS} CACHE INTERNAL "Tengine device about compiler options" FORCE)
SET (TENGINE_DEVICE_LINKER_OPTIONS      ${_TENGINE_DEVICE_LINKER_OPTIONS}   CACHE INTERNAL "Tengine device about linker options" FORCE)
SET (TENGINE_DEVICE_LINK_LIBRARIES      ${_TENGINE_DEVICE_LINK_LIBRARIES}   CACHE INTERNAL "Tengine device about link libraries" FORCE)
SET (TENGINE_DEVICE_DEPENDS_FORWARD     ${_TENGINE_DEVICE_DEPENDS_FORWARD}   CACHE INTERNAL "Tengine device about depends project" FORCE)

# generate device register configuration
GENERATE_REGISTER_HEADER_FILE ("register_" "unregister_" "" "${CMAKE_SOURCE_DIR}/source/device/register.h.in" "${CMAKE_BINARY_DIR}/source/device/register.h" "${_REGISTER_DEVICE_LIST}")
