Program Listing for File DeviceCurve.cuh

Return to documentation for file (include/flamegpu/runtime/detail/curve/DeviceCurve.cuh)

#ifndef INCLUDE_FLAMEGPU_RUNTIME_DETAIL_CURVE_DEVICECURVE_CUH_
#define INCLUDE_FLAMEGPU_RUNTIME_DETAIL_CURVE_DEVICECURVE_CUH_

#include "flamegpu/runtime/detail/SharedBlock.h"
#include "flamegpu/runtime/detail/curve/Curve.cuh"
#include "flamegpu/exception/FLAMEGPUDeviceException_device.cuh"
#include "flamegpu/detail/type_decode.h"
#include "flamegpu/util/dstring.h"

#ifdef FLAMEGPU_USE_GLM
#ifdef __CUDACC__
#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
#pragma nv_diag_suppress = esa_on_defaulted_function_ignored
#else
#pragma diag_suppress = esa_on_defaulted_function_ignored
#endif  // __NVCC_DIAG_PRAGMA_SUPPORT__
#endif  // __CUDACC__
#include <glm/glm.hpp>
#endif  // FLAMEGPU_USE_GLM

namespace flamegpu {
namespace detail {
namespace curve {

class DeviceCurve {
 public:
    typedef Curve::Variable          Variable;                    // !< Typedef for cuRVE variable handle
    typedef Curve::VariableHash      VariableHash;                // !< Typedef for cuRVE variable name string hash
    typedef Curve::NamespaceHash     NamespaceHash;               // !< Typedef for cuRVE variable namespace string hash
    static const int MAX_VARIABLES = Curve::MAX_VARIABLES;        // !< Default maximum number of cuRVE variables (must be a power of 2)static const VariableHash EMPTY_FLAG = Curve::EMPTY_FLAG;
    static const VariableHash EMPTY_FLAG = Curve::EMPTY_FLAG;
    static const int UNKNOWN_VARIABLE = -1;                       // !< value returned as a Variable if an API function encounters an error


    __device__ __forceinline__ static Variable getVariableIndex(VariableHash variable_hash);

 private:
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static char* getVariablePtr(const char(&variableName)[M], VariableHash namespace_hash, unsigned int offset);

    template <typename T, unsigned int N = 1, unsigned int M>
    __device__ __forceinline__ static T getVariable(const char(&variableName)[M], VariableHash namespace_hash, unsigned int agent_index = 0, unsigned int array_index = 0);
    template <typename T, unsigned int N = 1, unsigned int M>
    __device__ __forceinline__ static T getVariable_ldg(const char(&variableName)[M], VariableHash namespace_hash, unsigned int agent_index = 0, unsigned int array_index = 0);
    template <typename T, unsigned int N = 1, unsigned int M>
    __device__ __forceinline__ static void setVariable(const char(&variableName)[M], VariableHash namespace_hash, T value, unsigned int agent_index = 0, unsigned int array_index = 0);

 public:
     __device__ __forceinline__ static void init(const CurveTable* __restrict__ d_curve_table) {
         using detail::sm;
         for (int idx = threadIdx.x; idx < Curve::MAX_VARIABLES; idx += blockDim.x) {
             sm()->curve_variables[idx] = d_curve_table->variables[idx];
             sm()->curve_hashes[idx] = d_curve_table->hashes[idx];
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
             sm()->curve_type_size[idx] = d_curve_table->type_size[idx];
             sm()->curve_elements[idx] = d_curve_table->elements[idx];
#endif
             sm()->curve_count[idx] = d_curve_table->count[idx];
         }
    }

    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getAgentVariable(const char(&variableName)[M], unsigned int index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getMessageVariable(const char(&variableName)[M], unsigned int index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getAgentVariable_ldg(const char(&variableName)[M], unsigned int index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getMessageVariable_ldg(const char(&variableName)[M], unsigned int index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getAgentArrayVariable(const char(&variableName)[M], unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getMessageArrayVariable(const char(&variableName)[M], unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getAgentArrayVariable_ldg(const char(&variableName)[M], unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getMessageArrayVariable_ldg(const char(&variableName)[M], unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static void setAgentVariable(const char(&variableName)[M], T variable, unsigned int index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static void setMessageVariable(const char(&variableName)[M], T variable, unsigned int index);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static void setNewAgentVariable(const char(&variableName)[M], T variable, unsigned int index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static void setAgentArrayVariable(const char(&variableName)[M], T variable, unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static void setMessageArrayVariable(const char(&variableName)[M], T variable, unsigned int variable_index, unsigned int array_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static void setNewAgentArrayVariable(const char(&variableName)[M], T variable, unsigned int variable_index, unsigned int array_index);

    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentProperty(const char(&propertyName)[M]);
    template <typename T, unsigned int N = 0, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentArrayProperty(const char(&propertyName)[M], unsigned int array_index);


    __device__ __forceinline__ static unsigned int *getEnvironmentDirectedGraphPBM(VariableHash graphHash);
    __device__ __forceinline__ static unsigned int* getEnvironmentDirectedGraphIPBM(VariableHash graphHash);
    __device__ __forceinline__ static unsigned int* getEnvironmentDirectedGraphIPBMEdges(VariableHash graphHash);
    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentDirectedGraphVertexProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int vertex_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentDirectedGraphVertexArrayProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int vertex_index, unsigned int array_index);

    template <typename T, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentDirectedGraphEdgeProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int edge_index);
    template <typename T, unsigned int N, unsigned int M>
    __device__ __forceinline__ static T getEnvironmentDirectedGraphEdgeArrayProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int edge_index, unsigned int array_index);

    template<typename T, unsigned int I = 1, unsigned int J = 1, unsigned int K = 1, unsigned int W = 1, unsigned int M>
    __device__ __forceinline__ static char *getEnvironmentMacroProperty(const char(&name)[M]);

    template <unsigned int M>
    __device__ __forceinline__ static unsigned int getVariableCount(const char(&variableName)[M], VariableHash namespace_hash);

    __device__ __forceinline__ static bool isAgent(const char* agent_name);
    __device__ __forceinline__ static bool isState(const char* agent_state);
};

__device__ __forceinline__ DeviceCurve::Variable DeviceCurve::getVariableIndex(const VariableHash variable_hash) {
    using detail::sm;
    // loop unrolling of hash collision detection
    // (This may inflate register usage based on the max number of iterations in some cases)
    for (unsigned int x = 0; x< MAX_VARIABLES; x++) {
        const Variable i = (variable_hash + x) & (MAX_VARIABLES - 1);
        if (sm()->curve_hashes[i] == variable_hash)
            return i;
    }
    return UNKNOWN_VARIABLE;
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ char* DeviceCurve::getVariablePtr(const char(&variableName)[M], const VariableHash namespace_hash, const unsigned int offset) {
    using detail::sm;
    const Variable cv = getVariableIndex(Curve::variableHash(variableName) + namespace_hash);
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
    if (cv == UNKNOWN_VARIABLE) {
        DTHROW("Curve variable with name '%s' was not found.\n", variableName);
        return nullptr;
    } else if (sm()->curve_type_size[cv] != sizeof(typename detail::type_decode<T>::type_t)) {
        DTHROW("Curve variable with name '%s', type size mismatch %u != %llu.\n", variableName, sm()->curve_type_size[cv], sizeof(typename detail::type_decode<T>::type_t));
        return nullptr;
    } else if (!(sm()->curve_elements[cv] == detail::type_decode<T>::len_t * N || (namespace_hash == Curve::variableHash("_environment") && N == 0))) {  // Special case, environment can avoid specifying N
        DTHROW("Curve variable with name '%s', variable array length mismatch %u != %u.\n", variableName, sm()->curve_elements[cv], detail::type_decode<T>::len_t);
        return nullptr;
    } else if (offset >= sm()->curve_type_size[cv] * sm()->curve_elements[cv] * sm()->curve_count[cv]) {  // Note : offset is basically index * sizeof(T)
        DTHROW("Curve variable with name '%s', offset exceeds buffer length  %u >= %u.\n", variableName, offset, sm()->curve_type_size[cv] * sm()->curve_elements[cv] * sm()->curve_count[cv]);
        return nullptr;
    }
#endif
    // return a generic pointer to variable address for given offset
    return sm()->curve_variables[cv] + offset;
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getVariable(const char(&variableName)[M], const VariableHash namespace_hash, const unsigned int agent_index, const unsigned int array_index) {
    using detail::sm;
    const unsigned int buffer_offset = agent_index * static_cast<unsigned int>(sizeof(T)) * N + array_index * sizeof(typename detail::type_decode<T>::type_t);
    T *value_ptr = reinterpret_cast<T*>(getVariablePtr<T, N>(variableName, namespace_hash, buffer_offset));

#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
    if (!value_ptr)
        return {};
#endif
    return *value_ptr;
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getVariable_ldg(const char(&variableName)[M], const VariableHash namespace_hash, const unsigned int agent_index, const unsigned int array_index) {
    const unsigned int buffer_offset = agent_index * static_cast<unsigned int>(sizeof(T)) * N + array_index * sizeof(typename detail::type_decode<T>::type_t);
    T *value_ptr = reinterpret_cast<T*>(getVariablePtr<T, N>(variableName, namespace_hash, buffer_offset));

#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
    if (!value_ptr)
        return {};
#endif
    return __ldg(value_ptr);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setVariable(const char(&variableName)[M], const VariableHash namespace_hash, const T variable, const unsigned int agent_index, const unsigned int array_index) {
    const unsigned int buffer_offset = agent_index * static_cast<unsigned int>(sizeof(T)) * N + array_index * sizeof(typename detail::type_decode<T>::type_t);
    T* value_ptr = reinterpret_cast<T*>(getVariablePtr<T, N>(variableName, namespace_hash, buffer_offset));

#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
    if (!value_ptr)
        return;
#endif
    *value_ptr = variable;
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getAgentVariable(const char (&variableName)[M], unsigned int index) {
    using detail::sm;
    return getVariable<T>(variableName, 0, index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getMessageVariable(const char (&variableName)[M], unsigned int index) {
    return getVariable<T>(variableName, Curve::variableHash("_message_in"), index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getAgentVariable_ldg(const char (&variableName)[M], unsigned int index) {
    return getVariable_ldg<T>(variableName, 0, index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getMessageVariable_ldg(const char (&variableName)[M], unsigned int index) {
    return getVariable_ldg<T>(variableName, Curve::variableHash("_message_in"), index);
}

template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getAgentArrayVariable(const char(&variableName)[M], unsigned int agent_index, unsigned int array_index) {
    return getVariable<T, N>(variableName, 0, agent_index, array_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getMessageArrayVariable(const char(&variableName)[M], unsigned int message_index, unsigned int array_index) {
    return getVariable<T, N>(variableName, Curve::variableHash("_message_in"), message_index, array_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getAgentArrayVariable_ldg(const char(&variableName)[M], unsigned int agent_index, unsigned int array_index) {
    return getVariable_ldg<T, N>(variableName, 0, agent_index, array_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getMessageArrayVariable_ldg(const char(&variableName)[M], unsigned int message_index, unsigned int array_index) {
    return getVariable_ldg<T, N>(variableName, Curve::variableHash("_message_in"), message_index, array_index);
}

template <typename T, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setAgentVariable(const char(&variableName)[M], T variable, unsigned int index) {
    setVariable<T>(variableName, 0, variable, index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setMessageVariable(const char(&variableName)[M], T variable, unsigned int index) {
    setVariable<T>(variableName, Curve::variableHash("_message_out"), variable, index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setNewAgentVariable(const char(&variableName)[M], T variable, unsigned int index) {
    setVariable<T>(variableName, Curve::variableHash("_agent_birth"), variable, index);
}

template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setAgentArrayVariable(const char(&variableName)[M], T variable, unsigned int agent_index, unsigned int array_index) {
    setVariable<T, N>(variableName, 0, variable, agent_index, array_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setMessageArrayVariable(const char(&variableName)[M], T variable, unsigned int message_index, unsigned int array_index) {
    setVariable<T, N>(variableName, Curve::variableHash("_message_out"), variable, message_index, array_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ void DeviceCurve::setNewAgentArrayVariable(const char(&variableName)[M], T variable, unsigned int agent_index, unsigned int array_index) {
    setVariable<T, N>(variableName, Curve::variableHash("_agent_birth"), variable, agent_index, array_index);
}

template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentProperty(const char(&propertyName)[M]) {
    using detail::sm;
    return  *reinterpret_cast<const T*>(sm()->env_buffer + reinterpret_cast<ptrdiff_t>(getVariablePtr<T, 1>(propertyName, Curve::variableHash("_environment"), 0)));
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentArrayProperty(const char(&propertyName)[M], unsigned int array_index) {
    using detail::sm;
    return *reinterpret_cast<const T*>(sm()->env_buffer + reinterpret_cast<ptrdiff_t>(getVariablePtr<T, N>(propertyName, Curve::variableHash("_environment"), array_index * sizeof(T))));
}
__device__ __forceinline__ unsigned int *DeviceCurve::getEnvironmentDirectedGraphPBM(VariableHash graphHash) {
    using detail::sm;
    return reinterpret_cast<unsigned int *>(getVariablePtr<unsigned int, 1>("_pbm", graphHash ^ Curve::variableHash("_environment_directed_graph_vertex"), 0));
}
__device__ __forceinline__ unsigned int* DeviceCurve::getEnvironmentDirectedGraphIPBM(VariableHash graphHash) {
    using detail::sm;
    return reinterpret_cast<unsigned int*>(getVariablePtr<unsigned int, 1>("_ipbm", graphHash ^ Curve::variableHash("_environment_directed_graph_vertex"), 0));
}
__device__ __forceinline__ unsigned int* DeviceCurve::getEnvironmentDirectedGraphIPBMEdges(VariableHash graphHash) {
    using detail::sm;
    return reinterpret_cast<unsigned int*>(getVariablePtr<unsigned int, 1>("_ipbm_edges", graphHash ^ Curve::variableHash("_environment_directed_graph_vertex"), 0));
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentDirectedGraphVertexProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int vertex_index) {
    using detail::sm;
    return getVariable<T>(propertyName, graphHash ^ Curve::variableHash("_environment_directed_graph_vertex"), vertex_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentDirectedGraphVertexArrayProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int vertex_index, unsigned int array_index) {
    using detail::sm;
    return getVariable<T, N>(propertyName, graphHash ^ Curve::variableHash("_environment_directed_graph_vertex"), vertex_index, array_index);
}
template <typename T, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentDirectedGraphEdgeProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int edge_index) {
    using detail::sm;
    return getVariable<T>(propertyName, graphHash ^ Curve::variableHash("_environment_directed_graph_edge"), edge_index);
}
template <typename T, unsigned int N, unsigned int M>
__device__ __forceinline__ T DeviceCurve::getEnvironmentDirectedGraphEdgeArrayProperty(VariableHash graphHash, const char(&propertyName)[M], unsigned int edge_index, unsigned int array_index) {
    using detail::sm;
    return getVariable<T, N>(propertyName, graphHash ^ Curve::variableHash("_environment_directed_graph_edge"), edge_index, array_index);
}

template<typename T, unsigned int I, unsigned int J, unsigned int K, unsigned int W, unsigned int M>
__device__ __forceinline__ char* DeviceCurve::getEnvironmentMacroProperty(const char(&name)[M]) {
    return getVariablePtr<T, I*J*K*W>(name, Curve::variableHash("_macro_environment"), 0);
}

__device__ __forceinline__ bool DeviceCurve::isAgent(const char* agent_name) {
    return util::dstrcmp(agent_name, sm()->agent_name) == 0;
}
__device__ __forceinline__ bool DeviceCurve::isState(const char* agent_state) {
    return util::dstrcmp(agent_state, sm()->state_name) == 0;
}

template <unsigned int M>
__device__ __forceinline__ unsigned int DeviceCurve::getVariableCount(const char(&variableName)[M], const VariableHash namespace_hash) {
    using detail::sm;
    const Variable cv = getVariableIndex(Curve::variableHash(variableName) + namespace_hash);
#if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS
    if (cv == UNKNOWN_VARIABLE) {
        DTHROW("Curve variable with name '%s' was not found.\n", variableName);
        return 0;
    }
#endif
    return sm()->curve_count[cv];
}
}  // namespace curve
}  // namespace detail
}  // namespace flamegpu

#endif  // INCLUDE_FLAMEGPU_RUNTIME_DETAIL_CURVE_DEVICECURVE_CUH_