| 49 | )"; |
| 50 | |
| 51 | int main() { |
| 52 | // N can be quite a bit larger than this on most GPUs (~ 1M on MBP M1) |
| 53 | static constexpr size_t N = 1000; |
| 54 | Context ctx = createContext(); |
| 55 | |
| 56 | // Host-side data |
| 57 | std::array<float, N> theta1Arr, theta2Arr, v1Arr, v2Arr, lengthArr; |
| 58 | std::fill(v1Arr.begin(), v1Arr.end(), 0.0); |
| 59 | std::fill(v2Arr.begin(), v2Arr.end(), 0.0); |
| 60 | for (size_t i = 0; i < N; ++i) { |
| 61 | theta1Arr[i] = 3.14159 / 2 + i * 3.14159 / 16 / N; |
| 62 | theta2Arr[i] = 3.14159 / 2 + i * 3.14159 / 16 / N - 0.1; |
| 63 | lengthArr[i] = 1.0 - i * 0.5 / N; |
| 64 | } |
| 65 | |
| 66 | // GPU buffers |
| 67 | Tensor theta1 = createTensor(ctx, Shape{N}, kf32, theta1Arr.data()); |
| 68 | Tensor theta2 = createTensor(ctx, Shape{N}, kf32, theta2Arr.data()); |
| 69 | Tensor vel1 = createTensor(ctx, Shape{N}, kf32, v1Arr.data()); |
| 70 | Tensor vel2 = createTensor(ctx, Shape{N}, kf32, v2Arr.data()); |
| 71 | Tensor length = createTensor(ctx, Shape{N}, kf32, lengthArr.data()); |
| 72 | std::array<float, 2 * 2 * N> posArr; // x, y outputs for each pendulum |
| 73 | std::string screen(80 * 40, ' '); |
| 74 | Tensor pos = createTensor(ctx, Shape{N * 4}, kf32); |
| 75 | |
| 76 | // Prepare computation |
| 77 | KernelCode kernel{kUpdateSim, 256, kf32}; |
| 78 | printf("WGSL code: %s\n", kernel.data.c_str()); |
| 79 | Kernel update = createKernel( |
| 80 | ctx, kernel, Bindings{theta1, theta2, vel1, vel2, length, pos}, |
| 81 | /* nWorkgroups */ cdiv({N, 1, 1}, kernel.workgroupSize)); |
| 82 | |
| 83 | // Main simulation update loop |
| 84 | printf("\033[2J\033[H"); |
| 85 | while (true) { |
| 86 | auto start = std::chrono::high_resolution_clock::now(); |
| 87 | std::promise<void> promise; |
| 88 | std::future<void> future = promise.get_future(); |
| 89 | dispatchKernel(ctx, update, promise); |
| 90 | wait(ctx, future); |
| 91 | toCPU(ctx, pos, posArr.data(), sizeof(posArr)); |
| 92 | auto end = std::chrono::high_resolution_clock::now(); |
| 93 | std::chrono::duration<double> elapsed = end - start; |
| 94 | // N * 2 because there's two objects per pendulum |
| 95 | rasterize(posArr.data(), N * 2, 2.0, 2.0, screen, 80, 40); |
| 96 | printf("\033[1;1H" // reset cursor |
| 97 | "# simulations: %lu\n%s", |
| 98 | N, screen.c_str()); |
| 99 | resetCommandBuffer(ctx.device, update); // Prepare kernel command |
| 100 | // buffer for nxt iteration |
| 101 | std::this_thread::sleep_for(std::chrono::milliseconds(8) - elapsed); |
| 102 | } |
| 103 | } |
nothing calls this directly
no test coverage detected