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 &param = *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