Remove unused material instances before rendering frame.

Also ensure material texture hashes are unique so that the material
cleanup works correctly.

PiperOrigin-RevId: 937206048
Change-Id: Ibed53457ee271f4faae3bcac5fb479b5ce9fc352
This commit is contained in:
Haroon Qureshi
2026-06-24 02:46:04 -07:00
committed by Copybara-Service
parent 29b49991a2
commit 3e33f93ddc
5 changed files with 32 additions and 8 deletions
+3 -3
View File
@@ -94,16 +94,17 @@ mjrfFrameHandle FilamentContext::Render(
ValidateSwapChains(requests); ValidateSwapChains(requests);
material_manager_->BeginFrame();
std::unordered_map<mjrfScene*, std::vector<const mjrfRenderRequest*>> std::unordered_map<mjrfScene*, std::vector<const mjrfRenderRequest*>>
scene_to_requests; scene_to_requests;
for (const mjrfRenderRequest& request : requests) { for (const mjrfRenderRequest& request : requests) {
scene_to_requests[request.scene].push_back(&request); scene_to_requests[request.scene].push_back(&request);
} }
material_manager_->PrepareToRender();
for (auto& [scene, requests] : scene_to_requests) { for (auto& [scene, requests] : scene_to_requests) {
SceneView::downcast(scene)->PrepareToRender(requests); SceneView::downcast(scene)->PrepareToRender(requests);
} }
material_manager_->RemoveUnusedMaterials();
bool render_began = false; bool render_began = false;
mjrfRenderTarget* current_target = nullptr; mjrfRenderTarget* current_target = nullptr;
@@ -159,7 +160,6 @@ mjrfFrameHandle FilamentContext::Render(
if (render_began) { if (render_began) {
renderer_->endFrame(); renderer_->endFrame();
material_manager_->EndFrame();
} }
if constexpr (!UTILS_HAS_THREADING) { if constexpr (!UTILS_HAS_THREADING) {
engine_->execute(); engine_->execute();
+18 -2
View File
@@ -38,6 +38,13 @@ static void Combine(uint64_t& seed, const T* v) {
seed ^= std::hash<T>()(*v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= std::hash<T>()(*v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
} }
static void Combine(uint64_t& seed, const mjrfTexture* texture) {
if (texture) {
const uint64_t id = Texture::downcast(texture)->Id();
Combine(seed, &id);
}
}
template <typename T> template <typename T>
static uint64_t hash(const T& obj) { static uint64_t hash(const T& obj) {
static_assert(std::is_trivially_copyable_v<T>, static_assert(std::is_trivially_copyable_v<T>,
@@ -77,9 +84,9 @@ MaterialManager::~MaterialManager() {
} }
} }
void MaterialManager::BeginFrame() { used_keys_.clear(); } void MaterialManager::PrepareToRender() { used_keys_.clear(); }
void MaterialManager::EndFrame() { void MaterialManager::RemoveUnusedMaterials() {
if (instances_.size() == used_keys_.size()) { if (instances_.size() == used_keys_.size()) {
return; return;
} }
@@ -102,6 +109,15 @@ static MaterialManager::MaterialKey BuildMaterialKey(
uint64_t key = hash(material); uint64_t key = hash(material);
Combine(key, &geom_type); Combine(key, &geom_type);
Combine(key, &material_type); Combine(key, &material_type);
Combine(key, material.color_texture);
Combine(key, material.opacity_texture);
Combine(key, material.normal_texture);
Combine(key, material.orm_texture);
Combine(key, material.metallic_texture);
Combine(key, material.roughness_texture);
Combine(key, material.occlusion_texture);
Combine(key, material.emissive_texture);
Combine(key, material.reflection_texture);
return key; return key;
} }
+2 -2
View File
@@ -52,10 +52,10 @@ class MaterialManager {
// Marks the beginning of a new frame, allowing us to track which // Marks the beginning of a new frame, allowing us to track which
// MaterialInstances are used during the frame so they can be removed at the // MaterialInstances are used during the frame so they can be removed at the
// end of the frame. // end of the frame.
void BeginFrame(); void PrepareToRender();
// Removes any unused MaterialInstances. // Removes any unused MaterialInstances.
void EndFrame(); void RemoveUnusedMaterials();
// Returns a MaterialType that best matches the given material data and mesh. // Returns a MaterialType that best matches the given material data and mesh.
MaterialType GetMaterialType(const mjrfMaterial& material, const Mesh* mesh); MaterialType GetMaterialType(const mjrfMaterial& material, const Mesh* mesh);
+4 -1
View File
@@ -14,6 +14,7 @@
#include "render/filament/core/texture.h" #include "render/filament/core/texture.h"
#include <atomic>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
@@ -28,6 +29,8 @@
namespace mujoco { namespace mujoco {
static std::atomic<uint64_t> g_next_texture_id{1};
static constexpr int kNumFacesPerCube = 6; static constexpr int kNumFacesPerCube = 6;
static bool IsCompressed(const mjrfTextureConfig& config) { static bool IsCompressed(const mjrfTextureConfig& config) {
@@ -115,7 +118,7 @@ static filament::Texture::InternalFormat GetTextureInternalFormat(
Texture::Texture(filament::Engine* engine, const mjrfTextureConfig& config, Texture::Texture(filament::Engine* engine, const mjrfTextureConfig& config,
InternalFlags flags) InternalFlags flags)
: engine_(engine), config_(config) { : id_(g_next_texture_id++), engine_(engine), config_(config) {
if (IsCompressed(config_)) { if (IsCompressed(config_)) {
// We defer creation of compressed textures until Upload() is called. In // We defer creation of compressed textures until Upload() is called. In
// the meantime, we don't really know anything about the texture (e.g. // the meantime, we don't really know anything about the texture (e.g.
+5
View File
@@ -15,6 +15,7 @@
#ifndef MUJOCO_SRC_RENDER_FILAMENT_CORE_TEXTURE_H_ #ifndef MUJOCO_SRC_RENDER_FILAMENT_CORE_TEXTURE_H_
#define MUJOCO_SRC_RENDER_FILAMENT_CORE_TEXTURE_H_ #define MUJOCO_SRC_RENDER_FILAMENT_CORE_TEXTURE_H_
#include <cstdint>
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/Texture.h> #include <filament/Texture.h>
#include <math/vec3.h> #include <math/vec3.h>
@@ -57,6 +58,9 @@ class Texture : public mjrfTexture {
// Returns the underlying filament texture. // Returns the underlying filament texture.
filament::Texture* GetFilamentTexture() const { return texture_; } filament::Texture* GetFilamentTexture() const { return texture_; }
// Returns the unique id of the texture.
uint64_t Id() const { return id_; }
// Returns any spherical harmonics data associated with the texture. // Returns any spherical harmonics data associated with the texture.
using SphericalHarmonics = filament::math::float3[9]; using SphericalHarmonics = filament::math::float3[9];
const SphericalHarmonics* GetSphericalHarmonics() const { const SphericalHarmonics* GetSphericalHarmonics() const {
@@ -73,6 +77,7 @@ class Texture : public mjrfTexture {
private: private:
void ReleaseData(); void ReleaseData();
uint64_t id_ = 0;
filament::Engine* engine_ = nullptr; filament::Engine* engine_ = nullptr;
filament::Texture* texture_ = nullptr; filament::Texture* texture_ = nullptr;
mjrfTextureConfig config_; mjrfTextureConfig config_;