From 76ca736824aed724a54aa561a34d42f23879ddae Mon Sep 17 00:00:00 2001 From: Rowland <975945824@qq.com> Date: Wed, 24 Sep 2025 14:20:26 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=AE=8C=E8=B0=83=E8=AF=95=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QPanda3D/Panda3DWorld.py | 6 +- core/vr_manager.py | 203 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 204 insertions(+), 5 deletions(-) diff --git a/QPanda3D/Panda3DWorld.py b/QPanda3D/Panda3DWorld.py index 78193075..1afffc65 100644 --- a/QPanda3D/Panda3DWorld.py +++ b/QPanda3D/Panda3DWorld.py @@ -79,8 +79,8 @@ class Panda3DWorld(ShowBase): ShowBase.__init__(self) # 初始化渲染管线并设置可调整大小的标志 - self.render_pipeline.create(self) - _global_render_pipeline = self.render_pipeline + # self.render_pipeline.create(self) + # _global_render_pipeline = self.render_pipeline # 创建 Qt 能读的 RGBA8 贴图 self.qt_output_tex = Texture("qt_output_tex") @@ -138,7 +138,7 @@ class Panda3DWorld(ShowBase): #self.cam = self.render_pipeline._showbase.cam #self.camNode = self.cam.node() #self.camLens = self.camNode.get_lens() - self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam + # self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam #self.render_pipeline.daytime_mgr.update() diff --git a/core/vr_manager.py b/core/vr_manager.py index 8ab68ae9..74762612 100644 --- a/core/vr_manager.py +++ b/core/vr_manager.py @@ -119,6 +119,18 @@ class VRManager(DirectObject): self.sync_wait_times = [] self.pipeline_history_size = 30 + # GPU渲染时间监控(OpenVR Frame Timing) + self.enable_gpu_timing = True # 是否启用GPU时间监控 + self.gpu_scene_render_ms = 0.0 # GPU场景渲染时间 + self.gpu_pre_submit_ms = 0.0 # 提交前GPU时间 + self.gpu_post_submit_ms = 0.0 # 提交后GPU时间 + self.gpu_total_render_ms = 0.0 # GPU总渲染时间 + self.gpu_compositor_render_ms = 0.0 # GPU合成器渲染时间 + self.gpu_client_frame_interval_ms = 0.0 # 客户端帧间隔 + self.gpu_timing_history = [] # GPU时间历史记录 + self.gpu_timing_history_size = 30 # GPU时间历史记录大小 + self.gpu_timing_failure_count = 0 # GPU时间获取失败次数 + # VR系统信息 self.current_eye_resolution = (self.eye_width, self.eye_height) self.recommended_eye_resolution = (0, 0) @@ -530,6 +542,10 @@ class VRManager(DirectObject): # 更新系统性能指标 self._update_performance_metrics() + # 更新GPU渲染时间统计 + if self.enable_gpu_timing: + self._get_gpu_frame_timing() + # VR更新策略选择 if self.pose_strategy == 'update_task': # 🚀 新的Running Start策略:WaitGetPoses在Submit后调用,此处只更新相机 @@ -1190,6 +1206,64 @@ class VRManager(DirectObject): print(f" GPU监控: 不可用 (需要安装 GPUtil 或 pynvml)") print(f" 安装命令: pip install GPUtil nvidia-ml-py") + # GPU渲染时间(OpenVR Frame Timing) + if self.enable_gpu_timing: + print(f"⚡ GPU渲染时间:") + pipeline_stats = self._get_pipeline_stats() + gpu_stats = pipeline_stats.get('gpu_timing', {}) + gpu_current = pipeline_stats.get('current', {}) + + # 检查是否有可用的GPU时间数据 + has_gpu_data = any( + gpu_current.get(field, 0) > 0 + for field in ['gpu_scene_render', 'gpu_total_render', 'gpu_pre_submit', 'gpu_post_submit', 'gpu_compositor_render'] + ) + + if has_gpu_data: + # 显示GPU时间统计(最近30帧平均) + scene_render = gpu_stats.get('scene_render', {'avg': 0}) + total_render = gpu_stats.get('total_render', {'avg': 0}) + pre_submit = gpu_stats.get('pre_submit', {'avg': 0}) + post_submit = gpu_stats.get('post_submit', {'avg': 0}) + compositor = gpu_stats.get('compositor_render', {'avg': 0}) + + if scene_render['avg'] > 0: + print(f" GPU场景渲染: {scene_render['avg']:.2f}ms (min:{scene_render['min']:.1f}, max:{scene_render['max']:.1f})") + if total_render['avg'] > 0: + print(f" GPU总渲染时间: {total_render['avg']:.2f}ms (min:{total_render['min']:.1f}, max:{total_render['max']:.1f})") + if pre_submit['avg'] > 0: + print(f" GPU提交前时间: {pre_submit['avg']:.2f}ms (min:{pre_submit['min']:.1f}, max:{pre_submit['max']:.1f})") + if post_submit['avg'] > 0: + print(f" GPU提交后时间: {post_submit['avg']:.2f}ms (min:{post_submit['min']:.1f}, max:{post_submit['max']:.1f})") + if compositor['avg'] > 0: + print(f" GPU合成器时间: {compositor['avg']:.2f}ms (min:{compositor['min']:.1f}, max:{compositor['max']:.1f})") + + # 显示当前帧GPU时间 + print(f"🔍 当前帧GPU时间:") + if gpu_current.get('gpu_scene_render', 0) > 0: + print(f" 场景渲染: {gpu_current['gpu_scene_render']:.2f}ms") + if gpu_current.get('gpu_total_render', 0) > 0: + print(f" 总渲染: {gpu_current['gpu_total_render']:.2f}ms") + if gpu_current.get('gpu_compositor_render', 0) > 0: + print(f" 合成器: {gpu_current['gpu_compositor_render']:.2f}ms") + + # GPU时间瓶颈分析 + current_total = gpu_current.get('gpu_total_render', 0) + current_scene = gpu_current.get('gpu_scene_render', 0) + if current_total > 12.0: # 假设72fps目标,留出一些余量 + print(f" ⚠️ GPU总渲染时间过长: {current_total:.1f}ms") + elif current_scene > 8.0: + print(f" ⚠️ GPU场景渲染时间偏高: {current_scene:.1f}ms") + + else: + print(f" GPU渲染时间: 暂无数据") + if self.gpu_timing_failure_count > 0: + print(f" 获取失败次数: {self.gpu_timing_failure_count}") + else: + print(f" 等待OpenVR Frame Timing数据...") + else: + print(f"⚡ GPU渲染时间: 已禁用") + # VR特定指标 print(f"🥽 VR指标:") print(f" 总帧数: {stats['frame_count']}") @@ -1306,6 +1380,17 @@ class VRManager(DirectObject): if stats['gpu_memory_usage'] > 90: recommendations.append(" 🔴 显存使用率过高,可能需要降低纹理质量") + # GPU渲染时间建议 + if self.enable_gpu_timing: + if self.gpu_total_render_ms > 12.0: + recommendations.append(" ⚠️ GPU总渲染时间过长,建议优化场景复杂度") + if self.gpu_scene_render_ms > 8.0: + recommendations.append(" ⚠️ GPU场景渲染时间偏高,考虑降低渲染质量") + if self.gpu_compositor_render_ms > 3.0: + recommendations.append(" ⚠️ GPU合成器时间过长,检查VR设置或叠加层") + if self.gpu_timing_failure_count > 100: + recommendations.append(" ⚠️ GPU时间统计频繁失败,可能需要更新OpenVR") + # 失败率建议 submit_fail_rate = (stats['submit_failures'] / max(stats['frame_count'], 1)) * 100 if submit_fail_rate > 1: @@ -1357,6 +1442,17 @@ class VRManager(DirectObject): elif current['total_render'] > 0: summary += f" | 渲染: {current['total_render']:.1f}ms" + # 添加GPU渲染时间信息 + if self.enable_gpu_timing: + gpu_total = current.get('gpu_total_render', 0) + gpu_scene = current.get('gpu_scene_render', 0) + if gpu_total > 12.0: + summary += f" | GPU: {gpu_total:.1f}ms⚠️" + elif gpu_total > 0: + summary += f" | GPU: {gpu_total:.1f}ms" + elif gpu_scene > 0: + summary += f" | GPU场景: {gpu_scene:.1f}ms" + # 显示目标帧时间对比 vr_info = pipeline_stats['vr_info'] if vr_info['target_frame_time_ms'] > 0: @@ -1979,18 +2075,41 @@ class VRManager(DirectObject): 'max': max(times_list) } + # 计算GPU时间统计 + def get_gpu_field_stats(field_name): + """从GPU时间历史记录中提取特定字段的统计信息""" + values = [] + for gpu_data in self.gpu_timing_history: + if field_name in gpu_data: + values.append(gpu_data[field_name]) + return get_stats(values) + return { 'wait_poses': get_stats(self.wait_poses_times), 'render': get_stats(self.render_times), 'submit': get_stats(self.submit_times), 'sync_wait': get_stats(self.sync_wait_times), + 'gpu_timing': { + 'scene_render': get_gpu_field_stats('scene_render'), + 'pre_submit': get_gpu_field_stats('pre_submit'), + 'post_submit': get_gpu_field_stats('post_submit'), + 'total_render': get_gpu_field_stats('total_render'), + 'compositor_render': get_gpu_field_stats('compositor_render'), + 'frame_interval': get_gpu_field_stats('frame_interval') + }, 'current': { 'wait_poses': self.wait_poses_time, 'left_render': self.left_render_time, 'right_render': self.right_render_time, 'submit': self.submit_time, 'sync_wait': self.vr_sync_wait_time, - 'total_render': self.left_render_time + self.right_render_time + 'total_render': self.left_render_time + self.right_render_time, + 'gpu_scene_render': self.gpu_scene_render_ms, + 'gpu_pre_submit': self.gpu_pre_submit_ms, + 'gpu_post_submit': self.gpu_post_submit_ms, + 'gpu_total_render': self.gpu_total_render_ms, + 'gpu_compositor_render': self.gpu_compositor_render_ms, + 'gpu_frame_interval': self.gpu_client_frame_interval_ms }, 'vr_info': { 'eye_resolution': self.current_eye_resolution, @@ -2001,7 +2120,9 @@ class VRManager(DirectObject): 'vsync_to_photons_ms': self.vsync_to_photons_ms, 'vsync_window_ms': self.vsync_window_ms, 'async_reprojection': self.async_reprojection_enabled, - 'motion_smoothing': self.motion_smoothing_enabled + 'motion_smoothing': self.motion_smoothing_enabled, + 'gpu_timing_enabled': self.enable_gpu_timing, + 'gpu_timing_failures': self.gpu_timing_failure_count } } @@ -2130,6 +2251,84 @@ class VRManager(DirectObject): except Exception as e: print(f"⚠️ NVIDIA-ML初始化失败: {e}") + def _get_gpu_frame_timing(self, frames_ago=0): + """获取GPU渲染时间统计 + + Args: + frames_ago: 获取多少帧之前的数据,0表示当前帧 + + Returns: + dict: GPU时间数据,如果获取失败返回None + """ + if not self.enable_gpu_timing or not self.vr_compositor: + return None + + try: + # 调用OpenVR的getFrameTiming API + result, timing = self.vr_compositor.getFrameTiming(framesAgo=frames_ago) + + if not result: + self.gpu_timing_failure_count += 1 + if self.gpu_timing_failure_count % 300 == 1: # 每5秒输出一次错误 + print("⚠️ OpenVR getFrameTiming调用失败") + return None + + # 提取GPU时间数据(单位:毫秒) + gpu_data = {} + + # 检查timing对象是否有GPU时间相关的属性 + if hasattr(timing, 'm_flSceneRenderGpuMs'): + gpu_data['scene_render'] = timing.m_flSceneRenderGpuMs + self.gpu_scene_render_ms = timing.m_flSceneRenderGpuMs + + if hasattr(timing, 'm_flPreSubmitGpuMs'): + gpu_data['pre_submit'] = timing.m_flPreSubmitGpuMs + self.gpu_pre_submit_ms = timing.m_flPreSubmitGpuMs + + if hasattr(timing, 'm_flPostSubmitGpuMs'): + gpu_data['post_submit'] = timing.m_flPostSubmitGpuMs + self.gpu_post_submit_ms = timing.m_flPostSubmitGpuMs + + if hasattr(timing, 'm_flTotalRenderGpuMs'): + gpu_data['total_render'] = timing.m_flTotalRenderGpuMs + self.gpu_total_render_ms = timing.m_flTotalRenderGpuMs + + if hasattr(timing, 'm_flCompositorRenderGpuMs'): + gpu_data['compositor_render'] = timing.m_flCompositorRenderGpuMs + self.gpu_compositor_render_ms = timing.m_flCompositorRenderGpuMs + + if hasattr(timing, 'm_flClientFrameIntervalMs'): + gpu_data['frame_interval'] = timing.m_flClientFrameIntervalMs + self.gpu_client_frame_interval_ms = timing.m_flClientFrameIntervalMs + + # 将GPU时间数据添加到历史记录 + if gpu_data: + self.gpu_timing_history.append(gpu_data) + if len(self.gpu_timing_history) > self.gpu_timing_history_size: + self.gpu_timing_history.pop(0) + + # 调试信息 - 仅在第一次成功时输出 + if not hasattr(self, '_gpu_timing_success_logged'): + available_fields = list(gpu_data.keys()) + print(f"✅ GPU时间统计已启用 - 可用字段: {available_fields}") + self._gpu_timing_success_logged = True + + return gpu_data + + except AttributeError as e: + # OpenVR Python绑定可能不包含某些字段 + if self.gpu_timing_failure_count == 0: + print(f"⚠️ GPU时间统计部分功能不可用: {e}") + print(" 这可能是由于OpenVR Python绑定版本问题") + self.gpu_timing_failure_count += 1 + return None + + except Exception as e: + self.gpu_timing_failure_count += 1 + if self.gpu_timing_failure_count % 300 == 1: # 每5秒输出一次错误 + print(f"⚠️ 获取GPU时间统计失败: {e}") + return None + def _update_performance_metrics(self): """更新系统性能指标""" if not self.performance_monitoring: