Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  modify the contents of VBO  (Read 997 times)
0 Members and 1 Guest are viewing this topic.
Offline vastrolorde

Junior Member





« Posted 2014-03-27 16:46:19 »

Is there a way to modify the content of a vbo while it has been binded.
Or is there a better way to modify the size of a rectangle on the run?
Online Drenius
« Reply #1 - Posted 2014-03-27 16:58:02 »

How big is your VBO that there is a difference to just rendering it and modifying it then?
Offline SHC
« Reply #2 - Posted 2014-03-27 17:00:10 »

Yes it's possible to modify a VBO but before that, see the VBO drawing hints. There are constants for drawing which also give some hints to the opengl rendering engine.

1  
2  
3  
GL_STATIC_DRAW     // The VBO will be created once and drawn many times
GL_STREAM_DRAW     // The VBO will be updated every frame
GL_DYNAMIC_DRAW    // The VBO will be updated n times and is drawn n times

Then create the VBO as you normally would and you can update the contents with the
glBufferSubData()
function. It's syntax is

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
/**
 * Updates a subset of a buffer object's data store. It redefines some or
 * all of the data store for the buffer object currently bound to target. Data
 * starting at byte offset offset and extending for size bytes is copied to the
 * data store from the memory pointed to by data.
 *
 * @param target Specifies the target buffer object.

 * @param offset Specifies the offset into the buffer object's data store
 *               where data replacement will begin, measured in bytes.

 * @param data  A FloatBuffer containing the data of the VBO
 */

public static void glBufferSubData(int target, int offset, FloatBuffer data);

To replace the entire VBO, you can use the following, setting the offset to 0.

1  
glBufferData(GL_ARRAY_BUFFER, 0, data);

This updates the entire VBO.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline StrideColossus
« Reply #3 - Posted 2014-03-27 17:03:06 »

The glBufferSubData method works similarly to glBufferData.
You might also want to look at the usage hint you provide when initially uploading data using glBufferData (the last argument).
Offline vastrolorde

Junior Member





« Reply #4 - Posted 2014-03-27 17:39:00 »

So when the first buffer is created it is bound with GL_STREAM_DRAW. And i created the second buffer wit hthe data i want to be updated. But it seems like glBufferSubData is not changing the data out. Nothing changes.

glBufferSubData cannot be put into update method, cause update thread calls the update method out and update thread contains no GL syntax.


1  
2  
3  
4  
5  
6  
7  
8  
9  
public void renderInit() {
      renderInitStart();
     
     
      vboVertexID = glGenBuffers();
      glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
      glBufferData(GL_ARRAY_BUFFER, vertices, GL_STREAM_DRAW);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
   }


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
      @Override
   public void renderInitStart() {
      if(!textured){
         setTexture();
      }
      Texture tex = RenderThread.spritesheet.getTex();
      texture = tex.id;
      vboTexVertexID = glGenBuffers();
         
        glBindBuffer(GL_ARRAY_BUFFER, vboTexVertexID);
        glBufferData(GL_ARRAY_BUFFER, texVertices, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);            
     
   }

   @Override
   public void renderDraw() {
      glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
      glBufferSubData(GL_ARRAY_BUFFER,0,Vertices);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glDrawArrays(GL_QUADS, 0, 24);
      glDisable(GL_BLEND);
   }

   @Override
   public void update() {
      if(currentFuel != player.getFuel()){
         currentFuel = player.getFuel();
         float[] vertex = {
            width*x,height*y+10,width*x+hull*(player.getFuel()/100),height*y+10,width*x+hull*(player.getFuel()/100),height*y,width*x,height*y,
            width*x,height*y+44,width*x+fuel*(player.getFuel()/100),height*y+44,width*x+fuel*(player.getFuel()/100),height*y+34,width*x,height*y+34
           
         };
         Vertices.put(vertex);
         Vertices.rewind();
      }
   }
Offline StrideColossus
« Reply #5 - Posted 2014-03-27 18:23:02 »

It's tricky to work out what the problem is without seeing the 'loop' where these methods are being invoked or understanding what you're trying to achieve.

Is renderInitStart only invoked once?  If so, why is the glBufferSubData call there?  If it is called on every frame then you will need to move the glBufferSubData call after you've bound the VBO (I think calling methods on the default VBO is undefined but don't quote me on that).

i.e.

init:
- allocate the buffer
- bind
- glBufferData to initialise VBO (if required)

on each frame:
- bind the VBO
- glBufferSubData to update the VBO with the new vertices
- draw it

after each frame:
- update the vertices
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #6 - Posted 2014-03-27 21:20:13 »

I'm looking for an answer to this too.  My vertices and textures are fixed and I have VBOs bound for them.  However, the colors change possibly every frame.

How does glBufferSubData compare to glMapBuffer?
Offline vastrolorde

Junior Member





« Reply #7 - Posted 2014-03-28 07:45:44 »

well... i dont know about glMapBuffer. But the glBufferSubData: create the VBO normally except in the gl glBufferData you but GL_STREAM_DRAW instead of GL_STATIC_DRAW. and then when you have the now content ready for the buffer you just. glBindBuffer(GL_ARRAY_BUFFER, BufferID);
glBufferSubData(GL_ARRAY_BUFFER, offset, buffer with new content);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Offline vastrolorde

Junior Member





« Reply #8 - Posted 2014-03-28 13:43:29 »

Only problem that remains is that i have to change the entire buffer. When i try to change from the offset it doesent draw properl anymore..
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #9 - Posted 2014-03-28 17:26:39 »

This is what I discovered last night.  The following are scala snippets but should be easy to follow.

My original vertex data are stored in java.nio buffers:

1  
2  
3  
private val vertices: java.nio.FloatBuffer
private val textures: java.nio.FloatBuffer
private val colors: java.nio.ByteBuffer


Assuming you have somewhere to store the int handles to your VBOs (I have 3, one for vertices, textures, and colors):

1  
2  
3  
private var vHandle: Int = -1
private var tHandle: Int = -1
private var cHandle: Int = -1


Create your buffers just once and upload your data to the graphics card.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
val ib: IntBuffer = BufferUtils.createIntBuffer(3)  // 3 buffers needed

glGenBuffers(ib)
vHandle = ib.get(0)
tHandle = ib.get(1)
cHandle = ib.get(2)
 
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW)

glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glBufferData(GL_ARRAY_BUFFER, textures, GL_STATIC_DRAW)

glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glBufferData(GL_ARRAY_BUFFER, colors, GL_DYNAMIC_DRAW)  // dynamic as this could change

glBindBuffer(GL_ARRAY_BUFFER, 0)  // unbind


Now in your draw method you can paint statically which is the fastest:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glVertexPointer(3, GL_FLOAT, 0, 0)

glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glTexCoordPointer(2, GL_FLOAT, 0, 0)

glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0)

glDrawArrays(GL_QUADS, 0, 4 * capacity)  // 4 vertices per quad

glBindBuffer(GL_ARRAY_BUFFER, 0)


But if values change, i.e. you've directly modified the values in vertices, textures, and colors, you can intentionally do an upload.  Here's an example of me uploading the colors also during the draw/render phase:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glVertexPointer(3, GL_FLOAT, 0, 0)

glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glTexCoordPointer(2, GL_FLOAT, 0, 0)

glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glBufferSubData(GL_ARRAY_BUFFER, 0, colors)  // upload colors
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0)

glDrawArrays(GL_QUADS, 0, 4 * capacity)

glBindBuffer(GL_ARRAY_BUFFER, 0)


At some point in time you need to free the VBOs but that is only when you're done with them and not necessarily every frame.

1  
2  
3  
4  
5  
6  
7  
val ib: IntBuffer = BufferUtils.createIntBuffer(3)

ib.put(0, vHandle)
ib.put(1, tHandle)
ib.put(2, cHandle)

glDeleteBuffers(ib)


On my system, I can render a frame in about 1.5 msec with pure static VBOs.  If I need to upload the colors on 160000 quads, the render jumps up to around 2.0 msec.  Yes technically, I am not modifying the VBO purely in video memory and instead I'm uploading an entire data set.  However, the performance hit appears negligible and note that depending on how I manage things, I may not need to upload data every frame.

[edit] use glBufferSubData instead of glBufferData on upload
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline SHC
« Reply #10 - Posted 2014-03-28 17:41:48 »

Always use
glBufferSubData
to update the entire data. It just updates the data whereas
glBufferData
will delete the previous data, allocate new memory and then copy the data. With
glBufferSubData
there is some increase in performance since the same memory will be reused.

Offline StrideColossus
« Reply #11 - Posted 2014-03-28 17:51:03 »

Always use
glBufferSubData
to update the entire data. It just updates the data whereas glBufferSubData will delete the previous data, allocate new memory and then copy the data. With
glBufferSubData
there is some increase in performance since the same memory will be reused.

I assume you meant
glBufferData
in the above (where I've struck-out).

</pedantry> Wink
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #12 - Posted 2014-03-28 18:36:04 »

Good to know.  I'll give glBufferSubData a try and report back.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #13 - Posted 2014-03-29 01:51:07 »

Thanks SHC for the tip.  Using glBufferSubData reduced render from around 2.3 msec down to 1.6 msec.  Approximately 25% less time!

OP, did you manage to get your code working?
Offline vastrolorde

Junior Member





« Reply #14 - Posted 2014-03-29 10:54:43 »

Yes the code is working. Now i just need to torture the guy who built the threading system Cheesy, its a mess Cheesy.
Offline SHC
« Reply #15 - Posted 2014-03-29 16:04:19 »

I assume you meant
glBufferData
in the above (where I've struck-out).

Yeah. Was sleepy so a typo. Thanks.

Offline theagentd
« Reply #16 - Posted 2014-03-29 17:15:55 »

Always use
glBufferSubData
to update the entire data. It just updates the data whereas
glBufferData
will delete the previous data, allocate new memory and then copy the data. With
glBufferSubData
there is some increase in performance since the same memory will be reused.
This is not entirely true. glBufferData() doesn't immediately delete the previous data since the GPU might still be using it. However, you're right that it  reallocates the memory on each call. This is called orphaning and it has some useful characteristics. Let's say you have a small VBO which you update multiple times per frame. In this case, glBufferSubData() and glMapBuffer() will have terrible performance since each time you update the buffer you basically stall the entire OpenGL pipeline since the GPU has to finish using the old data before it's overwritten. If you instead use glBufferData(), the driver is smart enough to not immediately delete the old buffer and the driver may keep multiple internal buffers for each call to glBufferData(). In this case, there is no stall since the driver isn't forced to overwrite the old data of the buffer and can just keep the old buffers in memory and deallocate them when they no longer have a use. In the case of a buffer being updated only once per frame, the overhead of glBufferData() is a bad thing and glBufferSubData() or (even better) glMapBuffer() is preferred to glBufferData() like you said.

Myomyomyo.
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (25 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (33 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (43 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!