Wayverb
waveguide.h
1 #pragma once
2 
3 #include "waveguide/mesh.h"
4 
5 #include "core/cl/include.h"
6 #include "core/conversions.h"
7 #include "core/exceptions.h"
8 
9 #include <atomic>
10 #include <cassert>
11 #include <functional>
12 #include <iostream>
13 
14 namespace wayverb {
15 namespace waveguide {
16 
26 
31 
35 
36 template <typename step_preprocessor, typename step_postprocessor>
37 size_t run(const core::compute_context& cc,
38  const mesh& mesh,
39  step_preprocessor&& pre,
40  step_postprocessor&& post,
41  const std::atomic_bool& keep_going) {
42 
43  const auto num_nodes = mesh.get_structure().get_condensed_nodes().size();
44 
45  const program program{cc};
46  cl::CommandQueue queue{cc.context, cc.device};
47  const auto make_zeroed_buffer = [&] {
48  auto ret = cl::Buffer{
49  cc.context, CL_MEM_READ_WRITE, sizeof(cl_float) * num_nodes};
50  auto kernel = program.get_zero_buffer_kernel();
51  kernel(cl::EnqueueArgs{queue, cl::NDRange{num_nodes}}, ret);
52  return ret;
53  };
54 
55  auto previous = make_zeroed_buffer();
56  auto current = make_zeroed_buffer();
57 
58  const auto node_buffer = core::load_to_buffer(
59  cc.context, mesh.get_structure().get_condensed_nodes(), true);
60 
61  const auto boundary_coefficients_buffer = core::load_to_buffer(
62  cc.context, mesh.get_structure().get_coefficients(), true);
63 
64  cl::Buffer error_flag_buffer{cc.context, CL_MEM_READ_WRITE, sizeof(cl_int)};
65 
66  auto boundary_buffer_1 = core::load_to_buffer(
67  cc.context, get_boundary_data<1>(mesh.get_structure()), false);
68  auto boundary_buffer_2 = core::load_to_buffer(
69  cc.context, get_boundary_data<2>(mesh.get_structure()), false);
70  auto boundary_buffer_3 = core::load_to_buffer(
71  cc.context, get_boundary_data<3>(mesh.get_structure()), false);
72 
73  auto kernel = program.get_kernel();
74 
75  // run
76  auto step = 0u;
77 
78  // The preprocessor returns 'true' while it should be run.
79  // It also updates the mesh with new pressure values.
80  for (; pre(queue, current, step) && keep_going; ++step) {
81  // set flag state to successful
82  core::write_value(queue, error_flag_buffer, 0, id_success);
83 
84  // run kernel
85  kernel(cl::EnqueueArgs(queue,
86  cl::NDRange(mesh.get_structure()
87  .get_condensed_nodes()
88  .size())),
89  previous,
90  current,
91  node_buffer,
92  mesh.get_descriptor().dimensions,
93  boundary_buffer_1,
94  boundary_buffer_2,
95  boundary_buffer_3,
96  boundary_coefficients_buffer,
97  error_flag_buffer);
98 
99  // read out flag value
100  if (const auto error_flag =
101  core::read_value<error_code>(queue, error_flag_buffer, 0)) {
102  if (error_flag & id_inf_error) {
103  throw core::exceptions::value_is_inf(
104  "Pressure value is inf, check filter coefficients.");
105  }
106 
107  if (error_flag & id_nan_error) {
108  throw core::exceptions::value_is_nan(
109  "Pressure value is nan, check filter coefficients.");
110  }
111 
112  if (error_flag & id_outside_mesh_error) {
113  throw std::runtime_error("Tried to read non-existant node.");
114  }
115 
116  if (error_flag & id_suspicious_boundary_error) {
117  throw std::runtime_error("Suspicious boundary read.");
118  }
119  }
120 
121  post(queue, current, step);
122 
123  std::swap(previous, current);
124  }
125  return step;
126 }
127 
128 } // namespace waveguide
129 } // namespace wayverb
Definition: capsule_base.h:9
Definition: gpu_geometry_tests.cpp:24