Массив структур или структура массивов

Я использую MacMini '11 с AMD Radeon HD 6630M. Я рисую сетку, используя структуру массивов, и все хорошо: 60 кадров в секунду (с использованием CVDisplayLink). Я использую шейдер со встроенными атрибутами. Жизнь хороша. Я перехожу к использованию массива структур (чередующихся), потому что я понимаю, что это предпочтительнее для "современных" графических процессоров. Атрибуты определены в шейдере. Сетка красиво рисуется. Но когда я это делаю, частота кадров падает примерно на 33% (до 40 кадров в секунду). И есть несколько копий этих вызовов. Используя инструменты: Time Profiler, я получаю следующие сравнения:

Using structure of arrays (60 fps)
Running Time Self Symbol Name
3.0ms 0.0% 3.0 0x21b76c4 ATIRadeonX3000GLDriver
2.0ms 0.0% 0.0 gldUpdateDispatch ATIRadeonX3000GLDriver
2.0ms 0.0% 0.0 gleDoDrawDispatchCore GLEngine
2.0ms 0.0% 0.0 glDrawElements_ACC_Exec GLEngine
2.0ms 0.0% 0.0 glDrawElements libGL.dylib
2.0ms 0.0% 0.0 -[Mesh draw] me
Using array of structures (40 fps)
Running Time Self Symbol Name
393.0ms 7.4% 393.0 0x86f6695 ?
393.0ms 7.4% 0.0 gleDrawArraysOrElements_ExecCore GLEngine
393.0ms 7.4% 0.0 glDrawElements_IMM_Exec GLEngine
393.0ms 7.4% 0.0 glDrawElements libGL.dylib
393.0ms 7.4% 0.0 -[Mesh draw] me

Похоже, что libGL принимает решение идти в разных направлениях, и массив структур выглядит так, что драйвер X3000 не вызван. Выполняется ли это в программном эмуляторе Apple? Должен ли я просто оставаться со структурой массивов? Кто-нибудь видел что-то подобное?

Код атрибутов приведен из примера Apple и используется во всем моем приложении (по крайней мере, в 10 других областях) без какого-либо повышения производительности в этих областях. Это из медленной версии. Как я уже упоминал, я использую встроенные атрибуты в быстрой версии, так как данные не чередуются. Отрисовка на месте, просто медленно.

Надеюсь, это то, что вы ищете:

// Step 5 - Bind each of the vertex shader attributes to the programs
[self.meshShader addAttribute:@"inPosition"];
[self.meshShader addAttribute:@"inNormal"];
[self.meshShader addAttribute:@"inTexCoord"];
// Step 6 - Link the program
if([[self meshShader] linkShader] == 0){
 self.posAttribute = [meshShader attributeIndex:@"inPosition"];
 self.normAttribute = [meshShader attributeIndex:@"inNormal"]; 
 self.texCoordAttribute = [meshShader attributeIndex:@"inTexCoord"]; 
...
- (void) addAttribute:(NSString *)attributeName
{
 if ([attributes containsObject:attributeName] == NO){
 [attributes addObject:attributeName];
 glBindAttribLocation(program, [attributes indexOfObject:attributeName], 
 [attributeName UTF8String]);
 }
}

Update: После дальнейшего расследования: 1) Я использую dhpoWare modelObj loader (изменен), и поскольку он использует чередующийся массив структур, он также действует как мой массив структур по производительности - просто не так, как бит. Возможно, я неправильно интерпретирую инструменты. Код modelObj вызывает вызов glDrawElements_IMM_Exec, он также в кольцевом режиме вызывает gleDoDrawDispatchCore. Я не уверен, что он просто накапливает кучу вызовов в glDrawElements_IMM_Exec, а затем взрывает их через gleDoDrawDispatchCore. Не знаю. 2) Я думаю, что у инструментов есть проблемы, так как он показывает, что GLEngine вызывает один из моих неиспользуемых внутренних методов объектов 3ds, который не имеет внешних крючков. Я дважды проверил, установив там точку останова Xcode, и она никогда не срабатывала. Я больше не занимаюсь 3DS.

Думаю, я буду оглядываться и, возможно, споткнуться о ответ. Если бы кто-то дал мне мнение о том, может ли быть массив структур, это было бы оценено.

РЕШЕНИЕ: Я добавил VBO на передний план, и все хорошо. Исходный код пришел из руководства OpenGL ES 2.0, и добавление VBO исправляет мою проблему. Частота кадров при вызовах драйвера 60, 1 мс. Вот код:

glGenVertexArrays(1, &vaoName);
glBindVertexArray(vaoName);
// new - create VBO
glGenBuffers(1, &vboName);
glBindBuffer(GL_ARRAY_BUFFER, vboName);
// Allocate and load position data into the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(struct vertexAttribs) * self.numVertices, 
 vertexAttribData, GL_STATIC_DRAW);
// end of new
********** vtxStride = sizeof(struct vertexAttribs);
//GLfloat *vtxBuf = (GLfloat *)vertexAttribData; // no longer use this
GLfloat *vtxBuf = (GLfloat *)NULL; // use this instead
glEnableVertexAttribArray(self.posAttribute);
glVertexAttribPointer(self.posAttribute, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE,
 vtxStride, vtxBuf);
vtxBuf += VERTEX_POS_SIZE;
glEnableVertexAttribArray(self.normAttribute);
glVertexAttribPointer(self.normAttribute, VERTEX_NORM_SIZE, GL_FLOAT, GL_FALSE,
 vtxStride, vtxBuf);
vtxBuf += VERTEX_NORM_SIZE;
glEnableVertexAttribArray(self.texCoordAttribute);
glVertexAttribPointer(self.texCoordAttribute, VERTEX_TEX_SIZE, GL_FLOAT, GL_FALSE,
 vtxStride, vtxBuf);
...
1 ответ

Структуры массивов для достижения доступа по единице шага в памяти - это эмпирическое правило. Он применяется не только для GPU, но и для CPUS и Co-процессоров, таких как Intel Xeon Phi.

В вашем случае я не верю, что эта часть кода отправляется на GPU, вместо этого потеря производительности связана с доступом к памяти без единичного доступа (CPU в/из памяти).

licensed under cc by-sa 3.0 with attribution.