0
$\begingroup$

I am about to implement a framerate histogramm chart for a DirectX Renderer.

Ideally I would do this in pure shader code, but for a a histogramm I need to store the timestamps of the last x frames. I guess I could store these to a texture, but I was wondering if there is a more appropriate way to achieve that?

Thanks!

$\endgroup$
1
  • $\begingroup$ There are many ways to visualize such a histogram. Please add a picture of how your result should look like $\endgroup$
    – Thomas
    Jun 30, 2023 at 10:57

2 Answers 2

0
$\begingroup$

I don't think that you have access to the current time on GPU / pixel shader. So you need to transmit the information from CPU to GPU.

There are many ways to store the framerate results.

Example storing directly into a texture:

You can create a texture with height (framerate max) and width (number of samples) and store directly the new framerate value to this texture. The texture sampler can be set to mode wrap so that you can use the texture as ring buffer. This example has many disadvantages:

  1. You need to define the maximum and minimum framerate which should be visible. This is a disadvantage because the framerate can vary a lot depending on the complexity of the rendered geometry and the complexity of the shader which render the geometry. So when rotating the camera the number of pixel which got hit may vary a lot, so you can have huge jumps within your texture (see figure1 a).
  2. The next disadvantage is that when you render very complex geometries where your framerate drops a lot, your framerate will show the minimum framerate. But the framerate will not be the same. Lets say it changes from 0.01 frames per second to 0.4 frames per second. So each value within this range will be stored at min framerate but the factor from the minimum to the maximum is 40! (see figure1 b)
  3. When rendering only a small triangle, your framerate can increase and be outside the scale of your texture. Therefor it will not be visible inside your texture (see figure1 c).

enter image description here

Figure1: Displaying the disadvantages of storing the framerate directly to a texture.

Example storing framerate to a buffer:

First create a buffer on GPU where the framerates will be stored to and use it as ring buffer. Create a shader to visualize the histogram by passing an integer value as current position of the buffer and use modulo operator to find the correct position in the buffer when rendering with your pixel shader. This approch will have the following benefits:

  1. The buffer is very small in contrast to a texture.
  2. You only need to transfer 2 values (current position in buffer, new framerate value).
  3. You are not restricted to a minimum or maximum framerate which can be displayed.
  4. By passing the additional variables minFramerate and maxFramerate you can scale the histogram. So that in the example case b) will show you the big differences between 0.01 frames per second and 0.4 frames per second. The framerate also can not be outside of the maximal showable framerate (example case c).
  5. you can draw lines from one value to the next value, so there will be no gabs in between.
  6. you can change the shader from drawing connected lines to boxes if you like.
$\endgroup$
0
$\begingroup$

It sounds like you want to gather timings for say 100 frames (x frames) then show that data histogram style.

You could store the histogram data directly in the shader as an array of floats and draw directly out of the array using the vertex index id, but to update the histogram the array would have to be rewritten inside the shader, then the shader reloaded and recompiled. Overall it is not a very appealing approach.

A simple approach that is much more flexible, is to write the sample data into a vertex attributes buffer. Bind the vertex buffer and at draw time, the GPU feeds the data to your shader. Each histogram gl_line requires two values, so the first value would be zero and the second value would be the timing value. Repeat that for every timing value. The histogram then becomes a series of lines where the length of the line is determined by the passed in timing, the x position of the line is determined by the vertex index id, and the height of the lines can be uniformly scaled. Finally use a vec3 offset to move the histogram anywhere on the output buffer. gl line width can be used to thicken the lines up so the entire histogram isn't minuscule in size.

Now the histogram draw is just a matter of binding the vertex buffer containing the timing data, and doing the draw call. Changing the number of values is just a matter of writing a bigger vertex buffer and changing the number of vertices in the draw call.

To update the histogram gather more data, push it out to the vertex buffer and draw.

Once this is working it is easy to get fancy with ring buffers, using quads for the histogram lines, animating, etc.

enter image description here

$\endgroup$
3
  • $\begingroup$ He said, he is using directX, so gl line width is not available. There is no directX implementation for it. Alternatively you can do it this was: stackoverflow.com/questions/42510542/… $\endgroup$
    – Thomas
    Jul 1, 2023 at 13:12
  • $\begingroup$ line width isn't needed to implement this it is just a nicety. $\endgroup$
    – pmw1234
    Jul 1, 2023 at 14:03
  • $\begingroup$ Yes, I know... I only wanted to say, that it is not available... $\endgroup$
    – Thomas
    Jul 1, 2023 at 14:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.