Skip to main content
GameDev.net gamedev.net
🔒 Locked

Graph in texture

Started by patrrr Jan 15, 2007 at 9:56 PM 6 replies 1k views
Original Post
patrrr
patrrr
Hello! I want to plot a small graph in my application that is always updating based on data and I figured I can use a texture for that, when I get a new value I just move all the pixels in the texture one pixel to the left and set the pixel that corresponds to that new value. But how do I actually do these pixel operations on the texture? Will it be a huge performance hit? EDIT: I guess I can have a bitmap in memory that I update directly and then just call glTexImage on the graph texture. What is the fastest way?
silvermace
silvermace
updating a GL texture is considered an expensive operation (consider that the texture resides in two places, on GPU memory and your editable copy in System memory, and every glTex[Sub]Image call to update the texture results in a bus copy from Sys->GPU)

best thing to do is use polygons or lines and actually draw the graph out using points, as a few hundred 4byte float's being transfered shouldn't be as slow as a several thousand bytes + native conversion, not to mention the pixel modification operations that have to be done on the CPU first..
patrrr
patrrr
Thanks for your response.
I thought of that, but I want to be able to color code the pixels depending on what kind of data it is, like a network data graph; the height of each position is the number of packets, but I can also set all the pixels from Y number of packets down to 0 with different colors to tell what kind of data it was.

What if I have a 256x64 texture updated once every second, will it still be too slow and spike the frame rate notably on a modern computer?
AIRmichael
AIRmichael
Quote:
Original post by patrrr
Thanks for your response.
I thought of that, but I want to be able to color code the pixels depending on what kind of data it is, like a network data graph; the height of each position is the number of packets, but I can also set all the pixels from Y number of packets down to 0 with different colors to tell what kind of data it was.

What if I have a 256x64 texture updated once every second, will it still be too slow and spike the frame rate notably on a modern computer?


I did it once before, updating a 256x256texture in real time. It is slow, but not that slow. Still getting a reseaonable framerate... but you probably have to test it yourself:)

Kalidor
Kalidor
Quote:
Original post by patrrr
...when I get a new value I just move all the pixels in the texture one pixel to the left and set the pixel that corresponds to that new value.
You could fake this very efficiently by translating the texture matrix and updating only a small column of texels. You basically offset the origin of the texture by n texels and update the n columns of texels between the old and new offsets. I'll try to make a simple ASCII diagram of it using a 1D grayscale texture of width 4.
Original:     [ 25 | 173 | 243 | 95 ]     ^  offset = 0Update 1: (add 42 to the "end" of the graph)     [ 42 | 173 | 243 | 95 ]          ^       offset = 1/4Update 2: (add 104 to the "end" of the graph)     [ 42 | 104 | 243 | 95 ]                ^             offset = 2/4
Just make sure the texture is set to repeat in at least the axis you are offsetting.

EDIT: Although using simple primitives (ie: lines) will be much easier and probably faster. Any slight speed difference shouldn't be too big a deal anyway because this will most likely only be used for debugging purposes, so even if updating the texture were faster, I would still say choose the simpler option.
jouley
jouley
Quote:
Original post by patrrr
I want to be able to color code the pixels depending on what kind of data it is, like a network data graph; the height of each position is the number of packets, but I can also set all the pixels from Y number of packets down to 0 with different colors to tell what kind of data it was.

I'm with silvermace. You can color your vertices (or even pixels if you want, using an orthographic projection) with standard GL calls (glColor*). For example:
glBegin(GL_POINTS);glColor4f(1.0f, 0.0f, 0.0f, 1.0f);  //  opaque redglVertex3f(0.0f, 0.0f, 0.0f);glColor4f(0.0f, 1.0f, 0.0f, 0.5f);  //  semi-opaque greenglVertex3f(0.5f, 0.0f, 0.0f);glEnd( );
Wrapping up the functionality of a graph with different points will take a class or two, but can be reused 7.232 trillion times more effectively and easily than updating a texture.

Best of luck!
-jouley
patrrr
patrrr
Thanks alot for your replies!

You say that I should use the simple method (simple line primitives), but I can't see how this is easier to use:

* Let's say I have recorded 20 seconds and every second has 5 different "areas" or types. This will result in 100 line primitives

* If I want to scale the graph, I will also have to scale the line width or there will be spacing between the bars (which I don't want).

* I have to fiddle with the matrices

But you can update the graph much smoother if you use lines, which is neat.

One question, if you copy the same amount of data into a vertex buffer as into a texture, will the vertex buffer still be much faster? Why? It's the download to the GPU that is the bottle neck right? Independent on how/where the data will be stored?

To clarify, what I want is a bar graph.

Edit: never mind, silvermace already answered my "one question".
silvermace
silvermace
well, you haven't really explained exactly what you want to acheive with the graph, I cant see how a texture would be easier than (for example):
const int GRAPH_WIDTH = 256;struct graph_datum {  float color[3];  float plot_y;  void colorFromPacketCount(int packets) { ... }  void colorFromDataType(EDataType dtype) { ... }  ...};struct graph {  std::vector<graph_datum> data;  int count;  float graphX, graphY;  graph() { data.resize(GRAPH_WIDTH); count=0; }  void draw() {     glMatrixMode(GL_PROJECTION);     glPushMatrix();     glOrtho2D(0,640,480,0,-1,1); // this is the most matrix fiddling you'll have to do.     glMatrixMode(GL_MODELVIEW);     glPushMatrix();     glTranslatef(graphX, graphY, 0);     glBegin( GL_LINES );     for(int i=0; i<GRAPH_WIDTH; i++ ) {         graph_datum& d = data;                glColor3fv(d.color);         glVertex2f((float)i, 0);         glVertex2f((float)i, d.plot_y);     }     glEnd();          glMatrixMode(GL_PROJECTION);     glPopMatrix();     glMatrixMode(GL_MODELVIEW);     glPopMatrix();  }   void addDatum( const graph_datum& d ) {      data.at( GRAPH_WIDTH % count++ );  }};
hope that gives you some ideas?


Quote:
* Let's say I have recorded 20 seconds and every second has 5 different "areas" or types. This will result in 100 line primitives
Even if you're using immediate mode, this will still be faster than a texture update, if you're using VBOs or simple VAs it will be incomparably faster.

Quote:
One question, if you copy the same amount of data into a vertex buffer as into a texture, will the vertex buffer still be much faster? Why? It's the download to the GPU that is the bottle neck right? Independent on how/where the data will be stored?
if you use arrays, the GPU and PCI-E/AGP bus can probably stream the data, which means the GPU can start rendering before all the data has been copied. Additional to this, Textures may need to be converted to native hardware format, and depending on what hardware the code is running on, this will vary, coding detection code is almost definitely overkill. Also, I'm pretty sure (although if someone knows better, please correct me) that texture reads are dependant/blocked, so the GPU may waste alot of time waiting around for texture reads to return (this has been fixed on the latest NVIDIA 8800, but well, its obvious why that is moot..)

You're right about the scaling. I'm almost tempted not to be this cheeky, but if you use an FBO and render the graph to a texture, that will probably still be faster hahahaha, but don't quote me on that. [smile]

Cheers,
-Danu

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.