Allocate exact-sized interleaved (strided) buffers#10017
Conversation
a35232c to
eac2a19
Compare
|
@mhansen the unit tests seem to fail under ASAN. |
|
Whoops, sorry for the noise. I'll look at the tests tomorrow. |
| const uint8_t slot = mAttributes[attributeIndex].buffer; | ||
| const size_t end = offset + mVertexCount * stride; | ||
| const size_t elementSize = Driver::getElementTypeSize(mAttributes[attributeIndex].type); | ||
| const size_t end = offset + (mVertexCount - 1) * stride + elementSize; |
There was a problem hiding this comment.
This has an underflow issue. e.g., if mVertexCount == 0, mVertexCount - 1 will underflow for the type uint32_t.
There was a problem hiding this comment.
On #10009 I asked about this:
I see there's a check that mVertexCount > 0 here:
. Can we rely on that? Or is it stripped out in some builds?There was a problem hiding this comment.
Ah yeah we can rely on it then. Could you add comments about why it's safe?
| const uint8_t slot = mAttributes[attributeIndex].buffer; | ||
| const size_t end = offset + mVertexCount * stride; | ||
| const size_t elementSize = Driver::getElementTypeSize(mAttributes[attributeIndex].type); | ||
| const size_t end = offset + (mVertexCount - 1) * stride + elementSize; |
There was a problem hiding this comment.
The correct calculation is mVertexCount * stride.
Indeed the existing code was wrong because it added the "offset" to the size calculation, the offset should be irrelevant. If we compare this to a std::vector<Foo>, stride plays the role of sizeof(Foo) and mVertexCount plays the role of .size(). offset plays the role of offsetof(Foo, field), it shouldn't be part of the size calculation.
There was a problem hiding this comment.
D'oh. You're right, I completely bamboozled myself here.
There was a problem hiding this comment.
The simplification is offset + elementSize = stride, so offset + (mVertexCount - 1) * stride + elementSize collapses to stride + (mVertexCount - 1) * stride collapses to mVertexCount * stride. Sorry, I did this in an accretive not simplififying way.
There was a problem hiding this comment.
Wait, no, I remember why I did this - I was worried about if attributes are struct-of-array. While in this case (array of struct), mVertexCount * stride is correct, filament also seems to support vertices that are offset, e.g. here we have position at bytes 0-23 and color at bytes 23-35:
Lines 72 to 75 in 180e91f
If we used mVertexCount * stride, this would ignore colour's starting offset of 24. And the max-sized attribute would be computed as 24, so we'd allocate a 24-byte buffer.
I've added a test demonstrating this. And also another test for what happens with 32-byte-padded rows (ensuring that we allocate for the padding too)
There was a problem hiding this comment.
good catch! I completely agree.
This demonstrates the issue: oversized buffer. In the next commit, we will fix this. Towards google#10009
| const uint8_t slot = mAttributes[attributeIndex].buffer; | ||
| const size_t end = offset + mVertexCount * stride; | ||
| const size_t elementSize = Driver::getElementTypeSize(mAttributes[attributeIndex].type); | ||
| const size_t end = offset + (mVertexCount - 1) * stride + elementSize; |
There was a problem hiding this comment.
good catch! I completely agree.
| const size_t end = offset + mVertexCount * stride; | ||
| const size_t elementSize = Driver::getElementTypeSize(mAttributes[attributeIndex].type); | ||
| const size_t end = offset + (mVertexCount - 1) * stride + elementSize; | ||
| const size_t rounded = ((end + stride - 1) / stride) * stride; |
There was a problem hiding this comment.
yes perfect, this works.
Fixes #10009