13WGPUStringView visLabel(
const char *
s) {
16 out.length = WGPU_STRLEN;
20wgpu::ShaderModule visShader(wgpu::Device
device,
const std::string &
source) {
21 WGPUShaderSourceWGSL wgsl{};
22 wgsl.chain.sType = WGPUSType_ShaderSourceWGSL;
23 wgsl.code.data =
source.c_str();
24 wgsl.code.length =
source.size();
25 WGPUShaderModuleDescriptor
desc{};
26 desc.nextInChain = &wgsl.chain;
27 return device.CreateShaderModule(
28 reinterpret_cast<const wgpu::ShaderModuleDescriptor *
>(&
desc));
31struct VisibilityParams {
37static_assert(
sizeof(VisibilityParams) == 16);
39constexpr const char *kVisibilityWgsl = R
"wgsl(
40struct Light3D { posRadius: vec4f, color: vec4f };
49 lights: array<Light3D, 8>,
58struct Params { outputBase: u32, instanceCount: u32, indexType: u32, pad: u32 };
60 @builtin(position) pos: vec4f,
61 @location(0) worldNormal: vec3f,
62 @location(1) uv: vec2f,
63 @location(2) bary: vec3f,
64 @location(3) worldPos: vec3f,
65 @location(4) viewPos: vec3f,
66 @location(5) @interpolate(flat) instanceId: u32,
67 @location(6) @interpolate(flat) triBase: u32,
70 @location(0) id: vec2u,
71 @location(1) bary: vec2f,
73@group(0) @binding(0) var<uniform> frame: Frame;
74@group(0) @binding(1) var albedoTex: texture_2d<f32>;
75@group(0) @binding(7) var mainSampler: sampler;
76@group(1) @binding(0) var<storage, read> visibleModels: array<mat4x4f>;
77@group(1) @binding(1) var<storage, read> vertexWords: array<u32>;
78@group(1) @binding(2) var<storage, read> indexWords: array<u32>;
79@group(1) @binding(3) var<uniform> params: Params;
81fn loadIndex(index: u32) -> u32 {
82 if (params.indexType == 0u) {
83 let packed = indexWords[index >> 1u];
84 return select(packed & 0xffffu, packed >> 16u, (index & 1u) != 0u);
86 return indexWords[index];
88fn loadVec3(vertex: u32, wordOffset: u32) -> vec3f {
89 let base = vertex * 8u + wordOffset;
90 return vec3f(bitcast<f32>(vertexWords[base]), bitcast<f32>(vertexWords[base + 1u]),
91 bitcast<f32>(vertexWords[base + 2u]));
93fn inverse3x3(m: mat3x3f) -> mat3x3f {
94 let a = m[0].x; let b = m[1].x; let c = m[2].x;
95 let d = m[0].y; let e = m[1].y; let f = m[2].y;
96 let g = m[0].z; let h = m[1].z; let i = m[2].z;
97 let det = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
99 vec3f((e * i - f * h) / det, (f * g - d * i) / det, (d * h - e * g) / det),
100 vec3f((c * h - b * i) / det, (a * i - c * g) / det, (b * g - a * h) / det),
101 vec3f((b * f - c * e) / det, (c * d - a * f) / det, (a * e - b * d) / det));
105fn vs_main(@builtin(vertex_index) vertexIndex: u32,
106 @builtin(instance_index) instanceIndex: u32) -> VSOut {
107 let vertex = loadIndex(vertexIndex);
108 let objectPos = loadVec3(vertex, 0u);
109 let objectNormal = loadVec3(vertex, 3u);
110 let uvBase = vertex * 8u + 6u;
111 let globalInstance = params.outputBase + instanceIndex;
112 let model = visibleModels[globalInstance];
113 let world = model * vec4f(objectPos, 1.0);
115 out.pos = frame.mvp * world;
116 out.pos.y = -out.pos.y;
117 out.worldPos = world.xyz;
118 out.viewPos = (frame.view * world).xyz;
119 out.worldNormal = normalize(transpose(inverse3x3(
120 mat3x3f(model[0].xyz, model[1].xyz, model[2].xyz))) * objectNormal);
121 out.uv = vec2f(bitcast<f32>(vertexWords[uvBase]), bitcast<f32>(vertexWords[uvBase + 1u]));
122 let corner = vertexIndex % 3u;
123 out.bary = vec3f(select(0.0, 1.0, corner == 0u),
124 select(0.0, 1.0, corner == 1u),
125 select(0.0, 1.0, corner == 2u));
126 out.instanceId = globalInstance;
127 out.triBase = (vertexIndex / 3u) * 3u;
132fn fs_main(in: VSOut) -> VisOut {
133 let base = textureSample(albedoTex, mainSampler, in.uv) * frame.tint;
134 if (base.a < 0.5) { discard; }
135 let nearZ = max(frame.clipInfo.x, 1e-4);
136 let farZ = max(frame.clipInfo.y, nearZ + 1e-3);
137 let linearDepth = clamp((max(-in.viewPos.z, 0.0) - nearZ) / (farZ - nearZ), 0.0, 1.0);
139 out.id = vec2u(in.instanceId, in.triBase);
140 out.bary = in.bary.xy;
145constexpr const char *kResolveVertexWgsl = R
"wgsl(
147fn vs_main(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
148 let x = f32((index << 1u) & 2u);
149 let y = f32(index & 2u);
150 return vec4f(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0);
154std::string makeResolveFragment() {
156 const std::string entry =
"@fragment\nfn fs_main(in: FSIn) -> @location(0) vec4f {";
158 if (
pos == std::string::npos)
159 throw std::runtime_error(
"WebGPU visibility resolve: mesh fragment entry not found");
160 source.replace(
pos, entry.size(),
"fn shadeMesh(in: FSIn) -> vec4f {");
162struct ResolveParams { outputBase: u32, instanceCount: u32, indexType: u32, pad: u32 };
164 @location(0) color: vec4f,
165 @builtin(frag_depth) depth: f32,
167@group(1) @binding(0) var visID: texture_2d<u32>;
168@group(1) @binding(1) var visBary: texture_2d<f32>;
169@group(1) @binding(2) var<storage, read> resolveModels: array<mat4x4f>;
170@group(1) @binding(3) var<storage, read> resolveVertexWords: array<u32>;
171@group(1) @binding(4) var<storage, read> resolveIndexWords: array<u32>;
172@group(1) @binding(5) var<uniform> resolveParams: ResolveParams;
174fn resolveIndex(index: u32) -> u32 {
175 if (resolveParams.indexType == 0u) {
176 let packed = resolveIndexWords[index >> 1u];
177 return select(packed & 0xffffu, packed >> 16u, (index & 1u) != 0u);
179 return resolveIndexWords[index];
181fn resolveVec3(vertex: u32, wordOffset: u32) -> vec3f {
182 let base = vertex * 8u + wordOffset;
183 return vec3f(bitcast<f32>(resolveVertexWords[base]),
184 bitcast<f32>(resolveVertexWords[base + 1u]),
185 bitcast<f32>(resolveVertexWords[base + 2u]));
187fn resolveInverse3x3(m: mat3x3f) -> mat3x3f {
188 let a = m[0].x; let b = m[1].x; let c = m[2].x;
189 let d = m[0].y; let e = m[1].y; let f = m[2].y;
190 let g = m[0].z; let h = m[1].z; let i = m[2].z;
191 let det = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
193 vec3f((e * i - f * h) / det, (f * g - d * i) / det, (d * h - e * g) / det),
194 vec3f((c * h - b * i) / det, (a * i - c * g) / det, (b * g - a * h) / det),
195 vec3f((b * f - c * e) / det, (c * d - a * f) / det, (a * e - b * d) / det));
199fn resolve_main(@builtin(position) fragCoord: vec4f) -> ResolveOut {
200 let pixel = vec2i(fragCoord.xy);
201 let id = textureLoad(visID, pixel, 0).xy;
202 if (id.x < resolveParams.outputBase ||
203 id.x >= resolveParams.outputBase + resolveParams.instanceCount) { discard; }
204 var bary = vec3f(textureLoad(visBary, pixel, 0).xy, 0.0);
205 bary.z = 1.0 - bary.x - bary.y;
206 bary = clamp(bary, vec3f(0.0), vec3f(1.0));
207 bary /= max(bary.x + bary.y + bary.z, 1e-6);
208 let i0 = resolveIndex(id.y);
209 let i1 = resolveIndex(id.y + 1u);
210 let i2 = resolveIndex(id.y + 2u);
211 let objectPos = resolveVec3(i0, 0u) * bary.x + resolveVec3(i1, 0u) * bary.y +
212 resolveVec3(i2, 0u) * bary.z;
213 let objectNormal = resolveVec3(i0, 3u) * bary.x + resolveVec3(i1, 3u) * bary.y +
214 resolveVec3(i2, 3u) * bary.z;
215 let uv0base = i0 * 8u + 6u;
216 let uv1base = i1 * 8u + 6u;
217 let uv2base = i2 * 8u + 6u;
218 let uv0 = vec2f(bitcast<f32>(resolveVertexWords[uv0base]),
219 bitcast<f32>(resolveVertexWords[uv0base + 1u]));
220 let uv1 = vec2f(bitcast<f32>(resolveVertexWords[uv1base]),
221 bitcast<f32>(resolveVertexWords[uv1base + 1u]));
222 let uv2 = vec2f(bitcast<f32>(resolveVertexWords[uv2base]),
223 bitcast<f32>(resolveVertexWords[uv2base + 1u]));
224 let model = resolveModels[id.x];
225 let world = model * vec4f(objectPos, 1.0);
227 input.vNormal = normalize(transpose(resolveInverse3x3(
228 mat3x3f(model[0].xyz, model[1].xyz, model[2].xyz))) * objectNormal);
229 input.vUV = uv0 * bary.x + uv1 * bary.y + uv2 * bary.z;
230 input.vTint = ubo.tint;
231 input.vWorldPos = world.xyz;
232 input.vCameraPos = ubo.cameraPos.xyz;
233 input.vViewPos = (ubo.view * world).xyz;
234 input.fragCoord = fragCoord;
235 let clip = ubo.mvp * world;
237 out.color = shadeMesh(input);
238 out.depth = clip.z / max(clip.w, 1e-6);
245void fillVisibilityFrame(Mesh3DUBO &ubo, Graphics &gfx, Material *
material) {
248 ubo.model = glm::mat4(1.f);
251 ubo.cameraPos.w =
material->getRoughness();
252 ubo.ambient.w =
material->getMetallic();
253 ubo.texBomb = glm::vec4(
material->getTexCellBombScale(),
material->getTexCellBombStrength(),
254 material->getTexCellBombRotation(), 0.f);
255 ubo.parallax = glm::vec4(
material->getParallaxScale(),
material->getParallaxMinLayers(),
256 material->getParallaxMaxLayers(), 0.f);
264 sceneColorSamples == 1;
268 if (!gpuDrivenComputePending_ || gpuDrivenBuckets_.empty())
return;
269 gpuDrivenVisPending_ =
true;
270 frameHad3DThisFrame =
true;
275 if (!gpuDrivenVisPending_)
return;
276 gpuDrivenResolvePending_ =
true;
279void Graphics::ensureGpuDrivenVisibilityResources() {
280 if (gpuDrivenVisPipeline_)
return;
281 WGPUBindGroupLayoutEntry visEntries[4]{};
282 for (uint32_t i = 0; i < 3; ++i) {
283 visEntries[i].binding = i;
284 visEntries[i].visibility = WGPUShaderStage_Vertex;
285 visEntries[i].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
286 visEntries[i].buffer.minBindingSize = i == 0 ?
sizeof(glm::mat4) : 4u;
288 visEntries[3].binding = 3;
289 visEntries[3].visibility = WGPUShaderStage_Vertex;
290 visEntries[3].buffer.type = WGPUBufferBindingType_Uniform;
291 visEntries[3].buffer.hasDynamicOffset =
true;
292 visEntries[3].buffer.minBindingSize =
sizeof(VisibilityParams);
293 WGPUBindGroupLayoutDescriptor vbgl{};
294 vbgl.label = visLabel(
"eve_visibility_bgl");
296 vbgl.entries = visEntries;
297 gpuDrivenVisSetLayout_ =
device.CreateBindGroupLayout(
298 reinterpret_cast<const wgpu::BindGroupLayoutDescriptor *
>(&vbgl));
300 WGPUBindGroupLayoutEntry resolveEntries[6]{};
301 resolveEntries[0].binding = 0;
302 resolveEntries[0].visibility = WGPUShaderStage_Fragment;
303 resolveEntries[0].texture.sampleType = WGPUTextureSampleType_Uint;
304 resolveEntries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
305 resolveEntries[1].binding = 1;
306 resolveEntries[1].visibility = WGPUShaderStage_Fragment;
307 resolveEntries[1].texture.sampleType = WGPUTextureSampleType_UnfilterableFloat;
308 resolveEntries[1].texture.viewDimension = WGPUTextureViewDimension_2D;
309 for (uint32_t i = 2; i < 5; ++i) {
310 resolveEntries[i].binding = i;
311 resolveEntries[i].visibility = WGPUShaderStage_Fragment;
312 resolveEntries[i].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
313 resolveEntries[i].buffer.minBindingSize = i == 2 ?
sizeof(glm::mat4) : 4u;
315 resolveEntries[5].binding = 5;
316 resolveEntries[5].visibility = WGPUShaderStage_Fragment;
317 resolveEntries[5].buffer.type = WGPUBufferBindingType_Uniform;
318 resolveEntries[5].buffer.hasDynamicOffset =
true;
319 resolveEntries[5].buffer.minBindingSize =
sizeof(VisibilityParams);
320 WGPUBindGroupLayoutDescriptor rbgl{};
321 rbgl.label = visLabel(
"eve_visibility_resolve_bgl");
323 rbgl.entries = resolveEntries;
324 gpuDrivenResolveSetLayout_ =
device.CreateBindGroupLayout(
325 reinterpret_cast<const wgpu::BindGroupLayoutDescriptor *
>(&rbgl));
327 WGPUBindGroupLayout visLayouts[2] = {mesh3dSetLayout.Get(), gpuDrivenVisSetLayout_.Get()};
328 WGPUPipelineLayoutDescriptor vpl{};
329 vpl.label = visLabel(
"eve_visibility_layout");
330 vpl.bindGroupLayoutCount = 2;
331 vpl.bindGroupLayouts = visLayouts;
332 gpuDrivenVisPipelineLayout_ =
device.CreatePipelineLayout(
333 reinterpret_cast<const wgpu::PipelineLayoutDescriptor *
>(&vpl));
334 WGPUBindGroupLayout resolveLayouts[2] = {mesh3dSetLayout.Get(),
335 gpuDrivenResolveSetLayout_.Get()};
336 WGPUPipelineLayoutDescriptor rpl{};
337 rpl.label = visLabel(
"eve_visibility_resolve_layout");
338 rpl.bindGroupLayoutCount = 2;
339 rpl.bindGroupLayouts = resolveLayouts;
340 gpuDrivenResolvePipelineLayout_ =
device.CreatePipelineLayout(
341 reinterpret_cast<const wgpu::PipelineLayoutDescriptor *
>(&rpl));
343 wgpu::ShaderModule vis = visShader(device, kVisibilityWgsl);
344 WGPUColorTargetState targets[2]{};
345 targets[0].format = WGPUTextureFormat_RG32Uint;
346 targets[1].format = WGPUTextureFormat_RG16Float;
347 for (
auto &
target : targets)
target.writeMask = WGPUColorWriteMask_All;
348 WGPUFragmentState fs{};
349 fs.module = vis.Get();
350 fs.entryPoint = visLabel(
"fs_main");
352 fs.targets = targets;
353 WGPUDepthStencilState
depth{};
354 depth.format = WGPUTextureFormat_Depth32Float;
355 depth.depthWriteEnabled = WGPUOptionalBool_True;
356 depth.depthCompare = WGPUCompareFunction_Less;
357 WGPURenderPipelineDescriptor vpd{};
358 vpd.label = visLabel(
"eve_visibility");
359 vpd.layout = gpuDrivenVisPipelineLayout_.Get();
360 vpd.vertex.module = vis.Get();
361 vpd.vertex.entryPoint = visLabel(
"vs_main");
363 vpd.primitive.topology = WGPUPrimitiveTopology_TriangleList;
364 vpd.primitive.frontFace = WGPUFrontFace_CW;
365 vpd.primitive.cullMode = WGPUCullMode_None;
366 vpd.depthStencil = &
depth;
367 vpd.multisample.count = 1;
368 vpd.multisample.mask = 0xFFFFFFFFu;
369 gpuDrivenVisPipeline_ =
device.CreateRenderPipeline(
370 reinterpret_cast<const wgpu::RenderPipelineDescriptor *
>(&vpd));
372 wgpu::ShaderModule resolveVert = visShader(device, kResolveVertexWgsl);
373 const std::string resolveSource = makeResolveFragment();
374 wgpu::ShaderModule resolveFrag = visShader(device, resolveSource);
375 WGPUColorTargetState resolveTarget{};
376 resolveTarget.format = sceneColorFormat;
377 resolveTarget.writeMask = WGPUColorWriteMask_All;
378 WGPUFragmentState rfs{};
379 rfs.module = resolveFrag.Get();
380 rfs.entryPoint = visLabel(
"resolve_main");
382 rfs.targets = &resolveTarget;
383 depth.depthCompare = WGPUCompareFunction_Always;
384 WGPURenderPipelineDescriptor rpd{};
385 rpd.label = visLabel(
"eve_visibility_resolve");
386 rpd.layout = gpuDrivenResolvePipelineLayout_.Get();
387 rpd.vertex.module = resolveVert.Get();
388 rpd.vertex.entryPoint = visLabel(
"vs_main");
390 rpd.primitive.topology = WGPUPrimitiveTopology_TriangleList;
391 rpd.primitive.frontFace = WGPUFrontFace_CCW;
392 rpd.primitive.cullMode = WGPUCullMode_None;
393 rpd.depthStencil = &
depth;
394 rpd.multisample.count = 1;
395 rpd.multisample.mask = 0xFFFFFFFFu;
396 gpuDrivenResolvePipeline_ =
device.CreateRenderPipeline(
397 reinterpret_cast<const wgpu::RenderPipelineDescriptor *
>(&rpd));
400void Graphics::recordGpuDrivenVisibility(wgpu::CommandEncoder encoder) {
401 if (!gpuDrivenVisPending_ || gpuDrivenBuckets_.empty()) {
402 recordGpuDrivenVgVisibility(encoder);
405 createGbufferResources(sceneColorWidth, sceneColorHeight);
406 ensureGpuDrivenVisibilityResources();
407 lastGbufferSlot = currentFrameSlot();
408 GbufferSlot &slot = gbufferSlots[lastGbufferSlot];
409 WGPURenderPassColorAttachment
colors[2]{};
410 const WGPUTextureView views[2] = {slot.visIDView.Get(), slot.visBaryView.Get()};
411 for (uint32_t i = 0; i < 2; ++i) {
412 colors[i].view = views[i];
413 colors[i].depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
414 colors[i].loadOp = WGPULoadOp_Clear;
415 colors[i].storeOp = WGPUStoreOp_Store;
416 colors[i].clearValue = i == 0 ? WGPUColor{4294967295.0, 0.0, 0.0, 0.0}
417 : WGPUColor{0.0, 0.0, 0.0, 0.0};
419 WGPURenderPassDepthStencilAttachment
depth{};
420 depth.view = slot.depthView.Get();
421 depth.depthClearValue = 1.f;
422 depth.depthLoadOp = WGPULoadOp_Clear;
423 depth.depthStoreOp = WGPUStoreOp_Store;
424 depth.stencilLoadOp = WGPULoadOp_Undefined;
425 depth.stencilStoreOp = WGPUStoreOp_Undefined;
426 WGPURenderPassDescriptor rp{};
427 rp.colorAttachmentCount = 2;
428 rp.colorAttachments =
colors;
429 rp.depthStencilAttachment = &
depth;
430 wgpu::RenderPassEncoder pass =
431 encoder.BeginRenderPass(
reinterpret_cast<const wgpu::RenderPassDescriptor *
>(&rp));
432 pass.SetPipeline(gpuDrivenVisPipeline_);
434 auto &arena = currentUboArena();
435 ensureUboArena(arena, arena.used + gpuDrivenBuckets_.size() * 2048);
436 for (uint32_t i = 0; i < gpuDrivenBuckets_.size(); ++i) {
437 const GpuDrivenBucket &
bucket = gpuDrivenBuckets_[i];
438 auto *gpu =
static_cast<GpuMesh *
>(
bucket.mesh->gpuHandle);
441 fillVisibilityFrame(frame, *
this,
material);
442 frame.mvp = mesh3dViewProj;
443 frame.view = mesh3dView;
444 frame.cameraPos = glm::vec4(mesh3dCameraPos,
material->getRoughness());
445 frame.envProbeCenter = glm::vec4(mesh3dEnvProbeCenter, 1.f);
446 frame.envProbeExtent = glm::vec4(mesh3dEnvProbeExtent, 0.f);
448 if (probeIndex >= mesh3dReflectionProbes.
count)
continue;
449 const auto &probe = mesh3dReflectionProbes.
probes[probeIndex];
450 GpuTexture *gpuProbe = gpuForTexture(probe.cubemap);
451 if (!gpuProbe || !gpuProbe->isCube)
continue;
452 frame.reflectionProbeCenter[probeIndex] = glm::vec4(probe.center, probe.intensity);
453 frame.reflectionProbeExtent[probeIndex] =
454 glm::vec4(probe.extent, probe.blendDistance);
456 frame.ambient = glm::vec4(glm::vec3(mesh3dLighting.
ambient),
material->getMetallic());
457 frame.clipInfo = glm::vec4(mesh3dNear, mesh3dFar, 0.f, 0.f);
458 const uint32_t frameOffset = arena.alloc(
sizeof(Mesh3DUBO), 256);
459 const uint32_t shadowOffset = arena.alloc(
sizeof(ShadowUBO), 256);
460 const uint32_t paramsOffset = arena.alloc(
sizeof(VisibilityParams), 256);
461 queue.WriteBuffer(arena.buffer, frameOffset, &frame,
sizeof(frame));
462 ShadowUBO shadow = mesh3dShadows.
ubo;
463 queue.WriteBuffer(arena.buffer, shadowOffset, &shadow,
sizeof(shadow));
465 gpu->indexFormat == wgpu::IndexFormat::Uint16 ? 0
u : 1u, 0
u};
466 queue.WriteBuffer(arena.buffer, paramsOffset, &
params,
sizeof(
params));
468 GpuTexture *depthTex = mesh3dSceneDepthTexture ? gpuForTexture(mesh3dSceneDepthTexture)
469 : flatDepthTexture3D;
470 wgpu::BindGroup frameGroup =
471 makeMeshBindGroup(gpuForTexture(
material->getAlbedoTexture()), gpuForTexture(
material->getNormalTexture()),
472 gpuForTexture(mesh3dEnvTexture), gpuForTexture(
material->getHeightTexture()), depthTex,
473 nullptr, frameOffset, shadowOffset, 0, uploadSkinPalette(
nullptr));
474 const uint32_t frameOffsets[3] = {frameOffset, shadowOffset, 0};
475 pass.SetBindGroup(0, frameGroup, 3, frameOffsets);
476 WGPUBindGroupEntry
entries[4]{};
478 entries[0].buffer = gpuDrivenVisibleBuffer_.Get();
479 entries[0].size = gpuDrivenVisibleCapacity_;
481 entries[1].buffer = gpu->vertexBuffer.Get();
482 entries[1].size = gpu->vertexCapacity;
484 entries[2].buffer = gpu->indexBuffer.Get();
485 entries[2].size = gpu->indexCapacity;
487 entries[3].buffer = arena.buffer.Get();
488 entries[3].size =
sizeof(VisibilityParams);
489 WGPUBindGroupDescriptor bgd{};
490 bgd.layout = gpuDrivenVisSetLayout_.Get();
494 reinterpret_cast<const wgpu::BindGroupDescriptor *
>(&bgd));
495 pass.SetBindGroup(1,
group, 1, ¶msOffset);
496 pass.DrawIndirect(gpuDrivenVisIndirectBuffer_, uint64_t(i) * 16u);
499 gpuDrivenVisPending_ =
false;
500 recordGpuDrivenVgVisibility(encoder);
503void Graphics::flushGpuDrivenResolve(wgpu::RenderPassEncoder pass) {
504 if (!gpuDrivenResolvePending_ || gpuDrivenBuckets_.empty() || gbufferSlots.empty()) {
505 flushGpuDrivenVgResolve(pass);
508 GbufferSlot &slot = gbufferSlots[lastGbufferSlot];
509 auto &arena = currentUboArena();
510 ensureUboArena(arena, arena.used + gpuDrivenBuckets_.size() * 2048);
511 pass.SetPipeline(gpuDrivenResolvePipeline_);
512 for (
const GpuDrivenBucket &
bucket : gpuDrivenBuckets_) {
513 auto *gpu =
static_cast<GpuMesh *
>(
bucket.mesh->gpuHandle);
516 fillVisibilityFrame(frame, *
this,
material);
517 frame.mvp = mesh3dViewProj;
518 frame.view = mesh3dView;
519 frame.lightDir = glm::vec4(glm::vec3(mesh3dLighting.
lights[0].
posRadius),
520 float(mesh3dLighting.
count));
522 frame.lightColor.w = mesh3dEnvIntensity;
523 frame.cameraPos = glm::vec4(mesh3dCameraPos,
material->getRoughness());
524 frame.envProbeCenter = glm::vec4(mesh3dEnvProbeCenter, 1.f);
525 frame.envProbeExtent = glm::vec4(mesh3dEnvProbeExtent, 0.f);
527 if (probeIndex >= mesh3dReflectionProbes.
count)
continue;
528 const auto &probe = mesh3dReflectionProbes.
probes[probeIndex];
529 GpuTexture *gpuProbe = gpuForTexture(probe.cubemap);
530 if (!gpuProbe || !gpuProbe->isCube)
continue;
531 frame.reflectionProbeCenter[probeIndex] = glm::vec4(probe.center, probe.intensity);
532 frame.reflectionProbeExtent[probeIndex] =
533 glm::vec4(probe.extent, probe.blendDistance);
535 frame.ambient = glm::vec4(glm::vec3(mesh3dLighting.
ambient),
material->getMetallic());
539 ? mesh3dSsaoIntensity
541 frame.clipInfo = glm::vec4(mesh3dNear, mesh3dFar, 0.f, 0.f);
542 frame.cloud = mesh3dCloud;
543 frame.cloudWind = mesh3dCloudWind;
544 const uint32_t frameOffset = arena.alloc(
sizeof(Mesh3DUBO), 256);
545 const uint32_t shadowOffset = arena.alloc(
sizeof(ShadowUBO), 256);
546 const uint32_t paramsOffset = arena.alloc(
sizeof(VisibilityParams), 256);
547 queue.WriteBuffer(arena.buffer, frameOffset, &frame,
sizeof(frame));
548 ShadowUBO shadow = mesh3dShadows.
ubo;
550 queue.WriteBuffer(arena.buffer, shadowOffset, &shadow,
sizeof(shadow));
552 gpu->indexFormat == wgpu::IndexFormat::Uint16 ? 0
u : 1u, 0
u};
553 queue.WriteBuffer(arena.buffer, paramsOffset, &
params,
sizeof(
params));
555 GpuTexture *depthTex = mesh3dSceneDepthTexture ? gpuForTexture(mesh3dSceneDepthTexture)
556 : flatDepthTexture3D;
557 wgpu::BindGroup frameGroup =
558 makeMeshBindGroup(gpuForTexture(
material->getAlbedoTexture()), gpuForTexture(
material->getNormalTexture()),
559 gpuForTexture(mesh3dEnvTexture), gpuForTexture(
material->getHeightTexture()), depthTex,
560 nullptr, frameOffset, shadowOffset, 0, uploadSkinPalette(
nullptr));
561 const uint32_t frameOffsets[3] = {frameOffset, shadowOffset, 0};
562 pass.SetBindGroup(0, frameGroup, 3, frameOffsets);
563 WGPUBindGroupEntry
entries[6]{};
565 entries[0].textureView = slot.visIDView.Get();
567 entries[1].textureView = slot.visBaryView.Get();
569 entries[2].buffer = gpuDrivenVisibleBuffer_.Get();
570 entries[2].size = gpuDrivenVisibleCapacity_;
572 entries[3].buffer = gpu->vertexBuffer.Get();
573 entries[3].size = gpu->vertexCapacity;
575 entries[4].buffer = gpu->indexBuffer.Get();
576 entries[4].size = gpu->indexCapacity;
578 entries[5].buffer = arena.buffer.Get();
579 entries[5].size =
sizeof(VisibilityParams);
580 WGPUBindGroupDescriptor bgd{};
581 bgd.layout = gpuDrivenResolveSetLayout_.Get();
585 reinterpret_cast<const wgpu::BindGroupDescriptor *
>(&bgd));
586 pass.SetBindGroup(1,
group, 1, ¶msOffset);
587 pass.Draw(3, 1, 0, 0);
589 gpuDrivenResolvePending_ =
false;
590 gpuDrivenBuckets_.clear();
591 flushGpuDrivenVgResolve(pass);
std::unordered_map< std::string, QuestRuntime > entries
building::EdgeCurveGroup group
std::uint32_t instanceCount
std::vector< float > colors
const UnitySourceAsset & source
std::unique_ptr< RenderControl > renderControl_
void gpuDrivenRecordVisPass() override
Gpu driven record vis pass.
void gpuDrivenResolve() override
Gpu driven resolve.
bool gpuDrivenResolveWanted() const override
Gpu driven resolve wanted.
std::vector< ParamSpec > params
const char * kMesh3DFragWgsl
static constexpr int kMaxLights
Light3DGpu lights[kMaxLights]
static constexpr int kMaxProbes