WebGLでバッファやテクスチャなどを扱うと、ArrayBufferとArrayBufferViewを扱わなければなりません。この際、ArrayBufferとArrayBufferViewの適切な理解をしなければ多くのメモリを使ってしまったり、パフォーマンスを落としてしまったりすることがあります。
ArrayBufferとArrayBufferView
まず、ArrayBufferは、途中で容量を拡張したりすることができない要素が連続した配列つまりは、C++やJavaにおける標準的な配列です。C++で扱うときは、配列の途中のポインタを取れば、その途中のインデックスが0のように扱えるように、連続していることができます。
int* arr = new int[100];
int* arr2 = arr + 10;
int a = arr2[0]; // arrの10番目
(Cで書いたような例(最近ふれていないので何か間違っているかもしれない))
このように、配列の途中からの要素をあたかも別の配列のように見えるようにするポインタ的存在がArrayBufferViewです。
TypedArray
UInt8ArrayやUInt16Arrayなど型名が入っている配列はTypedArrayと言います。 これは、実はArrayBufferのように見えてArrayBufferViewのような存在です。
つまり、以下のようなことをしても実際にメモリに確保されてるのは、ArrayBufferの100バイト分になります。
const arr = new ArrayBuffer(100);
const arr2 = new UInt8Array(arr,10);
const a = arr2[0];
要するに、ただ単にオフセットを指定して、あたかも配列のように扱わせる、ポインタのようなものかつ、型を指定して値を取れるためのものがTypedArrayです。
TypedArrayはサイズをコンストラクタにとってそのサイズ分の配列を作成することができます。
const arr = new UInt8Array(100);
しかし、これはあくまで以下の別記法にすぎません。
const arr = new UInt8Array(new ArrayBuffer(100),0);
したがって、コンストラクタにサイズを指定したとき以外、TypedArrayでは実際の配列が確保されることはありません。
ArrayBuffer#slice()
sliceをすると、ArrayBufferの指定した部分だけコピーすることができます。しかし、これはTypedArrayなどの役割とは異なり、実際にArrayBufferがコピーされます。したがって、その分だけ利用しているメモリは増えます。
おわり
以上、雑でしたが無駄に配列をコピーしてしまうことのないよう、素晴らしいパフォーマンスをWebGLで実現したいですね!