OverviewFilesCommitsIssuesDocsReleasesPeers

nvidia-rtx-godot commits / 7db1dfb

Rebuild the RT scene uniform set only when a bound RID changes
update_uniform_set destroyed and recreated the scene descriptor set on every frame, for every viewport: ~30 bindings including the 12 material samplers, plus a set_resource_name call. That is per-frame driver work paid unconditionally, whether or not anything in the scene changed, and it is identical in an empty CSG test level and in a full Quake map -- which matches the observed slowdown being present even on the simplest path-traced scene. Descriptors only need rebuilding when the RESOURCES change. Buffers whose contents are updated in place -- the params UBO, the light SSBO -- keep the same RID, so their descriptors stay correct. So flatten the bound RIDs, compare against the set used last time, and reuse the existing set when they match. The tail that creates the bindless set moved into _update_bindless_uniform_set so it still runs on frames where the scene set is reused; the two sets have independent lifetimes and set 1 must stay current regardless. Measured effect not yet established -- this removes a cost that is provably per-frame, but it has not been benchmarked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7db1dfb4c0d698ca78dc10230f66642bb61cb48c
by plankatron <fleeky@gmail.com> · 2026-07-29T17:44:06.000Z

Changed files (2) +85 -35

servers/rendering/renderer_rd/forward_clustered/render_raytracing.cpp +80 -35
……@@ -2025,13 +2025,53 @@ uint32_t RenderRaytracing::gather_lights(const RenderDataRD *p_render_data, RT_L
20252025// Uniform set update
20262026// ---------------------------------------------------------------------------
20272027
2028// All texture kinds share descriptor set 1, so it is rebuilt as a unit whenever
2029// any table changed. Split out of update_uniform_set because that function can
2030// now return early when the scene set is unchanged, and the bindless set still
2031// has to be kept current on those frames.
2032void RenderRaytracing::_update_bindless_uniform_set(RID p_shader_rd) {
2033 bool bindless_dirty = !bindless_uniform_set.is_valid();
2034 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2035 if (!bindless_blocks[k] || !bindless_blocks[k]->is_initialized()) {
2036 return;
2037 }
2038 bindless_dirty = bindless_dirty || bindless_blocks[k]->needs_rebuild();
2039 }
2040
2041 if (!bindless_dirty) {
2042 return;
2043 }
2044
2045 Vector<RD::Uniform> bindless_uniforms;
2046 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2047 bindless_blocks[k]->collect_uniform(bindless_uniforms);
2048 }
2049
2050 if (bindless_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(bindless_uniform_set)) {
2051 RD::get_singleton()->free_rid(bindless_uniform_set);
2052 }
2053 bindless_uniform_set = RD::get_singleton()->uniform_set_create(bindless_uniforms, p_shader_rd, 1);
2054
2055 if (bindless_uniform_set.is_valid()) {
2056 RD::get_singleton()->set_resource_name(bindless_uniform_set, "Bindless Texture Set");
2057 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2058 bindless_blocks[k]->mark_rebuilt();
2059 }
2060 } else {
2061 ERR_PRINT_ONCE("RT: failed to create the bindless texture uniform set.");
2062 }
2063}
2064
20282065RID RenderRaytracing::update_uniform_set(RTViewportState *p_state, const RenderDataRD *p_render_data, uint32_t p_rt_flags) {
20292066 ERR_FAIL_NULL_V(p_state, RID());
20302067
2031 if (p_state->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_state->uniform_set)) {
2032 RD::get_singleton()->free_rid(p_state->uniform_set);
2033 p_state->uniform_set = RID();
2034 }
2068 // NOTE: the set is NOT freed here. It used to be destroyed and recreated every
2069 // frame for every viewport -- ~30 bindings including the 12 material samplers
2070 // -- which is pure per-frame driver work even when nothing about the scene
2071 // changed. It is now rebuilt only when one of the bound RIDs differs (see the
2072 // comparison against uniform_set_rids at the end of this function). Buffers
2073 // updated in place, like params and lights, keep their RID and so do not
2074 // require a new descriptor set.
20352075
20362076 // BindlessBlock handles its own uniform set cleanup via clear()
20372077
……@@ -2320,45 +2360,50 @@ RID RenderRaytracing::update_uniform_set(RTViewportState *p_state, const RenderD
23202360 RID shader_rd = shader ? shader->get_pipeline_shader_rd(p_rt_flags) : RID();
23212361
23222362 if (shader_rd.is_valid()) {
2323 p_state->uniform_set = RD::get_singleton()->uniform_set_create(
2324 uniforms,
2325 shader_rd,
2326 RenderForwardClustered::SCENE_UNIFORM_SET);
2327 RD::get_singleton()->set_resource_name(p_state->uniform_set, "RT Uniform Set");
2328
2329 // === SET 1: Bindless textures ===
2330 // All texture kinds share set 1, so the set is rebuilt as a unit whenever
2331 // any table changed.
2332 bool bindless_ready = true;
2333 bool bindless_dirty = !bindless_uniform_set.is_valid();
2334 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2335 if (!bindless_blocks[k] || !bindless_blocks[k]->is_initialized()) {
2336 bindless_ready = false;
2337 break;
2363 // Flatten the bound RIDs (plus the shader, since the set is created
2364 // against it) and reuse the existing set when nothing has changed.
2365 LocalVector<RID> rids;
2366 rids.push_back(shader_rd);
2367 for (const RD::Uniform &u : uniforms) {
2368 for (uint32_t i = 0; i < u.get_id_count(); i++) {
2369 rids.push_back(u.get_id(i));
23382370 }
2339 bindless_dirty = bindless_dirty || bindless_blocks[k]->needs_rebuild();
23402371 }
23412372
2342 if (bindless_ready && bindless_dirty) {
2343 Vector<RD::Uniform> bindless_uniforms;
2344 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2345 bindless_blocks[k]->collect_uniform(bindless_uniforms);
2373 bool unchanged = p_state->uniform_set.is_valid() &&
2374 RD::get_singleton()->uniform_set_is_valid(p_state->uniform_set) &&
2375 p_state->uniform_set_rids.size() == rids.size();
2376 if (unchanged) {
2377 for (uint32_t i = 0; i < rids.size(); i++) {
2378 if (p_state->uniform_set_rids[i] != rids[i]) {
2379 unchanged = false;
2380 break;
2381 }
23462382 }
2383 }
23472384
2348 if (bindless_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(bindless_uniform_set)) {
2349 RD::get_singleton()->free_rid(bindless_uniform_set);
2385 if (unchanged) {
2386 // Still bind the bindless set below, then hand back the cached set.
2387 if (bindless_blocks[0] && bindless_blocks[0]->is_initialized()) {
2388 _update_bindless_uniform_set(shader_rd);
23502389 }
2351 bindless_uniform_set = RD::get_singleton()->uniform_set_create(bindless_uniforms, shader_rd, 1);
2390 return p_state->uniform_set;
2391 }
23522392
2353 if (bindless_uniform_set.is_valid()) {
2354 RD::get_singleton()->set_resource_name(bindless_uniform_set, "Bindless Texture Set");
2355 for (uint32_t k = 0; k < BindlessBlock::TEXTURE_KIND_MAX; k++) {
2356 bindless_blocks[k]->mark_rebuilt();
2357 }
2358 } else {
2359 ERR_PRINT_ONCE("RT: failed to create the bindless texture uniform set.");
2360 }
2393 if (p_state->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_state->uniform_set)) {
2394 RD::get_singleton()->free_rid(p_state->uniform_set);
23612395 }
2396 p_state->uniform_set = RID();
2397 p_state->uniform_set_rids = rids;
2398
2399 p_state->uniform_set = RD::get_singleton()->uniform_set_create(
2400 uniforms,
2401 shader_rd,
2402 RenderForwardClustered::SCENE_UNIFORM_SET);
2403 RD::get_singleton()->set_resource_name(p_state->uniform_set, "RT Uniform Set");
2404
2405 // === SET 1: Bindless textures ===
2406 _update_bindless_uniform_set(shader_rd);
23622407 }
23632408
23642409 return p_state->uniform_set;
servers/rendering/renderer_rd/forward_clustered/render_raytracing.h +5 -0
……@@ -268,6 +268,10 @@ struct RTViewportState {
268268 RID params_buffer;
269269
270270 RID uniform_set;
271 // RIDs the live uniform_set was built from. The set is only rebuilt when one
272 // of them actually changes; buffers whose CONTENTS change (params, lights)
273 // keep the same RID and so need no new descriptor set.
274 LocalVector<RID> uniform_set_rids;
271275
272276 uint32_t frame_counter = 0;
273277};
……@@ -384,6 +388,7 @@ public:
384388
385389 void cleanup_caches();
386390
391 void _update_bindless_uniform_set(RID p_shader_rd);
387392 RTViewportState *build_tlas(const RenderDataRD *p_render_data, uint32_t p_rt_flags);
388393 uint32_t gather_lights(const RenderDataRD *p_render_data, RT_LightData *r_light_data, uint32_t p_max_lights);
389394 RID update_uniform_set(RTViewportState *p_state, const RenderDataRD *p_render_data, uint32_t p_rt_flags);