346 lines
14 KiB
Python
346 lines
14 KiB
Python
"""
|
||
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,
|
||
} |