| … | … | @@ -2025,13 +2025,53 @@ uint32_t RenderRaytracing::gather_lights(const RenderDataRD *p_render_data, RT_L |
| 2025 | 2025 | // Uniform set update |
| 2026 | 2026 | // --------------------------------------------------------------------------- |
| 2027 | 2027 | |
| 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. |
| 2032 | void 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 | |
| 2028 | 2065 | RID RenderRaytracing::update_uniform_set(RTViewportState *p_state, const RenderDataRD *p_render_data, uint32_t p_rt_flags) { |
| 2029 | 2066 | ERR_FAIL_NULL_V(p_state, RID()); |
| 2030 | 2067 | |
| 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. |
| 2035 | 2075 | |
| 2036 | 2076 | // BindlessBlock handles its own uniform set cleanup via clear() |
| 2037 | 2077 | |
| … | … | @@ -2320,45 +2360,50 @@ RID RenderRaytracing::update_uniform_set(RTViewportState *p_state, const RenderD |
| 2320 | 2360 | RID shader_rd = shader ? shader->get_pipeline_shader_rd(p_rt_flags) : RID(); |
| 2321 | 2361 | |
| 2322 | 2362 | 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)); |
| 2338 | 2370 | } |
| 2339 | | bindless_dirty = bindless_dirty || bindless_blocks[k]->needs_rebuild(); |
| 2340 | 2371 | } |
| 2341 | 2372 | |
| 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 | } |
| 2346 | 2382 | } |
| 2383 | } |
| 2347 | 2384 | |
| 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); |
| 2350 | 2389 | } |
| 2351 | | bindless_uniform_set = RD::get_singleton()->uniform_set_create(bindless_uniforms, shader_rd, 1); |
| 2390 | return p_state->uniform_set; |
| 2391 | } |
| 2352 | 2392 | |
| 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); |
| 2361 | 2395 | } |
| 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); |
| 2362 | 2407 | } |
| 2363 | 2408 | |
| 2364 | 2409 | return p_state->uniform_set; |