为什么静态方法在创建VBO时会占用内存?

时间:2016-03-22 15:49:59

标签: java memory-management lwjgl vbo

我有一个程序在屏幕上绘制六个字段,每个字段包含大约2000个顶点。要为这些创建VBO,我需要使用Buffer对象(Int / Float)。我需要能够将顶点位置等保存到xml文件中,所以我想序列化模型对象,转换为B64并将它们保存为字符串。问题是缓冲区对象不可序列化。

因此,为了解决这个问题,我从模型对象中删除了所有VBO代码(它最初是从一个单独的类扩展而来的),并创建了静态方法来创建我的VBO。因此,我调用静态方法为模型创建VBO,然后返回句柄,以便我可以调用渲染,更新顶点等。但是,这会产生在创建模型时严重增加内存的效果。

为什么会这样?最初内存使用量甚至都不明显。现在它崩溃了JVM。我没有改变任何代码逻辑,方法是相同的,除了现在它们是静态的并传回句柄。在创建VBO时,静态方法是否会以某种方式使用更多内存?我以为会少一点?我在使用后清除所有缓冲液。我处理了所有淘汰的模型。

修改 这是包含静态方法的Render类

package Drawing;

import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW;
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glBufferSubData;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;

/**
* This class calls all vbo functions in a static way which allows me to 
 * separate the Int/FloatBuffers from the model classes like Cube and
 * Quad.  Int/FloatBuffers will not serialize so the Cube/Quad classes
 * cannot be saved to file.  Keeping them static and separated 
 * will overcome this problem.
 */
public class Render {

static int VERTEXCOUNT = 0;//((QUAD_SIZE * QUAD_SIZE) * 12);
static FloatBuffer fbData = null;//BufferUtils.createFloatBuffer(VERTEXCOUNT);
static FloatBuffer fbNorm = null;//BufferUtils.createFloatBuffer(VERTEXCOUNT);
static FloatBuffer fbtex = null;//BufferUtils.createFloatBuffer((VERTEXCOUNT / 12) * 8);
static IntBuffer Indices = null;
private static int _VAOHandle = 0;
private static IntBuffer vboHandles;

static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
static final int NORMALS_IDX = 1;
static final int TEXTURE_IDX = 2;
static final int IBO_IDX = 3;

public static VBOIndexes createVBO(int QUAD_SIZE,
        float[] vertBuffer,
        float[] normals,
        float[] UVs,
        int[] idxBuffer)  throws Exception {

    VBOIndexes vboINDEXES = new VBOIndexes();

    try{

        VERTEXCOUNT = (int) ((QUAD_SIZE * QUAD_SIZE) * 12);
        fbData = BufferUtils.createFloatBuffer(VERTEXCOUNT);
        fbNorm = BufferUtils.createFloatBuffer(VERTEXCOUNT);
        fbtex = BufferUtils.createFloatBuffer((VERTEXCOUNT / 12) * 8);
        Indices = BufferUtils.createIntBuffer(VERTEXCOUNT / 2);


        _VAOHandle = glGenVertexArrays();

        vboINDEXES.VAOHandle = _VAOHandle;

        System.out.println("VAOHandle is : " + _VAOHandle);

        glBindVertexArray(_VAOHandle);

        vboHandles =  BufferUtils.createIntBuffer(4);
        glGenBuffers(vboHandles);

        vboINDEXES.idxPOS = vboHandles.get(POSITION_INDEX);
        vboINDEXES.idxNORM = vboHandles.get(NORMALS_IDX);
        vboINDEXES.idxTEX = vboHandles.get(TEXTURE_IDX);
        vboINDEXES.idxIBO = vboHandles.get(IBO_IDX);

        //FloatBuffer fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
        fbData.put(vertBuffer);
        fbData.rewind(); // rewind, otherwise LWJGL thinks our buffer is empty

        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX));

        glBufferData(GL_ARRAY_BUFFER, fbData, GL_DYNAMIC_DRAW);
        fbData.clear(); //don't need this anymore  


        //populate the normals buffer
        //FloatBuffer fbNorm = BufferUtils.createFloatBuffer(normalsBuffer.length );
        fbNorm.put(normals);
        fbNorm.rewind();
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(NORMALS_IDX)); //the vertex data
        glBufferData(GL_ARRAY_BUFFER, fbNorm, GL_STATIC_DRAW);
        fbNorm.clear(); //don't need this anymore 

        //populate the texture buffer

        fbtex.put(UVs);  
        fbtex.rewind();
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX)); 
        glBufferData(GL_ARRAY_BUFFER, fbtex, GL_DYNAMIC_DRAW);
        fbtex.clear(); //don't need this anymore  

        Indices.put(idxBuffer);
        Indices.rewind();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));

        glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices, GL_STATIC_DRAW);

        glEnableVertexAttribArray(POSITION_INDEX);
        glEnableVertexAttribArray(NORMALS_IDX);
        glEnableVertexAttribArray(TEXTURE_IDX);

        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); 
        glVertexAttribPointer(0,3, GL_FLOAT, false,0,0);    

        //normals
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(NORMALS_IDX));
        glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);  

        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX));
        glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0); 

        //bind IBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));

        glBindVertexArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);


        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        Indices.clear();

    }catch (Exception ex){
        System.out.println("createVBO: " + ex.getMessage());
        throw ex;
    }
    return vboINDEXES;
}

public static VBOIndexes createLineVBO( float[] vertBuffer,
                            int[] idxBuffer)  throws Exception {

    VBOIndexes vboINDEXES = new VBOIndexes();

    try{

        fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
        Indices = BufferUtils.createIntBuffer(vertBuffer.length / 2);

        _VAOHandle = glGenVertexArrays();

        vboINDEXES.VAOHandle = _VAOHandle;

        glBindVertexArray(_VAOHandle);

        vboHandles =  BufferUtils.createIntBuffer(4);
        glGenBuffers(vboHandles);

        vboINDEXES.idxPOS = vboHandles.get(POSITION_INDEX);
        vboINDEXES.idxIBO = vboHandles.get(IBO_IDX);

        fbData.put(vertBuffer);
        fbData.rewind(); // rewind, otherwise LWJGL thinks our buffer is empty

        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX));

        glBufferData(GL_ARRAY_BUFFER, fbData, GL_STATIC_DRAW);
        fbData.clear(); //don't need this anymore  

        //IntBuffer Indices = BufferUtils.createIntBuffer(idxBuffer.length);
        Indices.put(idxBuffer);
        Indices.rewind();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));
        //Util.checkGLError();
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices, GL_STATIC_DRAW);

        glEnableVertexAttribArray(POSITION_INDEX);
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); 
        glVertexAttribPointer(0,3, GL_FLOAT, false,0,0);    

        //bind IBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));

        Indices.clear();

        glBindVertexArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        //Util.checkGLError();

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    }catch (Exception ex){
        System.out.println("createVBO: " + ex.getMessage());
        throw ex;
    }
    return vboINDEXES;
}

  public static void updateVertices(int offset,
                            float[] vertBuffer,
                            int idxPOS)
  {
      //populate the vertex buffer
      FloatBuffer fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
      fbData.put(vertBuffer);   
      fbData.rewind();
      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); //the vertex data
      glBindBuffer(GL_ARRAY_BUFFER, idxPOS);
      glBufferSubData(GL_ARRAY_BUFFER, offset, fbData);
      fbData.clear(); //don't need this anymore  
  }

  public static void updateNormals(int offset,
                              float[] normals,
                              int idxNORM)
  {

      //populate the vertex buffer
      FloatBuffer fbData = BufferUtils.createFloatBuffer(normals.length);
      fbData.put(normals);
      fbData.rewind();
      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get( NORMALS_IDX)); //the vertex data
      glBindBuffer(GL_ARRAY_BUFFER, idxNORM);
      glBufferSubData(GL_ARRAY_BUFFER, 0, fbData);
      fbData.clear(); //don't need this anymore  
  }

  public static void updateTexture(int offset,
          float[] UVs,
          int idxTEX)
  {

      //populate the texture buffer
      FloatBuffer fbtex = BufferUtils.createFloatBuffer(UVs.length);
      fbtex.put( UVs );
      fbtex.rewind();

      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX)); //the texture data
      glBindBuffer(GL_ARRAY_BUFFER, idxTEX);
      glBufferSubData(GL_ARRAY_BUFFER, offset, fbtex);
      fbtex.clear(); //don't need this anymore  
  }

  public Render(){

  }

}

静态调用是在字段的构造函数(tile对象数组)中进行的,如下所示:

public Quad(Map<Integer, Cube> c, int SIZE) throws Exception{
//public Quad(ArrayList<Cube> c, int SIZE) throws Exception{
    QUAD_SIZE = SIZE;
    initArrays();
    initVBOData(SIZE);
    createVBO();
    cubes = c;

}

2 个答案:

答案 0 :(得分:0)

我相信答案是静态类不提供GC。随着所有数据传递创建VBO,G真的开始堆积......

答案 1 :(得分:0)

您的代码看起来很混乱,您应该花一些时间来更好地了解OpenGL的工作原理,使其更清晰,更易读。 我建议你从this sample中获取灵感。

很少考虑:

  • 你根本不需要静电
  • 我不知道lwjgl,但我想它需要直接缓冲区,你不能保证它们会被垃圾收集器删除,所以你应该自己分配它们并在你没有时将它们释放出去#39不再需要他们了。我创建了一个小类来解除分配直接缓冲区,取自JM3 here
  • 通过在vboINDEXES内保存opengl资源名称来避免冗余。您已经直接使用vboHandles
  • 如果缓冲区的维度没有变化,请分配一次并保留它们(fbDatafbNormfbTex),不需要{ {1}}他们也是
  • 因此,当clear()未实例化新缓冲区时,请使用已在开始时实例化的缓冲区
  • 从逻辑角度来看,updateNormals()不应该是IBO_INDEX
  • 的一部分
  • 当您调用vboINDEXES作为第一个参数传递包含属性索引的变量时,例如glVertexAttribPointer

ps:索引的复数是 indices