简体   繁体   English

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

[英]Why do static methods run up memory when creating VBO's?

I have a program that draws six fields on screen that contain around 2000 vertices per.我有一个程序在屏幕上绘制六个字段,每个字段包含大约 2000 个顶点。 To create the VBOs for these I need to use Buffer objects (Int/Float).要为这些创建 VBO,我需要使用 Buffer 对象(Int/Float)。 I need to be able to save the vertex positions etc to an xml file so I want serialize the model objects, convert to B64 and save them as a string.我需要能够将顶点位置等保存到 xml 文件中,所以我想序列化模型对象,转换为 B64 并将它们保存为字符串。 Problem is Buffer objects are not serializable.问题是 Buffer 对象不可序列化。

So, to get around this problem I removed all VBO code from the model objects (it was originally extended from a separate class) and created static methods to create my VBOs.因此,为了解决这个问题,我从模型对象中删除了所有 VBO 代码(它最初是从一个单独的类扩展而来)并创建了静态方法来创建我的 VBO。 So, I call the static method to create the VBO for a model and then return the handles so I can call render, update vertices etc. This, however, has had the effect of seriously ramping up memory when the models are created.因此,我调用静态方法为模型创建 VBO,然后返回句柄,以便我可以调用渲染、更新顶点等。但是,这会在创建模型时严重增加内存。

Why would this be?为什么会这样? Originally the memory usage was not even noticeable.最初的内存使用甚至不明显。 Now it crashes the JVM.现在它使 JVM 崩溃。 I haven't changed any of the code logic, the methods are the same except now they are static and pass back the handles.我没有更改任何代码逻辑,方法是相同的,除了现在它们是静态的并传回句柄。 Do static methods somehow use more memory when creating VBO's?创建 VBO 时,静态方法是否会以某种方式使用更多内存? I thought it would be less?我还以为会少呢? I do clear all buffers after use.使用后我会清除所有缓冲区。 I do dispose of all culled models.我确实处理了所有剔除的模型。

Edit: Here is the Render class that contains the static methods编辑:这是包含静态方法的 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(){

  }

}

The static calls are made in the constructor of the fields (array of tile objects) as follows:静态调用在字段(平铺对象数组)的构造函数中进行,如下所示:

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;

}

I believe the answer is that static classes do not provide GC.我相信答案是静态类不提供 GC。 With all of the data being passed around creating VBOs the G really starts to pile up...随着所有数据被传递创建 VBO,G 真的开始堆积起来......

Your code looks very confusing, you should spend some time in order to better understand how OpenGL works and make it cleaner and more readable.您的代码看起来很混乱,您应该花一些时间来更好地理解 OpenGL 的工作原理并使其更清晰、更具可读性。 I'd suggest you to take inspiration from this sample .我建议你从这个样本中获得灵感。

Few considerations:几点考虑:

  • you don't need static at all你根本不需要静态
  • I don't know lwjgl, but I guess it needs direct buffers and you have no guarantee they are going to be removed by the garbage collector, so you should allocate them by yourself and free them when you don't need them anymore.我不知道 lwjgl,但我猜它需要直接缓冲区,你不能保证它们会被垃圾收集器删除,所以你应该自己分配它们并在你不再需要它们时释放它们。 I created a small class to deallocate direct buffers, taken from JM3 here我创建了一个小类来释放直接缓冲区,取自 JM3 here
  • avoid redundancy by saving the opengl resources names inside vboINDEXES .通过在vboINDEXES保存 opengl 资源名称来避免冗余。 You are already using vboHandles directly您已经vboHandles直接使用vboHandles
  • if the dimension of your buffers doesn't change, allocate them once and keep them ( fbData , fbNorm , fbTex ), don't need to clear() them too如果缓冲区的维度没有改变,分配一次并保留它们( fbDatafbNormfbTex ),也不需要clear()它们
  • for this reason, when you updateNormals() don't instantiate a new buffer, use the one already instantiated at the begin因此,当您updateNormals()不实例化新缓冲区时,请使用在开始时已实例化的缓冲区
  • by a logic point of view, IBO_INDEX should not be part of the vboINDEXES从逻辑的角度来看, IBO_INDEX不应该是vboINDEXES一部分
  • when you call glVertexAttribPointer pass as first argument the variable holding the attribute index, such as POSITION_INDEX当您调用glVertexAttribPointer将保存属性索引的变量作为第一个参数传递,例如POSITION_INDEX

ps: the plural of index is indices ps:index的复数是indexes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM