Использование glMultiDrawElements в 64-битной ОС - PullRequest
4 голосов
/ 04 января 2012

Я недавно мигрировал из 32-битной среды в 64-битную, и она плавно отошла от одной проблемы: glMultiDrawElements использует некоторые массивы, которые не работают без некоторой настройки под 64-битной ОС.

glMultiDrawElements( GL_LINE_LOOP, fCount_, GL_UNSIGNED_INT,
                     reinterpret_cast< const GLvoid** >( iOffset_ ),
                     mesh().faces().size() );

Я использую VBO как для вершин, так и для индексов вершин. fCount_ и iOffset_ являются массивами GLsizei. Поскольку буфер связан с GL_ELEMENT_ARRAY_BUFFER, элементы iOffset_ используются как байтовые смещения от начала VBO. Это прекрасно работает под 32-битной ОС.

Если изменить glMultiDrawElements на glDrawElements и поместить его в цикл, он отлично работает на обеих платформах:

int offset = 0;
for ( Sy_meshData::Faces::ConstIterator i  = mesh().faces().constBegin();
                                        i != mesh().faces().constEnd(); ++i ) {
    glDrawElements( GL_LINE_LOOP, i->vertexIndices.size(), GL_UNSIGNED_INT,
                    reinterpret_cast< const GLvoid* >( sizeof( GLsizei ) * offset ) );
    offset += i->vertexIndices.size();
 }

Я думаю, что я вижу, что OpenGL читает 64-битные куски iOffset_, приводящие к большим числам, но glMultiDrawElements не поддерживает ни один тип шире, чем 32-битный (GL_UNSIGNED_INT), поэтому я не уверен, как исправить это.

Кто-нибудь еще имел эту ситуацию и решил ее? Или я справляюсь с этим совершенно неправильно и мне просто повезло на 32-битной ОС?

Обновление

Замена моего существующего кода на:

typedef void ( *testPtr )( GLenum mode, const GLsizei* count, GLenum type,
                           const GLuint* indices, GLsizei primcount );
testPtr ptr = (testPtr)glMultiDrawElements;
ptr( GL_LINE_LOOP, fCount_, GL_UNSIGNED_INT, iOffset_, mesh().faces().size() );

Результат точно такой же.

Ответы [ 2 ]

5 голосов
/ 04 января 2012

Простая причина в том, что glMultiDrawElements ожидает не массив целочисленных смещений (32 бита на вашей платформе), а массив указателей (64 бита на вашей платформе), интерпретируемых как смещения буфера.

Но вы просто приводите массив (или указатель на) целых чисел к массиву (или указателю на) указателей, что не сработает, поскольку функция теперь просто переосмысливает ваши n последовательных 32-битных значений какn последовательных 64-битных значений.Конечно, это работает для glDrawElements, потому что вы просто приводите одно целое число в один указатель, который, по существу, преобразует ваше 32-битное значение в 64-битное значение.массив, но каждое отдельное значение в этом массиве смещений:

std::vector<void*> pointers(mesh().faces().size());
for(size_t i=0; i<pointers.size(); ++i)
    pointers[i] = static_cast<void*>(iOffset_[i]);
glMultiDrawElements( GL_LINE_LOOP, fCount_, GL_UNSIGNED_INT, 
                     &pointers.front(), mesh().faces().size() );

Или лучше, просто сохраняйте свои смещения как указатели вместо целых с самого начала.

0 голосов
/ 04 января 2012

Вы сталкиваетесь с проблемами, которые я подробно рассмотрел в https://stackoverflow.com/a/8284829/524368

Я предлагаю вам последовать моему предложению в самом конце ответа и не пытаться преобразовать свои числа во что-то, что компилятор считает указателем, а преобразовать сигнатуру функции в нечто, принимающее число.

Обратите внимание, что в случае glMultiDrawElements первое косвенное обращение направляется не в VBO, а в память клиента. Таким образом, подпись, к которой нужно применить, например:

void myglMultiDrawElementsOffset(GLenum mode,
    const GLsizei * count,
    GLenum type,
    const uintptr_t * indices,
    GLsizei  primcount);
...