1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.renderer;
34
35import com.jme3.scene.Mesh;
36import com.jme3.shader.Shader;
37import com.jme3.texture.FrameBuffer;
38import com.jme3.texture.Image;
39import java.util.HashSet;
40
41/**
42 * The statistics class allows tracking of real-time rendering statistics.
43 * <p>
44 * The <code>Statistics</code> can be retrieved by using {@link Renderer#getStatistics() }.
45 *
46 * @author Kirill Vainer
47 */
48public class Statistics {
49
50    protected int numObjects;
51    protected int numTriangles;
52    protected int numVertices;
53    protected int numShaderSwitches;
54    protected int numTextureBinds;
55    protected int numFboSwitches;
56    protected int numUniformsSet;
57
58    protected int memoryShaders;
59    protected int memoryFrameBuffers;
60    protected int memoryTextures;
61
62    protected HashSet<Integer> shadersUsed = new HashSet<Integer>();
63    protected HashSet<Integer> texturesUsed = new HashSet<Integer>();
64    protected HashSet<Integer> fbosUsed = new HashSet<Integer>();
65
66    /**
67     * Returns a list of labels corresponding to each statistic.
68     *
69     * @return a list of labels corresponding to each statistic.
70     *
71     * @see #getData(int[])
72     */
73    public String[] getLabels(){
74        return new String[]{ "Vertices",
75                             "Triangles",
76                             "Uniforms",
77
78                             "Objects",
79
80                             "Shaders (S)",
81                             "Shaders (F)",
82                             "Shaders (M)",
83
84                             "Textures (S)",
85                             "Textures (F)",
86                             "Textures (M)",
87
88                             "FrameBuffers (S)",
89                             "FrameBuffers (F)",
90                             "FrameBuffers (M)" };
91
92    }
93
94    /**
95     * Retrieves the statistics data into the given array.
96     * The array should be as large as the array given in
97     * {@link #getLabels() }.
98     *
99     * @param data The data array to write to
100     */
101    public void getData(int[] data){
102        data[0] = numVertices;
103        data[1] = numTriangles;
104        data[2] = numUniformsSet;
105        data[3] = numObjects;
106
107        data[4] = numShaderSwitches;
108        data[5] = shadersUsed.size();
109        data[6] = memoryShaders;
110
111        data[7] = numTextureBinds;
112        data[8] = texturesUsed.size();
113        data[9] = memoryTextures;
114
115        data[10] = numFboSwitches;
116        data[11] = fbosUsed.size();
117        data[12] = memoryFrameBuffers;
118    }
119
120    /**
121     * Called by the Renderer when a mesh has been drawn.
122     *
123     */
124    public void onMeshDrawn(Mesh mesh, int lod){
125        numObjects ++;
126        numTriangles += mesh.getTriangleCount(lod);
127        numVertices += mesh.getVertexCount();
128    }
129
130    /**
131     * Called by the Renderer when a shader has been utilized.
132     *
133     * @param shader The shader that was used
134     * @param wasSwitched If true, the shader has required a state switch
135     */
136    public void onShaderUse(Shader shader, boolean wasSwitched){
137        assert shader.getId() >= 1;
138
139        if (!shadersUsed.contains(shader.getId()))
140            shadersUsed.add(shader.getId());
141
142        if (wasSwitched)
143            numShaderSwitches++;
144    }
145
146    /**
147     * Called by the Renderer when a uniform was set.
148     */
149    public void onUniformSet(){
150        numUniformsSet ++;
151    }
152
153    /**
154     * Called by the Renderer when a texture has been set.
155     *
156     * @param image The image that was set
157     * @param wasSwitched If true, the texture has required a state switch
158     */
159    public void onTextureUse(Image image, boolean wasSwitched){
160        assert image.getId() >= 1;
161
162        if (!texturesUsed.contains(image.getId()))
163            texturesUsed.add(image.getId());
164
165        if (wasSwitched)
166            numTextureBinds ++;
167    }
168
169    /**
170     * Called by the Renderer when a framebuffer has been set.
171     *
172     * @param fb The framebuffer that was set
173     * @param wasSwitched If true, the framebuffer required a state switch
174     */
175    public void onFrameBufferUse(FrameBuffer fb, boolean wasSwitched){
176        if (fb != null){
177            assert fb.getId() >= 1;
178
179            if (!fbosUsed.contains(fb.getId()))
180                fbosUsed.add(fb.getId());
181        }
182
183        if (wasSwitched)
184            numFboSwitches ++;
185    }
186
187    /**
188     * Clears all frame-specific statistics such as objects used per frame.
189     */
190    public void clearFrame(){
191        shadersUsed.clear();
192        texturesUsed.clear();
193        fbosUsed.clear();
194
195        numObjects = 0;
196        numTriangles = 0;
197        numVertices = 0;
198        numShaderSwitches = 0;
199        numTextureBinds = 0;
200        numFboSwitches = 0;
201        numUniformsSet = 0;
202    }
203
204    /**
205     * Called by the Renderer when it creates a new shader
206     */
207    public void onNewShader(){
208        memoryShaders ++;
209    }
210
211    /**
212     * Called by the Renderer when it creates a new texture
213     */
214    public void onNewTexture(){
215        memoryTextures ++;
216    }
217
218    /**
219     * Called by the Renderer when it creates a new framebuffer
220     */
221    public void onNewFrameBuffer(){
222        memoryFrameBuffers ++;
223    }
224
225    /**
226     * Called by the Renderer when it deletes a shader
227     */
228    public void onDeleteShader(){
229        memoryShaders --;
230    }
231
232    /**
233     * Called by the Renderer when it deletes a texture
234     */
235    public void onDeleteTexture(){
236        memoryTextures --;
237    }
238
239    /**
240     * Called by the Renderer when it deletes a framebuffer
241     */
242    public void onDeleteFrameBuffer(){
243        memoryFrameBuffers --;
244    }
245
246    /**
247     * Called when video memory is cleared.
248     */
249    public void clearMemory(){
250        memoryFrameBuffers = 0;
251        memoryShaders = 0;
252        memoryTextures = 0;
253    }
254
255}
256