EG/core/vr/performance/optimization.py
2025-10-20 17:01:45 +08:00

346 lines
14 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
VR对象池和优化系统
负责VR系统中的对象池管理、垃圾回收控制、分辨率缩放和性能模式控制。
"""
import gc
from panda3d.core import Mat4
class VROptimization:
"""VR优化系统 - 管理对象池、GC控制、分辨率缩放和性能模式"""
def __init__(self, vr_manager):
"""初始化VR优化系统
Args:
vr_manager: VR管理器实例引用
"""
self.vr_manager = vr_manager
# 对象池属性
self._matrix_pool = [] # Mat4对象池
self._matrix_pool_size = 8 # 池大小,足够处理多个控制器
self._cached_matrices = {} # 设备ID到矩阵的缓存
self._controller_poses_cache = {} # 控制器姿态缓存避免每帧clear()
# OpenVR Texture对象缓存 - 避免每帧创建openvr.Texture_t()
self._left_ovr_texture = None # 左眼纹理对象缓存
self._right_ovr_texture = None # 右眼纹理对象缓存
# Python垃圾回收控制
self._gc_control_enabled = True # 是否启用GC控制
self._gc_disabled = False # GC是否被禁用
self._manual_gc_interval = 900 # 每900帧手动触发一次GC (15秒@60fps) - 减少GC频率
self._last_manual_gc_frame = 0
# VR分辨率缩放优化
self.resolution_scale = 0.75 # 默认0.75倍分辨率,性能和质量平衡
self.base_eye_width = 1080 # 原始推荐分辨率
self.base_eye_height = 1200
self.scaled_eye_width = 1080 # 实际使用的缩放后分辨率
self.scaled_eye_height = 1200
# VR质量预设
self.quality_presets = {
'performance': 0.6, # 性能模式 - 约60%分辨率
'balanced': 0.75, # 平衡模式 - 约75%分辨率
'quality': 1.0 # 质量模式 - 100%分辨率
}
self.current_quality_preset = 'balanced' # 默认平衡模式
# 性能模式控制
self.performance_mode_enabled = False # 是否启用性能模式
self.performance_mode_trigger_frame = 600 # 600帧后自动启用性能模式
def _initialize_object_pools(self):
"""初始化对象池 - 修复16-19帧周期性GPU峰值"""
try:
# 预填充Mat4对象池
for _ in range(self._matrix_pool_size):
self._matrix_pool.append(Mat4())
print(f"✅ Mat4对象池初始化完成 - 池大小: {self._matrix_pool_size}")
# 🚀 预创建OpenVR Texture对象 - 消除每帧创建openvr.Texture_t()的开销
try:
import openvr
self._left_ovr_texture = openvr.Texture_t()
self._right_ovr_texture = openvr.Texture_t()
# 设置固定属性(这些不变)
self._left_ovr_texture.eType = openvr.TextureType_OpenGL
self._left_ovr_texture.eColorSpace = openvr.ColorSpace_Gamma
self._right_ovr_texture.eType = openvr.TextureType_OpenGL
self._right_ovr_texture.eColorSpace = openvr.ColorSpace_Gamma
print("✅ OpenVR Texture对象缓存已创建 - 避免每帧创建新对象")
except Exception as texture_error:
print(f"⚠️ OpenVR Texture对象创建失败: {texture_error}")
# 不影响整体初始化,但性能可能不是最优
# 启用GC控制
if self._gc_control_enabled:
# 禁用自动垃圾回收,改为手动控制
gc.disable()
self._gc_disabled = True
print("✅ Python垃圾回收已禁用改为手动控制")
except Exception as e:
print(f"⚠️ 对象池初始化失败: {e}")
def _get_pooled_matrix(self):
"""从对象池获取Mat4对象"""
if self._matrix_pool:
return self._matrix_pool.pop()
else:
# 池为空时创建新对象(不应该发生,但作为备用)
return Mat4()
def _return_pooled_matrix(self, matrix):
"""将Mat4对象返回对象池"""
if len(self._matrix_pool) < self._matrix_pool_size:
# 重置矩阵到单位矩阵
matrix.identMat()
self._matrix_pool.append(matrix)
def _manual_gc_control(self):
"""手动垃圾回收控制 - 避免VR渲染期间的GC峰值"""
if not self._gc_control_enabled or not self._gc_disabled:
return
# 🚀 智能GC间隔性能模式下减少GC频率
current_interval = self._manual_gc_interval
if self.performance_mode_enabled:
current_interval = self._manual_gc_interval * 2 # 性能模式下间隔翻倍
# 每N帧手动触发一次垃圾回收
if self.vr_manager.frame_count - self._last_manual_gc_frame >= current_interval:
# 在非渲染关键时刻触发GC
collected = gc.collect()
self._last_manual_gc_frame = self.vr_manager.frame_count
# 仅在收集到对象时输出信息
if collected > 0:
print(f"🗑️ 手动GC: 清理了 {collected} 个对象 (帧#{self.vr_manager.frame_count})")
def enable_gc_control(self):
"""启用垃圾回收控制 - 减少VR渲染期间的GC峰值"""
if not self._gc_control_enabled:
self._gc_control_enabled = True
if not self._gc_disabled:
gc.disable()
self._gc_disabled = True
print("✅ VR垃圾回收控制已启用")
else:
print(" VR垃圾回收控制已经启用")
def disable_gc_control(self):
"""禁用垃圾回收控制 - 恢复自动垃圾回收"""
if self._gc_control_enabled:
self._gc_control_enabled = False
if self._gc_disabled:
gc.enable()
self._gc_disabled = False
print("✅ VR垃圾回收控制已禁用恢复自动垃圾回收")
else:
print(" VR垃圾回收控制已经禁用")
def set_manual_gc_interval(self, frames):
"""设置手动垃圾回收间隔
Args:
frames: 帧数间隔 (建议100-600)
"""
if 50 <= frames <= 1800:
old_interval = self._manual_gc_interval
self._manual_gc_interval = frames
print(f"✅ 手动GC间隔: {old_interval}{frames}")
else:
print("⚠️ GC间隔应在50-1800帧之间")
def force_manual_gc(self):
"""强制执行一次垃圾回收"""
collected = gc.collect()
print(f"🗑️ 强制GC: 清理了 {collected} 个对象")
return collected
def get_object_pool_status(self):
"""获取对象池状态"""
return {
'matrix_pool_size': len(self._matrix_pool),
'matrix_pool_capacity': self._matrix_pool_size,
'cached_controllers': len(self.vr_manager.controller_poses),
'cached_matrices': len(self._cached_matrices),
}
# ====== VR分辨率缩放和质量预设系统 ======
def set_resolution_scale(self, scale):
"""设置VR分辨率缩放系数
Args:
scale: 缩放系数 (0.3-1.0)0.75表示75%分辨率
"""
if not (0.3 <= scale <= 1.0):
print(f"⚠️ 分辨率缩放系数应在0.3-1.0之间,当前: {scale}")
return False
old_scale = self.resolution_scale
self.resolution_scale = scale
# 如果VR已初始化重新创建缓冲区
if self.vr_manager.vr_initialized:
self._apply_resolution_scale()
print(f"✓ VR分辨率缩放: {old_scale}{scale}")
pixel_reduction = (1 - scale**2) * 100
print(f"📊 像素减少: {pixel_reduction:.1f}%")
return True
def set_quality_preset(self, preset_name):
"""设置VR质量预设
Args:
preset_name: 'performance', 'balanced', 'quality'
"""
if preset_name not in self.quality_presets:
print(f"⚠️ 未知的质量预设: {preset_name}")
print(f" 可用预设: {list(self.quality_presets.keys())}")
return False
old_preset = self.current_quality_preset
self.current_quality_preset = preset_name
scale = self.quality_presets[preset_name]
print(f"🎯 切换VR质量预设: {old_preset}{preset_name}")
return self.set_resolution_scale(scale)
def cycle_quality_preset(self):
"""循环切换质量预设"""
presets = list(self.quality_presets.keys())
current_index = presets.index(self.current_quality_preset)
next_index = (current_index + 1) % len(presets)
next_preset = presets[next_index]
return self.set_quality_preset(next_preset)
def _apply_resolution_scale(self):
"""应用分辨率缩放重新创建VR缓冲区"""
try:
# 计算新的分辨率
self.scaled_eye_width = int(self.base_eye_width * self.resolution_scale)
self.scaled_eye_height = int(self.base_eye_height * self.resolution_scale)
# 更新当前分辨率
self.vr_manager.eye_width = self.scaled_eye_width
self.vr_manager.eye_height = self.scaled_eye_height
if hasattr(self.vr_manager, 'current_eye_resolution'):
self.vr_manager.current_eye_resolution = (self.vr_manager.eye_width, self.vr_manager.eye_height)
print(f"🔄 重新创建VR缓冲区...")
print(f" 新分辨率: {self.vr_manager.eye_width}x{self.vr_manager.eye_height}")
# 清理旧的缓冲区
self.vr_manager._cleanup_vr_buffers()
# 🔧 关键修复:根据渲染模式选择创建方法
success = False
if self.vr_manager.vr_render_mode.name == "RENDER_PIPELINE":
print(f" 使用RenderPipeline模式重建...")
success = self.vr_manager._create_vr_buffers_with_pipeline()
if not success:
print("⚠️ RenderPipeline模式创建失败回退到普通渲染模式")
self.vr_manager.vr_render_mode = self.vr_manager.VRRenderMode.NORMAL
success = self.vr_manager._create_vr_buffers()
else:
print(f" 使用普通模式重建...")
success = self.vr_manager._create_vr_buffers()
if success:
# 重新设置相机
self.vr_manager._setup_vr_cameras()
print("✅ VR缓冲区重新创建成功")
return True
else:
print("❌ VR缓冲区重新创建失败")
return False
except Exception as e:
print(f"❌ 应用分辨率缩放失败: {e}")
import traceback
traceback.print_exc()
return False
def get_resolution_info(self):
"""获取分辨率相关信息"""
return {
'base_resolution': (self.base_eye_width, self.base_eye_height),
'current_resolution': (self.vr_manager.eye_width, self.vr_manager.eye_height),
'resolution_scale': self.resolution_scale,
'current_preset': self.current_quality_preset,
'available_presets': self.quality_presets,
'pixel_reduction_percent': (1 - self.resolution_scale**2) * 100
}
def print_resolution_info(self):
"""输出分辨率信息"""
info = self.get_resolution_info()
print("🔧 ===== VR分辨率信息 =====")
print(f" 推荐分辨率: {info['base_resolution'][0]}x{info['base_resolution'][1]}")
print(f" 当前分辨率: {info['current_resolution'][0]}x{info['current_resolution'][1]}")
print(f" 缩放系数: {info['resolution_scale']}")
print(f" 当前预设: {info['current_preset']}")
print(f" 像素减少: {info['pixel_reduction_percent']:.1f}%")
print(" 可用预设:")
for name, scale in info['available_presets'].items():
marker = "" if name == info['current_preset'] else " "
print(f" {marker} {name}: {scale} ({scale*100:.0f}%)")
print("==========================")
# ====== 性能模式控制方法 ======
def enable_performance_mode(self):
"""手动启用性能模式 - 立即禁用详细监控以提升性能"""
if not self.performance_mode_enabled:
self.performance_mode_enabled = True
print("🎯 性能模式已手动启用 - 禁用详细监控以提升性能")
print(" 现在将减少每帧对象创建显著提升VR性能稳定性")
else:
print(" 性能模式已经启用")
def disable_performance_mode(self):
"""禁用性能模式 - 重新启用详细监控(用于调试)"""
if self.performance_mode_enabled:
self.performance_mode_enabled = False
print("🔍 性能模式已禁用 - 重新启用详细监控")
print(" 注意这将增加每帧对象创建可能影响VR性能")
else:
print(" 性能模式已经禁用")
def set_performance_mode_trigger_frame(self, frame_count):
"""设置性能模式自动触发的帧数
Args:
frame_count: 触发帧数 (建议300-1200)
"""
if 100 <= frame_count <= 3600:
old_trigger = self.performance_mode_trigger_frame
self.performance_mode_trigger_frame = frame_count
print(f"✅ 性能模式触发帧数: {old_trigger}{frame_count}")
else:
print("⚠️ 触发帧数应在100-3600之间")
def get_performance_mode_status(self):
"""获取性能模式状态"""
return {
'performance_mode_enabled': self.performance_mode_enabled,
'trigger_frame': self.performance_mode_trigger_frame,
'current_frame': self.vr_manager.frame_count,
'will_trigger_at_frame': self.performance_mode_trigger_frame if not self.performance_mode_enabled else None,
'gc_interval_normal': self._manual_gc_interval,
'gc_interval_performance': self._manual_gc_interval * 2,
}