0

I have a really tough time coming up with a good title for this question, so please propose a new one if you can come up with a good one. Perhaps we can do it after solving my problem... Now to it:

I am currently porting code to use glMultiDrawElements instead of several calls to glDrawElements. For this, I am using something I call sequenceList, which is just a std::pair of two vectors, one unsigned int and one int.

  // Sequence of vectors defining < StartIndex per primitive, Number of vertices per primitive >
  using SequenceList = std::pair< std::vector< unsigned int >, std::vector< GLsizei > >;

To be able to use only one draw function for all variants (ever though there is just one primitive to draw using one index list) I've generalized the function call to always use a sequenceList object, but with only one index value. This means that I use glMultiDrawElements for all indexed draw calls (and glMultiDrawArrays for non-indexed draw calls).

void GLVBOProbe::draw( unsigned startIndex, int numberOfIndicesToDraw ) const
{
  VertexArray::SequenceList sequences = { { startIndex }, { numberOfIndicesToDraw } ) };
  GLVBOLib::the().draw( name_, sequences );
}

The draw call then binds the array/normal/texture and index (if needed) buffers. The call to glMultiDrawElements then looks like

glMultiDrawElements( info.mode, sequences.second.data(), GL_UNSIGNED_INT, (const GLvoid **)sequences.first.data(), (GLsizei)sequences.second.size() );

In my test case, I am rendering 75000 indices starting at 0. So the sequences.second contains 75000 values, and sequences.first contains only one value: 0.

Now to the problem: This crashes with a

First-chance exception at 0x000000004735E56B in Application.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

I have tried to find the problem in many different ways, and have finally been able to find a variant that doesn't crash, and the variant baffles me.

If I copy the vector to a new local variable, it works. Since the vector is of size 1, it wouldn't be a problem to just to that, but it feels less fun to do it every frame for 3000 index offsets.

// Non crashing version
std::vector< unsigned int > indicesOffset = sequences.first;
// using sequence and indices
glMultiDrawElements( info.mode, sequences.second.data(), GL_UNSIGNED_INT, (const GLvoid **)indicesOffset.data(), (GLsizei)sequences.second.size() );

A colleague of mine says it might have to do with the memory alignment of the vector, saying I have to use boost's boost::aligned_allocator to get it to work.

AzP
  • 1,081
  • 1
  • 16
  • 27
  • and if you use a reference? `std::vector< unsigned int >& indicesOffset = sequences.first;` – ratchet freak Dec 12 '14 at 11:11
  • 1
    It might have something to do with this question http://stackoverflow.com/questions/8719287/using-glmultidrawelements-in-64bit-os and the fact that it doesn't crash when copying the vector is purely coincidental. It's just because there is nothing in the memory _after_ the newly created vector. Instead of having a vector of ints, I should have a vector of int pointers. – AzP Dec 12 '14 at 11:11
  • 1
    are you one 64 bit? if so then I can indeed see the problem with the cast to `GLVoid**` from `unsigned int*` – ratchet freak Dec 12 '14 at 11:26
  • Yes, I'm on 64 bit. I also think that this is the issue. – AzP Dec 12 '14 at 11:30

2 Answers2

1

sizeof(GLvoid*) is not guaranteed to be equal to sizeof(unsigned int). You can however replace unsigned int with GLintptr​ which is guaranteed to be the same size as a pointer.

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • Thank you, the GLintptr is also an alternative:https://www.opengl.org/discussion_boards/showthread.php/182391-How-to-use-glMultiDrawElements-and-glDrawElements – AzP Dec 12 '14 at 11:34
  • Wait.. a GLVoid* must be the same size as a (unsigned int*), pointers are always the same size on a platform, aren't they? – AzP Dec 12 '14 at 11:35
  • Oh, sorry, I misread your answer as (unsigned int*) and not (unsigned int). My bad. – AzP Dec 12 '14 at 11:38
0

The issue seems to be that I am on a 64 bit platform, and glMultiDrawArrays expect pointers to ints, not actual ints.

More is described here.

https://www.opengl.org/discussion_boards/showthread.php/182391-How-to-use-glMultiDrawElements-and-glDrawElements

A solution to this is to use GLintptr as the type, which describes a byte offset in the array. So each position in the array also have to have it's pointer size multiplied with itself.

AzP
  • 1,081
  • 1
  • 16
  • 27