Бавно изобразяване след голямо прехвърляне от GPU към RAM?

Опитвах се да изобразя облак от точки (›100 милиона точки), прехвърлих всички данни към GPU и просто използвах името на буфера за достъп до него. Всичко работи добре, докато внедря функция, която изисква от мен да прехвърля всички данни обратно в RAM.

Ето как предавам данните на GPU:

glBindVertexArray(vao);

// some data
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * GetSize()  * 3, &vertices[0], GL_STATIC_DRAW); // pos

// some attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); // pos

...
// some other code
...

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

glDisableVertexAttribArray(0);

// Clear the contents in the RAM
vertices.clear();
vertices.shrink_to_fit();

След това имах нужда от функция в даден момент, за да върна данните, за да запазя промените, ето какво направих:

// restore data back to RAM
// this code was called for >4000 times

glBindBuffer(GL_ARRAY_BUFFER, c.vbo);
c.vertices.clear();
c.vertices.resize(c.sizeg);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * c.sizeg, &c.vertices[0].position.x);

След това програмата ще виси всеки път, когато трябва да изобразя този облак от точки.

Премахнах всички други кодове, за да тествам само този код, и тази част от кода за пренос на данни е точно причината за забавянето

Имам чувството, че има огромно количество копиране на данни вътре в графичния процесор всеки път, когато се опитам да изобразя данните, които са го причинили да виси. Въпреки това, след като прехвърлих обратно данните от GPU към RAM, данните, които първоначално бяха в GPU, остават недокоснати, мислех, че изобразяването трябва да е също толкова гладко, колкото преди, но не е така.

Променено ли е нещо в състоянието на OpenGL, което е причинило това забавяне?


person Zhou Zhi Hua    schedule 25.09.2020    source източник
comment
всеки път, когато се случи забавяне, забелязах драстично намаляване на 3D и производителността на копиране на графичния процесор в Windows Resource Manager, което ми дава намек, че моят графичен процесор трябва да прави нещо друго по време на забавянето вместо чертежа   -  person Zhou Zhi Hua    schedule 25.09.2020


Отговори (1)


Дадохте обещание на OpenGL. Тогава ти наруши обещанието си. Така че OpenGL ви наказа за това.

Казахте на OpenGL това за това как ще използвате този буферен обект:

GL_STATIC_DRAW

Това означава, че сте казали на OpenGL, че ще пишете в буфера (DRAW), но няма да четете от него. И ти каза, че ще му пишеш рядко (STATIC). Така че изпълнението на OpenGL послушно постави паметта на буферния обект на място, което е оптимално за достъп до GPU, но не и за достъп до CPU.

След това четете от него. Направихте нещото, което обещахте на OpenGL, че няма да направите.

Сега хората (много хора) непрекъснато нарушават тези обещания към внедряването на OpenGL. Толкова много реализации на практика спряха да им вярват. Тоест, вместо да слушат какво казвате, че ще правите с буфера, те обръщат внимание на това, което всъщност правите.

Реализацията видя, че четете от буфера. Така че предполага, че възнамерявате да правите това с известна редовност. Като такъв, той сега прехвърля паметта на буфера на място, което е по-оптимално за четене на CPU... но по-малко оптимално за четене на GPU.

Модерният OpenGL има API за създаване на буферни обекти, където лъжата вече не е разрешена. Вие определяте кои операции можете да използвате върху буфера и реализацията на OpenGL ще ви задържи, като направи всички други достъпи неуспешни.

Ако използвате API за буферно съхранение, тогава е много вероятно опитът за четене от буфера с glGetBufferSubData няма да накара API просто да разбърка паметта. Предотвратяването на разместването на хранилище е половината от смисъла на този API. Ако все още получавате този забавящ ефект от внедряването си, може да не можете да направите много, за да го спрете в OpenGL.

Най-ефективната алтернатива (различна от използването на Vulkan, където имате пълен контрол върху паметта) би била просто да не се опитвате да я четете от OpenGL изобщо. Тоест, не третирайте съхранението на GPU като нещо, което можете просто да прочетете, когато имате нужда от някакви данни. Ако трябва да използвате данните от процесора, запазете ги там. Тоест, запазете копие от него и в паметта на процесора.

person Nicol Bolas    schedule 25.09.2020