Я ищу совет по памяти/производительности, какой подход лучше.
Допустим, у меня есть 4 атрибута для сетки.
Vertex 3f
Normal 3f
TexCoords 2f
jointID 4i [Integer Joint Indices For Skeleton Animation]
И мне нужно, чтобы они были в памяти процессора, так как их можно изменить в любое время.
Лучше ли
a.Создайте 4 отдельных буфера для каждого компонента
//3,2,4 are the strides i.e vertex is 3 floats,texCoord is 2 floats so on
FloatBuffer vertices=BufferUtils.createFloatBuffer(numOfVertices*3);
FloatBuffer normals=BufferUtils.createFloatBuffer(numOfVertices*3);
FloatBuffer texCoords=BufferUtils.createFloatBuffer(numOfVertices*2);
IntBuffer vertexJoints=BufferUtils.createIntBuffer(numOfVertices*4);
Или
b. Создайте большой байтовый буфер с достаточной емкостью для хранения всех 4 атрибутов и создайте отдельные представления Float/Int Buffer Views для каждого из атрибутов.
ByteBuffer meshData=BufferUtils.createByteBuffer(((numOfVertices*3)+(numOfVertices*3)+(numOfVertices*2)+(numOfVertices*4))*4); //*4 because both float/int is 4 bytes
FloatBuffer vertices=meshData.position(0).limit(endVertexByte).asFloatBuffer();
FloatBuffer normals=meshData.position(endVertexByte).limit(endNormalByte).asFloatBuffer();
FloatBuffer texCoords=meshData.position(endNormalByte).limit(endTexCoordByte).asFloatBuffer();
IntBuffer jointIDs=meshData.position(endTexCoordByte).limit(endJointIndexByte or end of buffer in this case).asIntBuffer();
Из документов все методы BufferUtils создают directBuffer, который хранится в собственной памяти, и все, хотя второй подход создает буфер большего размера [поскольку мы умножаем на 4], чем все отдельные буферы атрибутов вместе взятые, создает только один большой кусок собственной памяти по сравнению с 4 отдельными областями памяти в первом подходе.
Но это только мое мнение, мысли?




Не будет никакой разницы в производительности, если мы просто посмотрим, как вы записываете (новые) данные в эти буферы с точки зрения ЦП. В любом случае у вас есть только четыре последовательных области памяти, к которым вы подключаетесь при обновлении данных атрибутов вершин. Просто в первом случае эти области памяти смещены на неизвестное количество байтов (поскольку распределитель памяти JVM будет выделять каждую область отдельно), а во втором случае вы знаете смещение между каждыми двумя последовательными областями памяти, потому что вы выделили эти в одном выделении буферной памяти JVM.
Однако разница будет заключаться в том, как вы на самом деле сопоставляете эти области памяти хоста на стороне клиента с памятью буферных объектов OpenGL на стороне сервера. Я полагаю, что как только вы обновите память на стороне хоста, вы фактически загрузите ее в буферные объекты OpenGL на стороне сервера и не будете использовать указатели памяти на стороне клиента/узла для команд спецификации вершин OpenGL (что доступно только в контексте совместимости с OpenGL).
В этом случае создание четырех отдельных смежных областей памяти на стороне клиента потребует от вас выполнения четырех команд загрузки в буферную память OpenGL (glBufferSubData()) и драйвера OpenGL для выполнения четырех отдельных загрузок с прямым доступом к памяти (DMA) через PCIe.
В случае, когда у вас есть только одна непрерывная область памяти на стороне клиента, вы можете выполнить только один вызов glBufferSubData() для всех данных атрибутов вершины в один буферный объект, где вы просто используете байтовые смещения в вызовах спецификации вершин OpenGL (например, для glVertexAttribPointer()).
Другая возможность также состоит в том, чтобы не выделять память хоста на стороне клиента самостоятельно, а иметь видимые для хоста, постоянно отображаемые буферные области, предоставляемые вам OpenGL (glBufferStorage() + glMapBufferRange()), в которые вы затем можете записать и явно сбросить или позволить им неявно/ когерентно обновляться драйвером OpenGL.
Как и в случае с четырьмя отдельными областями памяти на стороне клиента, вы также, скорее всего, заплатите за «четыре отдельные передачи DMA», когда будете отображать и очищать четыре отдельные области буферных объектов OpenGL.
Так что, в конце концов, важно не то, есть ли у вас одно или четыре представления буфера NIO в памяти на стороне клиента, а то, сколько объектов буфера OpenGL на стороне сервера вы сопоставляете с этими областями памяти — чем меньше, тем лучше.
Говоря об упаковке всего, чередующийся glBuffer лучше, чем 4 отдельных буфера, когда речь идет о скорости чтения графического процессора, или это отдельный вопрос для другой темы?
Я не совсем уверен, что мне нужно время для экспериментов, и если мои выводы совпадают с вашими, я отмечу это
Таким образом, второй подход лучше, если у вас есть только один glBuffer в случае interleavedBuffer [где мы указываем шаги и смещения в vertexAttribPointer], но не будет иметь значения, если у вас есть 4 отдельных объекта glBuffer, если вы хотите сохранить атрибуты отдельно, это вывод верный? glMapBuffer нельзя эффективно использовать в многопоточной настройке, где для работы вызовов требуется переключение контекста, и единственный вариант — сначала загрузить данные вершины в процессор, а затем создать glBuffers в основном потоке. Но с точки зрения памяти jni я делаю некоторую экономию?