LWJGL: управление буферной памятью

Я ищу совет по памяти/производительности, какой подход лучше.

Допустим, у меня есть 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 отдельными областями памяти в первом подходе.

Но это только мое мнение, мысли?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
265
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Не будет никакой разницы в производительности, если мы просто посмотрим, как вы записываете (новые) данные в эти буферы с точки зрения ЦП. В любом случае у вас есть только четыре последовательных области памяти, к которым вы подключаетесь при обновлении данных атрибутов вершин. Просто в первом случае эти области памяти смещены на неизвестное количество байтов (поскольку распределитель памяти JVM будет выделять каждую область отдельно), а во втором случае вы знаете смещение между каждыми двумя последовательными областями памяти, потому что вы выделили эти в одном выделении буферной памяти JVM.

Однако разница будет заключаться в том, как вы на самом деле сопоставляете эти области памяти хоста на стороне клиента с памятью буферных объектов OpenGL на стороне сервера. Я полагаю, что как только вы обновите память на стороне хоста, вы фактически загрузите ее в буферные объекты OpenGL на стороне сервера и не будете использовать указатели памяти на стороне клиента/узла для команд спецификации вершин OpenGL (что доступно только в контексте совместимости с OpenGL).

В этом случае создание четырех отдельных смежных областей памяти на стороне клиента потребует от вас выполнения четырех команд загрузки в буферную память OpenGL (glBufferSubData()) и драйвера OpenGL для выполнения четырех отдельных загрузок с прямым доступом к памяти (DMA) через PCIe. В случае, когда у вас есть только одна непрерывная область памяти на стороне клиента, вы можете выполнить только один вызов glBufferSubData() для всех данных атрибутов вершины в один буферный объект, где вы просто используете байтовые смещения в вызовах спецификации вершин OpenGL (например, для glVertexAttribPointer()).

Другая возможность также состоит в том, чтобы не выделять память хоста на стороне клиента самостоятельно, а иметь видимые для хоста, постоянно отображаемые буферные области, предоставляемые вам OpenGL (glBufferStorage() + glMapBufferRange()), в которые вы затем можете записать и явно сбросить или позволить им неявно/ когерентно обновляться драйвером OpenGL. Как и в случае с четырьмя отдельными областями памяти на стороне клиента, вы также, скорее всего, заплатите за «четыре отдельные передачи DMA», когда будете отображать и очищать четыре отдельные области буферных объектов OpenGL.

Так что, в конце концов, важно не то, есть ли у вас одно или четыре представления буфера NIO в памяти на стороне клиента, а то, сколько объектов буфера OpenGL на стороне сервера вы сопоставляете с этими областями памяти — чем меньше, тем лучше.

Таким образом, второй подход лучше, если у вас есть только один glBuffer в случае interleavedBuffer [где мы указываем шаги и смещения в vertexAttribPointer], но не будет иметь значения, если у вас есть 4 отдельных объекта glBuffer, если вы хотите сохранить атрибуты отдельно, это вывод верный? glMapBuffer нельзя эффективно использовать в многопоточной настройке, где для работы вызовов требуется переключение контекста, и единственный вариант — сначала загрузить данные вершины в процессор, а затем создать glBuffers в основном потоке. Но с точки зрения памяти jni я делаю некоторую экономию?

Sync it 13.12.2020 15:34

Говоря об упаковке всего, чередующийся glBuffer лучше, чем 4 отдельных буфера, когда речь идет о скорости чтения графического процессора, или это отдельный вопрос для другой темы?

Sync it 13.12.2020 15:37

Я не совсем уверен, что мне нужно время для экспериментов, и если мои выводы совпадают с вашими, я отмечу это

Sync it 14.12.2020 06:49

Другие вопросы по теме