Graphics problem, 2 Java codes, quad with border

Hi, I have a problem.

In my app all goes well, but I thought to do some optimization of the Java code, to reduce the amount of the Garbage collector work. I draw a quad with border, using a custom mesh. The code is:



The difference between two versions is only the reuse of the old containers. Vector3f[] vertices is global to the class, but can also be a local created variable, in the caller’s code



[java]

private void fillVerticeBuffer2(Vector3f downLeft, Vector3f upLeft, Vector3f downRight, Vector3f upRight, float edgeThickness, float borderSize, float overrun, Vector3f[] vertices)

{

Vector3f lToRUnitLength = downRight.subtract(downLeft).normalize();

Vector3f lToRBorderVect = lToRUnitLength.mult(borderSize);

Vector3f dToUpUnitLength = upLeft.subtract(downLeft).normalize();

Vector3f dToUpBorderVect = dToUpUnitLength.mult(borderSize);

Vector3f overrunVector = lToRUnitLength.mult(overrun);

Vector3f edgeThicknessVector = dToUpUnitLength.mult(edgeThickness);



Vector3f tmp = downLeft.subtract(overrunVector);

vertices[5] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = downRight.add(overrunVector);

vertices[9] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[5].subtract(lToRBorderVect);

vertices[2] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[9].add(lToRBorderVect);

vertices[3] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[2].subtract(dToUpBorderVect);

vertices[0] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[3].subtract(dToUpBorderVect);

vertices[1] = new Vector3f(tmp.x, tmp.y, tmp.z);



vertices[4] = new Vector3f(vertices[2].x, vertices[2].y, vertices[2].z);



tmp = vertices[5].add(edgeThicknessVector);

vertices[7] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[7].subtract(lToRBorderVect);

vertices[6] = new Vector3f(tmp.x, tmp.y, tmp.z);



vertices[8] = new Vector3f(vertices[5].x, vertices[5].y, vertices[5].z);



vertices[10] = new Vector3f(vertices[7].x, vertices[7].y, vertices[7].z);



tmp = vertices[9].add(edgeThicknessVector);

vertices[11] = new Vector3f(tmp.x, tmp.y, tmp.z);



vertices[12] = new Vector3f(vertices[9].x, vertices[9].y, vertices[9].z);



vertices[13] = new Vector3f(vertices[3].x, vertices[3].y, vertices[3].z);



vertices[14] = new Vector3f(vertices[11].x, vertices[11].y, vertices[11].z);



tmp = vertices[14].add(lToRBorderVect);

vertices[15] = new Vector3f(tmp.x, tmp.y, tmp.z);



vertices[16] = new Vector3f(vertices[6].x, vertices[6].y, vertices[6].z);



vertices[17] = new Vector3f(vertices[15].x, vertices[15].y, vertices[15].z);



tmp = vertices[16].add(dToUpBorderVect);

vertices[18] = new Vector3f(tmp.x, tmp.y, tmp.z);



tmp = vertices[17].add(dToUpBorderVect);

vertices[19] = new Vector3f(tmp.x, tmp.y, tmp.z);

}



public void updateVerticeBuffer(Vector3f downLeft, Vector3f upLeft, Vector3f downRight, Vector3f upRight, float edgeThickness, float borderSize, float overrun)

{

fillVerticeBuffer2(downLeft, upLeft, downRight, upRight, edgeThickness, borderSize, overrun, vertices);



this.clearBuffer(Type.Position);

this.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));



this.setDynamic();

this.updateBound();

}

[/java]

The result is:



http://i.imgur.com/JJ2m6.png



This is called every simulation step in my app, and you can imagine that always there are new Vector3f created. And also the JMonkeyEngine BufferUtils create new buffer every time. I thought not to create a new vector in vertices (Vector3f [] vertices;), but to reuse the ones I crated in constructor, just to assign the x, y, z values. So, I changed the code to:



[java]

private void fillVerticeBuffer(Vector3f downLeft, Vector3f upLeft, Vector3f downRight, Vector3f upRight, float edgeThickness, float borderSize, float overrun, Vector3f[] vertices)

{

Vector3f lToRUnitLength = downRight.subtract(downLeft).normalize();

Vector3f lToRBorderVect = lToRUnitLength.mult(borderSize);

Vector3f dToUpUnitLength = upLeft.subtract(downLeft).normalize();

Vector3f dToUpBorderVect = dToUpUnitLength.mult(borderSize);

Vector3f overrunVector = lToRUnitLength.mult(overrun);

Vector3f edgeThicknessVector = dToUpUnitLength.mult(edgeThickness);



Vector3f tmp = downLeft.subtract(overrunVector);

vertices[5].x = tmp.x;

vertices[5].y = tmp.y;

vertices[5].x = tmp.z;



tmp = downRight.add(overrunVector);

vertices[9].x = tmp.x;

vertices[9].y = tmp.y;

vertices[9].z = tmp.z;



tmp = vertices[5].subtract(lToRBorderVect);

vertices[2].x = tmp.x;

vertices[2].y = tmp.y;

vertices[2].z = tmp.z;



tmp = vertices[9].add(lToRBorderVect);

vertices[3].x = tmp.x;

vertices[3].y = tmp.y;

vertices[3].z = tmp.z;



tmp = vertices[2].subtract(dToUpBorderVect);

vertices[0].x = tmp.x;

vertices[0].y = tmp.y;

vertices[0].z = tmp.z;



tmp = vertices[3].subtract(dToUpBorderVect);

vertices[1].x = tmp.x;

vertices[1].y = tmp.y;

vertices[1].z = tmp.z;



vertices[4].x = vertices[2].x;

vertices[4].y = vertices[2].y;

vertices[4].z = vertices[2].z;



tmp = vertices[5].add(edgeThicknessVector);

vertices[7].x = tmp.x;

vertices[7].y = tmp.y;

vertices[7].z = tmp.z;



tmp = vertices[7].subtract(lToRBorderVect);

vertices[6].x = tmp.x;

vertices[6].y = tmp.y;

vertices[6].z = tmp.z;



vertices[8].x = vertices[5].x;

vertices[8].y = vertices[5].y;

vertices[8].z = vertices[5].z;



vertices[10].x = vertices[7].x;

vertices[10].y = vertices[7].y;

vertices[10].z = vertices[7].z;



tmp = vertices[9].add(edgeThicknessVector);

vertices[11].x = tmp.x;

vertices[11].y = tmp.y;

vertices[11].z = tmp.z;



vertices[12].x = vertices[9].x;

vertices[12].y = vertices[9].y;

vertices[12].z = vertices[9].z;



vertices[13].x = vertices[3].x;

vertices[13].y = vertices[3].y;

vertices[13].z = vertices[3].z;



vertices[14].x = vertices[11].x;

vertices[14].y = vertices[11].y;

vertices[14].z = vertices[11].z;



tmp = vertices[14].add(lToRBorderVect);

vertices[15].x = tmp.x;

vertices[15].y = tmp.y;

vertices[15].z = tmp.z;



vertices[16].x = vertices[6].x;

vertices[16].y = vertices[6].y;

vertices[16].z = vertices[6].z;



vertices[17].x = vertices[15].x;

vertices[17].y = vertices[15].y;

vertices[17].z = vertices[15].z;



tmp = vertices[16].add(dToUpBorderVect);

vertices[18].x = tmp.x;

vertices[18].y = tmp.y;

vertices[18].z = tmp.z;



tmp = vertices[17].add(dToUpBorderVect);

vertices[19].x = tmp.x;

vertices[19].y = tmp.y;

vertices[19].z = tmp.z;

}

[/java]



The result:

http://i.imgur.com/NFhIz.png



Is this a Java problem, or what sort of problem, because I really don’t understand why this works like that :slight_smile:



Thank you!

It’s not a Java problem. Your math got changed somehow or you are sharing state that you weren’t sharing before somehow. That’s something you’ll have to track down.



…but you also aren’t really saving any Vector3fs and you might as well go back to the old way. For example, every v.subtract() is creating a new Vector3f that you are copying the values into your temp array and then discarding. You could have just kept it instead.



In general, unless you are trying to run on non-desktop Java (like Android) you should not worry about short lived temporary objects. You can benchmark it if you want to but creating a handful of Vector3fs is a minuscule amount of time and “young generation” (ie: short lived temporary objects) are GC’ed almost for free.



However, you really should worry about the constant mesh recreation. That’s really expensive for a half a dozen ways I won’t go into here. You should try to reuse your mesh buffers whenever possible and only update them when the data has really changed (when possible). All of that other stuff you were doing is tiny in comparison.

Hi,

thank you for your reply. However, what I can say is:

  1. I’m not sharing any state. In my app I have many geometries, that have dynamic meshes. It is dynamic, and this is it. I can’t use static, is for simulation purposes, not a game. Every frame I change the mesh, and I need to update mesh data. It is because of that that I wanted to change from creating vectors every frame, and to use class ones, just assigning new values. Also, I tried to retrieve directly the float buffer, and to assign values, because I’m aware that what I use at the moment does copy all the vector data again. But my knowledge in JME is low so I didn’t manage to use this way. I’m still studying how to do this.



    If anyone can suggest why this happens, I will be very grateful, because I tried already many things, life using double buffering (my implementation), and it doesn’t work.



    Thank you!

You are still creating Vector3fs every frame. You just don’t realize you are. That’s my point.



Vector3f.subtract() creates a new instance. So you are not saving any instances, really. Well, I mean you are, just not as many as you think.



[java]

Vector3f tmp = downLeft.subtract(overrunVector);

vertices[5] = new Vector3f(tmp.x, tmp.y, tmp.z);

[/java]



Could have just as easily have been:

[java]

vertices[5] = downLeft.subtract(overrunVector);

[/java]



And you’d save one instance. Or even better:… you could save all of the instances and reuse your vertices array:

[java]

downLeft.subtract(overrunVector, vertices[5]);

[/java]



But the point is… these optimizations will save you teeny tiny amounts… especially when compared with the huge expense of the constant reallocation of the mesh buffers.



And anyway, something in your conversion got messed up because meshes won’t do that unless their values are wrong. So the old way had good data and the new way doesn’t… and that’s in your code somewhere. So as I said, something got shared where it shouldn’t be or the math got changed in a subtle way from the old to the new. Dump the vertices to log or something and maybe you’ll spot the error.

I’ve been through the two examples provided and they seem to be producing the same results to my eye.



If it were my code, I’d run the old function and the new function and dump the vertices array. If they have the same values then you know the problem is elsewhere and if they don’t then you can track down the error.

@pspeed said:
You are still creating Vector3fs every frame. You just don't realize you are. That's my point.

Vector3f.subtract() creates a new instance. So you are not saving any instances, really. Well, I mean you are, just not as many as you think.

[java]
Vector3f tmp = downLeft.subtract(overrunVector);
vertices[5] = new Vector3f(tmp.x, tmp.y, tmp.z);
[/java]

Could have just as easily have been:
[java]
vertices[5] = downLeft.subtract(overrunVector);
[/java]

And you'd save one instance. Or even better:.. you could save all of the instances and reuse your vertices array:
[java]
downLeft.subtract(overrunVector, vertices[5]);
[/java]

But the point is... these optimizations will save you teeny tiny amounts... especially when compared with the _huge_ expense of the constant reallocation of the mesh buffers.

And anyway, something in your conversion got messed up because meshes won't do that unless their values are wrong. So the old way had good data and the new way doesn't... and that's in your code somewhere. So as I said, something got shared where it shouldn't be or the math got changed in a subtle way from the old to the new. Dump the vertices to log or something and maybe you'll spot the error.


Well, thank you for your reply. I'm aware that I still create vectors, but what I have shown is the first step to reduce the creation of these Vector3.

The problem is that the only thing I changed in my project is the add of the second method, and use of this second one instead of the original. Nothing else changed. That's why I didn't understand why this is happening. All my mesh is changed at runtime, so even if I dump the values, I don't know which ones are correct. Anyway, I'll try to run both methods and to see the difference. If this changes nothing, then I don't know what can create this problem.

Also, is there a way to recover the float buffer and to change it, instead of using:
[java]this.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));[/java]

because the BufferUtils uses new allocations inside :)

Thank you again!

Something like:

[java]

VertexBuffer verts = getBuffer( Type.Position );

FloatBuffer pb = (FloatBuffer)verts.getData();

pb.clear();

pb.put(…);

…etc…

verts.updateData( pb );

updateBound();

[/java]

1 Like
@pspeed said:
Something like:
[java]
VertexBuffer verts = getBuffer( Type.Position );
FloatBuffer pb = (FloatBuffer)verts.getData();
pb.clear();
pb.put(...);
..etc...
verts.updateData( pb );
updateBound();
[/java]


Thank you very much for your help. I figured it out, it was a mistype at line 13. Also the code you provided works like a charm. Thank you again! I removed any vector creation, and I use only local declared vectors for the mesh, so it's awesome!