<p>We are developing a PPI plot for a radar system, similar to the following: <a href="https://i.sstatic.net/lGMg2.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lGMg2.png" alt="http://radar-review.blogspot.com/2014/04/"></a>
<strong>NOTE: 1 radial is defined as a single slice of data within the circle, and 1 range gate is defined as a single point along a radial.</strong></p>

<p>Our application must operate in real time, with large throughput and with a varying number of range gates per radial. </p>

<p>We have two implementations at the moment, both which stream radials to the GPU as vertex and/or texture data. </p>

<p>One version defines each range gate as separate primitives, then colors them using vertex coloring. The problem here is that the vertex buffer size must be rather large to accommodate a suitable amount of radials / range gates; this memory is not something we can necessarily rely on.</p>

<p>I am exploring another option, which generates one quad to represent each radial, then colors the range gates using texture mapping. The range gate texture buffer is a large 2D texture (2D to increase the maximum texture buffer size); 1D subsets of this texture are mapped to radials represent range gates. The problem with this method is that when a large number of fragments are being processed, each must perform a texture lookup to determine its color, which is wasteful since most fragments are redundant. This problem is compounded when zooming in, as every pixel in the window must sample the texture. The program's GPU usage skyrockets in these instances.</p>

<p>I've wondered if maybe it would be possible to sample each radial's 1D subset at the vertex level (since all vertices share a single 1D texture) then pass the sampled version to the fragment shader which then sample the subset. Each radial can have up to a thousand unique color samples. This would theoretically reduce the number of texture reads, but of course I don't even know if it's possible.</p>

<p>Is there an some way to optimize this process, or perhaps a way to reimagine the software that avoids some of these bottlenecks? </p>

CC BY-SA 4.0
2019-03-07T16:41:25.013Z
What do you refer to as vertices? Triangle vertices? So you are using a triangle mesh to draw this? As opposed to simply a texture? Can't you just generate a suitable 2d texture that you apply on a single quad? By this I mean a texture which has this circle with the radials in the middle. If you do this your problem with reduce to simply generating the correct texture fro your data (you do something similar currently from what I gather anyways but very inefficiently).
lightxbulb
CC BY-SA 4.0
2019-03-07T16:52:50.557Z
One approach generates a mesh for each radial (a triangle strip), where each range gate is described by a quad (really, two triangles). The second approach attempts to describe range gates by mapping a 1d texture onto each radial (a single quad).
Matthew Herndon
CC BY-SA 4.0
2019-03-07T16:57:07.200Z
Yes but why? Both of these generate a lot of triangles. Why not just make a quad and map a texture on it? Surely that will be more efficient. All you would have to do is to generate that texture. The second variant is not so terrible though, even though you generate a bunch of triangles. It really comes down to what your requirements are (in terms of resolution/zooming) and what your initial data looks like. I assume your initial data is resolution limited. What would be that initial resolution per radial and how many radials do you have.
lightxbulb
CC BY-SA 4.0
2019-03-07T17:03:22.070Z
The problem is that given the data we're expecting, there isn't really a trivial way to generate the circular texture you described in real time. As data arrives, it will need to be mapped to a radial at some arbitrary angle. That's the crux of the problem.
Matthew Herndon
CC BY-SA 4.0
2019-03-07T17:07:04.547Z
Join the chatroom if you want so we can clarify in real-time what you mean: https://chat.stackexchange.com/rooms/90733/trying-to-optimize-texture-mapping
lightxbulb
CC BY-SA 4.0
2019-03-07T17:15:25.620Z
I can't use the chat room, I don't have enough reputation.
Matthew Herndon
CC BY-SA 4.0
2019-03-07T17:19:36.807Z
Oh ok. Then we'll have to go back and forth over in the comments. From what you clarified last, it seems that your data arrives in the form of radial segments with some resolution say $w$ and you have a maximum of $h$ such radial segments (the last two are my assumptions), is that correct? And you're asserting that it is not efficient enough. How many such segments do you have? Basically how large can $h$ grow? Also how large can $w$ grow? And additionally at what resolution are you supposed to present the result?
lightxbulb
CC BY-SA 4.0
2019-03-07T17:32:33.607Z
I tried giving you write access to the chat room but I couldn't since: "Please note that you can only add users that have already visited chat.stackexchange.com." Try visiting chat.stackexchange.com
lightxbulb
CC BY-SA 4.0
2019-03-07T17:36:12.687Z
Unfortunately I still can't use the chat. [1]: Data arrives as a 1D array of intensity values, 1 for each range gate within a radial. These are colored via a colormap. [2]  We can't make many assumptions about how big h can grow; we want to maximize the # of draw-able radials while maintaining adequate performance. Currently this limit is defined by the size of the vertex buffer, which can store a maximum of 100,000 vertices. [3]  The plot must render with a varying resolution, as it's part of a map which can be panned and zoomed. (just visited chat.stackexchange.com)
Matthew Herndon
CC BY-SA 4.0
2019-03-07T17:47:30.967Z
Still can't add you for some reason. You say you can have $h$ grow arbitrarily large, does that mean that you remake your mesh every time? Since you triangles will need to form a fan with equidistant vertices, so a new triangle will have to change the angular distance between vertices on the circle, no? You could render more vertices with more draw calls but that seems inefficient. Maybe you can do a compute shader that directly samples your data which you feed in as a texture? That is, you feed in a texture where each row represents a radial (possibly empty such are simply $0$).
lightxbulb
CC BY-SA 4.0
2019-03-07T17:48:23.783Z
And then transform each pixel position on the unit disk onto the unit square in order to sample that texture. Note that you can even do some fancy (non-hardware) filtering this way.
lightxbulb
CC BY-SA 4.0
2019-03-07T18:59:17.063Z
Here's an example of what I mean: https://www.shadertoy.com/view/3dfXDB
Basically you can send in your radials as the rows of your texture. If some row is still empty (you still haven't computed the radial) you can for example set it to the background color. Use W/S for zoom, and mouse click to see the original texture used for this.
lightxbulb
CC BY-SA 4.0
2019-03-07T19:18:07.150Z
Thanks for the demo; another requirement that complicates things (should have mentioned this in the question) is that each radial can have an arbitrary width. This is another reason we're generating the graphics using a mesh.
Matthew Herndon
CC BY-SA 4.0
2019-03-07T19:27:52.437Z
As long as you're happy with texel precision, you can make the width arbitrary by repeating a row multiple times. Or you can use a look up table for the conversion of coordinates. In the shadertoy demo I use simply $\theta=atan(y,x)$, but you can have a mapping that shrinks/stretches space based on an arbitrary function, then you can have arbitrary width. I update the example to have a monotonically increasing function applied at the end so that the range is stretched based on it. Note that you can use a discrete lookup table for this to have an arbitrary width.
lightxbulb
CC BY-SA 4.0
2019-03-07T19:30:46.010Z
Your function to stretch/squeeze the range would be a monotonically non-decreasing function $f:[0,1]\rightarrow [0,1]$ such that $f(0) = 0, f(1) = 1$. Then you can construct $f$ to work similarly as what you were doing already.
lightxbulb
CC BY-SA 4.0
2019-03-07T19:35:47.730Z
As an example if I had two rows (two radials) the original mapping would map them to both hemicircles, so that the first row would correspond to $[0,\pi]$ and the second to $[\pi,2\pi]$. Now if you want the first to be only in $[0,a]$ and the second to be only in $[a,2\pi]$ all you have to do is construct a piecewise linear function mapping $[0,\pi]$ to $[0,a]$ and $[\pi,2\pi]$ to $[a,2\pi]$. Note that the function can be more complex, but it needs to be non-decreasing and $f(0)=0,f(1)=1$. For more points the function would obviously have more 'pieces' but the idea is the same.
lightxbulb
CC BY-SA 4.0
2019-03-09T13:12:40.900Z
Any updates on this?
lightxbulb
<texture><fragment-shader>
Trying to optimize texture mapping
Matthew Herndon
# Trying to optimize texture mapping

(Asked by: username_0 on 2019-03-07)

We are developing a PPI plot for a radar system, similar to the following: [![http://radar-review.blogspot.com/2014/04/](https://i.sstatic.net/lGMg2.png)](https://i.sstatic.net/lGMg2.png)
**NOTE: 1 radial is defined as a single slice of data within the circle, and 1 range gate is defined as a single point along a radial.**

Our application must operate in real time, with large throughput and with a varying number of range gates per radial.

We have two implementations at the moment, both which stream radials to the GPU as vertex and/or texture data.

One version defines each range gate as separate primitives, then colors them using vertex coloring. The problem here is that the vertex buffer size must be rather large to accommodate a suitable amount of radials / range gates; this memory is not something we can necessarily rely on.

I am exploring another option, which generates one quad to represent each radial, then colors the range gates using texture mapping. The range gate texture buffer is a large 2D texture (2D to increase the maximum texture buffer size); 1D subsets of this texture are mapped to radials represent range gates. The problem with this method is that when a large number of fragments are being processed, each must perform a texture lookup to determine its color, which is wasteful since most fragments are redundant. This problem is compounded when zooming in, as every pixel in the window must sample the texture. The program's GPU usage skyrockets in these instances.

I've wondered if maybe it would be possible to sample each radial's 1D subset at the vertex level (since all vertices share a single 1D texture) then pass the sampled version to the fragment shader which then sample the subset. Each radial can have up to a thousand unique color samples. This would theoretically reduce the number of texture reads, but of course I don't even know if it's possible.

Is there an some way to optimize this process, or perhaps a way to reimagine the software that avoids some of these bottlenecks?

**Tags:** texture, fragment-shader

> **Comments:**
> **username_1**: What do you refer to as vertices? Triangle vertices? So you are using a triangle mesh to draw this? As opposed to simply a texture? Can't you just generate a suitable 2d texture that you apply on a single quad? By this I mean a texture which has this circle with the radials in the middle. If you do this your problem with reduce to simply generating the correct texture fro your data (you do something similar currently from what I gather anyways but very inefficiently).  
> **username_0**: One approach generates a mesh for each radial (a triangle strip), where each range gate is described by a quad (really, two triangles). The second approach attempts to describe range gates by mapping a 1d texture onto each radial (a single quad).  
> **username_1**: Yes but why? Both of these generate a lot of triangles. Why not just make a quad and map a texture on it? Surely that will be more efficient. All you would have to do is to generate that texture. The second variant is not so terrible though, even though you generate a bunch of triangles. It really comes down to what your requirements are (in terms of resolution/zooming) and what your initial data looks like. I assume your initial data is resolution limited. What would be that initial resolution per radial and how many radials do you have.  
> **username_0**: The problem is that given the data we're expecting, there isn't really a trivial way to generate the circular texture you described in real time. As data arrives, it will need to be mapped to a radial at some arbitrary angle. That's the crux of the problem.  
> **username_1**: Join the chatroom if you want so we can clarify in real-time what you mean: https://chat.stackexchange.com/rooms/90733/trying-to-optimize-texture-mapping  
> **username_0**: I can't use the chat room, I don't have enough reputation.  
> **username_1**: Oh ok. Then we'll have to go back and forth over in the comments. From what you clarified last, it seems that your data arrives in the form of radial segments with some resolution say $w$ and you have a maximum of $h$ such radial segments (the last two are my assumptions), is that correct? And you're asserting that it is not efficient enough. How many such segments do you have? Basically how large can $h$ grow? Also how large can $w$ grow? And additionally at what resolution are you supposed to present the result?  
> **username_1**: I tried giving you write access to the chat room but I couldn't since: "Please note that you can only add users that have already visited chat.stackexchange.com." Try visiting chat.stackexchange.com  
> **username_0**: Unfortunately I still can't use the chat. [1]: Data arrives as a 1D array of intensity values, 1 for each range gate within a radial. These are colored via a colormap. [2]  We can't make many assumptions about how big h can grow; we want to maximize the # of draw-able radials while maintaining adequate performance. Currently this limit is defined by the size of the vertex buffer, which can store a maximum of 100,000 vertices. [3]  The plot must render with a varying resolution, as it's part of a map which can be panned and zoomed. (just visited chat.stackexchange.com)  
> **username_1**: Still can't add you for some reason. You say you can have $h$ grow arbitrarily large, does that mean that you remake your mesh every time? Since you triangles will need to form a fan with equidistant vertices, so a new triangle will have to change the angular distance between vertices on the circle, no? You could render more vertices with more draw calls but that seems inefficient. Maybe you can do a compute shader that directly samples your data which you feed in as a texture? That is, you feed in a texture where each row represents a radial (possibly empty such are simply $0$).  
> **username_1**: And then transform each pixel position on the unit disk onto the unit square in order to sample that texture. Note that you can even do some fancy (non-hardware) filtering this way.  
> **username_1**: Here's an example of what I mean: https://www.shadertoy.com/view/3dfXDB Basically you can send in your radials as the rows of your texture. If some row is still empty (you still haven't computed the radial) you can for example set it to the background color. Use W/S for zoom, and mouse click to see the original texture used for this.  
> **username_0**: Thanks for the demo; another requirement that complicates things (should have mentioned this in the question) is that each radial can have an arbitrary width. This is another reason we're generating the graphics using a mesh.  
> **username_1**: As long as you're happy with texel precision, you can make the width arbitrary by repeating a row multiple times. Or you can use a look up table for the conversion of coordinates. In the shadertoy demo I use simply $\theta=atan(y,x)$, but you can have a mapping that shrinks/stretches space based on an arbitrary function, then you can have arbitrary width. I update the example to have a monotonically increasing function applied at the end so that the range is stretched based on it. Note that you can use a discrete lookup table for this to have an arbitrary width.  
> **username_1**: Your function to stretch/squeeze the range would be a monotonically non-decreasing function $f:[0,1]\rightarrow [0,1]$ such that $f(0) = 0, f(1) = 1$. Then you can construct $f$ to work similarly as what you were doing already.  
> **username_1**: As an example if I had two rows (two radials) the original mapping would map them to both hemicircles, so that the first row would correspond to $[0,\pi]$ and the second to $[\pi,2\pi]$. Now if you want the first to be only in $[0,a]$ and the second to be only in $[a,2\pi]$ all you have to do is construct a piecewise linear function mapping $[0,\pi]$ to $[0,a]$ and $[\pi,2\pi]$ to $[a,2\pi]$. Note that the function can be more complex, but it needs to be non-decreasing and $f(0)=0,f(1)=1$. For more points the function would obviously have more 'pieces' but the idea is the same.  
> **username_1**: Any updates on this?  

---

## 0 answers

