.. _program_listing_file_include_flamegpu_simulation_detail_CUDAMacroEnvironment.h: Program Listing for File CUDAMacroEnvironment.h =============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/simulation/detail/CUDAMacroEnvironment.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_ #define INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_ #include #include #include #include #include #include #include #include #include "flamegpu/simulation/detail/CUDAErrorChecking.cuh" #include "flamegpu/runtime/detail/curve/HostCurve.cuh" #include "flamegpu/runtime/environment/HostMacroProperty.cuh" #include "flamegpu/detail/cuda.cuh" // forward declare classes from other modules namespace flamegpu { struct SubEnvironmentData; struct AgentFunctionData; struct EnvironmentData; class CUDASimulation; namespace detail { namespace curve { class CurveRTCHost; } // namespace curve class CUDAMacroEnvironment { public: struct MacroEnvProp { MacroEnvProp(const std::type_index& _type, const size_t _type_size, const std::array &_elements) : type(_type) , type_size(_type_size) , elements(_elements) , d_ptr(nullptr) , is_sub(false) { } ~MacroEnvProp() { if (d_ptr && !is_sub) { gpuErrchk(flamegpu::detail::cuda::cudaFree(d_ptr)); } } MacroEnvProp(const MacroEnvProp& other) = delete; MacroEnvProp(MacroEnvProp&& other) : type(other.type) , type_size(other.type_size) , elements(other.elements) , d_ptr(other.d_ptr) , is_sub(other.is_sub) { other.d_ptr = nullptr; } std::type_index type; size_t type_size; std::array elements; void *d_ptr; // Denotes whether d_ptr is owned by this struct or not bool is_sub; // ptrdiff_t rtc_offset; // This is set by buildRTCOffsets(); }; CUDAMacroEnvironment(const EnvironmentData& description, const CUDASimulation& _cudaSimulation); CUDAMacroEnvironment(CUDAMacroEnvironment&) = delete; CUDAMacroEnvironment(CUDAMacroEnvironment&&) = delete; void init(cudaStream_t stream); void init(const SubEnvironmentData& mapping, std::shared_ptr master_macro_env, cudaStream_t stream); void free(); void mapRTCVariables(detail::curve::CurveRTCHost& curve_header) const; void unmapRTCVariables(detail::curve::CurveRTCHost& curve_header) const; void registerCurveVariables(detail::curve::HostCurve &curve) const; #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS void resetFlagsAsync(const std::vector& streams); bool getDeviceReadFlag(const std::string& property_name); bool getDeviceWriteFlag(const std::string& property_name); unsigned int getDeviceRWFlags(const std::string& property_name); #endif template HostMacroProperty getProperty(const std::string& name); #ifdef SWIG template HostMacroProperty_swig getProperty_swig(const std::string& name); #endif const std::map& getPropertiesMap() const; std::shared_ptr getHostPropertyMetadata(const std::string property_name); private: const CUDASimulation& cudaSimulation; std::map properties; std::map> host_cache; cudaStream_t stream = nullptr; }; template HostMacroProperty CUDAMacroEnvironment::getProperty(const std::string& name) { // Validation auto prop = properties.find(name); if (prop == properties.end()) { THROW flamegpu::exception::InvalidEnvProperty("Environment macro property with name '%s' not found, " "in HostEnvironment::getMacroProperty()\n", name.c_str()); } else if (prop->second.type != std::type_index(typeid(T))) { THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' type mismatch '%s' != '%s', " "in HostEnvironment::getMacroProperty()\n", name.c_str(), std::type_index(typeid(T)).name(), prop->second.type.name()); } else if (prop->second.elements != std::array{I, J, K, W}) { THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' dimensions mismatch (%u, %u, %u, %u) != (%u, %u, %u, %u), " "in HostEnvironment::getMacroProperty()\n", name.c_str(), I, J, K, W, prop->second.elements[0], prop->second.elements[1], prop->second.elements[2], prop->second.elements[3]); } #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS const unsigned int flags = getDeviceWriteFlag(name); if (flags & (1 << 1)) { THROW flamegpu::exception::InvalidOperation("Environment macro property '%s' was written to by an agent function in the same layer, " "accessing it with a host function in the same layer could cause a race condition, in CUDAMacroEnvironment::getProperty().", name.c_str()); } const bool read_flag = flags & (1 << 0); #else const bool read_flag = false; #endif // See if there is a live metadata in cache auto cache = host_cache.find(name); if (cache != host_cache.end()) { if (cache->second.lock()) { return HostMacroProperty(cache->second.lock()); } host_cache.erase(cache); } auto ret = std::make_shared(prop->second.d_ptr, prop->second.elements, sizeof(T), read_flag, name, stream); host_cache.emplace(name, ret); return HostMacroProperty(ret); } #ifdef SWIG template HostMacroProperty_swig CUDAMacroEnvironment::getProperty_swig(const std::string& name) { // Validation auto prop = properties.find(name); if (prop == properties.end()) { THROW flamegpu::exception::InvalidEnvProperty("Environment macro property with name '%s' not found, " "in HostEnvironment::getMacroProperty()\n", name.c_str()); } else if (prop->second.type != std::type_index(typeid(T))) { THROW flamegpu::exception::InvalidEnvProperty("Environment macro property '%s' type mismatch '%s' != '%s', " "in HostEnvironment::getMacroProperty()\n", name.c_str(), std::type_index(typeid(T)).name(), prop->second.type.name()); } #if !defined(FLAMEGPU_SEATBELTS) || FLAMEGPU_SEATBELTS const unsigned int flags = getDeviceWriteFlag(name); if (flags & (1 << 1)) { THROW flamegpu::exception::InvalidOperation("Environment macro property '%s' was written to by an agent function in the same layer, " "accessing it with a host function in the same layer could cause a race condition, in CUDAMacroEnvironment::getProperty().", name.c_str()); } const bool read_flag = flags & (1 << 0); #else const bool read_flag = false; #endif // See if there is a live metadata in cache auto cache = host_cache.find(name); if (cache != host_cache.end()) { if (cache->second.lock()) { return HostMacroProperty_swig(cache->second.lock()); } host_cache.erase(cache); } auto ret = std::make_shared(prop->second.d_ptr, prop->second.elements, sizeof(T), read_flag, name, stream); host_cache.emplace(name, ret); return HostMacroProperty_swig(ret); } #endif } // namespace detail } // namespace flamegpu #endif // INCLUDE_FLAMEGPU_SIMULATION_DETAIL_CUDAMACROENVIRONMENT_H_