Просмотр исходного кода

Added hooks for detailed performance profiling.
Implementors can provide their own AppProfiler
implementation to collect and/or visualize timing
stats however they want, even at the viewport level
if they choose.
A basic profiler implementation will be following
shortly that does simple update vs render frame
timings.

pspeed42 11 лет назад
Родитель
Сommit
a517130528

+ 31 - 0
jme3-core/src/main/java/com/jme3/app/Application.java

@@ -38,6 +38,8 @@ import com.jme3.audio.AudioRenderer;
 import com.jme3.audio.Listener;
 import com.jme3.input.*;
 import com.jme3.math.Vector3f;
+import com.jme3.profile.AppProfiler;
+import com.jme3.profile.AppStep;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.RenderManager;
 import com.jme3.renderer.Renderer;
@@ -91,6 +93,8 @@ public class Application implements SystemListener {
     protected InputManager inputManager;
     protected AppStateManager stateManager;
 
+    protected AppProfiler prof;
+
     private final ConcurrentLinkedQueue<AppTask<?>> taskQueue = new ConcurrentLinkedQueue<AppTask<?>>();
 
     /**
@@ -250,6 +254,11 @@ public class Application implements SystemListener {
         renderManager = new RenderManager(renderer);
         //Remy - 09/14/2010 setted the timer in the renderManager
         renderManager.setTimer(timer);
+        
+        if (prof != null) {
+            renderManager.setAppProfiler(prof);
+        }
+        
         viewPort = renderManager.createMainView("Default", cam);
         viewPort.setClearFlags(true, true, true);
 
@@ -387,6 +396,25 @@ public class Application implements SystemListener {
         context.create(false);
     }
 
+    /**
+     * Sets an AppProfiler hook that will be called back for
+     * specific steps within a single update frame.  Value defaults
+     * to null.
+     */
+    public void setAppProfiler(AppProfiler prof) {
+        this.prof = prof;
+        if (renderManager != null) {
+            renderManager.setAppProfiler(prof);
+        }
+    }
+ 
+    /**
+     * Returns the current AppProfiler hook, or null if none is set.
+     */   
+    public AppProfiler getAppProfiler() {
+        return prof;
+    }
+
     /**
      * Initializes the application's canvas for use.
      * <p>
@@ -595,6 +623,7 @@ public class Application implements SystemListener {
         // Make sure the audio renderer is available to callables
         AudioContext.setAudioRenderer(audioRenderer);
 
+        if (prof!=null) prof.appStep(AppStep.QueuedTasks);
         runQueuedTasks();
 
         if (speed == 0 || paused)
@@ -603,10 +632,12 @@ public class Application implements SystemListener {
         timer.update();
 
         if (inputEnabled){
+            if (prof!=null) prof.appStep(AppStep.ProcessInput);
             inputManager.update(timer.getTimePerFrame());
         }
 
         if (audioRenderer != null){
+            if (prof!=null) prof.appStep(AppStep.ProcessAudio);
             audioRenderer.update(timer.getTimePerFrame());
         }
 

+ 13 - 3
jme3-core/src/main/java/com/jme3/app/SimpleApplication.java

@@ -38,6 +38,7 @@ import com.jme3.input.FlyByCamera;
 import com.jme3.input.KeyInput;
 import com.jme3.input.controls.ActionListener;
 import com.jme3.input.controls.KeyTrigger;
+import com.jme3.profile.AppStep;
 import com.jme3.renderer.RenderManager;
 import com.jme3.renderer.queue.RenderQueue.Bucket;
 import com.jme3.scene.Node;
@@ -228,30 +229,39 @@ public abstract class SimpleApplication extends Application {
 
     @Override
     public void update() {
+        if (prof!=null) prof.appStep(AppStep.BeginFrame);
+        
         super.update(); // makes sure to execute AppTasks
         if (speed == 0 || paused) {
             return;
         }
 
         float tpf = timer.getTimePerFrame() * speed;
-
+        
         // update states
+        if (prof!=null) prof.appStep(AppStep.StateManagerUpdate);
         stateManager.update(tpf);
 
         // simple update and root node
         simpleUpdate(tpf);
  
+        if (prof!=null) prof.appStep(AppStep.SpatialUpdate);
         rootNode.updateLogicalState(tpf);
         guiNode.updateLogicalState(tpf);
         
         rootNode.updateGeometricState();
         guiNode.updateGeometricState();
-
+        
         // render states
+        if (prof!=null) prof.appStep(AppStep.StateManagerRender);
         stateManager.render(renderManager);
+        
+        if (prof!=null) prof.appStep(AppStep.RenderFrame);
         renderManager.render(tpf, context.isRenderable());
         simpleRender(renderManager);
-        stateManager.postRender();        
+        stateManager.postRender();
+                
+        if (prof!=null) prof.appStep(AppStep.EndFrame);
     }
 
     public void setDisplayFps(boolean show) {

+ 32 - 0
jme3-core/src/main/java/com/jme3/renderer/RenderManager.java

@@ -37,6 +37,9 @@ import com.jme3.material.RenderState;
 import com.jme3.material.Technique;
 import com.jme3.math.*;
 import com.jme3.post.SceneProcessor;
+import com.jme3.profile.AppProfiler;
+import com.jme3.profile.AppStep;
+import com.jme3.profile.VpStep;
 import com.jme3.renderer.queue.GeometryList;
 import com.jme3.renderer.queue.RenderQueue;
 import com.jme3.renderer.queue.RenderQueue.Bucket;
@@ -80,6 +83,7 @@ public class RenderManager {
     private Matrix4f orthoMatrix = new Matrix4f();
     private String tmpTech;
     private boolean handleTranlucentBucket = true;
+    private AppProfiler prof;
 
     /**
      * Create a high-level rendering interface over the
@@ -377,6 +381,15 @@ public class RenderManager {
         uniformBindingManager.setTimer(timer);
     }
 
+    /**
+     * Sets an AppProfiler hook that will be called back for
+     * specific steps within a single update frame.  Value defaults
+     * to null.
+     */
+    public void setAppProfiler(AppProfiler prof) {
+        this.prof = prof;
+    }
+
     /**
      * Returns the forced technique name set.
      * 
@@ -779,10 +792,12 @@ public class RenderManager {
 
         // render opaque objects with default depth range
         // opaque objects are sorted front-to-back, reducing overdraw
+        if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Opaque);
         rq.renderQueue(Bucket.Opaque, this, cam, flush);
 
         // render the sky, with depth range set to the farthest
         if (!rq.isQueueEmpty(Bucket.Sky)) {
+            if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Sky);
             renderer.setDepthRange(1, 1);
             rq.renderQueue(Bucket.Sky, this, cam, flush);
             depthRangeChanged = true;
@@ -793,6 +808,7 @@ public class RenderManager {
         // rest of the scene's objects. Consequently, they are sorted
         // back-to-front.
         if (!rq.isQueueEmpty(Bucket.Transparent)) {
+            if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Transparent);
             if (depthRangeChanged) {
                 renderer.setDepthRange(0, 1);
                 depthRangeChanged = false;
@@ -802,6 +818,7 @@ public class RenderManager {
         }
 
         if (!rq.isQueueEmpty(Bucket.Gui)) {
+            if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Gui);
             renderer.setDepthRange(0, 0);
             setCamera(cam, true);
             rq.renderQueue(Bucket.Gui, this, cam, flush);
@@ -828,6 +845,8 @@ public class RenderManager {
      * @see #setHandleTranslucentBucket(boolean) 
      */
     public void renderTranslucentQueue(ViewPort vp) {
+        if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Translucent);
+        
         RenderQueue rq = vp.getQueue();
         if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
             rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
@@ -963,6 +982,8 @@ public class RenderManager {
         if (!vp.isEnabled()) {
             return;
         }
+        if (prof!=null) prof.vpStep(VpStep.BeginRender, vp, null);
+                
         SafeArrayList<SceneProcessor> processors = vp.getProcessors();
         if (processors.isEmpty()) {
             processors = null;
@@ -988,20 +1009,24 @@ public class RenderManager {
                     vp.isClearStencil());
         }
 
+        if (prof!=null) prof.vpStep(VpStep.RenderScene, vp, null);
         List<Spatial> scenes = vp.getScenes();
         for (int i = scenes.size() - 1; i >= 0; i--) {            
             renderScene(scenes.get(i), vp);
         }
 
         if (processors != null) {
+            if (prof!=null) prof.vpStep(VpStep.PostQueue, vp, null);
             for (SceneProcessor proc : processors.getArray()) {
                 proc.postQueue(vp.getQueue());
             }
         }
 
+        if (prof!=null) prof.vpStep(VpStep.FlushQueue, vp, null);
         flushQueue(vp);
 
         if (processors != null) {
+            if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
             for (SceneProcessor proc : processors.getArray()) {
                 proc.postFrame(vp.getOutputFrameBuffer());
             }
@@ -1010,6 +1035,8 @@ public class RenderManager {
         renderTranslucentQueue(vp);
         // clear any remaining spatials that were not rendered.
         clearQueue(vp);
+        
+        if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
     }
 
     public void setUsingShaders(boolean usingShaders) { 
@@ -1037,18 +1064,23 @@ public class RenderManager {
         this.shader = renderer.getCaps().contains(Caps.GLSL100);
         uniformBindingManager.newFrame();        
 
+        if (prof!=null) prof.appStep(AppStep.RenderPreviewViewPorts);        
         for (int i = 0; i < preViewPorts.size(); i++) {
             ViewPort vp = preViewPorts.get(i);
             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
                 renderViewPort(vp, tpf);
             }
         }
+        
+        if (prof!=null) prof.appStep(AppStep.RenderMainViewPorts);
         for (int i = 0; i < viewPorts.size(); i++) {
             ViewPort vp = viewPorts.get(i);
             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
                 renderViewPort(vp, tpf);
             }
         }
+        
+        if (prof!=null) prof.appStep(AppStep.RenderPostViewPorts);
         for (int i = 0; i < postViewPorts.size(); i++) {
             ViewPort vp = postViewPorts.get(i);
             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {