|
7 | 7 | */ |
8 | 8 |
|
9 | 9 | #include <executorch/backends/webgpu/runtime/WebGPUGraph.h> |
| 10 | +#include <executorch/backends/webgpu/runtime/WebGPUUtils.h> |
10 | 11 | #include <executorch/backends/webgpu/runtime/ops/OperatorRegistry.h> |
11 | 12 | #include <executorch/backends/webgpu/runtime/ops/view_copy/view_copy.h> |
12 | 13 |
|
@@ -38,11 +39,49 @@ void add_flat_copy(WebGPUGraph& graph, int in_id, int out_id) { |
38 | 39 | } |
39 | 40 |
|
40 | 41 | // Aliased in/out already in place; CopyBufferToBuffer rejects src == dst. |
41 | | - if (in_tensor.buffer == out_tensor.buffer) { |
42 | | - return; |
43 | | - } |
| 42 | + const bool aliased = in_tensor.buffer == out_tensor.buffer; |
| 43 | + const size_t dispatch_idx = aliased |
| 44 | + ? 0 |
| 45 | + : graph.add_buffer_copy( |
| 46 | + in_tensor.buffer, out_tensor.buffer, out_tensor.nbytes); |
44 | 47 |
|
45 | | - graph.add_buffer_copy(in_tensor.buffer, out_tensor.buffer, out_tensor.nbytes); |
| 48 | + // Dynamic shapes: view preserves numel; copy_nbytes + out dims track live in. |
| 49 | + std::vector<int64_t> out_max = out_tensor.dims; |
| 50 | + graph.add_tensor_resize_hook( |
| 51 | + in_id, [in_id, out_id, out_max, dispatch_idx, aliased](WebGPUGraph& g) { |
| 52 | + const uint64_t target = utils::numel_of(g.cur_dims(in_id)); |
| 53 | + std::vector<int64_t> od = out_max; |
| 54 | + const uint64_t maxnumel = utils::numel_of(out_max); |
| 55 | + if (maxnumel != target) { |
| 56 | + bool resolved = false; |
| 57 | + // Assumes one dynamic dim; picks the leftmost numel-divisible. |
| 58 | + for (size_t d = 0; d < od.size(); d++) { |
| 59 | + if (out_max[d] <= 0) { |
| 60 | + continue; |
| 61 | + } |
| 62 | + const uint64_t rest = maxnumel / static_cast<uint64_t>(out_max[d]); |
| 63 | + if (rest != 0 && target % rest == 0) { |
| 64 | + const uint64_t nd = target / rest; |
| 65 | + if (nd <= static_cast<uint64_t>(out_max[d])) { |
| 66 | + od[d] = static_cast<int64_t>(nd); |
| 67 | + resolved = true; |
| 68 | + break; |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + // Fail loud: a silent miss would leave od at max while copy_nbytes |
| 73 | + // shrinks to the live size, desyncing consumers from the real copy. |
| 74 | + if (!resolved) { |
| 75 | + throw std::runtime_error( |
| 76 | + "view_copy(resize): could not resolve live output shape"); |
| 77 | + } |
| 78 | + } |
| 79 | + g.set_cur_dims(out_id, od); |
| 80 | + if (!aliased) { |
| 81 | + g.dispatch_at(dispatch_idx).copy_nbytes = |
| 82 | + static_cast<size_t>(target) * sizeof(float); |
| 83 | + } |
| 84 | + }); |
46 | 85 | } |
47 | 86 |
|
48 | 87 | namespace { |
|
0 commit comments