载入中...
搜索中...
未找到
WebGpuVirtualGeometry.cpp
浏览该文件的文档.
2
3#include "gpgpu/GpuBuffer.h"
5
6#include <algorithm>
7#include <cstring>
8#include <vector>
9
10namespace eve::virtualgeometry {
11namespace webgpu {
12
25
26namespace {
27
28constexpr const char* kCullWgsl = R"wgsl(
29struct U { viewProj: mat4x4f, model: mat4x4f, cameraPos: vec4f, params: vec4f,
30 frustum: array<vec4f, 6>, misc: vec4f };
31struct Visible { counter: atomic<u32>, ids: array<u32> };
32@group(0) @binding(2) var<storage, read_write> cl: array<vec4u>;
33@group(0) @binding(3) var<storage, read_write> vis: Visible;
34@group(0) @binding(5) var<storage, read_write> u: U;
35@group(0) @binding(6) var<storage, read_write> stats: array<atomic<u32>>;
36fn center(id:u32)->vec3f { let v=cl[id*4u]; return vec3f(bitcast<f32>(v.x),bitcast<f32>(v.y),bitcast<f32>(v.z)); }
37fn err(id:u32)->f32 { return bitcast<f32>(cl[id*4u+2u].y); }
38@compute @workgroup_size(64)
39fn main(@builtin(global_invocation_id) gid:vec3u) {
40 let id=gid.x; if(id>=u32(u.misc.x)){return;}
41 let w4=u.model*vec4f(center(id),1); let w=w4.xyz/max(w4.w,1e-6);
42 let sc=max(length(u.model[0].xyz),max(length(u.model[1].xyz),length(u.model[2].xyz)));
43 let r=bitcast<f32>(cl[id*4u].w)*sc;
44 for(var i=0u;i<6u;i=i+1u){let p=u.frustum[i];if(dot(p.xyz,w)+p.w < -r){return;}}
45 let d=max(length(w-u.cameraPos.xyz),1e-4); let ec=err(id)/d;
46 let parent=cl[id*4u+1u].w; var ep=1e30;
47 if(parent!=0xffffffffu){let pw=u.model*vec4f(center(parent),1);ep=err(parent)/max(length(pw.xyz-u.cameraPos.xyz),1e-4);}
48 let leaf=cl[id*4u+2u].z==0u;
49 if(!((ec<=u.params.w||leaf)&&ep>u.params.w)){return;}
50 let slot=atomicAdd(&vis.counter,1u);vis.ids[slot]=id;atomicAdd(&stats[0],1u);
51})wgsl";
52
53constexpr const char* kRasterWgsl = R"wgsl(
54struct U { viewProj: mat4x4f, model: mat4x4f, cameraPos: vec4f, params: vec4f,
55 frustum: array<vec4f, 6>, misc: vec4f };
56struct Visible { counter: atomic<u32>, ids: array<u32> };
57@group(0) @binding(0) var<storage,read_write> pos:array<u32>;
58@group(0) @binding(1) var<storage,read_write> tri:array<u32>;
59@group(0) @binding(2) var<storage,read_write> cl:array<vec4u>;
60@group(0) @binding(3) var<storage,read_write> vis:Visible;
61@group(0) @binding(4) var<storage,read_write> pix:array<atomic<u32>>;
62@group(0) @binding(5) var<storage,read_write> u:U;
63@group(0) @binding(6) var<storage,read_write> stats:array<atomic<u32>>;
64fn p(i:u32)->vec3f{let b=i*3u;return vec3f(bitcast<f32>(pos[b]),bitcast<f32>(pos[b+1u]),bitcast<f32>(pos[b+2u]));}
65@compute @workgroup_size(128)
66fn main(@builtin(global_invocation_id) gid:vec3u){
67 let slot=gid.x/124u;let t=gid.x%124u;if(slot>=atomicLoad(&vis.counter)){return;}
68 let id=vis.ids[slot];let range=cl[id*4u+1u];if(t>=range.y){return;}
69 let b=(range.x+t)*3u;let c0=u.viewProj*(u.model*vec4f(p(tri[b]),1));
70 let c1=u.viewProj*(u.model*vec4f(p(tri[b+1u]),1));let c2=u.viewProj*(u.model*vec4f(p(tri[b+2u]),1));
71 if(c0.w<=1e-6||c1.w<=1e-6||c2.w<=1e-6){return;}
72 let s0=(c0.xy/c0.w*.5+vec2f(.5))*u.params.xy;let s1=(c1.xy/c1.w*.5+vec2f(.5))*u.params.xy;
73 let s2=(c2.xy/c2.w*.5+vec2f(.5))*u.params.xy;
74 let area=(s1.x-s0.x)*(s2.y-s0.y)-(s1.y-s0.y)*(s2.x-s0.x);if(area<=0){return;}
75 let view=vec2i(u.params.xy);let lo=clamp(vec2i(floor(min(min(s0,s1),s2))),vec2i(0),view-vec2i(1));
76 let hi=clamp(vec2i(ceil(max(max(s0,s1),s2))),vec2i(0),view-vec2i(1));let ia=1/area;
77 for(var y=lo.y;y<=hi.y;y=y+1){for(var x=lo.x;x<=hi.x;x=x+1){let q=vec2f(f32(x)+.5,f32(y)+.5);
78 let e0=(s1.x-s0.x)*(q.y-s0.y)-(s1.y-s0.y)*(q.x-s0.x);let e1=(s2.x-s1.x)*(q.y-s1.y)-(s2.y-s1.y)*(q.x-s1.x);
79 let e2=(s0.x-s2.x)*(q.y-s2.y)-(s0.y-s2.y)*(q.x-s2.x);if(e0<0||e1<0||e2<0){continue;}
80 let z=(e1*c0.z/c0.w+e2*c1.z/c1.w+e0*c2.z/c2.w)*ia;let d=u32(clamp(z,0,1)*65535);
81 atomicMin(&pix[u32(y*view.x+x)],(min(d,0xffffu)<<16u)|(id&0xffffu));}}
82 atomicAdd(&stats[4],1u);
83})wgsl";
84
86 if (v->positions) s->bindBuffer(0, v->positions);
87 if (v->triangles) s->bindBuffer(1, v->triangles);
88 if (v->clusters) s->bindBuffer(2, v->clusters);
89 if (v->visible) s->bindBuffer(3, v->visible);
90 if (v->pixels) s->bindBuffer(4, v->pixels);
91 if (v->uniforms) s->bindBuffer(5, v->uniforms);
92 if (v->stats) s->bindBuffer(6, v->stats);
93}
94void pixels(VgState* s, int w, int h) {
95 int n = std::max(1, w * h);
96 if (n <= s->pixelCapacity) return;
97 delete s->pixels;
98 s->pixels = gpgpu::webgpuNewBuffer(n * int(sizeof(uint32_t)), "storage");
99 s->pixelCapacity = n;
100 bind(s->cull, s);
101 bind(s->raster, s);
102}
103std::vector<uint32_t> packed(const VirtualGeometryAsset& a) {
104 std::vector<uint32_t> o;
105 o.reserve(a.clusters.size() * 16);
106 auto b = [](float f) {
107 uint32_t u;
108 std::memcpy(&u, &f, 4);
109 return u;
110 };
111 for (auto& c : a.clusters) {
112 o.insert(o.end(), {b(c.cx), b(c.cy), b(c.cz), b(c.r), c.triStart, c.triCount, c.lodLevel, c.parent, b(c.errorR),
113 b(c.errorRScreen), c.childCount, 0});
114 for (auto x : c.children) o.push_back(x);
115 }
116 return o;
117}
118} // namespace
119} // namespace webgpu
120
121void vgCreate(VgBackend& b) {
122 auto* s = new webgpu::VgState();
123 try {
124 s->cull = gpgpu::webgpuNewShaderFromWgsl(webgpu::kCullWgsl);
125 s->raster = gpgpu::webgpuNewShaderFromWgsl(webgpu::kRasterWgsl);
126 b.state = s;
127 } catch (...) {
128 delete s->cull;
129 delete s->raster;
130 delete s;
131 throw;
132 }
133}
134void vgDestroy(VgBackend& b) {
135 auto* s = static_cast<webgpu::VgState*>(b.state);
136 if (!s) return;
137 delete s->cull;
138 delete s->raster;
139 delete s->positions;
140 delete s->triangles;
141 delete s->clusters;
142 delete s->visible;
143 delete s->pixels;
144 delete s->uniforms;
145 delete s->stats;
146 delete s;
147 b.state = nullptr;
148}
149void vgUpload(VgBackend& b, const VirtualGeometryAsset& a) {
150 auto* s = static_cast<webgpu::VgState*>(b.state);
151 if (!s) return;
152 delete s->positions;
153 delete s->triangles;
154 delete s->clusters;
155 s->positions = gpgpu::webgpuNewBuffer(int(a.positions.size() * 4), "storage");
156 s->positions->uploadBytes(a.positions.data(), a.positions.size() * 4);
157 s->triangles = gpgpu::webgpuNewBuffer(int(a.triangles.size() * 4), "storage");
158 s->triangles->uploadBytes(a.triangles.data(), a.triangles.size() * 4);
159 auto p = webgpu::packed(a);
160 s->clusters = gpgpu::webgpuNewBuffer(int(p.size() * 4), "storage");
161 s->clusters->uploadBytes(p.data(), p.size() * 4);
162 if (!s->uniforms) s->uniforms = gpgpu::webgpuNewBuffer(int(sizeof(VgUniforms)), "storage");
163 if (!s->visible) s->visible = gpgpu::webgpuNewBuffer((s->visibleCapacity + 1) * 4, "storage");
164 if (!s->stats) s->stats = gpgpu::webgpuNewBuffer(32, "storage");
165 webgpu::pixels(s, s->viewW, s->viewH);
166 webgpu::bind(s->cull, s);
167 webgpu::bind(s->raster, s);
168}
169void vgUploadUniforms(VgBackend& b, const VgUniforms& u) {
170 auto* s = static_cast<webgpu::VgState*>(b.state);
171 if (!s) return;
172 if (!s->uniforms) s->uniforms = gpgpu::webgpuNewBuffer(int(sizeof(u)), "storage");
173 s->uniforms->uploadBytes(&u, sizeof(u));
174 s->cull->bindBuffer(5, s->uniforms);
175 s->raster->bindBuffer(5, s->uniforms);
176}
177void vgReset(VgBackend& b, int n) {
178 auto* s = static_cast<webgpu::VgState*>(b.state);
179 if (!s || n <= 0) return;
180 if (s->visibleCapacity == n && s->visible && s->stats) return;
181 s->visibleCapacity = n;
182 delete s->visible;
183 delete s->stats;
184 s->visible = gpgpu::webgpuNewBuffer((n + 1) * 4, "storage");
185 s->stats = gpgpu::webgpuNewBuffer(32, "storage");
186 s->cull->bindBuffer(3, s->visible);
187 s->cull->bindBuffer(6, s->stats);
188 s->raster->bindBuffer(3, s->visible);
189 s->raster->bindBuffer(6, s->stats);
190}
191int vgUpdate(VgBackend& b, int clusters, int capacity, int w, int h) {
192 auto* s = static_cast<webgpu::VgState*>(b.state);
193 if (!s || !s->visible) return 0;
194 webgpu::pixels(s, w, h);
195 s->viewW = w;
196 s->viewH = h;
197 s->visible->fillFloat32(0);
198 s->stats->fillFloat32(0);
199 std::vector<uint32_t> clear(size_t(w) * h, 0xffffffffu);
200 s->pixels->uploadBytes(clear.data(), clear.size() * 4);
201 gpgpu::webgpuDispatch(s->cull, (clusters + 63) / 64, 1, 1);
202 gpgpu::webgpuDispatch(s->raster, (capacity * 124 + 127) / 128, 1, 1);
203 uint32_t count = 0;
204 s->visible->downloadBytes(&count, 4);
205 s->lastVisible = int(std::min(count, uint32_t(capacity)));
206 return s->lastVisible;
207}
208bool vgReadPixels(VgBackend& b, std::vector<uint32_t>& out) {
209 auto* s = static_cast<webgpu::VgState*>(b.state);
210 if (!s || !s->pixels) return false;
211 out.resize(size_t(s->viewW) * s->viewH);
212 s->pixels->downloadBytes(out.data(), out.size() * 4);
213 return true;
214}
215} // namespace eve::virtualgeometry
float w
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
glm::vec4 p[6]
std::uint32_t capacity
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
float v
std::int32_t c
int h
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float f
uint8_t * pixels
std::uint32_t count
int children
Definition TreeMesh.cpp:295
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:18
Compute program for the WebGPU backend. Accepts WGSL source; GLSL/SPIR-V input is rejected (browsers ...
Definition WebGpuGpgpu.h:22
void webgpuDispatch(ComputeShader *shader, int groupsX, int groupsY, int groupsZ)
Webgpu dispatch.
WebGpuGpuBuffer * webgpuNewBuffer(int byteSize, const std::string &usage)
Webgpu new buffer.
WebGpuComputeShader * webgpuNewShaderFromWgsl(const std::string &wgsl)
Webgpu new shader from wgsl.
void vgReset(VgBackend &be, int visibleCapacity)
Vg reset.
int vgUpdate(VgBackend &be, int clusterCount, int visibleCapacity, int viewW, int viewH)
Vg update.
void vgUploadUniforms(VgBackend &be, const VgUniforms &u)
Vg upload uniforms.
bool vgReadPixels(VgBackend &be, std::vector< uint32_t > &out)
Vg read pixels.
void vgCreate(VgBackend &be)
Vg create.
void vgDestroy(VgBackend &be)
Vg destroy.
void vgUpload(VgBackend &be, const VirtualGeometryAsset &asset)
Vg upload.