<p>Rather than trying to speed up your shader by fiddling with the code, can I suggest you make use of the GPU's inherent ability to rapidly fill polygons? This will allow it to eliminate the vast bulk of the cases where there is no need to even make a decision.</p>

<p>What I suggest you try is <em>something</em> like the following: Create, say, a heptagon (i.e. the blue dashed outline (<em>note: it shares some of the boundary with the green but I just noticed this is not particularly obvious in the diagram</em>)) that starts from the original location and extends to the new position but lies inside the extremes of the new location's circle. 
The shader for this is then utterly trivial.</p>

<p><a href="https://i.sstatic.net/UXeIn.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/UXeIn.png" alt="enter image description here"></a></p>

<p>Then there can be one or two cases depending on how much you want to optimise. If the tail extends outside of the end position circle, you draw the green-dashed nonagon with your decision-based shader. This contains vastly fewer pixels. 
If the tail doesn't extend outside, then you'll need to mirror this polygon to get the other side of the circle. Alternatively, rather than make the decision, you could always mirror it and let the Z-test eliminate unneeded fills.</p>

<p>Your examples also have the have the capsules shown as opaque. If this is the case, you can also make gains with, say, TBDR-systems (a blatant PowerVR plug :-) ) or those with early-Z, provided you supply all your opaque "tail" portions first and then follow with all parts requiring decisions.</p>

<p>The shapes of course were just examples. You may find it's better to use more segments in your outlines in order to reduce the regions requiring the complex shader.</p>

CC BY-SA 3.0
2016-09-05T12:09:40.927Z
2018-04-23T07:46:41.127Z
2018-04-23T07:46:41.127Z
Simon F
<p>I have been working on how the GPU does parellel processing, and branching. However I am not yet to the point where I know how to make this shader more efficent. Essentially I dont know enough about how it works.</p>

<p>Anyway I have the following shader:</p>

<pre><code>precision highp float;

varying vec3 o_color; //Color it should be
varying vec2 texture_coord; //Interpolated value 0-1
varying float ratio_out; //This is the height / width of the capsule on screen
varying float rdistOut; //This number is used to fill in all pixels when particle is slow enough for the geometry to be a square but still has some distance from last position.

void main()
{


    vec2 yCoord = vec2(0.5);
    float yScale = ratio_out;

    vec2 my = texture_coord * vec2(1.0, yScale);

    vec2 del = yCoord - my;

    float len = del.x * del.x + del.y * del.y;
    if ((!(my.y &gt; 1.0) &amp;&amp; (len &lt; 0.25)) || (my.y &gt; yCoord.y &amp;&amp; my.y &lt; rdistOut))
    {
        gl_FragColor = vec4(o_color, 1.0);
    }
    else
    {
        gl_FragColor.a = 0.0;
    }
}
</code></pre>

<p>What it does is draw capsules on the screen. Basically these capsules connect where the particle was to where it is.</p>

<p>On the cpu I compute the vertices of this with some linear algebra, but in screen space terms the rectangle we will be shading has a maximum width of <code>W</code> and a minimum height of <code>W</code>. If the capsule is moving faster then <code>W/2</code> then the capsules geometry will start to get longer to accommodate.</p>

<p>Here are some diagrams of what is going on:</p>

<p>This is an image of a single capsule. Because the distance between the current and last position is not large enough so the screen-space geometry is a square. You can see that to compensate that lighter area is shaded in as well to connect the two points.</p>

<p><a href="https://i.sstatic.net/J6619.png" rel="noreferrer"><img src="https://i.sstatic.net/J6619.png" alt="enter image description here"></a></p>

<p>Here are some more examples of what could happen
<a href="https://i.sstatic.net/TEi8a.png" rel="noreferrer"><img src="https://i.sstatic.net/TEi8a.png" alt="enter image description here"></a></p>

<p>The thing is these capsules are all individual, sometimes every capsule will be elongated, sometimes it will only be a small percent. This shader needs to be as steady fps as possible.</p>

<p>Now here are some tips that are useful and might help make things more efficent:</p>

<ol>
<li>The dot product is NEVER needed past the point where the circle part is done.</li>
<li>If the scaleFactor is greater then 1 then the dot product is never needed past the center of the circle.</li>
</ol>

<p>This is shown in this diagram.  In this case none of the grey area needs to preform the dot product.
<a href="https://i.sstatic.net/XWikU.png" rel="noreferrer"><img src="https://i.sstatic.net/XWikU.png" alt="enter image description here"></a></p>

<p>Explanation of variables:</p>

<p>o_color: is the color that that particle is</p>

<p>texture_coord: these are the exact same as if you were going to texture this, they go from 0-1</p>

<p>ratio_out: height / width. Will never be less then 1</p>

<p>Inside the main function to get the coordinates in screen scale we simply multiply the y texture coordinate by the scale factor. That makes the center of the circle part a 0.5, 0.5.</p>

<p>rdistOut is the tiny area that the particle sometimes has when it is a square but still moving. Things should be shaded from 0.5-rdistOut.</p>

<p>Could you please help me remove un-needed dot product computations and comparisons as well as get rid of branching?</p>

<p><strong>Please include an explanation of how you got the GPU to skip dot product calculations or why you did what you did. Next time I hope to be able to do this myself.</strong></p>

CC BY-SA 3.0
2016-09-03T03:41:28.150Z
To clarify, is the dot product you are referring to "len"?
aces
CC BY-SA 3.0
2016-09-03T03:43:57.580Z
Yes, I have used dot(delta, delta) before in place of dist * dist. I just did the dot product that way to simplify things.
J.Doe
CC BY-SA 3.0
2016-09-03T04:02:03.603Z
What is the average speed of the particle? Is it normal to be the same size as that blue diagram at the bottom? I'm just trying to get a good idea of the use cases.
aces
CC BY-SA 3.0
2016-09-03T04:07:48.937Z
The simulation has many modes. Sometimes they move with herd mentality meaning they might all be longer or they all might be shorter. Sometimes they are vary individualistic with some being long and others short. I have thought about it quite a bit and thought the simulation the particles will be shorter and longer equally.  So unfortunately we can optimize due to use cases.
J.Doe
CC BY-SA 3.0
2016-09-04T03:49:50.160Z
@J.Doe: The only way you could avoid the dot product would be... by using a conditional branch around it. Which could wind up being slower than just doing the dot product. And let's face facts: a 2D vector dot-product is *trivially* fast on GPUs these days.
Nicol Bolas
CC BY-SA 3.0
2016-09-05T03:14:05.163Z
This shader looks like it should be super fast already, can't think of any further optimizations really. If / else branches will only really hurt you in a shader if you have a fair bit of code in each branch, here you're not even doing any arithmetic in the branches, just returning values, so the performance hit should be negligible. You could always replace it with a ternary operator, as in gl_FragColor = (condition) ? true_value : false_value. This compiles to a conditional move rather than a branch, so might get you a small speed boost.
russ
<shader><glsl>
I dont understand how a GPU computes and branches, could you please help me fix this shader preformance
J.Doe
# I dont understand how a GPU computes and branches, could you please help me fix this shader preformance

(Asked by: username_0 on 2016-09-03)

I have been working on how the GPU does parellel processing, and branching. However I am not yet to the point where I know how to make this shader more efficent. Essentially I dont know enough about how it works.

Anyway I have the following shader:

```
precision highp float;

varying vec3 o_color; //Color it should be
varying vec2 texture_coord; //Interpolated value 0-1
varying float ratio_out; //This is the height / width of the capsule on screen
varying float rdistOut; //This number is used to fill in all pixels when particle is slow enough for the geometry to be a square but still has some distance from last position.

void main()
{

    vec2 yCoord = vec2(0.5);
    float yScale = ratio_out;

    vec2 my = texture_coord * vec2(1.0, yScale);

    vec2 del = yCoord - my;

    float len = del.x * del.x + del.y * del.y;
    if ((!(my.y > 1.0) && (len < 0.25)) || (my.y > yCoord.y && my.y < rdistOut))
    {
        gl_FragColor = vec4(o_color, 1.0);
    }
    else
    {
        gl_FragColor.a = 0.0;
    }
}

```

What it does is draw capsules on the screen. Basically these capsules connect where the particle was to where it is.

On the cpu I compute the vertices of this with some linear algebra, but in screen space terms the rectangle we will be shading has a maximum width of `W` and a minimum height of `W`. If the capsule is moving faster then `W/2` then the capsules geometry will start to get longer to accommodate.

Here are some diagrams of what is going on:

This is an image of a single capsule. Because the distance between the current and last position is not large enough so the screen-space geometry is a square. You can see that to compensate that lighter area is shaded in as well to connect the two points.

[![enter image description here](https://i.sstatic.net/J6619.png)](https://i.sstatic.net/J6619.png)

Here are some more examples of what could happen
[![enter image description here](https://i.sstatic.net/TEi8a.png)](https://i.sstatic.net/TEi8a.png)

The thing is these capsules are all individual, sometimes every capsule will be elongated, sometimes it will only be a small percent. This shader needs to be as steady fps as possible.

Now here are some tips that are useful and might help make things more efficent:

1. The dot product is NEVER needed past the point where the circle part is done.
2. If the scaleFactor is greater then 1 then the dot product is never needed past the center of the circle.

This is shown in this diagram. In this case none of the grey area needs to preform the dot product.
[![enter image description here](https://i.sstatic.net/XWikU.png)](https://i.sstatic.net/XWikU.png)

Explanation of variables:

o\_color: is the color that that particle is

texture\_coord: these are the exact same as if you were going to texture this, they go from 0-1

ratio\_out: height / width. Will never be less then 1

Inside the main function to get the coordinates in screen scale we simply multiply the y texture coordinate by the scale factor. That makes the center of the circle part a 0.5, 0.5.

rdistOut is the tiny area that the particle sometimes has when it is a square but still moving. Things should be shaded from 0.5-rdistOut.

Could you please help me remove un-needed dot product computations and comparisons as well as get rid of branching?

**Please include an explanation of how you got the GPU to skip dot product calculations or why you did what you did. Next time I hope to be able to do this myself.**

**Tags:** shader, glsl

> **Comments:**
> **username_1**: To clarify, is the dot product you are referring to "len"?  
> **username_0**: Yes, I have used dot(delta, delta) before in place of dist * dist. I just did the dot product that way to simplify things.  
> **username_1**: What is the average speed of the particle? Is it normal to be the same size as that blue diagram at the bottom? I'm just trying to get a good idea of the use cases.  
> **username_0**: The simulation has many modes. Sometimes they move with herd mentality meaning they might all be longer or they all might be shorter. Sometimes they are vary individualistic with some being long and others short. I have thought about it quite a bit and thought the simulation the particles will be shorter and longer equally.  So unfortunately we can optimize due to use cases.  
> **username_2**: @username_0: The only way you could avoid the dot product would be... by using a conditional branch around it. Which could wind up being slower than just doing the dot product. And let's face facts: a 2D vector dot-product is *trivially* fast on GPUs these days.  
> **username_3**: This shader looks like it should be super fast already, can't think of any further optimizations really. If / else branches will only really hurt you in a shader if you have a fair bit of code in each branch, here you're not even doing any arithmetic in the branches, just returning values, so the performance hit should be negligible. You could always replace it with a ternary operator, as in gl_FragColor = (condition) ? true_value : false_value. This compiles to a conditional move rather than a branch, so might get you a small speed boost.  

---

## 1 answers

### Answer by username_4 on 2016-09-05. Score: 6

Rather than trying to speed up your shader by fiddling with the code, can I suggest you make use of the GPU's inherent ability to rapidly fill polygons? This will allow it to eliminate the vast bulk of the cases where there is no need to even make a decision.

What I suggest you try is *something* like the following: Create, say, a heptagon (i.e. the blue dashed outline (*note: it shares some of the boundary with the green but I just noticed this is not particularly obvious in the diagram*)) that starts from the original location and extends to the new position but lies inside the extremes of the new location's circle.
The shader for this is then utterly trivial.

[![enter image description here](https://i.sstatic.net/UXeIn.png)](https://i.sstatic.net/UXeIn.png)

Then there can be one or two cases depending on how much you want to optimise. If the tail extends outside of the end position circle, you draw the green-dashed nonagon with your decision-based shader. This contains vastly fewer pixels.
If the tail doesn't extend outside, then you'll need to mirror this polygon to get the other side of the circle. Alternatively, rather than make the decision, you could always mirror it and let the Z-test eliminate unneeded fills.

Your examples also have the have the capsules shown as opaque. If this is the case, you can also make gains with, say, TBDR-systems (a blatant PowerVR plug :-) ) or those with early-Z, provided you supply all your opaque "tail" portions first and then follow with all parts requiring decisions.

The shapes of course were just examples. You may find it's better to use more segments in your outlines in order to reduce the regions requiring the complex shader.


---

