1 // Copyright 2019-2021 Intel Corporation 2 // SPDX-License-Identifier: Apache-2.0 3 4 #pragma once 5 6 // openvkl 7 #include "openvkl/openvkl.h" 8 // rkcommon 9 #include "rkcommon/math/range.h" 10 #include "rkcommon/math/vec.h" 11 // half 12 #include "../external/half.hpp" 13 14 #include <vector> 15 16 using namespace rkcommon::math; 17 18 namespace openvkl { 19 namespace testing { 20 21 struct TemporalConfig 22 { 23 enum Type 24 { 25 Constant, 26 Structured, 27 Unstructured, 28 }; 29 30 Type type{Constant}; 31 std::vector<float> sampleTime; 32 33 // Threshold for temporal compression on temporally unstructured volumes. 34 // Lossy if > 0, but will remove duplicate samples at 0. 35 bool useTemporalCompression = false; 36 float temporalCompressionThreshold = 0; 37 38 TemporalConfig() = default; 39 TemporalConfigTemporalConfig40 TemporalConfig(Type type, size_t numSamples) 41 : type(type), sampleTime(equidistantTime(numSamples)) 42 { 43 assert(type == Constant || numSamples > 0); 44 } 45 TemporalConfigTemporalConfig46 explicit TemporalConfig(const std::vector<float> &sampleTime) 47 : type(Unstructured), sampleTime(sampleTime) 48 { 49 assert(!sampleTime.empty()); 50 } 51 isCompatibleTemporalConfig52 bool isCompatible(const TemporalConfig &other) const 53 { 54 return (type == other.type) && 55 (sampleTime.size() == other.sampleTime.size()) && 56 // If two volumes are compressed differently they incompatible! 57 !(useTemporalCompression || other.useTemporalCompression); 58 } 59 hasTimeTemporalConfig60 bool hasTime() const 61 { 62 return type != Constant; 63 } 64 getNumSamplesTemporalConfig65 size_t getNumSamples() const 66 { 67 return type == Constant ? 1 : sampleTime.size(); 68 } 69 70 private: equidistantTimeTemporalConfig71 static std::vector<float> equidistantTime(size_t numSamples) 72 { 73 std::vector<float> st(numSamples); 74 // Initialize to {} for numSamples 0, {0} for numSamples 1, 75 // and a regular grid between 0 and 1 for numSamples > 1. 76 const float dt = 77 1.f / static_cast<float>(std::max<size_t>(numSamples, 2) - 1); 78 for (size_t i = 0; i < numSamples; ++i) 79 st[i] = i * dt; 80 return st; 81 } 82 }; 83 84 85 /////////////////////////////////////////////////////////////////////////// 86 // Helper functions /////////////////////////////////////////////////////// 87 /////////////////////////////////////////////////////////////////////////// 88 89 template <typename T> getVKLDataType()90 inline VKLDataType getVKLDataType() 91 { 92 if (std::is_same<T, unsigned char>::value) { 93 return VKL_UCHAR; 94 } else if (std::is_same<T, short>::value) { 95 return VKL_SHORT; 96 } else if (std::is_same<T, unsigned short>::value) { 97 return VKL_USHORT; 98 } else if (std::is_same<T, half_float::half>::value) { 99 return VKL_HALF; 100 } else if (std::is_same<T, float>::value) { 101 return VKL_FLOAT; 102 } else if (std::is_same<T, double>::value) { 103 return VKL_DOUBLE; 104 } else { 105 return VKL_UNKNOWN; 106 } 107 } 108 sizeOfVKLDataType(VKLDataType dataType)109 inline size_t sizeOfVKLDataType(VKLDataType dataType) 110 { 111 switch (dataType) { 112 case VKL_UCHAR: 113 return sizeof(unsigned char); 114 case VKL_SHORT: 115 return sizeof(short); 116 case VKL_USHORT: 117 return sizeof(unsigned short); 118 case VKL_HALF: 119 return sizeof(half_float::half); 120 case VKL_FLOAT: 121 return sizeof(float); 122 case VKL_DOUBLE: 123 return sizeof(double); 124 case VKL_UNKNOWN: 125 break; 126 default: 127 break; 128 }; 129 130 throw std::runtime_error("cannot compute size of unknown VKLDataType"); 131 } 132 133 template <typename T> computeValueRange(const void * data,size_t numValues)134 inline range1f computeValueRange(const void *data, size_t numValues) 135 { 136 const T *valuesTyped = (const T *)data; 137 138 auto minmax = std::minmax_element(valuesTyped, valuesTyped + numValues); 139 140 return range1f(*minmax.first, *minmax.second); 141 } 142 computeValueRange(VKLDataType dataType,const void * data,size_t numValues)143 inline range1f computeValueRange(VKLDataType dataType, 144 const void *data, 145 size_t numValues) 146 { 147 if (dataType == VKL_UCHAR) 148 return computeValueRange<unsigned char>(data, numValues); 149 else if (dataType == VKL_SHORT) 150 return computeValueRange<short>(data, numValues); 151 else if (dataType == VKL_USHORT) 152 return computeValueRange<unsigned short>(data, numValues); 153 else if (dataType == VKL_HALF) 154 return computeValueRange<half_float::half>(data, numValues); 155 else if (dataType == VKL_FLOAT) 156 return computeValueRange<float>(data, numValues); 157 else if (dataType == VKL_DOUBLE) 158 return computeValueRange<double>(data, numValues); 159 else 160 throw std::runtime_error( 161 "computeValueRange() called with unsupported data type"); 162 } 163 164 /////////////////////////////////////////////////////////////////////////// 165 // TestingVolume ////////////////////////////////////////////////////////// 166 /////////////////////////////////////////////////////////////////////////// 167 168 struct TestingVolume 169 { 170 TestingVolume() = default; 171 virtual ~TestingVolume(); 172 173 void release(); 174 VKLVolume getVKLVolume(VKLDevice device); 175 176 // returns an application-side computed value range, for comparison with 177 // vklGetValueRange() results 178 virtual range1f getComputedValueRange() const = 0; 179 180 protected: 181 virtual void generateVKLVolume(VKLDevice device) = 0; 182 183 VKLVolume volume{nullptr}; 184 }; 185 186 // Inlined definitions //////////////////////////////////////////////////// 187 ~TestingVolume()188 inline TestingVolume::~TestingVolume() 189 { 190 release(); 191 } 192 release()193 inline void TestingVolume::release() 194 { 195 if (volume) { 196 vklRelease(volume); 197 volume = nullptr; 198 } 199 } 200 getVKLVolume(VKLDevice device)201 inline VKLVolume TestingVolume::getVKLVolume(VKLDevice device) 202 { 203 if (!volume) { 204 generateVKLVolume(device); 205 } 206 207 return volume; 208 } 209 210 } // namespace testing 211 } // namespace openvkl 212