NVIDIA Index example code nvidia_logo_transpbg.gif Up
distributed_sparse_volume_data.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 *****************************************************************************/
6
7#include <iostream>
8#include <limits>
9#include <sstream>
10#include <vector>
11
12#include <mi/dice.h>
13
14// Include code shared by all examples.
15#include "utility/example_shared.h"
16
17#include <nv/index/icamera.h>
18#include <nv/index/iconfig_settings.h>
19#include <nv/index/idistributed_data_access.h>
20#include <nv/index/iindex.h>
21#include <nv/index/ilight.h>
22#include <nv/index/imaterial.h>
23#include <nv/index/iscene.h>
24#include <nv/index/isession.h>
25#include <nv/index/isparse_volume_subset.h>
26#include <nv/index/isparse_volume_rendering_properties.h>
27
28#include <nv/index/app/forwarding_logger.h>
29#include <nv/index/app/idata_analysis_and_processing.h>
30#include <nv/index/app/index_connect.h>
31#include <nv/index/app/string_dict.h>
32
33//----------------------------------------------------------------------
35 public nv::index::app::Index_connect
36{
37public:
39 :
40 Index_connect()
41 {
42 // INFO_LOG << "DEBUG: Distributed_sparse_volume_data() ctor";
43 }
44
46 {
47 // Note: Index_connect::~Index_connect() will be called after here.
48 // INFO_LOG << "DEBUG: ~Distributed_sparse_volume_data() dtor";
49 }
50
51 // launch application
52 mi::Sint32 launch();
53
54protected:
55 virtual bool evaluate_options(nv::index::app::String_dict& sdict) CPP11_OVERRIDE;
56 // override
58 mi::neuraylib::INetwork_configuration* network_configuration,
59 nv::index::app::String_dict& options) CPP11_OVERRIDE
60 {
61 check_success(network_configuration != 0);
62
63 check_success(options.is_defined("unittest"));
64 const bool is_unittest = nv::index::app::get_bool(options.get("unittest"));
65 if (is_unittest)
66 {
67 info_cout("NETWORK: disabled networking mode.", options);
68 network_configuration->set_mode(mi::neuraylib::INetwork_configuration::MODE_OFF);
69 return true;
70 }
71
72 return initialize_networking_as_default_udp(network_configuration, options);
73 }
74
75private:
76 mi::Size calc_offset(const mi::math::Vector<mi::Sint32, 3>& p, const mi::math::Vector<mi::Uint32, 3>& s, mi::Uint32 b) const;
77 mi::Float32 analyze_sparse_volume_data(
78 mi::neuraylib::IDice_transaction* dice_transaction) const;
79 // Edit the data in the volume
80 // \param[in] dice_transaction transaction
81 void edit_sparse_volume_data(
82 mi::neuraylib::IDice_transaction* dice_transaction) const;
83 // Export the data in the volume
84 // \param[in] dice_transaction transaction
85 // \returns average of the data in the volume
86 mi::Float32 export_sparse_volume_data(
87 mi::neuraylib::IDice_transaction* dice_transaction) const;
88 void render_frame(const std::string& output_filename) const;
89
90 // Create a synthetic sparse volume to the scene.
91 mi::neuraylib::Tag create_synthetic_volume(
92 const nv::index::ISession* session,
93 const mi::math::Vector<mi::Uint32, 3>& volume_size,
94 mi::neuraylib::IDice_transaction* dice_transaction) const;
95 std::vector<mi::Uint32> evaluate_sparse_volume_data_locality(
96 const nv::index::IDistributed_data_locality* data_locality,
97 const mi::math::Bbox<mi::Sint32, 3>& query_bound,
98 const mi::neuraylib::Tag& scene_element_tag,
99 const std::string& scene_element_type) const;
100 // Get brick's clamped bboxes
101 //
102 // \param[in] svol_data_subset_desc
103 // \param[in] brick_idx
104 // \param[in] brick_position
105 // \param[in] query_bbox_s32
106 // \param[out] out_brick_box_subdata_clamped
107 // \param[out] out_brick_box_clamped
108 void get_brick_clamped_bbox(
109 const nv::index::ISparse_volume_subset_data_descriptor* svol_data_subset_desc,
110 const mi::Uint32 brick_idx,
111 const mi::math::Vector<mi::Sint32, 3>& brick_position,
112 const mi::math::Bbox<mi::Sint32, 3>& query_bbox_s32,
113 mi::math::Bbox<mi::Sint32, 3>& out_brick_box_subdata_clamped,
114 mi::math::Bbox<mi::Sint32, 3>& out_brick_box_clamped) const;
115
116 // This session tag
117 mi::neuraylib::Tag m_session_tag;
118 // NVIDIA IndeX cluster configuration
119 mi::base::Handle<nv::index::ICluster_configuration> m_cluster_configuration;
120 // Application layer image file canvas (a render target)
121 mi::base::Handle<nv::index::app::canvas_infrastructure::IIndex_image_file_canvas> m_image_file_canvas;
122 // Create_icons options
123 std::string m_outfname;
124 bool m_is_unittest;
125 std::string m_voxel_format;
126 mi::neuraylib::Tag m_sparse_volume_tag;
127};
128
129//----------------------------------------------------------------------
131{
132 m_cluster_configuration = get_index_interface()->get_api_component<nv::index::ICluster_configuration>();
133 check_success(m_cluster_configuration.is_valid_interface());
134
135 // create image canvas in application_layer
136 m_image_file_canvas = create_image_file_canvas(get_application_layer_interface());
137 check_success(m_image_file_canvas.is_valid_interface());
138
139 // Verifying that local host has joined
140 // This may fail when there is a license problem.
141 check_success(is_local_host_joined(m_cluster_configuration.get()));
142
143 {
144 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
145 check_success(dice_transaction.is_valid_interface());
146 {
147 // Setup session information
148 m_session_tag = m_index_session->create_session(dice_transaction.get());
149 check_success(m_session_tag.is_valid());
150
151 mi::base::Handle<const nv::index::ISession> session(dice_transaction->access<nv::index::ISession>(m_session_tag));
152 check_success(session.is_valid_interface());
153
154 // Setup the session's configuration
155 {
156 mi::base::Handle<nv::index::IConfig_settings> edit_config_settings(
157 dice_transaction->edit<nv::index::IConfig_settings>(session->get_config()));
158 check_success(edit_config_settings.is_valid_interface());
159
160 // All data should be uploaded immediately, even when it is not initially visible
161 edit_config_settings->set_force_data_upload(true);
162
163 // Set smaller subcube size in unit test mode
164 if (m_is_unittest)
165 {
166 const mi::math::Vector<mi::Uint32, 3> subcube_size(30);
167 mi::math::Vector<mi::Float32, 3> minimal_volume_scaling;
168 edit_config_settings->get_minimal_volume_scaling(minimal_volume_scaling);
169 edit_config_settings->set_subcube_configuration(
170 subcube_size,
171 edit_config_settings->get_subcube_border_size(),
172 edit_config_settings->get_continuous_volume_translation_supported(),
173 edit_config_settings->get_volume_rotation_supported(),
174 minimal_volume_scaling);
175 }
176 }
177
178 //----------------------------------------------------------------------
179 // Scene setup: add volume data, scene parameters
180 //----------------------------------------------------------------------
181
182 // the Size of the volume and the global scene transformation used below.
183 mi::math::Vector<mi::Uint32, 3> volume_size(1000, 1000, 1000);
184 mi::math::Matrix<mi::Float32, 4, 4> transform(
185 0.02f, 0.0f, 0.0f, 0.0f,
186 0.0f, 0.02f, 0.0f, 0.0f,
187 0.0f, 0.0f, -0.02f, 0.0f, // adjust for coordinate system
188 0.0f, 0.0f, 0.0f, 1.0f
189 );
190
191 // Use a smaller volume but a larger global scene scaling in unit test mode, to speed things up.
192 if (m_is_unittest)
193 {
194 volume_size = mi::math::Vector<mi::Uint32, 3>(100, 100, 100);
195 transform = mi::math::Matrix<mi::Float32, 4, 4>(
196 0.2f, 0.0f, 0.0f, 0.0f,
197 0.0f, 0.2f, 0.0f, 0.0f,
198 0.0f, 0.0f, -0.2f, 0.0f, // adjust for coordinate system
199 0.0f, 0.0f, 0.0f, 1.0f
200 );
201 }
202
203 m_sparse_volume_tag = create_synthetic_volume(session.get(), volume_size, dice_transaction.get());
204 check_success(m_sparse_volume_tag.is_valid());
205 INFO_LOG << "Created a synthetic sparse volume dataset: size = "
206 << "[" << volume_size.x << " " << volume_size.y << " " << volume_size.z << "], " << "tag = " << m_sparse_volume_tag.id;
207
208 // Set up the scene and the camera
209 mi::base::Handle<nv::index::IScene> scene_edit(dice_transaction->edit<nv::index::IScene>(session->get_scene()));
210 check_success(scene_edit.is_valid_interface());
211
212 // Set region of interest to fit the volume in this example
213 const mi::math::Bbox<mi::Float32, 3> global_roi(
214 0.0f, 0.0f, 0.0f,
215 static_cast<mi::Float32>(volume_size.x),
216 static_cast<mi::Float32>(volume_size.y),
217 static_cast<mi::Float32>(volume_size.z));
218 scene_edit->set_clipped_bounding_box(global_roi);
219 scene_edit->set_transform_matrix(transform);
220
221 // Create a camera and set the camera parameters to see the whole volume data.
222 mi::base::Handle< nv::index::IPerspective_camera > cam(
223 scene_edit->create_camera<nv::index::IPerspective_camera>());
224 check_success(cam.is_valid_interface());
225
226 const mi::math::Vector< mi::Float32, 3 > from(-6.0f, 35.0f, 7.0f);
227 const mi::math::Vector< mi::Float32, 3 > to ( 9.0f, 14.f, -11.0f);
228 const mi::math::Vector< mi::Float32, 3 > up ( 0.0f, -0.10f, 1.0f);
229 mi::math::Vector<mi::Float32, 3> viewdir = to - from;
230 viewdir.normalize();
231
232 cam->set(from, viewdir, up);
233 cam->set_aperture(0.033f);
234 cam->set_aspect(1.0f);
235 cam->set_focal(0.03f);
236 cam->set_clip_min(2.0f);
237 cam->set_clip_max(400.0f);
238
239 const mi::neuraylib::Tag camera_tag = dice_transaction->store(cam.get());
240 check_success(camera_tag.is_valid());
241
242 scene_edit->set_camera(camera_tag);
243
244 const mi::math::Vector<mi::Uint32, 2> canvas_resolution(1024, 1024);
245 m_image_file_canvas->set_resolution(canvas_resolution);
246 }
247 dice_transaction->commit();
248 }
249
250 // The following block invokes the example code/functionality:
251 {
252 INFO_LOG << "Render the initial sparse 3D volume ...";
253 mi::Sint32 frame_idx = 0;
254 {
255 const std::string outfname = get_output_file_name(m_outfname, frame_idx);
256 ++frame_idx;
257 render_frame(outfname);
258 }
259
260 // Applying operations to the volume now ...
261 INFO_LOG << "Analyzing the sparse volume data ...";
262 {
263 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
264 check_success(dice_transaction.is_valid_interface());
265 {
266 mi::Float32 value = analyze_sparse_volume_data(dice_transaction.get());
267 INFO_LOG << "voxel_format: " << m_voxel_format << ", unittest: " << m_is_unittest << ", generated value: " << value;
268
269 if (m_voxel_format == "uint8")
270 {
271 if (m_is_unittest)
272 {
273 check_success(fabs(value - 225.47f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
274 }
275 else
276 {
277 check_success(fabs(value - 237.931f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
278 }
279 }
280 else if (m_voxel_format == "rgba8")
281 {
282 if (m_is_unittest)
283 {
284 check_success(fabs(value - 126.25) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
285 }
286 else
287 {
288 check_success(fabs(value - 50.625) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
289 }
290 }
291 else if (m_voxel_format == "sint16")
292 {
293 if (m_is_unittest)
294 {
295 check_success(fabs(value - 29044.3f) < (65535.0f/1000.0f)); // (65535.0f/1000.0f) 0.1%
296 }
297 else
298 {
299 check_success(fabs(value - 30577.9f) < (65535.0f/1000.0f)); // (65535.0f/1000.0f) 0.1%
300 }
301 }
302 else if (m_voxel_format == "float32")
303 {
304 if (m_is_unittest)
305 {
306 check_success(fabs(value - 0.886378f) < (1.0f/1000.0f)); // (1.0f/1000.0f) 0.1%
307 }
308 else
309 {
310 check_success(fabs(value - 0.935178) < (1.0f/1000.0f)); // (1.0f/1000.0f) 0.1%
311 }
312 }
313 else
314 {
315 ERROR_LOG << "Unknown voxel format: " << m_voxel_format;
316 }
317 }
318 dice_transaction->commit();
319 }
320
321 INFO_LOG << "Editing the sparse volume data ...";
322 {
323 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
324 check_success(dice_transaction.is_valid_interface());
325 {
326 edit_sparse_volume_data(dice_transaction.get());
327 }
328 dice_transaction->commit();
329 }
330
331 INFO_LOG << "Render the edited sparse 3D volume ...";
332 {
333 const std::string outfname = get_output_file_name(m_outfname, frame_idx);
334 ++frame_idx;
335 render_frame(outfname);
336 }
337
338 INFO_LOG << "Analyzing the sparse volume data after editing ...";
339 {
340 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
341 check_success(dice_transaction.is_valid_interface());
342 {
343 mi::Float32 value = analyze_sparse_volume_data(dice_transaction.get());
344 // Set all values to 42.0
345 check_success(value == 42.0f);
346 }
347 dice_transaction->commit();
348 }
349
350 INFO_LOG << "Exporting subset of the sparse volume data ...";
351 {
352 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
353 check_success(dice_transaction.is_valid_interface());
354 {
355 mi::Float32 value = export_sparse_volume_data(dice_transaction.get());
356
357 INFO_LOG << "voxel_format: " << m_voxel_format << ", unittest: " << m_is_unittest << ", export value: " << value;
358
359 if (m_voxel_format == "uint8")
360 {
361 if (m_is_unittest)
362 {
363 check_success(fabs(value - 165.244f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
364 }
365 else
366 {
367 check_success(fabs(value - 171.237f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
368 }
369 }
370 else if (m_voxel_format == "rgba8")
371 {
372 if (m_is_unittest)
373 {
374 check_success(fabs(value - 118.402f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
375 }
376 else
377 {
378 check_success(fabs(value - 2.40677f) < (255.0f/1000.0f)); // (255.0f/1000.0f) 0.1%
379 }
380 }
381 else if (m_voxel_format == "sint16")
382 {
383 if (m_is_unittest)
384 {
385 check_success(fabs(value - 19539.6f) < (65535.0f/1000.0f)); // (65535.0f/1000.0f) 0.1%
386 }
387 else
388 {
389 check_success(fabs(value - 20579.5f) < (65535.0f/1000.0f)); // (65535.0f/1000.0f) 0.1%
390 }
391 }
392 else if (m_voxel_format == "float32")
393 {
394 if (m_is_unittest)
395 {
396 check_success(fabs(value - 13.6316f) < (1.0f/1000.0f)); // (1.0f/1000.0f) 0.1%
397 }
398 else
399 {
400 check_success(fabs(value - 11.4886f) < (1.0f/1000.0f)); // (1.0f/1000.0f) 0.1%
401 }
402 }
403 else
404 {
405 ERROR_LOG << "Unknown voxel format: " << m_voxel_format;
406 }
407 }
408 dice_transaction->commit();
409 }
410 }
411
412 return 0;
413}
414
415//----------------------------------------------------------------------
416bool Distributed_sparse_volume_data::evaluate_options(nv::index::app::String_dict& sdict)
417{
418 const std::string com_name = sdict.get("command:", "<unknown_command>");
419 m_is_unittest = nv::index::app::get_bool(sdict.get("unittest", "false"));
420
421 if (m_is_unittest)
422 {
423 if (nv::index::app::get_bool(sdict.get("is_call_from_test", "false")))
424 {
425 sdict.insert("is_dump_comparison_image_when_failed", "0");
426 }
427 sdict.insert("dice::verbose", "2");
428 sdict.insert("outfname", "");
429 }
430
431 m_outfname = sdict.get("outfname");
432 m_voxel_format = sdict.get("voxel_format");
433
434 info_cout(std::string("Running ") + com_name, sdict);
435
436 // print help and exit if -h
437 if (sdict.is_defined("h"))
438 {
439 std::cout
440 << "info: Usage: " << com_name <<" [option]\n"
441 << "Option: [-h]\n"
442 << " print this message\n"
443
444 << " [-dice::network::multicast_address address]\n"
445 << " set multicast address. (default: ["
446 << sdict.get("dice::network::multicast_address") + "])\n"
447
448 << " [-dice::network::cluster_interface]\n"
449 << " set cluster interface. (default: ["
450 << sdict.get("dice::network::cluster_interface") + "])\n"
451
452 << " [-voxel_format VOXEL_FORMAT]\n"
453 << " the voxel format. 'uint8', 'rgba8', 'sint16', 'float32' \n"
454 << " (default: [" << m_voxel_format << "])\n"
455
456 // Note: subcube_size is [30 30 30], the generator shows
457 // multiple same generate bounds. Because that generate
458 // bounds has a subcube. These subcubes are shared in a
459 // brick. Thus, they show multiple times.
460 << " [-unittest bool]\n"
461 << " when true, unit test mode (create smaller volume). Also small subcube_size."
462 << sdict.get("unittest") + "])\n"
463
464 << std::endl;
465 exit(1);
466 }
467
468 return true;
469}
470
471//----------------------------------------------------------------------
472mi::Size Distributed_sparse_volume_data::calc_offset(const mi::math::Vector<mi::Sint32, 3>& p, const mi::math::Vector<mi::Uint32, 3>& s, mi::Uint32 b) const
473{
474 const mi::Size o = static_cast<mi::Size>(p.x + b)
475 + static_cast<mi::Size>(p.y + b) * s.x
476 + static_cast<mi::Size>(p.z + b) * s.x * s.y;
477 return o;
478}
479
480//----------------------------------------------------------------------
481mi::neuraylib::Tag Distributed_sparse_volume_data::create_synthetic_volume(
482 const nv::index::ISession* session,
483 const mi::math::Vector<mi::Uint32, 3>& volume_size,
484 mi::neuraylib::IDice_transaction* dice_transaction) const
485{
486 check_success(dice_transaction != 0);
487 check_success(volume_size.x > 0 && volume_size.y > 0 && volume_size.z > 0);
488
489 const mi::math::Bbox<mi::Uint32, 3> volume_bbox(mi::math::Vector<mi::Uint32, 3>(0), volume_size);
490
491 // A synthetic volume generator relies on the data import functionality of NVIDIA IndeX. Instead of reading data from disk,
492 // the data is created on the fly.
493 // sparse volume creation parameter
494 nv::index::app::String_dict sparse_volume_opt;
495 sparse_volume_opt.insert("args::type", "sparse_volume");
496 sparse_volume_opt.insert("args::importer", "nv::index::plugin::base_importer.Sparse_volume_generator_synthetic");
497 {
498 std::stringstream sstr;
499 sstr << "0 0 0 " << volume_size.x << " " << volume_size.y << " " << volume_size.z;
500 sparse_volume_opt.insert("args::bbox", sstr.str());
501 }
502 sparse_volume_opt.insert("args::voxel_format", m_voxel_format);
503 sparse_volume_opt.insert("args::synthetic_type", "perlin_noise");
504 sparse_volume_opt.insert("args::parameter::cube_unit", "1024");
505 sparse_volume_opt.insert("args::parameter::time", "0");
506 sparse_volume_opt.insert("args::parameter::terms", "2");
507 sparse_volume_opt.insert("args::parameter::turbulence_weight", "1 1 1 1");
508 sparse_volume_opt.insert("args::parameter::abs_noise", "false");
509 sparse_volume_opt.insert("args::parameter::ridged", "true");
510 nv::index::IDistributed_data_import_callback* generator =
511 get_importer_from_application_layer(
512 get_application_layer_interface(),
513 "nv::index::plugin::base_importer.Sparse_volume_generator_synthetic",
514 sparse_volume_opt);
515
516 // Create the volume scene element using the above importer and parameters and the scene (that is part of the session).
517 mi::base::Handle<nv::index::IScene> scene(dice_transaction->edit<nv::index::IScene>(session->get_scene()));
518 check_success(scene.is_valid_interface());
519
520 mi::math::Matrix<mi::Float32, 4, 4> transform_mat(1.0f); // Identity matrix
521 const bool is_rendering_enabled = true;
522 const mi::math::Bbox<mi::Float32, 3> ijk_bbox(volume_bbox);
523 mi::base::Handle<nv::index::ISparse_volume_scene_element> svol_scene_element(
524 scene->create_sparse_volume(ijk_bbox, transform_mat, generator, dice_transaction));
525 check_success(svol_scene_element.is_valid_interface());
526 svol_scene_element->set_enabled(is_rendering_enabled);
527
528 if(svol_scene_element.is_valid_interface())
529 {
530 const mi::neuraylib::Tag svol_scene_element_tag = dice_transaction->store_for_reference_counting(svol_scene_element.get());
531 check_success(svol_scene_element_tag.is_valid());
532
533 // Create static group node for large data and append the volume
534 mi::base::Handle<nv::index::IStatic_scene_group> static_group(scene->create_scene_group<nv::index::IStatic_scene_group>());
535 check_success(static_group.is_valid_interface());
536 {
537 // Add a sparse_volume_render_properties to the scene.
538 mi::base::Handle<nv::index::ISparse_volume_rendering_properties> sparse_render_prop(
539 scene->create_attribute<nv::index::ISparse_volume_rendering_properties>());
540 sparse_render_prop->set_filter_mode(nv::index::SPARSE_VOLUME_FILTER_NEAREST);
541 sparse_render_prop->set_sampling_distance( 1.0);
542 sparse_render_prop->set_reference_sampling_distance( 1.0);
543 sparse_render_prop->set_voxel_offsets( mi::math::Vector<mi::Float32, 3>(0.0f, 0.0f, 0.0f));
544 sparse_render_prop->set_preintegrated_volume_rendering(false);
545 sparse_render_prop->set_lod_rendering_enabled( false);
546 sparse_render_prop->set_lod_pixel_threshold( 2.0);
547 sparse_render_prop->set_debug_visualization_option( 0);
548 const mi::neuraylib::Tag sparse_render_prop_tag
549 = dice_transaction->store_for_reference_counting(sparse_render_prop.get());
550 check_success(sparse_render_prop_tag.is_valid());
551 static_group->append(sparse_render_prop_tag, dice_transaction);
552 INFO_LOG << "Created a sparse_render_prop_tag: tag = " << sparse_render_prop_tag;
553
554 // Add a colormap to the scene.
555 const mi::Sint32 colormap_entry_id = 1; // same as demo application's colormap file 1
556 const mi::neuraylib::Tag colormap_tag =
557 create_colormap(colormap_entry_id, scene.get(), dice_transaction);
558 check_success(colormap_tag.is_valid());
559 static_group->append(colormap_tag, dice_transaction);
560 }
561
562 static_group->append(svol_scene_element_tag, dice_transaction);
563 const mi::neuraylib::Tag static_group_tag = dice_transaction->store_for_reference_counting(static_group.get());
564 check_success(static_group_tag.is_valid());
565
566 // Add the new volume to the hierarchical scene description
567 scene->append(static_group_tag, dice_transaction);
568
569 return svol_scene_element_tag;
570 }
571
572 return mi::neuraylib::NULL_TAG;
573}
574
575//----------------------------------------------------------------------
576std::vector<mi::Uint32> Distributed_sparse_volume_data::evaluate_sparse_volume_data_locality(
577 const nv::index::IDistributed_data_locality* svol_data_locality,
578 const mi::math::Bbox<mi::Sint32, 3>& query_bound,
579 const mi::neuraylib::Tag& scene_element_tag,
580 const std::string& scene_element_type) const
581{
582 // Determine all host in the cluster that store part of the distributed data (here: sparse volume).
583 std::vector<mi::Uint32> cluster_host_ids;
584 std::ostringstream hosts;
585 std::ostringstream locality_report;
586 for(mi::Uint32 i = 0; i < svol_data_locality->get_nb_cluster_nodes(); ++i)
587 {
588 // A host id=0 indicates that an issue occurred, e.g., no data has been loaded or no distribution scheme has been set up.
589 check_success(svol_data_locality->get_cluster_node(i) != 0);
590
591 const mi::Uint32 host_id = svol_data_locality->get_cluster_node(i);
592 cluster_host_ids.push_back(host_id);
593
594 // The remaining part is just for reporting/logging.
595 hosts << host_id << " ";
596
597 const mi::Size nb_subregions = svol_data_locality->get_nb_bounding_box(host_id);
598 locality_report << "Host " << host_id << " stores part of the distributed data in the following " << nb_subregions << " regions:\n";
599 for(mi::Uint32 j = 0; j < nb_subregions; ++j)
600 {
601 const mi::math::Bbox<mi::Sint32, 3> bbox = svol_data_locality->get_bounding_box(host_id, j);
602 locality_report << " " << (j+1) << ")\t" << bbox;
603 if(j < nb_subregions-1)
604 {
605 locality_report << "\n";
606 }
607 }
608 }
609 INFO_LOG << "\n"
610 << "Data locality for a " << scene_element_type
611 << " with tag id " << scene_element_tag.id
612 << " and query region " << query_bound << "\n"
613 << "The distributed data is located on the following hosts (ids): [ " << hosts.str() << "]." << "\n"
614 << locality_report.str()
615 << "\n";
616
617 return cluster_host_ids;
618}
619
620//----------------------------------------------------------------------
621void Distributed_sparse_volume_data::get_brick_clamped_bbox(
622 const nv::index::ISparse_volume_subset_data_descriptor* svol_data_subset_desc,
623 const mi::Uint32 brick_idx,
624 const mi::math::Vector<mi::Sint32, 3>& brick_position,
625 const mi::math::Bbox<mi::Sint32, 3>& query_bbox_s32,
626 mi::math::Bbox<mi::Sint32, 3>& out_brick_box_subdata_clamped,
627 mi::math::Bbox<mi::Sint32, 3>& out_brick_box_clamped) const
628{
629 check_success(svol_data_subset_desc != 0);
630
631 const mi::math::Vector<mi::Sint32, 3> query_bbox_ext_s32 = query_bbox_s32.extent();
632
633 const mi::math::Vector<mi::Uint32,3> svol_data_brick_dim = svol_data_subset_desc->get_subset_data_brick_dimensions();
634 const mi::Uint32 svol_data_brick_border = svol_data_subset_desc->get_subset_data_brick_shared_border_size();
635
636 const mi::math::Vector<mi::Sint32, 3> brick_pos_vol = mi::math::Vector<mi::Sint32, 3>(brick_position) + mi::math::Vector<mi::Sint32, 3>(svol_data_brick_border);
637
638 const mi::math::Bbox<mi::Sint32, 3> brick_box_global = mi::math::Bbox<mi::Sint32, 3>(brick_pos_vol,
639 brick_pos_vol + mi::math::Vector<mi::Sint32, 3>(svol_data_brick_dim)
640 - 2 * mi::math::Vector<mi::Sint32, 3>(svol_data_brick_border));
641 const mi::math::Bbox<mi::Sint32, 3> brick_box_subdata = mi::math::Bbox<mi::Sint32, 3>(brick_box_global.min - query_bbox_s32.min,
642 brick_box_global.max - query_bbox_s32.min);
643 // max clamp with [[0,0,0], ext.size()]
644 const mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped = mi::math::Bbox<mi::Sint32, 3>(mi::math::clamp(brick_box_subdata.min, mi::math::Vector<mi::Sint32, 3>(0u), query_bbox_ext_s32),
645 mi::math::clamp(brick_box_subdata.max, mi::math::Vector<mi::Sint32, 3>(0u), query_bbox_ext_s32));
646 const mi::math::Bbox<mi::Sint32, 3> brick_box_global_clamped = mi::math::Bbox<mi::Sint32, 3>(brick_box_subdata_clamped.min + query_bbox_s32.min,
647 brick_box_subdata_clamped.max + query_bbox_s32.min);
648 const mi::math::Bbox<mi::Sint32, 3> brick_box_clamped = mi::math::Bbox<mi::Sint32, 3>(brick_box_global_clamped.min - brick_pos_vol,
649 brick_box_global_clamped.max - brick_pos_vol);
650
651 out_brick_box_subdata_clamped = brick_box_subdata_clamped;
652 out_brick_box_clamped = brick_box_clamped;
653}
654
655//----------------------------------------------------------------------
656mi::Float32 Distributed_sparse_volume_data::analyze_sparse_volume_data(
657 mi::neuraylib::IDice_transaction* dice_transaction) const
658{
659 mi::base::Handle<const nv::index::ISession> the_session(dice_transaction->access<nv::index::ISession>(m_session_tag));
660 check_success(the_session.is_valid_interface());
661
662 mi::base::Handle<const nv::index::ISparse_volume_scene_element> sparse_volume(dice_transaction->access<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag));
663 check_success(sparse_volume.is_valid_interface());
664
665 const mi::math::Vector<mi::Sint32, 2> trace(50, 50);
666 const mi::math::Bbox<mi::Sint32, 3> query_bbox_s32(
667 trace.x, trace.y, 0,
668 trace.x + 1, trace.y + 1, static_cast<mi::Uint32>(sparse_volume->get_bounding_box().max.z));
669 const mi::math::Bbox<mi::Float32, 3> query_bbox_f32(query_bbox_s32);
670
671 // Access the distribution scheme
672 const mi::neuraylib::Tag dist_layout_tag = the_session->get_distribution_layout();
673 check_success(dist_layout_tag.is_valid());
674
675 mi::base::Handle<const nv::index::IData_distribution> distribution_layout(dice_transaction->access<nv::index::IData_distribution>(dist_layout_tag));
676 check_success(distribution_layout.is_valid_interface());
677
678 // Find out on which hosts the data is located and print this information
679 mi::base::Handle<nv::index::IDistributed_data_locality> svol_data_locality(
680 distribution_layout->get_data_locality<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag, query_bbox_f32, dice_transaction));
681 check_success(svol_data_locality.is_valid_interface());
682
683 // Determine all host in the cluster that store part of the distributed data.
684 std::vector<mi::Uint32> cluster_host_ids = evaluate_sparse_volume_data_locality(svol_data_locality.get(), query_bbox_s32, m_sparse_volume_tag, sparse_volume->get_class_name());
685
686 // Create the access factory
687 const mi::neuraylib::Tag data_access_tag = the_session->get_data_access_factory();
688 check_success(data_access_tag.is_valid());
689
690 mi::base::Handle<const nv::index::IDistributed_data_access_factory> svol_access_factory(
691 dice_transaction->access<nv::index::IDistributed_data_access_factory>(data_access_tag));
692 check_success(svol_access_factory.is_valid_interface());
693
694 mi::base::Handle<nv::index::IDistributed_data_access> svol_data_access(
695 svol_access_factory->create_distributed_data_access<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag));
696 check_success(svol_data_access.is_valid_interface());
697
698 // Now retrieve the data
699 check_success(svol_data_access->access(query_bbox_f32, dice_transaction) >= 0);
700
701 const mi::math::Bbox<mi::Float32, 3> effective_bbox_f32 = svol_data_access->get_bounding_box();
702 check_success(effective_bbox_f32 == query_bbox_f32);
703
704 mi::Float32 avg = -1.0f;
705
706 mi::base::Handle<const nv::index::IDistributed_data_subset> data_subset(svol_data_access->get_distributed_data_subset());
707 mi::base::Handle<const nv::index::ISparse_volume_subset> svol_data_subset(data_subset->get_interface<const nv::index::ISparse_volume_subset>());
708 check_success(svol_data_subset.is_valid_interface());
709
710 mi::base::Handle<const nv::index::ISparse_volume_attribute_set_descriptor> svol_data_attrib_desc(svol_data_subset->get_attribute_set_descriptor());
711 mi::base::Handle<const nv::index::ISparse_volume_subset_data_descriptor> svol_data_subset_desc(svol_data_subset->get_subset_data_descriptor());
712
713 const mi::Uint32 svol_attrib_index_0 = 0u;
714 nv::index::ISparse_volume_attribute_set_descriptor::Attribute_parameters svol_attrib_param_0;
715 check_success(svol_data_attrib_desc->get_attribute_parameters(svol_attrib_index_0, svol_attrib_param_0));
716
717 const nv::index::Sparse_volume_voxel_format svol_voxel_fmt = svol_attrib_param_0.format;
718 const mi::Sint32 svol_voxel_fmt_size = nv::index::get_sizeof(svol_voxel_fmt);
719
720 const mi::math::Vector<mi::Sint32, 3> query_bbox_ext_s32 = query_bbox_s32.extent(); // size (= query_bbox_s32.max() - query_bbox_s32.min())
721
722 const mi::Size svol_query_buffer_size =
723 static_cast<mi::Size>(query_bbox_ext_s32.x) *
724 static_cast<mi::Size>(query_bbox_ext_s32.y) *
725 static_cast<mi::Size>(query_bbox_ext_s32.z) *
726 svol_voxel_fmt_size;
727
728 mi::Uint8* svol_query_buffer = new mi::Uint8[svol_query_buffer_size];
729
730 const mi::math::Vector<mi::Uint32,3> svol_data_brick_dim = svol_data_subset_desc->get_subset_data_brick_dimensions();
731 const mi::Uint32 svol_data_brick_border = svol_data_subset_desc->get_subset_data_brick_shared_border_size();
732 const mi::Uint32 svol_subset_nb_bricks = svol_data_subset_desc->get_subset_number_of_data_bricks();
733 for (mi::Uint32 b = 0u; b < svol_subset_nb_bricks; ++b)
734 {
735 const nv::index::ISparse_volume_subset_data_descriptor::Data_brick_info brick_info = svol_data_subset_desc->get_subset_data_brick_info(b);
736 const nv::index::ISparse_volume_subset::Data_brick_buffer_info brick_data_nfo = svol_data_subset->access_brick_data_buffer(b, svol_attrib_index_0);
737
738 const mi::Uint8* svol_brick_data_raw = reinterpret_cast<mi::Uint8*>(brick_data_nfo.data);
739 if (svol_brick_data_raw == NULL)
740 {
741 ERROR_LOG << "error accessing brick data pointer "
742 << "(brick_idx: " << b
743 << ", brick_level: " << brick_info.brick_lod_level << ").";
744 delete [] svol_query_buffer;
745 check_success(false);
746 }
747
748 mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped;
749 mi::math::Bbox<mi::Sint32, 3> brick_box_clamped;
750 get_brick_clamped_bbox(svol_data_subset_desc.get(), b, brick_info.brick_position, query_bbox_s32, brick_box_subdata_clamped, brick_box_clamped);
751
752 for (mi::Uint32 z = 0u; z < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().z); ++z)
753 {
754 for (mi::Uint32 y = 0u; y < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().y); ++y)
755 {
756 const mi::math::Vector<mi::Sint32, 3> line_pos_dst =
757 mi::math::Vector<mi::Sint32, 3>(brick_box_subdata_clamped.min.x,
758 brick_box_subdata_clamped.min.y + y,
759 brick_box_subdata_clamped.min.z + z);
760
761 const mi::Size dst_off = calc_offset(line_pos_dst, mi::math::Vector<mi::Uint32, 3>(query_bbox_ext_s32), 0u);
762
763 const mi::math::Vector<mi::Sint32, 3> line_pos_src =
764 mi::math::Vector<mi::Sint32, 3>(brick_box_clamped.min.x,
765 brick_box_clamped.min.y + y,
766 brick_box_clamped.min.z + z);
767 const mi::Size src_off = calc_offset(line_pos_src, svol_data_brick_dim, svol_data_brick_border);
768
769 const mi::Size line_size = static_cast<mi::Size>(brick_box_subdata_clamped.extent().x) * svol_voxel_fmt_size;
770
771 memcpy(svol_query_buffer + dst_off * svol_voxel_fmt_size,
772 svol_brick_data_raw + src_off * svol_voxel_fmt_size,
773 line_size);
774 }
775 }
776 }
777
778 if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_UINT8)
779 {
780 // Average the contents of the trace
781 const mi::Uint8* voxel_data = svol_query_buffer;
782
783 mi::Sint64 sum = 0;
784 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
785 for (mi::Sint64 k = 0; k < count; ++k)
786 {
787 sum += static_cast<mi::Sint64>(voxel_data[k]);
788 }
789
790 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(count);
791 INFO_LOG << "Tracing 8-bit volume: [" << trace.x << ", " << trace.y
792 << ", " << query_bbox_s32.min.z << ":" << query_bbox_s32.max.z - 1 << "]: "
793 << "count=" << count << ", sum=" << sum << ", avg=" << avg;
794 }
795 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_UINT8_4)
796 {
797 // Average the contents of the trace
798 const mi::math::Vector_struct<mi::Uint8, 4>* voxel_data =
799 reinterpret_cast< mi::math::Vector_struct<mi::Uint8, 4>*>(svol_query_buffer);
800
801 mi::Sint64 sum = 0;
802 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
803 for (mi::Sint64 k = 0; k < count; ++k)
804 {
805 mi::math::Vector<mi::Uint8, 4> voxel_v(voxel_data[k]);
806 mi::math::Vector<mi::Float32, 4> voxel_f32_4(voxel_v);
807 sum += static_cast<mi::Sint64>(((voxel_f32_4.x + voxel_f32_4.y + voxel_f32_4.z) / 3.0f));
808 }
809
810 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(count);
811 INFO_LOG << "Tracing rgba8 volume: [" << trace.x << ", " << trace.y
812 << ", " << query_bbox_s32.min.z << ":" << query_bbox_s32.max.z - 1 << "]: "
813 << "count=" << count << ", sum=" << sum << ", avg=" << avg;
814 }
815 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_SINT16)
816 {
817 // Average the contents of the trace
818 const mi::Sint16* voxel_data = reinterpret_cast<mi::Sint16*>(svol_query_buffer);
819
820 mi::Sint64 sum = 0;
821 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
822 for (mi::Sint64 k = 0; k < count; ++k)
823 {
824 sum += voxel_data[k];
825 }
826
827 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(count);
828 INFO_LOG << "Tracing sint16 volume: [" << trace.x << ", " << trace.y
829 << ", " << query_bbox_s32.min.z << ":" << query_bbox_s32.max.z - 1 << "]: "
830 << "count=" << count << ", sum=" << sum << ", avg=" << avg;
831 }
832 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_FLOAT32)
833 {
834 // Average the contents of the trace
835 const mi::Float32* voxel_data = reinterpret_cast<mi::Float32*>(svol_query_buffer);
836
837 mi::Float32 sum = 0;
838 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
839 for (mi::Sint64 k = 0; k < count; ++k)
840 {
841 sum += voxel_data[k];
842 }
843
844 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(count);
845 INFO_LOG << "Tracing uint16 volume: [" << trace.x << ", " << trace.y
846 << ", " << query_bbox_s32.min.z << ":" << query_bbox_s32.max.z - 1 << "]: "
847 << "count=" << count << ", sum=" << sum << ", avg=" << avg;
848 }
849 else
850 {
851 ERROR_LOG << "Analyze volume data failed: data access on not-known volume type.";
852 }
853
854 return avg;
855}
856
857//----------------------------------------------------------------------
858void Distributed_sparse_volume_data::edit_sparse_volume_data(
859 mi::neuraylib::IDice_transaction* dice_transaction) const
860{
861 mi::base::Handle<const nv::index::ISession> the_session(
862 dice_transaction->access<nv::index::ISession>(m_session_tag));
863 check_success(the_session.is_valid_interface());
864
865 mi::base::Handle<const nv::index::ISparse_volume_scene_element> sparse_volume(
866 dice_transaction->access<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag));
867 check_success(sparse_volume.is_valid_interface());
868
869 const mi::math::Vector<mi::Sint32, 2> trace(50, 50);
870 const mi::math::Bbox<mi::Sint32, 3> query_bbox_s32(
871 trace.x, trace.y, 0,
872 trace.x + 1, trace.y + 1, static_cast<mi::Sint32>(sparse_volume->get_bounding_box().max.z));
873 INFO_LOG << "The sparse volume will be edited inside the following 3D bounding box: " << query_bbox_s32 << ".";
874 const mi::math::Bbox<mi::Float32, 3> query_bbox_f32(query_bbox_s32);
875
876 // Access the distribution scheme
877 const mi::neuraylib::Tag dist_layout_tag = the_session->get_distribution_layout();
878 check_success(dist_layout_tag.is_valid());
879
880 mi::base::Handle<const nv::index::IData_distribution> distribution_layout(dice_transaction->access<nv::index::IData_distribution>(dist_layout_tag));
881 check_success(distribution_layout.is_valid_interface());
882
883 // Distribution layout
884 mi::base::Handle<nv::index::IDistributed_data_locality> svol_data_locality(
885 distribution_layout->get_data_locality<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag, query_bbox_f32, dice_transaction));
886 check_success(svol_data_locality.is_valid_interface());
887
888 // Determine all host in the cluster that store part of the distributed data (here: sparse volume).
889 std::vector<mi::Uint32> cluster_host_ids = evaluate_sparse_volume_data_locality(
890 svol_data_locality.get(), query_bbox_s32, m_sparse_volume_tag, sparse_volume->get_class_name());
891
892 // Set up distributed algorithm and start the job
893 const mi::Sint32 voxel_value = 42; // just some "arbitrary" number
894
895 // Access an application layer component that provides some sample distributed jobs:
896 mi::base::Handle<nv::index::app::data_analysis_and_processing::IData_analysis_and_processing> processing(
897 get_application_layer_interface()->get_api_component<nv::index::app::data_analysis_and_processing::IData_analysis_and_processing>());
898 check_success(processing.is_valid_interface());
899 // Create a job that distributed to all nodes/GPUs and add edits the volume data.
900 // For more details on how to implement the mandelbrot, please review the provided
901 // source that was shipped with the application layer component 'nv::index::app::data_analysis_and_processing::IData_analysis_and_processing'.
902 mi::base::Handle<nv::index::IDistributed_data_job> algo(processing->get_sample_tool_set()->create_sparse_volume_voxel_value_setting(
903 m_sparse_volume_tag,
904 voxel_value,
905 query_bbox_s32));
906 distribution_layout->create_scheduler()->execute(algo.get(), dice_transaction);
907}
908
909//----------------------------------------------------------------------
910mi::Float32 Distributed_sparse_volume_data::export_sparse_volume_data(
911 mi::neuraylib::IDice_transaction* dice_transaction) const
912{
913 mi::base::Handle<const nv::index::ISession> the_session(dice_transaction->access<nv::index::ISession>(m_session_tag));
914 check_success(the_session.is_valid_interface());
915
916 mi::base::Handle<const nv::index::ISparse_volume_scene_element> sparse_volume(dice_transaction->access<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag));
917 check_success(sparse_volume.is_valid_interface());
918
919 // Select what subset of the volume should be exported
920 mi::math::Bbox<mi::Sint32, 3> query_bbox_s32(sparse_volume->get_bounding_box());
921 query_bbox_s32.min += (query_bbox_s32.max - query_bbox_s32.min) / 4;
922 query_bbox_s32.max -= (query_bbox_s32.max - query_bbox_s32.min) / 4;
923 const mi::math::Bbox<mi::Float32, 3> query_bbox_f32(query_bbox_s32);
924
925 // Access the distribution scheme
926 const mi::neuraylib::Tag dist_layout_tag = the_session->get_distribution_layout();
927 check_success(dist_layout_tag.is_valid());
928
929 mi::base::Handle<const nv::index::IData_distribution> distribution_layout(dice_transaction->access<nv::index::IData_distribution>(dist_layout_tag));
930 check_success(distribution_layout.is_valid_interface());
931
932 // Find out on which hosts the data is located and print this information
933 mi::base::Handle<nv::index::IDistributed_data_locality> svol_data_locality(
934 distribution_layout->get_data_locality<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag, query_bbox_f32, dice_transaction));
935 check_success(svol_data_locality.is_valid_interface());
936
937 // Determine all host in the cluster that store part of the distributed data.
938 std::vector<mi::Uint32> cluster_host_ids = evaluate_sparse_volume_data_locality(svol_data_locality.get(), query_bbox_s32, m_sparse_volume_tag, sparse_volume->get_class_name());
939
940 // Create the access factory
941 const mi::neuraylib::Tag data_access_tag = the_session->get_data_access_factory();
942 check_success(data_access_tag.is_valid());
943
944 mi::base::Handle<const nv::index::IDistributed_data_access_factory> svol_access_factory(
945 dice_transaction->access<nv::index::IDistributed_data_access_factory>(data_access_tag));
946 check_success(svol_access_factory.is_valid_interface());
947
948 mi::base::Handle<nv::index::IDistributed_data_access> svol_data_access(
949 svol_access_factory->create_distributed_data_access<nv::index::ISparse_volume_scene_element>(m_sparse_volume_tag));
950 check_success(svol_data_access.is_valid_interface());
951
952 // Now retrieve the data
953 check_success(svol_data_access->access(query_bbox_f32, dice_transaction) >= 0);
954
955 const mi::math::Bbox<mi::Float32, 3> effective_bbox_f32 = svol_data_access->get_bounding_box();
956 check_success(effective_bbox_f32 == query_bbox_f32);
957
958 mi::Float32 avg = -1.0f;
959
960 mi::base::Handle<const nv::index::IDistributed_data_subset> data_subset(svol_data_access->get_distributed_data_subset());
961 mi::base::Handle<const nv::index::ISparse_volume_subset> svol_data_subset(data_subset->get_interface<const nv::index::ISparse_volume_subset>());
962 check_success(svol_data_subset.is_valid_interface());
963
964 mi::base::Handle<const nv::index::ISparse_volume_attribute_set_descriptor> svol_data_attrib_desc(svol_data_subset->get_attribute_set_descriptor());
965 mi::base::Handle<const nv::index::ISparse_volume_subset_data_descriptor> svol_data_subset_desc(svol_data_subset->get_subset_data_descriptor());
966
967 const mi::Uint32 svol_attrib_index_0 = 0u;
968 nv::index::ISparse_volume_attribute_set_descriptor::Attribute_parameters svol_attrib_param_0;
969 check_success(svol_data_attrib_desc->get_attribute_parameters(svol_attrib_index_0, svol_attrib_param_0));
970
971 const nv::index::Sparse_volume_voxel_format svol_voxel_fmt = svol_attrib_param_0.format;
972 const mi::Sint32 svol_voxel_fmt_size = nv::index::get_sizeof(svol_voxel_fmt);
973
974 // const mi::math::Vector<mi::Sint32, 3> query_bbox_ext_s32 = query_bbox_s32.extent(); // size (= query_bbox_s32.max() - query_bbox_s32.min())
975 const mi::math::Vector<mi::Uint32,3> svol_data_brick_dim = svol_data_subset_desc->get_subset_data_brick_dimensions();
976 const mi::Uint32 svol_data_brick_border = svol_data_subset_desc->get_subset_data_brick_shared_border_size();
977 const mi::Uint32 svol_subset_nb_bricks = svol_data_subset_desc->get_subset_number_of_data_bricks();
978
979 mi::Sint64 sum = 0;
980 mi::Sint64 nb_voxels = 0;
981
982 if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_UINT8)
983 {
984 for (mi::Uint32 b = 0u; b < svol_subset_nb_bricks; ++b)
985 {
986 const nv::index::ISparse_volume_subset_data_descriptor::Data_brick_info brick_info = svol_data_subset_desc->get_subset_data_brick_info(b);
987 const nv::index::ISparse_volume_subset::Data_brick_buffer_info brick_data_nfo = svol_data_subset->access_brick_data_buffer(b, svol_attrib_index_0);
988 const mi::Uint8* svol_brick_data_raw = reinterpret_cast<mi::Uint8*>(brick_data_nfo.data);
989 check_success (svol_brick_data_raw != 0);
990
991 mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped;
992 mi::math::Bbox<mi::Sint32, 3> brick_box_clamped;
993 get_brick_clamped_bbox(svol_data_subset_desc.get(), b, brick_info.brick_position, query_bbox_s32, brick_box_subdata_clamped, brick_box_clamped);
994 for (mi::Uint32 z = 0u; z < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().z); ++z)
995 {
996 for (mi::Uint32 y = 0u; y < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().y); ++y)
997 {
998 const mi::math::Vector<mi::Sint32, 3> line_pos_src =
999 mi::math::Vector<mi::Sint32, 3>(brick_box_clamped.min.x,
1000 brick_box_clamped.min.y + y,
1001 brick_box_clamped.min.z + z);
1002 const mi::Size src_off = calc_offset(line_pos_src, svol_data_brick_dim, svol_data_brick_border);
1003
1004 // Average the contents with trace by trace
1005 const mi::Uint8* voxel_data = svol_brick_data_raw + src_off * svol_voxel_fmt_size;
1006 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
1007 for (mi::Sint64 k = 0; k < count; ++k)
1008 {
1009 sum += static_cast<mi::Sint64>(voxel_data[k]);
1010 }
1011 nb_voxels += count;
1012 }
1013 }
1014 }
1015 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(nb_voxels);
1016 INFO_LOG << "Average voxel value in exported data: " << avg << " of " << nb_voxels;
1017 }
1018 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_UINT8_4)
1019 {
1020 for (mi::Uint32 b = 0u; b < svol_subset_nb_bricks; ++b)
1021 {
1022 const nv::index::ISparse_volume_subset_data_descriptor::Data_brick_info brick_info = svol_data_subset_desc->get_subset_data_brick_info(b);
1023 const nv::index::ISparse_volume_subset::Data_brick_buffer_info brick_data_nfo = svol_data_subset->access_brick_data_buffer(b, svol_attrib_index_0);
1024 const mi::Uint8* svol_brick_data_raw = reinterpret_cast<mi::Uint8*>(brick_data_nfo.data);
1025 check_success (svol_brick_data_raw != 0);
1026
1027 mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped;
1028 mi::math::Bbox<mi::Sint32, 3> brick_box_clamped;
1029 get_brick_clamped_bbox(svol_data_subset_desc.get(), b, brick_info.brick_position, query_bbox_s32, brick_box_subdata_clamped, brick_box_clamped);
1030 for (mi::Uint32 z = 0u; z < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().z); ++z)
1031 {
1032 for (mi::Uint32 y = 0u; y < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().y); ++y)
1033 {
1034 const mi::math::Vector<mi::Sint32, 3> line_pos_src =
1035 mi::math::Vector<mi::Sint32, 3>(brick_box_clamped.min.x,
1036 brick_box_clamped.min.y + y,
1037 brick_box_clamped.min.z + z);
1038 const mi::Size src_off = calc_offset(line_pos_src, svol_data_brick_dim, svol_data_brick_border);
1039
1040 // Average the contents with trace by trace
1041 const mi::math::Vector_struct<mi::Uint8, 4>* voxel_data =
1042 reinterpret_cast<const mi::math::Vector_struct<mi::Uint8, 4>* >(svol_brick_data_raw + src_off * svol_voxel_fmt_size);
1043 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
1044 for (mi::Sint64 k = 0; k < count; ++k)
1045 {
1046 sum += (static_cast<mi::Sint64>(voxel_data[k].x) +
1047 static_cast<mi::Sint64>(voxel_data[k].y) +
1048 static_cast<mi::Sint64>(voxel_data[k].z)) / 3;
1049 }
1050 nb_voxels += count;
1051 }
1052 }
1053 }
1054 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(nb_voxels);
1055 INFO_LOG << "Average voxel value in exported data: " << avg << " of " << nb_voxels;
1056 }
1057 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_SINT16)
1058 {
1059 for (mi::Uint32 b = 0u; b < svol_subset_nb_bricks; ++b)
1060 {
1061 const nv::index::ISparse_volume_subset_data_descriptor::Data_brick_info brick_info = svol_data_subset_desc->get_subset_data_brick_info(b);
1062 const nv::index::ISparse_volume_subset::Data_brick_buffer_info brick_data_nfo = svol_data_subset->access_brick_data_buffer(b, svol_attrib_index_0);
1063 const mi::Uint8* svol_brick_data_raw = reinterpret_cast<mi::Uint8*>(brick_data_nfo.data);
1064 check_success (svol_brick_data_raw != 0);
1065
1066 mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped;
1067 mi::math::Bbox<mi::Sint32, 3> brick_box_clamped;
1068 get_brick_clamped_bbox(svol_data_subset_desc.get(), b, brick_info.brick_position, query_bbox_s32, brick_box_subdata_clamped, brick_box_clamped);
1069 for (mi::Uint32 z = 0u; z < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().z); ++z)
1070 {
1071 for (mi::Uint32 y = 0u; y < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().y); ++y)
1072 {
1073 const mi::math::Vector<mi::Sint32, 3> line_pos_src =
1074 mi::math::Vector<mi::Sint32, 3>(brick_box_clamped.min.x,
1075 brick_box_clamped.min.y + y,
1076 brick_box_clamped.min.z + z);
1077 const mi::Size src_off = calc_offset(line_pos_src, svol_data_brick_dim, svol_data_brick_border);
1078
1079 // Average the contents with trace by trace
1080 const mi::Sint16* voxel_data = reinterpret_cast<const mi::Sint16*>(svol_brick_data_raw + src_off * svol_voxel_fmt_size);
1081 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
1082 for (mi::Sint64 k = 0; k < count; ++k)
1083 {
1084 sum += voxel_data[k];
1085 }
1086 nb_voxels += count;
1087 }
1088 }
1089 }
1090 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(nb_voxels);
1091 INFO_LOG << "Average voxel value in exported data: " << avg << " of " << nb_voxels;
1092 }
1093 else if(svol_voxel_fmt == nv::index::SPARSE_VOLUME_VOXEL_FORMAT_FLOAT32)
1094 {
1095 for (mi::Uint32 b = 0u; b < svol_subset_nb_bricks; ++b)
1096 {
1097 const nv::index::ISparse_volume_subset_data_descriptor::Data_brick_info brick_info = svol_data_subset_desc->get_subset_data_brick_info(b);
1098 const nv::index::ISparse_volume_subset::Data_brick_buffer_info brick_data_nfo = svol_data_subset->access_brick_data_buffer(b, svol_attrib_index_0);
1099 const mi::Uint8* svol_brick_data_raw = reinterpret_cast<mi::Uint8*>(brick_data_nfo.data);
1100 check_success (svol_brick_data_raw != 0);
1101
1102 mi::math::Bbox<mi::Sint32, 3> brick_box_subdata_clamped;
1103 mi::math::Bbox<mi::Sint32, 3> brick_box_clamped;
1104 get_brick_clamped_bbox(svol_data_subset_desc.get(), b, brick_info.brick_position, query_bbox_s32, brick_box_subdata_clamped, brick_box_clamped);
1105 for (mi::Uint32 z = 0u; z < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().z); ++z)
1106 {
1107 for (mi::Uint32 y = 0u; y < static_cast<mi::Uint32>(brick_box_subdata_clamped.extent().y); ++y)
1108 {
1109 const mi::math::Vector<mi::Sint32, 3> line_pos_src =
1110 mi::math::Vector<mi::Sint32, 3>(brick_box_clamped.min.x,
1111 brick_box_clamped.min.y + y,
1112 brick_box_clamped.min.z + z);
1113 const mi::Size src_off = calc_offset(line_pos_src, svol_data_brick_dim, svol_data_brick_border);
1114
1115 // Average the contents with trace by trace
1116 const mi::Float32* voxel_data =
1117 reinterpret_cast<const mi::Float32*>(svol_brick_data_raw + src_off * svol_voxel_fmt_size);
1118 mi::Sint64 count = static_cast<mi::Sint64>(effective_bbox_f32.max.z - effective_bbox_f32.min.z);
1119 for (mi::Sint64 k = 0; k < count; ++k)
1120 {
1121 sum += static_cast<mi::Sint64>(voxel_data[k]);
1122 }
1123 nb_voxels += count;
1124 }
1125 }
1126 }
1127 avg = static_cast<mi::Float32>(sum) / static_cast<mi::Float32>(nb_voxels);
1128 INFO_LOG << "Average voxel value in exported data: " << avg << " of " << nb_voxels;
1129 }
1130 else
1131 {
1132 ERROR_LOG << "unknown voxel_format: " << svol_voxel_fmt;
1133 }
1134 return avg;
1135}
1136
1137//----------------------------------------------------------------------
1138void Distributed_sparse_volume_data::render_frame(
1139 const std::string& output_filename) const
1140{
1141 // Rendering to a file by means of the file canvas
1142 m_image_file_canvas->set_rgba_file_name(output_filename.c_str()); // No output if empty string
1143
1144 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
1145 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
1146 check_success(dice_transaction.is_valid_interface());
1147
1148 m_index_session->update(m_session_tag, dice_transaction.get());
1149
1150 mi::base::Handle<nv::index::IFrame_results> frame_results(
1151 m_index_rendering->render(
1152 m_session_tag,
1153 m_image_file_canvas.get(),
1154 dice_transaction.get()));
1155 check_success(frame_results.is_valid_interface());
1156
1157 dice_transaction->commit();
1158}
1159
1160//----------------------------------------------------------------------
1161// The API example illustrates the use of the general distributed computing concepts
1162// data locality, access and edit applied to a sysnthetic sparse volume dataset.
1163int main(int argc, const char* argv[])
1164{
1165 nv::index::app::String_dict sdict;
1166 sdict.insert("dice::verbose", "3"); // log level
1167 sdict.insert("unittest", "0"); // default mode
1168 sdict.insert("outfname", "frame_distributed_sparse_volume_data"); // output file base name
1169 sdict.insert("verify_image_fname", ""); // for unit test
1170 sdict.insert("dice::network::multicast_address", "224.1.3.2"); // default multicast address
1171 sdict.insert("dice::network::cluster_interface", ""); // default cluster interface address
1172 sdict.insert("voxel_format", "uint8"); // default voxel_format
1173 sdict.insert("is_dump_comparison_image_when_failed", "1"); // default: dump images when failed.
1174 sdict.insert("is_call_from_test", "0"); // default: not call from make check.
1175
1176 // DiCE settings
1177 sdict.insert("dice::network::mode", "OFF");
1178
1179 // IndeX settings
1180 sdict.insert("index::config::set_monitor_performance_values", "true");
1181 sdict.insert("index::service", "rendering_and_compositing");
1182 sdict.insert("index::cuda_debug_checks", "false");
1183
1184 // Application_layer settings
1185 sdict.insert("index::app::components::application_layer::component_name_list",
1186 "canvas_infrastructure image io data_analysis_and_processing");
1187 sdict.insert("index::app::plugins::base_importer::enabled", "true");
1188
1189 // Initialize the NVIDIA IndeX library
1190 Distributed_sparse_volume_data distributed_data_example;
1191 distributed_data_example.initialize(argc, argv, sdict);
1192 check_success(distributed_data_example.is_initialized());
1193
1194 // launch the application. creating the scene and rendering.
1195 const mi::Sint32 exit_code = distributed_data_example.launch();
1196 INFO_LOG << "Shutting down ...";
1197
1198 return exit_code;
1199}
virtual bool initialize_networking(mi::neuraylib::INetwork_configuration *network_configuration, nv::index::app::String_dict &options) CPP11_OVERRIDE
virtual bool evaluate_options(nv::index::app::String_dict &sdict) CPP11_OVERRIDE
int main(int argc, const char *argv[])
#define check_success(expr)