Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guarantee typed array compatible byte alignment #167

Closed
pjcozzi opened this issue Oct 28, 2013 · 12 comments
Closed

Guarantee typed array compatible byte alignment #167

pjcozzi opened this issue Oct 28, 2013 · 12 comments

Comments

@pjcozzi
Copy link
Member

pjcozzi commented Oct 28, 2013

This is a serious (but easy to fix) issue that we need to consider ASAP.

We want a glTF implementation to be able to create a single arraybuffer from a glTF buffer and then use the glTF bufferView and accessor (CC #161) to create a typed array view (e.g., Float32Array) into that arraybuffer without copying it. However, to do so, the byte offset of the typed array view must be a multiple of the size of the type (e.g., 4 for Float32Array). For homogenous arraybuffers where every element is the same type, this, of course, just works, but for heterogeneous arraybuffers, it does not work in the general case.

The glTF spec needs to guarantee this byte alignment and the converter needs to add the required padding, which will only have a trivial impact on the total size.

JSON example

Say we have this buffer view:

"bufferView_393": {
  "buffer": "anim.bin",
  "byteLength": 36608,
  "byteOffset": 46728
}

which is then referenced from this animation parameter

"translation": {
  "bufferView": "bufferView_393",
  "byteOffset": 312,
  "count": 78,
  "type": "FLOAT_VEC3"
}

In order to make a typed array for translation, we want to write code like

new Float32Array(buffer, bufferView_393.byteOffset + translation.byteOffset, translation.count);

For this code to work, bufferView_393.byteOffset + translation.byteOffset must be division by 4 (which it is in this case).

@fabrobinet
Copy link
Contributor

Good catch, so the 2 actions to do are:

  • mention this in the SPEC. Especially because buffers are likely to be concatenated...
  • make sure we add padding in the converter.

Anything else ?

@pjcozzi
Copy link
Member Author

pjcozzi commented Oct 28, 2013

No, just those two items.

@pjcozzi
Copy link
Member Author

pjcozzi commented Nov 2, 2013

Will the converter be updated in dev-2?

@fabrobinet
Copy link
Contributor

yes, that's an easy one.

@pjcozzi
Copy link
Member Author

pjcozzi commented Nov 2, 2013

Very nice. 👍

@fabrobinet
Copy link
Contributor

on dev-2

@fabrobinet
Copy link
Contributor

on master now.

@pjcozzi
Copy link
Member Author

pjcozzi commented Nov 7, 2013

Re-opening for the spec.

@pjcozzi pjcozzi reopened this Nov 7, 2013
@pjcozzi pjcozzi added this to the Draft 1.0 spec milestone Apr 30, 2014
@pjcozzi pjcozzi removed this from the Spec 1.0 milestone Aug 27, 2015
@pjcozzi
Copy link
Member Author

pjcozzi commented Sep 17, 2015

@tparisi here is text for the draft 1.0 spec:


Accessor Attribute Size

The following tables can be used to compute the size of an accessor's attribute type.

componentType Size in bytes
5120 (BYTE) 1
5121(UNSIGNED_BYTE) 1
5122 (SHORT) 2
5123 (UNSIGNED_SHORT) 2
5126 (FLOAT) 4
type Number of components
"SCALAR" 1
"VEC2" 2
"VEC3" 3
"VEC4" 4
"MAT2" 4
"MAT3" 9
"MAT4" 16

The size of an accessor's attribute type, in bytes, is (size in bytes of the 'componentType') * (number of components defined by 'type').

For example:

"accessor_1": {
    "bufferView": "bufferView_1",
    "byteOffset": 7032,
    "byteStride": 12,
    "componentType": 5126, // FLOAT
    "count": 586,
    "type": "VEC3"
}

In this accessor, the componentType is 5126 (FLOAT) so each component is four bytes. The type is "VEC3" so there are three components. The size of the attribute type is 12 bytes (4 * 3).

BufferView and Accessor Byte Alignment

The offset of an accessor into a bufferView (i.e., accessor.byteOffset) and the offset of an accessor into a buffer (i.e., accessor.byteOffset + bufferView.byteOffset) must be a multiple of the size of the accessor's attribute type.

Implementation Note: This allows a runtime to efficiently create a single arraybuffer from a glTF buffer or an arraybuffer per bufferView, and then use an accessor to create a typed array view (e.g., Float32Array) into an arraybuffer without copying it because the byte offset of the typed array view is a multiple of the size of the type (e.g., 4 for Float32Array).

Consider the following example:

"bufferView_1": {
    "buffer": "buffer_1",
    "byteLength": 17136,
    "byteOffset": 620,
    "target": 34963
},
"accessor_1": {
    "bufferView": "bufferView_1",
    "byteOffset": 4608,
    "byteStride": 0,
    "componentType": 5123, // UNSIGNED_SHORT
    "count": 5232,
    "type": "SCALAR"
}

The size of the accessor attribute type is two bytes (the componentType is unsigned short and the type is scalar). The accessor's byteOffset is also divisible by two. Likewise, the accessor's offset into buffer_1 is 5228 (620 + 4608), which is divisible by two.


@tfili can you confirm that the converter ensures an accessor's byteOffset is also properly aligned? Not just accessor.byteOffset + bufferView.byteOffset?

@pjcozzi pjcozzi added the tools label Sep 17, 2015
@tfili
Copy link

tfili commented Sep 17, 2015

It looks like there is code in there for that. Since it always outputs floats except for indices, it just verifies the indices are 4-byte aligned.

@pjcozzi
Copy link
Member Author

pjcozzi commented Sep 17, 2015

Thanks!

@tparisi you can close this when you update the spec.

@pjcozzi pjcozzi removed the tools label Sep 17, 2015
@tparisi
Copy link
Contributor

tparisi commented Sep 17, 2015

Fixed in 88b5f24

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants