Hi team,
I have some prebuilt game asset files which happen to have half-float vertex format. Eg. They use 3 float16 for position, 3 bytes for tangent, etc. I want to directly upload those interleaved vertex buffers to WebGPU (without doing CPU side float conversion) but some patches are needed.
-
Extend
GetTypeByteLength(type),VertexBuffer.HALF_FLOATandConstants.HALF_FLOAT -
Ideally, we would extend the buffer.align.pure.js to support Float16Array so that VertexBufferGetDataType works(inferring vertex format from the underlying data structure). But that requires tool chain supports. The best we can have right now is to let user know “HALF_FLOAT must be passed explicitly; it is never inferred from the data.”
-
Modify
_computeHashCode(). The only reason to modify it is I chose to use the established value Constants.HALF_FLOAT=5131 which is the enum value of GL_HALF_FLOAT. And the hash algorithm only leaves 3 bits for all the vertex types. In WebGL it happens to be ok because those values range from 5120 to 5126. And in WebGL2 half float is added with a odd number 5131. -
Patch
buffer.align.pure.js_alignBuffer -
Patch
checkNonFloatVertexBuffersso that half float doesn’t trigger shader recompile. -
Patch a few functions in
bufferUtils. One thing to note is that the original GetTypeArrayData promotes values to float and then does implicit conversion back to underlying TypedArray, which works for all previous cases but not half float because due to the tool chain limits, the half float data is represented by underlying Uint16Array. So I changed this part to enable byte to byte copy without implicit conversion. -
Patch
webgpuCacheRenderPipeline.ts_GetVertexInputDescriptorFormat
And I have questions on the original _computeHashCode
private _computeHashCode(): void {
// note: cast to any because the property is declared readonly
(this.hashCode as any) =
(VertexBuffer._GetTypeHashIndex(this.type) << 0) +
((this.normalized ? 1 : 0) << 3) +
(this._size << 4) +
((this._instanced ? 1 : 0) << 6) +
/* keep 5 bits free */
(this.byteStride << 12);
}
this._size is the number of components. It ranges from 1 to 4 and when it is 4, it carries to bit 6 and interferes with the instanced bit. And if it was instanced, the carry keeps propagates. Is that intended or a bug?