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.
This commit is contained in:
parent
3d32b012c2
commit
a517130528
@ -38,6 +38,8 @@ import com.jme3.audio.AudioRenderer;
|
|||||||
import com.jme3.audio.Listener;
|
import com.jme3.audio.Listener;
|
||||||
import com.jme3.input.*;
|
import com.jme3.input.*;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.profile.AppProfiler;
|
||||||
|
import com.jme3.profile.AppStep;
|
||||||
import com.jme3.renderer.Camera;
|
import com.jme3.renderer.Camera;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.Renderer;
|
import com.jme3.renderer.Renderer;
|
||||||
@ -91,6 +93,8 @@ public class Application implements SystemListener {
|
|||||||
protected InputManager inputManager;
|
protected InputManager inputManager;
|
||||||
protected AppStateManager stateManager;
|
protected AppStateManager stateManager;
|
||||||
|
|
||||||
|
protected AppProfiler prof;
|
||||||
|
|
||||||
private final ConcurrentLinkedQueue<AppTask<?>> taskQueue = new ConcurrentLinkedQueue<AppTask<?>>();
|
private final ConcurrentLinkedQueue<AppTask<?>> taskQueue = new ConcurrentLinkedQueue<AppTask<?>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,6 +254,11 @@ public class Application implements SystemListener {
|
|||||||
renderManager = new RenderManager(renderer);
|
renderManager = new RenderManager(renderer);
|
||||||
//Remy - 09/14/2010 setted the timer in the renderManager
|
//Remy - 09/14/2010 setted the timer in the renderManager
|
||||||
renderManager.setTimer(timer);
|
renderManager.setTimer(timer);
|
||||||
|
|
||||||
|
if (prof != null) {
|
||||||
|
renderManager.setAppProfiler(prof);
|
||||||
|
}
|
||||||
|
|
||||||
viewPort = renderManager.createMainView("Default", cam);
|
viewPort = renderManager.createMainView("Default", cam);
|
||||||
viewPort.setClearFlags(true, true, true);
|
viewPort.setClearFlags(true, true, true);
|
||||||
|
|
||||||
@ -387,6 +396,25 @@ public class Application implements SystemListener {
|
|||||||
context.create(false);
|
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.
|
* Initializes the application's canvas for use.
|
||||||
* <p>
|
* <p>
|
||||||
@ -595,6 +623,7 @@ public class Application implements SystemListener {
|
|||||||
// Make sure the audio renderer is available to callables
|
// Make sure the audio renderer is available to callables
|
||||||
AudioContext.setAudioRenderer(audioRenderer);
|
AudioContext.setAudioRenderer(audioRenderer);
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.QueuedTasks);
|
||||||
runQueuedTasks();
|
runQueuedTasks();
|
||||||
|
|
||||||
if (speed == 0 || paused)
|
if (speed == 0 || paused)
|
||||||
@ -603,10 +632,12 @@ public class Application implements SystemListener {
|
|||||||
timer.update();
|
timer.update();
|
||||||
|
|
||||||
if (inputEnabled){
|
if (inputEnabled){
|
||||||
|
if (prof!=null) prof.appStep(AppStep.ProcessInput);
|
||||||
inputManager.update(timer.getTimePerFrame());
|
inputManager.update(timer.getTimePerFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioRenderer != null){
|
if (audioRenderer != null){
|
||||||
|
if (prof!=null) prof.appStep(AppStep.ProcessAudio);
|
||||||
audioRenderer.update(timer.getTimePerFrame());
|
audioRenderer.update(timer.getTimePerFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import com.jme3.input.FlyByCamera;
|
|||||||
import com.jme3.input.KeyInput;
|
import com.jme3.input.KeyInput;
|
||||||
import com.jme3.input.controls.ActionListener;
|
import com.jme3.input.controls.ActionListener;
|
||||||
import com.jme3.input.controls.KeyTrigger;
|
import com.jme3.input.controls.KeyTrigger;
|
||||||
|
import com.jme3.profile.AppStep;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
@ -228,6 +229,8 @@ public abstract class SimpleApplication extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
|
if (prof!=null) prof.appStep(AppStep.BeginFrame);
|
||||||
|
|
||||||
super.update(); // makes sure to execute AppTasks
|
super.update(); // makes sure to execute AppTasks
|
||||||
if (speed == 0 || paused) {
|
if (speed == 0 || paused) {
|
||||||
return;
|
return;
|
||||||
@ -236,11 +239,13 @@ public abstract class SimpleApplication extends Application {
|
|||||||
float tpf = timer.getTimePerFrame() * speed;
|
float tpf = timer.getTimePerFrame() * speed;
|
||||||
|
|
||||||
// update states
|
// update states
|
||||||
|
if (prof!=null) prof.appStep(AppStep.StateManagerUpdate);
|
||||||
stateManager.update(tpf);
|
stateManager.update(tpf);
|
||||||
|
|
||||||
// simple update and root node
|
// simple update and root node
|
||||||
simpleUpdate(tpf);
|
simpleUpdate(tpf);
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.SpatialUpdate);
|
||||||
rootNode.updateLogicalState(tpf);
|
rootNode.updateLogicalState(tpf);
|
||||||
guiNode.updateLogicalState(tpf);
|
guiNode.updateLogicalState(tpf);
|
||||||
|
|
||||||
@ -248,10 +253,15 @@ public abstract class SimpleApplication extends Application {
|
|||||||
guiNode.updateGeometricState();
|
guiNode.updateGeometricState();
|
||||||
|
|
||||||
// render states
|
// render states
|
||||||
|
if (prof!=null) prof.appStep(AppStep.StateManagerRender);
|
||||||
stateManager.render(renderManager);
|
stateManager.render(renderManager);
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.RenderFrame);
|
||||||
renderManager.render(tpf, context.isRenderable());
|
renderManager.render(tpf, context.isRenderable());
|
||||||
simpleRender(renderManager);
|
simpleRender(renderManager);
|
||||||
stateManager.postRender();
|
stateManager.postRender();
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.EndFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplayFps(boolean show) {
|
public void setDisplayFps(boolean show) {
|
||||||
|
@ -37,6 +37,9 @@ import com.jme3.material.RenderState;
|
|||||||
import com.jme3.material.Technique;
|
import com.jme3.material.Technique;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.post.SceneProcessor;
|
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.GeometryList;
|
||||||
import com.jme3.renderer.queue.RenderQueue;
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
||||||
@ -80,6 +83,7 @@ public class RenderManager {
|
|||||||
private Matrix4f orthoMatrix = new Matrix4f();
|
private Matrix4f orthoMatrix = new Matrix4f();
|
||||||
private String tmpTech;
|
private String tmpTech;
|
||||||
private boolean handleTranlucentBucket = true;
|
private boolean handleTranlucentBucket = true;
|
||||||
|
private AppProfiler prof;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a high-level rendering interface over the
|
* Create a high-level rendering interface over the
|
||||||
@ -377,6 +381,15 @@ public class RenderManager {
|
|||||||
uniformBindingManager.setTimer(timer);
|
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.
|
* Returns the forced technique name set.
|
||||||
*
|
*
|
||||||
@ -779,10 +792,12 @@ public class RenderManager {
|
|||||||
|
|
||||||
// render opaque objects with default depth range
|
// render opaque objects with default depth range
|
||||||
// opaque objects are sorted front-to-back, reducing overdraw
|
// 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);
|
rq.renderQueue(Bucket.Opaque, this, cam, flush);
|
||||||
|
|
||||||
// render the sky, with depth range set to the farthest
|
// render the sky, with depth range set to the farthest
|
||||||
if (!rq.isQueueEmpty(Bucket.Sky)) {
|
if (!rq.isQueueEmpty(Bucket.Sky)) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Sky);
|
||||||
renderer.setDepthRange(1, 1);
|
renderer.setDepthRange(1, 1);
|
||||||
rq.renderQueue(Bucket.Sky, this, cam, flush);
|
rq.renderQueue(Bucket.Sky, this, cam, flush);
|
||||||
depthRangeChanged = true;
|
depthRangeChanged = true;
|
||||||
@ -793,6 +808,7 @@ public class RenderManager {
|
|||||||
// rest of the scene's objects. Consequently, they are sorted
|
// rest of the scene's objects. Consequently, they are sorted
|
||||||
// back-to-front.
|
// back-to-front.
|
||||||
if (!rq.isQueueEmpty(Bucket.Transparent)) {
|
if (!rq.isQueueEmpty(Bucket.Transparent)) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Transparent);
|
||||||
if (depthRangeChanged) {
|
if (depthRangeChanged) {
|
||||||
renderer.setDepthRange(0, 1);
|
renderer.setDepthRange(0, 1);
|
||||||
depthRangeChanged = false;
|
depthRangeChanged = false;
|
||||||
@ -802,6 +818,7 @@ public class RenderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rq.isQueueEmpty(Bucket.Gui)) {
|
if (!rq.isQueueEmpty(Bucket.Gui)) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Gui);
|
||||||
renderer.setDepthRange(0, 0);
|
renderer.setDepthRange(0, 0);
|
||||||
setCamera(cam, true);
|
setCamera(cam, true);
|
||||||
rq.renderQueue(Bucket.Gui, this, cam, flush);
|
rq.renderQueue(Bucket.Gui, this, cam, flush);
|
||||||
@ -828,6 +845,8 @@ public class RenderManager {
|
|||||||
* @see #setHandleTranslucentBucket(boolean)
|
* @see #setHandleTranslucentBucket(boolean)
|
||||||
*/
|
*/
|
||||||
public void renderTranslucentQueue(ViewPort vp) {
|
public void renderTranslucentQueue(ViewPort vp) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.RenderBucket, vp, Bucket.Translucent);
|
||||||
|
|
||||||
RenderQueue rq = vp.getQueue();
|
RenderQueue rq = vp.getQueue();
|
||||||
if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
|
if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
|
||||||
rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
|
rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
|
||||||
@ -963,6 +982,8 @@ public class RenderManager {
|
|||||||
if (!vp.isEnabled()) {
|
if (!vp.isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.BeginRender, vp, null);
|
||||||
|
|
||||||
SafeArrayList<SceneProcessor> processors = vp.getProcessors();
|
SafeArrayList<SceneProcessor> processors = vp.getProcessors();
|
||||||
if (processors.isEmpty()) {
|
if (processors.isEmpty()) {
|
||||||
processors = null;
|
processors = null;
|
||||||
@ -988,20 +1009,24 @@ public class RenderManager {
|
|||||||
vp.isClearStencil());
|
vp.isClearStencil());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.RenderScene, vp, null);
|
||||||
List<Spatial> scenes = vp.getScenes();
|
List<Spatial> scenes = vp.getScenes();
|
||||||
for (int i = scenes.size() - 1; i >= 0; i--) {
|
for (int i = scenes.size() - 1; i >= 0; i--) {
|
||||||
renderScene(scenes.get(i), vp);
|
renderScene(scenes.get(i), vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processors != null) {
|
if (processors != null) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.PostQueue, vp, null);
|
||||||
for (SceneProcessor proc : processors.getArray()) {
|
for (SceneProcessor proc : processors.getArray()) {
|
||||||
proc.postQueue(vp.getQueue());
|
proc.postQueue(vp.getQueue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.FlushQueue, vp, null);
|
||||||
flushQueue(vp);
|
flushQueue(vp);
|
||||||
|
|
||||||
if (processors != null) {
|
if (processors != null) {
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
|
||||||
for (SceneProcessor proc : processors.getArray()) {
|
for (SceneProcessor proc : processors.getArray()) {
|
||||||
proc.postFrame(vp.getOutputFrameBuffer());
|
proc.postFrame(vp.getOutputFrameBuffer());
|
||||||
}
|
}
|
||||||
@ -1010,6 +1035,8 @@ public class RenderManager {
|
|||||||
renderTranslucentQueue(vp);
|
renderTranslucentQueue(vp);
|
||||||
// clear any remaining spatials that were not rendered.
|
// clear any remaining spatials that were not rendered.
|
||||||
clearQueue(vp);
|
clearQueue(vp);
|
||||||
|
|
||||||
|
if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUsingShaders(boolean usingShaders) {
|
public void setUsingShaders(boolean usingShaders) {
|
||||||
@ -1037,18 +1064,23 @@ public class RenderManager {
|
|||||||
this.shader = renderer.getCaps().contains(Caps.GLSL100);
|
this.shader = renderer.getCaps().contains(Caps.GLSL100);
|
||||||
uniformBindingManager.newFrame();
|
uniformBindingManager.newFrame();
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.RenderPreviewViewPorts);
|
||||||
for (int i = 0; i < preViewPorts.size(); i++) {
|
for (int i = 0; i < preViewPorts.size(); i++) {
|
||||||
ViewPort vp = preViewPorts.get(i);
|
ViewPort vp = preViewPorts.get(i);
|
||||||
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
||||||
renderViewPort(vp, tpf);
|
renderViewPort(vp, tpf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.RenderMainViewPorts);
|
||||||
for (int i = 0; i < viewPorts.size(); i++) {
|
for (int i = 0; i < viewPorts.size(); i++) {
|
||||||
ViewPort vp = viewPorts.get(i);
|
ViewPort vp = viewPorts.get(i);
|
||||||
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
||||||
renderViewPort(vp, tpf);
|
renderViewPort(vp, tpf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prof!=null) prof.appStep(AppStep.RenderPostViewPorts);
|
||||||
for (int i = 0; i < postViewPorts.size(); i++) {
|
for (int i = 0; i < postViewPorts.size(); i++) {
|
||||||
ViewPort vp = postViewPorts.get(i);
|
ViewPort vp = postViewPorts.get(i);
|
||||||
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user