1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3
4 // ospray
5 #include "volume/Volume.h"
6 #include "common/Data.h"
7 #include "common/Util.h"
8 #include "transferFunction/TransferFunction.h"
9 #include "volume/Volume_ispc.h"
10
11 #include "openvkl/openvkl.h"
12 #include "openvkl/vdb.h"
13
14 #include <unordered_map>
15
16 namespace ospray {
17
18 // Volume defintions ////////////////////////////////////////////////////////
19
Volume(const std::string & type)20 Volume::Volume(const std::string &type) : vklType(type)
21 {
22 // check VKL has default config for VDB
23 if (type == "vdb"
24 && (vklVdbLevelNumVoxels(0) != 262144 || vklVdbLevelNumVoxels(1) != 32768
25 || vklVdbLevelNumVoxels(2) != 4096 || vklVdbLevelNumVoxels(3) != 512
26 || vklVdbLevelNumVoxels(4) != 0))
27 throw std::runtime_error(toString()
28 + " Open VKL has non-default configuration for VDB volumes.");
29
30 ispcEquivalent = ispc::Volume_createInstance_vklVolume();
31 managedObjectType = OSP_VOLUME;
32 }
33
~Volume()34 Volume::~Volume()
35 {
36 if (vklSampler)
37 vklRelease(vklSampler);
38
39 if (vklVolume)
40 vklRelease(vklVolume);
41
42 if (embreeGeometry)
43 rtcReleaseGeometry(embreeGeometry);
44 }
45
toString() const46 std::string Volume::toString() const
47 {
48 return "ospray::Volume";
49 }
50
commit()51 void Volume::commit()
52 {
53 if (!vklDevice) {
54 throw std::runtime_error("invalid Open VKL device");
55 }
56 if (!embreeDevice) {
57 throw std::runtime_error("invalid Embree device");
58 }
59
60 if (vklSampler)
61 vklRelease(vklSampler);
62
63 if (vklVolume)
64 vklRelease(vklVolume);
65
66 vklVolume = vklNewVolume(vklDevice, vklType.c_str());
67
68 if (!vklVolume)
69 throw std::runtime_error("unsupported volume type '" + vklType + "'");
70
71 if (!embreeGeometry) {
72 embreeGeometry = rtcNewGeometry(embreeDevice, RTC_GEOMETRY_TYPE_USER);
73 }
74
75 handleParams();
76
77 vklCommit(vklVolume);
78 (vkl_box3f &)bounds = vklGetBoundingBox(vklVolume);
79
80 vklSampler = vklNewSampler(vklVolume);
81 vklCommit(vklSampler);
82
83 ispc::Volume_set(ispcEquivalent, embreeGeometry);
84 ispc::Volume_set_vklVolume(
85 ispcEquivalent, vklVolume, vklSampler, (ispc::box3f *)&bounds);
86 }
87
checkDataStride(const Data * data) const88 void Volume::checkDataStride(const Data *data) const
89 {
90 if (data->stride().y != int64_t(data->numItems.x) * data->stride().x
91 || data->stride().z != int64_t(data->numItems.y) * data->stride().y) {
92 throw std::runtime_error(
93 toString() + " Open VKL only supports 1D strides between elements");
94 }
95 }
96
handleParams()97 void Volume::handleParams()
98 {
99 // pass all supported parameters through to VKL volume object
100 std::for_each(params_begin(), params_end(), [&](std::shared_ptr<Param> &p) {
101 auto ¶m = *p;
102 param.query = true;
103
104 if (param.data.is<bool>()) {
105 vklSetBool(vklVolume, param.name.c_str(), param.data.get<bool>());
106 } else if (param.data.is<float>()) {
107 vklSetFloat(vklVolume, param.name.c_str(), param.data.get<float>());
108 } else if (param.data.is<int>()) {
109 vklSetInt(vklVolume, param.name.c_str(), param.data.get<int>());
110 } else if (param.data.is<vec3f>()) {
111 vklSetVec3f(vklVolume,
112 param.name.c_str(),
113 param.data.get<vec3f>().x,
114 param.data.get<vec3f>().y,
115 param.data.get<vec3f>().z);
116 } else if (param.data.is<void *>()) {
117 vklSetVoidPtr(vklVolume, param.name.c_str(), param.data.get<void *>());
118 } else if (param.data.is<const char *>()) {
119 vklSetString(
120 vklVolume, param.name.c_str(), param.data.get<const char *>());
121 } else if (param.data.is<vec3i>()) {
122 vklSetVec3i(vklVolume,
123 param.name.c_str(),
124 param.data.get<vec3i>().x,
125 param.data.get<vec3i>().y,
126 param.data.get<vec3i>().z);
127 } else if (param.data.is<ManagedObject *>()) {
128 Data *data = (Data *)param.data.get<ManagedObject *>();
129
130 if (data->type == OSP_DATA) {
131 auto &dataD = data->as<Data *>();
132 std::vector<VKLData> vklBlockData;
133 vklBlockData.reserve(data->size());
134 for (auto &&data : dataD) {
135 checkDataStride(data);
136 VKLData vklData = vklNewData(vklDevice,
137 data->size(),
138 (VKLDataType)data->type,
139 data->data(),
140 VKL_DATA_SHARED_BUFFER,
141 data->stride().x);
142 vklBlockData.push_back(vklData);
143 }
144 VKLData vklData = vklNewData(
145 vklDevice, vklBlockData.size(), VKL_DATA, vklBlockData.data());
146 vklSetData(vklVolume, param.name.c_str(), vklData);
147 vklRelease(vklData);
148 for (VKLData vd : vklBlockData)
149 vklRelease(vd);
150
151 if (vklType == "vdb" && param.name == "node.data") {
152 // deduce format
153 std::vector<uint32_t> format;
154 format.reserve(data->size());
155 for (auto &&data : dataD) {
156 bool isTile = data->size() == 1;
157 if (!isTile) {
158 if (data->numItems.x != data->numItems.y
159 || data->numItems.x != data->numItems.z)
160 throw std::runtime_error(
161 toString() + " VDB leaf node data must have size n^3.");
162 }
163 format.push_back(isTile ? VKL_FORMAT_TILE : VKL_FORMAT_DENSE_ZYX);
164 }
165 VKLData vklData =
166 vklNewData(vklDevice, format.size(), VKL_UINT, format.data());
167 vklSetData(vklVolume, "node.format", vklData);
168 vklRelease(vklData);
169 }
170
171 } else {
172 checkDataStride(data);
173 VKLData vklData = vklNewData(vklDevice,
174 data->size(),
175 (VKLDataType)data->type,
176 data->data(),
177 VKL_DATA_SHARED_BUFFER,
178 data->stride().x);
179
180 std::string name(param.name);
181 if (name == "data") { // structured volumes
182 vec3ul &dim = data->numItems;
183 vklSetVec3i(vklVolume, "dimensions", dim.x, dim.y, dim.z);
184 vklSetInt(vklVolume, "voxelType", (VKLDataType)data->type);
185 }
186 vklSetData(vklVolume, name.c_str(), vklData);
187 vklRelease(vklData);
188 }
189 } else {
190 param.query = false;
191 }
192 });
193 }
194
setDevice(RTCDevice embreed,VKLDevice vkld)195 void Volume::setDevice(RTCDevice embreed, VKLDevice vkld)
196 {
197 embreeDevice = embreed;
198 vklDevice = vkld;
199 }
200
201 OSPTYPEFOR_DEFINITION(Volume *);
202
203 } // namespace ospray
204